
1. 이전 글
2. 진행 내용
- 클린 아키텍처를 적용한 특강 신청 어플리케이션 개발
2-1. 클린 아키텍처
이번 주에 진행했던 클린 아키텍처는 항해플러스를 시작하기 전 가장 기대되었던 주제 중 하나였다. 개발을 하다 보면 아키텍처에 대한 고민은 필수적으로 따라오지만, 아키텍처라는 것이 정답이 없다는 점이 항상 어렵게 느껴졌다. 구글링을 하거나 책을 읽거나, 심지어 컨퍼런스 영상을 보더라도 각자의 상황에 따라 구조가 다르기 때문에 레퍼런스를 단순히 따라 할 수는 없었다.
2주차 발제로는 레이어드 아키텍처, 헥사고날 아키텍처, 클린 아키텍처에 대해서 간략한 개념과 장/단점에 대해서 설명해주셨고, 과제로는 실무에서 보편적으로 많이 쓰이는 클린 + 레이어드 아키텍처를 사용해서 이를 기반으로 특강 신청 어플리케이션을 만들어 보는 것이였다.
과제를 통해서 내 프로젝트에 어떻게 배운 아키텍처를 녹여낼 지 고민하는 시간이 매우 유익했고. 의존성 역전 원칙(Dependency Inversion Principle)이나 계층 간의 분리, 그리고 코드의 변경 용이성을 높이는 설계에 대한 내용이 특히 흥미로웠다.





