클린아키텍처 4주차

JunMyung Lee·2021년 12월 23일
0

개발지식

목록 보기
10/14

스터디 범위 15장 ~ 19장

참여자 총 7명

  • @LIAM
  • @BRANDON
  • @CHRIS
  • @LEO
  • @PARKER
  • @ODIN
  • @BUZZ

스터디의 방향성이 @CHRIS의 전체적인 설명을 듣고 이후 사람들은 추가적인 내용이나 질의를 하는식으로 하였다. 그러다보니 마지막 순서인 내가 딱히 이곳에다가 책의 전체적인 내용을 작성하는 부분이 줄어들었다.
나는 책을 보면서 궁금했던 사항이나 현재 프로젝트와 연관되어서 작성만 하도록 ..

@LEO

15장 아키텍처란

  • 소프트웨어 시스템이 쉽게 개발, 배포, 운영, 유지보수되도록 만들기 위해서는 가능한 한 많은 선택지를 가능한 한 오래 남겨두는 전략을 따라야한다.
  • 주의를 기울여 신중하게 아키텍처를 만들면 유지보수 비용을 크게 줄일수 있다.
    • 시스템을 컴포넌트로 분리하고 안정된 인터페이스를 두어 서로 격리한다. 이를 통해 미래에 추가될 기능에 대한 길을 밝혀 둘 수 있을 뿐만 아니라 의도치 않은 장애가 발생할 위험을 크게 줄일 수 있다.
  • 아키텍트의 목표는 시스템에서 정책을 가장 핵심적인 요소로 식별하고 동시에 세부사항은 정책에 무관하게 만들수 있는 형태의 시스템을 구축하는것이다.
    • 세부사항을 결정하는 일은 미루거나 연기할 수 있게 된다.
  • 뛰어난 아키텍트라면 이러한 결정이 아직 내려지지 않은 것처럼 행동하며, 여전히 결정을 가능한 한 오랫동안 연기하거나 변경할 수 있는 형태로 시스템을 만든다.
    • 좋은 아키텍트는 결정되지 않은 사항의 수를 최대화한다.
  • 좋은 아키텍트는 세부사항을 정책으로부터 신중하게 가려내고 정책이 세부사항과 결합되지 않도록 엄격하게 분리한다.

16장 독립성

  • 각 컴포넌트를 적절히 격리하여 유지하고 컴포넌트 간 통신 방식을 특정 형태로 제한하지 않는다면, 시간이 지나 운영에 필요한 요구사항이 바뀌더라도 스레드, 프로세스, 서비스로 구성된 기술 스펙트럼 사이를 전환하는 일이 훨씬 쉬어질것이다.

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

