Ch20. 업무 규칙
애플리케이션을 업무 규칙과 플러그인으로 구분하려면 업무 규칙이 실제로 무엇인지를 잘 이해해야 한다.
엄밀하게 말하면 업무 규칙은 사업적으로 수익을 얻거나 비용을 줄일 수 있는 규칙 또는 절차다.
대출에 N%의 이자를 부과한다는 사실은 은행이 돈을 버는 업무 규칙이다.
이러한 사실은 컴퓨터 프로그램으로 이자를 계산하든, 또는 직원이 주판을 튕겨 계산하든 아무상관 없다.
이러한 규칙을 핵심 업무 규칙이라고 한다.
왜냐하면 이들 규칙은 사업 자체에 핵심적이며, 규칙을 자동화하는 시스템이 없더라도 업무 규칙은 그대로 존재하기 때문이다.
핵심 업무 규칙은 보통 데이터를 요구한다. 예를 들어 대출에는 대출 잔액, 이자율, 지급 일정이 필요하다.
이러한 데이터를 우리는 핵심 업무 데이터라고 부르겠다.
핵심 규칙과 핵심 데이터는 본직적으로 결합되어 있기 때문에 객체로 만들 좋은 후보가 된다.
이러한 유형의 객체를 엔티티라고 하겠다.
[엔티티]
엔티티는 컴퓨터 시스템 내부의 객체로서, 핵심 업무 데이터를 기반으로 동작하는 일련의 조그만 핵심 업무 규칙을 구체화한다.
엔티티 객체는 핵심 업무 데이터를 직접 포함하거나, 핵심 업무 데이터에 매우 쉽게 접근할 수 있다.
엔티티의 인터페이스는 핵심 업무 데이터를 기반으로 동작하는 핵심 업무 규칙을 구현한 함수들로 구성된다.
예를 들어 Loan 엔티티가 UML 클래스로 어떻게 표현되는지 살펴보자.
Loan 엔티티는 세 가지의 핵심 업무 데이터와 세 가지 핵심 업무 규칙을 인터페이스로 제공한다.

우리는 이러한 종류의 클래스를 생성할 때, 업무에서 핵심적인 개념을 구현하는 소프트웨어는 한데 모으고, 구축 중인 자동화 시스템의 나머지 모든 고려사항과 분리시킨다.
이 클래스(Entity)는 DB, 사용자 인터페이스, 서드파티 프레임워크에 대한 고려사항들로 인해 오염되서는 절대 안 된다.
엔티티는 순전히 업무에 대한 것이며, 이외의 것은 없다.
엔티티가 꼭 클래스일 필요는 없다.
유일한 요구조건은 핵심 업무 데이터와 핵심 업무 규칙을 하나로 묶어서 별도의 소프트웨어 모듈로 만들어야 한다는 것이다.
[유스케이스]
모든 업무 규칙이 엔티티처럼 순수한 것은 아니다. 자동화된 시스템이 동작하는 방법을 정의하고, 제약함으로써 수익을 얻거나 비용을 줄이는 업무 규칙도 존재한다.
예를 들어 은행 직원이 신규 대출을 생성할 때 사용하는 애플리케이션을 상상해 보자.
은행에서 대출 담당자가 신청자의 신상정보를 수집하여 검증한 후, 신청자의 신용도가 500보다 낮다면 대출 견적을 제공하지 않기로 결정했다고 해 보자.
따라서 시스템에서 신상정보 화면을 모두 채우고 검증한 후, 신용도에 따라 대출이 진행된다.

