소프트웨어 시스템의 아키텍처란 시스템을 구축했던 사람들이 만들어낸 시스템의 형태이다.
이 아키텍처의 주된 목적은 시스템의 생명주기를 지원하는 것이다. 개발, 배포, 유지보수 등
모든 소프트웨어 시스템은 주요한 두 가지 구성요소로 분해가 가능하다. 바로 정책과 세부사항(디테일)이다.
정책은 모든 업무 규칙과 업무 절차를 구체화한다. 시스템의 진정한 가치가 살아있는 곳.
세부사항은 사람, 외부 시스템, 프로그래머가 정책과 소통할 때 필요한 요소지만, 정책이 가진 행위에는 조금도 영향을 미치지 않는다. 이러한 세부사항의 예시로는, 웹 시스템, 입출력 장치, DB, 서버, 프레임워크 등이 존재한다.
아키텍트의 목표는 시스템에서 정책을 가장 핵심적인 요소로 식별하고, 세부사항은 정책에 무관하게 만들 수 있는 형태의 시스템을 구축하는데 있다.
정책은 세부사항에 관한 어떠한 지식도 갖지 못하게 하며, 어떤 경우에도 세부사항에 의존하지 않게 된다
좋은 아키텍트는 결정되지 않은 사항의 수를 최대화한다
예시로, 과거의 장치종속성의 문제를 들었다. 요즘의 운영체제는 입출력 장치를 함수로 추상화했고, 이 함수는 천공카드와 같은 단위 레코드를 처리한다. 프로그램은 운영체제의 서비스를 호출하고, 해당 서비스가 추상화된 단위 레코드 장치를 처리한다. 그리고 오퍼레이터가 해당 추상 서비스를 카드판독기, 자기테이프나 또 다른 단위 레코드 장치 중 어디에 연결해야하는지 알려주었다.
이런 식으로 세부사항인 입출력 장치에 대한 결정을 연기시키는 부분이 좋은 아키텍트의 한 예시이다.
다른 예시로, 시스템의 고수준 정책이 디스크의 물리적 구조로부터 독립적으로 수정한 예시도 설명하심.
이번 장에서의 내용은 유스케이스 결합 분리, 분리할 단위, 중복 등에 관한 설명이다
유스케이스를 분리하여 (ex. addOrder, deleteOrder) 이 유스케이스를 분리하는 것은 수직적으로 분리하는 것이고, 수평적으로 분리도 하는데 이때는 UI 계층, 업무 로직 계층, 데이터베이스 계층으로 나눈다.
그리고 중복에 대한 설명이 있었는데, 보통 소프트웨어에서 중복은 나쁜 것이므로 통합하려고 한다. 하지만 이 중복이 진짜 통합해야 하는 것인지 구별을 잘 해야 한다. 우발적인 중복일 확률이 높다고 설명하심. 결국 이 분기가 나중에 프로젝트가 커지면 중복이였던 부분이 중복이 아니게 될 수도 있다는 점이다.
주로 중복이거나 통합 될 만한 코드를 최대한 줄이려고 했는데 좀 더 생각을 하면서 해야겠다,,,
그리고 분리를 어느 단위에서 하는 부분도 나왔는데, 소스 수준, 배포 수준, 서비스 수준이 존재한다. 프로젝트에 따라 어떤 수준이 제일 좋을지는 다 다른데, 현시점에 가장 인기 있는 분리 수준은 서비스 수준 분리 모드이다(MSA 마이크로 서비스 아키텍쳐) 하지만 단점도 여러가지가 있는데 제일 큰 단점은 아무래도 노력인듯 하다. 서비스 수준에서의 분리는 작업량이 많이 소요된다고 한다.
저자는 컴포넌트가 서비스화될 가능성이 있다면 컴포넌트 결합을 분리하되 서비스가 되기 직전에 멈추는 방식을 선호한다고 한다. 이 방식은 프로젝트 초기에는 소스 수준의 분리로 수행이되고, 배포 개발에서 문제가 생긴다면 배포 수준까지 분리 수준을 높이고, 운영적인 문제가 증가한다면 이제 서비스 수준까지 분리할 생각을 신중하게 하면 된다.
좋은 아키텍처는 모놀리틱 구조로 태어나서 단일 파일로 배포되더라도, 이후는 독립적으로 배포 가능한 단위까지 성장하고, 또 서비스 레벨도 독립적인 수준까지 성장하는 아키텍처라고 한다. 반대도 성립해야한다고 한다,,
이번 장은 컴포넌트 단위 또는 DB와 비즈니스 로직등에서 경계를 두어 다른 컴포넌트에 영향을 최소한으로 주고, 언제든지 다른 DB, GUI로 교체할 수 있게 만들 수 있는 플러그인 아키텍처에 관한 설명을 한다.
소프트웨어 개발 기술의 역사는 플러그인을 쉽게 생성하고, 확장 가능하며 유지보수가 쉬운 아키텍처를 확립할 수 있게 만드는 방법에 대한 이야기이다.
경계를 그어 플러그인 아키텍처 처럼 언제든지 GUI를 변경하고 DB를 변경할 수 있고, 이 세부사항의 결정을 미루어 개발할 때의 장애물을 최대한 줄여 속도의 장점을 갖는 등 여러 장점이 존재한다.
DB와 비즈니스 로직 사이에서도 경계를 그을 수 있는데, 이때의 방법도 의존성 역전 원칙을 사용하면 쉽게 경계를 그을 수 있다. DB와 비즈니스 로직은 뗄레야 뗄 수 없는 관계라고 많이들 생각하지만, 이 생각도 잘못되었다고 한다. DB는 비즈니스 로직이 간접적으로 사용할 수 있는 도구이다.
소프트웨어 아키텍처는 선을 긋는 기술이며 이러한 선을 저자는 경계라고 부른다
아키텍처 관점의 목표는 저수준 프로세스가 고수준 프로세스의 플러그인이 되도록 만드는 것이다
경계에 횡단에 대한 내용이 있는데, 이는 한쪽 기능에서 반대편 기능을 호출하여 데이터를 전달 한다는 의미이다.
고수준 클라이언트가 저수준 서비스를 호출하는 방식은 동적 다형성을 사용하여 제어흐름과는 반대 방향으로 의존성을 역전시킨 방식에 대한 내용이 있다.
서비스의 인터페이스를 두어, 컴파일 타임 의존성에서는 클라이언트가 서비스 인터페이스로 향하지만, 런타임 의존성에서는 서비스 구현체에서 서비스 인터페이스로 방향을 향하므로 두 타임에서 의존성이 반대가 된다.
결국 이 방식도 저수준 -> 고수준으로 향하기 때문에 적절한 방식이라고 볼 수 있다.
소프트웨어 시스템이란 정책을 기술한 것
이번장도 저수준 -> 고수준에 대한 얘기가 많았고, 정책에 대한 얘기로는, 같은 이유로 같은 시점에 변하는 정책은 묶어야 하며(CCP), 이러한 정책들을 동일 수준으로 분리하고 동일 컴포넌트에 속해야 한다. 그리고 재편성된 컴포넌트들을 적절히 비순환 방향 그래프로 구성하는 기술을 아키텍처 개발은 포함한다.
그래프에서의 노드들은 동일 수준의 정책을 포함하는 컴포넌트에 해당하며, 엣지는 컴포넌트 사이의 의존성이다. 그리고 이러한 의존성은 소스 코드, 컴파일 타임 의존성이다.
수준에 대한 정의로는 입력과 출력까지의 거리라고 정의하고 있다
고수준 정책은 저수준 정책보다 덜 빈번하게 변경되며, 변경되는 이유는 중요한 경우가 많고, 저수준 정책에서는 더 빈번하게 변경되며, 변경되는 이유는 덜 중요한 경우가 많다.
여기서의 논의는 저번 장에서도 계속 말하는 저수준 컴포넌트는 고수준 컴포넌트에 플러그인 되어야 한다는 점으로도 볼 수 있다.
업무 규칙 이란 사업적으로 수익을 얻거나 비용을 줄일 수 있는 규칙 또는 절차이다
컴퓨터상으로 구현했는지와 별개임. 은행을 예시로, 얼마를 빌려주면 N%의 이자를 부과하겠다 도 은행의 업무 규칙이다. 이를 여기서는 핵심 업무 규칙이라고 부른다.
그리고 이 핵심 업무 규칙에는 데이터가 반드시 필요한데, 이 데이터를 핵심 업무 데이터라고 부른다.
이 둘은 본질적으로 결합 되어 있기 때문에 객체로 만들기 좋다. 이 객체를 엔티티라고 한다고 하심
이 엔티티는, 다른 DB, 인터페이스, 서드파티 등으로 오염되어서는 절대 안된다.
그리고 이 엔티티를 어떻게 사용할지를 기술한게 유스케이스라고 한다
유스케이스에는 입력 데이터, 출력데이터, 그리고 출력을 만드는 처리 단계를 기술한다. 엔티티와는 다르게 좀 더 애플리케이션에 특화된 업무 규칙을 설명한다.
유스케이스는 엔티티 내부 핵심 규칙을 어떻게 언제 호출할지를 명시하는 규칙을 담는다
유스케이스는 데이터를 명시하는 점만 빼면, 어떤 사용자 인터페이스를 사용할지에 대해서는 기술하지 않는다. 따라서 웹을 사용할지, 앱을 사용할지 등은 전혀 모른다.
유스케이스 또한 객체이고, 엔티티를 의존하는 객체이다. 엔티티는 유스케이스가 뭔지도 모르지만, 유스케이스는 엔티티의 존재를 알고 있다.
제대로 된 유스케이스는 데이터를 사용자나 컴포넌트간 주고 받는 방식에 대해서는 몰라야 한다. HTML이나 SQL에 대해서 알게 되는 일을 원하지 않는다.
단순한 요청 데이터 구조를 입력으로 받고, 단순한 응답 데이터 구조를 반환한다. 이 데이터 구조는 HttpRequest, HttpResponse 같은 표준 프레임워크 인터페이스로 파생되지 x
업무 규칙은 소프트웨어 시스템이 존재하는 이유이다 이는 다른 저수준 관심사(DB, 인터페이스)에 오염되어서는 안된다.