콘웨이의 법칙(Conway's law)

  • 서로 다른 속도와 다른 이유로 변경된다면 이 두 코드는 진짜 중복이 아니다.
    • 두 화면은 서로 다른 방향으로 분기하며, 결국에는 매우 다른 모습을 가질 가능성이 높다. 이러한 이유로 해당 코드를 통합하지 않도록 유의해야한다. 그렇지 않으면 나중에 코드를 다시 분리하느라 큰 수고를 감수해야한다.

좋은 아키텍처는 시스템이 모노리틱 구조로 태어나서 단일 파일로 배포되더라도 이후에는 독립적으로 베포 가능한 단위들의 집합으로 성장하고 또 독립적인 서비스나 마이크로서비스 수준까지 성장할 수 있도록 만들어져야한다. -> 시스템의 결합 분리 모드는 시간이 지나면서 바뀌기 쉬우며, 뛰어난 아키텍트라면 이러한 변경을 예측하여 큰 무리없이 반영할 수 있도록 만들어야한다는 점이다.

17장 경계 : 선 긋기

  • 아키텍트의 목표는 필요한 시스템을 만들고 유지하는 데 드는 인적 자원을 최소화하는 것
    • 인적자원의 효율을 떨어뜨리는 요인은 -> 결합 -> 경계선을 긋는 행위는 결정을 늦추고 연기하는데 도움이됨
    • 의존성 역전 원칙과 안정된 추상화 원칙을 응용
    • 의존성 화살표는 저수준 세부사항에서 고수준의 추상화를 향하도록 배치

18장 경계 해부학

  • 경계는 변경이 전파되는 것을 막는 방화벽을 구축하고 관리하는 수단으로써 존재

@PARKER

15장 아키텍처란?

  • 소프트웨어 아키텍처는 코드(프로그래밍)와 멀어져서는 안된다.
  • "가능한 한 많은 선택지를, 가능한 한 오래 남겨두는 전략" (선택을 최대한 미뤄라, 선택을 미룰 수 있는 아키텍처를 만들어라.)
    • 여기서 선택지 = 중요치 않은 세부사항(detail)

      • 소프트웨어 시스템 구성요소 = 정책 + 세부사항
        • 정책: 업무 규칙과 절차를 구체화한 것 (도메인)
        • 세부사항: 정책이 가진 행위에는 전혀 영향을 주지 않는 것 (인프라)
          • Ex. 입출력 장치, 데이터베이스, 웹 시스템, 서버, 프레임워크, 통신 프로토콜 등
    • 개발 초기에는 고수준 정책에 몰두해라! → 시간이 지남에 따라 정보가 쌓인다. → 쌓인 정보를 바탕으로 최적의 세부사항을 선택할 수 있다.

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

  • 시스템 아키텍처는 시스템의 동작 여부와는 거의 관련이 없다.
    • 형편없는 아키텍처도 잘 동작한다.
  • 아키텍처의 주된 목적은 '시스템의 생명주기를 지원'하는 것이다.
    • 쉽게 시스템을 이해

    • 쉽게 개발

    • 쉽게 유지보수

    • 쉽게 배포

      → 시스템의 수명과 관련된 비용은 최소화/프로그래머의 생산성은 최대화

  • 개발
    • 팀의 규모에 따라 아키텍처가 달라진다.
    • 팀 규모가 작다면, 컴포넌트를 나누거나 잘 정의된 인터페이스가 불 필요할 수 있다.
  • 배포
    • 배포 비용이 높을수록 시스템의 유용성은 떨어진다.
    • "배포 전략은 개발 초기에 결정하자."
  • 운영
    • 비용 → 운영 < 개발/배포/유지보수
    • 운영에 문제가 발생하면, 대부분 하드웨어를 늘린다. (하드웨어 비용 < 인적 자원)
  • 유지보수
    • 소프트웨어 시스템에서 가장 비용이 큰 작업
    • 탐사(spelunking): 유지보수를 적용할 최적의 코드와 그 전략을 찾아가는 과정

16장 독립성

  • 유스케이스( = 시스템의 행위)
    • 아키텍처는 행위를 명확히 하고 외부로 드러내며, 이를 통해 시스템이 지닌 의도를 알아볼 수 있도록 해야한다.

    • 행위는 일급 요소(일급 시민 또는 일급 객체로 이해함.)이며, 개발자가 한 눈에 알아볼 수 있어야 한다. (일급 요소와 일급 객체는 다름)

      💡 일급 객체 (또는 일급 시민, 일급 요소(?) first-class object/citizen/type/entity/value/element)
    1. 모든 일급 객체는 함수의 실질적인 매개변수가 될 수 있다.

    2. 모든 일급 객체는 함수의 반환값이 될 수 있다.

    3. 모든 일급 객체는 할당의 대상이 될 수 있다.

    4. 모든 일급 객체는 비교 연산을 적용할 수 있다.

  • 운영
    • 아키텍처는 운영 시 필요한 처리량과 응답시간에 따라 선택사항을 열어두어야 한다.
    • 시스템에 따라 처리하는 방법을 달리하고, 변경할 수 있어야 한다.
      • 모노리틱
      • 마이크로 서비스
      • 단일 프로세스에서 여러 다중 스레드
      • 다중 프로세스 (또는 서버)
      • ...
  • 개발
    • 콘웨이의 법칙 작용

      💡 "시스템을 설계하는 조직이라면 어디든지 그 조직의 의사소통 구조와 동일한 구조의 설계를 만들어 낼 것이다."
    • 참고자료: https://johngrib.github.io/wiki/Conway-s-law/
      → 팀 구성에 따라 설계가 달라진다.

    • 많은 팀들이 각각의 관심사로 나눠 시스템을 개발한다면, 각 팀들은 독립적으로 행동이 가능하도록 아키텍처를 구성해야 한다.

  • 현실 세계에서도 적용할만 한 아키텍처 원칙들

- 계층 결합 분리
    - 시스템의 기본적인 의도(핵심 비즈니스 로직) 이해 → 그 의도와는 다르게 변경되는 것들을 분리(단일 책임 원칙 + 공통 폐쇄 원칙)
    - 위 그림의 가로로 분리한 모습
- 유스케이스 결합 분리
    - 유스케이스 자체가 변경되는 경우
    - 위 그림의 세로로 분리한 모습
- 결합 분리 모드
    - 분리된 로직은 서로 다른 서버에서 실행 가능하므로, 처리량에 따라 유연하게 대처가 가능하다.
    - 이렇게 독립된 서버에서 실행가능한 컴포넌트를 서비스 또는 마이크로서비스라고 부른다. (정확한 기준은 모호)
    - 종류
        - 소스 수준 분리 모드(모노리틱 구조)
        - 배포 수준 분리 모드(멀티 모듈)
        - 서비스 수준 분리 모드(마이크로서비스)
    - 결합 분리 모드는 시간이 지나면서 바뀌기가 쉬우며, 이를 반영할 수 있는 아키텍처가 되어야 한다.
  • 진짜 중복과 가짜 또는 우발적인 중복을 구분해야 한다.
    • 진짜 중복: 동일한 변경을 모든 복사본에 똑같이 적용
    • 우발적인 중복: 초반에는 중복으로 보이지만, 시간이 지날수록 각각의 경로로 발전하는 경우
    • 계층 및 유스케이스 분리 시 진짜 중복인지 신중하게 판단해야 한다.

17장 경계: 선 긋기

  • 개발 초기에 그어야할 선 → 정책/세부사항
  • 세부사항을 너무 일찍 결정하지 말자.
  • 관련이 있는 것과 없는 것 사이에 선을 긋는다.
    • GUI/업무 규칙
    • 데이터베이스/GUI
    • 데이터베이스/업무 규칙
  • 선 긋기 = 플러그인 아키텍처
    • 핵심로직 + 플러그인(세부사항)

18장 경계 해부학

  • 소스 수준 분리 모드는 경계가 한 눈에 드러나지 않는다. (그렇다고 없는 것은 아님.)
  • 저수준 → 고수준 의존 (런타임과 컴파일 타임 의존 방향이 같다.)
  • 고수준 → 저수준 의존 (동적 다형성으로 의존성을 역전시켜야 한다. → 런타임과 컴파일 타임 의존 방향이 반대)

19장 정책과 수준

  • 소프트웨어 시스템 = 정책을 기술한 것
  • 수준 = 입력과 출력까지의 거리
    • 입력과 출력으로부터 멀수록 정책의 수준은 높아진다.
  • 고수준은 저수준보다 변경이 적다.
  • 정책을 변경되는 방식에 따라 컴포넌트로 분리(단일 책임 원칙, 공통 폐쇄 원칙) → 각 정책 컴포넌트는 고수준 정책을 의존(저수준은 의존성 역전 원칙, 안정된 의존성 원칙, 안정된 추상화 원칙으로 고수준으로 분리 후 의존하도록 변경)

@ODIN

15장. 아키텍처란?

  • 아키텍처의 궁극적인 목표는 시스템의 수명과 관련된 비용은 최소화하고, 프로그래머의 생산성은 최대화하는 데 있다.
  • 좋은 아키텍트는 세부사항에 대한 결정을 가능한 한 오랫동안 미룰 수 있는 방향으로 정책을 설계한다.

16장. 독립성

  • 유스케이스
    • 아키텍처는 반드시 유스케이스를 지원해야함.
    • 좋은 아키텍처가 행위를 지원하기 위해 할 수 있는 일 중에서 가장 중요한 사항은 행위를 명확히 하고 외부로 드러내며, 이를 통해 시스템이 지닌 의도를 아키텍처 수준에서 알아볼 수 있게 만드는 것.
  • 운영
    • 더 실질적이며 덜 피상적인 역할?
    • 각 컴포넌트를 적절히 격리하여 유지하고 컴포넌트 간 통신 방식을 특정 형태로 제한하지 않는다면, 시간이 지나 운영에 필요한 요구사항이 바뀌더라도 스레드, 프로세스, 서비스로 구성된 기술 스펙트럼 사이를 전환하는 일이 훨씬 쉬워질 것.
  • 개발
    • 콘웨이의 법칙 : 잘 격리되어 독립적으로 개발 가능한 컴포넌트 단위로 시스템을 분할
  • 배포
    • 좋은 아키텍처는 즉각적인 배포(immediate deployment)를 목표로 한다. → 마스터(메인) 컴포넌트는 시스템 전체를 하나로 묶고, 각 컴포넌트를 올바르게 구동하고 관리.
  • 선택사항 열어놓기
    • 선택사항을 열어 둠으로써, 향후 시스템에 변경이 필요할 때 어떤 방향으로든 쉽게 변경할 수 있도록 한다.
  • 계층 결합 분리
    • 단일 책임 원칙과 공통 패쇄 원칙을 적용하여, 그 의도의 맥락에 따라서 다른 이유로 변경되는 것들은 분리하고, 동일한 이유로 변경되는 것들을 묶는다.
  • 유스케이스 결합 분리
    • 시스템을 수평적 계층으로 분할하면서 동시에 해당 계층을 가로지르는 얇은 수직적인 유스케이스로 시스템을 분할할 수 있다.
  • 결합 분리 모드
    • 때때로 컴포넌트를 서비스 수준까지도 분리해야한다.
  • 개발 독립성
    • 컴포넌트가 완전히 분리되면 팀 사이의 간섭은 줄어든다.
  • 배포 독립성
    • 유스케이스와 계층의 결합이 분리되면 배포 측면에서도 고도의 유연성이 생긴다. → 새로 유스케이스를 추가하는 일에도 나머지를 그대로 둔 채 새로운 jar파일이나 서비스 몇개를 추가하면 되는 정도로 단순해진다.
  • 중복
    • 진짜 중복 과 우발적 중복이 있다. 시간이 지나며 화면은 서로 다른 방향으로 분기하여 결국에는 매우 다른 모습을 가질 가능성이 높다. 진짜중복인지 확인하라. 통합하고 싶다는 유혹이 섯부르게 넘어가지 말자.
  • 결합 분리모드(다시)
    • 소스 수준 분리모드 : 모든 컴포넌트가 같은 주소 공간에서 실행되고, 서로 통신할 때 간단한 함수 호출을 사용한다(모노리틱 구조)
    • 배포 수준 분리모드 : 배포 가능한 단위(jar, 공유 라이브러리)들 사이의 의존성을 제어할 수 있다.
    • 서비스 수준 분리모드 : 의존하는 수준을 데이터 구조 단위까지 낮출 수 있다.
    • 현 시점 가장 인기 있어 보이는 모드는 서비스 수준 분리 모드.
    • 좋은 아키텍처라면 나중에 상황이 바뀌었을 때 이 진행 방향을 거꾸로 돌려 원래 형태인 모노리틱 구조로 되돌릴 수도 있어야 한다.
  • 결론
    • 뛰어난 아키텍트라면 변경을 예측하여 큰 무리 없이 반영할 수 있도록 만들어야 한다.

잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다

17장. 경계: 선 긋기

  • SW 아키텍처는 선을 긋는 기술이면, 이러한 선을 경계라고 부른다. 경계는 SW요소를 서로 분리하고, 경계 한편에 있는 요소가 반대편에 있는 요소를 알지 못하도록 한다.
  • 아키텍트의 목표는 필요한 시스템을 만들고 유지하는데 드는 인적 자원을 최소화 하는것이다. 이러한 인적 자원의 효율을 떨어뜨리는 요인이 "결합"이다. 특히 너무 일찍 내려진 결정에 따른 결합이다.
  • 좋은 시스템 아키텍처는 이러한 결정을 가능한 최후의 순간에 내릴 수 있게 해주며 결정에 따른 영향이 크지 않게 만든다.
  • 어떻게/언제 선을 그을까?
    • 관련이 있는 것과 없는 것 사이에 선을 긋는다.
      • GUI는 업무 규칙과 관련이 없기 때문에 사이에 선이 있어야한다.

      • 데이터베이스는 GUI와 관련이 없으므로 사이에 선이 있어야 한다.

      • 데이터베이스는 업무 규칙과 관련이 없으므로 선이 있어야한다.

        → 업무 규칙이 데이터베이스에 신경 쓰지 않아야 한다는 부분에서 동의 하지 않을 수 있다. (데이터베이스는 업무 규칙과 서로 떼어놓을 수 없는 관계라고 배운 사람이 많다. 심지어 업무 규칙이 구체화된 것이 바로 데이터베이스라고 확신하는 사람도 더러있는데, 이는 잘 못 된 생각이다. 데이터베이스는 업무 규칙이 간접적으로 사용할 수 있는 도구다.)

18장. 경계 해부학

  • 경계 횡단하기
    • 적절한 위치에서 경계를 횡단하게 하는 비결은 소스코드의 의존성 관리에있다.
  • 두려운 단일체
    • 아키텍처 경계 중에서 가장 단순하며 가장 흔한 형태는 물리적으로 엄격하게 구분되지 않는 형태다.
    • 거의 모든 경우에 특정한 동적 다형성에 의존하여 의존성을 관리한다.
  • 배포형 컴포넌트
    • 아키텍처의 경계가 물리적으로 드러날 수 있는데 가장 단순한 형태는 동적 링크 라이브러리다.(npm, jar 등)
    • 배포 과정에서만 차이가 날 뿐, 배포 수준의 컴포넌트는 단일체와 동일.
  • 스레드
    • 모든 스레드가 단 하나의 컴포넌트에 포함될 수 도 있고, 많은 컴포넌트에 걸쳐 분산될 수도 있다.
  • 로컬 프로세스
    • 훨씬 강한 물리적 형태를 띠는 아키텍처 경계로 로컬 프로세스가 있다.
  • 서비스
    • 물리적인 형태를 띠는 가장 강력한 경계는 서비스이다.
      • 명령행 도는 그와 동등한 시스템 호출을 통해 구동
      • 자신의 물리적 위치에 구애받지 않음.
      • 모든 통신이 네트워크를 통해 이뤄진다고 가정
      • 서비스의 경계를 지나는 통신은 함수 호출에 비해 매우 느리다 → 이때 발생하는 레이턴시에 따른 문제는 고수준에서 처리 할 수 있어야 한다.
      • 저수준 서비스는 고수준 서비스에 '플러그인'되어야한다.
  • 한 시스템 안에서도 통신이 빈번한 로컬 경계와 지연을 중요하게 고려해야 하는 경계가 혼합되어있음을 의미.

19장. 정책과 수준

  • 대다수의 주요 시스템에서 하나의 정책은 이 정책을 서술하는 여러 개의 조그만 정책들로 쪼갤 수 있다.
    • 집계와 관련된 업무 규칙을 처리하는 방식을 서술하는 조그만 정책
    • 특정 보고서를 어떤 포맷으로 만들지를 서술하는 정책
    • 입력 데이터를 어떻게 검증할지를 서술하는 정책
  • 좋은 아키텍처라면 각 컴포넌트를 연결할 때 의존성의 방향이 컴포넌트의 수준을 기반으로 연결되도록 만들어야한다. → 저수준 컴포넌트가 고수준 컴포넌트에 의존하도록 설계되어야 한다.
  • 수준
    • 엄밀하게 정의하면 '입력과 출력까지의 거리'
      • 시스템의 입출력 모두로부터 멀리 위치할수록 정책의 수준은 높아짐.
      • 입출력을 다루는 정책이라면 시스템에서 최하위 수준에 위치
    • 소스코드 의존성은 그 수준에 따라 결합되어야 하며, 데이터 흐름을 기준으로 결합되서는 안된다.
  • 단일 책임, 개방 폐쇄, 공통 패쇄, 의존성 역전, 안정된 의존성, 안정된 추상화 원칙이 정책에 대한 논의에 포함된다.

@BUZZ

  • 15 아키텍처란?
    • 좋은 아키텍처는 시스템을 쉽게 (이해하고, 개발하며, 유지보수하고, 배포)할 수 있게 한다.

    • 아키텍처는 시스템의 동작 여부 자체와는 거의 관련이 없다.

    • 아키텍처는 소프트웨어를 유연하고 부드럽게 구조화한다.

    • 좋은 아키텍트는 시스템의 핵심적인 요소(정책이라고 한다)를 식별하고, 동시에 세부사항은 이 정책에 무관하게 만들 수 있는 형태로 시스템을 구축한다.

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

      좋은 아키텍처는 중요한 것과 중요하지 않은 것을 구분하고,
      중요하지 않은 것에 의존하지 않도록 잘 분리하여 설계한다.

    • 책 내용 요약

      개발

      개발하기 힘든 시스템이라면 수명이 길지도 않고 건강하지도 않을 것이다.

      • 시스템 아키텍처는 개발팀이 시스템을 쉽게 개발할 수 있도록 만들어야 한다.

        배포

        소프트웨어 시스템이 사용될 수 있으려면 반드시 배포할 수 있어야 한다. 배포 비용이 높을수록 시스템의 유용성은 떨어진다.

      • 소프트웨어 아키텍처는 시스템을 단 한 번에 쉽게 배포할 수 있도록 만드는 데 목표를 두어야 한다.

        운영

        아키텍처가 시스템 운영에 미치는 영향은 개발, 배포, 유지보수에 미치는 영향보다 적다.

        좋은 소프트웨어 아키텍처는 시스템을 운영하는데 필요한 요구도 알려준다.

      • 시스템 아키텍처는 유스케이스, 기능, 시스템의 필수 행위를 일급(first-class) 엔티티로 격상시키고, 이들 요소가 개발자에게 주요 목표로 인식되도록 해야 한다.
        - 이를 통해 시스템을 이해하기 쉬워지며, 따라서 개발과 유지보수에 큰 도움이 된다.

        유지보수

        유지보수는 모든 측면에서 봤을 때 소프트웨어 시스템에서 비용이 가장 많이 든다.

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

        • 탐사: 기존 소프트웨어에 새로운 기능을 추가하거나 결함을 수정할 때, 소프트웨어를 파헤쳐서 어디를 고치는게 최선인지, 그리고 어떤 전략을 쓰는게 최적일지를 결정할 때 드는 비용이다.
      • 아키텍처를 신중하게 만들면 이 비용을 크게 줄일 수 있다.
        - 컴포넌트 분리 및 안정된 인터페이스를 두어 서로 격리하기

        선택사항 열어 두기

        소프트웨어를 부드럽게 만들기 위해서는 구조적 가치를 중요하게 여겨야 한다.

      • 소프트웨어를 부드럽게 유지하는 방법은 선택사항을 가능한 한 많이, 그리고 가능한 한 오랫동안 열어 두는 것이다.

        • 선택사항: 중요하지 않은 세부사항(detail)
      • 모든 소프트웨어 시스템은 주요한 두 가지 구성요소로 분해할 수 있다. 정책(policy)과 세부사항이다.

        • 정책 요소는 모든 업무 규칙과 업무 절차를 구체화 한다. 정책이란 시스템의 진정한 가치가 살아 있는 곳이다.
        • 세부사항은 사람, 외부 시스템, 프로그래머가 정책과 소통할 때 필요한 요소지만, 정책이 가진 행위에는 조금도 영향을 끼치지 않는다. ex) 입출력 장치, 데이터베이스, 웹 시스템, 서버, 프레임워크, 통신 프로토콜 등
      • 아키텍트의 목표는 시스템에서 정책을 가장 핵심적인 요소로 식별하고, 동시에 세부사항은 정책에 무관하게 만들 수 있는 형태의 시스템을 구축하는데 있다.

        • 따라서 세부사항을 결정하는 일은 미루거나 나중에 할 수 있다.
      • 좋은 아키텍트는 결정되지 않은 사항의 수를 최대화 한다.

        장치 독립성

        1960년대에 프로그래머는 많은 실수를 저릴렀는데, 대표적인 실수 중 하나는 코드를 입출력 장치와 결합해버린 일이다. 프린터로 인쇄할 일이 생기면, 해당 프린터를 제어하는 입출력 명렁어를 직접 사용해서 코드를 작성했다.

      • 이러한 코드는 장치 종속적(device dependent)이다.

        왜 이러한 방법이 잘못된 것일까? → 장치를 바꾼다면 이 코드는 못 쓰게 되기 때문

      • 오늘날의 운영체제는 입출력 장치를 소프트웨어 함수로 추상화 했고, 해당 함수는 천공카드와 같은 단위 레코드를 처리한다.

        광고 우편

        저자는 1960년대 후반에 광고 우편을 인쇄하는 회사에서 일했다고 한다.

      • 장치 독립성을 이용해 어떤 장치를 사용할지 전혀 모른채, 그리고 고려하지 않고도 프로그램을 작성할 수 있엇다고 한다.

      • 이러한 프로그램에는 형태가 있었는데, 이 형태는 정책을 세부사항으로부터 분리했다.
        - 어떤 장치를 사용할지에 대한 결정을 연기시켰다.

        물리적 주소 할당

        시스템에서 고수준의 정책을 물리적 구조로부터 독립시킴으로써 애플리케이션과 하드웨어를 분리할 수 있다.

        결론

        좋은 아키텍트는 세부사항을 정책으로부터 신중하게 가려내고, 정책이 세부사항과 결합되지 않도록 엄격하게 분리한다. 이를 통해 정책은 세부사항에 관한 어떠한 지식도 갖지 못하게 되며, 어떤 경우에도 세부사항에 의존하지 않게 된다.

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

  • 16 독립성 스크린샷 2021-11-30 오후 4.49.46.png

    유스케이스

    아키텍처는 반드시 유스케이스를 지원해야함. 유스케이스를 통해 행위를 명확히 하고 외부로 드러내며, 시스템이 지닌 의도를 아키텍처 수준에서 알아볼 수 있게 만들어야함.

    운영

    시스템의 운영 지원 관점에서 아키텍처는 더욱 실질적이며 덜 피상적인 역할을 맡음. 예를 들면 유스케이스에 걸맞는 응답시간, 처리량을 보장할 때 이러한 운영 작업을 허용할 수 있는 형태로 아키텍쳐를 구조화 하되 형태는 여러가지로 구조화 될 수 있음. 그러므로 어떤 형태로든 전환할 수 있도록 선택사항을 열어두는것이 좋은 아키텍쳐임.

    개발

    개발시 콘웨이 법칙이 작용함.

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

    예를들면 한개의 컴파일러를 만드는데 4개의팀이 참여하면 4단계로 빌드해야하는 구조로된다는법칙임 그러므로 각 팀이 서로 방해받지 않으며 독립적으로 행동 하기 편한 아키텍처를 반드시 확보하여함.

    배포

    좋은 아키텍처는 시스템이 빌드된 후 즉각 배포할 수 있도록 지원해야한다. → 시스템을 컴포넌트 단위로 적절하게 분할하고 격리시켜야 가능.

    선택사항 열어놓기

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

    계층 결합 분리

    아키텍트는 SRP, CCP를적용하여 다른 이유로 변경되는 것들을 분리하고, 동일한 이유로 변경되것들을 묶음. 스크린샷 2021-11-30 오후 3.36.35.png 그림에서는 UI계층은 업무로직계층과 관련이 없기 때문에 수평적으로 분리되어있음.
    → 그러므로 서로 독립적으로 변경이가능함.

    유스케이스 결합 분리

    유스케이스 또한 서로 다른 이유로 변경됨. 그림에서는 수평적으로 분리하는 동시에 계층을 가로지르는 수직적인 유스케이스로 시스템이 분할됨. → 주문 추가 유스케이스 UI계층과 주문 삭제 유스케이스 UI계층이 분할됨. → 이렇게 분리함으로써 기존요소에 지장을 주지않고 새로운 유스케이스를 계속 추가할 수 있음. → 또한 유스케이스를 뒷받침하는 UI와 데이터베이스 계층을 서로 묶어서 각 유스케이스가 UI와 데이터베이스의 서로 다른 관점을 사용하게되면 새로운 유스케이스를 계속 추가하더라도 기존 유스케이스에는 영향을 주지 않음. (AOP)

    결합 분리 모드

    그림에서 처럼 결합 분리 작업은 운영 관점에서도 도움이 됨. → 유스케이스에서 서로 다른 관점으로 분리되었다면 각 유스케이스 별 처리량에 따른 서로 다른 구조로 설계할 수 있기 때문.

    개발 독립성

    컴포넌트가 완전히 분리되면 각 컴포넌트를 개발하는 팀사이의 간섭은 줄어듬. → 예를 들면 업무 규칙이 UI를 알지 못하면 UI를 중점에 둔 팀은 업무 규칙에 중점을 둔 팀에 그다지 영향을 줄 수 없음.

    배포 독립성

    그림에서처럼 유스케이스와 계층의 결합이 분리되면 운영중인 시스템에서도 계층과 유스케이스를 교체(시스템 런타임중 새로운 jar, 서비스 등을 추가하는 일)할 수 있음.

    중복

    중복의 종류로는 진짜 중복, 우발적 중복이 있음.

    진짜 중복? 한 인스턴스가 변경되면 모든 복사본에도 적용해야함.

    우발적 중복? 처음에는 비슷해보이지만 시간이 지나면 서로 다른 방향으로 분기됨.

    아키텍트는 우발적 중복 여부를 확인하고 통합작업을 신중히 결정하는것이 중요함.

    결합 분리 모드(다시)

    계층과 유스케이스의 결합을 분리하는 방법.
    • 소스 수준 분리 모드(모노리틱) : 소스 코드 모듈 사이의 의존성 제어함.

    • 배포 수준 분리 모드 : jar 파일과 같이 배포 가능한 단위들 사이의 의존성을 제어함.

    • 서비스 수준 분리 모드 : MSA

      좋은 아키텍처는

      시스템이 모로리틱 구조 → 독립적 배포가능 단위 집합 구조 → 독립적인 서비스 구조로 성장할 수 있도록 만들 수 있어야 함.

  • 17 경계: 선긋기

    이른결정이란? 시스템의 업무 요구사항 즉, 유스케이스와 관련없는 프레임워크, 데이터베이스등을 결정하는것을 말함.

    이른결정에 따른 결합을 없애기위해 소프트웨어 요소를 서로 분리해야함. 이는 선을 긋는다고 표현하며 이러한 선을 경계라고 말함. 다시말해 경계선을 긋는 행위는 결정을 늦추고 연기하는 데 도움을 줌. 궁극적으로는 결합으로 인해 발생되는 리스크로부터 시간을 절약해줌.

    경계선을 잘 그은 사례 : FitNesse

    개발초기에 업무규칙과 데이터베이스 사이에 경계선을 그어 플랫파일에 저장하는 시스템을 단 하루만에 모든 시스템이 Mysql에 저장하는 시스템으로 변경됨.

    어떻게 선을 그을까? 그리고 언제 그을까?

    • 선은 관련있는것과 없는것 사이에 긋는다.

    • 데이터베이스는 업무규칙이 사용하는 간접적 도구다.

      ![스크린샷 2021-11-30 오후 3.52.02.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/050dad6d-ef3f-4686-ba05-9fbb3ec0cba4/스크린샷_2021-11-30_오후_3.52.02.png)

      그림에서 경계선은 Interface, Database Access사이에 그어짐.
      Database Access를 알고있는 클래스는 없음.

      스크린샷 2021-11-30 오후 3.52.12.png

      큰 개념에서 보게되면

      Business Rules 컴포넌트안에 Database Interface를 Database 컴포넌트안에 Database Access가 의존하고있음.

      Business Rules 컴포넌트에게 있어 Database 컴포넌트는 문제가되지않음, 그러나 Business Rules 컴포넌트의 호출을 쿼리언어로 변환하는 코드를 Database 컴포넌트가 담고있기때문에 Database 컴포넌트는 Business Rules 컴포넌트 없이 존재할 수 없음.

      화살표 방향은 Business Rules 컴포넌트를 향하고있기 때문에 Database 컴포넌트는 다른 구현체로도 교체될 수 있음.

    • 앞서 말했다시피 데이터베이스에 대한 결정 연기가능.

    • 업무규칙 작성, 테스트에 집중 가능.

      입력과 출력은?

      앞서 말했다시피 행위적인것(GUI) 구조적인것에 더 가치를 둬야하기 때문에, 입출력은 중요하지 않다.

      사용자 경험 인터페이스. (화면, 마우스, 음향 등) 뒤에는 이것을 조작하는 모델(데이터 구조와 함수의 집합) 이 존재.
      중요한 것은 업무 규칙.

      스크린샷 2021-11-30 오후 3.56.58.png

      Business Rules 컴포넌트와 Databse 컴포넌트의 관계와 같이 Business 컴포넌트는 GUI 컴포넌트를 신경쓰지 않는다.

    • GUI는 다른 종류의 인터페이스로 교체가능.

      플러그인 아키텍처

      스크린샷 2021-11-30 오후 3.59.17.png

      데이터베이스와 GUI 컴포넌트 추가와 관련해 서드파티 플러그인을 사용할 수 있게 해주는 패턴임

      결론

      시스템을 핵심 업무와 나머지는 플러그인인 컴포넌트 단위로 분리.

      즉, 의존성 역전 원칙과 안정된 추상화 원칙을 이용해서 경계를 분리할수 있다.

  • 18 경계 해부학 시스템 아키텍처는 소프트웨어 컴포넌트와 그 컴포넌트를 분리하는 경계에 의해 정의됨.
    경계는 다양한 형태로 나타남.

    경계 횡단하기

    런타임에 경계를 횡단함.
    → 한쪽경계에서 다른쪽으로 데이터를 넘김.
    소스코드 의존성관리를 통에 적절한 위치에 경계횡단 가능.

    두려운 단일체

    배포관점에서 볼 때 소스수준 분리모드 즉, 단일체(monolith)는 경계가 드러나지 않는다. 그러나 경계가 존재하지않거나 경계자체가 무의미하지않음.! → 정적으로 링크된 단일 실행파일을 만들더라도 그안에 포함된 다양한 컴포넌트를 개발하고 바이너리로만드는 과정을 독립적으로 수행하기 때문. 가장 단순한 형태의 경계횡단 → 저수준 클라이언트에서 고수준 서비스의 함수를 호출. 스크린샷 2021-11-30 오후 4.21.23.png 왼쪽에서 오른쪽으로 경계를 횡단함. 만약 고수준 클라이언트가 저수준 서비스를 호출해야 한다면 의존성을 역전시킴. 스크린샷 2021-11-30 오후 4.22.21.png 모두 오른쪽에서 왼쪽으로 경계를 횡단함.
    고수준은 저수준(세부사항)으로 부터 독립적으로 유지시켜야 함.

    결론

    단일체 말고는 대다수가 한가지 이상 경계전략 사용하는데, DIP원칙을 따라야한다 저수준 컴포넌트가 고수준 컴포넌트를 의존해야한다.
    1. 상위 모듈은 하위 모듈에 의존해서는 안된다

    2. 추상화는 세부 사항에 의존해서는 안된다

      SOLID - DIP(Dependency Inversion Principle)란 : 의존성 역전 원칙

  • 19 정책과 수준 수준을 정의하자면 입력과 출력까지의 거리다. 입.출력과 멀어질수록 정책의 수준은 높아짐. 그림을 보면 번역 컴포넌트는 고수준 컴포넌트겠지? 스크린샷 2021-11-30 오후 4.32.08.png 데이터흐름은 실선, 의존성은 점선으로 표시됨. 그러므로 데이터흐름과 의존성은 항상 같은 방향을 가리키지 않음. 소스코드 의존성은 그 수준에 따라 결합되어야 하며, 데이터 흐름을 기준으로 결합되어서는 안된다.
    • 잘못된 아키텍처 예
      // 잘못된 아키텍처.
      function encrypt() {
        while (true)
          writeChar(translate(readChar()));
      }
      
      위 코드는 고수준인 encrypt 함수가 저수준인 readChar와 writeChar 함수에 의존하기 때문에 잘못된 아키텍처이다. 개선된 아키텍처 스크린샷 2021-11-30 오후 4.40.34.png 이 구조에서 고수준의 암호화 정책을 저수준의 입력/출력 정책으로부터 분리시킨 방식에 주목
      • 입력과 출력에 변화가 생기더라도 암호화 정책은 거의 영향을 받지 않기 때문이다.