바로 이것이 유스케이스다. 유스케이스는 자동화된 시스템이 사용되는 방법을 설명한다.
유스케이스는 사용자가 제공해야 하는 입력, 사용자에게 보여줄 출력, 그리고 해당 출력을 생성하기 위한 처리 단계를 기술한다.
엔티티 내의 핵심 업무 규칙과는 반대로, 유스케이스는 애플리케이션에 특화된 업무 규칙을 설명한다.
유스케이스는 엔티티 내부의 핵심 업무 규칙을 어떻게, 그리고 언제 호출할지를 명시하는 규칙을 담는다.
즉, 엔티티가 어떻게 춤을 출지를 유스케이스가 제어하는 것이다.
또 한가지 특징으로 유스케이스는 사용자 인터페이스를 기술하지 않는다.
이 점은 매우 중요하다. 유스케이스는 시스템이 사용자에게 어떻게 보이는지를 설명하지 않는다.
이보다는 애플리케이션에 특화된 규칙을 설명하며, 이를 통해 사용자와 엔티티 사이의 상호작용을 규정한다.
엔티티는 자신을 제어하는 유스케이스에 대해 아무것도 알지 못한다.
즉, 유스케이스는 엔티티에 의존한다.
[요청 및 응답 모델]
유스케이스는 입력 데이터를 받아서 출력 데이터를 생성한다.
제대로 된 유스케이스 객체라면 데이터를 사용자나 또 다른 컴포넌트와 주고 받는 방식에 대해서는 전혀 눈치챌 수 없어야 한다.
유스케이스는 단순히 요청 데이터 구조를 입력으로 받고, 응답 데이터 구조를 출력으로 반환한다.
이들 데이터 구조는 HttpRequest나 HttpResponse 같은 표준 혹은 웹에 대해서 전혀 알지 못해야 한다.
[결론]
업무 규칙은 소프트웨어 시스템이 존재하는 이유다.
업무 규칙은 핵심적인 기능이다. 업무 규칙은 수익을 내기 때문에 집안의 가보다.
업무 규칙은 저수준 관심사로 인해 오염되어서는 안 되며, 원래 그대로의 모습으로 남아 있어야 한다.
업무 규칙은 시스템의 심장부에 위치해야 하며, 가장 독립적이며 가장 많이 재사용할 수 있는 코드여야 한다.
Ch21. 소리치는 아키텍처
[아키텍처의 테마]
야콥슨(Object Oriented Software Engineering의 저자)은 소프트웨어 아키텍처는 시스템의 유스케이스를 지원하는 구조라고 지적했다.
소프트웨어 애플리케이션의 아키텍처도 애플리케이션의 유스케이스에 대해 소리쳐야 한다.
아키텍처는 프레임워크에 대한 것이 아니다.
프레임워크는 도구일 뿐, 아키텍처가 준수해야 할 대상은 아니다.
[아키텍처의 목적]
좋은 아키텍처는 유스케이스를 그 중심에 두기 때문에, 프레임워크나 도구, 환경에 전혀 구애받지 않고 유스케이스를 지원하는 구조를 아무런 문제 없이 기술할 수 있다.
좋은 소프트웨어 아키텍처는 프레임워크, 데이터베이스, 웹 서버, 그리고 여타 개발 환경 문제나 도구에 대해서는 결정을 미룰 수 있도록 만든다.
프레임워크는 열어 둬야 할 선택사항이다.
좋은 아키텍처는 유스케이스에 중점을 두며, 지엽적인 관심사에 대한 결합은 분리시킨다.
[하지만 웹은?]
웹은 아키텍처일까?
애플리케이션이 웹을 통해 전달된다는 사실은 세부사항이며, 시스템 구조를 지배해서는 절대 안된다.
실제 애플리케이션을 웹으로 전달할지 여부는 미루어야 할 결정사항 중 하나다.
[테스트하기 쉬운 아키텍처]
테스트를 돌리는 데 웹 서버가 반드시 필요한 상황이 되어서는 안 된다.
DB가 반드시 연결되어 있어야만 테스트를 돌릴 수 있어서도 안 된다.
엔티티 객체는 반드시 오래된 방식의 간단한 객체(plain old object)여야 하며, 다른 복잡한 것에 의존해서는 안 된다.
최종적으로, 프레임워크로 인한 어려움을 겪지 않고도 반드시 이 모두를 있는 그대로 테스트할 수 있어야 한다.
[결론]
아키텍처는 시스템을 이야기해야 하며, 시스템에 적용한 프레임워크에 대해 이야기해서는 안 된다.
새로 들어온 프로그래머가 소스 저장소를 봤을 때 첫 인상이 “오, 헬스 케어 시스템이군”이어야 한다.
Ch22. 클린 아키텍처
지난 수십 년간 우리는 시스템 아키텍처와 관련된 여러 가지 아이디어를 봐왔다. 다음의 내용도 여기에 포함된다.
- 육각형 아키텍처: 포트와 어댑터라고도 알려졌으며, 앨리스터 코오번이 개발했다.
- DCI(Data, Context and Interaction): 제임스 코플리언과 트리그베 린스쿠주가 만들었다.
- BCE(Boundary-Control-Entity): 이바 야콥슨이 자신의 저서인 Object Oriented Software Engineering에서 소개했다.
이들 아키텍처는 모두 세부적인 면에서는 다소 차이가 있더라도 그 내용은 상당히 비슷하다.
이들의 목표는 모두 같은데, 바로 관심사의 분리다.
이들 모두 소프트웨어를 계층으로 분리함으로써 관심사의 분리라는 목표를 달성할 수 있었다.
각 아키텍처는 최소한 업무 규칙을 위한 계층 하나와, 사용자와 시스템 인터페이스를 위한 또 다른 계층 하나는 반드시 포함한다.
또한 다음과 같은 특성을 지니도록 만들었다.
- 프레임워크 독립성: 아키텍처는 다양한 기능의 라이브러리를 제공하는 소프트웨어다. 즉, 프레임워크의 존재 여부에 의존하지 않는다.
- 테스트 용이성: 업무 규칙은 UI, DB, 웹 서버, 또는 여타 외부 요소가 없이도 테스트할 수 있다.
- UI 독립성: 시스템의 나머지 부분을 변경하지 않고도 UI를 쉽게 변경할 수 있다.
- DB 독립성: 업무 규칙은 DB에 결합되지 않는다.
- 모든 외부 에이전시에 대한 독립성: 실제로 업무 규칙은 외부 세계와의 인터페이스에 대해 전혀 알지 못한다.
그림 22.1의 다이어그램은 이들 아키텍처 전부를 실행 가능한 하나의 아이디어로 통합하려는 시도다.

