TestRepo은(는) 무엇을 하나요?
.NET에서 수직 슬라이스 아키텍처(Vertical Slice Architecture)를 구축하고 유지 관리하는 방법 — 슬라이스 구조(단일 파일 및 폴더 변형), 중재자 없이 직접 핸들러 디스패치, 교차 관심사, 슬라이스 간 공유 가능 요소, 도메인 모델 또는 Clean 레이어와의 상호작용, 슬라이스 수준 테스팅을 다룹니다. 수직 슬라이스로 구성된 모듈에서 유스케이스/엔드포인트/기능을 추가하거나 수정할 때, 또는 슬라이스 간 중복이 논의될 때 사용하십시오.
슬라이스 구조
수직 슬라이스는 두 가지 주요 변형으로 구성할 수 있습니다:
- 단일 파일 슬라이스: 모든 요청, 핸들러, 응답 및 유효성 검사 로직을 하나의 파일에 포함합니다. 간단한 유스케이스에 적합합니다.
- 폴더 기반 슬라이스: 각 슬라이스가 고유한 폴더를 가지며, 내부에
Request.cs,Handler.cs,Response.cs등의 파일로 분리합니다. 복잡한 유스케이스에 적합합니다.
직접 핸들러 디스패치 (MediatR 대신)
중재자(MediatR)를 사용하지 않고 직접 핸들러를 호출하는 방법:
public class CreateUserHandler
{
private readonly AppDbContext _db;
public CreateUserHandler(AppDbContext db)
{
_db = db;
}
public async Task<Response> HandleAsync(Request request)
{
// 비즈니스 로직 구현
var user = new User(request.Name, request.Email);
_db.Users.Add(user);
await _db.SaveChangesAsync();
return new Response(user.Id);
}
}
컨트롤러 또는 엔드포인트에서 직접 호출:
app.MapPost("/users", async (CreateUserHandler handler, CreateUserRequest request) =>
{
var response = await handler.HandleAsync(request);
return Results.Ok(response);
});
교차 관심사 처리
- 로깅: 핸들러 내에서
ILogger<T>를 직접 주입받아 사용하거나, AOP 방식의 데코레이터 패턴을 적용할 수 있습니다. - 유효성 검사: FluentValidation과 같은 라이브러리를 사용하여 각 슬라이스 내에서 요청 유효성 검사를 수행합니다.
- 권한 부여: 핸들러 또는 엔드포인트 레벨에서
[Authorize]특성 또는 정책 기반 검사를 적용합니다.
슬라이스 간 공유 요소
수직 슬라이스는 다음 요소를 공유할 수 있습니다:
- 데이터베이스 컨텍스트:
DbContext는 공유되지만, 각 슬라이스는 자신의 유스케이스에 필요한 엔티티만 사용합니다. - 도메인 모델: 공통 도메인 엔티티와 값 객체를 공유합니다.
- 서비스: 인프라 서비스(예: 이메일 발송, 파일 저장)는 공유 가능하지만, 비즈니스 로직은 각 슬라이스에 캡슐화됩니다.
공유하지 말아야 할 것: 슬라이스 간의 비즈니스 로직, 유효성 검사 규칙, 프레젠테이션 로직은 중복을 허용하더라도 공유하지 않습니다.
도메인 모델 및 Clean 레이어와의 상호작용
- 수직 슬라이스는 Clean Architecture의 레이어(도메인, 애플리케이션, 인프라)를 침범하지 않고 사용합니다. 각 슬라이스는 애플리케이션 레이어의 일부로 볼 수 있습니다.
- 도메인 모델은 모든 슬라이스가 참조하는 공유 계층으로 유지됩니다.
- 각 슬라이스는 도메인 모델을 사용하여 비즈니스 로직을 수행하며, 인프라(예: 데이터베이스, 외부 API)는 핸들러 내에서 직접 해결합니다.
슬라이스 수준 테스팅
각 슬라이스에 대해 독립적인 단위 테스트 및 통합 테스트를 작성합니다:
[Fact]
public async Task CreateUser_ValidRequest_ReturnsUserId()
{
// Arrange
var db = new AppDbContext(Options);
var handler = new CreateUserHandler(db);
var request = new CreateUserRequest { Name = "Test", Email = "[email protected]" };
// Act
var response = await handler.HandleAsync(request);
// Assert
Assert.True(response.UserId > 0);
}
테스트는 특정 슬라이스의 동작에 집중하며, 다른 슬라이스에 의존하지 않도록 설계됩니다.