@CHRIS

15. 아키텍처란?

소프트웨어 시스템의 아키텍처란 시스템을 구축했던 사람들이 만들어낸 시스템의 형태다.

시스템 아키텍처는 시스템의 동작 여부와는 거의 관련이 없다.

형편없는 아키텍처를 갖춘 시스템도 그런대로 잘 동작하고 대체로 운영에서는 문제를 겪지 않지만 배포, 유지보수, 계속되는 개발 과정에서 어려움을 겪는다.

좋은 아키텍처는 시스템을 쉽게 이해하고, 쉽게 개발하며, 쉽게 유지보수하고, 또 쉽게 배포하게 해준다.

아키텍처의 궁극적인 목표는 시스템의 수명과 관련된 비용은 최소화하고, 프로그래머의 생산성은 최대화하는 데 있다.

  • 개발 시스템 아키텍처는 개발팀(들)이 시스템을 쉽게 개발할 수 있도록 뒷받침해야만 한다. 팀 구조가 다르다면 아키텍처 관련 결정에서도 차이가 난다. (소규모, 중규모, 대규모, ...)
  • 배포 안타깝게도 초기 개발 단계에서는 배포 전략을 거의 고려하지 않는데,
    이로 인해 개발하기는 쉬울지 몰라도 배포하기는 상당히 어려운 아키텍처가 만들어진다. 배포 비용이 높을수록 시스템의 유용성은 떨어진다.
    → 소프트웨어 아키텍처는 시스템을 단 한 번에 쉽게 배포할 수 있도록 만드는 데 그 목표를 두어야 한다. (MSA is not a silver bullet)
  • 운영 아키텍처가 시스템 운영에 미치는 영향은 개발, 배포, 유지보수에 미치는 영향보다는 덜 극적이지만 시스템을 운영할 때 아키텍처가 맡는 또 다른 역할이 있다. 좋은 소프트웨어 아키텍처는 시스템을 운영하는 데 필요한 요구(정책, 비지니스 로직)도 알려준다. (시스템을 이해하기 쉬워지며, 따라서 개발과 유지보수에 큰 도움이 된다)
  • 유지 보수 유지보수는 모든 측면에서 봤을 때 소프트웨어 시스템에서 비용이 가장 많이 든다.
  • 🌟 선택사항 열어 두기 소프트웨어의 두 가지 가치: 행위적 가치, 구조적 가치
    이 중에서 두 번째 가치가 더 중요한데, 소프트웨어를 부드럽게soft 만드는 것은 바로 이 구조적 가치이기 때문이다. 소프트웨어를 부드럽게 유지하는 방법은 선택사항을 가능한 한 많이, 그리고 가능한 한 오랫동안 열어 두는 것이다. 열어 둬야 할 선택사항? → 중요치 않은 세부사항detail (IO device, DB, Communication Protocol, Framework, ...) 아키텍트의 목표는 시스템에서 정책을 가장 핵심적인 요소로 식별하고, 동시에 세부사항은 정책에 무관하게 만들 수 있는 형태의 시스템을 구축하는데 있다. 세부사항에 대한 결정을 오랫동안 미루거나 연기할 수 있다면, 더 많은 정보를 얻을 수 있고, 이를 기초로 제대로 된 결정을 내릴 수 있다. 또한 이를 통해 다양한 실험을 시도해볼 수 있는 선택지도 열어 둘 수 있다.

