Unisquads
로그인
홈
이용약관·개인정보처리방침·콘텐츠정책·© 2026 Unisquads
이용약관·개인정보처리방침·콘텐츠정책
© 2026 Unisquads. All rights reserved.

클린 아키텍처 및 헥사고날 아키텍처 (r1)

이 문서의 과거 버전 (r1)을 보고 있습니다. 수정일: 2026.02.13 22:23

클린 아키텍처 및 헥사고날 아키텍처

이름

클린 아키텍처 및 헥사고날 아키텍처

분류

소프트웨어 아키텍처

제안자

클린 아키텍처: 로버트 C. 마틴, 헥사고날 아키텍처: 앨리스터 코번

주요 목표

의존성 규칙 준수, 비즈니스 로직 격리, 테스트 용이성, 프레임워크 독립성

핵심 개념

의존성 역전 원칙, 계층화, 포트와 어댑터

적용 분야

엔터프라이즈 애플리케이션, 마이크로서비스, 복잡한 도메인 중심 시스템

아키텍처 상세

클린 아키텍처 구조

엔티티 → 유스케이스 → 인터페이스 어댑터 → 프레임워크/드라이버의 계층화된 원형 구조

헥사고날 아키텍처 구조

중심의 도메인과 외부의 포트, 어댑터로 구성된 육각형 모델

공통 원칙

의존성은 안쪽으로(의존성 규칙), 외부 변경으로부터 비즈니스 로직 보호

주요 구성 요소

엔티티, 유스케이스, 게이트웨이, 컨트롤러, 프레젠터, 리포지토리

장점

유지보수성 향상, 테스트 용이, 기술 스택 변경에 유연, 도메인 이해도 증가

단점

초기 복잡도 증가, 학습 곡선, 과도한 설계 가능성

관련 패턴/아키텍처

Onion Architecture, DIP, 레이어드 아키텍처, DDD

주요 구현 프레임워크/도구

언어/프레임워크에 독립적 (예: Spring, .NET, Node.js 등에서 적용)

참고 문헌

로버트 C. 마틴, '클린 아키텍처'; 앨리스터 코번, '포트와 어댑터'

1. 개요

클린 아키텍처와 헥사고날 아키텍처는 소프트웨어 시스템의 핵심 비즈니스 로직과 외부 요소(데이터베이스, 사용자 인터페이스, 외부 서비스 등)를 분리하여 설계하는 것을 목표로 하는 아키텍처 패턴이다. 이 두 패턴은 로버트 C. 마틴과 알리스테어 콕번에 의해 각각 제안되었으며, 관심사의 분리 원칙을 극대화하는 데 중점을 둔다.

이러한 아키텍처의 근본적인 목적은 시스템을 변경에 유연하고, 테스트하기 쉬우며, 장기적으로 유지보수 가능하도록 만드는 것이다. 핵심 비즈니스 규칙은 외부 프레임워크, 데이터베이스, UI 기술로부터 독립적으로 유지되어, 이러한 외부 요소가 변경되거나 교체되어도 애플리케이션의 중심 기능에는 최소한의 영향만 미치게 한다.

클린 아키텍처와 헥사고날 아키텍처는 각각 독립적으로 발전했지만, 의존성 방향을 안쪽(핵심)으로 수렴시키고 외부와의 접점을 명확히 정의한다는 공통된 철학을 공유한다. 이는 전통적인 계층형 아키텍처에서 발생할 수 있는 의존성 혼란과 변경의 파급 효과를 줄이는 데 기여한다. 결과적으로 이 아키텍처들은 복잡한 도메인을 가진 엔터프라이즈 애플리케이션 설계에 널리 채택되고 있다.

2. 클린 아키텍처의 핵심 개념

클린 아키텍처의 핵심은 의존성 규칙이다. 이 규칙은 소스 코드의 의존성이 항상 안쪽으로, 즉 고수준의 정책을 향해야 한다고 명시한다. 구체적으로, 외부 계층에 있는 코드는 내부 계층에 있는 코드에 대해 알지 못하며, 내부 계층의 변경이 외부 계층에 영향을 미쳐서는 안 된다. 이는 의존성의 방향을 제어함으로써 시스템의 핵심 비즈니스 로직이 외부 프레임워크나 데이터베이스와 같은 세부사항으로부터 보호받게 한다.

이 규칙을 구현하는 구조는 일반적으로 동심원 계층으로 표현된다. 가장 중심에는 엔티티가 위치하며, 이는 기업의 핵심 비즈니스 규칙을 캡슐화한다. 그 다음 계층은 유스케이스로, 애플리케이션에 특화된 비즈니스 규칙을 포함한다. 가장 바깥쪽 계층에는 인터페이스 어댑터, 프레임워크, 드라이버와 같은 구체적인 구현 세부사항이 위치한다.

계층

설명

예시

엔티티 (Entities)

기업의 핵심 비즈니스 객체와 규칙[1]

도메인 모델, 비즈니스 규칙

유스케이스 (Use Cases)

애플리케이션의 특정 시나리오를 구현한 응용 비즈니스 규칙

"계좌 이체하기", "상품 주문하기"

인터페이스 어댑터 (Interface Adapters)

내부 데이터 형식을 외부 형식(예: 웹, 데이터베이스)으로 변환

컨트롤러, 프레젠터, 게이트웨이

프레임워크 & 드라이버 (Frameworks & Drivers)

외부 프레임워크, 데이터베이스, UI 도구 등의 구체적 구현

Spring, Hibernate, 웹 서버

이 구조에서 각 계층은 안쪽 계층에 정의된 추상화에 의존하며, 구체적인 구현은 바깥쪽 계층에서 제공한다. 예를 들어, 유스케이스 계층은 데이터 저장소에 대한 인터페이스(예: Repository)를 정의하고, 외부 계층의 어댑터가 이를 구현한다. 이로 인해 데이터베이스를 MySQL에서 MongoDB로 변경하더라도 핵심 비즈니스 로직은 전혀 수정할 필요가 없다.

2.1. 의존성 규칙

의존성 규칙은 클린 아키텍처의 가장 근본적인 원칙으로, 소프트웨어 계층 간 의존성의 방향을 규정한다. 이 규칙은 "소스 코드 의존성은 반드시 안쪽으로, 고수준의 정책을 향해야 한다"고 명시한다. 즉, 저수준의 세부 사항(예: 데이터베이스, 웹 프레임워크, UI)은 고수준의 비즈니스 로직에 의존할 수 있지만, 그 반대는 허용되지 않는다.

이 규칙을 통해 핵심 비즈니스 로직은 외부 요소의 변경으로부터 보호된다. 예를 들어, 데이터베이스를 MySQL에서 MongoDB로 변경하거나 웹 프레임워크를 교체하더라도, 애플리케이션의 핵심 규칙은 전혀 영향을 받지 않아야 한다. 의존성 역전 원칙을 적용하여, 저수준 모듈이 고수준 모듈이 정의한 추상 인터페이스에 의존하도록 함으로써 이 방향성을 실현한다.

구체적인 구현에서는 인터페이스(또는 추상 클래스)가 이 규칙의 매개체 역할을 한다. 비즈니스 로직 계층은 구체적인 데이터베이스 접근 방법을 정의하는 인터페이스에만 의존한다. 실제 데이터베이스 연동 코드는 이 인터페이스를 구현하는 형태로 외부 계층에 위치하며, 따라서 의존성 방향은 바깥쪽에서 안쪽을 향하게 된다.

