1인 프로젝트의 아키텍처 선택기
목차
레이어드 아키텍처를 기본으로, 헥사고날은 왜 고려하지 않았는가
1. 당연히 레이어드 아키텍처
1인 프로젝트를 시작할 때 아키텍처 선택은 사실 고민할 것도 없었어요.
레이어드 아키텍처. 단순하고, 익숙하고, 빠르게 개발할 수 있습니다.
Controller -> Service -> Repository -> DatabaseSpring Boot로 개발하는 대부분의 프로젝트가 이 구조를 따르거든요. 튜토리얼도 이 구조고, 실무에서도 이 구조예요. 굳이 다른 걸 선택할 이유가 없었습니다.
2. 그런데 요즘 기술 블로그를 보면…
개발 공부를 하다 보면 헥사고날 아키텍처 얘기가 자주 나와요.
카카오뱅크, 카카오페이, 우아한형제들 등 국내 기술 블로그에서 “포트와 어댑터”, “클린 아키텍처” 키워드를 심심찮게 볼 수 있어요. 그래서 한번 찾아봤습니다.
헥사고날 아키텍처란?
Alistair Cockburn이 제안한 아키텍처로, 포트와 어댑터(Ports and Adapters) 아키텍처라고도 불려요.

핵심은 비즈니스 로직을 외부 세계로부터 격리시키는 거예요. UI나 Database도 “외부 요소”로 취급합니다.
장점은 분명해요
기술 교체가 쉬워요. Redis를 PostgreSQL로, REST를 gRPC로 바꿔도 도메인 로직은 그대로예요. Port 인터페이스만 Mocking하면 테스트도 간단합니다. 카카오뱅크 메시지 허브 팀도 헥사고날로 다양한 서버나 인프라 연결을 쉽게 구성했다고 해요.
3. 근데 나한테 필요할까?
결론부터 말하면, 전혀 필요 없어요.
파일 수가 2배
로그인 기능 하나 만드는데
헥사고날 (10개+ 파일)├── LoginUseCase.java (port/in)├── LoginUseCaseImpl.java (usecase)├── JwtPort.java (port/out)├── TokenPort.java (port/out)├── JwtAdapter.java (infrastructure)├── RedisTokenAdapter.java (infrastructure)├── AuthController.java (presentation)├── LoginRequest.java (dto)├── TokenResponse.java (dto)├── TokenPair.java (domain)└── RefreshToken.java (domain)레이어드 (5~6개 파일)├── AuthController.java├── AuthService.java├── JwtUtil.java├── RedisTokenRepository.java├── TokenPair.java (domain)└── dto/ (Request, Response)파일 수가 거의 2배 차이. 1인 프로젝트에서 이건 치명적이에요.
카카오페이도 제거했어요
카카오페이 홈 서비스팀은 헥사고날을 적용했다가 제거했어요.
“이미 연동 인터페이스가 외부 변화를 막아주는 훌륭한 방파제 역할을 하고 있었기 때문에 헥사고날 아키텍처의 핵심인 ‘도메인 로직 보호’라는 장점이 퇴색될 수밖에 없었습니다.”
PR 기준 8000줄 이상의 코드가 줄어들었다고 해요.
내 상황
헥사고날이 빛나는 건 gRPC + REST + WebSocket을 동시에 지원하거나, 저장소 교체가 잦거나, 대규모 팀이 협업할 때예요. 이 프로젝트는 HTTP + WebSocket 정도만 쓰고, 저장소 교체 가능성도 낮고, 1인 개발이에요. 오버엔지니어링이 확실합니다.
4. 최종 선택: 도메인 기반 멀티모듈 + 레이어드
모듈 구조
backend/├── auth/ # 인증 도메인├── user/ # 사용자 도메인├── upload/ # 파일 업로드 도메인├── core/ # 공통 유틸, 예외 처리└── bootstrap/ # 앱 실행모듈 내부 구조 (기술 기반 패키지)
user/├── controller/ # REST API├── service/ # 비즈니스 로직├── repository/ # 데이터 접근├── entity/ # JPA Entity├── domain/ # 도메인 모델│ └── vo/ # Value Objects└── dto/ # Request, Response의존성 방향

