5-Step Architecture Spec (Revised v3)

# 5-Step Architecture Spec (Revised v3)

이 문서는 헥사고날 아키텍처와 DDD 전략적 설계를 실무적으로 결합하고, 바이브 모델링을 통해 도출된 도메인 자아를 소프트웨어 제조 공정으로 치환한 표준 지침입니다.

## Core Philosophy

Service는 도메인 모델이라는 Category와 유스케이스라는 Category를 연결하는 Functor입니다. 모델은 비즈니스 규칙의 정적 보존 처인 Brain이며, Policy는 그 규칙이 환경에 따라 발현되는 방식인 Law입니다. Service는 이들 사이의 Morphism(사상)을 조율하여 유스케이스의 맥락으로 데이터를 전이시키는 역할을 수행합니다. 따라서 Service는 로직을 소유하지 않고 오직 흐름만을 관장함으로써 요구사항의 변화에 모델을 수정하지 않고도 대응할 수 있는 유연성을 확보합니다.

모델은 시스템의 목적에 따라 고유한 바이브(Vibe)를 가집니다. 예를 들어 엄격한 통제가 중요한 보안 지향적 바이브나 복잡한 관계 중심의 비즈니스 지향적 바이브를 가질 수 있으며, 설계자는 이를 속성과 흐름에 투영해야 합니다.

---

## The 5-Step Standard Process

### [Step 1] 도메인 자아 확립 (Domain Model Discovery)

비즈니스의 핵심 상태와 행위를 관리하는 Aggregate Root(AR)를 정의합니다.

#### 바이브 기반 속성 정의
모델이 지향하는 가치에 따라 속성을 그룹화합니다.
- 제약/통제 속성: 객체의 상태값, 접근 제어 카운트, 변경 이력 등 엄격한 정합성이 필요한 정보.
- 컨텍스트 속성: 객체가 속한 그룹, 위치, 관계 등 구조적 정보를 정의하는 정보.
- 가공 속성: 실시간 상태와 정책을 결합하여 도출되는 결과값(예: 현재 행사 가능한 최종 권한 리스트).

#### Lifecycle Status 및 전이 설계
AR은 고정된 데이터가 아니라 생명주기에 따라 변이하는 자아를 가집니다.
* 전이 이벤트: 생성 요청, 승인, 만료, 종료 처리 등.
* 상태 보호: 외부에서 상태값을 직접 수정할 수 없으며, 반드시 모델 내부의 전이 로직(예: lockAccount, activate)을 통해서만 상태가 변경됩니다.
* 상태 검증: 특정 상태에서만 허용되는 액티비티를 모델 스스로 검증합니다(예: LOCKED 상태에서는 인증 액티비티 진입 불가).

#### Reconstitution (복원 능력)
AR은 reconstitute 메서드를 통해 과거의 상태를 복원합니다.
* 데이터 복원: DB에 저장된 원천 데이터를 불러와 AR의 속성을 채웁니다.
* 자아 복구: 단순히 값만 채우는 것이 아니라, 마지막 수정자나 수정 사유 등 감사(Audit)에 필요한 맥락을 함께 복원하여 도메인의 영속적 자아를 증명합니다.

### [Step 2] 법전 정의 (Policy Abstraction)

비즈니스 제약 조건 중 외부 환경(보안, 계산 로직 등)에 따라 변하기 쉬운 규칙을 @FunctionalInterface 등으로 추상화합니다.

* 원칙: 모델은 법전의 내용을 알 필요가 없습니다. 법전(Policy)이 모델에 주입될 때, 모델은 그 법에 따라 판단할 뿐입니다.

### [Step 3] 흐름 조율 (Service Orchestration)

서비스는 비즈니스 로직을 직접 구현하는 뇌(Brain)가 아니라, 도메인 모델(Category A)을 유스케이스 결과(Category B)로 사상하는 함자(Functor)로서 전체 공정을 조율합니다.

#### 핵심 원칙
* Interface Driven: 유스케이스를 완성하기 위해 필요한 기술적 도구들의 명세(Activity Interface)를 이 단계에서 먼저 도출합니다.
* Logicless Functor: 서비스 내부에서 if나 for를 통한 비즈니스 판단을 지양합니다. 대신 외부의 환경 정보(IP, HR 데이터 등)를 취합하여 모델이 이해할 수 있는 정책(Policy)으로 변환해 전달하는 사상(Mapping) 책임에 집중합니다.