이 규칙을 준수한 아키텍처는 다음과 같은 계층 구조를 갖는다.

계층

설명

의존성 방향

엔티티

핵심 비즈니스 규칙과 데이터 구조

없음 (가장 안쪽)

유스케이스

애플리케이션 특화 비즈니스 규칙

→ 엔티티

인터페이스 어댑터

외부 시스템과의 데이터 변환기

→ 유스케이스, 엔티티

프레임워크/드라이버

데이터베이스, UI, 프레임워크

→ 인터페이스 어댑터

이 표에서 알 수 있듯, 모든 의존성은 안쪽 계층을 향하며, 바깥쪽 계층의 변경이 안쪽으로 전파되는 것을 방지한다.

2.2. 계층 구조

클린 아키텍처의 계층 구조는 동심원으로 표현되며, 가장 안쪽에서 바깥쪽으로 향할수록 정책의 중요도는 높아지고 세부사항 및 의존성은 낮아집니다. 이 구조는 의존성 규칙을 따르며, 의존성 방향은 항상 안쪽으로 향합니다.

주요 계층은 다음과 같습니다.

계층

설명

구성 요소 예시

엔티티

가장 안쪽에 위치하며, 업무 규칙과 핵심 도메인 로직을 캡슐화합니다.

엔티티, 값 객체

유스케이스

애플리케이션의 특정 업무 시나리오를 담당합니다. 엔티티를 조정하여 시스템의 동작을 구현합니다.

유스케이스, 애플리케이션 서비스

인터페이스 어댑터

외부 세계와의 데이터 변환을 담당합니다. 내부의 유스케이스와 엔티티를 위해 데이터를 적절한 형식으로 변환합니다.

컨트롤러, 프레젠터, 게이트웨이

프레임워크와 드라이버

가장 바깥쪽 계층으로, 데이터베이스, 웹 프레임워크, UI 등 모든 외부 도구와 세부사항을 포함합니다.

데이터베이스, 웹 프레임워크, UI

이 계층 구조의 핵심은 도메인과 비즈니스 로직이 외부 요소에 의존하지 않도록 보호하는 데 있습니다. 데이터 흐름은 외부 계층에서 시작되어 컨트롤러를 통해 유스케이스로 전달되고, 유스케이스는 엔티티를 사용하여 비즈니스 규칙을 처리한 후, 결과는 다시 프레젠터 등을 통해 외부로 반환됩니다. 이로 인해 데이터베이스나 UI와 같은 외부 세부사항을 변경하더라도 핵심 비즈니스 로직은 영향을 받지 않게 됩니다.

2.3. 엔티티, 유스케이스, 인터페이스

엔티티는 애플리케이션의 핵심 비즈니스 규칙을 캡슐화하는 객체입니다. 이는 도메인 모델의 중심 요소로, 외부 세계의 변화(예: 데이터베이스, UI, 프레임워크 변경)에 가장 덜 영향을 받도록 설계됩니다. 예를 들어, 은행 애플리케이션의 '계좌'나 전자상거래 시스템의 '주문'이 엔티티에 해당합니다. 이들의 상태와 행위는 순수한 비즈니스 로직만을 포함하며, 외부 의존성을 가지지 않습니다.

유스케이스는 애플리케이션의 특정 시나리오를 구현합니다. '계좌에서 출금한다' 또는 '상품을 주문한다'와 같은 구체적인 작업 흐름을 담당하는 객체입니다. 유스케이스는 엔티티를 조정하여 비즈니스 규칙을 실행하지만, 그 자체로는 비즈니스 규칙이 아닙니다. 외부 세계(예: 데이터 저장소, UI)와의 상호작용이 필요할 때는 인터페이스를 통해 정의된 계약에 의존하며, 구체적인 구현에는 직접 의존하지 않습니다.

인터페이스는 내부의 유스케이스나 엔티티가 외부 요소(예: 데이터베이스, 웹 API, 사용자 인터페이스)와 소통하기 위한 계약을 정의합니다. 클린 아키텍처에서 모든 의존성은 외부에서 내부로 향합니다. 따라서 구체적인 구현(어댑터)은 이러한 인터페이스에 의존하며, 핵심 비즈니스 로직(엔티티와 유스케이스)은 안정된 인터페이스에만 의존합니다. 이는 의존성 역전 원칙의 직접적인 적용입니다.

구성 요소

설명

책임

변경 빈도

엔티티

핵심 비즈니스 객체

비즈니스 규칙과 상태 캡슐화

매우 낮음

유스케이스

애플리케이션별 비즈니스 로직

특정 시나리오의 작업 흐름 조정

낮음

인터페이스

외부 세계와의 계약

상호작용을 위한 메서드 시그니처 정의

중간

3. 헥사고날 아키텍처의 핵심 개념

헥사고날 아키텍처는 앨리스터 콕번이 제안한 아키텍처 패턴으로, 애플리케이션의 핵심 로직을 외부 요소로부터 분리하는 데 초점을 맞춘다. 이 패턴은 애플리케이션을 중앙의 내부 영역과 이를 둘러싼 외부 영역으로 구성하며, 포트와 어댑터라는 개념을 통해 두 영역이 상호작용하는 방식을 정의한다.

내부 영역은 비즈니스 규칙과 핵심 로직을 포함한다. 이 영역은 데이터베이스, 사용자 인터페이스, 외부 API와 같은 외부 세부사항에 대해 전혀 알지 못한다. 대신, 내부 영역은 필요한 기능을 포트라는 추상화된 인터페이스를 통해 선언한다. 예를 들어, '데이터 저장'이라는 행위는 UserRepositoryPort와 같은 인터페이스로 정의된다. 외부 영역은 데이터베이스, 웹 프레임워크, 메시지 큐 등과 같은 구체적인 기술과 도구로 구성된다. 외부 영역의 구성 요소는 내부 영역이 정의한 포트를 구현하는 어댑터의 형태를 띤다. 데이터베이스에 접근하는 JpaUserRepositoryAdapter나 REST API를 제공하는 WebControllerAdapter가 어댑터의 예시이다.

이 구조의 핵심은 의존성 방향이 항상 외부에서 내부를 향한다는 점이다. 어댑터는 포트에 의존하지만, 내부 영역은 어떤 어댑터에도 의존하지 않는다. 이는 의존성 역전 원칙의 직접적인 적용이다. 결과적으로 애플리케이션은 외부 기술로부터 완전히 독립된 핵심을 가지게 되며, 웹, CLI, 테스트 등 다양한 방식으로 애플리케이션에 접근할 수 있는 다수의 어댑터를 둘러싸는 '육각형' 형태를 그리게 된다. 이 모양에서 헥사고날(육각형) 아키텍처라는 이름이 유래했다.

구성 요소

설명

예시

포트

내부 영역이 외부와 통신하기 위해 제공하는 추상 인터페이스

OrderRepository, PaymentNotificationPort

어댑터

포트를 구현하여 내부 영역과 외부 기술을 연결하는 구체 클래스

MySQLOrderRepositoryAdapter, KafkaNotificationAdapter

내부 영역

비즈니스 엔티티와 유스케이스로 구성된 애플리켍션 핵심

