본문 바로가기

백엔드 개발일지

[Architecture] 그라밋 프로젝트, 클린 아키텍처 입히기

반응형

1. 개요

YAPP에서 진행 중인 ‘그라밋’ 프로젝트클린 아키텍처를 도입하기로 결정했습니다.

 

이전 프로젝트 ‘삐삐’에서는 멀티 모듈 구조를 적용해 도메인 간의 의존성을 분리하면서, 특정 도메인의 변경이 다른 도메인에 영향을 주지 않도록 설계했습니다. 덕분에 유지보수성이 크게 향상되는 걸 경험했습니다.

하지만 프로젝트가 커지고 기능이 추가될수록, 서비스 계층이 점점 비대해지는 문제를 겪었습니다. 모듈을 나누긴 했지만, 여전히 외부 의존성(ex. DB, Framework 등)에 깊게 묶여 있다는 점도 고민이었습니다.

 

이런 문제를 해결할 방법을 찾던 중, 비즈니스 로직이 특정 계층에 몰리지 않으면서도 외부 변경에 유연하게 대응할 수 있는 구조클린 아키텍처를 알게 되었습니다.

 

 

 

2. 클린 아키텍처

1) 클린 아키텍처란?

 

클린 아키텍처(Clean Architecture)는 비즈니스 로직을 핵심으로 유지하면서, 외부 요소(데이터베이스, 프레임워크 등)와의 결합도를 최소화하는 아키텍처 패턴입니다. 소프트웨어의 유지보수성과 확장성을 극대화하기 위해, 각 계층 간의 의존성을 명확히 분리하는 것이 핵심이죠.

이 개념은 로버트 C. 마틴(‘Uncle Bob’)이 제안한 것으로, 핵심 원칙은 단순합니다. "의존성은 안쪽(비즈니스 로직)으로 향해야 한다." 즉, 데이터베이스나 UI 같은 세부사항이 핵심 도메인 로직을 직접 침범하지 않도록 보호하는 구조입니다.

 

 

2) 왜 클린 아키텍처가 필요할까?

기존의 레이어드 아키텍처나 단순한 MVC 구조에서는, 서비스 계층이 점점 비대해지고 데이터베이스, 웹 프레임워크 등에 강하게 결합되는 문제가 발생합니다.

 

이렇게 되면,

  • 특정 프레임워크나 라이브러리에 종속되어 변경이 어려워지고,
  • 테스트가 어려워지며,
  • 새로운 기능 추가 시 기존 코드에 영향을 미치는 범위가 넓어지는 문제가 생깁니다.

클린 아키텍처는 이러한 문제를 해결하기 위해 비즈니스 로직과 외부 요소를 철저히 분리하고, 변경에 유연한 시스템을 만들도록 설계됩니다.

 

 

3) 클린 아키텍처의 핵심 원칙

클린 아키텍처에서 제시하는 핵심 원칙은 다음과 같습니다.

  • 의존성 규칙(Dependency Rule)
    • 안쪽 계층(엔터티, 유스케이스)은 바깥쪽(프레젠테이션, 데이터) 계층에 의존하면 안 된다.
    • 즉, 비즈니스 로직은 프레임워크나 데이터베이스를 전혀 몰라도 동작 가능해야 한다.
  • 계층 구조
    • 엔티티(Entities): 가장 핵심적인 도메인 규칙
    • 유스케이스(Use Cases): 애플리케이션의 동작을 정의하는 계층
    • 인터페이스 어댑터(Interface Adapters): 외부와의 연결 담당 (ex. 컨트롤러, 레포지토리)
    • 프레임워크 & 드라이버(Frameworks & Drivers): DB, 웹 프레임워크 등 가장 바깥쪽
  • 프레임워크 독립성
    • 특정 웹 프레임워크나 ORM에 묶이지 않고, 언제든 교체할 수 있도록 설계
  • 테스트 용이성
    • 핵심 비즈니스 로직을 쉽게 테스트할 수 있도록 구성

 

 

 

 

3. 그라밋의 클린 아키텍처

그라밋 프로젝트에서는 클린 아키텍처의 원칙을 따라 애플리케이션을 계층별로 명확하게 분리했습니다. 이를 통해 비즈니스 로직과 외부 요소 간의 결합도를 최소화하고, 유지보수성과 확장성을 높이고자 했습니다.

 

 

1) 구조

그라밋 프로젝트는 다음과 같은 네 개의 계층으로 구성되어 있습니다

 

1. Domain 계층 (핵심 비즈니스 로직)

  • 애플리케이션의 핵심 도메인 모델과 비즈니스 규칙을 정의하는 계층
  • model, policy, IdGenerator 등의 패키지에서 도메인 로직을 담당
  • 외부 요소에 의존하지 않으며, 오직 비즈니스 로직만 포함

 

2. Application 계층 (유즈케이스 조합 및 실행)

 

  • 도메인 계층을 활용하여 유즈케이스(Use Case) 를 정의하는 계층
  • service, usecase 패키지에서 애플리케이션 동작을 조합
  • 비즈니스 로직을 실행하는 역할을 하지만, 인프라 및 프레임워크에 직접 의존하지 않음

3. Presentation 계층 (클라이언트 요청 처리)

 

  • 사용자의 요청을 받고 응답을 반환하는 계층
  • controller, dto, mapper 패키지에서 클라이언트와의 상호작용 담당
  • API를 정의하고, 요청을 Application 계층으로 전달하여 유즈케이스 실행

4. Infrastructure 계층 (외부 시스템과의 연결)

 

  • 데이터베이스, 메시징 시스템, API 호출 등 외부 의존성을 관리하는 계층
  • database, feign, gateway, token 등의 패키지에서 외부 시스템과의 연결 담당
  • 도메인 로직을 직접 포함하지 않으며, 인터페이스를 통해 Application 계층과 연결됨

 

 

2) 적용하면서 신경 쓴 점

현재는 러닝커브를 고려해서 단일 모듈 내에서 패키지로 레이어를 나누어 진행하고 있습니다. 그러다 보니 단일 모듈 내에서 클린 아키텍처 원칙에 위배하지 않도록 다음과 같은 점들을 신경썼습니다.

  • 비즈니스 로직 보호: 핵심 도메인은 외부 의존성과 분리하여 변경이 최소화됨
  • 의존성 역전: 외부 시스템(Database, API 등)이 내부 도메인 로직을 침범하지 않도록 인터페이스 기반의 의존성 주입 적용
  • 확장성 고려: 새로운 기능을 추가할 때 특정 계층에 집중되거나 기존 코드에 영향을 덜 주도록 설계

 

 

 

4. 마무리

이번 구조를 통해 비즈니스 로직을 중심으로 한 탄탄한 아키텍처를 구축할 수 있었습니다. 하지만 단일 모듈 내에서 클린 아키텍처를 적용하다 보니, 예상치 못한 계층 간 의존성이 발생할 가능성이 있습니다. 이를 방지하기 위해, 앞으로는 멀티 모듈을 도입하여 각 계층을 독립적인 모듈로 점진적으로 분리할 계획입니다.

 

이러한 구조적 개선을 통해, 새로운 기능이 추가되더라도 특정 계층만 수정하면 되므로 유지보수가 용이하며, 다양한 기술 스택을 유연하게 적용할 수 있을 것으로 기대됩니다.

 

 

반응형