[의존성 규칙]
그림 22.1에서 각각의 동심원은 소프트웨어에서 서로 다른 영역을 표현한다.
보통 안으로 들어갈수록 고수준 소프트웨어가 된다.
바깥쪽 원은 메커니즘이고, 안쪽 원은 정책이다.
이러한 아키텍처가 동작하도록 하는 가장 중요한 규칙은 의존성 규칙이다.
소스 코드 의존성은 반드시 안쪽으로, 고수준의 정책을 향하게 해야 한다.
내부의 원에 속한 요소는 외부의 원에 속한 어떠한 것도 알지 못한다.
엔티티
엔티티는 전사적인 핵심 업무 규칙을 캡슐화한다.
엔티티는 메서드를 가지는 객체이거나 일련의 데이터 구조와 함수의 집합일 수도 있다.
유스케이스
유스케이스 계층의 소프트웨어는 애플리케이션에 특화된 업무 규칙을 포함한다.
유스케이스는 엔티티로 들어오고 나가는 데이터 흐름을 조정하며, 엔티티가 자신의 핵심 업무 규칙을 사용해서 유스케이스의 목적을 달성하도록 이끈다.
인터페이스 어댑터
인터페이스 어댑터 계층은 일련의 어댑터들로 구성된다.
이 계층은 , 예를 들어 GUI의 MVC 아키텍처를 모두 포괄한다.
프레젠터, 뷰, 컨트롤러는 모두 인터페이스 어댑터 계층에 속한다.
이 계층은 데이터를 엔티티와 유스케이스에게 가장 편리한 형식에서 영속성용으로 사용 중인 임의의 프레임워크(즉, DB)가 이용하기에 가장 편리한 형식으로 변환한다.
또한 이 계층에는 데이터를 외부 서비스와 같은 외부적인 형식에서 유스케이스나 엔티티에서 사용되는 내부적인 형식으로 변환하는 또 다른 어댑터가 필요하다.
원은 네 개여야만 하나?
그림 22.1에 표시한 원들은 그저 개념을 설명하기 위한 하나의 예시일 뿐이다.
네 개보다 더 많은 원이 필요할 수도 있다.
하지만 어떠한 경우에도 의존성 규칙은 적용된다.
소스 코드 의존성은 항상 안쪽을 향한다.
안쪽으로 향할수록 추상화와 정책의 수준은 높아진다.
그리고 안쪽으로 이동할수록 소프트웨어는 점점 추상화되고, 더 높은 수준의 정책들을 캡슐화한다.
경계 횡단하기
그림 22.1의 우측 하단 다이어그램에 원의 경계를 횡단하는 방법을 보여주는 예시가 있다.
우선 제어흐름에 주목해보자.
컨트롤러 → 유스케이스 → 프레젠터
다음으로 소스 코드 의존성도 주목해서 보자. 각 의존성은 유스케이스를 향해 안쪽을 가리킨다.
이처럼 제어흐름과 의존성의 방향이 명백히 반대인 경우, 대체로 의존성 역전 원칙을 사용하여 해결한다.
경계를 횡단하는 데이터는 어떤 모습인가
경계를 가로지르는 데이터는 흔히 간단한 데이터 구조로 이루어져 있다.
기본적은 구조체나 간단한 데이터 전송 객체(DTO)등 원하는 대로 고를 수 있다.
중요한 점은 격리되어 있는 간단한 데이터 구조가 경계를 가로질러 전달된다는 사실이다.
한가지 유의해야할 점은 경계를 가로질러 데이터를 전달할 때, 데이터는 항상 내부의 원에서 사용하기에 가장 편리한 형태를 가져야만 한다.
[전형적인 시나리오]
그림 22.2의 다이어그램은 DB를 사용하는 웹 기반 자바시스템의 전형적인 시나리오를 보여준다.

