PART 2 · 강의 2/4

계층형 아키텍처
패턴

Layered, Hexagonal, Onion 아키텍처의 특징과 차이점을 이해하고 적절한 선택 기준을 학습합니다.

00

아키텍처 패턴 비교

각 탭을 클릭하여 아키텍처 패턴의 특징을 살펴보세요

N-Tier / Layered Architecture

Presentation Layer
UI, Controllers, Views
V
Application Layer
Use Cases, Services
V
Domain Layer
Business Logic, Entities
V
Infrastructure Layer
Database, External APIs
핵심 원칙

상위 계층은 하위 계층에만 의존합니다. 각 계층은 자신의 바로 아래 계층만 알고, 건너뛰기(skip)는 피해야 합니다. 가장 전통적이고 이해하기 쉬운 아키텍처 패턴입니다.

Presentation
-->
Application
-->
Domain
-->
Infrastructure

장점

  • 이해하기 쉽고 직관적
  • 팀원 온보딩이 빠름
  • 명확한 역할 분리
  • 대부분의 프레임워크가 지원
  • 작은 프로젝트에 적합

단점

  • 도메인이 인프라에 의존
  • 테스트하기 어려움 (DB 의존)
  • 비즈니스 로직이 서비스에 분산
  • 변경 시 여러 계층 수정 필요
  • 기술 변경에 취약

Hexagonal Architecture (Ports & Adapters)

Domain
Core
In
Out
API
DB
REST Controller
Repository Impl
GraphQL
PostgreSQL
핵심 원칙

도메인 코어가 중심이며, 외부와의 통신은 포트(인터페이스)와 어댑터를 통해 이루어집니다. 도메인은 어떤 기술에도 의존하지 않습니다. 포트는 "무엇을"을, 어댑터는 "어떻게"를 담당합니다.

Port와 Adapter의 역할
  • Driving Port (Primary) - 외부에서 애플리케이션을 호출하는 인터페이스 (API, UI)
  • Driven Port (Secondary) - 애플리케이션이 외부를 호출하는 인터페이스 (Repository, Gateway)
  • Driving Adapter - REST Controller, GraphQL Resolver, CLI
  • Driven Adapter - JPA Repository, Redis Cache, HTTP Client

장점

  • 도메인이 기술에 독립적
  • 테스트가 매우 쉬움
  • 어댑터 교체가 자유로움
  • DDD와 잘 어울림
  • AI 시대에 유연한 통합

단점

  • 초기 학습 곡선이 있음
  • 작은 프로젝트에는 과도함
  • 보일러플레이트 코드 증가
  • 팀 전체의 이해 필요
  • 잘못 구현하기 쉬움

Onion Architecture

Infrastructure
Application Services
Domain Services
Entity
핵심 원칙

의존성은 항상 안쪽을 향합니다. 가장 안쪽의 Entity가 핵심이며, 바깥쪽 레이어는 안쪽 레이어에 의존하지만 그 반대는 허용되지 않습니다. Clean Architecture의 모태가 되는 아키텍처입니다.

Infrastructure
-->
Application
-->
Domain
-->
Entity

장점

  • 핵심 도메인 보호
  • 의존성 방향이 명확
  • 프레임워크 독립적
  • Clean Architecture와 호환
  • 장기 유지보수에 유리

단점

  • 복잡도 증가
  • 많은 인터페이스 필요
  • 작은 팀에는 부담
  • 과도한 추상화 위험
  • 레이어 경계 혼란
01

아키텍처 비교표

세 가지 아키텍처의 주요 특징 비교

특성 Layered Hexagonal Onion
의존성 방향 위에서 아래로 외부에서 내부로 바깥에서 안쪽으로
도메인 위치 중간 레이어 중앙 (Core) 가장 안쪽 (Core)
인프라 의존성 도메인이 인프라에 의존 인프라가 도메인에 의존 인프라가 도메인에 의존
테스트 용이성 낮음 (DB 의존) 높음 (Mock 용이) 높음 (Mock 용이)
학습 곡선 낮음 중간 높음
적합한 프로젝트 소규모, 단순 CRUD 중/대규모, 복잡한 도메인 대규모, 장기 유지보수
AI 협업 적합성 보통 우수 우수
02