주문 생성, 결제 처리 로직

외부 영역

데이터베이스, UI, 외부 서비스 등 구체적인 기술 구현체

PostgreSQL, Spring MVC 컨트롤러, SMTP 클라이언트

3.1. 포트와 어댑터

헥사고날 아키텍처의 핵심 구성 요소는 포트와 어댑터이다. 이 패턴은 때로 포트와 어댑터 아키텍처로 불리기도 한다. 이 개념은 시스템을 내부의 순수한 비즈니스 로직과 외부 세계와의 상호작용을 분리하는 데 목적이 있다.

포트는 애플리케이션의 내부 영역이 외부와 통신하기 위해 제공하는 추상적인 인터페이스 또는 계약이다. 이는 주로 인터페이스나 추상 클래스의 형태로 정의된다. 포트는 '무엇을' 해야 하는지(예: 데이터 저장, 외부 API 호출)를 정의하지만, '어떻게' 수행할지는 명시하지 않는다. 예를 들어, UserRepositoryPort는 사용자 데이터를 저장하고 조회하는 메서드 시그니처만을 선언한다.

어댑터는 포트에 정의된 계약을 실제로 구현하는 구성 요소이다. 어댑터는 외부 세계(예: 데이터베이스, 웹 프레임워크, 메시지 큐)에 대한 구체적인 기술적 세부 사항을 캡슐화한다. 어댑터는 두 가지 유형으로 구분된다.

* 주도형(Driving) 어댑터: 외부에서 애플리케이션의 내부로 요청을 전달한다. 예를 들어, 웹 컨트롤러나 CLI 명령어 핸들러가 이에 해당한다.

* 피동형(Driven) 어댑터: 애플리케이션 내부의 요청에 의해 외부 시스템을 호출한다. 예를 들어, MySQL 데이터베이스에 접근하는 리포지토리 구현체나 SMTP를 통해 이메일을 발송하는 서비스 구현체가 이에 해당한다.

이 구조의 핵심은 의존성 방향이 항상 내부 영역을 향한다는 점이다. 어댑터는 포트 인터페이스에 의존하며, 내부 영역의 비즈니스 로직은 구체적인 어댑터 구현에 대해 전혀 알지 못한다. 이는 의존성 역전 원칙의 직접적인 적용이다. 결과적으로, 데이터베이스를 MongoDB에서 PostgreSQL로 변경하거나, 웹 프레임워크를 Spring에서 다른 것으로 교체해야 할 때, 내부의 핵심 로직을 수정하지 않고 해당 포트에 맞는 새로운 어댑터를 구현하여 교체하기만 하면 된다.

3.2. 내부 영역과 외부 영역

헥사고날 아키텍처는 애플리케이션을 내부 영역과 외부 영역으로 명확히 구분하는 것을 핵심으로 삼는다. 내부 영역은 비즈니스 로직과 도메인 모델을 포함하는 애플리케이션의 핵심이다. 이 영역은 외부 세계의 변화, 예를 들어 데이터베이스, 웹 프레임워크, 사용자 인터페이스, 외부 API와 같은 기술적 세부사항으로부터 완전히 독립적이다. 내부 영역의 코드는 순수한 도메인 지식과 규칙만을 표현하며, 외부에 대한 어떠한 의존성도 가지지 않는다.

반면 외부 영역은 애플리케이션을 둘러싸고 있는 모든 기술적 인프라와 세부 구현을 말한다. 데이터베이스, 웹 서버, UI 프레임워크, 외부 메시징 시스템 등이 여기에 속한다. 외부 영역의 구성 요소들은 내부 영역이 정의한 포트를 통해 애플리케이션과 상호작용한다. 이때 외부 영역의 구체적인 구현체를 어댑터라고 부른다. 예를 들어, 내부 영역이 "데이터를 저장한다"는 추상적인 포트를 정의하면, 외부 영역의 MySQL 어댑터나 MongoDB 어댑터가 이를 구체적으로 구현한다.

이러한 분리의 가장 큰 이점은 의존성 방향이 항상 외부에서 내부를 향한다는 점이다. 즉, 외부 영역(어댑터)이 내부 영역의 포트에 의존하며, 그 반대는 성립하지 않는다. 이 규칙 덕분에 내부의 핵심 비즈니스 로직은 외부 기술의 변경이나 교체에 영향을 받지 않는다. 데이터베이스를 오라클에서 PostgreSQL로 변경하거나, 웹 프레임워크를 스프링에서 다른 것으로 전환하더라도 내부 영역의 코드는 단 한 줄도 수정할 필요가 없다. 필요한 것은 새로운 기술에 맞는 어댑터를 외부 영역에 구현하는 것뿐이다.

내부와 외부의 경계는 인터페이스나 추상 클래스로 정의된 포트를 통해 명시적으로 드러난다. 이 경계를 넘나드는 모든 통신은 이러한 포트를 통해서만 이루어지며, 이는 시스템의 진입점(입력)과 출구(출력)를 구조화한다. 결과적으로 애플리케이션은 외부 요소들로부터 보호받는 강력한 핵심을 갖게 되며, 이는 테스트 용이성과 유지보수성을 극대화하는 기반이 된다.

4. 두 아키텍처의 비교

두 아키텍처는 소프트웨어 아키텍처에서 핵심 비즈니스 로직을 보호하고 외부 변화에 유연하게 대응하기 위해 고안된 패턴이다. 둘 다 의존성 역전 원칙을 근간으로 하여, 고수준의 정책이 저수준의 세부사항에 의존하지 않도록 설계한다. 이로 인해 테스트 용이성과 유지보수성이 크게 향상된다는 공통된 이점을 가진다. 또한, 둘 다 도메인 중심 설계를 지향하며, 도메인 모델이 외부 프레임워크나 데이터베이스와 같은 인프라로부터 격리되는 구조를 지닌다.

주요 차이점은 구조의 표현 방식과 세부적인 구성 요소에 있다. 클린 아키텍처는 동심원 계층 구조를 사용하여 의존성 방향을 시각적으로 명확히 보여준다. 가장 안쪽의 엔티티부터 바깥쪽의 프레임워크와 드라이버까지, 의존성은 항상 안쪽을 향한다. 반면, 헥사고날 아키텍처는 육각형 모양으로 애플리케이션 코어를 중심에 두고, 주변에 다양한 포트와 어댑터를 배치하는 방식으로 개념을 표현한다. 이는 인바운드(사용자 요청)와 아웃바운드(데이터베이스 호출) 어댑터를 대칭적으로 다루는 데 초점을 맞춘다.

구성 요소의 명칭과 세부 분류에서도 차이가 나타난다. 클린 아키텍처는 유스케이스를 비즈니스 규칙의 한 층으로 명시적으로 분리하여, 시스템이 수행할 수 있는 특정 작업을 중점적으로 모델링한다. 헥사고날 아키텍처에서는 '애플리케이션 코어' 또는 '도메인'이라는 더 포괄적인 용어를 사용하며, 포트를 통해 외부와의 모든 상호작용 계약을 정의한다. 따라서 헥사고날 아키텍처는 구조적 표현이 더 단순하고 실용적이라면, 클린 아키텍처는 이론적 계층을 더 세분화하여 설명한다.

비교 항목

클린 아키텍처