그림 22.2 그림에서 주목해야할 점은 모든 의존성의 방향이 경계선을 안쪽으로 가로지르고 있다.
[결론]
이러한 간단한 규칙들을 준수하는 일은 어렵지 않으며, 향후 겪을 수많을 고통거리를 덜어줄 것이다.
소프트웨어를 계층으로 분리하고 의존성 규칙을 준수한다면, 본질적으로 테스트하기 쉬운 시스템을 만들게 될 것이며, 그에 따른 이점을 누릴 수 있다.
Ch23. 프레젠터와 험블 객체
22장에서 프레젠터의 개념을 소개했다.
프레젠터는 험블 객체 패턴을 따른 형태로, 아키텍처 경계를 식별하고 보호하는 데 도움이 된다.
[험블 객체 패턴]
험블 객체 패턴은 디자인 패턴으로, 테스트하기 어려운 행위와 테스트하기 쉬운 행위를 단위 테스트 작성자가 분리하기 쉽게 하는 방법으로 고안됐다.
행위들은 두 개의 모듈 또는 클래스로 나눈다.
이들 모듈 중 하나가 험블이다.
가장 기본적인 본질은 남기고, 테스트하기 어려운 행위를 모두 험블 객체로 옮긴다.
나머지 모듈에는 험블 객체에 속하지 않은, 테스트하기 쉬운 행위를 모두 옮긴다.
[프레젠터와 뷰]
뷰는 험블 객체이고 테스트하기 어렵다.
뷰는 데이터를 GUI로 이동시키지만, 데이터를 직접 처리하지는 않는다.
프레젠터는 테스트하기 쉬운 객체다.
프레젠터의 역할은 애플리케이션으로부터 데이터를 받아 화면에 표현할수 있는 포맷으로 만드는 것이다.
이를 통해 뷰는 데이터를 화면으로 전달하는 간단한 일만 처리하도록 만든다.
화면에 표시되고 애플리케이션에서 어느 정도 제어할 수 있는 요소라면 무조건 뷰 모델 내부에 문자열, 불(boolean), 또는 열거형(enum) 형태로 표현한다.
뷰는 뷰 모델의 데이터를 화면에 로드할 뿐이며, 이 외에 뷰가 맡은 역할은 전혀 없다.
따라서 뷰는 보잘것 없다(humble).
[테스트와 아키텍처]
테스트 용이성은 좋은 아키텍처가 지녀야 할 속성으로 오랫동안 알려져 왔다.
험블 객체 패턴이 좋은 예인데, 행위를 테스트하기 쉬운 부분과 테스트하기 어려운 부분으로 분리하면 아키텍처 경계가 정의되기 때문이다.
프레젠터와 뷰 사이의 경계가 이런 경계라고 볼 수 있다.
[데이터베이스와 게이트웨이]
유스케이스 인터랙터와 데이터베이스 사이에는 데이터베이스 게이트웨이가 위치한다.
여기서 유념해야 될 것은 유스케이스 계층은 SQL을 허용하지 않는다.
따라서 유스케이스 계층은 필요한 메서드를 제공하는 게이트웨이 인터페이스를 호출한다.
그리고 인터페이스의 구현체는 데이터베이스 계층에 위치한다.
이 구현체가 험블이다.
[데이터 매퍼]
하이버네이트 같은 ORM은 어느 계층에 속한다고 생각하는가?
ORM 시스템은 당연히 데이터베이스 계층에 속한다.
따라서 ORM은 게이트웨이 인터페이스와 데이터베이스 사이에서 일종의 또 다른 험블 객체 경계를 생성한다.
[서비스 리스너]
서비스는 어떨까? 애플리케이션이 다른 서비스와 반드시 통신해야 한다면, 또는 애플리케이션에서 일련의 서비스를 제공해야 한다면, 우리는 여기에서 서비스 경계를 생성하는 험블 객체 패턴을 발견할 수 있을까?
당연하다! 데이터를 수신하고, 데이터를 애플리케이션에서 사용할 수 있는 간단한 데이터 구조로 포맷을 변경한다.
[결론]
각 아키텍처 경계마다 경계 가까이 숨어 있는 험블 객체 패턴을 발견할 수 있을 것이다.
이러한 아키텍처 경계에서 험블 객체 패턴을 사용하면 전체 시스템의 테스트 용이성을 크게 높일 수 있다.
Ch24. 부분적 경계
아키텍처 경계를 완벽하게 만드는 데는 비용이 많이 든다.
많은 경우에, 뛰어난 아키텍트라면 이러한 경계를 만드는 비용이 너무 크다고 판단하면서도, 한편으로는 나중에 필요할 수도 있으므로 이러한 경계에 필요한 공간을 확보하기 원할 수 있다.
아키텍트의 경우 이 문제를 검토하면서 “그래, 하지만 나중에 필요할지도.” 라는 생각이 들 수 있다.
만약 그렇다면 부분적 경계(partial bounday)를 구현해볼 수 있다.
[마지막 단계를 건너뛰기]
부분적 경계를 생성하는 방법 하나는 독립적으로 컴파일하고 배포할 수 있는 컴포넌트를 만들기 위한 작업은 모두 수행한 후, 단일 컴포넌트에 그대로 모아만 두는 것이다.
쌍방향 인터페이스도 그 컴포넌트에 있고, 입력 혹은 출력 데이터 구조도 거기에 있으며, 모든 것이 완전히 준비되어 있다.
하지만 모두를 단일 컴포넌트로 컴파일해서 배포한다.
[일차원 경계]
완벽한 형태의 아키텍처 경계는 양방향으로 격리된 상태를 유지해야 하므로, 쌍방향 Boundary 인터페이스를 사용한다.
추후 완벽한 형태의 경계로 확장할 수 있는 공간을 확보하고자 할 때 활용할 수 있는 더 간단한 구조가 그림 24.1에 나와 있다.
이는 전통적인 전략 패턴을 사용한 사례다.

[퍼사드]
이보다 훨씬 더 단순한 경계는 파사드 패턴으로, 그림 24.2와 같다.

경계는 Facade 클래스로만 간단히 정의된다.
클라이언트는 이들 서비스 클래스에 직접 접근할 수 없다.
[결론]
아키텍처 경계를 부분적으로 구현하는 간단한 방법 세 가지를 살펴보았다.
물론 이 외에도 방법이 많다.
이러한 접근법 각각은 나름의 비용과 장점을 가진다.
각 접근법은 완벽한 형태의 경계를 담기 위한 공간으로써, 적절하게 사용할 수 있는 상황이 서로 다르다.
'Book Notes' 카테고리의 다른 글
| [개발서적] Clean Architecture 6부(ch30~34) 요약 (4) (0) | 2025.12.15 |
|---|---|
| [개발서적] Clean Architecture 5부(ch25~28) 요약 (3) (0) | 2025.12.10 |
| [개발서적] Clean Architecture 5부(ch15~19) 요약 (1) (0) | 2025.12.10 |
| [개발서적] Clean Architecture 4부(ch12~14) 요약 (0) | 2025.11.26 |
| [개발서적] Clean Architecture 3부(ch7~11) 요약 (1) | 2025.11.16 |