클린 아키텍처(Clean Architecture)는 소프트웨어 시스템의 유지보수성, 확장성, 독립성을 극대화하기 위해 설계된 구조적 아키텍처다. 로버트 C. 마틴(일명 ‘아저씨’)이 제안한 개념으로 모든 시스템의 핵심은 의존성 방향과 책임의 분리에 있다고 강조한다. 핵심은 단 하나다.
비즈니스 로직(core)는 프레임워크, 데이터베이스, UI 등 어떤 외부 기술에도 의존하지 않아야 한다.
소프트웨어에서 “컴포넌트”는 재사용 가능하고 독립적인 단위의 코드 조각을 말한다. 일반적으로는 하나의 모듈, 클래스, 혹은 레이어를 말하며 명확한 책임을 가진다.
저수준 컴포넌트는 구현 세부사항에 가까운 코드다. 일반적으로는 외부 기술, 프레임워크, DB, UI 등 인프라스트럭처나 외부 의존성에 가까운 것들이다.
저수준 컴포넌트 | 설명 |
---|---|
JpaRepository , JdbcTemplate | DB와 직접 통신하는 DAO 계층 |
RestTemplate , WebClient | 외부 API 호출 |
Controller , View , HTML , Thymeleaf | UI 계층 |
Redis , Kafka , Elasticsearch | 기술 의존 인프라 |
S3Uploader , EmailSender | 특정 기술에 의존적인 구현 |
이들은 시스템의 중심이 아니라 도구다. 언제든 바뀔 수 있어야 하므로 핵심 로직이 이들에 의존하면 안 된다.
고수준 컴포넌트는 비즈니스 규칙을 포함한 핵심 도메인 로직이다. 시스템의 동작 목적을 정의하며 외부 기술에 전혀 의존하지 않아야 한다.
고수준 컴포넌트 | 설명 |
---|---|
UseCase , Service , Application Logic | 핵심 시나리오 처리 로직 |
Domain Entity , Value Object | 도메인 주도 설계의 중심 객체 |
Port Interface | 외부 의존성과의 계약(Contract) 역할 |
Business Rule Validator | 도메인 제약 조건 및 정책 |
고수준 모듈은 저수준 모듈에 의존해서는 안 된다. 둘 다 **추상화된 인터페이스에 의존해야 한다.
// 고수준
public interface CouponRepository {
void save(Coupon coupon);
}
// 저수준
@Repository
public class JpaCouponRepository implements CouponRepository {
@Override
public void save(Coupon coupon) {
jpaRepo.save(coupon);
}
}
CouponService
는 CouponRepository
인터페이스만 의존하고 그 구현체는 나중에 주입된다. 이로써 비즈니스 로직이 JPA인지 MongoDB인지 Redis인지 알 필요가 없다.
구성 요소 | 위치 | 설명 |
---|---|---|
Controller , DTO | Interface Adapter | 요청/응답 처리 |
Service , UseCase | Application Layer | 시나리오 단위 처리 |
Domain , Entity , VO , Validator | Domain Layer | 비즈니스 규칙 |
JpaRepository , S3Uploader , KafkaProducer | Infrastructure Layer | 외부 시스템 연동 |
그리고 핵심은 항상 “Domain은 외부 기술을 전혀 몰라야 한다”는 것이다.
이전까지는 Service가 Controller 아래에 있다고만 생각했지 이 구조 속에서 누가 누굴 의존해야 하는가에 대해 명확한 기준이 없었다. 클린 아키텍처를 통해 ‘책임의 방향’을 정하고 ‘의존성은 항상 저수준을 향하지 않게’ 구조를 짜면서 확실한 기준을 세울 수 있었다. 이제 어떤 프레임워크나 DB, 메시징 시스템을 쓰더라도 내 로직은 바뀌지 않도록 설계할 수 있다는 자신감이 생겼다. 유지보수하기 편한 구조를 고민할 때 더는 ‘Controller -> Service -> Repository’가 아니라 ‘비즈니스는 가장 안쪽에 있어야 한다’는 관점으로 생각하는 계기가 되었다.