SubSystem

|

서브 시스템

시스템의 모듈 뷰를 문서화할 때 일정하게 조합된 모듈을 서브 시스템이라고 식별할 수 있다.

서브 시스템은 보통 다음과 같은 경우 사용할 수 있다.

  • 전체 시스템에서 기능적인 밀집성이 있는 서브 집합
  • 독립적으로 실행 가능
  • 점증적으로 개발되고 배포될 수 있음


서브 시스템의 예시

예를 들어, 화성 탐사 로봇의 소프트웨어는 다음과 같은 서브 시스템으로 분할 할 수 있다.

  • 커뮤니케이션
  • 모션
  • 전력 관리
  • 주행
  • 상태 모니터링


라이브러리 != 서브 시스템

로봇 시스템내에서 수학 유틸리티 라이브러리가 있다고 가정하자. 이 경우 라이브러리는 시스템의 부분이며, 모듈의 조합이고 밀집성있는 기능을 갖고 있다. 하지만 시스템의 목적의 일부가 되는 작업을 독립적으로 수행할 수 없기 때문에 라이브러리를 서브 시스템이라고 하지는 않는다.


서브 시스템의 활용

서브 시스템은 독립적인 특성을 갖고 있다. 이 특성 덕분에 서브 시스템을 다음과 같은 경우에 활용할 수 있다.

  • 서브 시스템의 성능 검토를 분석가에게 요청 가능
  • 서브 시스템을 패키지로 만들어 다른 팀에게 구현하도록 넘겨 줄 수 있음
  • 테스트도 독립적으로 할 수 있음


UML

서브 시스템은 UML에서 <<subsytem>>과 같은 스테레오 타입으로 표현할 수 있다. 서브 시스템은 모듈(구현 단위)의 그룹 또는 런타임 존재를 갖는 컴포넌트의 그룹을 표현할 수 있다.

Module Style

|

모듈 스타일

모듈 스타일은 크게 다음 6가지가 존재한다.

  • 분할 스타일: 모듈과 서브 모듈의 구조(포함 관계)를 보여준다.
  • 사용 스타일: 모듈 사이의 기능적 의존성 관계를 나타낸다.
  • 일반화 스타일: 모듈 사이의 특별한 관계를 나타낸다.
  • 레이어 스타일: 레이어 형태로 보여준다.
  • 관점 스타일: 관점이라는 특별한 모듈을 서술한다.
  • 데이터 모델 스타일: 데이터 엔티티 관계를 보여준다.


분할 스타일

모듈과 서브 모듈로서 코드의 구조 및 시스템의 책임의 분할을 보여준다. 거의 모든 아키텍트들이 분할 스타일로 시작한다. 분할 정복(Divide and conquer) 기법을 많이 사용한다.

분할 스타일은 시스템을 구현 단위로 분할하는데 사용된다. 분할 뷰는 모듈과 서브 모듈로 코드의 구성을 기술하며, 시스템의 책임이 어떻게 분할되는지를 보여준다.

분할 스타일에서는 일부분(is part of) 관계를 이용한다. 분할 그래프에서는 반복(loop)은 허용되지 않는다. 모듈은 하나의 부모만 가질 수 있다.

분할 스타일은 모듈 사이의 모든 의존성을 보여주지는 않는다.

분할 스타일의 예시는 다음과 같다.

image


사용 스타일

사용 스타일(Uses style)은 의존(depends on) 관계가 사용하다(use) 관계로 특수화된 결과다. 분할 스타일이 모듈과 서브 모듈로서 구현 단위의 구성을 보여주는 것이라면, 사용 스타일은 모듈이 어떤 다른 모듈을 사용하는지를 보여준다.

사용 스타일의 예시는 다음과 같다.

image

사용 스타일은 인터페이스를 명확하게 보여줄 수도 있다.

사용하다 관계는 호출(call) 또는 불러내기(invoke) 관계와 비슷해보이지만 다르다.


일반화 스타일

일반화 스타일(Generalization style)은 일종(is a) 관계를 사용한다. 부모 모듈과 자식 모듈로 표현하며 공통성(Commonality)과 가변성(Variation)을 보여준다.

일반화는 구현(Implementation) 또는 상속(Inheritance)을 표현할 수 있다.

image

