이번에 포스팅 할 부분의 경우 소프트웨어 아키텍처에 대해서 설명을 해보려고 한다.
소프웨어 아키텍처란 시스템 아키텍처에 비해서 작은 단위의 아키텍처를 의미를 하게 된다.
또한 레거시 프로젝트를 운영을 하면서 많은 부분이 이미 엉키고 설키는 것을 볼 수 있다.
또한 팀단위로 작업을 하다 보면 많은 사람들의 생각이 다른것을 느낄 수 있다. 여기서 “중요한 것은 룰을 지키는 것”이다.
결국 나중에는 패키지 구조 와 아키텍처는 깨지기 마련이라고 생각이 든다. (처음에 잘 만든 도자기도 잘못 관리를 하게 되면 깨지기 마련이기 때문이다.)
그렇기에 소프트웨어 아키텍처의 경우 사내 혹은 팀 단위로 개발을 하게 될 경우 같이 일하는 사람들 과의 소통이 중요 하다고 생각이 든다.
일반적인 소프트웨어 아키텍처의 경우 역사적으로 MVC 패턴 부터 기반해서 자리를 잡게 되었다. 또한 MVC 아키텍처를 좀더 진화하게된 Controller, Service, Repository 로 구성된 레이어 아키텍처 가 있으며, 레이어 아키텍처를 보완한 클린아키텍처 그리고 헥사고날 아키텍처가 있다.
다만 필자가 생각하기에는 클린 아키텍처와 헥사고날 아키텍처 까지는 아직 구성을 하지 않아도 된다고 생각이 들었다. 워낙 두 아키텍처의 경우 많은 부분을 쪼개고 복잡해지는 효과가 발생이되며, 런닝 커브 또한 상당히 높은 아키텍처이기 때문이다. 팀 단위로 프로젝트를 운영을 하다보면 잘못된 방향으로 갈 수 있다고 판단을 하게 되었다.
그렇기에 많이 접하고 많이 사용되는 3계층 레이어 아키텍처에서 레이어를 하나 추가한 4계층 레이어 아키텍처가 적합하다고 생각을 하였다.
What is a 4-tier layer architecture?
4계층 레이어 아키텍처는 “사용자 인터페이스" , “응용 계층”, “도메인 계층", “인프라스트럭처 계층" 과 같이 나눌 수 있다.
계념적으로 보면 다음 과 같다.
- 사용자 인터페이스 계층 : 사용자에게 정보를 보여주고 사용작의 명령을 해석해주는 계층
- 응용 계층 : 도메인 객체가 문제를 해결하게 사용을 한다. 해당 계층에는 비지니스 로직 과 다른 시스템의 응용 계층 과 상호 작용을 하는 계층
- 도메인 계층 : 업무 단위의 계념 그리고 상황에 다른 정보 , 업무의 규칙 등을 책임 지는 계층 이다.
- 인프라스트럭처 계층 : 상위 계층을 지원하는 일반화 된 기술적 기능을 제공을 한다.
그렇다면 기존에 3계층 레이어 과 비교하면 어떻게 매핑이 되는 것일까?
- 사용자 인터페이스 는 “컨트롤러” 와 매핑
- 응용 계층의 경우 “서비스" 와 매핑
- 도메인 계층의 경우 “새로운 계층"
- 인프라 스트럭처의 경우 “레파지토리"
Advantages and disadvantages of 4-layer layers
4계층 레이어 아키텍처를 사용을 하면서 주관적인 내가 정의한 장단점은 다음과 같다.
장점
- 트랜잭션 처리 : 트랜잭션 관리에 유용하다. 계층적으로 각각의 트랜잭션을 걸어서 단독 혹은 같이 사용할 수 있기 때문에 개발자가 직접적인 컨트롤이 가능해서 성능에 밀접하게 사용을 할 수 있다.
- 유지보수성 : 만약 Query 조회 하는 플랫폼을 변경을 할 시 모든 부분을 변경을 하는 것이 아니라 인프라 스트럭처 계층 에서 레파지토리만 변경을 할 수 있다.
- 확장성 : 서비스에서 도메인을 바라 볼 때에는 어떤 “플랫폼” 혹은 무언가에 집중을 하는 것이 아니라 행동 혹은 이벤트에만 집중을 할 수 있기 때문에이다.
- 직관적 : Read 와 Wirte 의 분리 그리고 객체간의 분리가 가능 하다. 서비스는 비지니스 로직의 통합체 그리고 도메인은 직접적인 도메인의 정의 및 규칙이기 때문이다.
단점
- 복잡성 : 많은 비지니스 로직을 표현을 하다 보면 복잡해 질 수 있다.
- 유지 보수성 : 언젠가는 깨지는 위험이 있는 아키텍처 이다.
- 트랜잭션 처리 : 다만 트랜잭션 처리가 만약 미흡 하거나 길게 사용하게 되면, DB 락이 발생이 될 수 있는 단점이 있다.
다음 과 같이 매핑이 되고 Spring 에서는 어떻게 매핑이 되는지 알아보자.
Spring’s structure
Spring 에서 패키지 구조를 다음 과 같이 나눌 수 있다.
- web 의 경우 사용자 인터페이스로 사용
- service 의 경우 응용 계층으로 사용
- domain 의 경우 도메인 계층으로 사용
- dto 의 경우 데이터 전달 객체 으로 사용
- core 의 경우 전반적인 소프트웨어어에서 사용 되는 것으로 사용을 할 수 있다.
사용자 인터페이스 (Web) 패키지
web 패키지 아래는 다음 과 같이 구성이 된다. REST 규칙에 맞게 패키지를 구성을 하게 되었다. 그리고 각각의 규칙에 맞게 컨트롤러를 구성을 해준다. 여기서 패키지를 나누었던 이유는 패키지를 통해서 각각의 사용자 인터페이스를 규칙적으로 나눈 것을 명시 해주기 위함 이다.
서비스 패키지
서비스 계층에서도 각각의 도메인 (업무) 단위로 나누게 되었다. 인터페이스를 통해서 구성을 하였다.
사용자 인터페이스는 서비스에서 각각의 서비스 구현체를 바라 보는 것이 아니라 인터페이스만 바라보게 된다. 이때 큰 장점은 어떤 구현체에 “의존적" 인 것이 아니라 Service 인터페이스에만 “의존적" 이게 된다.
만약 CommentService 에서 다른 요건이 들어와서 CommentAdminService 교체가 필요한 상황이라고 한다면 CommentServiceImpl 을 교체하는 것으로만으로 정상적으로 동작을 하게 된다. DIP (의존성 역전 원칙) 을 활용할 수 있다.
서비스 계층의 경우 각각의 Domain 만 바라보게 되며, 각각의 Domain 을 합치는 역할을 하게 된다. SRP (단일 책임 원칙) 을 가지게 되면서 큰 분류의 도메인이 되는 것이다.
실질적인 비지니스의 경우 Domain 레이어에 있는 객체들이 하게 된다. “어떻게 한다” 라는 개념을 책임을 위임 하게 되는 것이다.
여기서 의존성이 단방향으로 흐르게 정의를 하고 싶어서 도메인으로 정의를 하게 하였다. 하지만 꼭 도메인 만 바라보게 되는 방식으로 작업을 하지 않아도 된다. Service 레이어 에서 Service 레이어를 바라보게만 하지 않는다면 도메인 레이어와 인프라 스트럭처 레이어를 보겠끔해도 무관하다고 생각이 든다.
도메인 패키지
도메인 레이어의 경우 작은 단위의 비지니스 로직을 관장을 하게 된다. 다만 여기서 도메인 패키지 내의 통신은 지양 해야 된다. 그렇지 않는다면 레이어를 나눈 의미가 사라지게 되기 때문이다.
단편적으로 각각의 책임을 주기 위해서 읽기 쓰기 전용 혹은 각각의 객체로 정의를 해주고 사용을 한다. 여기서 인프라스트럭처의 레파지토리만 바라보게 된다. 패키지 내의 객체의 통신은 Service 레이어에서만 꼭 하길 바란다. 그렇지 않는다면, 모든 레이어에 대한 정의가 모호해 지고 의존성의 꼬이는 현상이 발생이 되기 때문이다.
인프라 패키지
인프라 패키지의 경우 서버의 설정 그리고 레파지토리를 구현을 해준다. 외부의 의존되는 패키지이기 때문에 설정 , 그리고 레파지토리를 넣어줌으로 인해서 외부의 의존성을 많이 두는 패키지이다.
여기서 중요한 점은 만약 외부의 또 다른 플랫폼 혹은 라이브러리 변경이 있다면, infra 패키에서 추가를 해준 뒤 Domain 에서 해당 하는 부분만 변경을 해주면 Service Layer 에서는 어떤 부분도 수정이 될 필요가 없다.
즉 단순하게 플랫폼 혹은 라이브러리 변경에 유연하게 대응을 할 수 있다.
DTO 패키지
DTO 패키지의 경우 레이어간의 메세지를 전달하는 Class 를 관리하는 패키지 이다.
일반적으로 Request, Response, View, Entity 등 .. 두어서 각각의 역할에 맞게 사용을 한다. 단 해당 패키지에서는 비지니스 로직이 들어 있으면 안된다. 그렇기 때문에 그 점만 생각하고 작성을 하는 것이 중요하다.
Core 패키지
core 패키지의 경우 스프링에 관련된 혹은 서버에서 사용하는 부분을 관리하는 패키지 이다. 보통은 AOP , interceptor , utils 등 .. 을 사용을 하고 있다.
Summary
주관적인 필자가 생각한 4 계층 레이어 아키텍처에 대해서 설명을 해보았다. Spring 에서 적용하는 법 그리고 장단점에 대해서는 많은 주관적인 생각이 포함이 되어 있는점 그리고 정답은 아니기에 좋은 방향으로 고민을 해보는 것도 좋은 개발자가 되는 과정이라고 생각을 한다. 필자 또한 필요에 따라서 새로운 부분을 적용 그리고 정의를 계속하려고 하고 있으며 클린 아키텍처 혹은 헥사고날 또한 적용을 해보면서 유연하고 확장성 있는 소프트 웨어 아키텍처를 고민을 해보려고 한다.