단순해요. 레이어드 아키텍처의 기본이죠.
출처: Best practices for multi-module projects with Spring Boot - Bootify
5. 그래도 멀티모듈은 유지한 이유
헥사고날은 선택하지 않았지만, 도메인 기반 멀티모듈 구조는 유지했어요.
도메인 경계가 명확해요
각 모듈이 하나의 책임을 가져요. auth는 인증만, user는 사용자만.
코드 찾기 쉬워요
“로그인 버그 수정해주세요” → auth 모듈만 보면 됨.
의존성 관리가 쉬워요
각 모듈이 필요한 의존성만 가져요. upload 모듈에 Redis 의존성 필요 없음.
나중에 분리 가능
서비스가 커지면 특정 모듈만 마이크로서비스로 분리할 수 있어요.
6. DDD는 필요한 것만
적용한 것
1. 엔티티(Entity) vs 값 객체(Value Object)

출처: Entity vs Value Object: the ultimate list of differences - Enterprise Craftsmanship
2. 도메인 모델에 비즈니스 로직 배치

Service에서 모든 로직을 처리하는 게 아니라, 도메인 객체가 자신의 행위를 책임져요.
3. 다른 애그리거트는 ID로 참조
적용하지 않은 것
- 유비쿼터스 언어 - 1인 프로젝트라 의미 없음
- Port/Adapter - 오버엔지니어링
- CQRS - 복잡도 증가 대비 이점 적음
7. 결론
아키텍처 스펙트럼
[단순 레이어드] ──── [멀티모듈] ──── [헥사고날] ──── [MSA] ↑ 내가 선택한 지점핵심
도메인별 모듈 분리, Entity/VO 구분, 도메인 모델에 로직 배치, ID 참조로 느슨한 결합은 가져갔어요. Port/Adapter 인터페이스, UseCase 인터페이스, 과도한 추상화, 유비쿼터스 언어는 버렸습니다.
1인 프로젝트에서 헥사고날은 오버엔지니어링이에요. 레이어드 + 멀티모듈이면 충분해요. 출시가 먼저고, 리팩토링은 나중입니다.
참고 자료
- PresentationDomainDataLayering - Martin Fowler
- Hexagonal Architecture - Alistair Cockburn
- 유일한 멀티모듈 헥사고날 아키텍처 - 카카오뱅크
- Hexagonal Architecture, 진짜 하실 건가요? - 카카오페이
- 멀티모듈 설계 이야기 with Spring, Gradle - 우아한형제들
- Best practices for multi-module projects with Spring Boot - Bootify
- Entity vs Value Object - Enterprise Craftsmanship
- AnemicDomainModel - Martin Fowler
- DDD - 애그리거트, 애그리거트 루트
Layered architecture as the foundation, and why hexagonal was not considered
1. Layered Architecture, Obviously
When starting a solo project, the architecture choice was a no-brainer.
Layered architecture. Simple, familiar, and enables rapid development.
Controller -> Service -> Repository -> DatabaseMost projects built with Spring Boot follow this structure. Tutorials use it, and production systems use it. There was no reason to choose anything else.
2. But Looking at Recent Tech Blogs…
While studying development, hexagonal architecture comes up frequently.
Korean tech blogs from companies like KakaoBank, KakaoPay, and Woowa Brothers (Baemin) regularly mention “ports and adapters” and “clean architecture.” So I looked into it.
What Is Hexagonal Architecture?
An architecture proposed by Alistair Cockburn, also known as Ports and Adapters architecture.

