콘텐츠로 바로가기

Foundations & Architectural Patterns

소프트웨어 시스템의 대규모 구조를 결정하는 기본 설계 원칙과 레이어드, 헥사고날 등 현대적 아키텍처 패턴의 물리적 구성을 다루는 학습 노드입니다.

Article
M

Me

hyunyoun's Blog

system-architecture-distributed-systemssystem-architecturedistributed-systemsfoundationsarchitectural-patternsarchitectural-evolutionlearningspring-boot9 min read

1. Overview

기초 및 아키텍처 패턴(Foundations & Architectural Patterns, FAP)은 수만 줄의 코드가 뒤엉켜 무너지는 것을 막고, 변화하는 비즈니스 요구사항에 유연하게 대응할 수 있도록 소프트웨어의 뼈대를 세우는 '건축 설계 원칙'을 다룹니다.

아키텍처는 나중에 바꾸기 가장 힘든 '초기의 중대한 결정'들의 집합입니다. 학습자는 고전적인 계층형(Layered) 구조부터 시작해, 도메인 핵심 로직을 외부 기술로부터 완벽히 격리하는 헥사고날(Hexagonal)과 클린 아키텍처(Clean Architecture)의 물리적 진화를 학습합니다. 이 과정을 통해 높은 응집도(Cohesion)와 낮은 결합도(Coupling)라는 추상적인 목표를, 구체적인 코드 파일의 위치와 의존성 방향(Dependency Rule)으로 구현해 내는 시스템 설계자로 거듭납니다.

2. Scope & Boundaries

In-Scope

  • 아키텍처 품질 속성 (Quality Attributes): 유지보수성, 확장성, 테스트 가능성, 보안, 가용성 등 비기능 요구사항(NFR)과 아키텍처 드라이버.
  • 고전적 설계 패턴 (Classic Architectures): 레이어드 아키텍처(Layered), 파이프 앤 필터(Pipe-and-Filter), 플러그인(Plug-in) 구조.
  • 모던 격리 아키텍처 (Modern Architectures): 의존성 역전(DIP), 헥사고날(Hexagonal/Ports & Adapters), 클린 아키텍처(Clean Architecture), 양파(Onion) 아키텍처.
  • 컴포넌트 설계와 DDD 기초: 관심사 분리(Separation of Concerns), 공통 폐쇄 원칙(CCP), 바운디드 컨텍스트(Bounded Context) 기초.

Out-of-Scope

  • 객체 지향 디자인 패턴 (GOF Patterns): 팩토리(Factory), 싱글톤(Singleton), 데코레이터(Decorator) 같은 클래스 레벨의 마이크로 설계 \rightarrow 05-01. OOP & Language Paradigms 영역으로 위임.
  • 마이크로서비스 네트워크 설계 (Microservices): 여러 대의 서버로 쪼개진 서비스 간의 API 통신, 서킷 브레이커, 서비스 디스커버리 \rightarrow 07-06. Microservices & Containers 영역으로 위임.

Boundaries

  • FAP vs. Microservices (07-06): 07-06이 '여러 애플리케이션 간의 통신과 네트워크 분할'을 다룬다면, FAP는 **'단일 애플리케이션 내부에서 폴더(모듈)를 어떻게 나누고 화살표(의존성)를 어느 방향으로 그릴 것인가'**라는 내부 해부학에 초점을 맞춥니다. 모노리스(Monolith) 내부가 잘 쪼개져 있어야 마이크로서비스로도 찢을 수 있습니다.

3. Counterexample

  • 프레임워크 중심의 묻지마 레이어드 (Architecture Fallacy): Spring이나 Django 같은 프레임워크가 만들어준 Controller $\rightarrow$ Service $\rightarrow$ Repository 폴더 구조에 비즈니스 로직을 마구잡이로 구겨 넣는 행위. 시간이 지나면 Service 계층에 데이터베이스 쿼리와 외부 API 호출 코드가 뒤섞여, DB를 MySQL에서 MongoDB로 바꾸거나 로직만 따로 떼어내 유닛 테스트를 하려 할 때 시스템 전체를 뜯어고쳐야 하는 **'의존성 지옥(Dependency Hell)'**에 빠지게 됩니다. 이는 비즈니스 규칙(Domain)이 외부 기술(Framework, DB)에 종속된 전형적인 안티패턴입니다.
  • "아키텍처는 코드 없이 그림만 그리는 것"이라는 오해: 화이트보드에 네모 상자와 화살표를 아름답게 그려놓고 끝내는 행위. 아키텍처는 패키지 구조, Import 문법, 컴파일 타임 의존성으로 물리적인 코드 레벨에서 강제되어야 합니다. 그림으로는 헥사고날 아키텍처라고 해놓고, 실제 코드에서는 Domain 폴더에서 DB 폴더를 import 하고 있다면 그 아키텍처는 죽은 것입니다.

