내부 아키텍처 설계 원칙
이 문서는 Functorium의 내부(Internal) 아키텍처 설계 원칙을 다룹니다. 소프트웨어 아키텍처의 정의에서 시작하여, 관심사의 분리 원칙에 따른 레이어 구조, 의존성 방향, 그리고 테스트와 관측 가능성까지 아키텍처 전반을 시각 자료와 함께 설명합니다. 아키텍처 설계를 처음 접하는 개발자부터, 기존 프로젝트에 Functorium을 적용하려는 팀까지 참고할 수 있습니다.
들어가며
섹션 제목: “들어가며”“새 프로젝트를 시작할 때 폴더 구조부터 먼저 정하고 나면, 정작 비즈니스 코드와 기술 코드가 뒤섞여 유지보수가 어려워진 경험은 없는가?” “기술 프레임워크를 교체할 때 비즈니스 로직까지 함께 수정해야 했던 적은 없는가?” “테스트를 작성하려 했지만 외부 의존성 때문에 포기한 적은 없는가?”
아키텍처 설계의 핵심은 관심사 분리 원칙에 기반한 레이어 구조와 의존성 방향 규칙에 있습니다. 비즈니스 관심사와 기술 관심사를 명확히 분리하고, 의존성 방향을 밖에서 안쪽으로 유지하면 각 관심사를 독립적으로 개발하고 테스트할 수 있습니다.
이 문서에서 배우는 내용
섹션 제목: “이 문서에서 배우는 내용”이 문서를 통해 다음을 학습합니다:
- 소프트웨어 아키텍처 정의 - 아키텍처가 단순한 폴더 구조가 아닌 핵심 구조적 결정인 이유
- Internal/External 아키텍처 구분 - 서비스 단위와 레이어 단위의 관심사 분리
- 레이어별 관심사와 의존성 방향 - Domain, Application, Adapter 레이어의 역할과 의존 관계
- 테스트와 관측 가능성 배치 - 단위 테스트, 통합 테스트, Observability의 아키텍처 내 위치
아키텍처 설계의 핵심은 비즈니스 관심사와 기술 관심사를 분리하고, 의존성 방향을 밖에서 안쪽으로 유지하는 것입니다.
소프트웨어 아키텍처 정의
섹션 제목: “소프트웨어 아키텍처 정의”소프트웨어 아키텍처는 단순한 폴더 구조가 아닙니다. 시스템의 핵심 구조적 결정이며, 변경 비용이 높기 때문에 초기에 신중하게 설계해야 합니다. 다음 그림은 소프트웨어 아키텍처가 무엇인지, 왜 중요한지를 보여줍니다.

- 출처: 소프트웨어 아키텍처의 중요성
애플리케이션 아키텍처
섹션 제목: “애플리케이션 아키텍처”애플리케이션 아키텍처 변천사
섹션 제목: “애플리케이션 아키텍처 변천사”애플리케이션 아키텍처는 모놀리식에서 마이크로서비스로, 그리고 다시 모듈러 모놀리스로 진화해왔습니다. 각 단계에서 해결하려는 문제와 트레이드오프가 다릅니다. Functorium은 이러한 아키텍처 변천의 교훈을 바탕으로, Internal 아키텍처에 집중하여 어떤 External 아키텍처와도 결합할 수 있는 구조를 제공합니다.

애플리케이션 External(Outer) / Internal(Inner) 아키텍처
섹션 제목: “애플리케이션 External(Outer) / Internal(Inner) 아키텍처”
아키텍처 설계 원칙
섹션 제목: “아키텍처 설계 원칙”-
관심사의 분리(Separation of concerns) 원칙
- 출처: 아키텍처 원칙
구분 관심사 단위 물리적 실체 External 아키텍처 서비스 컨테이너 Internal 아키텍처 레이어 - 객체 지향 객체 클래스
Internal 아키텍처 관심사
섹션 제목: “Internal 아키텍처 관심사”Internal 아키텍처의 핵심은 관심사의 분리입니다. 비즈니스 로직(무엇을 해야 하는가)과 기술적 세부사항(어떻게 구현하는가)을 명확히 구분하면, 각각을 독립적으로 개발하고 테스트할 수 있습니다. Functorium은 이 원칙을 세 개의 레이어로 구체화합니다.