헥사고날 아키텍처

구조 모델

동심원 계층

육각형(헥사곤)

핵심 구성 요소

엔티티, 유스케이스, 인터페이스, 프레임워크

애플리케이션 코어(도메인), 포트, 어댑터

의존성 방향

안쪽 원칙(의존성 규칙)

안쪽으로(코어는 외부에 의존하지 않음)

주요 초점

계층 간 의존성과 추상화 수준

포트를 통한 외부 시스템과의 명확한 인터페이스

시각적 표현

추상적이고 이론적

실용적이고 대칭적

결론적으로, 두 패턴은 본질적으로 동일한 목표를 공유하지만, 클린 아키텍처가 보다 포괄적인 아키텍처 원칙과 계층을 제시한다면, 헥사고날 아키텍처는 포트-어댑터 모델에 특화된 보다 구체적인 구현 패턴에 가깝다. 많은 현대의 애플리케이션은 이 두 아이디어를 혼합하여 사용한다.

4.1. 공통점

두 아키텍처는 소프트웨어 설계의 근본적인 목표를 공유하며, 이를 달성하기 위한 유사한 구조적 원칙을 제시한다.

가장 핵심적인 공통점은 의존성의 방향을 비즈니스 로직 중심으로 수렴시키는 것이다. 클린 아키텍처의 의존성 규칙과 헥사고날 아키텍처의 포트를 통한 접근은 모두 외부의 구체적인 기술(예: 데이터베이스, 웹 프레임워크, UI)로부터 핵심 비즈니스 로직을 보호하고 독립시키는 것을 목표로 한다. 이로 인해 두 방식 모두 도메인 모델이 외부 변경에 영향을 받지 않도록 설계된다.

또한, 둘 다 명확한 경계를 통해 시스템을 영역으로 구분한다. 클린 아키텍처는 동심원 계층으로, 헥사고날 아키텍처는 육각형 내부와 외부로 영역을 나눈다. 이 구분은 다음과 같은 공통 이점을 제공한다.

공통 이점

설명

테스트 용이성

비즈니스 로직을 외부 인프라 없이 격리하여 단위 테스트하기 용이하다.

기술 독립성

핵심 로직이 특정 프레임워크나 라이브러리에 종속되지 않아 기술 스택 변경이 상대적으로 쉽다.

유지보수성

관심사의 분리로 인해 코드의 변경이 특정 영역에 국한되어 이해하고 수정하기 편리하다.

결국 두 패턴 모두 변화에 유연하고 장기적으로 지속 가능한 소프트웨어를 만들기 위한 전략으로, 비즈니스 가치를 구현하는 도메인 코드를 시스템의 가장 안정된 중심에 위치시킨다는 철학을 공유한다.

4.2. 차이점

두 아키텍처는 근본적인 목표를 공유하지만, 개념을 표현하는 방식과 세부적인 구조에서 차이를 보인다.

가장 큰 차이는 아키텍처를 묘사하는 시각적 은유에 있다. 클린 아키텍처는 동심원을 사용하여 의존성 방향을 강조하는 반면, 헥사고날 아키텍처는 육각형 모양으로 포트와 어댑터의 연결 구조를 시각화한다. 이는 헥사고날 아키텍처가 외부 시스템과의 상호작용에 보다 명시적 초점을 맞추고 있음을 의미한다. 또한, 클린 아키텍처는 엔티티, 유스케이스 등 계층의 명칭을 보다 추상적인 비즈니스 용어로 정의하는 경향이 있다.

구조적 측면에서도 차이가 존재한다. 헥사고날 아키텍처는 '포트'와 '어댑터'라는 구체적인 구성 요소를 명시적으로 정의하여, 애플리케이션이 외부 세계에 제공하거나 필요로 하는 모든 인터페이스를 포트로 규정한다. 반면 클린 아키텍처는 인터페이스 계층을 포함한 각 계층의 책임은 설명하지만, 포트와 같은 특정 메커니즘에 대한 명칭을 강제하지는 않는다. 이는 클린 아키텍처가 보다 높은 수준의 원칙과 규칙을 제시하는 지침에 가깝다는 점을 시사한다.

비교 항목

클린 아키텍처

헥사고날 아키텍처

주요 은유

동심원

육각형 (포트와 어댑터)

강조점

의존성 규칙과 계층 간 경계

애플리케이션 코어와 외부 에이전시의 명확한 분리

핵심 구성 요소

엔티티, 유스케이스, 컨트롤러, 게이트웨이 등

포트, 어댑터 (주/부), 애플리케이션 코어

특성

보다 추상적이고 원칙 중심의 패턴

보다 구체적이고 구현 친화적인 패턴

결론적으로, 헥사고날 아키텍처는 클린 아키텍처의 원칙을 구체화하고 실용적으로 해석한 하나의 구현체로 볼 수 있다. 두 방식 모두 비즈니스 로직의 격리와 테스트 용이성을 추구하지만, 클린 아키텍처가 설계 철학에 더 무게를 둔다면, 헥사고날 아키텍처는 그 철학을 적용하기 위한 실질적인 구조와 용어를 제공한다.

5. 설계 원칙과 이점

클린 아키텍처와 헥사고날 아키텍처는 비즈니스 로직의 독립성을 보장하는 설계 원칙을 통해 몇 가지 공통된 핵심 이점을 제공한다. 이러한 이점은 소프트웨어의 장기적인 생명력과 품질을 결정짓는 중요한 요소들이다.

가장 두드러진 이점은 테스트 용이성이다. 핵심 비즈니스 로직이 외부 프레임워크나 인프라로부터 격리되어 있기 때문에, 단위 테스트를 작성하기가 매우 수월해진다. 데이터베이스나 API 같은 외부 의존성 없이도 순수한 도메인 로직을 검증할 수 있다. 이는 테스트 실행 속도를 높이고, 테스트 환경 구성을 단순화하며, 결과적으로 더 안정적인 소프트웨어를 만드는 데 기여한다.

다음으로 중요한 이점은 유지보수성과 기술 독립성이다. 비즈니스 규칙은 가장 안정적인 부분으로, 외부 요소의 변경에 영향을 받지 않도록 설계된다. 이는 데이터베이스를 MySQL에서 MongoDB로 변경하거나, 웹 프레임워크를 교체해야 할 때, 핵심 코드를 수정하지 않고도 적응할 수 있음을 의미한다. 의존성 방향이 외부에서 내부를 향하기 때문에, 새로운 기술을 도입하거나 기존 기술을 업그레이드하는 작업이 시스템 전반에 걸친 파급 효과를 최소화하면서 수행될 수 있다.

이러한 설계는 궁극적으로 시스템의 응집도를 높이고 결합도를 낮추는 효과를 가져온다. 각 계층이나 영역이 명확한 책임을 가지며, 변경이 발생할 때 그 영향을 국지적으로 제한할 수 있다. 결과적으로 코드의 가독성이 향상되고, 새로운 기능 추가나 버그 수정이 더 예측 가능해지며, 개발 팀의 생산성을 장기적으로 유지하는 데 기여한다[2].

5.1. 테스트 용이성

