일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 |
- EffectiveJava
- 파이썬
- lombok
- interceptor
- Spring Security
- 배낭문제
- 자바
- TDD
- thymeleaf
- 클린아키텍처
- 이펙티브자바
- cache
- 캐시
- JVM
- @Transactional
- 타임리프
- Java
- 알고리즘
- AOP
- JPA
- BFS
- Transactional
- spring
- 코딩테스트
- collapse
- effective java
- Garbage Collection
- 동시성처리
- EntityGraph
- 멱등성
- Today
- Total
Jinnie devlog
클린아키텍처가 도대체 뭔데... 본문
기존에 개인적인 프로젝트나 팀 프로젝트를 몇 번 진행해봤지만, 아키텍처를 고민해본 적은 없는 것 같다.
Spring 프레임워크의 기본 MVC 패턴만 고려하여 Controller, Service, ServiceImpl, Repository 까지만 작성을 했었는데 이번에 루퍼스 과제를 진행하면서 클린 아키텍처에 대해 알게되었다. 아니 아직 잘 모른다...
TDD를 하면서 가장 기본적인 패키지 구조부터 잘 모르니 너무 막막했다.
우선 멘토링을 들으면서 알게되었는데 MVC랑 클린 아키텍처는 비교 대상이 아니고, MVC는 클린 아키텍처의 Interface Adapters 계층에서 구현 가능하다. 즉, 클린 아키텍처는 MVC를 포함할 수 있는 더 넓은 개념이다!
단, MVC는 프레임워크 중심 설계이고, 클린 아키텍처는 도메인 중심 설계인 것.
클린아키텍처는 도메인 중심의 아키텍처로서, 도메인 계층을 제외한 모든 계층은 분리되어야 하는 외부 요소로 취급한다.
즉, 도메인 주도 설계(DDD)를 지원하는 아키텍처이다.
클린아키텍처와 반대된다고 볼 수 있는 계층형 아키텍처에서 계층 간 의존성은 항상 다음 계층인 아래 방향을 가리킨다.
계층형 아키텍처에는 여러가지 문제가 있지만 가장 문제는, 계층의 의존성이 영속성 계층을 향한다는 것이다.
우리가 만드는 프로젝트의 목적은 도메인이자 비즈니스이고, 각각의 비즈니스 규칙과 비즈니스 모델을 만들고 유지보수하는 것이 목적이다. 그런데 계층형 아키텍처 입장에서는 데이터베이스를 바탕으로 아키텍처를 만들고 있는 것이다.
클린아키텍처는,
의존성의 방향으로 도메인 계층이 외부 요소에 의존하지 않고, 프레젠테이션 계층, 영속성 계층이 도메인 계층에 의존한다.
외부에 포함된 기술적인 컴포넌트를 어댑터(Adapter) 라고 부르고, 어댑터가 내부와 상호작용 하는 접점을 포트(Port)라고 한다.
"도메인", "의존성" 이 가장 핵심인 것 같다.
의존성은 바깥에서 안쪽으로만 향해야 한다. 즉, 도메인 게층은 프레임워크, UI, DB를 전혀 몰라야 한다.
계층형 아키텍처에서 계층 간 의존성은 다음 계층인 아래 방향을 가리키는데, 그 말은 영속성 계층을 변경할 때마다 도메인 계층도 함께 변경해야 한다는 의미이다.
영속성 코드가 바뀐다고 해서 도메인 코드까지 바꾸지 않으려면, 의존석 역전 원칙을 적용하면 된다.
여기서 의존성 역전 원칙이란,
- 고수준 모듈은 저수준 모듈에 의존해서는 안된다. 추상화에 의존해야 한다.
- 추상화는 구체적인 것에 의존해서는 안된다. 구체적인 것이 추상화에 의존해야 한다.
클린 아키텍처의 의존성은 밖에서 안으로 향하고, 바깥 원은 안쪽 원에 영향을 미치지 않는다. 경계의 바깥으로 갈수록 덜 중요하고 세부적인 영역으로 표현되며, 안으로 갈수록 더 고수준(좀 더 추상화된 개념)으로 표현된다.
=> 바깥 원은 안쪽 원에 영향을 미치지 않는다!!
회원가입과 주문으로 각 계층에 대하여 예를 들어 보자면 아래와 같다.
1. Entities (도메인 엔티티)
- 핵심 비즈니스 로직, 불변의 규칙. 외부 기술 의존 없음
- 예: User, Order, Account
2. Use Cases (애플리케이션 서비스)
- 특정 시나리오를 수행하는 규칙. 도메인 엔티티를 사용하여 흐름 제어.
- 예: 회원가입, 주문 생성
3. Interface Adapters
- 외부 시스템과 내부 유스케이스 연결
- 예: Controller, Repository 구현체
4. Frameworks & Drivers
- 가장 바깥 계층, 교체 가능해야 함
- UI(React, Thymeleaf), DB(JPA, MyBatis), 프레임워크(Spring)
정리
이론적으로는 이해가 되었는데, 실제 코드를 작성할 때는 잘 지키지 못한 것 같다.
과제를 하면서 궁금했던 두 가지 사항이 있었는데, 생각해보면 이것들이 다 클린아키텍처와 연관이 있는 것 같다.
1. 왜 Entity ↔ DTO 변환을 해서 사용하는가?
- Controller -> UseCase -> Domain 흐름에서 의존성 역전을 지키기 위해
- DTO는 adapter 계층의 개념. 엔티티는 domain 계층의 개념
- 즉, 서로 다른 계층이 직접 의존하지 않도록 중간에 DTO를 둔다.
public record UserResponse(String userId, String email) {
public static UserResponse from(User user) {
return new UserResponse(user.getUserId(), user.getEmail());
}
}
2. Request / Response DTO를 따로 두는 이유
- 요청(Request): 유효성 검증 목정 (@NotNull, @Email 등)
- 응답(Response): 클라이언트에 필요한 데이터만 제공 (민감 정보 제외)
- 즉, Input과 Output 요구사항이 다르기 때문
public record SignUpRequest(String userId, String password, String email){}
public record UserResponse(String userId, String email(){}
결론적으로 TDD 과제는 제출 했지만, 말그대로 테스트만 가능한 형태이고 각 계층들의 역할과 책임은 깊게 고려하지 않은 것 같다.
앞으로는 각 계층의 책임을 명확히 구분하고, 도메인 로직을 중심으로 한 설계와 테스트 작성에 집중하여 유지보수성과 테스트 용이성을 갖춘 코드를 작성하고자 한다...홧팅
'교육' 카테고리의 다른 글
@Transactional 남용 줄이기 도전기 - 두 번의 삽질 (4) | 2025.08.08 |
---|---|
WIL - 3주차 (Domain Modeling) (1) | 2025.08.03 |
WIL - 2주차 (Software Design) (0) | 2025.07.25 |
좋아요 토글 API, REST스럽게 만들기 (3) | 2025.07.25 |
WIL - 1주차 (TDD) (0) | 2025.07.18 |