Internal 아키텍처는 관심사의 분리 원칙에 따라 기술 관심사와 비즈니스 관심사로 구분합니다. 이렇게 구분된 관심사는 레이어로 정의하여 관리합니다.
레이어 분류
섹션 제목: “레이어 분류”| 관심사 구분 | 레이어 이름 | 레이어 역할 |
|---|---|---|
| 기술 관심사 | Adapter 레이어 | 기술 흐름과 단위 (입력/출력 처리) |
| 비즈니스 관심사 | Application 레이어 | 비즈니스 흐름 (Use Case) |
| 비즈니스 관심사 | Domain 레이어 | 비즈니스 단위 (Entity) |
- 비즈니스 관심사만 단위와 흐름을 명시적으로 레이어를 구분합니다.
- 기술 관심사(Adapter 레이어)가 비즈니스 관심사에 의존하도록 의존성 방향이 밖에서 안쪽으로 향합니다.
- 이를 통해 비즈니스 관심사(Application/Domain 레이어)는 기술에 의존하지 않고 개발 및 테스트할 수 있습니다.

Internal 아키텍처 레이어 의존성
섹션 제목: “Internal 아키텍처 레이어 의존성”의존성 시각화(클래스 다이어그램)
섹션 제목: “의존성 시각화(클래스 다이어그램)”의존성 방향은 아키텍처에서 가장 중요한 규칙 중 하나입니다. 의존성이 안쪽(비즈니스)에서 바깥쪽(기술)으로 향하면, 데이터베이스를 변경할 때 비즈니스 로직까지 수정해야 합니다. Functorium은 의존성 역전(DIP)을 통해 항상 바깥에서 안쪽으로 의존하도록 강제합니다.

의존성 통합
섹션 제목: “의존성 통합”App =
Driving인터페이스 정의 및 구현 +Driven인터페이스 정의 및 사용

의존성 방향
섹션 제목: “의존성 방향”
- Driving Adapter(입력):
App provided i/f인터페이스를 사용(uses) 합니다. - Application:
App provided i/f인터페이스를 구현(implements) 하고,App required i/f인터페이스를 사용(uses) 합니다. - Driven Adapter(출력):
App required i/f인터페이스를 구현(implements) 합니다.
의존성 역전(DIP)을 통해 Adapter 레이어가 Application 레이어에 정의된 인터페이스에 의존하게 되어, 의존성 방향이 밖에서 안쪽으로 향합니다.
의존성 비교
섹션 제목: “의존성 비교”-
클린 아키텍처

-
헥사고날 아키텍처

-
클린 아키텍처와 헥사고날 아키텍처와 동일한 의존성 방향임을 확인할 수 있습니다.
Internal 아키텍처
섹션 제목: “Internal 아키텍처”최종적인 Internal 아키텍처는 지금까지 설명한 관심사 분리, 레이어 구조, 의존성 방향을 하나로 통합한 것입니다. 각 레이어가 어떤 패턴을 사용하고, 테스트와 관측 가능성이 어디에 위치하는지 확인할 수 있습니다.

