5장 : 아키텍처

15장 : 아키텍처란?

  • 소프트웨어 아키텍트 : 최고의 프로그래머이며, 앞으로도 계속 프로그래밍 작업을 맡을 뿐만 아니라 동시에 나머지 팀원들이 생산성을 극해화 할 수 있는 설계를 하도록 방향을 이끌어 준다.

  • 아키텍처의 주된 목적은 시스템의 생명주기를 지원하는 것이다. 좋은 아키텍처는 시스템을 쉽게 이해하고, 쉽게 개발하며, 쉽게 유지보수하고, 또 쉽게 배포하게 해준다. 아키텍처의 궁극적인 목표는 시스템의 수명과 관련된 비용은 최소화하고, 프로그래머의 생산성은 최대화하는 데 있다

  • 시스템 아키텍처는 개발팀이 시스템을 쉽게 개발할 수 있도록 뒷받침 해야한다.

배포

  • 한번에 쉽게 배포할 수 있도록 해야한다.

  • 개발 초기 단계에 해당 단계를 진행하기 쉽지 않을 수 있지만 고려해야한다.

운영

  • 시스템을 운영하는데 필요한 요구도 알려준다.

  • 유스케이스, 기능, 시스템의 필수 행위를 일급 엔티티로 격상 시키도, 이들 요소가 개발자에게 주요 목표로 인식 되도록 해야한다.

  • 이를 통해 시스템을 이해하기 위워지며 개발과 유지보수에 큰 도움이 된다.

유지보수

  • 비용이 가장 많은 단계이다.

  • 가장 큰 비용은 탐사 와 이로인한 위험 부담이 있다.

  • 탐사 : 새로운 기능 추가, 결함 수정시에 어디를 고쳐야할지 결정할때 드는 비용

  • 시스템을 컴포넌트로 분리하고 안정된 인터페이스를 두어 격리한다.

선택 사항 열어두기

  • 행위적 가치와 구조적 가치를 소프트웨어는 지닌다.

  • 소프트웨어를 부드럽게 만드는것은 구조적 가치이다.

  • 중요치 않은 세부사항에 대해서는 열어두어야한다.

  • 정책 : 시스템의 진정한 가치가 살아있는것

  • 세부사항 : 사람, 외부시스템 프로그래머가 정책과 소통할때 필요한 요소지만 , 정책이 가진 행위에는 영향을 미치지 않는것

    • 예시 ) DB, 웹 시스템, 프레임 워크 등..

  • 아키텍처는 초기에 정책을 가장 핵심적인 역할로 식별하고 세부사항에는 열어 두어야한다.

  • 웹이나 DB종류 Rest와 같이 세부사항을 연기하고 미뤄서 나중에 결정할 수 있다.

  • 좋은 아키텍트는 결정되지 않은 사항의 수를 최대화한다.

장치 독립성

  • 동일한 프로그램을 아무런 변경없이도 카드에서 읽고 쓰거나 테이프에서 읽고 쓸 수 있게 되었다.

  • 개방 폐쇄 원칙이 탄생한 순간으로 이전의 문제였던 장치 독립성 문제를 해결하였다.

광고 우편 , 물리적 주소할당

  • 세부사항을 분리한 예시

  • 주소할당체계를 변경하여 디스크 드라이브 구조에 대한 결정사항을 애플리케이션으로부터 분리할 수 있게 되었다.

결론

좋은 아키텍트는 세부사항에 대한 결정을 가능한 한 오랫동안 미룰 수 있는 방향으로 정책을 설계한다.

