아키텍처를 설계하고, 좋은 코드를 작성하는 방법에 대해 고민하는 과정들은 결국 "좋은" 소프트웨어를 구현하기 위한 것일 것이다.
그렇다면 아키텍처를 구상해보기 전에, "좋은" 소프트웨어란 무엇일까에 대해 집어보자.
좋은 소프트웨어 시스템?
소프트웨어의 가치는 행위 가치와 구조 가치로 나뉘고, 소프트웨어를 정말로 부드럽게(Soft) 만드는 것은 구조 가치이다.
Clean Architecture - Robert C. Martin
☝ 행위 가치 : 소프트웨어의 기능
☝ 구조 가치 : 소프트웨어 아키텍처
로버트는 코드와 설계의 구조를 깔끔하게 만들려는 생각을 하지 않고 기능 구현만 목적으로 삼으면 소프트웨어가 엉망이 된 상황에 대처하는 데 더 많은 비용이 든다며 구조 가치. 즉, 아키텍처 설계에 대한 중요함을 강조한다.
이 말을 다른 시야로 해석한다면 결국 책에서 말하고 있듯, “기능이 잘 동작하는 것과 더불어 이해하기 쉽고 변경하기 쉬운 시스템” 을 만드는 것이 중요하다는 의미로 해석된다.
개발자의 역할은 문제 영역의 비즈니스 로직을 분석 및 이해하고 프로그래밍 언어라는 도구로 잘 표현하는 일이다. 여기서 잘 표현한다는 것은 기능이 잘 동작하는 것과 더불어 이해하기 쉽고 변경하기 쉬운 시스템을 만드는 것을 의미한다.
도메인 주도 설계로 시작하는 마이크로서비스 개발 - 3장 중…
기능이 잘 동작하며, 유지보수에 유연하고, 변화에 빠르고 부드럽게 대응 할 수 있는 시스템을 만들자.
그러한 시스템을 만들기 위해서는 어떤 것들을 고려해야 할까?
- 관심사의 분리 (separation of concerns)
- 비지니스 로직과 기술 로직을 구분하자.
- 데이터베이스 중심의 아키텍처에서 벗어나자. (비지니스 중심의 아키텍처를 지향하자.)
- 데이터베이스 중심의 아키텍처를 기반으로 작업을 하게 된다면, 중심이 되는 곳이 데이터베이스이기 때문에 클라우드 인프라를 사용하는 가장 큰 장점인 자동 스케일 아웃이 의미가 없어진다. 백날 애플리케이션을 확장해봤자, 결국 부하가 가장 크게 일어나는 곳은 데이터베이스이기때문에 얻을 수 있는 효과가 미미하다.
- 비지니스 중심의 아키텍처.
- 헥사고날 아키텍처
- 클린 아키텍처
마이크로서비스 아키텍처
MSA와 유사한 구조를 가진다는 DDD 설계 방식을 따르는 헥사고날 아키텍처, 클린 아키텍처를 참고하여 다음과 같은 아키텍처 규칙들을 도출할 수 있다.
- 지향하는 관심사에 따라 응집성을 높이고 관심사가 다른 영역과는 의존도를 낮춘다.
- 업무 규칙을 정의하는 비지니스 로직 영역을 다른 기술 기반 영역으로부터 분리하기 위해 노력한다.
- 세부 기술 중심, 저수준의 외부 영역과 핵심 업무 규칙이 정의된 고수준의 내부 영역으로 구분한다.
- 고수준 영역은 저수준 영역에 의존하지 않게 해야하며, 저수준 영역이 고수준 영역에 의존하게 한다.
- 저수준 영역은 언제든지 교체, 확장이 가능해야하고 이 같은 변화가 고수준 영역에 영향을 줘서는 안 된다.
- 자바처럼 인터페이스 및 추상 클래스를 지원하는 언어의 경우 저수준 영역의 구체 클래스가 고수준 영역의 추상 인터페이스에 의존하게 하는 의존성 역전의 원칙을 적용한다.
- 인터페이스는 고수준의 안정된 영역에 존재해야하며, 저수준의 어댑터가 이를 구현한다.