레이어별 역할과 패턴
섹션 제목: “레이어별 역할과 패턴”| 구분 | 레이어 | 패턴 | 설명 |
|---|---|---|---|
| 입력(Request) | Adapter | Result 패턴 | T(성공)/Error(실패) 형태로 결과 반환 |
| 출력(Response) | Adapter | Strategy 패턴, 함수형 | IObservablePort 인터페이스를 통한 외부 시스템 연동 |
| 비즈니스 연산 | Application | Mediator 패턴(CQRS) | IRequest/IResponse 인터페이스 (ICommandRequest, IQueryRequest) |
| 비즈니스 단위 | Domain | 함수형 | 비즈니스 핵심 로직과 엔티티 |
테스트 자동화
섹션 제목: “테스트 자동화”
- 단위 테스트(Unit Tests): 비즈니스 관심사만을 테스트합니다.
- 통합 테스트(Integration Tests): 기술 관심사까지 포함하여 테스트합니다.
관찰 가능성
섹션 제목: “관찰 가능성”
External 아키텍처
섹션 제목: “External 아키텍처”이 문서는 Internal 아키텍처에 집중합니다. External 아키텍처(서비스 간 통신, 컨테이너 오케스트레이션, API Gateway 등)는 별도 문서로 다룰 예정입니다.
FAQ
섹션 제목: “FAQ”Q1. 왜 기술 관심사와 비즈니스 관심사를 분리해야 하나요?
섹션 제목: “Q1. 왜 기술 관심사와 비즈니스 관심사를 분리해야 하나요?”기술(프레임워크, DB, 외부 API 등)은 시간이 지남에 따라 변경될 수 있습니다. 비즈니스 로직이 특정 기술에 강하게 결합되어 있으면, 기술 변경 시 비즈니스 로직까지 수정해야 합니다. 관심사를 분리하면 기술 변경이 비즈니스 로직에 영향을 주지 않아 유지보수성이 높아집니다.
또한 독립적 개발이 가능해집니다. 기술 관심사(Adapter) 구현이 완료되지 않은 상황에서도 비즈니스 관심사(Application/Domain)는 독립적으로 개발하고 테스트할 수 있습니다. 예를 들어, DB 연동이 준비되지 않아도 In-Memory 구현체 또는 단위 테스트로 대체하여 비즈니스 로직 개발을 진행할 수 있습니다.
Q2. Driving Adapter와 Driven Adapter의 차이점은 무엇인가요?
섹션 제목: “Q2. Driving Adapter와 Driven Adapter의 차이점은 무엇인가요?”| 구분 | Driving Adapter (입력) | Driven Adapter (출력) |
|---|---|---|
| 역할 | 애플리케이션을 호출하는 주체 | 애플리케이션이 호출하는 대상 |
| 예시 | REST Controller, CLI, Message Consumer | Repository, External API Client, Message Publisher |
| 인터페이스 | App provided i/f를 사용(uses) | App required i/f를 구현(implements) |
Q3. 왜 의존성 방향이 밖에서 안쪽으로 향해야 하나요?
섹션 제목: “Q3. 왜 의존성 방향이 밖에서 안쪽으로 향해야 하나요?”의존성 방향이 안쪽(비즈니스)에서 밖쪽(기술)으로 향하면, 비즈니스 로직이 기술에 의존하게 됩니다. 이 경우 기술 변경 시 비즈니스 로직도 함께 변경해야 합니다. 반대로 밖에서 안쪽으로 향하면, 기술이 비즈니스에 의존하므로 기술만 교체하면 됩니다.
Q4. Application 레이어와 Domain 레이어를 왜 분리하나요?
섹션 제목: “Q4. Application 레이어와 Domain 레이어를 왜 분리하나요?”- Application 레이어: 비즈니스 흐름(Use Case)을 담당합니다. “어떤 순서로 무엇을 할지”를 정의합니다.
- Domain 레이어: 비즈니스 단위(Entity)를 담당합니다. “무엇이 어떤 규칙을 가지는지”를 정의합니다.
흐름과 단위를 분리하면 Use Case 변경이 Entity에 영향을 주지 않고, Entity의 규칙 변경이 Use Case 흐름에 최소한의 영향만 줍니다.
Q5. 이 아키텍처는 클린 아키텍처, 헥사고날 아키텍처와 어떤 관계인가요?
섹션 제목: “Q5. 이 아키텍처는 클린 아키텍처, 헥사고날 아키텍처와 어떤 관계인가요?”모두 동일한 의존성 방향(밖에서 안쪽)을 가집니다. 용어와 표현 방식은 다르지만 핵심 원칙은 같습니다:
| 본 문서 | 클린 아키텍처 | 헥사고날 아키텍처 |
|---|---|---|
| Adapter 레이어 | Frameworks & Drivers | Port & Adapter |
| Application 레이어 | Use Cases | Application |
| Domain 레이어 | Entities | Domain |
Q6. 단위 테스트에서 Adapter를 제외하는 이유는 무엇인가요?
섹션 제목: “Q6. 단위 테스트에서 Adapter를 제외하는 이유는 무엇인가요?”Adapter는 외부 기술(DB, HTTP, 파일 시스템 등)과 연동되어 있어 테스트 환경 구성이 복잡하고 실행 속도가 느립니다. 비즈니스 로직(Application/Domain)만 테스트하면 빠르고 안정적인 단위 테스트가 가능합니다. Adapter는 통합 테스트에서 검증합니다.