16. 독립성

(너무 길어서 다른 부분과 중복이 되는 중간은 짜름)

좋은 아키텍처는 다음을 지원해야 한다.

  • 시스템의 유스케이스 아키텍트의 최우선 관심사는 유스케이스이며, 아키텍처에서도 유스케이스가 최우선이다. 좋은 아키텍처가 행위를 지원하기 위해 할 수 있는 일 중에서 가장 중요한 사항은 행위를 명확히 하고 외부로 드러내며,
    이를 통해 시스템이 지닌 의도를 아키텍처 수준에서 알아볼 수 있게 만드는 것이다. 이들 요소는 클래스이거나 함수 또는 모듈로서 아키텍처 내에서 핵심적인 자리를 차지할 뿐만 아니라, 자신의 기능을 분명하게 설명하는 이름을 가질 것이다.
  • 시스템의 운영 아키텍처는 각 유스케이스에 걸맞은 처리량과 응답시간을 보장해야 한다. 아키텍처에서 각 컴포넌트를 적절히 격리하여 유지하고 컴포넌트 간 통신 방식을 특정 형태로 제한하지 않는다면, 기술 스펙트럼 사이를 전환하는 일이 훨씬 쉬워질 것이다.
  • 시스템의 개발 아키텍처는 개발환경을 지원하는 데 있어 핵심적인 역할을 수행한다. 많은 팀으로 구성되며 관심사가 다양한 조직에서 어떤 시스템을 개발해야 한다면,
    각 팀이 독립적으로 행동하기 편한 아키텍처를 반드시 확보하여 개발 하는 동안 팀들이 서로를 방해하지 않도록 해야 한다. → 이러한 아키텍처를 만들려면 잘 격리되어 독립적으로 개발 가능한 컴포넌트 단위로 시스템을 분할할 수 있어야 한다.
  • 시스템의 배포 아키텍처는 배포 용이성을 결정하는 데 중요한 역할을 한다.
    이때 목표는 즉각적인 배포immediate deployment다. 좋은 아키텍처라면 시스템이 빌드된 후 즉각 배포할 수 있도록 지원해야 한다.
  • 선택사항 열어놓기 좋은 아키텍처는 컴포넌트 구조와 관련된 이 관심사들 사이에서 균형을 맞추고, 각 관심사 모두를 만족시킨다. 라고하지만 현실에서는 이러한 균형을 잡기가 매우 어렵다. 하지만 몇몇 아키텍처 원칙은 구현에 비싸지 않지만 시스템을 제대로 격리된 컴포넌트 단위로 분할할 때 도움이 되며, 이를 통해 선택사항을 가능한 한 많이, 그리고 가능한 한 오랫동안 열어 둘 수 있게 해준다.
  • 계층과 유스케이스의 결합을 분리하는 방법은 다양하다
    • 소스 수준 분리 모드

    • 배포 수준 분리 모드

    • 서비스 수준 분리 모드

      프로젝트 초기 단계는 어떤 모드가 최선인지 알기 어렵다는 게 답이다.

      사실 프로젝트가 성숙해갈수록 최적인 모드가 달라질 수 있다. (상황에 따라 바뀐다)

      좋은 아키텍처는 시스템이 모노리틱 구조로 태어나서 단일 파일로 배포되더라도, 이후에는 독립적으로 배포 가능한 단위들의 집합으로 성장하고, 또 독립적인 서비스나 마이크로서비스 수준까지 성장할 수 있도록 만들어져야한다.
      또한 좋은 아키텍처라면 나중에 상황이 바뀌었을 때 이 진행 방향을 거꾸로 돌려 원래 형태인 모노리틱 구조로 되돌릴 수도 있어야 한다.

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

