본문으로 바로가기

클린아키텍처 - 세부사항

category software engineering 2023. 9. 3. 19:59
728x90

데이터베이스는 세부사항이다

데이터 구조는 시스템 아키텍처에서 중요하지만 데이터에 접근할 방법을 제공하는 유틸리티이고 데이터베이스는 실제로 아키텍처와는 관계 없는 일개 소프트웨어이고 기술일 뿐이다. 오래전 데이터 중심에 ‘디스크’가 있었고 이걸 RAM으로 읽는데 너무 오랜 시간이 걸렸고 이를 위해 색인, 캐시, 쿼리 계획 최적화가 필요해졌다.

시간이 지나며 이름을 기준으로 저장하거나 조회할 때 편리한 파일 시스템과 시스템 내용을 기반으로 서로 공유하는 일부 내용 기반으로 다수의 레코드를 연관짓는 RDBMS로 대표적인 시스템으로 분리되었다.

하지만 현재 디스크는 RAM으로 대체되고 있고 테이블 구조가 아니라 다루기 편리한 형태로 구조를 변경하여 입맛에 맞는 구조로 사용하기에 데이터베이스는 데이터를 저장하는 공간인 세부사항일 뿐이다.

 

웹은 세부사항이다

웹 또한 단순한 입출력 장치이고 GUI일 뿐이다. 하지만 무수한 위젯과 가젯으로 복잡함을 생각해볼 때 장치 독립성은 비현실적이라고 할 수도 있다. 하지만 UI와 어플리케이션 사이에는 추상화가 가능한 또 다른 경계가 분명히 존재한다. 각 유스케이스가 장치 독립적인 방식으로 UI라는 입출력 장치를 동작시킨다고 생각하자.

 

프레임워크는 세부사항이다

프레임워크는 풀려고 하는 문제가 많이 겹칠수록 유용하지만 실제로 당신이 풀어야할 특별한 관심사는 염두해두지 않는다. 프레임워크 개발자는 어플리케이션과 강력하게 결합되길 바라지만 사실 온전히 위험은 당신이 감수해야한다. 만약 초기에 도움이 됐더라도 프레임워크가 성숙해지고 시간이 지나며 프레임워크와 계속 싸우고 있을 수도 있다. 원치 않는 방향으로 진화하거나 새로운 프레임워크가 더 마음에 들 수도 있다.

이를 해결하기 위해 프록시를 만들고 업무 규칙에 플러그인할 수 있는 컴포넌트에 프록시를 위치시키고 핵심 코드안으로 들어오지 못하도록 해야한다. 의존성 주입은 업무 객체가 아닌 메인 컴포넌트에서 알도록하고 업무 객체는 절대 알아서 안된다.

물론 피할수 없는 경우도 있지만 피할 수 있다면 아키텍처의 안쪽 원으로 들어오지 못하도록 하자.

 

사례

책의 사례를 요약하면 아키텍처 다이어그램은 첫째로 단일 책임 원칙에 기반한 액터의 분리, 그리고 두 번째로 의존성 규칙에 따라 차원을 분리하였다. 서로 다른 이유와 속도로 변경되는 컴포넌트를 분리하는 목적이었고 그 이유가 액터와 관련이 있고 서로 다른 정책 수준을 갖고 있기 때문이었다.

 

빠져 있는 장

마지막 장이다. 이제 소프트웨어를 올바른 경계로 정의하고 명확한 책임 그리고 통제된 의존성을 가진 클래스와 컴포넌트로 구성할 수 있다. 하지만 클린 아키텍처를 제쳐두고 다른 접근법을 알아보자.

  • 계층 기반 패키지 - 코드가 하는일에 반해 코드를 분리하는 방법으로 [Controller / Service, ServiceImpl / Repository, RepositoryImpl] 로 나누는 방법이다. 복잡하지 않을 떄 무언가를 작동 시켜줄 빠른 방법이다.
  • 기능 기반 패키지 - 도메인, 서로 연관된 기능에 기반하여 수직의 얇은 조각으로 코드를 나누는 방법이다. 계층형과 비슷하지만 하나의 패키지에 속하게 된다. [Controller, Service, ServiceImpl, Repository, RepositoryImple ]. 이를 통해 변경해야할 코드를 찾기 쉬워진다.
  • 포트와 어댑터 - 내부 도메인과 외부 인프라로 구분되며 외부가 내부에 의존하는 방법이다. Order 관련 도메인 패키지가 내부며 그 외 패키지는 모두 외부이다. 의존성이 ‘내부’를 향해 흐르는 모습을 주목해야한다. 계층 기반에서 Repository, RepositoryImpl가 같이 있었지만 포트와 어댑터라면 Service, ServiceImpl, 그리고 RepositoryImpl를 알고있는 Interface 3개가 한 묶음이 되고 RepositoryImpl의 의존성이 그 인터페이스를 바라보게 된다.
  • 컴포넌트 기반 패키지 - 계층형 아키텍처는 컨트롤러 → 서비스 → 레포지토리로 의존성을 가져야하고 개발자들이 그렇게 만들어준다고 믿더라도 실제로 그렇지 않을 수도 있다. 그래서 컴포넌트 기반 패키지를 도입해야한다. 저자는 멋지고 깔끔한 인터페이스 감싸진 연관된 기능들의 묶음으로 컴포넌트를 정의하고 이를 작은 배포단위로 모든 책임을 하나의 패키지로 모으는걸 이야기한다. 모노리틱 어플리케이션에서 컴포넌트를 잘 정의하면 MSA로 가기 위한 발판으로 삼을 수 있다.

public 타입에 대해서도 좋은 이야기가 나왔는데, service와 repository 인터페이스는 외부 패키지의 클래스로부터 자신이 속한 내부로 들어오는 의존성이 존재하므로 public으로 선언되어야 하지만 구체클래스인 serviceImpl나 repositoryImpl는 protected와 같이 누구도 알 필요가 없는 제한적인 패키지로 만들어야한다.

만약 포트&어댑터였다면 OrderService와 Orders 인터페이스가 외부로 들어오는 의존성이기에 public을 지정해야하고 구현 클래스 패키지는 protected로 지정하고 런타임에 의존성을 주입할 수 있다.