4. Prerequisites

  • 객체 지향 프로그래밍 (Basic): 다형성(Polymorphism)과 인터페이스(Interface)를 모르면 의존성 역전(DIP)을 물리적으로 구현할 수 없습니다. (05-01. OOP)
  • 소프트웨어 공학 (Recommended): 테스트 주도 개발(TDD)과 리팩토링의 필요성을 알아야 "왜 굳이 코드를 이렇게 피곤하게 나눠야 하는지" 공감할 수 있습니다. (09-01. SE)

5. Learning Map

Sequence Core Cluster Objective & Description Evidence (BoK)
1 Thinking in Structures (Quality Attributes) 코드를 짜기 전, 시스템이 달성해야 하는 성능, 보안, 유지보수성 등 보이지 않는 제약 조건(NFR)을 정의합니다. P2:SWEBOK
2 Traditional Layering (Layered Architecture) 하향식으로 흐르는 레이어드 구조의 편리함을 배우고, 그것이 거대해질 때 발생하는 파멸적 스파게티 의존성을 분석합니다. P1:CS2023
3 Inverting Dependencies (Clean & Hexagonal) 인터페이스를 통해 화살표 방향을 꺾어(DIP), 도메인을 중앙에 두고 DB와 UI를 플러그인처럼 갈아끼우는 현대적 설계를 마스터합니다. Industry Arch
4 Evaluating Design (ADR & Trade-offs) 은탄환은 없습니다. 결정의 배경과 득실을 아키텍처 결정 기록(ADR)으로 문서화하고 진화시키는 방법을 익힙니다. Industry

6. Learning Topics

Basic

Core Topic 01: 아키텍처의 목적과 품질 속성 (Architectural Goals)

  • Why to Learn: "코드가 돌아가기만 하면 끝 아닌가요?"라는 주니어 마인드를 버리고, 변경 비용과 시스템 생명주기를 고려하는 시야를 갖추기 위함입니다.
  • What to Learn:
    • Concepts: 소프트웨어 아키텍처의 정의, 기능 요구사항 vs 비기능 요구사항(NFR).
    • Skills: 6대 품질 속성(성능, 가용성, 확장성, 보안성, 수정 용이성, 테스트 용이성) 식별.
    • Tools: 아키텍처 시나리오 프로파일링.
    • Trade-offs: 데이터를 암호화하는 보안성(Security)을 챙기면 필연적으로 암복호화 연산이 추가되어 응답 속도 성능(Performance)이 떨어지는 식의 품질 간 제로섬 게임.
  • How to Learn:
    • 1단계: '쇼핑몰 결제 시스템'의 요구사항을 보고, "블랙프라이데이에 트래픽이 100배 뛰어도 죽지 않아야 함(가용성/확장성)"과 "코드 배포를 무정지로 하루 10번 할 수 있어야 함(수정 용이성)"을 도출해 냅니다.
    • 2단계: 이 품질 속성들을 만족시키기 위해 단일 모노리스(Monolith) 대신 메시지 큐를 활용한 이벤트 기반(Event-Driven) 구조를 채택했을 때 잃게 되는 것(디버깅 난이도, 강한 일관성 포기)을 목록화합니다.
  • Implement: 특정 토이 프로젝트 기획서를 읽고, 시스템이 최우선으로 달성해야 할 품질 속성 3가지와 이를 위해 포기한 것을 기록한 아키텍처 드라이버(Architectural Drivers) 명세서 작성.