17. 경계: 선 긋기

소프트웨어 아키텍처는 선을 긋는 기술이며, 이러한 선을 경계boundary 라고 부른다.

경계는 소프트웨어 요소를 서로 분리하고, 경계 한편에 있는 요소가 반대편에 있는 요소를 알지 못하도록 막는다.

좋은 시스템 아키텍처는 시스템의 업무 요구사항, 즉 유스케이스와 아무런 관련이 없는 결정(DB, Framework, Protocol)을 가능한 한 최후의 순간에 내릴 수 있게 해주며, 결정에 따른 영향이 크지 않게 만든다.

  • 어떻게 선을 그을까? 그리고 언제 그을까? 관련이 있는 것과 없는 것 사이에 선을 긋는다.
    • GUI는 업무 규칙과는 관련 없기 때문에, 이 둘 사이에는 반드시 선이 있어야 한다.

    • 데이터베이스는 GUI와는 관련이 없으므로, 이 둘 사이에도 반드시 선이 있어야 한다.

    • 데이터베이스는 업무 규칙과 관련이 없으므로, 이 둘 사이에도 선이 있어야 한다.

      Database 컴포넌트는 다양한 구현체로 교체될 수 있으며, BusinessRules는 조금도 개의치 않는다.

  • 입력과 출력은? 입력과 출력은 중요하지 않다.

  • 플러그인 아키텍처