언제 어떤 아키텍처를 선택할까?

상황별 아키텍처 선택 가이드

Layered

Layered Architecture 추천

  • 단순한 CRUD 애플리케이션
  • 소규모 팀, 빠른 개발 필요
  • 복잡한 비즈니스 로직이 적음
  • 프로토타입 또는 MVP
  • 기술 변경 가능성 낮음
Hexagonal

Hexagonal Architecture 추천

  • 복잡한 도메인 로직
  • 외부 시스템 연동이 많음
  • 테스트 주도 개발(TDD)
  • 마이크로서비스 아키텍처
  • AI 서비스 통합 계획
Onion

Onion Architecture 추천

  • 대규모 엔터프라이즈 시스템
  • 장기 유지보수 예상
  • DDD 기반 설계
  • Clean Architecture 적용
  • 여러 팀이 협업
AI 시대의 선택 기준

AI와 협업할 때는 Hexagonal 또는 Onion 아키텍처가 유리합니다. 도메인과 인프라가 분리되어 있어 AI에게 "UserRepository 인터페이스의 새로운 구현체 만들어줘"와 같은 명확한 요청이 가능하고, 생성된 코드가 기존 도메인 로직에 영향을 주지 않습니다.

03

코드로 보는 차이점

동일한 기능을 각 아키텍처에서 구현하는 방식

주문 생성 기능 구현 비교

// Layered Architecture - 도메인이 인프라에 의존

class OrderService {
    private orderRepository = new OrderRepository(); // 직접 의존
    private paymentGateway = new StripePaymentGateway(); // 직접 의존

    async createOrder(orderData) {
        // 비즈니스 로직과 인프라 코드가 섞임
        const order = new Order(orderData);

        // 결제 처리 (Stripe에 직접 의존)
        await this.paymentGateway.charge(order.totalAmount);

        // DB 저장 (Repository에 직접 의존)
        await this.orderRepository.save(order);

        return order;
    }
}

// 문제점: 테스트 시 실제 DB와 Stripe API 필요!
// Hexagonal Architecture - 포트와 어댑터로 분리

// Port (인터페이스) 정의
interface OrderRepository {
    save(order: Order): Promise<Order>;
}

interface PaymentGateway {
    charge(amount: number): Promise<PaymentResult>;
}

// Use Case (도메인은 인터페이스에만 의존)
class CreateOrderUseCase {
    constructor(
        private orderRepo: OrderRepository,    // 인터페이스
        private paymentGw: PaymentGateway      // 인터페이스
    ) {}

    async execute(orderData) {
        const order = new Order(orderData);
        await this.paymentGw.charge(order.totalAmount);
        await this.orderRepo.save(order);
        return order;
    }
}

// Adapter (실제 구현체)
class PostgresOrderRepository implements OrderRepository { ... }
class StripePaymentAdapter implements PaymentGateway { ... }

// 테스트 (Mock 객체로 쉽게 테스트!)
const mockRepo = new MockOrderRepository();
const mockPayment = new MockPaymentGateway();
const useCase = new CreateOrderUseCase(mockRepo, mockPayment);
SUMMARY

핵심 요약

  • Layered Architecture - 단순하고 직관적이나, 도메인이 인프라에 의존하는 문제가 있다
  • Hexagonal Architecture - 포트와 어댑터로 도메인을 보호하며, 테스트와 확장이 용이하다
  • Onion Architecture - 의존성이 항상 안쪽을 향하며, Clean Architecture의 근간이 된다
  • 프로젝트의 복잡도, 팀 규모, 유지보수 기간을 고려하여 선택해야 한다
  • AI 시대에는 도메인과 인프라가 분리된 아키텍처가 협업에 유리하다
주의사항

아키텍처는 "은탄환"이 아닙니다. 팀의 역량과 프로젝트 요구사항에 맞는 선택이 중요하며, 처음부터 완벽한 아키텍처를 고집하기보다 점진적으로 발전시키는 것이 현실적입니다.