#### 공정 프로세스 (Morphism Flow)
* Activity 명세 정의: 유스케이스 목적에 맞는 도구(Persistence, Notify, Audit 등)의 인터페이스를 정의합니다.
* AR 복원 (Reconstitute): 식별 정보를 통해 도메인 모델의 자아를 깨웁니다. 이때 모델 스스로 현재 액티비티를 수행할 수 있는 상태인지 검증하게 합니다.
* 맥락 취합 및 정책 주입: 유스케이스 상황에 맞는 법전(Policy)을 선택합니다.
* 비즈니스 수행 (Brain Execution): 주입된 정책과 함께 모델의 행위를 실행합니다. 모델은 스스로의 뇌를 통해 판단하고 상태를 변이시킵니다.
* 결과 사상 및 저장: 변이된 상태를 저장하고, 발생한 이벤트(Audit Log 등)를 외부로 전파하며 최종 응답 DTO로 매핑합니다.

### [Step 4] 도구 제작 (Activity Implementation)

Step 3에서 설계된 유스케이스 시나리오를 완성하기 위해 필요한 구체적인 도구들을 구현합니다. Activity는 유스케이스가 외부 세계에 던지는 기술적 명령의 실체이자, 인프라 기술을 비즈니스 언어로 추상화하는 완충 지대입니다.

- 원칙 1 (Use Case Driven): Activity 명세(Interface)는 유스케이스가 비즈니스 흐름을 이어가기 위해 필요한 행위의 목적으로부터 도출됩니다. 단순히 데이터에 접근하는 수단이 아니라, 자원 생성(Creation), 검증(Verification), 상태 제어(Lifecycle Control) 등 비즈니스 목적이 명시된 행위여야 합니다.
- 원칙 2 (Implementation Purity & Double Porting):
    - Activity 구현체: 특정 인프라 기술(JPA, JDBC 등)을 직접 알지 못하게 합니다. 대신 인프라 계층 내부에 정의된 인터페이스(Port)에 의존하여 비즈니스 데이터의 흐름과 복원(Reconstitution) 공정만 제어합니다.
    - Adapter: 특정 인프라 기술을 사용하여 Port를 실제로 구현하며, 기술적 변환(Mapping)에만 집중합니다. 이를 통해 기술적 변경이 Activity의 로직에 영향을 주지 않는 구조를 완성합니다.
- 원칙 3 (Infrastructure Selection & Layered Adapter Design):
    - 기술 선택의 독립성: 요구 성능과 특성에 따라 JdbcClient(RDB), Valkey(Cache), Kafka(Message) 등 최적의 인프라를 자유롭게 선택합니다. 예를 들어 권한 검증은 고속 캐시를, 감사 로그는 메시지 브로커를 선택할 수 있습니다.
    - Mapping Responsibility: 어댑터는 기술적 데이터(Table/JSON)와 도메인 모델(AR) 사이의 차이를 메우는 유일한 장소입니다. reconstitute 공정을 통해 인프라의 로우 데이터를 비즈니스 규칙이 살아있는 AR로 정교하게 변환합니다.
    - 물리적 분리: 인터페이스(Port)는 Step 3 패키지에, 구현체(Activity/Adapter)는 Step 4 인프라 패키지에 두어 의존성을 격리합니다.
- 원칙 4 (Inter-Module Cooperation & Privacy):
    - 이벤트 기반 협력: 모듈 간의 강한 결합을 피하기 위해 도메인 이벤트 발행을 적극 활용합니다. 유스케이스 완료 시점에 발행된 이벤트는 infra 계층의 어댑터를 통해 외부 모듈(예: 감사 로그 모듈)로 전파됩니다.
    - 외부 참조 격리: 타 모듈의 테이블은 SELECT만 허용하며, 자신의 infra 패키지 안에서 전용 VO로 매핑하여 사용함으로써 외부 모델의 변경이 현재 모듈의 model 계층으로 침투하는 것을 차단합니다.

### [Step 5] 반복 공정 검증 (Multilayered Testing)

* Model Test: 정책을 Stub/Mock으로 주입하여 비즈니스 로직의 순수성을 ms 단위로 검증합니다.
* Service Test: 각 컴포넌트 간의 호출 흐름(Orchestration)만 검증합니다. 로직 테스트를 지양하여 테스트 무거움을 방지합니다.

---

## Implementation Guidelines (Deep Dive)