위의 그림처럼 인터페이스의 경우는 두 가지 표기법이 모두 동일하다. 하지만, 좌측의 표기법이 하나의 인터페이스를 여러 모듈들이 구현하는 경우 더 편리하게 표현할 수 있다.


레이어 스타일

레이어 스타일(Layered style)은 레이어 단위로 소프트웨어를 분할 하는 스타일이다. 각 레이어는 밀집성을 갖는 서비스 집합을 표현하며, 레이어간에는 허용(allowed to use) 관계의 제약이 있다. 레이어들의 관계는 엄격하며 단방향으로 이루어진다.

아키텍처에서 가장 일반적으로 사용되는 스타일이다.

하위 레이어에서 상위 레이어를 사용하는 경우는 레이어 스타일이 아니다.

상위 레이어에서 하위 레이어를 건너뛰고 최하위 레이어를 사용하는 경우가 있다. 이때 상위 레이어를 레이어 브릿징(Layer bridging)이라고 한다. 하지만, 이런 사용이 많은 경우 이식성과 변경용이성 관점에서 시스템은 잘못 구조화되었다고 볼 수 있다.

레이어는 소스 코드 검토로 도출되지 않는다. 소스 코드에서는 명확한 경계가 드러나지 않는다. 소스 코드는 사용(use) 관계까지는 드러날 수 있지만, 레이어 스타일에서의 관계는 허용(allowed to use) 관계이기 때문이다.

Module View

|

모듈 뷰

시스템의 기본적인 구현 단위 또는 모듈과 함께 이들의 관계를 열거, 서술하는 뷰.

보통 모듈 구조(Module structure)는 시스템의 어떤 부분의 변경이 다른 부분에 얼마나 큰 영향을 미치는지를 결정한다. 변경용이성(Modifiability), 이식성(Portability), 재사용성(Resuability)과 관련된 시스템의 기능을 결정한다.


모듈 뷰의 요소, 관계, 속성

요소

  • 모듈: 모듈은 밀집성을 갖는 책임의 집합을 제공하는 소프트웨어의 구현 단위

관계

  • 일부분(is part of)
  • 의존(depends on)
  • 일종(is a)

속성

모듈의 속성은 구현과 분석에 이용되기 떄문에 모듈 뷰 문서에 기록되어야 한다.

  • 이름(Name)
  • 책임(Responsibility): 모듈의 이름이 책임을 알려줄 수는 있지만, 책임 속성을 통해 훨씬 더 명확하게 보여줄 수 있음
  • 인터페이스 가시성(Visibility of interface): 부모 모듈이 서브 모듈을 가지는 경우, 서브 모듈의 인터페이스는 외부에 노출되지 않는다. 하지만, 선택적으로 서브 모듈의 일부 인터페이스를 외부에 노출시키도록 표현할 수도 있다. 레이어와 서브 시스템이 주로 이런 방식을 사용한다.
  • 구현 정보(Implementation information): 모듈은 구현단위다. 엄격히 말하면 아키텍처적인 정보는 아니지만, 아키텍처 문서에 기록하는 것이 유용하다. 구현 정보에는 소스 코드 단위 매핑, 테스트 정보, 관리 정보, 구현 제약사항 등이 포함될 수 있다.


모듈 뷰 사용

모듈 뷰는 구현, 분석, 의사 소통 등의 용도로 많이 활용된다.

하지만, 모듈 뷰는 소프트웨어의 정적인 부분만을 보여준다. 따라서 모듈 뷰만 이용해서 시스템의 런타임(Runtime) 행위를 알아내는 것은 어렵다. 따라서 모듈 뷰는 일반적으로 성능, 신뢰성 등 런타임 품질 분석에는 사용되지 않는다.


모듈 뷰 표기법

모듈 뷰는 UML 또는 비형식적 표기법으로 둘 다 표현이 가능하다. UML을 이용할 경우 다음과 같이 표현한다.

image


모듈 뷰에서 관계는 다음과 같이 표현한다.

image


다른 뷰와의 관계

모듈 뷰는 일반적으로 C&C 뷰(컴포넌트 커넥터 뷰)에 매핑된다. 모듈은 주로 런타임시 실행되는 컴포넌트와 매핑이 되며, 일대일 또는 일대다 등의 관계로 매핑이 된다.

