C# 아키텍처 마스터리 — 레거시 ASP.NET Core 앱을 클린 아키텍처로 리팩터링 (파트 10)

발행: (2025년 12월 24일 오전 06:05 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

Introduction

대부분의 ASP.NET Core 시스템은 처음부터 깨진 것이 아니라, 점차 깨집니다.
레거시 시스템은 나쁜 개발자 때문이라기보다, 압박을 받는 좋은 개발자들의 결과물인 경우가 많습니다.

이번 Part 10에서는 시니어 팀이 레거시 ASP.NET Core 애플리케이션을 클린 아키텍처로 점진적으로 리팩터링하는 방법을 다룹니다. 전체 재작성, 대대적인 리팩터링, 혹은 기능 동결 없이 진행합니다. 이는 파괴가 아니라 통제된 진화에 관한 이야기입니다.

절대 재작성하지 말고, 재구성하라.
재작성은 비즈니스 로직을 제대로 이해하지 못하고, 엣지 케이스가 문서화되지 않으며, 배포가 중단되기 때문에 실패합니다.

클린 아키텍처 리팩터링은 완벽함을 추구하는 것이 아니라 시점을 만들는 것입니다.

Identifying Problem Areas

코드를 건드리기 전에 다음을 찾아보세요:

  • 비대해진 컨트롤러
  • 거대한 서비스(God services)
  • DbContext 누수
  • 테스트하기 어려운 로직
  • 변화에 대한 두려움

이 항목들은 어디서 시작해야 할지를 알려줄 뿐, 전체를 한 번에 재설계하라는 뜻은 아닙니다.

Protect Behavior with Characterization Tests

// Characterization test
[Fact]
public async Task CreateOrder_Current_Behavior_Is_Preserved()
{
    var response = await client.PostAsJsonAsync("/orders", request);
    response.StatusCode.Should().Be(HttpStatusCode.OK);
}

이 테스트들은:

  • 현재 동작을 캡처하고
  • 우발적인 회귀를 방지하며
  • 리팩터링에 대한 안전망을 제공합니다

예쁘게 만들 필요는 없습니다.

Refactoring Steps

Extract Use Cases

레거시 컨트롤러에는 비즈니스 규칙, 데이터 접근, 매핑 로직이 모두 섞여 있는 경우가 많습니다.
모든 것을 재설계하기보다 유스케이스를 추출하는 방식으로 리팩터링합니다.

Before

public IActionResult Create(OrderDto dto) { /* everything */ }

After

public IActionResult Create(OrderDto dto)
{
    _useCase.Execute(dto);
    return Ok();
}

Create an Application Layer

Application/
 └─ Orders/
     └─ CreateOrderUseCase.cs

컨트롤러는 이제 애플리케이션 레이어에 위임하는 어댑터가 됩니다.

Introduce Repository Interfaces

EF Core를 바로 제거하지 마세요. 대신:

  1. 레포지토리 인터페이스를 도입한다.
  2. DbContext 접근을 래핑한다.
  3. EF 사용을 외부로 옮겨 마이그레이션 시점을 만든다.
public interface IOrderRepository
{
    Task SaveAsync(Order order);
}

Improve the Domain Model

레거시 도메인은 흔히 빈약합니다. 작게 시작하세요:

  • 값 객체(Value objects)
  • 불변 조건(Invariants)
  • 행동이 풍부한 엔티티(Behavior‑rich entities)

“완벽한” 도메인이 필요하지 않습니다. 어제보다 경계가 명확해지면 충분합니다.

Refactoring Rules

  • 의존성은 항상 안쪽을 향해야 합니다.
  • 인터페이스는 안쪽으로, 구현은 바깥쪽으로 이동한다.
  • DI를 사용해 시스템을 가장자리에서 연결한다.

What to Avoid

  • 대대적인 재작성(Big‑bang rewrites)
  • 프레임워크 전면 정리(Framework purges)
  • 조기 추상화(Premature abstractions)
  • 도메인 과잉 모델링(Over‑modeling the domain)
  • 기능 작업 동결(Freezing feature work)

리팩터링은 배포와 동시에 진행되어야 합니다.

Winning Indicators

다음 상황이 되면 성공적인 진행 중입니다:

  • 테스트 작성이 쉬워진다
  • 컨트롤러가 작아진다
  • 로직이 안쪽으로 이동한다
  • EF Core가 덜 눈에 띈다
  • 변경이 안전하게 느껴진다
  • 아키텍처가 점진적으로 개선된다

Conclusion

클린 아키텍처는 도착점이 아니라 방향입니다. 레거시 시스템은 완벽함이 아니라 올바른 방향으로 나아가는 모멘텀이 필요합니다. 안전하게 리팩터링하고 시스템을 지속적으로 전진시켜야 합니다.

Written by Cristian Sifuentes — helping teams modernize legacy .NET systems without rewrites, fear, or lost velocity.

Back to Blog

관련 글

더 보기 »