홈으로 돌아가기

Go에서의 DDD와 Clean Architecture: 실용적인 접근법

이 기사는 과도한 구조를 피하면서 Go에서 DDD와 Clean Architecture를 실용적으로 적용하는 방법을 설명합니다. 코드 예제, 프로젝트 구성 권장 사항 및 기술 부채를 줄이는 핵심 규칙이 제공됩니다.

Go: 200개 파일 없는 DDD와 Clean Architecture
Advertisement 728x90

Go에서의 DDD와 Clean Architecture: 오버엔지니어링 없이 실용적인 접근법

건축적 문제에서 비롯된 기술 부채는 기업 IT 예산의 최대 40%를 소비합니다. Go 프로젝트에서 이는 과도하게 복잡한 구조로 나타납니다: 빈 인터페이스와 비즈니스 로직이 묻힌 레이어로 가득 찬 200개의 파일. 근본 원인은 Java나 C#에서 빌려온 DDD와 Clean Architecture 패턴을 잘못 적용하는 것입니다. 하지만 실용적으로 사용하면 이러한 패턴은 복잡성 문제를 해결합니다. 오버엔지니어링을 피하고 유지보수 가능한 시스템을 구축하는 방법은 다음과 같습니다.

Go 프로젝트가 파일 미로로 변하는 이유는?

다른 언어에서 Go로 넘어온 개발자들은 종종 관용적인 Go에 맞지 않는 건축 습관을 그대로 가져옵니다. Go Developer Survey 2024에 따르면, 가장 큰 문제는 다양한 경험 수준과 비관용적 패턴으로 인한 코드 표준 유지의 어려움입니다. 예를 들어, 핵심 원리를 이해하지 않고 Java를 모방한 domain, application, infrastructure 같은 폴더 구조를 만드는 경우입니다.

Carnegie Mellon 연구에 따르면 건축적 문제는 기술 부채의 주요 원인입니다. Go에서는 다음과 같이 나타납니다:

Google AdInline article slot
  • 중복된 struct가 가득한 dto 폴더.
  • 사소한 변환을 위한 레이어 간 mappers.
  • 인프라(database/sql 등)에 의존하는 domain의 인터페이스.
  • 비즈니스 로직 없이 리포지토리를 호출하는 유스케이스.

결과: 200개의 파일이 있지만 실제 비즈니스 규칙을 설명하는 파일은 없습니다. Clean Architecture와 DDD가 해결책이 아니라 문제가 됩니다.

DDD: 폴더가 아니라 언어와 경계에 관한 것

Domain-Driven Design은 폴더 집합이 아닙니다—문제 도메인을 모델링하는 접근법입니다. 주요 개념:

Ubiquitous Language

개발자와 비즈니스 이해관계자는 코드, 문서, 논의에서 동일한 용어를 사용해야 합니다. 매니저가 "주문 확인"이라고 하면 코드에는 Confirm() 메서드가 있어야지 SetStatus()가 아닙니다. 이는 혼란을 없애고 온보딩을 가속화합니다.

Google AdInline article slot

Bounded Context

대형 시스템은 여러 컨텍스트로 구성됩니다. 예를 들어, 판매에서의 "고객"(퍼널이 있는 리드)과 지원에서의 "고객"(티켓)은 다른 모델입니다. Bounded Context는 모델이 일관되게 유지되는 명확한 경계를 정의합니다. 마이크로서비스에서는 하나의 서비스가 보통 하나의 컨텍스트와 맞춰집니다.

Entity와 Value Object

  • Entity는 고유 ID를 가지며 정체성을 유지합니다(예: Order). 비즈니스 규칙을 포함합니다.
  • Value Object는 불변하며 속성으로 정의됩니다(예: Money). 동일한 필드를 가진 두 객체는 동등합니다.

Go에서의 Value Object 예시:

type Money struct {
    Amount   int64
    Currency string
}

func (m Money) Add(other Money) (Money, error) {
    if m.Currency != other.Currency {
        return Money{}, errors.New("currency mismatch")
    }
    return Money{Amount: m.Amount + other.Amount, Currency: m.Currency}, nil
}

Aggregate

단일 단위로 취급되는 객체 그룹입니다. 모든 접근은 루트(Aggregate Root)를 통해 이뤄집니다. 예를 들어, Order(루트)가 OrderItem을 포함합니다. 규칙: 일관성을 위해 변경은 루트만 통해 이뤄집니다.

Google AdInline article slot

Clean Architecture: 의존성 규칙을 기반으로

Clean Architecture의 본질은 비즈니스 로직이 구현 세부사항(데이터베이스, 프레임워크)에 의존하지 않는 것입니다. 유일한 규칙: 의존성은 안쪽을 가리킵니다(Dependency Rule).

Go에서의 작동 방식

  • domain: 비즈니스 모델(Entity, Value Object, repository 인터페이스)을 포함합니다. stdlib 외부 import 없음.
  • application: 도메인을 조율하는 유스케이스. domain에만 의존.
  • infrastructure: 어댑터 구현(데이터베이스, HTTP 클라이언트). 인터페이스를 통해 domain에 의존.
  • delivery: 진입점(HTTP, gRPC). application에 의존.

domaindatabase/sql을 import하면 건축이 깨집니다. 올바른 예: domain에 repository 인터페이스 선언, infrastructure/postgres에 구현.

DDD와 Clean Architecture 결합의 이점

| Aspect | Effect | Improvement Metric |

|---------------|---------------------------------|--------------------|

| Testability | Domain isolation from infrastructure | +40% coverage |

| Flexibility | Swap adapters in hours | -90% time |

| Understandability | Clear component boundaries | -70% onboarding |

실제 프로젝트 구조: 200개 파일 피하기

Go 서비스의 최적 구조:

internal/
  domain/
    order.go        # Aggregate Order
    order_repo.go   # Repository interface
  application/
    create_order.go # Use case
  infrastructure/
    postgres/
      order_repo.go # Implementation
  delivery/
    http/
      order_handler.go

주요 원칙:

  • Repository 인터페이스는 domain에, 구현은 infrastructure에.
  • 정말 필요하지 않으면 dtomappers 폴더 만들지 말기: 경계를 위반하지 않으면 레이어 간 동일 struct 재사용.
  • 비즈니스 로직은 domain에만. 예: OrderCancel() 메서드가 상태 확인:
func (o *Order) Cancel() error {
    if o.status == StatusShipped {
        return errors.New("cannot cancel shipped order")
    }
    o.status = StatusCancelled
    return nil
}

주요 요점

  • Ubiquitous Language는 DDD의 기반입니다. 코드 용어가 비즈니스 용어와 맞지 않으면 모델이 틀립니다.
  • Dependency Rule은 Clean Architecture의 핵심입니다. 위반 시 스파게티 코드가 됩니다.
  • 실용주의—필요 없으면 레이어 만들지 말기. Go에서는 struct가 맞으면 dto를 생략할 수 있습니다.
  • Aggregates는 트랜잭션 경계를 정의합니다. 일관성을 위해 루트만 통해 변경.
  • Testing—도메인 테스트는 인프라 없이 실행되어 개발을 가속화합니다.

— Editorial Team

Advertisement 728x90

다음 읽기