플러그인 형태로 시스템을 구축함으로써 변경에 있어 현실성 있는 가능성을 제공해준다.

18. 경계 해부학

  • 시스템 아키텍처는 일련의 소프트웨어 컴포넌트와 그 컴포넌트들을 분리하는 경계에 의해 정의된다.

  • 적절한 위치에서 경계를 횡단하게 하는 비결은 소스 코드 의존성 관리에 있다.

    (not Runtime 의존성)

  • 단일체 아키텍처 경계 중에서 가장 단순하며 가장 흔한 형태는 물리적으로 엄격하게 구분되지 않는 형태다. 이 형태에서는 함수와 데이터가 단일 프로세서에서 같은 주소 공간을 공유하며 그저 나름의 규칙에 따라 분리되어 있을 뿐이다. 가장 단순한 형태의 경계 횡단은 저수준 클라이언트에서 고수준 서비스로 향하는 함수 호출이다.

고수준 클라이언트가 저수준 서비스를 호출해야 한다면 동적 다형성을 사용 하여 제어흐름과는 반대 방향으로 의존성을 역전시킬 수 있다.

모노리틱 구조의 실행 파일이라도 이처럼 규칙적인 방식으로 구조를 분리하면 프로젝트를 개발, 테스트, 배포하는 작업에 큰 도움이 된다.
  • 배포형 컴포넌트 단일체(모놀리식)과 다르게 아키텍처의 경계가 물리적으로 드러날 수도 있는데 그중 가장 단순한 형태는 동적 링크 라이브러리다. (e.g. jar, ddl, gem, ...) 하지만 배포 과정에서만 차이가 날 뿐, 배포 수준의 컴포넌트는 단일체와 동일하다.
  • 로컬 프로세스 로컬 프로세스들은 동일한 프로세서 또는 하나의 멀티코어 시스템에 속한 여러 프로세서들에서 실행되지만, 각각이 독립된 주소 공간에서 실행된다. 로컬 프로세스를 일종의 최상위 컴포넌트라고 생각하면 로컬 프로세스 간 분리 전략은 단일체나 바이너리 컴포넌트의 경우와 동일하다. (저수준 → 고수준) 하지만 프로세스간 통신은 비싼 작업이므로 통신이 빈번히 이뤄지지 않게 제한이 필요하다
  • 서비스 물리적인 형태를 띠는 가장 강력한 경계는 바로 서비스다. 서비스들은 모든 통신이 네트워크를 통해 이뤄진다고 가정한다. 이를 제외하고는 로컬 프로세스에 적용한 규칙이 서비스에도 그대로 적용 된다. 저수준 서비스는 반드시 고수준 서비스에 플러그인되어야 한다. 고수준 서비스의 소스 코드에는 저수준 서비스를 특정 짓는 어떤 물리적인 정보 (예를 들면, URI)도 절대 포함해서는 안 된다.

