횡단 관심사(Cross-cutting Concerns)
소프트웨어 개발에서는 여러 기능이나 모듈에서 반복적으로 사용되는 공통적인 요소들이 있습니다. 이를 '횡단 관심사(Cross-cutting concerns)'라고 합니다. 쉽게 말해, 특정 기능에 국한되지 않고 다양한 부분에서 필요로 하는 기능들을 의미합니다.
예를 들어, 회사에서 여러 부서가 공통적으로 사용하는 업무 프로세스를 생각해 볼 수 있습니다. 모든 부서에서 개별적으로 문서를 관리한다고 가정하면 다음과 같은 공통적인 규칙이 필요할 것입니다.
- 문서는 보안 규정에 따라 접근 권한이 있어야 한다.
- 변경 사항이 기록되어야 한다.
- 일정 기간이 지나면 보관하거나 삭제해야 한다.
이러한 규칙은 특정 부서에만 적용되는 것이 아니라, 회사 전체에서 공통적으로 적용되어야 하는 사항입니다.
소프트웨어에서의 횡단 관심사
소프트웨어에서도 위와 같은 개념이 적용됩니다. 여러 기능에서 공통적으로 필요한 요소들이 있으며, 이를 별도로 관리하지 않으면 코드가 중복되고 유지보수가 어려워질 수 있습니다.
대표적인 횡단 관심사의 예시는 다음과 같습니다.
- 로그 기록: 프로그램이 수행하는 작업을 기록하는 기능.
- 보안 및 인증: 사용자가 허가된 권한을 가지고 있는지 확인하는 기능.
- 예외 처리: 오류가 발생했을 때 이를 처리하고 알리는 기능.
이러한 기능들은 특정 모듈에 국한되지 않고, 애플리케이션 전반에서 필요로 합니다.
횡단 관심사를 별도로 관리해야 하는 이유
만약 이러한 공통 기능을 개별 모듈마다 따로 구현한다면 다음과 같은 문제점이 발생할 수 있습니다.
- 코드 중복 증가: 동일한 기능이 여러 곳에서 중복 작성됩니다.
- 유지보수의 어려움: 기능을 변경할 때 모든 곳을 수정해야 합니다.
- 일관성 부족: 일부 모듈에서는 기능이 적용되지 않을 수도 있습니다.
따라서, 횡단 관심사는 별도의 모듈이나 서비스로 분리하여 관리하는 것이 좋습니다. 이를 통해 코드의 재사용성을 높이고 유지보수를 쉽게 할 수 있습니다.
횡단 관심사의 예제 (ASP.NET Core 기반)
예를 들어, 로그인과 관련된 이벤트마다 로그를 기록해야 한다고 가정해 봅시다.
기존 방식 (중복 코드 발생)
public class AccountController : Controller
{
public IActionResult Login(string username)
{
Console.WriteLine($"사용자 {username}이 로그인했습니다.");
return View();
}
public IActionResult Logout(string username)
{
Console.WriteLine($"사용자 {username}이 로그아웃했습니다.");
return View();
}
}
위 코드에서는 로그인과 로그아웃 시마다 로그를 남기는 코드가 중복되어 있습니다. 만약 로그를 남기는 로직이 여러 컨트롤러에서도 필요하다면 유지보수가 어려워질 수 있습니다.
개선된 방식 (Middleware 활용)
이를 해결하기 위해 미들웨어(Middleware)를 활용하여 횡단 관심사인 로그 기록 기능을 별도로 관리할 수 있습니다.
public class LoggingMiddleware
{
private readonly RequestDelegate _next;
public LoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
Console.WriteLine($"Request: {context.Request.Method} {context.Request.Path}");
await _next(context);
Console.WriteLine($"Response: {context.Response.StatusCode}");
}
}
그리고 Startup.cs 혹은 Program.cs에서 미들웨어를 추가합니다.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseMiddleware<LoggingMiddleware>();
app.MapControllers();
app.Run();
이제 애플리케이션 내의 모든 요청과 응답에 대해 자동으로 로그가 기록되며, 개별 컨트롤러에서 중복된 코드 없이 횡단 관심사를 관리할 수 있습니다.
개선된 방식 (MediatR 활용)
또 다른 방법으로 MediatR을 활용하여 횡단 관심사를 관리할 수도 있습니다. MediatR은 CQRS 패턴을 기반으로 명령과 이벤트를 처리하는 라이브러리로, 요청(Request)과 동작(Behavior)을 분리하여 코드의 구조를 개선할 수 있습니다.
- 먼저 IRequestHandler를 사용하여 요청을 정의합니다.
public class LoginCommand : IRequest { public string Username { get; set; } public LoginCommand(string username) { Username = username; } }
- IRequestHandler를 구현하여 요청을 처리합니다.
public class LoginHandler : IRequestHandler<LoginCommand> { public Task Handle(LoginCommand request, CancellationToken cancellationToken) { Console.WriteLine($"사용자 {request.Username}이 로그인했습니다."); return Task.CompletedTask; } }
- IPipelineBehavior를 활용하여 로깅과 같은 횡단 관심사를 구현할 수 있습니다.
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> { public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken) { Console.WriteLine($"Handling {typeof(TRequest).Name}"); var response = await next(); Console.WriteLine($"Handled {typeof(TRequest).Name}"); return response; } }
- Program.cs에서 MediatR을 설정하고 의존성을 등록합니다
-
이제 모든 MediatR 요청이 LoggingBehavior를 통해 자동으로 로깅되며, 각 핸들러에서 중복된 로그 코드 없이 횡단 관심사를 효율적으로 관리할 수 있습니다.var builder = WebApplication.CreateBuilder(args); builder.Services.AddMediatR(typeof(Program)); builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>)); var app = builder.Build(); app.Run();
결론
횡단 관심사는 다양한 기능에서 공통적으로 필요로 하는 요소이며, 이를 적절하게 분리하여 관리하면 코드의 품질을 높이고 유지보수를 효율적으로 할 수 있습니다. .NET과 같은 프레임워크에서는 미들웨어, 필터, AOP, MediatR 등의 개념을 활용하여 횡단 관심사를 효과적으로 관리할 수 있습니다. 이러한 개념을 잘 활용하면 보다 구조적인 개발이 가능해집니다.
'지식 > IT' 카테고리의 다른 글
AOP(Aspect-Oriented Programming, 관전 지향 프로그래밍) (0) | 2025.03.19 |
---|
댓글