16장 : 독립성 (ME)

  • 좋은 아키텍처가 지원해야할 4가지

    1. 시스템의 유스케이스

    2. 시스템의 운영

    3. 시스템의 개발

      • 콘웨이의 법칙

        • 시스템을 설게하는 조직이라면 어디든지 그 조직의 의사소통 구조와 동일한 구조의 설계를 만들어 낼것이다.

      • 각 팀이 독립적으로 행동하기 편한 아키텍처를 반드시 확보하여 개발하는 동안 팀들이 서로 방해받지 않도록 해야한다.

    4. 시스템의 배포

      • 배포용이성을 결정하는데 중요한 역할을 한다.

      • 목표는 즉각적인 배포다.

      • 시스템을 컴포넌트 단위로 적절하게 분할하고 격리시켜야 한다.

  • 선택 사항 열어두기

    • 좋은 아키텍처는 선택사항을 열어 둠으로써, 향후 시스템에 변경이 필요할 때 어떤 방향으로든 쉽게 변경할 수 있도록 한다.

  • 계층 결합 분리

    • 아키텍트는 단일 책임 원칙과 공통 폐쇄 원칙을 적용하여, 그 의도의 맥락에 따라서 다른 이유로 변경되는 것들은 분리하고 동일한 이유로 변경되는 것들은 묶는다.

    • 시스템을 수평적인 게층으로 분리할 수 있는것을 알게되었다.

  • 유스케이스 결합 분리

    • UI의 일부 , 애플리케이션 특화 업무 규칙의 일부, 애플리케이션 독립적 업무 규칙의 일부, 그리고 데이터베이스 기능의 일부를 사용한다.

    • 시스템에서 서로 다른 이유로 변경되는 요소들의 결합을 분리하면 기존 요소에 지장을 주지 않고도 새로운 유스케이스를 계속해서 추가할 수 있게 된다.

    • 또한 유스케이스를 뒷받침 하는 UI와 데이터 베이스를 서로 묶어서 각 유스케이스와 UI와 데이터 베이스의 서로 다른 관점을 사용하게 되면 새로운 유스케이스를 추가하더라도 기존 유스케이스에 영향을 주는 일은 거의 없을 것이다.

  • 결합 분리 모드

    • 관점을 분리

    • 때때로 컴포넌트를 서비스 수준 까지도 분리해야 한다는 것이다.

  • 개발 독립성

    • 여러 팀이 분리되어도 유스케이스의 결합이 분리된다면 한 시스템의 아키텍처는 그 팀 구조를 뒷받침 해줄것이다.

  • 배포 독립성

    • 배포 측면에서도 고도의 유연성이 생긴다.

    • 실제로 잘 분리되었다면 시스템에서도 계층과 유스케이스를 교채할 수 있다.

    • jar, 서비스를 추가하는것과 같이 단순한 일이 된다.

  • 중복

    • 진짜 중복 ,거짓된 중복, 우발적 중복

  • 결합 분리 모드 ( 다시 )

    • 소스 수준 부리모드 : 소스코드 모듈사이의 의존성을 제거한다. (모노리틱 구조)

    • 배포 수준 분리 모드 : jar, dll 등으로 분리하는것

    • 서비스 수준 분리모드 : 네트워크 통신으로 소통하게 하는것 ( MSA, 마이크로 서비스 아키텍처 )

    • 어떤것을 겷정하는 것이 초기에는 어렵지만 이후에는 많은 것을 분리해야할 수 있다.

    • 초기에는 컴포넌트 소스코드 수준에서 분리된다.

    • 좋은 아키텍처는 결합 분리 모드를 선택사항으로 남겨두어서 배포 규모에 따라 가장 적합한 모드를 선택해 사용할 수 있게 한다.

17장 : 선 긋기

  • 실패 사례 : 여러개의 서비스 팜을 생성하게 되면서 개발비용을 엄청 가중시킨 사례가 있다.

  • 성공 사례 : 일단 선택사항에 대해서는 열어둔다. 필요한 기능을 우선적 개발하고 추가 요구사항에 대해서 변경했다.

    • 특히 데이터베이스를 사용하지 않음으로 관리비 등으로 부터 벗어날 수 있었다.

  • 어떻게 선을 그을까?

    • 화살표의 방향, 선의 방향에 따라 데이터 베이스는 비즈니스 룰의 영향을 받는것이다. ( 비즈니스 룰 -> 데이터 베이스 )

    • 데이터 베이스는 어떠한 것으로도 변경될 수 있다.

  • 입력과 출력

    • 중요하지 않다.

    • GUI 는 다른 종류의 인터페이스로 얼마든지 교체할 수 있다.

  • 플러그인 아키텍처