클린 아키텍처와 헥사고날 아키텍처는 모두 핵심 비즈니스 로직을 외부 요소로부터 격리하여 테스트 용이성을 크게 향상시킨다. 핵심 로직은 프레임워크, 데이터베이스, 사용자 인터페이스, 외부 API와 같은 구체적인 구현 세부사항에 의존하지 않는다. 따라서 도메인 로직을 테스트할 때 이러한 외부 의존성을 실제로 구동하지 않고도 모의 객체나 스텁을 통해 쉽게 대체할 수 있다. 이는 빠르고 안정적인 단위 테스트 작성에 결정적인 이점을 제공한다.

이러한 아키텍처는 테스트를 위한 명확한 경계를 제공한다. 예를 들어, 유스케이스나 도메인 서비스를 테스트할 때 실제 데이터베이스에 연결하거나 HTTP 요청을 보낼 필요가 없다. 대신, 해당 컴포넌트가 의존하는 포트나 인터페이스에 대한 가짜 구현을 주입하여 순수하게 비즈니스 규칙의 정확성만을 검증할 수 있다. 이는 테스트의 실행 속도를 획기적으로 높이고, 테스트 환경 구성의 복잡성을 줄인다.

테스트 유형

설명

아키텍처의 이점

단위 테스트

개별 컴포넌트(엔티티, 유스케이스)의 고립된 테스트

외부 의존성 없이 핵심 로직만을 빠르게 테스트 가능

통합 테스트

여러 컴포넌트 간의 상호작용 테스트

어댑터와 인프라스트럭처 계층을 실제 구현으로 교체하여 테스트 가능

엔드투엔드 테스트

전체 시스템의 사용자 시나리오 테스트

외부 영역의 실제 구성 요소를 통해 전체 흐름 검증 가능

결과적으로, 애플리케이션의 가장 중요한 부분인 비즈니스 규칙에 대한 테스트 커버리지를 높이고 신뢰성을 확보하는 동시에, 테스트 피드백 루프를 짧게 유지하여 개발 생산성을 향상시킨다. 테스트가 용이한 설계는 결국 코드의 품질과 변경에 대한 안정성을 보장하는 근간이 된다.

5.2. 유지보수성

클린 아키텍처와 헥사고날 아키텍처는 모두 유지보수성을 크게 향상시키는 것을 주요 목표로 삼는다. 이는 비즈니스 로직과 외부 프레임워크, 데이터베이스, UI와 같은 세부 사항을 명확히 분리함으로써 달성된다. 핵심 도메인 코드는 외부 변화에 영향을 받지 않도록 설계되므로, 데이터베이스를 교체하거나 웹 프레임워크를 업그레이드하는 등의 변경이 발생하더라도 애플리케이션의 중심부를 수정할 필요가 거의 없다. 이는 변경의 영향을 국소화하여 시스템 전체를 이해하고 수정하는 데 드는 비용과 시간을 줄인다.

또한, 명확한 계층 구조와 의존성 규칙은 코드베이스의 구조를 직관적으로 만들어준다. 새로운 개발자가 프로젝트에 합류했을 때, 비즈니스 규칙이 어디에 위치하는지, 외부 시스템과의 통신은 어떻게 이루어지는지를 빠르게 파악할 수 있다. 이는 팀의 생산성을 높이고, 지식이 특정 인원에게 집중되는 것을 방지한다. 모듈 간의 결합도가 낮기 때문에, 한 모듈을 수정할 때 다른 모듈에 대한 부작용을 걱정할 필요가 적어지며, 이는 코드 변경을 더 안전하고 예측 가능하게 만든다.

측면

유지보수성 향상 효과

변경 용이성

데이터베이스, UI, 외부 서비스 변경 시 핵심 로직 수정 최소화

가독성

명확한 계층 구조로 코드 흐름과 책임 소재 파악 용이

결합도 감소

모듈 간 의존성이 낮아 한 부분의 수정이 다른 부분에 미치는 영향 최소화

기술 부채 관리

핵심 도메인이 프레임워크에 종속되지 않아 기술 스택 교체 비용 감소

장기적으로 볼 때, 이러한 아키텍처는 기술 부채의 누적을 효과적으로 관리하도록 돕는다. 프레임워크나 라이브러리의 구버전에 갇히거나, 특정 벤더의 기술에 깊이 종속되는 상황을 피할 수 있다. 핵심 비즈니스 로직은 순수하게 유지되므로, 새로운 요구사항이 발생하거나 시장 변화에 대응해야 할 때, 기존 코드를 재사용하거나 확장하는 것이 상대적으로 수월해진다. 결과적으로 애플리케이션의 수명 주기를 연장하고 전체적인 소유 비용을 낮추는 데 기여한다.

5.3. 기술 독립성

클린 아키텍처와 헥사고날 아키텍처는 핵심 비즈니스 로직이 특정 기술이나 프레임워크에 종속되지 않도록 설계하는 것을 주요 목표로 삼는다. 이는 의존성 역전 원칙을 통해 실현되며, 핵심 로직은 추상화된 인터페이스에만 의존하고, 구체적인 기술 구현체는 외부 계층에서 이 인터페이스를 구현하는 방식으로 구성된다.

이러한 설계는 기술 스택의 변경이나 업그레이드에 매우 유연하게 대응할 수 있게 해준다. 예를 들어, 데이터베이스를 MySQL에서 MongoDB로 변경하거나, 웹 프레임워크를 교체해야 하는 경우, 핵심 도메인 코드는 전혀 수정할 필요가 없다. 변경 사항은 해당 기술을 구현한 외부 어댑터 계층만 수정하면 반영된다. 이는 장기적인 프로젝트에서 기술 부채를 줄이고, 새로운 기술 도입을 용이하게 만든다.

아키텍처 구성 요소

기술 의존성

변경 영향 범위

엔티티, 유스케이스 (핵심 비즈니스 규칙)

독립적

영향 없음

인터페이스 (포트)

독립적

영향 없음

컨트롤러, 게이트웨이, 리포지토리 구현체 (어댑터)

의존적

해당 구현체만 수정

결과적으로 애플리케이션의 가장 가치 있는 부분인 비즈니스 규칙은 외부 변화로부터 보호받으며, 인프라나 UI와 같은 세부사항은 플러그인처럼 교체 가능한 구성 요소가 된다. 이는 소프트웨어의 수명을 연장하고, 팀이 비즈니스 요구사항에 더 집중할 수 있는 환경을 제공한다.

6. 구현 패턴과 예시

구현 시 핵심은 의존성 주입을 통해 고수준의 비즈니스 로직이 저수준의 세부 사항에 의존하지 않도록 구성하는 것이다. 의존성 역전 원칙을 적용하여, 도메인 계층에서 필요한 인터페이스를 정의하고, 인프라스트럭처 계층에서 이를 구현하는 어댑터를 제공하는 구조가 일반적이다. 예를 들어, 데이터 저장소에 접근하는 리포지토리 인터페이스는 도메인 계층에 위치시키고, 실제 데이터베이스 연동 코드는 외부 계층의 어댑터로 구현한다.

프레임워크 선택은 중요한 결정 요소이다. 스프링 프레임워크나 마이크로소프트 닷넷 코어와 같이 강력한 의존성 주입 컨테이너를 제공하는 프레임워크는 이러한 아키텍처 구현을 용이하게 한다. 그러나 프레임워크 자체에 대한 의존성을 애플리케이션의 핵심 계층으로 침투시키지 않도록 주의해야 한다. 프레임워크 관련 코드(예: 어노테이션, 특정 클래스 상속)는 주로 외부의 프레젠테이션 계층이나 인프라스트럭처 계층의 구성 모듈에 한정시키는 것이 바람직하다.