Core Topic 02: 계층형 아키텍처의 명암 (Layered Architecture)

  • Why to Learn: 현존하는 90% 이상의 백엔드 프로젝트가 채택한 가장 직관적인 구조의 한계를 뼈저리게 느끼고 파훼법을 찾기 위해서입니다.
  • What to Learn:
    • Concepts: Presentation(Controller) \rightarrow Business(Service) \rightarrow Data Access(Repository) \rightarrow Database의 하향식 흐름.
    • Skills: 계층 간 데이터 전달 객체(DTO) 매핑, 순환 참조(Circular Dependency) 회피 로직.
    • Tools: 의존성 분석 도구(Java의 ArchUnit, JDepend).
    • Trade-offs: 새로운 기능을 추가할 때 어디에 코드를 넣어야 할지 누구나 알 수 있는 압도적인 직관성 vs 비즈니스 로직(Service)이 항상 데이터베이스(Repository)에 의존하게 되어, DB 없이 비즈니스 로직만 유닛 테스트하는 것이 거의 불가능해지는 치명적 결함.
  • How to Learn:
    • 1단계: Spring이나 Express.js로 전형적인 3계층 게시판 API를 만들면서, Service 클래스가 DB 쿼리를 날리는 ORM 객체에 끈적하게 달라붙어(Coupled) 있음을 확인합니다.
    • 2단계: "데이터베이스를 Oracle에서 MongoDB로 바꾸라"는 지시가 떨어졌을 때, Service 코드 수백 군데를 뜯어고쳐야 하는 재앙적 시나리오를 시뮬레이션하며 의존성 하향 흐름의 한계를 증명합니다.
  • Implement: 3계층 아키텍처로 짜인 기존 코드를 분석하여, 패키지(폴더) 간의 import 의존성 그래프를 그어보고 상위 계층이 하위 계층에 침식된(Leaky Abstraction) 지점을 찾아내는 리포트.

Practical

Core Topic 03: 헥사고날 및 클린 아키텍처 (Clean & Hexagonal Architecture)

  • Why to Learn: 데이터베이스, 웹 프레임워크, 외부 API를 내 비즈니스 로직의 '중심'에서 '변두리 플러그인'으로 밀어내어, 10년이 지나도 썩지 않는 코어(Core)를 지키기 위함입니다.
  • What to Learn:
    • Concepts: 의존성 역전 원칙(DIP), 헥사고날 아키텍처(Ports and Adapters), 클린 아키텍처(의존성 규칙).
    • Skills: 도메인 엔티티 설계, 인바운드/아웃바운드 포트(Interface) 선언, 어댑터(Adapter) 구현, Use Case 분리.
    • Tools: 도메인 중심 폴더 구조(Domain-centric Packaging).
    • Trade-offs: 데이터베이스 없이도 핵심 로직을 0.01초 만에 유닛 테스트할 수 있는 경이로운 유연성 vs DTO, Entity, Model 변환 코드를 계속 짜야 하고 파일 개수가 3배로 늘어나는 극심한 보일러플레이트(Boilerplate) 오버헤드.
  • How to Learn:
    • 1단계: 기존 Service $\rightarrow$ Repository(구현체)의 의존성을 끊기 위해, Service는 자신이 필요한 기능을 Port(인터페이스)로 선언만 하고, 인프라 계층이 그 Port를 구현하는 Adapter가 되어 의존성 화살표의 방향을 반대(\leftarrow)로 꺾어버리는 의존성 역전(DIP) 마법을 수행합니다.
    • 2단계: 이 구조 하에서, 실제 DB 연결 없이 Mock Adapter(가짜 객체)만 끼워 넣고 비즈니스 로직 전체를 완벽하게 검증하는 테스트 코드를 작성합니다.
  • Implement: '은행 계좌 이체' 기능을 헥사고날 아키텍처 패턴에 맞춰 코딩하되, 도메인 폴더 내에는 어떤 외부 라이브러리(Spring, TypeORM 등)의 import도 허용하지 않는 순수(Vanilla) 모듈 작성.

Advanced

