-
Notifications
You must be signed in to change notification settings - Fork 0
Description
계층형 아키텍처의 문제는 무엇일까?
계층형 아키텍처는 코드에 나쁜 습관들이 스며들기 쉽게 만들고 시간이 지날수록 소프트웨어를 점점 변경하기 어렵게 만드는 수많은 허점들을 노출한다.
계층형 아키텍처는 데이터베이스 주도 설계를 유도한다.
계층형 아키텍터의 토대는 데이터베이스이다. 웹 계층은 도메인 계층에 의존하고 도메인 계층은 영속성 계층에 의존하기 때문에 자연스레 데이터베이스에 의존하게 된다. 모든 것이 영속성 계층을 토대로 만들어지므로 다양한 문제를 초래한다.
계층형 아키텍처에서는 도메인 로직을 먼저 구현하는게 아닌 데이터베이스의 구조를 먼저 생각하고 이를 토대로 도메인 로직을 구현하게 된다. 의존성 방향에 따라 자연스럽지만 비즈니스 관점에서는 전혀 맞지 않는 방법이다. 무엇보다 도메인 로직을 먼저 만들어야 로직을 제대로 이해했는지 확인할 수 있고 이를 기반으로 영속성 계층과 웹 계층을 만들어야한다.
데이터베이스 중심적인 아키텍처가 만들어지는 가장 큰 원인은 ORM 프레임워크를 사용하기 때문이다. ORM 프레임워크를 계층형 아키텍처와 결합하면 비즈니스 규칙을 영속성 관점에서 섞고 싶은 유혹이 생긴다. ORM에 의해 관리되는 엔티티들은 일반적으로 영속성 계층에 둔다. 계층은 아래 방향으로만 접근 가능하기 때문에 도메인 계층에서는 엔티티에 접근할 수 있다. 이러한 접근은 분명 사용되기 마련이다. 하지만 이렇게 되면 영속성 계층과 도메인 계층 사이에 강결합이 생기고 서비스는 영속성 모델을 비즈니스 모델처럼 사용하게 되면서 이로 인해 도메인 로직뿐만 아니라 즉시 로딩/지연 로딩, 트랜잭션, 캐시 플러스 등등 영속성 계층과 관련된 작업을 해야만 한다. 영속성 코드가 도메인 코드에 녹아들게 되면서 사실상 하나만 바꾸는 것이 어려워진다.
지름길을 택하기 쉬워진다.
계층형 아키텍처의 규칙은 특정한 계층에서는 같은 계층의 컴포넌트나 아래에 있는 계층에만 접근 가능하다는 것이다. 만약 상위 계층에 위치한 컴포넌트에 접근해야한다면 간단한 방법은 해당 컴포넌트 계층을 아래로 내려버리면 된다. 한번은 괜찮겠지만 이것이 지속적으로 발생하면 영속성 계층에 헬퍼, 리포지토리, 유틸리티 등등이 추가되면서 점점 비대해진다.
지름길 모드를 끄고 싶다면 추가적인 아키텍처 규칙을 강제하지 않는 한 계층은 최선의 선택이 아니다.
테스트하기 어려워진다.
계층형 아키텍처를 사용할때 일반적으로 나타나는 변화의 형태는 계층을 건너뛰는 것이다. 엔티티 필드 하나만 조작해야하는 요구사항이라면 웹 계층에서 바로 영속성 계층에 접근하면 도메인 계층은 건드릴 필요가 없지 않을까? 이것이 반복되면 문제가 생긴다.
첫 번째 문제는 도메인 로직을 웹 계층에서 구현하게 된다. 유즈케이스가 확장되면 더 많은 도메인 로직이 웹 계층으로 확산되면서 책임이 섞이고 로직이 파편화된다.
두 번째 문제는 웹 계층 테스트에서 도메인 계층뿐만 아니라 영속성 계층도 모킹해야되면서 테스트 복잡도가 올라간다.
유즈케이스를 숨긴다.
기능을 추가하거나 변경할 적절한 위치를 찾는일이 빈번하기 때문에 아키텍처는 코드를 빠르게 탐색하는 데 도움이 돼야 한다.
계층형 아키텍처는 도메인 로직이 여러 계층에 걸쳐 흩어지기 쉽다.(강제하지 않기 때문) 그리고 도메인 서비스 너비에 대한 규칙을 강제하지도 않는다. 그래서 공통적인 AService가 특정 도메인의 모든 로직을 포함하곤 한다. 만약 고도로 특화된 좁은 도메인 서비스가 유즈케이스 하나씩만 담당하게 한다면 이런 작업들이 얼마나 수월할까? userService가 아니라 RegisterUserService를 열어서 바로 작업하면 되는 것처럼 말이다.
동시 작업이 어려워진다.
특정 날짜까지 소프트웨어가 완성돼야 한다는 것은 여러 작업을 동시에 해야하는 것을 의미한다. 대부분 서로의 도움을 주고받으며 개발해야하는데 계층형 아키텍처는 동시 작업 측면에서 도움이 되지 않는다.
3명이 개발자가 있을때 한명은 웹, 한명은 도메인, 한명은 영속성 계층을 개발할 수 있을까? 계층형은 영속성 계층 위에 만들어지기 때문에 영속성 계층부터 개발해야 한다. 물론 인터페이스들로 작업하면 될 수 있지만 이는 데이터베이스 주도 설계를 하지 않는 경우에만 가능하다. 데이터베이스 주도 설계는 영속성 로직이 도메인 로직과 뒤섞여서 각 측면을 개별적으로 작업할 수가 없기 때문이다.
코드에 넓은 서비스가 있다면 서로 다른 기능을 동시에 작업하기 더욱 어렵다. 이는 merge conflict와 잠재적으로 이전 코드를 되돌려야하는 문제를 야기한다.