19. 정책과 수준

  • 컴퓨터 프로그램은 각 입력을 출력으로 변환하는 정책을 상세하게 기술한 설명서다. 소프트웨어 아키텍처를 개발하는 기술에는 이러한 정책을 신중하게 분리 하고, 정책이 변경되는 양상에 따라 정책을 재편성하는 일도 포함된다. (CCP)
  • 수준 level: 입력과 출력까지의 거리 입출력에서 멀어질수록 정책의 수준은 높아지며, 입출력을 다루는 정책이라면 낮은 수준에 위치한다. 문자 읽기, 쓰기: 저수준 / 번역: 고수준

소스 코드 의존성은 그 수준에 따라 결합되어야 하며, 데이터 흐름을 기준으로 결합되어서는 안 된다.

→ 고수준과 저수준을 분리하여 저수준이 변경이 필요하더라도 고수준의 정책은 영향을 받지 않으면서 변경이 가능하다

이는 저수준 컴포넌트가 고수준 컴포넌트에 플러그인되어야 한다는 관점으로 바라볼 수도 있다.


@BRANDON

15. 아키텍처란?

좋은 아키텍트는 세부사항을 정책으로부터 신중하게 가려내고, 정책이 세부사항과 결합되지 않도록 분리한다. 이를 통해 정책은 세부사항에 관한 어떠한 지식도 갖지 못하게 되며, 어떤 경우에도 세부사항에 의존하지 않게 된다. 좋은 아키텍트는 세부사항에 대한 결정을 가능한 한 오랫동안 미룰 수 있는 방향으로 정책을 설계한다.

16. 독립성

시스템의 결합 분리 모드는 시간이 지나면서 바뀌기 쉬우며,

뛰어난 아키텍트라면 이러한 변경을 예측하여 큰 무리 없이 반영할 수 있도록 만들어야 한다.

17. 경계 : 선 긋기

  • 17장은 한 번 더 읽어봐야겠어요 너무 약식으로 읽었다보니 다른 멤버가 쓴 내용을 참조하도록 할께요 😵
🗒️ **직렬화 / 마샬링 / 언마샬링** * 직렬화 ⇒ 일련의 객체 정보를 파일로 저장하거나 네트워크 상 공유를 용이하게 하기 위해 primitive한 데이터로 변조하는 작업 (byte stream 변환) * 마샬링 ⇒ 직렬화의 과정에 마샬링이 포함됨. 변환하는 일련의 과정을 뜻함. 변환자체에 목적이 있으며 이종 언어/플랫폼간의 데이터 송수신 시 사용.

1) 직렬화된 객체를 바이트 단위로 분해 (marshalling)
2) 직렬화 되어 분해된 데이터를 순서에 따라 전송
3) 전송 받은 데이터를 원래대로 복원 (unmarshalling)

18. 경계 해부학

