클린 아키텍처에 대해 공부하기전에 기존 계층형 아키텍처가 무엇이며 어떠한 단점으로 인해 클린아키텍처가 대두되었는지 알아 보고자 한다. 계층형 아키텍처란 전통적인 웹 애플리케이션 구조이며, 웹 계층, 도메인 계층, 영속성 계층으로 구성된 3계층 구조로써 아래 와 같은 구성 모습을 보인다.
사실 계층형 아키텍처는 견고한 아키텍처 패턴이다. 다만 계층을 잘 이해하고 구성해야만 하며, 웹 계층이나 영속성 계층에 독립적으로 도메인 로직을 작성할 수 있으며 원한다면 도메인 로직에 영향을 주지 않고 웹 계층과 영속성 계층에 사용된 기술을 변경할 수도 있으며, 기존 기능에 영향을 주지 않고 새로운 기능을 추가할 수도있다. 즉 잘 만들어진 계층형 아키텍처는 선택의 폭을 넓히고 변화하는 요구사항과 외부 요인에 빠르게 적용할 수 있다.
그렇다면 계층형 아키텍처의 단점은 무엇인가.
계층형 아키텍처는 데이터베이스 주도 설계를 유도한다.
계층형 아키텍처의 토대는 데이터베이스이다. 상위계층에서 하위계층으로 의존관계가 맺어지기에 웹은 도메인계층에 의존하고, 도메인 계층은 영속성 계층에 의존하기 때문에 자연스레 데이터베이스에 의존하게 된다. 이는 다양한 문제를 초래 할 수 있는데, 흔히 비지니스 로직을 구현하는데 있어, 상태가 아니라 행동을 중심으로 모델링한다고 표현하는데 어떤 경우에건 상태가 중요한 요소이긴 하지만 행동이 상태를 바꾸는 주체이기에 행동이 비즈니스를 이끌어간다고 할 수 있다. 그렇다면 영속성 계층을 토대로 만들었던 이유는 무엇인가.
그동안 관습적으로 만들어온 애플리케이션의 유스케이스는 도메인 로직이 아닌 영속성 계층을 구현했다고 볼 수있다. 필자 역시도 10여년전 개발했을 당시 영속성 계층부터 구현을 시작하여 웹으로 이어지는 구조로 개발을 했었다. 이는 데이터베이스의 구조를 먼저 생각하고, 이를 토대로 도메인 로직을 구현했다는 의미이다.
하지만 이는 비즈니스 관점에서는 전혀 맞지 않는 방법이라고 할 수 있다. 다른 무엇보다 도메인 로직을 먼저 만들어야 하며 그래야만 로직을 제대로 이해 했는지 확인 할 수 있다. 그리고 나서 이를 기반으로 영속성 계층과 웹 계층을 만들어야 한다.
지름길을 택하기 쉬어진다
전통적인 계층형 아키텍처에서 전체적으로 적용되는 유일한 규칙은 특정한 계층에서는 같은 계층에 있는 컴포넌트나 아래에 있는 계층에만 접근 가능하다는 것이다. 이 같은 유일한 규칙은 결국 아래 계층으로 갈수록 비대해질 수 밖에 없는 이유를 야기한다.
테스트하기 어려워진다
계층형 아키텍처를 사용할 때 일반적으로 나타나는 변화의 형태는 계층을 건너뛰는 것이다. 엔티티 필드를 단 하나만 조작하면 되는 경우에 웹 계층에서 무심코 영속성 계층에 접근을 하게 된다면 말이다. 이 경우 도메인 로직을 웹 계층에 구현하게 된다는 의미이며 이는 결국 유스케이스가 확장됨에 따라 더 많은 도메인 로직이 웹 계층에 추가될 것이며 이는 애플리케이션 전반에 걸쳐 책임이 섞이고 핵심 도메인 로직이 퍼진다는 의미이다.
또한 이는 웹 계층 테스트를 구현할 경우 도메인 계층뿐 아니라 영속성 계층도 모킹을 해야 한다는 의미이며 이는 단위 테스트의 복잡도가 올라감을 의미한다.
유스케이스를 숨긴다
개발자들은 항상 새로울 유스케이스를 짜는 것을 선호한다. 그러나 실제로는 새로운 코드를 짜는 데 시간을 쓰기보다는 기존 코드를 바꾸는 데 더 많은 시간을 쓰며, 앞서 논의 했듯 계층형 아키텍처에서는 도메인 로직이 여러 계층에 걸쳐 흩어지기 쉽고 또한 계층형 아키텍처는 서비스의 '너비'에 대한 규칙을 강제하지 않으며 이는 곧 넓은 서비스는 영속성 계층에 많은 의존성을 갖게 되고, 다시 웹 레이어의 많은 컴포넌트가 이 서비스에 의존하게 만든다.
동시작업이 어려워진다.
계층형 아키텍처는 모든 것이 영속성 계층 위에 만들어지기 때문에 영속성 계층을 먼저 개발해야 하고, 그 다음에 도메인 계층을 그리고 마지막으로 웹 계층을 만들어야 한다. 때문에 특정 기능은 동시에 한 명의 개발자만 작업할 수 있다.
또한 코드에 앞서 말한 서비스의'너비'에 대해 규칙을 강제하지 않기에 넓은 서비스 안에서 서로 다른 기능을 동시에 작업하기란 더욱 어려울 것이다. 풀어 얘기한다면 서로 다른 유스케이스에 대한 작업을 하게 된다면 같은 서비스를 동시에 편집하는 상황이 발생하고, 이는 병합 충돌과 잠재적으로 이전 코드로 되돌려야하는 문제를 야기하게 된다.