다만 모듈 뷰는 소프트웨어의 정적인 분할을 표현하는 것이기 때문에, 객체의 여러 인스턴스(ex. 데이터 리파지토리 또는 네트워크 등)는 모듈 뷰에 나타나지 말아야 한다.

System Context Diagram

|

Context Diagram

System Context Diagram의 목적은 시스템의 범위를 표현하는 것이다. 레벨이 존재하긴 하지만 대부분의 Context Diagram은 최상위 수준(TLCD, Top level context diagram)으로 표현한다.

Context는 시스템이 상호작용하는 환경을 의미하며 다음과 같은 것들이 될 수 있다.

  • 사람
  • 다른 시스템
  • 센서, 제어 장치 등의 H/W

Context Diagram은 개발해야 하는 범위를 알 수 있고, 시스템의 범위를 벗어나있는 프레임워크, 라이브러리, 외부 서비스, 다른 시스템, 다른 접점의 S/W 등을 명확하게 보여준다.


Context Diagram 내용

순수한 Context Diagram은 시스템에 대한 아키텍처 세부사항을 보여주지 않는다. (하지만 같은 Context내의 시스템의 일부 내부 구조를 보여주는 경우가 종종 있다.) 또한 인터랙션 정보나 데이터 흐름(데이터가 전송되고, 자극이 발생하고, 메시지가 전송되는 등)을 보여주지도 않는다.


Domain Model

|

DDD START! 도메인 주도 설계 구현과 핵심 개념 익히기

이 포스팅은 아래 책을 보고 공부한 내용을 요약한 글입니다.

image


도메인

도메인(Domain)은 소프트웨어로 해결하고자 하는 문제 영역입니다. 하나의 도메인은 여러 개의 하위 도메인으로 나눌 수 있습니다.

예를 들면, 온라인 서점 도메인은 아래 그림과 같이 여러 하위 도메인으로 나눠집니다.

image

특정 도메인용 소프트웨어라고 해서 모든 기능을 구현하는 것은 아닙니다. 아래 그림과 같이 외부 시스템과 연동해서 사용하기도 합니다.

image


도메인 모델

도메인 모델은 특정 도메인을 개념적으로 표현한 것입니다. 아래는 주문 모델을 객체 모델로 표현한 그림입니다.

image

도메인 모델이 도메인의 모든 내용을 담고 있지는 않지만, 위 도메인 모델을 보면 주문(Order)은 주문 번호와 총 금액을 갖고 있고, 배송 정보를 변경할 수 있음을 알 수 있습니다. 또한 취소(Cancel) 할 수 있는 것도 알 수 있습니다.

이렇게 도메인 모델을 이용해서 여러 관계자들이 도메인을 이해하고 지식을 공유하는데 도움을 줄 수 있습니다.

도메인 모델은 객체 외에도 아래 그림처럼 상태 다이어그램을 이용해서 표현할 수도 있습니다.

image

도메인 모델은 꼭 UML 표기법만 사용할 필요는 없습니다. 관계가 중요하다면 그래프로, 계산 규칙이 중요하다면 수학 공식으로 도메인 모델을 만들 수도 있습니다. 표현 방식이 중요하지는 않습니다.

도메인 모델은 개념 모델입니다. 개념 모델을 이용해서 바로 코드를 작성할 수 있는 것은 아니기 때문에 구현 모델은 따로 필요합니다. 개념 모델과 구현 모델은 서로 다르지만 최대한 서로 따르게 할 수는 있습니다.

도메인에 따라 용어가 바뀔 수 있기 때문에 여러 하위 도메인을 하나의 다이어그램에 모델링하는 것은 좋지 않습니다. 예를 들어, ‘상품’이라는 용어는 카탈로그에서의 상품과 배송에서의 상품이 서로 다릅니다. 즉, 이 경우 카탈로그 도메인 모델과 배송 도메인 모델을 따로 만들어야 한다는 뜻입니다.


개념 모델과 구현 모델

개념 모델은 순수하게 문제를 분석한 결과물입니다. 개념 모델은 데이터베이스, 트랜잭션 처리, 성능 등을 고려하지 않기 떄문에 실제 코드에 개념 모델을 그대로 사용할 수는 없습니다.