구체적인 코드 구조는 다음과 같은 패턴을 따른다.

계층/디렉토리

주요 책임

예시 컴포넌트

엔티티/도메인

핵심 비즈니스 규칙과 데이터를 캡슐화

User, Order, Product

유스케이스/애플리케이션

애플리케이션 특정 비즈니스 규칙 조정

CreateOrderService, SendNotificationUseCase

인터페이스 어댑터

외부 세계와의 데이터 변환

UserController(REST API), DatabaseRepositoryImpl

프레임워크/드라이버

도구와 프레임워크의 세부 사항

Main 클래스, SpringBootApplication 설정

이 구조에서 컨트롤러는 HTTP 요청을 받아 유스케이스를 호출하고, 유스케이스는 도메인 엔티티와 리포지토리 인터페이스를 통해 로직을 수행한다. 실제 데이터베이스 접근을 담당하는 JpaRepositoryImpl 같은 클래스는 가장 바깥쪽 계층에 위치하며, 런타임에 의존성 주입을 통해 내부 계층에 연결된다. 이로써 비즈니스 로직은 데이터베이스 기술이 MySQL에서 MongoDB로 변경되더라도 영향을 받지 않게 된다.

6.1. 프레임워크 선택

클린 아키텍처와 헥사고날 아키텍처는 핵심 비즈니스 로직이 특정 프레임워크나 라이브러리에 의존하지 않도록 설계하는 것을 목표로 한다. 따라서 프레임워크 선택은 외부 영역의 구현 세부사항으로 취급되며, 핵심 로직을 침범해서는 안 된다.

프레임워크는 주로 인프라스트럭처 계층이나 외부 영역의 어댑터를 구현하는 데 사용된다. 예를 들어, 웹 프레임워크는 컨트롤러 어댑터를, ORM 라이브러리는 데이터 액세스 어댑터를 구성하는 데 활용된다. 핵심 도메인 모델은 이러한 프레임워크의 구체적인 클래스나 어노테이션을 직접 참조하지 않는다.

이러한 접근 방식은 다음과 같은 이점을 제공한다.

이점

설명

기술 스택 교체 용이성

비즈니스 규칙이 프레임워크에 묶이지 않으므로, 새로운 프레임워크로의 전환이 비교적 수월해진다.

프레임워크 업그레이드 리스크 감소

프레임워크의 주요 버전 변경이 핵심 로직에 미치는 영향을 최소화할 수 있다.

테스트 용이성

실제 프레임워크 없이도 핵심 로직을 단위 테스트할 수 있다.

프레임워크를 선택할 때는 의존성 방향을 고려해야 한다. 의존성은 항상 프레임워크에서 애플리케이션의 내부 영역을 향해야 하며, 그 반대가 되어서는 안 된다. 의존성 주입 컨테이너를 사용하더라도, 설정 코드는 애플리케이션의 가장 바깥쪽 계층에 위치시켜 의존성 규칙을 준수해야 한다.

6.2. 의존성 주입

의존성 주입은 클린 아키텍처 및 헥사고날 아키텍처에서 핵심적인 의존성 역전 원칙을 실현하는 구체적인 구현 기법이다. 이 패턴은 객체가 자신이 필요로 하는 의존성(서비스나 객체)을 직접 생성하거나 찾지 않고, 외부로부터 주입받도록 설계하는 것을 의미한다. 주로 생성자 주입, 세터 주입, 인터페이스 주입 등의 방식으로 구현되며, 이를 통해 결합도를 낮추고 테스트 용이성을 극대화할 수 있다.

이 아키텍처에서 의존성 주입은 고수준의 비즈니스 로직(내부 영역)이 저수준의 세부 사항(외부 영역)에 직접 의존하는 것을 방지하는 데 필수적이다. 예를 들어, 유스케이스는 데이터 저장소에 접근하기 위해 구체적인 데이터베이스나 API 클래스를 참조하지 않고, 추상화된 저장소 인터페이스(포트)에만 의존한다. 애플리케이션 실행 시점(런타임)에 외부 영역의 구체적인 어댑터(예: MySQL 리포지토리 구현체)가 해당 인터페이스를 통해 내부 영역에 주입된다.

의존성 주입을 효과적으로 관리하기 위해 의존성 주입 컨테이너나 IoC 컨테이너를 사용하는 것이 일반적이다. 이러한 컨테이너는 객체의 생성과 생명주기, 의존 관계 설정을 중앙에서 관리한다. 널리 사용되는 프레임워크로는 스프링 프레임워크의 ApplicationContext, Google Guice, .NET Core의 내장 DI 컨테이너 등이 있다. 이들의 사용은 설정의 편의성을 높이고, 애플리케이션의 구성 요소를 유연하게 교체할 수 있게 한다.

주입 방식

설명

장점

생성자 주입

의존성을 클래스의 생성자 매개변수를 통해 전달한다.

객체 생성 시 모든 의존성이 확보되어 불변성을 보장하며, 테스트가 용이하다.

세터 주입

의존성을 공개된 세터 메서드를 통해 설정한다.

의존성을 나중에 변경할 수 있어 유연성이 높다.

인터페이스 주입

의존성 주입을 위한 전용 인터페이스를 정의한다.

주입 메커니즘을 명시적으로 정의할 수 있다.

의존성 주입을 적용하면 비즈니스 로직은 구체적인 구현으로부터 완전히 분리된다. 결과적으로 단위 테스트 시 실제 데이터베이스나 외부 서비스 대신 모의 객체(Mock)나 스텁(Stub)을 쉽게 주입하여 로직만을 격리하여 검증할 수 있다. 이는 테스트 주도 개발과도 잘 조화를 이루며, 궁극적으로 시스템의 변경과 진화에 더욱 민첩하게 대응할 수 있는 기반을 마련해 준다.

7. 적용 시 고려사항

클린 아키텍처와 헥사고날 아키텍처는 많은 이점을 제공하지만, 실제 프로젝트에 적용할 때는 몇 가지 고려해야 할 사항이 존재한다. 가장 큰 고려사항은 초기 복잡성의 증가이다. 전통적인 계층형 아키텍처에 비해 더 많은 인터페이스, 의존성 주입 설정, 추상화 계층을 정의해야 하므로, 소규모이거나 요구사항이 단순한 프로젝트에서는 과도한 설계가 될 수 있다. 개발 팀 구성원이 이러한 아키텍처의 철학과 규칙을 충분히 이해하지 못하면, 오히려 코드 구조를 더 복잡하게 만들거나 의도된 의존성 방향을 위반하는 실수를 범할 위험이 있다.

적용하려는 프로젝트의 규모와 성격을 신중히 평가하는 것이 중요하다. 장기적으로 유지보수되고 비즈니스 로직이 복잡한 엔터프라이즈 애플리케이션, 또는 외부 시스템(데이터베이스, 메시징 큐, 외부 API 등)과의 결합을 느슨하게 유지해야 하는 시스템에서는 그 가치가 매우 크다. 반면, 단기 프로토타입, 간단한 CRUD 위주의 애플리케이션, 또는 소규모 스타트업의 초기 제품에서는 오버헤드가 이익을 상쇄할 수 있다. 아키텍처의 엄격한 계층 분리는 때로는 간단한 작업을 수행하기 위해 여러 파일을 수정해야 하는 상황을 만들기도 한다.

