계층형 아키텍처의 문제는 무엇일까?

log.yunsik·2023년 6월 21일
0
post-custom-banner

계층형 아키텍처는 데이터베이스 설계를 유도한다

  • 모든 것이 영속성 계층을 토대로 만들어진다. 웹 계층은 도메인 계층에 의존하고, 도메인 계층은 영속성 계층에 의존하기 때문에 자연스레 데이터베이스에 의존하게 되기 때문이다.

  • 우리가 만드는 애플리케이션의 목적은 비즈니스 규칙이나 정책을 반영한 모델로 만들어서 사용자가 더욱 편리하게 활용할 수 있게 한다. 이때 우리는 상태가 아니라 행동을 중심으로 모델링한다. 따라서 데이터베이스의 구조를 먼저 생각하고 이를 토대로 도메인 로직을 구현하는 것은 비즈니스 관점에서 전혀 맞지 않는 방법이다. 도메인 로직을 먼저 만들어야 한다. 그래야만 우리가 로직을 제대로 이해했는지 확인할 수 있다. 그리고 도메인 로직이 맞다는 것을 확인한 후에 이를 기반으로 영속성 계층과 웹 계층을 만들어야 한다.

ORM 사용시 주의사항

  • ORM 프레임워크를 계층형 아키텍처와 결합하면 비즈니스 규칙을 영속성 관점과 섞고 싶은 유혹을 쉽게 받는다.

  • 그림과 같이 ORM에 의해 관리되는 엔티티들은 일반적으로 영속성 계층에 둔다. 계층은 아래 방향으로만 접근 가능하기 때문에 도메인 계층에서는 이러한 엔티티에 접근할 수 있고 사용되기 마련이다. 이렇게 되면 영속성 계층과 도메인 계층 사이에 강한 결합이 생긴다. 서비스는 영속성 모델을 비즈니스 모델처럼 사용하게 되고 이로 인해 도메인 로직뿐만 아니라 즉시로딩/지연로딩, 데이터베이스 트랜잭션, 캐시 플러시 등등 영속성 계층과 관련된 작업들을 해야만 한다. 영속성 코드가 도메인 코드에 녹아들어가서 둘 중 하나만 바꾸는 것이 어려워진다. 이는 계층형 아키텍처의 목표와 정확히 반대되는 상황이다.

지름길을 택하기 쉬워진다

  • 계층형 아키텍처에서 적용되는 유일한 규칙은 특정한 계층에서 같은 계층에 있는 컴포넌트나 아래에 있는 계층에만 접근 가능하다는 것이다.

  • 만약 상위 계층에 위치한 컴포넌트에 접근해야 한다면 컴포넌트 계층을 아래로 내려버리면 된다. 그러면 접근 가능하게 되고 문제가 해결된다. 하지만 이는 하위 계층을 비대하게 만든다.

  • 어떤 계층에서도 속하지 않는 것처럼 보이는 헬퍼 컴포넌트나 유틸리티 컴포넌트들이 아래 계층으로 내릴 가능성이 큰 후보이다.

테스트하기 어려워 진다


계층형 아키텍처를 사용할 때 일반적으로 나타나는 변화의 형태는 계층을 건너뛰는 것이다. 엔티티 필드를 단 하나만 조작하면 되는 경우에 웹 계층에서 바로 영속성 계층에 접근하면 도메인 계층을 건드릴 필요가 없다. 하지만 이는 두가지 문제점이 있다.

  • 도메인 로직을 웹 계층에 구현하게 된다는 것이다. 앞으로 유스케이스가 확장된다면 더 많은 도메인 로직을 웹 계층에 추가해서 애플리케이션 전반에 걸쳐 책임이 섞이고 핵심 도메인 로직들이 퍼져나갈 확률이 높다.

  • 웹 계층 테스트에서 도메인 계층뿐만 아니라 영속성 계층도 모킹해야 한다는 것이다. 이렇게 되면 단위 테스트의 복잡도가 올라간다. 시간이 흘러 웹 컴포넌트의 규모가 커지면 다양한 영속성 컴포넌트에 의존성이 많이 쌓이면서 테스트의 복잡도를 높인다. 어느 순간에는 실제로 테스트를 작성하는 것보다 종속성을 이해하고 목을 만드는데 더 많은 시간이 걸리게 된다.

유스케이스를 숨긴다

  • 계층형 아키텍처에서는 도메인 로직이 여러 계층에 걸쳐 흩어지기 쉽다. 유스케이스가 간단해서 도메인 계층을 생략한다면 웹 계층에 존재할 수도 있고, 도메인 계층에과 영속성 계층 모두에서 접근할 수 있도록 특정 컴포넌트를 아래로 내렸다면 영속성 계층에 존재할 수도 있다. 이럴 경우 새로운 기능을 추가할 적당한 위치를 찾는 일은 이미 어려워진 상태이다.

  • 계층형 아키텍처는 도메인 서비스의 너비에 관한 규칙을 강제하지 않는다.

  • 시간이 지나면 여러 개의 유스케이스를 담당하는 아주 넓은 서비스가 만들어지기도 한다. 넓은 서비스는 연속성 계층에 많은 의존성을 갖게 되고 다시 웹 레이어의 많은 컴포넌트가 이 서비스에 의존하게 된다. 그럼 서비스를 테스트하기도 어려워지고 작업해야 할 유스케이스를 책임지는 서비스를 찾기도 어려워진다.

동시 작업이 어려워진다

  • 애플리케이션에 새로운 유스케이스를 추가한다고 상상해보자. 계층별로 한 명은 웹 계층에 필요한 기능을 추가하고 한 명은 도메인 계층에, 나머지 개발자는 영속성 계층에 기능을 추가할 수 있다. 하지만 계층형 아키텍처에서는 모든 것이 영속성 계층 위에 만들어지기 때문에 영속성 계층을 먼저 개발해야 하고 그 다음에 도메인 계층을 마지막으로 웹 계층을 만들어야 한다. 그렇기 때문에 특정 기능은 동시에 한 명의 개발자만 작업할 수 있다.

  • 개발자들이 인터페이스를 같이 먼저 정의하고 인터페이스들로 먼저 작업하면 된다고 이야기할 수도 있지만 이는 데이터베이스 주도 설계를 하지 않는 경우에만 가능하다. 데이터베이스 주도 설계는 영속성 로직이 도메인 로직과 너무 뒤섞여서 각 측면을 개별적으로 작업할 수 없기 때문이다.

  • 코드에 넓은 서비스가 있다면 서로 다른 기능을 동시에 작업하기가 더욱 어렵다. 서로 다른 유스케이스에 대한 작업을 하게 되면 같은 서비스를 동시에 편집하는 상황이 발생하고 이는 병합 충돌과 잠재적으로 이전 코드로 되돌려야 하는 문제를 야기하기 때문이다.

유지보수 가능한 소프트웨어를 만드는데 어떻게 도움이 될까?

계층형 아키텍처를 올바르게 구축하고 몇 가지 규칙들을 적용하면 유지보수하기 매우 쉬워지며 코드를 쉽게 변경하거나 추가할 수 있게 된다.

그러나 계층형 아키텍처는 많은 것들이 잘못된 방향으로 흘러가도록 용인한다. 엄격한 훈련 없이는 시간이 지날수록 품질이 저하되고 유지보수하기가 어려워지기 쉽다.

계층형 아키텍처로 만들든 다른 아키텍처 스타일로 만들든 계층형 아키텍처의 함정을 염두에 두면 지름길을 택하지 않고 유지보수하기에 더 쉬운 솔루션을 만드는데 도움이 될 것이다.

post-custom-banner

0개의 댓글