01. 계층형 아키텍처의 문제는 무엇일까? #
사실 계층형 아키텍처는 ‘견고한 아키텍쳐’이다.
- (계층을 잘 이해하고 구성한다면) 웹 계층이나, 영속성 계층에 독립적으로 도메인 로직을 작성할 수 있다.
- (계층을 잘 이해하고 구성한다면) 도메인 로직에 영향을 주지 않고 웹 계층, 영속성 계층의 기술을 추가/변경할 수 있다.
- = 각각을 독립적인 계층으로 만들 수 있다.
- = 결합도를 낮출 수 있다.
잘 만들어진 ‘계층형 아키텍쳐’는 선택의 폭을 넓히고, 변화하는 요구사항과 외부 요인에 빠르게 적응할 수 있게 해준다.
" 엉클 밥에 의하면 이것이 바로 아키텍처의 전부다. “
다만, 책에서는 계층형 아키텍처는 아래와 같은 단점(특징)을 가지고 있다고 소개한다.
- 나쁜 습관(= 계층을 제대로 유지하지 않고 깨버리거나, 무시하거나 등)들이 스며들기 쉬운 아키텍쳐이다.
- 시간이 지날수록 소프트웨어를 점점 더 변경하기 어렵게 만드는 수많은 허점들을 노출하는 아키텍쳐이다.
다만, 이러한 특징도 앞서 말한 것과 같이 계층형 아키텍처를 제대로 이해하지 못하고 구성했기 때문은 아닐까…??
혹은 제대로 이해했더라도 이를 쉽게 깰 수 있게하거나, 시간이 지날수록 어쩔 수 없는 문제점들이 있다고 말하는 것 같다.
계층형 아키텍쳐는 ‘데이터베이스 주도 설계’를 유도한다. #
” 정의에 따르면 전통적인 계층형 아키텍쳐의 토대는 ‘데이터베이스’이다. “
계층형 아키텍쳐는 다음과 같이 의존 방향을 갖는다.
웹 계층 → 도메인 계층 → 영속성 계층(DB)
따라서, 결국에는 영속성 계층(DB)에 의존하게 된다.
우리가 만드는 대부분의 애플리케이션의 목적이 무엇인지 생각해보자.
(우리는 대부분)‘비즈니스를 관장하는 규칙/정책’을 반영한 모델을 만들어서, 사용자가 이 규칙/정책을 더욱 편리하게 활용할 수 있게 하는 것에 목적을 둔다.
이때, 우리는 상태(state)가 아니라 행동(behavior)을 중심으로 모델링한다.
‘상태(state)‘가 중요한 요소이긴 하지만 행동(behavior)이 상태(state)를 바꾸는 주체이기 때문에 행동(behavior)이 비즈니스를 이끌어간다.
그렇다면 우리는 왜 ‘도메인 로직’이 아닌 ‘데이터베이스’를 토대로 아키텍쳐를 만드는걸까?
그동안 우리가, 내가 작업했던 방식을 돌이켜보면 데이터베이스를 먼저 설계하고 이를 토대로 도메인 로직을 구현했다.
- 실제로 이것은 전통적인 계층형 아키텍쳐에서 합리적인 방법이다. (‘의존성의 뱡향’에 따라 자연스럽게 구현한 것이기 때문이다.)
- ORM 프레임워크를 사용하기 때문이다.
하지만 이러한 순서(DB 설계가 먼저 진행되는 것)는 비즈니스 관점에서는 전혀 맞지 않다.
비즈니스 관점에서는 도메인 로직(=비즈니스 로직 부분, 서비스 계층 등 으로 볼 수 있다.) 이 먼저 작성되어야 한다.
일반적으로 내가 작성해왔던, 혹은 ORM에 의해 관리되는 엔티티들은 아래와 유사한 구조로 관리되어왔다.
도메인 계층 서비스
|
----------
| |
영속성 계층 엔티티 ← 레포지토리
이 경우 아래와 같은 단점이 발생한다.
1. 영속성 계층과 도메인 계층에 강한 결합이 생긴다.
- 영속성 계층 변경 시 도메인 계층에 영향을 미친다.
2. 도메인 계층(서비스)에서 영속성 계층을 위한 작업(TX 관리, 즉시로딩/지연로딩, 플러시 등등)을 해줘야한다.
지름길(= 나쁜길)을 선택하기 쉬워진다. #
계층형 아키텍쳐에서의 유일한 규칙은 ‘특정 계층에서는 같은 계층 or 아래 계층만 접근 가능하다’는 것이다.
팀마다 다를 수 있지만 보통 위 규칙 외에 다른 규칙을 강제하지는 않는다.
다만 여러가지 상황이 발생할 수 있다.
1. ‘A’ 컴포넌트를 개발 후에 어떤 계층에 넣을 것인지?
- 이 경우, A 컴포넌트를 아무 곳에서나 쓸 수 있게 하기 위해서 밑에 계층(도메인, 영속성 계층)에 둘 수 있다.
- 이를 위한 명확한 규칙도 없다. (물론 감각적으로, 혹은 팀에서 정한 룰이 있을 것이다.)
2. 중간 계층을 건너뛸 수도 있다.
- 이것들이 쌓이면 통일성, 유지보수가 힘들어질 것이다.
” 계층형 아키텍쳐를 사용할 때 일반적으로 나타나는 변화의 형태이다. “
3. 아래 계층(도메인, 영속성 계층)은 점점 더 비대해진다.
- (1번과 비슷한 의미로) 무심코 개발한 컴포넌트(헬퍼, 유틸리티성 등)를 아래 계층으로 내릴 가능성이 크다.
이러한 나쁜, 통일되지 않는 규칙들을 제거/관리하고 싶다면, 규칙을 코드/빌드 레벨단에서 강제해야 할 것이다.
여기서 말한 코드/빌드 레벨이란, 아래와 같은 것들을 의미한다.
- 빌드가 실패되게 한다.
- MR(PR)을 허용되지 않게 한다.
- 커밋(commit)이 허용되지 않게 한다.
테스트하기 어려워진다. #
책에서 말한 내용은 계층형 아키텍처를 잘 사용하지 못했을 때(예를 들어, “지름길(= 나쁜길)을 선택하기 쉬워진다.” 의 내용들이 기반일 때)에 특히나 나타날 수 있는 내용들인 것 같다.
예를 들어, 중간 계층을 건너뛰는 코드가 있을 때 ‘컨트롤러 테스트에서 영속성 코드가 발생하고, 이것들을 테스트하기 어렵다’는 내용이다.
이 비유법은 적절한건가? 다른 아키텍쳐였더라도 잘못 사용했더라면 이런 문제점은 똑같이 발생하지 않을까??
(= 즉, 규칙을 잘 지킨다는 가정을 하면 다른 아키텍처들과 비슷하지 않을까??)
유스케이스를 숨긴다. #
아래 내용은 다른 아키텍쳐에서도 발생하면 똑같이 어려움을 겪는 문제다.
다만 다른 아키텍쳐에서는 아래의 내용들을 나름(?) 강제하고 있나보다.
책에서는 계층형 아키텍처는 아래와 같은 것들을 이야기 할 때, “발생하기 쉽다” 고 이야기한다.
이 점을 인지하면서 읽으면 더욱 좋을 것 같다.
계층형 아키텍쳐에서는 ‘도메인 로직’이 여러 계층(웹, 도메인, 영속성)에 흩어지기 쉽다.
- (이런 경우) 새로운 코드를 추가할 적당한 위치를 찾는 것은 이미 어려워진 상태다.
- (이런 경우) 이미 관리/유지보수가 어려워진 상태다.
계층형 아키텍쳐에서는 도메인(서비스)의 ‘너비’에 관한 규칙을 강제하지 않는다.
- 1개의 서비스가 모든 로직(ex, CRUD)을 담당하는 넓은 서비스가 만들어지기 쉽다.
동시 작업이 어려워진다. #
(이것도 잘 사용하지 못해서일 가능성이 크지만) 이 부분은 공감한다.
” 지연되는 소프트웨어 프로젝트에 인력을 더하는 것은 개발을 늦출 뿐이다. “
계층형 아키텍쳐에서는 동시 작업이 가능하게 하는 측면에서 그다지 도움이 되지 않는다.
- 계층형 아키텍처에서는 ‘데이터베이스’를 먼저 작업하기 때문에 영속성 계층이 작업되기 전까지 웹, 도메인 계층을 작업하기 힘들다.
- 계층형 아키텍처에서는 ‘넓은’ 서비스를 만들기 쉽게 하기 때문에, 결합도를 높여 같이 작업하기 힘들게 만든다.
+ 동시 작업에 대해서 예시를 들면, 아래와 같이 분배할 수 있을 것이다.
- 한 명은 웹 계층, 한 명은 도메인 계층, 한 명은 영속성 계층
- 한 명은 A(웹, 도메인, 영속성), 한 명은 B(웹, 도메인, 영속성)
유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 될까? #
올바르게 구축하고, 몇 가지 추가적인 규칙들을 적용하면 계층형 아키텍쳐는 유지보수하기 매우 쉬워지며 코드를 쉽게 변경하거나 추가할 수 있게 된다.
그러나 계층형 아키텍쳐에서는 많은 것들이 잘못된 방향으로 흘러가도록 용인하고, 쉽게 허용한다.
따라서, 철저하게 관리하지 않으면 시간이 지날수록 ‘잘’ 관리되기 힘들다.
” 특히, 이러한 규칙은 보통 마감일이 설정되었을 때 조금씩 느슨해지기 마련이다. “
계층형 아키텍쳐로 만들든 다른 아키텍쳐 스타일로 만들든, 계층형 아키텍쳐의 함정을 인지하고 지름길을 택하지 않는다면, 유지보수하기에 더 쉬운 솔루션을 만드는 데 도움이 될 것이다.