성공적인 적용을 위해서는 팀 내 합의와 교육이 선행되어야 한다. 모든 개발자가 의존성 규칙과 같은 핵심 원칙을 이해하고 준수하도록 해야 한다. 또한, 프레임워크나 인프라에 대한 의존성을 핵심 도메인으로부터 분리하는 과정에서 발생할 수 있는 성능 오버헤드에 대한 고려도 필요하다. 적절한 상황에서 선택적으로 적용하거나, 핵심 모듈에만 점진적으로 도입하는 접근법이 효과적일 수 있다.

7.1. 복잡성 증가

클린 아키텍처와 헥사고날 아키텍처를 도입하는 주요 목적은 장기적인 유지보수성과 유연성을 확보하는 것이지만, 이러한 이점은 초기 설계와 구현의 복잡성 증가라는 비용을 수반한다.

가장 명확한 복잡성은 계층 구조와 추상화의 증가에서 비롯된다. 도메인 로직을 외부 프레임워크나 인프라로부터 분리하기 위해 여러 계층(예: 엔티티, 유스케이스, 인터페이스 어댑터)을 정의하고, 이들 사이의 의존성 방향을 엄격히 관리해야 한다. 또한 외부 세계와의 모든 상호작용은 포트와 어댑터를 통해 이루어지도록 설계해야 하므로, 간단한 기능 하나를 구현하더라도 더 많은 인터페이스와 클래스를 생성하게 된다. 이는 소규모이거나 프로토타입 프로젝트에서는 과도한 설계로 비칠 수 있다.

이러한 구조적 복잡성은 학습 곡선과 팀 협업에 영향을 미친다. 모든 개발자가 의존성 규칙과 같은 핵심 원칙을 이해하고 준수해야 하며, 새로운 팀원은 코드베이스의 구조를 파악하는 데 더 많은 시간이 필요하다. 또한 비즈니스 로직이 분산되지 않고 적절한 계층에 위치하도록 지속적인 주의가 요구되며, 이를 지키지 않을 경우 아키텍처의 본래 목적이 훼손될 수 있다. 결국, 아키텍처의 이점을 실현하기 위해서는 초기 투자와 팀 전체의 일관된 노력이 필요하다.

7.2. 적용 프로젝트 규모

클린 아키텍처와 헥사고날 아키텍처는 프로젝트 규모에 따라 그 효용성이 달라진다. 소규모의 단순한 프로젝트, 예를 들어 소수의 엔드포인트만을 가진 마이크로서비스나 간단한 유틸리티 애플리케이션에서는 이러한 아키텍처의 도입이 과도한 설계와 복잡성을 초래할 수 있다. 이 경우, 비즈니스 로직이 거의 없거나 빠른 프로토타이핑이 목표라면 더 간결한 구조를 선택하는 것이 효율적이다.

중규모 이상의 프로젝트, 특히 비즈니스 로직이 복잡하고 장기적인 유지보수와 확장이 요구되는 애플리케이션에서 이 아키텍처들의 진가를 발휘한다. 도메인 규칙이 풍부하고, 외부 시스템(데이터베이스, 외부 API, UI 프레임워크)과의 결합을 느슨하게 유지해야 할 필요가 있을 때 적합하다. 대규모 모놀리식 애플리케이션을 모듈화하거나, 여러 팀이 협업하는 환경에서 각 팀의 독립성을 보장하는 데도 효과적이다.

적용 여부를 결정할 때는 프로젝트의 예상 수명 주기와 변화의 빈도를 고려해야 한다. 요구사항이 자주 변경되거나, 기술 스택의 교체 가능성을 염두에 둔 프로젝트라면 초기 투자 비용을 감수하고 적용하는 것이 장기적으로 유리하다. 반면, 단기간 내에 완성되어 이후 큰 변경이 예상되지 않는 프로젝트에서는 적용의 이점이 상대적으로 작을 수 있다.

프로젝트 규모/특성

아키텍처 적용 적합성

주요 고려사항

소규모/단순 프로젝트

낮음

과도한 설계(Over-engineering) 위험

중규모/복잡한 비즈니스 로직

높음

유지보수성, 테스트 용이성 확보에 유리

대규모/장기 프로젝트

매우 높음

모듈화, 팀 간 독립적 개발, 기술 스택 교체 대응

프로토타입 또는 개념 검증(PoC)

낮음

개발 속도와 간결성이 더 우선시됨

결론적으로, 이러한 아키텍처는 규모와 복잡성이 증가함에 따라 그 가치가 선형적으로 증가하는 경향을 보인다. 설계 결정은 항상 프로젝트의 구체적인 맥락과 비용 대비 편익 분석을 바탕으로 이루어져야 한다.

8. 관련 아키텍처 패턴

클린 아키텍처와 헥사고날 아키텍처와 유사한 목적과 철학을 공유하는 다른 소프트웨어 설계 패턴들이 존재합니다. 대표적으로 Onion 아키텍처와 DCI 패턴이 있으며, 이들은 모두 관심사의 분리와 핵심 비즈니스 로직의 보호를 강조합니다.

Onion 아키텍처는 제프리 팔레르모가 제안한 패턴으로, 이름처럼 양파의 겹겹이 쌓인 계층 구조를 모델로 합니다. 가장 안쪽의 핵심에는 도메인 모델과 도메인 서비스가 위치하며, 그 바깥으로 애플리케이션 서비스, 인프라스트럭처 계층이 순차적으로 감싸는 형태를 가집니다. 핵심 규칙은 의존성 방향이 항상 안쪽으로 향한다는 점입니다. 즉, 외부 계층은 내부 계층에 의존할 수 있지만, 그 반대는 허용되지 않습니다. 이는 클린 아키텍처의 의존성 규칙과 본질적으로 동일한 개념으로, 데이터베이스나 UI와 같은 외부 세부사항이 핵심 비즈니스 규칙에 영향을 미치지 못하도록 보장합니다.

DCI 패턴은 데이터, 콘텍스트, 상호작용의 약자로, 시스템을 세 가지 주요 관점으로 분리합니다. 데이터는 시스템의 상태를 나타내는 도메인 객체를 의미합니다. 콘텍스트는 특정 사용자 시나리오나 유스케이스를 실행하기 위해 필요한 객체들을 함께 묶는 역할을 합니다. 상호작용은 콘텍스트 내에서 데이터 객체들이 수행하는 역할 기반의 행동을 정의합니다. DCI의 주요 목적은 객체지향 설계에서 흔히 발생하는 비즈니스 로직이 여러 클래스에 분산되는 문제를 해결하고, 특정 시나리오의 실행 흐름을 한눈에 이해하기 쉽게 만드는 데 있습니다. 이는 클린 아키텍처의 유스케이스를 명시적으로 구현하는 방식과 정신적으로 연결됩니다.

이들 패턴과의 관계는 다음 표로 요약할 수 있습니다.

패턴

주요 초점

클린/헥사고날 아키텍처와의 관계

Onion 아키텍처

계층적 의존성 방향 (안쪽으로)