단일체를 제외한 대다수의 시스템은 한 가지 이상의 경계전략을 사용한다.
실제로 서비스는 상호작용하는 일련의 로컬 프로세스 퍼사드(Facade)에 불과할 때가 많다.
대체로 한 시스템 안에서도 통신이 빈번한 로컬 경계와 지연을 중요하게 고려해야 하는 경계가 혼합되어 있음을 의미한다.

19. 정책과 수준

function encrypt() {
  while (true) {
    writeChar(translate(readChar()));
  }
}
  • 고수준인 encrypt 함수가 저수준인 readChar와 writeChart 함수에 의존하기 때문에 잘못된 아키텍처
🗒️ **import 문에 대해**

Import 문은 순수하게 개발자가 작성 중인 클래스에서 참조하는 각 클래스의 정규화된 이름 대신 짧은 클래스 이름을 사용할 수 있도록 하기 위해 존재합니다. 컴파일러는 한 줄의 바이트 코드가 생성되기 전에 참조된 클래스의 이름을 확인하는 매우 초기에 이러한 import 문을 사용합니다.


@LIAM

15. 아키텍처란?

아키텍처의 주된 목적은 시스템의 생명주기를 지원하는 것
시스템의 수명과 관련된 비용은 최소화하고, 프로그래머의 생산성은 최대화하는 것

✅ 좋은 아키텍처란 결국, **개발, 배포, 운영, 유지보수를 모두 고려**한 프로그램

16. 독립성

  • 유스케이스 - 시스템 구조 자체에서 확인이 가능해야 한다 ( 시스템이 지닌 의도를 아키텍처 수준에서 분간)
    • 시스템이 무엇을 제공하는지 가장 간단하게 보여주는 다이어그램
  • 운영 - 해당 요구나 환경에 의해 아키텍처를 구조화 한다
    • 사용자 입장의 경우 → 여러 데이터를 필요 데이터만 빠르게 조회 ( 속도가 중요 )
    • 관리자 입장의 경우 → 특정 데이터를 연관된 모든 데이터 를 조회 ( 정확도이 중요)
  • 개발 - 독립적으로 개발하는 동안 서로를 방해하지 않도록 해야한다
    • 서로간의 연결이 되는 Request, Response에 대한 구조가 명확히 정의되어야 할듯 하다
  • 유스케이스 결합 분리 - 새로운 유스케이스를 추가할 때, 기존 유스케이스에 영향을 주는 일은 없어야 한다
    • 각 계층에서 서로 겹치지 않게 해야한다
  • 중복 - 거짓된 또는 우발적인 중복에 대해서는 중복이 아니다

17. 경계 : 선긋기

선을 그음으로써 소프트웨어 요소를 서로 분리하고, 서로 다른 위치에 있는 각각의 요소를 알지 못하도록 막는다

FitNesse( 웹 서버 형태로 제공되는 오픈소스 인수 테스트 자동화 도구 ) 이야기

경계선을 긋는 행위는 결정을 늦추고 연기하는데 도움이 된다.

✅ 배보다 배꼽이 더 크지 말자 역할이 간결한 프로그램은 간결한 환경설정과 간결한 결과가 필요하다

18. 경계 해부학

???????

19. 정책과 수준

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

SOLID를 잘 적용해야한다

QNA || 후기 || 한마디

@LEO

스터디 진척률 50% 🎉

❓ 19장에서 단일책임원칙, 개방폐쇄원칙, 공통 폐쇄원칙, 의존성 역전 원칙, 안정된 의존성 원칙, 안정된 추상화 원칙이 모두 포함한다고 하는데.. 각 원칙이 어디에서 무슨 이유로 사용되는 건가요?

@PARKER

💡 '아키텍처'가 무엇인지 쪼금이라도 알게 되었던 같습니다~

인상깊었던 문구

  • "좋은 아키텍트는 결정되지 않은 사항의 수를 최대화한다."
    -
    진짜 중복과 가짜 또는 우발적인 중복을 구분해야 한다.

@ODIN

🤔 후기 계속 책을 읽어나가면서 내용을 전체적으로 파악 하기 위한 시간이 많이 소모되는것 같네요. 하나를 가볍게 넘기면 다음부분이 이해가 안되다보니 어렵네요.. ㅠ 많이 얻어갑니다 ㅎㅎ..

@BUZZ

  • 다같이 이야기해서 들으니까 이해가 되는게 많은것같아요.
  • 저두 일욜이나 토요일 반나절은 잡아먹어요~ 2시간이뭐야~ 천재

@CHRIS

설계에 관심을 가져야하는 이유가 단순히 이론적인 부분을 만족하자는 것이 아닌,

실질적으로 변경에 유연하고 새로운 개발자가 들어왔을 때 쉽게 파악할 수 있는 구조를 설계하고 개발할 수 있어야하기 때문이라고 생각합니다.

그리고 이러한 부분이 개발자를 코드 싸개와 구분되게 하는 중요한 척도 중에 하나라고 봅니다.

아무리 서비스가 잘 돌아가더라도 새로운 기능을 만들때 3달이 걸리며 QA에 2달이 걸린다면 그 서비스가 시장에서 큰 의미를 가질 수 있을까요?

또 그러한 서비스를 개발하는 개발자의 직업 만족도는 얼마나 높을까요?

그런 측면에서 개인적으로 1, 2장과 더불어 좋아하는 부분입니다.


@BRANDON


@LIAM

❓ 개발 초기에는 데이터베이스, 웹 서버, REST 적용 유무, 프레임워크를 선택할 필요가 없다고 한다. 프레임워크를 사용하고, AWS서비스를 사용하고, REST를 사용함으로써 개발외적인 요소를 신경쓰지 않는 (예를들면 JDBC로 구축시 보안문제) 장점이 있고, 개발 방향성도 나쁘지 않을것 같은데.. ❓ 선택사항 열어놓기 신규 프로젝트를 개발 시 가장 난해한 말이 아닐까 한다. 추후 확장성을 고려해서, 나중에 사용할 수도.. 등등의 말은 우리를 더욱 개발하기 어렵게 한다. ***"아, 이기능만 없으면 좀더 깔끔하게 코드가 나올 수 있을 것 같은데.."*** 개인적으로 초기 개발단계에서 코드를 뒤집어야 할 정도로 변경이 필요한 코드는 1차적으로 개발자의 잘못도 존재하지만 잘못된 기획의 문제도 존재한다고 생각된다 **결론 → 기획자와 개발자가 친해져서 여러 이야기들이 오가야 한다** ❓ 거짓된 중복 해당 부분이 이번 부분에서 가장 실무적으로 와닿는 부분이다. 확실하게 나뉘는 서비스에 대해서 개발을 진행하다보면, IntelliJ에서 `duplicate code`라고 중복제거를 하라고 경고를 한다. 정말 그것이 중복코드인가? 모두 같은 비지니스 로직을 가지고 있지만 중간에 한줄의 if와 하나의 변수명이 다른데 정말 이외의 코드에서 서비스간 변경이 없을 것이라고 확신할 수 있는가? 개발자는 중복 제거를 하지 않는 코드를 보면 가슴이 답답하다 ❓ 정책 중, 반대로 고수준의 정책이 저수준으로 향하는 예제와 변경사항의 문제점은 무엇이 있을까?
profile
11년차 검색개발자 입니다. 여러 지식과 함께 실제 서비스를 운영 하면서 발생한 이슈에 대해서 정리하고 공유하고자 합니다.

0개의 댓글