내부 영역
내부 영역에서는 업무 규칙을 정의한다. 도메인 모델 패턴을 사용하여 내부 로직을 구현한다.
내부 영역 구조
- 인터페이스 : 정의 했던 아키텍처 규칙에 맞게, 인터페이스는 고수준 영역에 존재하고 저수준의 외부 어댑터가 인터페이스를 구현하게 설계되어있다.
- 서비스 인터페이스
- 레포지토리 인터페이스
- 도메인 이벤트 인터페이스
- 프록시 인터페이스
- 서비스 : 도메인을 활용하여 시스템의 흐름 처리.
- 도메인 : 비지니스 개념을 표현.
내부 영역 구현 방식
Aggregate 사용.
Aggregate : 개념적으로 연관된 도메인들을 묶어 놓은 것.
애그리게이트를 사용하며, 다음과 같은 규칙들을 소개한다.
- 애그리게이트 루트만 참조한다.
- 애그리게이트 내 상세 클래스를 바로 참조하지 않고 루트를 통해 참조해야한다. 수정할 때도 마찬가지다.
- 애그리게이트 간의 참조는 객체를 직접 참조하는 대신 기본키를 사용한다. (JPA 기준 : 엔티티 필드값으로 연관관계 매핑을 걸어 참조하지 말고, PK를 갖게한다.)
- 기본키를 사용하면 느슨하게 연관되고 수정이 필요하지 않은 애그리게이트를 함께 수정하는 실수를 방지한다.
- 하나의 트랜잭션으로 하나의 애그리게이트만 생성 및 수정한다.
외부 영역
외부 영역은 내부 영역의 인터페이스를 구현하는 여러 어댑터들로 구성된다.
- API 어댑터
- 클라이언트와 주고 받는 REST API 관리.
- API Proxy 어댑터
- 타 마이크로서비스의 API 를 호출하는 어댑터. 호출하려는 서비스에 구현되어있는 방식에 맞게 통신방법을 선택한다. (ex. REST, SOAP, Socket.io etc…)
- DB 어댑터
- ORM (Object Relation Mapping) - ex. JPA, Spring Data JPA
- SQLM (SQL Mapping) - ex. Mybatis
- 두 가지 방법 중 선택하여 사용한다. (자바를 사용하는 경우 기준)
- 도메인 이벤트 발행 어댑터
- 도메인에서 이벤트가 발생했을 경우 메세지 브로커로 이벤트를 발행시키는 어댑터.
- 도메인 이벤트 핸들러 (이벤트 수신 어댑터)
- 메세지 브로커에서 해당 도메인에 관련된 이벤트가 발생되었을 경우 수신해 올 어댑터.
DDD를 적용한 전략적 설계
DDD의 전략적 설계 : https://silvers-dev-note.tistory.com/53 참고
유비쿼터스 언어
DDD 의 전략을 도입하여 마이크로서비스를 설계함에 있어서, "유비쿼터스 언어" 라는 개념이 등장한다.
유비쿼터스 언어 (도메인 언어) : 특정 도메인의 의도를 명확히 파악, 반영하고 도메인의 핵심 개념을 잘 전달할 수 있는 언어를 협업 구성원들이 약속하고 통용적으로 사용하는 언어.
이러한 유비쿼터스 언어를 사용하라고 말하고 있는데, 이 말은 즉, 각 개념들을 지칭하는 말들을 약속하여 모두 동일하게 사용하자는 뜻이다.
(ex. 서비스를 이용하는 유저 : "회원" 이라고 부르자.)
또한, 이렇게 도메인에서 비지니스 적으로 정의한 용어를 코드에서 동일하게 사용하도록 하자.
그렇게해서 헷갈림없이 누구나 동일한 용어를 사용할 수 있어야한다.
컨텍스트
도메인과 서브도메인을 설계하여 바운더리 컨텍스트를 구분하고, 컨텍스트 맵을 작성하자.
컨텍스트 맵 : https://silvers-dev-note.tistory.com/52
- 서브도메인
- 핵심 서브도메인 : 차별화를 만들 비지니스 영역. 우선순위가 높다. 소프트웨어 개발에서 전략적으로 가장 큰 투자가 필요한 영역.
- 지원 서브도메인 : 핵심 서브도메인을 지원하기 때문에, 비지니스에 있어 필수적이지만 핵심은 아닌 영역.
- 일반 서브도에인 : 비지니스적으로 특화된 영역을 아니나, 전체 비지니스 솔루션에는 필요한 영역.
서브도메인으로 구성한 컨텍스트 맵

세부 설계
마이크로서비스를 세부적으로 설계하는 방법을 순차적으로 기입해보겠다.
- 비지니스 이해 (비지니스에 대한 이해가 없다면 앞으로의 과정을 수행할 수 없다.
- 이벤트 스토밍을 통해 바운디드 컨텍스트 분류.
- 이벤트 스토밍 : https://silvers-dev-note.tistory.com/51
- 모델링
- 프론트엔드 모델링
- 아키텍처 정의
- 표준 레이아웃 정의
- UI 레이아웃 설계
- UI 디자인 및 UI 레이아웃 반영
- 이벤트 설계
- 백엔드 모델링
- 이벤트 스토밍을 통해 도출된 결과물을 가지고 패키지 구조 및 아키텍처 설계
- API 설계
- DDD의 전술적 설계를 이용한 도메인 모델링
- 프론트엔드 모델링
DDD가 결합된 마이크로서비스 아키텍처를 요약한다면 다음 그림과 같다고 볼 수 있을 것 같다.

참고 서적
- 도메인 주도 설계로 시작하는 마이크로서비스 개발