The core idea is isolating business logic from the outside world. Even UI and database are treated as “external elements.”
The Advantages Are Clear
Technology swaps are easy. Switch Redis to PostgreSQL, or REST to gRPC, and the domain logic stays the same. Testing is straightforward too — just mock the Port interfaces. KakaoBank’s messaging hub team reportedly used hexagonal architecture to easily connect to various servers and infrastructure.
3. But Do I Actually Need It?
The short answer: absolutely not.
Twice the Number of Files
Just to build a login feature:
Hexagonal (10+ files)├── LoginUseCase.java (port/in)├── LoginUseCaseImpl.java (usecase)├── JwtPort.java (port/out)├── TokenPort.java (port/out)├── JwtAdapter.java (infrastructure)├── RedisTokenAdapter.java (infrastructure)├── AuthController.java (presentation)├── LoginRequest.java (dto)├── TokenResponse.java (dto)├── TokenPair.java (domain)└── RefreshToken.java (domain)Layered (5-6 files)├── AuthController.java├── AuthService.java├── JwtUtil.java├── RedisTokenRepository.java├── TokenPair.java (domain)└── dto/ (Request, Response)The file count is nearly double. For a solo project, this is critical.
Even KakaoPay Removed It
KakaoPay’s Home Service team adopted hexagonal architecture and then removed it.
“The integration interfaces were already serving as excellent barriers against external changes, so the core benefit of hexagonal architecture — ‘protecting domain logic’ — was inevitably diminished.”
They reported that over 8,000 lines of code were reduced in the PR.
Source: Hexagonal Architecture, Are You Really Going to Do It? - KakaoPay
My Situation
Hexagonal shines when you need to support gRPC + REST + WebSocket simultaneously, when storage swaps are frequent, or when large teams are collaborating. This project only uses HTTP + WebSocket, storage changes are unlikely, and it is a solo effort. It is clearly over-engineering.
4. Final Choice: Domain-Based Multi-Module + Layered
Module Structure
backend/├── auth/ # Authentication domain├── user/ # User domain├── upload/ # File upload domain├── core/ # Shared utilities, exception handling└── bootstrap/ # App executionInternal Module Structure (Technology-Based Packages)
user/├── controller/ # REST API├── service/ # Business logic├── repository/ # Data access├── entity/ # JPA Entity├── domain/ # Domain model│ └── vo/ # Value Objects└── dto/ # Request, ResponseDependency Direction

Simple. The basics of layered architecture.
Source: Best practices for multi-module projects with Spring Boot - Bootify
5. Why Multi-Module Was Still Kept
I did not choose hexagonal, but I kept the domain-based multi-module structure.
Clear Domain Boundaries
Each module has a single responsibility. auth handles only authentication, user handles only users.
Easy to Find Code
“Please fix the login bug” -> Just look at the auth module.
Easy Dependency Management
Each module only has the dependencies it needs. The upload module does not need a Redis dependency.
Future Separation Possible
If the service grows, specific modules can be extracted into microservices.
Source: Multi-Module Design Story with Spring, Gradle - Woowa Brothers
6. DDD — Only What’s Needed
What Was Applied
1. Entity vs Value Object

Source: Entity vs Value Object: the ultimate list of differences - Enterprise Craftsmanship
2. Placing Business Logic in Domain Models

Instead of handling all logic in the Service, domain objects take responsibility for their own behavior.
3. Referencing Other Aggregates by ID
What Was Not Applied
- Ubiquitous Language - Meaningless for a solo project
- Port/Adapter - Over-engineering
- CQRS - Benefits do not justify the added complexity
7. Conclusion
Architecture Spectrum
[Simple Layered] ──── [Multi-Module] ──── [Hexagonal] ──── [MSA] ↑ Where I landedKey Takeaways
What I kept: domain-based module separation, Entity/VO distinction, business logic in domain models, and loose coupling through ID references. What I discarded: Port/Adapter interfaces, UseCase interfaces, excessive abstraction, and ubiquitous language.
Hexagonal is over-engineering for a solo project. Layered + multi-module is sufficient. Ship first, refactor later.
References
- PresentationDomainDataLayering - Martin Fowler
- Hexagonal Architecture - Alistair Cockburn
- Hexagonal Architecture in Messaging Hub - KakaoBank
- Hexagonal Architecture, Are You Really Going to Do It? - KakaoPay
- Multi-Module Design Story with Spring, Gradle - Woowa Brothers
- Best practices for multi-module projects with Spring Boot - Bootify
- Entity vs Value Object - Enterprise Craftsmanship
- AnemicDomainModel - Martin Fowler
- DDD - Aggregates and Aggregate Roots