결론

  • 소프트웨어 아키텍처에서 경계선을 그리려면 먼저 시스템을 컴포넌트 단위로 분할해야 한다.

  • 일부 컴포넌트는 핵심 업무 규칙에 해당한다. 나머지 컴포넌트는 플러그인으로, 핵심 업무와는 직접적인 관련이 없지만 필수 기능을 포함한다.

  • 그런 다음 컴포넌트 사이의 화살표가 특정 방향, 즉 핵심 업무를 향하도록 이들 컴포넌트의 소스를 배치한다.

  • 이는 의존성 역전 원칙과 안정된 추상화 원칙을 응용한 것임을 눈치챌 수 있어야 한다. 의존성 화살표는 저수준 세부사항에서 고수준의 추상화를 향하도록 배치된다.

18장 : 경계 해부학

경계 횡단 하기

  • 소스코드 의존성 관리

  • 두려운 단일체

    • 저수준 -> 고수준으로 향하는 함수 호출

    • 고수준 -> 저수준 ( 동적 다형성을 사용 )

  • 배포형 컴포넌트

    • 아키텍처의 경계가 물리적으로 드러나는 경우 : 동적 링크 라이브러리

  • 스레드

    • 단일체 ,배포험 컴포넌트 모두 사용가능

  • 로컬 프로세스

    • 고수준 프로세스의 소스 코드가 저수분 프로세스의 이름, 물리주소, 레지스트리 조회 키를 절대로 포함해서는 안 된다.

    • 저수준 프로세스가 고수준 프로세스의 플러그인이 되도록 만드는것이 아키텍처 관점의 목표라는 사실을 기억하자.

  • 서비스

    • 물리적인 형태를 띠는 가장 강력한 경계

    • 함수 호출에 비해 느리다.

  • 결론

    • 대체로 한 시스템 안에서도 통신이 빈번한 로컬 경계와 지연을 중요하게 고려해야 하는 경계가 혼합되어 있음을 의미한다.

19장 : 정책과 수준 (ME)

  • 소프트웨어 시스템 : 정책을 기술한 것

    • 입력을 출력으로 변환하는 정책을 상세하게 기술한 설명서다.

    • 좋은 아키텍처라면 각 컴포넌트를 연결할 때 의존성의 방향이 컴포넌트의 수준을 기반으로 연결되도록 만들어야 한다. 즉, 저수준 컴포넌트가 고수준 컴포넌트에 의존하도록 설계되어야 한다.

  • 수준

    • 입력과 출력까지의 거리

    • 프로그램을 제대로 설계했다면 소스 코드 의존성은 곧 점선처럼 표시되어야 한다.

    • 데이터 흐름과 소스코드 의존성이 항상 같은 방향을 가리키지는 않는 다는 사실이다.

    • 정책을 컴포넌트로 묶는 기준은 정책이 변경되는 사실에 달려 있다.

    • 모든 소스 코드 의존성의 방향이 고수준 정책을 향할 수 있도록 정책을 분리했다면 변경의 영향도를 줄일 수 있다.

20장 : 업무규칙

  • 엔티티

    • 컴퓨터 시스템 내부의 객체로서 핵심 업무 데이터를 기반으로 동작하는 일련의 조그만 핵심 업무 규칙을 구체화한다.

    • 엔티티 객체는 핵심 업무 데이터를 직접 포함하거나 핵심 업무 데이터에 매우 쉽게 접근할 수 있다.

  • 유스케이스

    • 자동화된 시스템이 사용되는 방법을 설명한다.

    • 엔티티 내의 핵심 업무 규칙과는 반대로 유스케이스는 애플리케이션에 특화된 업무 규칙을 설명한다.

    • 엔티티는 자신을 제어하는 유스케이스에 대해 알지 못한다. (DIP)

    • 저수준인 유스케이스는 고수준인 엔티티에 대해 알고있다.

    • 유스케이스는 단일 애플리케이션에 특화되어 있으며 따라서 해당 입력과 출력보다 가깝게 위히하기 떄문에 저수준이다.

    • 하지만 엔티티는 유스케이스에 의존하지 않는다.

  • 결론

    • 업무 규칙은 사용자 인터페이스나 데이터베이스와 같은 저수준의 관심사로 인해 오염되어서는 안 되며, 원래 그대로의 모습으로 남아 있어야 한다.

    • 이상적으로는 업무 규칙을 표현하는 코드는 반드시 시스템의 심장부에 위치해야 하며, 덜 중요한 코드는 이 심장부에 플러그인되어야 한다.

    • 업무 규칙은 시스템에서 가장 독립적이며 가장 많이 재사용할 수 있는 코드여야 한다.

Last updated