### 1. Unified Reconstitution

모든 AR은 reconstitute 메서드를 통해 복원됩니다. 이는 생성과 조회를 기술적으로 분리하지 않고 도메인 관점에서 하나로 통합하는 핵심 장치입니다. 도메인 모델은 이 지점을 통해 기술적 환경에 구애받지 않고 스스로의 자아를 증명합니다. 

### 2. The Functorial Service Principle

Service는 비즈니스 로직의 소유자가 아니라, 카테고리 간의 전이를 담당하는 Functor(함자)입니다.

- 철학: 도메인 모델(Category A)이 가진 순수한 비즈니스 규칙을 보전하면서, 이를 유스케이스(Category B)라는 실행 문맥으로 사상(Mapping)합니다.
- 역할 (Orchestration): 서비스는 모델 내부에서 처리할 수 없는 흐름을 조율(Morphism)할 뿐이며, 스스로 뇌가 되지 않습니다. 유스케이스의 변화는 곧 Functor의 사상 규칙이 변하는 것이므로, 모델을 수정하지 않고도 서비스의 조율 로직(Step 3)을 변경함으로써 요구사항에 유연하게 대응합니다.

### 3. Vibe-Driven Attribute & Lifecycle (추가)

모델은 지향하는 가치(보안, 조직 등)에 따라 속성을 그룹화하고 생명주기를 스스로 관리합니다.

- 바이브별 속성 격리: 도메인 성격에 맞는 속성 그룹을 AR 내부에서 명확히 구분하여 정의합니다.
- 상태 전이 매트릭스: AR은 스스로의 상태 전이 규칙을 내포합니다. 비정상적인 전이 시도는 모델 내부에서 거절되어 도메인 정합성을 보호합니다.

### 4. Explicit Policy Injection

AR의 메서드가 정책을 필요로 할 경우, 항상 파라미터로 정책 인터페이스를 명시적으로 전달받습니다. 서비스(Functor)가 외부 환경의 법전(Policy)을 모델의 입에 넣어주는 형태이며, 모델은 주입된 법에 따라 스스로 판단합니다.

### 5. Defensive Copy in Model

내부 컬렉션을 노출할 때는 반드시 Collections.unmodifiableList() 등을 사용하여 외부에서 내부 상태를 오염시키는 것을 원천 차단합니다. 이는 모델의 불변성과 정합성을 유지하기 위한 최소한의 방어 기제입니다.

---

## 📦 Module 구성 가이드 (Spring Modulith 지향)

모듈의 내부 구조는 캡슐화를 통해 비즈니스 침투를 막고, 명확한 포트를 통해 기술과 소통합니다. 패키지 간의 가시성을 제어하여 상위 계층이 하위 구현체에 의존하지 않도록 설계합니다.

| **계층** | **가시성** | **주요 컴포넌트** | **설명** |
| --- | --- | --- | --- |
| 1. application | Public | Service, DTO, Port | 모듈의 외부에 노출되는 유일한 성문이자 API 창구입니다. 유스케이스 입출력 규격을 정의하고 Functor로서 모델과 액티비티 사이의 사상을 조율합니다. |
| 2. model | Internal | Aggregate Root, VO, Policy | 비즈니스의 심장입니다. 오직 도메인 언어로만 대화하며 인프라 기술에 대한 지식이 전무합니다. 바이브에 따른 속성과 상태 전이 로직을 소유합니다. |
| 3. activity | Internal | Activity Implementation | 유스케이스가 요구하는 고수준 기술 명령을 수행합니다. 특정 인프라 기술에 의존하지 않고 내부 포트를 통해 데이터 흐름을 제어하며 모델을 복원합니다. |
| 4. infra | Internal | Adapter, Port Implementation | 구체적인 인프라 기술(JdbcClient, Valkey, Kafka 등)이 실현되는 장소입니다. 데이터 포맷 변환, 로우 데이터 매핑, 외부 메시지 발행을 전담합니다. |
| 5. controller | Internal | REST Controller, OpenAPI | 외부 요청을 application 계층의 Command 객체로 변환하여 전달하는 단순 진입점입니다. 웹 기술과 유스케이스를 연결하는 얇은 층입니다. |

---




댓글

이 블로그의 인기 게시물

Session 대신 JWT를 사용하는 이유

스프링 부트 개발자를 위한 유용한 VSCode 설정

osx 매버릭스에서 영문키 반복 입력되게 하기