구조적 관점에서 매우 유사하며, 클린 아키텍처의 구체적인 구현 모델 중 하나로 간주됨

DCI 패턴

런타임 상호작용과 역할 모델링

행위적 관점을 보완하며, 유스케이스 구현 내에서 객체 간 협력 방식을 구조화하는 데 활용 가능

따라서 이러한 패턴들은 상호 배타적이기보다는 상호 보완적으로 적용될 수 있습니다. 예를 들어, Onion 아키텍처로 전체 계층 구조를 정의한 후, 애플리케이션 서비스 계층 내에서 특정 유스케이스를 구현할 때 DCI의 개념을 차용할 수 있습니다.

8.1. Onion 아키텍처

Onion 아키텍처는 제프리 팔레르노(Jeffrey Palermo)가 2008년에 제안한 소프트웨어 설계 패턴이다. 이 아키텍처는 이름처럼 의존성의 방향이 양파의 겹쳐진 층처럼 안쪽으로 향하는 구조를 가진다. 핵심 비즈니스 로직을 중앙에 두고, 외부의 기술적 세부 사항(예: 데이터베이스, 웹 프레임워크, UI)을 외곽 계층으로 분리하는 것이 기본 아이디어이다.

이 아키텍처는 일반적으로 다음과 같은 계층으로 구성된다.

계층

설명

예시

도메인 모델 (Domain Model)

가장 중심에 위치한 핵심 계층. 엔티티와 비즈니스 규칙을 포함한다.

Order, Customer, Product 클래스

도메인 서비스 (Domain Services)

단일 엔티티에 속하지 않는 복잡한 비즈니스 로직을 구현한다.

OrderProcessingService, PaymentCalculationService

애플리케이션 서비스 (Application Services)

유스케이스를 조정하고, 외부 계층과 도메인 계층을 연결하는 진입점 역할을 한다.

CreateOrderCommandHandler, GetUserProfileQuery

인프라스트럭처 (Infrastructure)

가장 바깥쪽 계층. 데이터 접근, 외부 API 호출, 프레임워크 관련 코드를 구현한다.

EntityFrameworkDbContext, SmtpEmailService, FileSystemRepository

의존성은 항상 안쪽으로만 흐른다. 즉, 도메인 모델 계층은 어떤 외부 계층에도 의존하지 않으며, 인프라스트럭처 계층은 애플리케이션 서비스나 도메인 계층에 의존한다. 이는 의존성 역전 원칙(DIP)을 명시적으로 적용한 것으로, 핵심 비즈니스 로직이 데이터베이스나 웹 서버와 같은 외부 요소의 변경으로부터 보호되게 한다.

클린 아키텍처와 헥사고날 아키텍처와 마찬가지로, Onion 아키텍처의 주요 목표는 관심사의 분리와 테스트 용이성 향상이다. 도메인 로직은 외부 의존성이 없기 때문에 단위 테스트가 매우 쉬워진다. 또한, 외부 기술을 교체해야 할 때(예: ORM 변경, 데이터베이스 교체) 도메인 코어를 수정하지 않고 외부 인프라 계층만 교체하면 되므로 유지보수성이 크게 향상된다.

8.2. DCI 패턴

DCI 패턴은 객체 지향 프로그래밍에서 시스템의 동적인 행위를 구조적인 측면과 분리하여 설계하는 패턴이다. Data, Context, Interaction의 세 가지 핵심 요소로 구성된다. Data는 시스템의 상태를 캡슐화하는 도메인 모델 객체를 의미한다. Context는 특정 사용 사례나 시나리오를 실행하기 위해 필요한 객체들 간의 상호작용을 설정하는 역할을 한다. Interaction은 Context 내에서 Data 객체들이 수행하는 구체적인 역할(Role)과 그 역할들 사이의 메시지 흐름을 정의한다.

이 패턴의 주요 목적은 유스케이스나 사용자 시나리오와 같은 시스템의 동작을 코드에서 명시적으로 표현하는 것이다. 전통적인 객체 지향 설계는 캡슐화와 상속에 중점을 두어 정적인 구조를 잘 표현하지만, 객체들이 협력하여 수행하는 특정 동작은 여러 클래스에 분산되기 쉽다. DCI 패턴은 이러한 동작을 별도의 Interaction 객체로 모아 가독성과 유지보수성을 높인다.

요소

설명

Data (데이터)

시스템의 핵심 도메인 개념과 상태를 나타내는 객체. 일반적인 엔티티나 값 객체에 해당한다.

Context (컨텍스트)

특정 상호작용(예: '계좌 이체')을 수행하기 위해 필요한 객체들을 선정하고 역할을 부여하는 조정자.

Interaction (상호작용)

Context 내에서 Data 객체들이 부여받은 역할(Role)을 통해 수행하는 메서드들의 집합. 시나리오의 알고리즘을 표현한다.

DCI 패턴은 복잡한 비즈니스 로직을 가진 애플리케이션, 특히 사용자 상호작용 흐름이 중요한 시스템에서 유용하게 적용된다. 이 패턴은 코드를 데이터(무엇인가)와 행위(무엇을 하는가)로 깔끔하게 분리함으로써, 클린 아키텍처나 헥사고날 아키텍처에서 추구하는 관심사 분리 원칙을 동작 수준에서 구현하는 한 가지 방법을 제공한다[3].

9. 여담

클린 아키텍처와 헥사고날 아키텍처는 종종 로버트 C. 마틴(Uncle Bob)과 알리스테어 콕번의 개인적인 아이디어로 오해받기도 한다. 그러나 이들의 핵심은 새로운 발명이라기보다는 기존의 견고한 소프트웨어 설계 원칙들—예를 들어 정보 은닉, 관심사의 분리, 의존성 역전 원리 등—을 구조화된 아키텍처 스타일로 정리하고 명확한 규칙과 다이어그램으로 제시한 것에 있다.

이러한 아키텍처 스타일의 이름과 시각적 표현은 때때로 논쟁을 불러일으킨다. '클린'이라는 용어는 마치 다른 접근법이 '더럽다'는 함의를 줄 수 있으며, '헥사곤'은 실제로는 여섯 개의 변보다는 포트와 어댑터의 개념을 강조하는 은유적 도구에 가깝다. 이러한 명명법은 개념을 쉽게 전달하고 기억하게 하는 마케팅적 측면도 있다.

실무에서 이 아키텍처들은 처음 접하는 개발자에게 과도한 추상화와 보일러플레이트 코드 증가로 인한 피로감을 줄 수 있다. 특히 소규모이거나 요구사항이 빠르게 변화하는 프로젝트에서는 적용이 과할 수 있다. 따라서 이는 만능 해결책이 아니라, 시스템의 장기적인 복잡성을 관리하기 위한 하나의 선택지로 바라보는 것이 바람직하다.

10. 관련 문서

  • 위키백과 - 클린 아키텍처

  • 위키백과 - Hexagonal architecture (software)

  • Martin Fowler - Hexagonal Architecture

  • The Clean Code Blog - The Clean Architecture

  • Herbertograca - The Onion Architecture

  • Microsoft Learn - Clean architecture with ASP.NET Core

  • Alistair Cockburn - Hexagonal Architecture

리비전 정보

버전r1
수정일2026.02.13 22:23
편집자unisquads
편집 요약AI 자동 생성
히스토리로 돌아가기