클린 아키텍처 (정리)
클린 아키텍처 (정리)
원문: https://www.notion.so/1c7bf506e9948003ba4dd4a575d4f01e?pvs=1
복잡한 시스템일수록 구조가 중요하다. 클린 아키텍처는 유지 보수성과 확장성을 높이기 위해 설계된 아키텍처 패턴이다. (예제 코드는 NestJS 를 기반으로 했으며 추가 예제 코드는 SpringBoot+Lombok 이다.)
[1] 아키텍처 패턴이란?
(1) 정의
아키텍처 패턴은 소프트웨어의 전체 구조를 어떻게 설계할지에 대한 ‘전략적인 청사진’이다.
즉, 어떤 식으로 코드 구성 요소(모듈, 계층 등)를 나누고, 그 사이의 관계를 정할지를 정의한 일종의 설계 템플릿이다.
- 예시
(2) 클린 아키텍처란?
1) 정의
-
클린 아키텍처는 소프트웨어 시스템을 유연하고, 테스트 가능하고, 유지보수하기 쉽게 만드는 아키텍처 패턴이다.
-
핵심은 의존성 방향을 내부 → 외부로만 향하게 해서 비즈니스 로직을 외부 기술(프레임워크, DB 등)과 분리하는 것이다.
2) 목적
-
비즈니스 로직 보호
-
테스트 용이성 증가
-
프레임워크 독립성 확보
-
UI, DB, 외부 라이브러리로부터 독립
3) 아키텍처 구조 (원형 계층 구조)
- 원형 계층 구조란?
- 예시 구조
- 바깥쪽은 안쪽에 의존해도 됨.
→ 클린 아키텍처는 마치 핵을 감싸는 양파같은 구조이다. 핵심 비즈니스 로직은 외부에 절대 영향을 받지 않도록 “보호”하는 구조이다.
4) 언제 사용하는가?
복잡하고 오래 유지복수해야 하는 백엔드 시스템에서 사용하면 효과가 크다.
- 사용 안해도 되는 경우
정리하자면, “기술보다 도메인이 중요한 프로젝트” 일수록 클린 아키텍처가 잘 어울린다.
[2] 클린 아키텍처의 핵심 원칙
(1) 의존성 규칙 (Dependency Rule)
1) 정의
즉,
-
바깥쪽은 안쪽을 사용할 수 있다.
-
안쪽은 바깥쪽을 절대 몰라야 한다.
2) 원형 계층 구조에서 보면
plain text
Entities ← 가장 핵심
Use Cases ← 안쪽
InterfaceAdapters
Frameworks ← 바깥
-
🔁 가능: Controller → UseCase
-
🚫 불가능: UseCase → Controller
-
🔁 가능: MySQLRepo → Entity
-
🚫 불가능: Entity → MySQLRepo
3) 왜 중요한가?
-
비즈니스 로직의 독립성 확보
-
테스트 용이성
-
확장성 / 유연성
-
예시)
4) 정리
(2) SOLID 원칙
1) 정의
2) SOLID 5가지 원칙 정리
3) 1️⃣ 단일 책임 원칙 (SRP)
-
정의
-
왜 중요할까?
-
예시
-
실무에서의 팁
-
요약
3) 2️⃣ 개방-폐쇄 원칙 (OCP)
-
정의
-
왜 중요할까?
-
예시
-
실무에서의 팁
-
요약
4) 3️⃣ 리스코프 치환 원칙(LSP)
-
정의
-
왜 중요할까?
-
예시
-
실무에서의 팁
-
요약
5) 4️⃣ 인터페이스 분리 원칙(ISP)
-
정의
-
왜 중요할까?
-
예시
-
실무에서의 팁
-
요약
6-1) 5️⃣ 의존성 역전 원칙 (DIP : Dependency Inversion Principle)
-
정의
-
왜 중요할까?
-
예시
-
실무에서의 팁
-
DIP가 중요한 순간
-
요약
6-2) 의존성 규칙 vs 의존성 역전 원칙
예시 코드가 똑같아 보여서 헷갈릴 수 있다.
실제로는 적용 대상과 강조점이 살짝 다르기 때문에 둘은 서로 다른 개념이다.
-
핵심 차이 요약
-
쉽게 기억하는 비유
-
결론
[3] 클린 아키텍처의 계층 구조 (Entities / UseCases / Interface Adapters / Frameworks)
(1) 전체 구조 한눈에 보기

- 계층별 간단 요약
(2) 각 계층의 역할
1) Entities 계층 (도메인 모델)
핵심 비즈니스 규칙과 데이터 구조를 담는 계층
-
외부 기술 완전 몰라도 됨
-
DB, 프레임워크와 완전히 분리됨
-
변경이 거의 없어야 하고, 시스템의 가장 중요한 규칙을 담음
- 예시
2) Use Cases 계층 (Application business Logic)
사용자의 행동(흐름)을 정의하고, Entity를 조합해서 실행
-
Repository 인터페이스를 통해 DB 저장/조회
-
UseCase의 책임 : “무엇을 할 것인가”를 정의
- 예시
3) Interface Adapters 계층 (입출력 어댑터)
외부 세계와 내부 로직을 연결 주로 Controller, DTO, Repository 구현체 등이 여기에 포함
- 예시
4) Frameworks & Drivers 계층 (외부 기술)
웹 서버, DB, 이메일, 파일 시스템, 외부 API 등 NestJS, MySQL, Redis, S3 등이 여기에 포함됨
-
테스트하기 어려운 기술적 요소들
-
외부 도구로써 언제든 교체될 수 있어야 함
- NestJS 폴더 구조 예시
- 핵심 요약
(3) 계층 간 의존성 방향 (핵심 개념)
1) 개념 설명
의존성은 무조건 바깥 → 안쪽으로만 향해야 한다.
→ 즉, 바깥 계층은 안쪽 계층을 참조해도 되지만, 안쪽 계층은 바깥 계층을 절대 참조하면 안 된다.
- 원형 구조로 볼 경우
- 예시
-
왜 이렇게 설계해야 할까?
-
정리 요약
2) 실무에서의 구조 예시 (NestJS 기준)
클린 아키텍처 철학을 실제 NestJS 프로젝트 폴더 구조로 현실적으로 적용한 예시이다.
- 기본 폴더 구조 예시
- 각 폴더 별 책임 다시 정리
- 의존성 주입 예시 (app.module.ts)
- 실무 적용 팁
Comments