Core Topic 04: 아키텍처 평가와 의사결정 (ADR & Trade-off Analysis)

  • Why to Learn: "내가 이 패턴을 좋아해서 썼다"는 변명 대신, 논리적이고 정량적인 근거를 바탕으로 아키텍처를 결정하고 그 역사를 후임자에게 남기기 위해서입니다.
  • What to Learn:
    • Concepts: 아키텍처 결정 기록(ADR, Architecture Decision Records), ATAM (Architecture Tradeoff Analysis Method).
    • Skills: 대안(Alternatives) 벤치마킹, 트레이드오프(Trade-off) 정량화, 진화적 아키텍처를 위한 피트니스 함수(Fitness Functions) 세팅.
    • Tools: Markdown 기반 ADR 템플릿, Log4Brain.
    • Trade-offs: 처음에는 가볍게 모노리스(Monolith)로 시작하다가 트래픽이 터지면 마이크로서비스(MSA)로 전환하는 '진화적 결단' vs 처음부터 완벽한 클린 아키텍처 MSA를 고집하다가 오픈도 못 하고 프로젝트가 망하는 '오버엔지니어링(Over-engineering)'.
  • How to Learn:
    • 1단계: "시스템 로그인 방식을 세션(Session) 기반에서 JWT(JSON Web Token)로 변경한다"는 주제로, 상태 비저장(Stateless)의 이득과 토큰 탈취 시 강제 로그아웃이 불가능한 보안적 손실을 조목조목 비교합니다.
    • 2단계: 이를 바탕으로 Context(배경), Decision(결정), Consequences(결과적 득실)가 포함된 마크다운 포맷의 ADR 문서를 팀원들이 납득할 수 있게 작성합니다.
  • Implement: 본인이 진행 중인 프로젝트 코드베이스의 doc/adr 폴더에 0001-use-hexagonal-architecture.md라는 문서를 작성하고, 왜 레이어드 아키텍처를 버렸는지에 대한 3가지 논리적 근거를 명시.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core/misused/legacy)
Dependency Inversion 고수준 모듈이 저수준 모듈에 의존하지 않고, 둘 다 추상화(인터페이스)에 의존하게 하는 설계 원칙입니다. 추천 유연성 확보 SOLID / DIP Dependency Injection '객체 주입' 자체로 오해 P1:CS2023/Software Design core
Cohesion (응집도) 한 컴포넌트 내부의 요소들이 서로 얼마나 밀접하게 관련되어 있는지를 나타내는 물리적 설계 척도입니다. 기본 품질 측정 Coupling SRP '코드가 짧음'과 혼동 P2:SWEBOK Design core
Hexagonal Arch 애플리케이션의 핵심 비즈니스 로직을 외부 환경(DB, UI 등)으로부터 포트와 어댑터를 통해 격리하는 구조입니다. 실무 격리/테스트 Ports & Adapters Onion Architecture '레이어 추가'로만 오해 Industry Cockburn core
ADR 팀 내에서 내린 중요한 아키텍처 결정 사항을 그 배경과 득실을 포함하여 기록한 문서입니다. 실무 지식 관리 Documentation RFC 단순한 '매뉴얼'로 오해 Industry Nygard core

8. References

Primary References

Secondary References

  • [Clean Architecture] Robert C. Martin — Modern implementation authority.
  • [Software Architecture in Practice] Bass et al. — Focus on quality attributes.

Industry References

  • [Gartner: Reference Architecture Patterns] — Enterprise standard definitions.
  • [Martin Fowler - Architecture section] — Pragmatic modern pattern blog.

9. Final Checklist

Primary Checklist

  • 레이어드 아키텍처에서 'DB 스키마 변경'이 'UI 코드'까지 영향을 미치는 물리적 원인을 의존성 관점에서 설명 가능한가? (P2)
  • 특정 설계안이 시스템의 성능(Performance)을 높이는 대신 무엇(예: 유지보수성)을 희생했는지 트레이드오프를 식별 가능한가? (P1, P2)

Secondary Checklist

  • 인터페이스를 통한 추상화가 시스템의 전체적인 물리적 복잡도를 높이는지 낮추는지 목적에 따라 변론할 수 있는가?
  • 응집도는 높고 결합도는 낮은 시스템이 왜 실제 운영 환경에서 장애 전파(Cascading Failure)를 물리적으로 억제하는지 인지하는가?

Industry Checklist

  • 실무 개발 과정에서 발생하는 중요한 설계 변경 사항을 ADR 문서로 남기고 팀원들과 기술적 합의를 이끌어낼 수 있는가? (SFIA)
  • 복잡한 레거시 코드를 보고 물리적 컴포넌트 경계를 다시 설정하는 리팩토링 전략을 제시 가능한가?

System Architecture · Architectural Evolution

1 / 5