개념 모델을 처음부터 완벽한 모델로 만드는 것은 아주 어렵습니다. 소프트웨어를 개발하면서 개발자와 관계자들이 해당 도메인을 더 잘 이해할 수 있습니다. 프로젝트 초기에 완벽하 도메인 모델을 만들더라도 결국 모델을 수정하거나 보완하는 경우가 발생하게 됩니다.

따라서, 처음부터 완벽한 개념 모델을 만들기보다 전반적 개념을 알 수 있는 수준으로 개념 모델을 작성하는 것이 좋습니다.


도메인 모델 도출 방법

도메인을 모델링할 때 기본은 모델을 구성하는 핵심 구성요소, 규칙, 기능을 찾는 것입니다. 이 과정은 요구사항에서 출발합니다.

주문 도메인과 관련된 요구사항은 다음과 같습니다.

  • 최소 한 종류 이상의 상품을 주문해야 한다.
  • 한 상품을 한 개 이상 주문할 수 있다.
  • 총 주문 금액은 각 상품의 구매 가격 합을 모두 더한 금액이다.
  • 각 상품의 구매 가격 합은 상품 가격에 구매 개수를 곱한 값이다.
  • 주문할 떄 배송지 정보를 반드시 지정해야 한다.
  • 배송지 정보는 받는 사람 이름, 전화번호, 주소로 구성된다.
  • 출고를 하면 배송지 정보를 변경할 수 없다.
  • 출고 전에 주문을 취소할 수 있다.
  • 고객이 결제를 완료하기 전에는 상품을 준비하지 않는다.

이 요구사항에서 알 수 있는 것은 주문(Order)은 아래 기능을 제공한다는 것입니다.

  • 출고 상태로 변경
  • 배송지 정보 변경
  • 주문 취소
  • 결제 완료로 변경

코드로 표현하면 다음과 같습니다.

public class Order {
    public void changeShipped() {...}
    public void changeShippingInfo(ShippingInfo newShipping) {...}
    public void cancel() {...}
    public void completePayment() {...}
}

그 외 위 요구사항 중 아래 요구 사항을 반영하면

  • 한 상품을 한 개 이상 주문할 수 있다.
  • 총 주문 금액은 각 상품의 구매 가격 합을 모두 더한 금액이다.

OrderLine 객체를 구성할 수 있고, Order와의 관계를 표현할 수 있습니다.

또한, 아래 요구 사항을 보면

  • 출고를 하면 배송지 정보를 변경할 수 없다.
  • 출고 전에 주문을 취소할 수 있다.
  • 고객이 결제를 완료하기 전에는 상품을 준비하지 않는다.

주문의 상태(OrderState)가 필요함을 알 수가 있습니다.

public enum OrderState {
    PAYMENT_WATING,
    PREPARING,
    SHIPPED,
    DELIVERING,
    DELIVERY_COMPLETED,
    CANCELED,
}

이와 같은 방식으로 요구사항으로부터 도메인 모델을 점진적으로 만들어 나갑니다.


Entity와 Value

도출한 모델은 크게 EntityValue로 구분할 수 있습니다.

image

Entity

Entity의 가장 큰 특징은 식별자를 갖는다는 것입니다. 식별자는 객체마다의 고유값입니다. 예를 들면 주문 도메인에서 Order는 주문 번호를 가지며, 주문 번호는 Order의 식별자가 됩니다.

배송지가 변경되어도 주문 번호가 바뀌지 않는 것처럼 식별자는 Entity의 생성, 변경, 삭제까지 계속 유지됩니다.


Value

아래 코드에서 receiverNamereceiverPhoneNumber는 서로 다른 데이터를 갖지만, 두 필드는 개념적으로 받는 사람을 의미합니다. 즉, 두 필드가 하나의 개념을 표현하고 있습니다.

public class ShippingInfo {
    private String receiverName;
    private String receiverPhoneNumber;
    // ...
}

Value는 개념적으로 완전한 하나를 표현할 때 사용합니다. 위의 코드에서 받는 사람을 위한 Value 타입인 Receiver를 다음과 같이 작성할 수 있습니다.

public class Receiver {
    private String name;
    private String phoneNumber;
    // ...
}

Value 타입이 꼭 두 개 이상의 데이터를 가질 필요는 없습니다. 의미를 명확하게 표현하기 위해 사용하는 경우도 있습니다. 예를 들면 다음과 같습니다.

public class Money {
    private int value;
    // ...
}