아키텍처 규칙
솔루션
솔루션명
프로젝트명1 // 서비스
src // 애플리케이션 레이어
프로젝트명1
프로젝트명1.Adapters.Infrastructure
프로젝트명1.Adapters.Persistence
프로젝트명1.Adapters.Presentation
프로젝트명1.Application
프로젝트명1.Domain
tests // 테스트 레이어
프로젝트명1.Tests.Integration
프로젝트명1.Tests.Performance
프로젝트명1.Tests.Unit
프로젝트명2 // 서비스
tests
솔루션명.Tests.E2E
레이어 이름
- 애플리케이션 레이어
- 기술 관심사
Host
: 프로세스(생략)Adapter
: 기능
- 비즈니스 관심사
Application
: UseCaseDomain
: AggregateRoot
- 기술 관심사
- 테스트 레이어
E2E
Integration
,Performance
, ...Unit
애플리케이션 레이어 구성
T1.T2{.T3}
src
├─ ArchDdd : Host(생략)
├─ ArchDdd.Adapters.Infrastructure : Adapter
├─ ArchDdd.Adapters.Persistence : Adapter
├─ ArchDdd.Adapters.Presentation : Adapter
├─ ArchDdd.Application : Application
└─ ArchDdd.Domain : Domain
T1
: Process 이름T2
: Layer 이름Domain
⊂Application
⊂Adapter
⊂Host
T3
: Feature 이름(생략 가능)- Presentation, Infrastructure, Persistence, ...
테스트 레이어 구성
T1.T2.T3
tests
├─ ArchDdd.Tests.E2E : Test
├─ ArchDdd.Tests.Integration : Test
└─ ArchDdd.Tests.Unit : Test
T1
: Process 이름T2
: Layer 이름Test
T3
: Feature 이름(테스트 피라미드)Unit
⊂Integration
⊂E2E
레이어 식별
- 네임스페이스와 정적 클래스를 이용하여 레이어를 식별하기 위해
AssemblyReference.cs
파일을 모든 프로젝트에 생성합니다.
using System.Reflection;
namespace ArchDdd.Application; // Application 레이어
public static class AssemblyReference
{
public static readonly Assembly Assembly = typeof(AssemblyReference).Assembly;
}
레이어 의존성
Host // 기술 관심사: 프로세스
↓
Adapter // 기술 관심사: Infrastructure, Persistence, Presentation
↓
Application // 비즈니스 관심사: UseCase
↓
Domain // 비즈니스 관심사: AggregateRoot
레이어 의존성 테스트
[Fact]
public void DomainLayer_ShouldNotDependOn_AnyLayers()
{
// Arrange
var assembly = Domain.AssemblyReference.Assembly;
var otherAssemblies = new[]
{
Host.AssemblyReference.Assembly.GetName().Name,
Adapters.Persistence.AssemblyReference.Assembly.GetName().Name,
Adapters.Infrastructure.AssemblyReference.Assembly.GetName().Name,
Adapters.Presentation.AssemblyReference.Assembly.GetName().Name,
Application.AssemblyReference.Assembly.GetName().Name,
};
// Act
var actual = Types
.InAssembly(assembly)
.ShouldNot()
.HaveDependencyOnAny(otherAssemblies)
.GetResult();
// Assert
actual.IsSuccessful.Should().BeTrue();
}
Host 레이어 인터페이스
// Program 어셈블리
//public sealed partial class Program { }
public interface IAppMaker
{
}
// Integration 테스트
public sealed class WebAppFactoryFixture
//: WebApplicationFactory<Program>
: WebApplicationFactory<IAppMarker>
, IAsyncLifetime
{
// ...
}
의존성 등록
레이어 소통
메시지 처리
Middleware --> WebApi Controller --> Pipeline --> UseCase
Middleware
: ASP.NET WebApi- ErrorHandlingMiddleware: 예외 처리
- RequestTimeMiddleware: 4초 이상 작업 로그
Pipeline
: MediatR- LoggingPipeline: 성공/실패 로그
- ValidatorPipeline: UseCase 데이터 유효성 검사
순서 | 구분 | 로그 | 기능 |
---|---|---|---|
1 | ErrorHandlingMiddleware | Error | 전역 예외 처리 |
2 | RequestTimeMiddleware | Warning | 4초 이상 |
3 | LoggingPipeline | Information, Error | 모든 메시지 |
4 | ValidatorPipeline | - | 메시지 유효성 검사 |