3. 과제 고민 포인트
3-1. Application(Facade) 레이어 사용?
클린+레이어드 아키텍처를 사용하면서, `Controller -> Service -> (interface) Repository <-- (implementation) Repository`에 대한 의존 방향은 설정했다. 그러나 과제 요구사항을 구현하기 위해서는 "특강"이라는 개념(도메인) 하나를 설정해서 하기엔 특강 신청이라는 기능을 구현함에 있어서 "특강"이라는 패키지 안에 전부 구현하기에는 역활과 책임의 경계가 모호하다고 판단했다.
그래서 "특강(Lecutre)"과, "특강 신청(Application)"으로 개념을 나눴는데 특강 신청을 위해서는 특강 정보를 알아야 했다. 여기서 Facade가 없다면 특강 신청 도메인에서 특강 도메인에 대한 정보를 불러오기 위해선 아래와 같은 방법을 고민해볼 수 있다.
1. ApplicationService에 LectureService 주입 ?
- 같은 레이어끼리 참조를 허용하게 되면 외부 도메인의 데이터를 받아올 수 있다. 하지만 의존 방향이 하나의 방향으로 흘러야 하는 레이어드 아키텍처의 관점에서 이는 맞지 않고, 같은 레이어끼리 참조를 허용하게 되면 순환 참조 문제가 발생할 수 있다. 예시로 이후 Lecture 쪽에서 Application 쪽을 참조해야 하는 일이 있을 때 순환참조가 발생한다.
2. ApplicationService에 LectureRepository 주입 ?
- 이는 레이어드 아키텍처 관점에서는 올바른 의존방향이다. 그러나 이런 의존 방향으로 구현하게 되면 Application에서 Lecture에 관한 쿼리를 DB에 날릴 수 있게 되며, ApplicationService에 Lecture에 대한 역할과 책임이 생기므로, SRP 원칙 위반이라고 볼 수 있다.
3. ApplicationController에 LectureService 주입 ?
- 이 방법도 레이어드 아키텍처 관점에서는 올바른 의존방향이다. 하지만 컨트롤러에 LectureService의 데이터를 받아오는 로직이 추가되는 것은 "컨트롤러" 자체의 역할에는 맞지 않기에 이 또한 SRP 원칙 위반이라고 볼 수 있다.
4. API로 호출 ?
- ApplicationService에서 LectureClient같은 API 호출 클래스를 주입받아 API로 호출해서 받아오는 방법도 있다. 마이크로서비스 아키텍처라면 적절한 선택일 것 같다. 그러나 과제의 범위는 마이크로서비스로 구현하는 것이 아닌 모놀리틱한 구조로 어플리케이션 개발을 하는것이다. 실제로 실무에서도 제대로 된 마이크로 서비스 아키텍처를 하고있는 곳은 별로 없기에 해당 방법은 오버엔지니어링이라는 판단을 했다.
위 방법 모두 전부 다 가능은 하지만 아키텍처 관점에 위반되는 사항이 있거나, 오버엔지니어링이거나, 객체지향 관점에서 위반이 발생할 수 밖에 없다. 이를 해결하고자 Controller와 Service 사이 Facade 라는 추가적인 레이어를 하나 세우게 되었다.
Facade 레이어의 역할은 여러 외부 도메인 서비스를 주입받아 Controller를 위한 응답 데이터를 가공하는 역할을 한다. 또한 추후 어플리케이션이 확장되어 이벤트 기반 아키텍처를 적용한다면 이벤트 메세지를 발행하는 책임 또한 Facade에 부여할 수 있게 되어 확장성도 용이할 것 같다는 생각을 했다.
과제에서 레이어를 추가함으로써, 순환참조 문제에서도 자유로울 수 있고, 레이어별 역할과 책임 또한 명확해져 유지보수 관점에서도 훌륭하다고 판단했다. 그러나 레이어 별 데이터를 주고받을 때도 의존 방향이 일관되어야 하기에 Facade 레이어만을 위한 DTO를 추가적으로 만들어줘야 해서 꽤나 많은 코드 중복이 생길 수 있는 단점이 있다.
개발하는 서비스가 도메인별로 잘 쪼개진 마이크로서비스라면, Facade는 필요하지 않을 수 있다. 하지만 대부분 마이크로 서비스 아키텍처로 개발하는 곳은 굉장히 드물고, "도메인"이라는 것 특성 상 경계가 모호한 경우가 많기에 Facade 레이어는 대부분의 상황에서 필요하지 않을까 싶다.
3-2. 테스트 컨테이너 vs H2 인메모리 데이터베이스
테스트 컨테이너는 애플리케이션 테스트 중 필요한 데이터베이스, 메시징 시스템 등 외부 리소스를 Docker 컨테이너로 손쉽게 실행하고 관리할 수 있게 해주는 Java 라이브러리이다.
과제를 진행하면서 h2 인메모리 데이터베이스를 이용하여 테스트하는 방법도 있지만 이는 권장사항이 아니다. 테스트 환경 자체는 실제 프로덕션 환경과 유사해야하기 때문이다.
과제에서 테스트 컨테이너를 적용하는 것은 선택사항이였으나 나는 실무에 배운 내용을 적용하기 위해서는 필수적인 사항이라고 생각했고, 이론적으로만 알고있었던 테스트 컨테이너를 실제로 적용해보는 경험을 했다.
4. 마무리
과제 진행 깃허브 레포지토리 : https://github.com/DevCHW?tab=repositories
기본 과제 PR 링크 : https://github.com/DevCHW/hhplus-cleanarchitecture/pull/2
심화 과제 PR 링크 : https://github.com/DevCHW/hhplus-cleanarchitecture/pull/3
2주차 진행 과제 2가지에 대해서도 All Pass를 하여 블루 뱃지를 획득했다 !

2주차 진행내용을 통해 "왜 이런 구조를 사용하는가?"라는 질문에 대한 답을 스스로 생각해보고, 이를 실제 코드에 녹여내는 경험을 할 수 있었다. 물론 이렇게 적용한 아키텍처가 어느 상황에서나 정답은 아니지만, 방향성은 앞으로의 개발에서 중요한 나침반 역할을 할 것 같다.
특히, 프로젝트의 성장과 함께 유지보수성을 확보하려면 단순히 기능을 구현하는 것에 그치지 않고, 어떻게 구조화해야 하는지를 계속 고민해야 한다는 점을 다시금 느꼈다. 이번 경험을 통해 배운 점들을 잘 정리해서 앞으로의 개발에 지속적으로 적용해 나가고 싶다.
'외부활동 > 항해플러스' 카테고리의 다른 글
항해플러스 백엔드 7기 수료 후기 및 회고 (2) | 2025.03.12 |
---|---|
항해플러스 3~5주차 회고 (0) | 2025.01.17 |
항해 플러스 백엔드 1주차 회고 - TDD (2) | 2024.12.22 |
항해플러스 백엔드 7기를 시작하며... (1) | 2024.12.20 |
개발을 하며 만났던 문제들과 해결 과정, 공부한 내용 등을 기록합니다.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!