diff --git "a/ch19_\354\225\204\355\202\244\355\205\215\354\262\230_\352\262\260\354\240\225/ch19_eden.md" "b/ch19_\354\225\204\355\202\244\355\205\215\354\262\230_\352\262\260\354\240\225/ch19_eden.md" new file mode 100644 index 0000000..0b57333 --- /dev/null +++ "b/ch19_\354\225\204\355\202\244\355\205\215\354\262\230_\352\262\260\354\240\225/ch19_eden.md" @@ -0,0 +1,245 @@ +# 아키텍처 결정 + +아키텍트의 핵심 역할은 **아키텍처 결정을 내리는 것**입니다. +아키텍처 결정에는 시스템 구조뿐만 아니라, 아키텍처 특성에 영향을 미치는 다양한 기술 결정을 포함합니다. +아키텍트는 정보를 수집하고, 결정을 정당화 및 문서화한 뒤, 이해관계자와 효과적으로 소통해야 합니다. + +## 19.1 아키텍처 결정 안티패턴 + +아키텍처 결정에서 주로 발생하는 대표적인 안티패턴으로는 ‘**네 패를 먼저 보여주지마**’, ‘**무한반복 회의**’, **‘이메일 기반 아키텍처’**가 있으며, 이들은 서로 연계되어 누적되는 경향이 있습니다. + +### 19.1.1 ‘네 패를 먼저 보여주지마’ 안티패턴 + +이 안티패턴은 잘못된 선택을 두려워해 결정을 회피하거나 미루는 현상을 말합니다. +이를 극복하는 방법은 두 가지입니다. + +1. **중요한 결정을 내리기 전, 책임질 수 있는 마지막 순간까지 기다리기**: 충분한 정보를 수집해 결정을 검증하고 정당화하되, 지나치게 시간을 끌지 않아야 합니다. +2. **개발팀과 지속적 협력**: 아키텍트가 결정한 내용을 의도한 대로 추진하며, 개발팀의 도움을 받아 문제 발생 시 신속히 대응할 수 있도록 합니다. + +예를 들어 개발 과정에서 일부 서비스의 확장성 요건으로 인해 메모리 사용량이 예상보다 많아지면, 아키텍트는 개발팀과 협력하여 아키텍처를 조정해야 합니다. + +### 19.1.2 ‘무한반복 회의’ 안티패턴 + +이 안티패턴은 어떤 결정을 왜 했는지 알지 못한 채, 회의만 계속 반복하는 상황을 의미합니다. +이는 아키텍트가 자신의 결정을 정당화하지 못할 때 발생하며, 방지를 위해서는 결정의 기술적, 비즈니스적 근거를 명확히 제시해야 합니다. +예를 들어, 모놀리식 애플리케이션을 개별 서비스로 분리하는 아키텍처 리팩터링은 기술적으로 자원 사용과 관리 효율성을 높이는 동시에, 비즈니스적으로도 신기능 출시를 앞당기고 개발 비용을 절감할 수 있다는 점을 명확히 설명할 수 있어야 합니다. +아키텍처 결정을 정당화하려면 비즈니스 가치를 제시하는 것이 중요합니다. +일반적인 요소로는 비용, 출시 시기, 유저 만족도, 전략적 포지셔닝 등을 꼽을 수 있으며, 이들 중 이해관계자에게 무엇이 중요한지 고려해야 합니다. + +### 19.1.3 ‘이메일 기반 아키텍처’ 안티패턴 + +이 안티패턴은 소통 수단으로 이메일을 사용하고, 결정 사항을 체계적으로 문서화하지 않은 탓에, 아키텍처 결정을 제대로 전달하지 못해 사람들이 결정을 놓쳐버리는 상황을 의미합니다. +이를 방지하려면 단일 기록 시스템에 아키텍처 결정의 세부 정보를 보관해야 합니다. +이를 통해 기록의 일관성을 유지하고, 결정의 변경 사항을 효과적으로 전달할 수 있습니다. +또한 아키텍처 결정은 관련자에게만 통지하고, 이메일에는 결정의 맥락만 언급하며, 세부 정보는 링크로 제공해야 합니다. + +## 19.2 아키텍처적으로 중요한 + +다소 기술적인 내용이더라도, 그것이 아키텍처 특성을 직접 지원하기 위해 선택된 기술이라면 이는 아키텍처 결정으로 간주할 수 있습니다. +아키텍처 결정의 본질은 아키텍처적으로 중요한(architecturally significant) 것들이어야 한다는 것입니다. +이는 **구조, 비기능적 특성, 의존성, 인터페이스, 구현 기술에 영향을 미치는 결정**이라고 정의할 수 있습니다. + +- **구조 (Structure)** + - 아키텍처의 패턴이나 스타일에 영향을 미치는 결정들. + - 예: 여러 마이크로서비스 간 데이터를 공유하기로 한 결정 -> 서비스 경계 콘텍스트와 애플리케이션 구조에 영향을 미침. +- **비기능 특성 (Nonfunctional Characteristic)** + - 개발 및 유지보수 중인 시스템에서 중요한 아키텍처 특성. + - 예: 성능이 중요한 특성이고 기술 선택이 성능에 영향을 미칠 경우, 이는 아키텍처 결정이 됨. +- **의존성 (Dependency)** + - 시스템 내부의 컴포넌트 또는 서비스 간 커플링 지점. + - 확장성, 모듈성, 민첩성, 시험성, 안정성 등에 영향을 미침. +- **인터페이스 (Interface)** + - 서비스와 컴포넌트에 접근하고 조정하는 수단. + - 예: 계약 버저닝, 버전 구식화 등의 계약 정의 내용 +- **구현 기술 (Implementation Technique)** + - 플랫폼, 프레임워크, 도구, 프로세스와 관련된 결정. + +## 19.3 아키텍처 결정 레코드 + +아키텍처 결정을 효과적으로 문서화하기 위해 **아키텍처 결정 레코드(ADR)** 가 사용됩니다. +ADR은 보통 한두 페이지 분량의 짧은 텍스트 파일로, 아스키독(AsciiDoc), 마크다운(Markdown), 또는 위키 페이지 템플릿 포맷으로 작성됩니다. + +### 19.3.1 기본구조 + +ADR(아키텍처 결정 레코드)의 기본 구조는 다음 5개 섹션으로 구성됩니다: **제목(Title), 상태(Status), 콘텍스트(Context), 결정(Decision), 결과(Consequences)**. +여기에 **컴플라이언스(Compliance), 노트(Notes)** 섹션을 추가할 수 있습니다. +필요에 따라 섹션을 확장하거나 대안 분석 결과를 기록하는 **대안(Alternatives)** 섹션을 추가할 수 있습니다. + +#### 제목 + +ADR의 제목은 일련 번호와 함께 아키텍처 결정을 간결한 문구로 표현합니다. +예를 들어, “42. 주문 서비스와 결제 서비스 간의 비동기 메시징 사용”과 같이 짧고 명료하게 작성합니다. + +#### 상태 + +ADR의 **상태(Status)**는 다음 세 가지로 표시됩니다: + +1. **제안됨(Proposed)**: 상위 의사 결정권자의 승인이 필요한 상태. + - 제안됨 상태의 ADR은 수락됨 상태가 될 때까지 계속 수정됩니다. +2. **수락됨(Accepted)**: 결정이 승인되어 구현 준비가 된 상태. +3. **대체됨(Superseded)**: 이전에 수락된 결정이 번복되어 다른 ADR에 의해 대체된 상태. + - 제안됨 상태의 ADR은 대체되지 않습니다. + +대체됨 상태는 어떤 결정이 내려졌고, 당시 왜 그런 결정을 했는지, 새로운 결정은 무엇이고, 왜 변경을 하게 됐는지 등에 관한 이력을 관리합니다. +어떤 ADR이 대체되면 그 ADR을 대체한 결정이 병기되며, 반대로 ADR을 대체한 결정에는 자신이 대체한 ADR이 병기됩니다. +이와 같이 기록하면 과거 결정의 변경 사유와 새로운 결정의 배경을 명확히 알 수 있어, 불필요한 혼란을 방지할 수 있습니다. + +``` +ADR 42. 주문 서비스와 결제 서비스 간의 비동기 메시징 사용 +상태: 68로 대체됨 + +ADR 68. 주문 서비스와 결제 서비스 간의 REST 사용 +상태: 수락됨, 42를 대체함 +``` + +ADR의 상태 섹션에는 아키텍처 결정이 승인되기 위한 기준과 절차를 명확히 하여, 상사나 다른 유관자들과 승인 절차를 논의하도록 돕습니다. +이를 위한 주요 주제는 비용, 전체 팀 영향도, 보안입니다. + +- **비용**: + - 소프트웨어 구매, 라이선스, 추가 하드웨어, 구현 공수 등이 포함됩니다. + - 공수의 경우 예상 소요 시간과 FTE(full-time equivalency)를 기준으로 계산하며, PO나 PM이 이를 파악하고 있습니다. + - 비용이 정해진 한도를 초과하면, ADR의 상태를 제안으로 설정하고 다른 승인자의 승인을 기다려야 합니다. +- **전체 팀 영향도 및 보안**: + - 아키텍처 결정이 다른 팀, 시스템, 보안에 영향을 미칠 경우, 상위 협의체의 승인이 필요합니다. + +예를 들어 **“1천만 원 초과 비용은 아키텍처 검토 위원회 승인 필요”**와 같은 지출 한도를 설정하고 이를 문서화하면, ADR 승인 기준이 명확해져서 아키텍트 스스로 승인 가능한 결정과 그렇지 않은 결정을 구별할 수 있습니다. + +#### 콘텍스트 + +ADR 콘텍스트 섹션은 결정의 배경이 되는 불가항력적인 요소를 설명하고, 다른 대안들에 대해서 논의하는 부분입니다. +각 대안에 대한 상세한 분석이 필요한 경우, 대안 분석 섹션을 추가해 세부 내용을 기록합니다. + +콘텍스트 섹션을 통해 아키텍처를 간결하고 효과적으로 문서화할 수 있으며, 특정 아키텍처 영역을 명확히 기술해야 합니다. +예를 들어 다음과 같이 시나리오와 대안을 포함해 아키텍처를 설명하는 간결한 문장으로 구성할 수 있습니다. + +``` +주문의 총 결제 금액을 주문 서비스가 처리하려면 결제 서비스에 정보를 전달해야 하며, 이는 REST 또는 비동기 메시징으로 수행할 수 있다. +``` + +#### 결정 + +결정 섹션에는 아키텍처 결정과 그 이유를 명확히 기술합니다. +결정에는 수동적 어조 대신 긍정적이고 단호한 어조로 작성해야 설득력이 높아지고, 의견 표현을 넘어 실제 결정으로 전달됩니다. + +- 비권장: “비동기 메시징이 최선의 선택이라고 생각합니다.” +- 권장: “서비스 간에는 비동기 메시징을 사용할 것입니다.” + +**결정 섹션의 강점**은 **'어떻게(How)'보다 '왜(Why)'**에 중점을 두는 데 있습니다. +작동 원리는 콘텍스트 다이어그램으로 추측할 수 있지만, 결정 이유는 그렇지 않습니다. +**결정 이유**와 **배경**을 명확히 알면, 문제의 맥락을 이해하고, 실수를 예방하기 위해 리팩터링을 하는 것도 사능합니다. + +구글은 과거 두 서비스 간 통신 수단으로 gRPC를 선택했지만, 이유를 명확히 기록하지 않아 문제가 발생했습니다. +시간이 지나 다른 아키텍트가 이 결정을 무시하고 메시징 방식으로 리팩터링을 진행했으나, 레이턴시 급증과 타임아웃 문제가 발생했습니다. +gRPC 선택 이유가 레이턴시 최소화였음을 알았다면, 불필요한 리팩터링을 피할 수 있었을 것입니다. + +#### 결과 + +결과(Consequences) 섹션은 **아키텍처 결정의 전체적인 영향도를 기술**하는 중요한 부분입니다. +이 섹션에서 결정의 장점과 단점을 구체적으로 기술하여, 아키텍처 결정이 어떤 영향을 미치는지를 다시 검토할 수 있습니다. +또한 비용이나 다른 아키텍처 특성과 관련된 트레이드오프 분석 결과를 문서화할 수도 있습니다. +예를 들어, 비동기 메시징 방식을 사용해 리뷰 게시 요청의 응답 시간을 크게 개선(3,100ms → 25ms)했다고 합시다. +비동기 요청은 복잡한 에러 처리 문제를 동반할 수 있지만, 응답성 향상과 비즈니스 가치를 고려한 결과임을 트레이드 오프 분석 결과로 명시할 수 있습니다. +이와 같이 트레이드오프와 결정 과정을 문서화하여, 잠재적인 이슈를 예방하고 아키텍처 전반의 맥락을 명확히 할 수 있습니다. + +#### 컴플라이언스 + +컴플라이언스 섹션은 표준은 아니지만 추가하기를 권장합니다. +이 섹션에는 **아키텍처 결정을 컴플라이언스 관점에서 어떻게 측정하고 관리할지** 작성합니다. +컴플라이언스 체크를 수동으로 할지 또는 피트니스 함수를 통해 자동화할지를 결정해야 하며, 자동화를 선택한다면 피트니스 함수 작성 방법과 코드베이스 변경이 필요한지를 기록해야 합니다. +수행할 테스트, 테스트의 위치, 그리고 테스트 실행 시기 및 방법을 함께 정의합니다. + +예를 들어, 전통적인 n-티어 아키텍처에서 공유 기능은 공유 서비스 레이어에 분리하여 구현하기로 결정했다고 가정합니다. +이 결정은 Java ArchUnit이나 .NET NetArchTest를 활용해 자동으로 측정 및 관리할 수 있습니다. +아래와 같이 피트니스 함수를 정의하고, @SharedService 애너테이션을 모든 공유 클래스에 적용하여 컴플라이언스 체크를 자동화할 수 있습니다. + +```java +@Test +public void shared_services_should_reside_in_services_layer() { + classes() + .that() + .areAnnotatedWith(SharedService.class) + .should() + .resideInAPackage("..services..") + .because("비즈니스 레이어에서 비즈니스 객체가 사용하는 " + + "모든 공유 객체는 공유 서비스 레이어에 두고 " + + "공유 기능을 분리하여 구현한다.") + .check(myClasses); +} +``` + +#### 노트 + +다양한 메타데이터(원저자, 승인일, 승인자, 대체일, 최종 수정일, 수정자, 최종 수정 내역)로 구성된 노트 섹션을 추가하는 것이 권장됩니다. +ADR을 버전 관리 시스템에 저장할 때, 해당 시스템에 저장되지 않는 부가적인 메타 정보를 이곳에서 보완할 수 있습니다. + +### 19.3.2 ADR 저장 + +아키텍처 결정들은 개별 파일이나 위키 페이지 형태로 관리되어야 합니다. +많은 아키텍트들이 ADR을 Git 리포지터리에 저장하지만, 대규모 조직에서는 다음과 같은 문제를 고려해야 합니다: + +1. 일부 사용자는 Git 리포지터리에 접근할 수 없습니다. +2. 통합 아키텍처나 공통 결정과 같이, Git 리포지터리 외부의 콘텍스트를 포함한 ADR을 Git에 저장하는 것이 적절하지 않습니다. + +따라서, 위키 또는 문서 렌더링 소프트웨어와 같이 쉽게 접근할 수 있는 공유 파일 서버에 저장하는 것이 좋습니다. + +디렉터리 구조는 다음과 같이 구성할 수 있습니다.: + +1. application: 애플리케이션 콘텍스트의 아키텍처 결정을 포함하며, 다음의 서브디렉터리를 포함합니다. + - common: 모든 애플리케이션에 공통적으로 적용되는 결정 (예: 특정 애너테이션 사용 규칙). + - 특정 애플리케이션 디렉터리 (예: atp, pstd): 특정 애플리케이션에만 적용되는 아키텍처 결정 +2. integration: 애플리케이션, 시스템, 서비스 간 통신과 관련된 아키텍처 결정 +3. enterprise: 전사적으로 영향을 미치는 아키텍처 결정 + - ex) 모든 데이터베이스 액세스는 데이터베이스를 소유한 시스템만 가능하다. + + + +ADR을 위키에 저장하면, 디렉터리 구조가 그대로 네비게이션 랜딩 페이지로 활용됩니다. +각 디렉터리(application, integration, enterprise)는 하나의 랜딩 페이지가 되고, ADR은 개별 위키 페이지로 표시됩니다. + +### 19.3.3 ADR로 문서화 + +ADR은 소프트웨어 아키텍처를 효과적으로 문서화하는 도구입니다. +콘텍스트 섹션은 아키텍처 결정이 필요한 시스템의 영역과 결정의 대안을 기술하며, 결정 섹션은 결정 이유를 명확히 설명합니다. +또한, 결과 섹션에서는 확장성과 성능 간 트레이드오프 같은 추가적인 배경을 기술합니다. +이러한 정보들이 모여 아키텍처 문서화의 완성도를 높입니다. + +### 19.3.4 ADR로 표준화 + +ADR 표준화는 일하는 방식을 통제하지 않는 선에서 표준을 제시할 수 있습니다. +콘텍스트 섹션은 표준을 강제해야 하는 상황을 설명하고, 결정 섹션은 해당 표준을 우선시해야 하는 이유를 명확히 기술해 개발자가 이를 납득하고 따르게 합니다. +또한, 결과 섹션은 표준의 타당성과 결과를 스스로 검증할 수 있게 하여, 필요시 표준을 재고하거나 변경할 수 있게 합니다. + +### 19.3.5 예시 + +경매 시스템 구축 예제에서는, 해당 시스템에서 필요로 하는 다양한 아키텍처 결정이 언급됩니다. +주요 결정에는 이벤트 기반 마이크로서비스 사용, 입찰자와 경매인 UI 분리, 실시간 전송 프로토콜(RTP) 활용, 단일 레이어 구조, 메시지 발행/구독 방식 채택 등이 포함됩니다. +이와 같은 각 결정들의 이유은 명확히 문서화 되어야 합니다. + +다음은 BidCapture, Bidstreamer, BidTracker 서비스 간의 메시지 발행/구독 시스템에 대한 결정 사례입니다. + + + +``` +ADR 76. 입찰 서비스 간 펍/섭 메시징 + +콘텍스트 + +BidCapture 서비스는 온라인 입찰차 또는 경매인을 통한 라이브 입찰자로부터 입찰을 받아 BidStreamer 서비스, BidTracker 서비스에 전달해야 한다. +입찰은 비동기 점대점(p2p), 비동기 pub/sub, 온라인 경매 API를 통한 REST 방식으로 전달할 수 있다. + +결정 + +BidCapture, Bidstreamer, BidTracker 세 서비스는 비동기 펍/섭 메시지를 주고받기로 결정할 예정이다. BidStreamer 서비스는 BidCapture 서비스가 받은 순서 그대로 입찰을 수신해야 한다. +메시징과 큐는 스트림의 입찰 순서를 자동으로 보장한다. +비동기 펍/섭 메시징을 사용하면 입찰 프로세스의 성능이 개선되고 입찰 정보를 확장할 수 있다. + +결과 + +메시징 큐의 고가용성이 필요하고 클러스터 구성을 해야 할 것이다. +내부 입찰 이벤트는 API 레이어에서 수행되는 보안 체크를 우회할 것이다. +업데이트: 2020년 4월 14일 ARB 회의에서 검토한 결과, ARB는 위와 같은 트레이드오프를 수용하기로 판단했으며, 세 서비스 간 입찰 이벤트에 추가적으로 보안 체크는 필요하지 않다고 결론지었다. + +컴플라이언스 + +주기적으로 수동 코드 검사 및 설계 리뷰를 실시하여 BidCapture, BidStreamer, BidTracker 세 서비스 간에 비동기 펍/섭 메시징이 제대로 이뤄지고 있는지 확인할 예정이다. +``` diff --git "a/ch19_\354\225\204\355\202\244\355\205\215\354\262\230_\352\262\260\354\240\225/ch19_eden/19-3.png" "b/ch19_\354\225\204\355\202\244\355\205\215\354\262\230_\352\262\260\354\240\225/ch19_eden/19-3.png" new file mode 100644 index 0000000..dcb5a9d Binary files /dev/null and "b/ch19_\354\225\204\355\202\244\355\205\215\354\262\230_\352\262\260\354\240\225/ch19_eden/19-3.png" differ diff --git "a/ch19_\354\225\204\355\202\244\355\205\215\354\262\230_\352\262\260\354\240\225/ch19_eden/19-4.png" "b/ch19_\354\225\204\355\202\244\355\205\215\354\262\230_\352\262\260\354\240\225/ch19_eden/19-4.png" new file mode 100644 index 0000000..c68b029 Binary files /dev/null and "b/ch19_\354\225\204\355\202\244\355\205\215\354\262\230_\352\262\260\354\240\225/ch19_eden/19-4.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden.md" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden.md" new file mode 100644 index 0000000..5e3e1e1 --- /dev/null +++ "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden.md" @@ -0,0 +1,271 @@ +# 아키텍처 리스크 분석 + +아키텍처는 항상 리스크를 내포하며, 리스크 분석을 통해 내부 결함을 파악하고 리스크를 줄이는 작업이 필요합니다. +본 장에서는 리스크 스토밍(Risk Storming)을 활용하여 리스크를 도출, 평가, 식별하는 방법과 프랙티스를 다룹니다. + +## 20.1 리스크 매트릭스 + +아키텍처 리스크 평가 시, 리스크를 낮음/중간/높음으로 분류해야 하는데, 이 과정은 주관적일 수 있습니다. +이 때 리스크 매트릭스를 활용하면, 주관성을 줄이고 특정 아키텍처 영역에서 리스크를 효과적으로 찾아낼 수 있습니다. + +아키텍처 리스크 매트릭스는 **리스크 영향도**와 **발생 가능성**의 두 차원을 기반으로 리스크를 평가하며, 낮음(1), 중간(2), 높음(3) 등급으로 분류됩니다. +**각 등급의 숫자를 곱해 리스크를 정량화**하며, 1-2는 낮은 리스크(밝은 회색), 3-4는 중간 리스크(중간 회색), 6-9는 높은 리스크(짙은 회색)로 표시됩니다. + + + +## 20.2 리스크 평가 + +리스크 평가는 전체 아키텍처의 리스크를 리스크 매트릭스를 기반으로 유의미한 평가 기준에 따라 정리한 리포트입니다. +리스크 평가는 애플리케이션의 서비스나 도메인 영역에 기반한 평가 기준을 포함합니다. + + + +리스크 매트릭스를 활용하면 평가 기준별로, 서비스 또는 도메인 영역별로 누적 리스크를 계산할 수 있습니다. +위 예제에서는 데이터 무결성의 누적 리스크는 17점으로 가장 높고, 가용성은 10점으로 가장 낮습니다. +도메인 영역에서는 고객 등록이 24점으로 가장 높은 리스크를 가지며, 주문 이행은 8점으로 가장 낮습니다. +이와 같이 각 영역별 수치를 상대적으로 비교하여, 특정 리스크 범주나 도메인 영역에서의 리스크가 개선 또는 악화 되었는지를 알 수 있습니다. + +위 예제에서는 모든 리스크 분석 결과를 담았지만, 효과적인 메시지 전달을 위해서는 일부 결과로 필터링하는게 좋습니다. +예를 들어, 리스크가 높은 시스템 영역만 발표하면 다음처럼 SNR(신호대잡음비, signal-to-noise-ratio)이 개선되어 시스템 상태가 명확하게 드러납니다. + + + +지금까지 살펴본 리스크 평가는 특정 시점의 리스크 상태를 보여주는 스냅샷의 일종으로, 리스크의 방향성을 알려주지는 않습니다. +리스크 방향성을 표시할 때는 플러스(+), 마이너스(-) 기호를 사용하면 좋습니다. +예를 들어, 다음 예제에서는 고객 등록의 성능은 리스크 등급이 중간(4)이나, 마이너스 부호로 점점 상황이 악화되고 있음을 나타냅니다. +반면, 카탈로그 체크아웃의 확장성은 등급이 높고(6) 플러스 부호로 개선 중임을 보여줍니다. +부호가 없으면 리스크가 안정적이고, 개선 또는 악화되지 않았다는 뜻입니다. + + + +다만 플러스/마이너스 부호가 헷갈리는 경우를 대비해, 리스크 등급 번호와 화살표를 함께 표기할 수도 있습니다. +다음과 같이 화살표로 방향을 명확히 표시하면 따로 범례가 필요 없으며, 화살표에 색깔(빨간색: 악화, 초록색: 개선)을 추가하면 리스크의 방향성을 더욱 직관적으로 전달할 수 있습니다. + + + +## 20.3 리스크 스토밍 + +리스크 스토밍은 여러 관계자가 모여 특정 범위 내 아키텍처 리스크를 찾아내는 협력적인 활동입니다. +일반적인 리스크 영역에는 **검증되지 않은 기술, 성능, 확장성, 가용성, 데이터 소실, 단일 장애 지점, 보안** 등이 포함됩니다. +이 활동에는 아키텍트뿐 아니라 개발자, 기술 책임자가 함께 참여하면, 구현 관점에서도 리스크를 검토할 수 있습니다. + +리스크 스토밍은 개별 파트와 협력 파트로 이루어지며, 두 활동이 함께 진행되어야 효과적인 리스크 스토밍이 가능합니다. + +- **개별 파트**: + - 참가자들이 독립적으로 리스크 매트릭스를 활용해 각자 아키텍처 영역에 리스크를 할당합니다. + - 다른 사람의 영향 없이 집중할 수 있습니다. +- **협력 파트**: + - 모든 참가자가 모여 리스크 영역에 대한 공감을 형성하고, 리스크를 줄이기 위한 방안을 논의합니다. + +리스크 스토밍에서는 아키텍처 다이어그램을 사용합니다. +전체 리스크 평가에는 종합적인 아키텍처 다이어그램을 활용하고, 특정 영역에 대한 평가에는 해당 영역의 아키텍처 다이어그램을 활용합니다. +리스크 스토밍을 주관하는 아키텍트는 다이어그램을 최신 상태로 유지하며, 모든 참가자들이 이를 확인할 수 있도록 관리해야 합니다. + +다음의 다이어그램은 AWS ELB가 웹 서버(Nginx)와 연결되고, 최종적으로 각 EC2 인스턴스에서 실행되는 애플리케이션 서비스에 요청을 전달합니다. +애플리케이션 서비스는 MySQL, 레디스 캐시, 몽고DB를 호출하여 로깅 작업을 수행하며, 푸시 확장 서버도 호출됩니다. +푸시 확장 서버는 다시 MySQL, 레디스 캐시, 몽고DB의 로깅 기능과 연계됩니다. + + + +리스크 스토밍은 다음의 세 가지 활동으로 구성됩니다. +식별은 개별적으로, 합의와 완화는 협력적으로 진행됩니다. + +1. 식별(Identification): 개별적이고 비협력적으로 진행되며, 각자가 리스크를 파악합니다. +2. 합의(Consensus): 모든 참가자가 모여 협력적으로 리스크에 대한 공감대를 형성합니다. +3. 완화(Mitigation): 협력적으로 리스크를 줄이기 위한 방안을 논의하고 실행합니다. + +### 20.3.1 식별 + +식별 활동은 참여자가 개별적으로 아키텍처 내 리스크 영역을 파악하는 과정으로, 다음 단계를 거칩니다: + +1. **초대장 발송**: 리스크 스토밍을 주관하는 아키텍트가 참가자들에게 초대장을 보내며, 초대장에는 아키텍처 다이어그램, 분석 대상 리스크 영역, 협력 파트 일정 및 장소가 포함됩니다. +2. **리스크 분석**: 참가자는 리스크 매트릭스를 활용해 아키텍처를 분석하고, 리스크를 낮음(1-2), 중간(3-4), 높음(6-9)으로 분류합니다. +3. **포스트잇 작성**: 리스크 매트릭스에서 식별한 리스크 번호를 색상별 포스트잇(초록: 낮음, 노랑: 중간, 빨강: 높음)에 기재합니다. + +리스크 스토밍은 보통 한 가지 부문(예: 성능)만 분석하지만, 필요에 따라 여러 부문(예: 성능, 확장성, 데이터 소실)을 동시에 분석할 수도 있습니다. +예를 들어, 세 참가자가 중앙 데이터베이스에서 리스크 높음(6)을 식별했더라도, 한 명은 가용성 리스크, 나머지 두 명은 성능 리스크를 발견할 수 있습니다. +이 경우, 참가자들은 포스트잇에 리스크 번호와 함께 부문명을 병기하여 구분하고, 각 부문을 별도로 논의해야 합니다. + +### 20.3.2 합의 + +합의 활동은 참가자들이 아키텍처 내 리스크에 대해 공감대를 형성하는 협력적인 과정입니다. +아키텍처 다이어그램을 대형 스크린에 표시한 상태에서, 참가자들은 각자가 발견한 리스크를 다이어그램에 배치합니다. +이를 통해 리스크 영역에 대한 시각적 합의가 이루어집니다. + + + +리스크 배치가 끝나면 협력 파트가 시작됩니다. +이 과정의 목표는 참가자들이 한 팀이 되어 리스크 영역을 분석하고, 해당 영역이 실제 리스크인지 합의하는 것입니다. +위 예제에서는 다양한 아키텍처 리스크 영역이 식별되었습니다. + +1. 일래스틱 로드 밸런서: + - 리스크 중간(3): 2명 + - 리스크 높음(6): 1명 +2. 푸시 확장 서버: + - 리스크 높음(9): 1명 +3. MySQL 데이터베이스: + - 리스크 중간(3): 3명 +4. 레디스 캐시: + - 리스크 높음(9): 1명 +5. 몽고DB 로깅: + - 리스크 낮음(2): 3명 +6. 기타 아키텍처 영역: + - 리스크 없음 + +3번(MySQL 데이터베이스)과 5번(몽고DB 로깅)은 세 참가자가 모두 리스크 레벨과 당위성에 동의했으므로 추가 논의가 필요 없습니다. +반면, 1번(일래스틱 로드 밸런서)은 의견 차이가 있어 논의가 필요하며, 2번(푸시 확장 서버)과 4번(레디스 캐시)은 한 명만 리스크로 식별했으므로 합의를 통해 검토해야 합니다. + +1번 일래스틱 로드 밸런서의 리스크에 대해, 두 참가자는 리스크 중간(3)으로, 한 참가자는 리스크 높음(6)으로 식별했습니다. +리스크 높음으로 평가한 참가자는 **장애 발생 시 전체 시스템에 영향을 미친다**고 설명했으며, 이는 사실로 인정되었습니다. +그러나 다른 두 참가자는 **그런 상황이 거의 발생하지 않을 것**이라 주장했고, **논의 끝에 세 번째 참가자는 리스크 레벨을 중간(3)으로 낮추기로 동의**했습니다. + +2번 푸시 확장 서버에 대해, 한 참가자는 리스크 높음(9)으로 식별했으나, 다른 두 참가자는 리스크가 없다고 보았습니다. +리스크를 식별한 참가자는 **과거 부하가 큰 상황에서 푸시 확장 서버가 지속적으로 다운되는 문제를 목격한 경험**을 공유했습니다. +이러한 논의를 통해 다른 참가자들도 미처 알지 못했던 리스크를 파악하게 되었으며, 이는 리스크 스토밍의 핵심 가치인 **협력과 정보 공유**의 중요성을 보여줍니다. + +4번 레디스 캐시에 대해서 한 참가자는 리스크 높음(9)으로 식별했지만, 다른 두 참가자는 리스크가 없다고 판단했습니다. +이유를 묻자, **해당 참가자는 레디스 캐시가 무엇인지 모른다**고 답했습니다. +리스크 스토밍에서 검증되지 않았거나 알려지지 않은 기술은 가장 높은 리스크 등급(9)을 매기게 됩니다. +개발자가 리스크 스토밍에 참여하면 아키텍처에 대한 이해를 높이고, 아키텍트는 팀원의 기술적 공백이 리스크 요인임을 인지할 수 있습니다. + +합의 활동은 모든 참가자가 식별된 리스크 영역에 의견을 함께 할 때까지 반복됩니다. +다음과 같이 최종 결과가 도출되면 다음 활동으로 넘어갑니다. + + + +### 20.3.3 완화 + +참가자들은 합의 과정에서 식별된 리스크를 줄이거나 제거하는 방법을 모색하며, 필요에 따라 아키텍처의 일부 영역을 개선하거나 변경합니다. +필요에 따라 아키텍처 전반을 변경해야 할 수도 있지만, 간단한 리팩터링(예: 배압 큐 추가)으로 해결 가능할 수도 있습니다. +이 때 아키텍처 변경이 비용 대비 가치가 있는지 판단하게 되고, 필요하다면 비즈니스 이해관계자들을 설득해야 합니다. +예를 들어, 리스크 스토밍을 통해 가용성 측면에서 중앙 데이터베이스의 리스크가 중간(4)으로 식별됐다고 합시다. +중앙 데이터베이스의 리스크를 줄이기 위해 클러스터링 및 물리적 분리를 제안했으나, $20,000의 비용이 부담되어 거절될 수 있습니다. +이에 대해 클러스터링은 포기하고 데이터베이스를 두 파트로 분리만 하는 방안으로 합의하여, $8,000의 비용으로 리스크를 완화하게 됩니다. +리스크 스토밍 기법을 사용해서 리스크를 잘 정리해두면 이해관계자 간 협상에 효과적으로 사용할 수 있습니다. + +## 20.4 애자일 스토리 리스크 분석 + +리스크 스토밍은 아키텍처뿐만 아니라 소프트웨어 개발 전반에도 활용 가능합니다. +예를 들어, 애자일 이터레이션에서 유저 스토리를 완료하는데 존재하는 리스크를 평가할 수 있습니다. +리스크 매트릭스를 활용해 이터레이션에서 스토리가 완료되지 않았을 때의 영향도와 스토리가 완료되지 않을 가능성을 분석하고, 리스크가 높은 스토리를 우선 추적 및 처리할 수 있습니다. + +## 20.5 리스크 스토밍 예시 + +환자들의 건강 상태에 대해 간호사가 조언을 해주는 콜 센터 시스템의 요구사항이 다음과 같다고 합시다. + +1. **진단 엔진 사용** + - 질문을 받으면 간호사나 환자에게 의료 문제를 안내하는 서드파티 진단 엔진을 사용한다. +2. **서비스 방식** + - 환자는 콜 센터에 전화를 걸어 간호사와 통화하거나, 셀프 서비스 웹사이트를 통해 진단 엔진에 직접 액세스할 수 있다. +3. **동시 지원 규모** + - 전국적으로 250명의 간호사와 수십만 명의 셀프 서비스 환자를 동시에 지원해야 한다. +4. **의무 기록 열람** + - 간호사는 환자의 의무 기록을 열람할 수 있지만, 환자는 자신의 의무 기록을 볼 수 없다. +5. **법률 준수** + - **미국 의료 정보 이동 및 책임법**(HIPAA)에 따라, 의무 기록은 간호사 외의 누구도 의무 기록을 열람할 수 없어야 한다. +6. **데이터 요청 처리** + - 전염병과 독감 유행 시즌에 데이터 요청이 급증해도, 시스템이 이를 감당할 수 있어야 한다. +7. **간호사 연결** + - 간호사 프로필(예: 외국어 가능)에 따라 통화가 연결되어야 한다. +8. **진단 엔진 성능** + - 서드파티 진단 엔진은 초당 약 500개의 요청을 처리할 수 있어야 한다. + +해당 서비스에 대해서 다음과 같이 아키텍처를 구성할 수 있습니다. + + + +먼저 아키텍처에는 총 3개의 웹 기반 유저 인터페이스가 존재합니다. + +- 셀프 서비스 인터페이스: 환자용. +- 간호사 인터페이스: 전화를 받는 간호사용. +- 관리 인터페이스: 간호사 프로필과 시스템 설정값을 관리. + +콜 센터는 크게 두 부분으로 구성됩니다. + +- 통화 접수기: 걸려온 전화를 받음. +- 통화 라우터: 중앙 데이터베이스에서 간호사 프로필을 조회 후, 적절한 간호사에게 통화 연결. + +진단 시스템 API 게이트웨이는 이 아키텍처의 핵심으로, 요청을 보안 체크한 후 적절한 백엔드 서비스로 전달합니다. +전체 시스템은 **사례 관리, 간호사 프로필 관리, 의무 기록 인터페이스, 외부 진단 엔진** 4개 주요 서비스로 구성되며, 외부 시스템 및 콜센터 연결용 전용 프로토콜을 제외한 모든 통신은 REST를 사용합니다. + +아키텍트는 리스크 평가를 위해 요구사항과 다이어그램을 재검토하여, 가용성, 탄력성, 보안 측면에서 리스크 수준을 파악하려 합니다. +리스크를 확인한 후 이를 줄이기 위한 아키텍처 개선 방안을 고민할 계획입니다. + +### 20.5.1 가용성 + +아키텍트는 1차 리스크 스토밍 세션에서 시스템 성공을 위해 가용성을 최우선으로 검토했습니다. +참가자들은 협력을 통해 리스크 매트릭스를 작성하고, 가용성과 관련된 주요 리스크 영역을 도출했습니다. + +- 중앙 데이터베이스: + - 영향도: 높음 (3) + - 가능성: 중간 (2) + - 리스크 수준: 높음 (6) +- 진단 엔진 7 요소: + - 영향도: 높음 (3) + - 가능성: 알 수 없음 (2) + - 리스크 수준: 높음 (9) +- 의무 기록 가용성: + - 시스템 실행에 필수 컴포넌트가 아님 + - 리스크 수준: 낮음 (2) +- 기타 시스템 파트 + - 각 서비스 : 여러 인스턴스로 구성 + - API 게이트웨이: 클러스터링 처리 + - 가용성 측면에서 리스크 없음 + + + +참가자들은 데이터베이스가 다운되면 간호사는 수기로 사례 기록을 작성할 수 있지만, 통화 라우터는 작동하지 않을 것이라는 점에 동의했습니다. +이를 완화하기 위해 **데이터베이스를 두 개로 분리**하기로 했습니다: 간호사 프로필 정보용 클러스터형 데이터베이스, 사례 기록용 단일 인스턴스 데이터베이스. +이 변경으로 **데이터베이스 가용성 우려가 해소되고, 사례 기록은 관리자만 볼 수 있어 보안도 강화**되었습니다. +통화 라우터에 캐시를 도입하는 방법도 고려했으나, 통화 라우터의 구현 코드가 서드파티 제품일 가능성이 높으므로, 데이터베이스 액세스 방식을 채택했습니다. + +외부 시스템(진단 엔진, 의무 기록 시스템)은 제어가 어려워 가용성 관리에 리스크가 큽니다. +이를 완화하기 위해 각 시스템의 SLA(서비스 수준 계약)나 SLO(서비스 수준 목표)를 확인하는 것이 권장됩니다. +진단 엔진은 SLA로 99.99% 가용성(연간 다운타임 52.60분)을, 의무 기록 시스템은 99.9% 가용성(연간 다운타임 8.77시간)을 보장하며, 이는 상대적으로 리스크가 낮은 수준으로 평가됩니다. + +이후 변경된 아키텍처 다이어그램에서는 데이터베이스를 두 개로 분리하고, SLA를 다이어그램에 명시해 리스크를 줄였습니다. + + + +### 20.5.2 탄력성 + +2차 리스크 스토밍에서는 탄력성, 특히 **사용자 부하 급증에 따른 가변 확장성**을 논의했습니다. +독감 시즌에 **셀프 서비스 파트를 통해 진단 엔진에 많은 액세스가 몰려서, 진단 인터페이스의 부하가 크게 증가**할 가능성이 제기되었습니다. +참가자들은 **진단 엔진 인터페이스를 리스크 높음(9)으로 만장일치로 식별**했습니다. +초당 500개 요청 처리 능력으로는 예상되는 부하를 감당하기 어렵다고 판단했으며, REST 프로토콜을 사용하는 경우 문제가 더욱 심각해질 것으로 보았습니다. + +참가자들은 다음과 같은 방안을 검토했습니다. + +- **API 게이트웨이와 진단 엔진 인터페이스 사이에 비동기 큐 배치**: 둘 사이의 호출을 완충하는 것이 가능하지만, 대기 시간 증가와 타임아웃 가능성이 있습니다. +- **앰뷸런스 패턴을 적용하여, 셀프 서비스보다 간호사 요청에 더 높은 우선순위를 부여**: 메시지 채널 2개를 필요로 하고, 대기 시간 문제는 여전히 해결되지 않습니다. +- **발병 관련 진단 질문을 캐시**: 진단 엔진 인터페이스에 도달하는 호출을 줄일 수 있어서, 리스크를 효과적으로 완화할 수 있습니다. + +논의 결과, 새로운 아키텍처에서는 **간호사용과 셀프 서비스 환자용으로 나뉜 2개의 큐 채널**이 도입되고, **특정 질병 및 독감 관련 요청을 처리하는 질병 진단 캐시 서버**가 새로 도입되었습니다. +이 구조는 진단 엔진 호출의 병목을 제거하여, 수만 개의 요청을 동시에 처리할 수 있습니다. + + + +### 20.5.3 보안 + +아키텍트는 시스템의 또 다른 중요한 특성인 보안을 논의하기 위해 최종 세션을 열기로 했습니다. +특히, HIPAA 규제 요구사항에 따라 **의무 기록은 간호사만 열람 가능하도록 안전하게 관리**해야 합니다. +이 요구사항은 API 게이트웨이의 인증 및 인가 문제로 한정되지 않을 수 있습니다. + +진단 시스템 API 게이트웨이의 보안에 대한 리스크 스토밍 결과, 관리 직원이나 셀프 서비스 환자가 의무 기록을 열람할 리스크가 다음과 같이 평가되었습니다. + +- 진단 시스템 API 게이트웨이: + - 가능성: 중간(2) + - 영향도: 높음(3) + - 리스크 수준: 높음(6) + +각 API 호출에 대해 보안 체크가 이루어지긴 하지만, 모든 요청이 동일한 API 게이트웨이를 통과하기 때문에 가능성이 중간으로 판단되었습니다. +참가자들은 API 게이트웨이를 사용자 유형 별로 관리자, 셀프 서비스/진단, 간호사용으로 분리하면, 관리자 또는 셀프 서비스 웹 인터페이스의 호출이 의무 기록 시스템에 접근하는 것을 막을 수 있다고 의견을 모았습니다. +아키텍트는 이를 반영한 최종 아키텍처를 완성했습니다. + + + +리스크 스토밍을 통해 가용성, 탄력성, 보안 문제를 해결하는 데 있어 의미 있는 진전이 이루어졌습니다. +잘 보이지 않는 리스크 영역을 다른 아키텍트, 개발자, 주요 이해관계자들과 협력하여 효과적으로 식별할 수 있었습니다. + +리스크 스토밍은 시스템이 운영되는 동안 지속적으로 반복해야 합니다. +리스크 스토밍의 빈도는 변경 주기, 아키텍처 리팩터링, 점진적 개발 등 다양한 요인에 따라 달라지며, 일반적으로 주요 기능 추가 후, 또는 매 이터레이션 종료 시수행할 수 있습니다. diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-1.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-1.png" new file mode 100644 index 0000000..9002be1 Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-1.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-10.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-10.png" new file mode 100644 index 0000000..5571013 Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-10.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-11.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-11.png" new file mode 100644 index 0000000..f85accf Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-11.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-12.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-12.png" new file mode 100644 index 0000000..b624058 Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-12.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-13.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-13.png" new file mode 100644 index 0000000..a71e652 Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-13.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-2.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-2.png" new file mode 100644 index 0000000..fb7d264 Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-2.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-3.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-3.png" new file mode 100644 index 0000000..1858c15 Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-3.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-4.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-4.png" new file mode 100644 index 0000000..0d1d94f Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-4.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-5.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-5.png" new file mode 100644 index 0000000..b1cd129 Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-5.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-6.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-6.png" new file mode 100644 index 0000000..d68104c Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-6.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-7.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-7.png" new file mode 100644 index 0000000..2738e4b Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-7.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-8.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-8.png" new file mode 100644 index 0000000..e3fbdc9 Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-8.png" differ diff --git "a/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-9.png" "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-9.png" new file mode 100644 index 0000000..736a455 Binary files /dev/null and "b/ch20_\354\225\204\355\202\244\355\205\215\354\262\230_\353\246\254\354\212\244\355\201\254_\353\266\204\354\204\235/ch20_eden/20-9.png" differ diff --git "a/ch21_\354\225\204\355\202\244\355\205\215\354\262\230_\353\217\204\354\213\235\355\231\224_\353\260\217_\355\224\204\353\240\210\354\240\240\355\205\214\354\235\264\354\205\230/ch21_eden.md" "b/ch21_\354\225\204\355\202\244\355\205\215\354\262\230_\353\217\204\354\213\235\355\231\224_\353\260\217_\355\224\204\353\240\210\354\240\240\355\205\214\354\235\264\354\205\230/ch21_eden.md" new file mode 100644 index 0000000..3c51935 --- /dev/null +++ "b/ch21_\354\225\204\355\202\244\355\205\215\354\262\230_\353\217\204\354\213\235\355\231\224_\353\260\217_\355\224\204\353\240\210\354\240\240\355\205\214\354\235\264\354\205\230/ch21_eden.md" @@ -0,0 +1,139 @@ +# 아키텍처 도식화 및 프레젠테이션 + +아키텍트로서 성공하려면 효과적인 의사 소통이 중요하며, 아키텍처 도식화와 프레젠테이션은 이를 위한 핵심 소프트 스킬입니다. +이 두 스킬은 서로 다른 매체를 사용하지만, 아키텍처 비전의 중요한 부분을 시각적으로 표현한다는 공통점을 가집니다. + +아키텍처를 시각적으로 기술할 때는 **전체 아키텍처의 관점에서 시작하여, 개별 파트를 상세히 설명**해야 합니다. +각 파트가 전체 아키텍처에서 어떤 위치에 있는지 명확히 알려주지 않으면 청중이 혼란스러울 수 있습니다. +**표현 일관성**이란 다이어그램이나 프레젠테이션에서 **특정 파트에 대한 뷰를 보여주기 전에, 전체 아키텍처에서 파트 간의 관계를 설명**하는 것을 의미합니다. +표현 일관성을 잘 지키면, 청중이 현재 표시된 내용의 범위를 쉽게 이해하고 혼동하지 않을 수 있습니다. +예를 들어, 실리콘 샌드위치 카타에서 플러그인의 상호 연관성을 자세히 설명하려고 할 때, **전체 토폴로지를 표시한 뒤, 플러그인 구조를 하나씩 살펴보면서 이들 간의 관계를 설명**할 수 있습니다. + + + +## 21.1 도식화 + +아키텍처 토폴로지를 통해 아키텍트와 개발자 간 공통 이해를 형성할 수 있기 때문에, 다이어그램을 작성하는 것은 아키텍트의 중요한 기술입니다. + +### 21.1.1 도구 + +아키텍트는 강력한 다이어그램 도구를 선택하여 학습하는 것이 중요합니다. +다만 설계 초기에는 정확도가 낮은 아티팩트부터 시작하는 것이 좋습니다. +초반부터 다이어그램 작성에 많은 시간을 투자할수록, 그 결과물에 집착하게 됩니다. +가능한 절차를 간소화하고. 적시에 아티팩트를 제작하는 것이 더 중요합니다. + +일반적으로는 화이트보드 보다 **태블릿과 프로젝터**가 더 선호됩니다. +태블릿은 제한 없는 캔버스를 제공하여, 팀 작업에 필요한 그림을 자유롭게 추가할 수 있습니다. +또한 다양한 시나리오를 복사 붙여넣기 하면서 실험할 수 있으며, 결과물을 깔끔하게 캡처할 수 있습니다. + +다이어그램 도구는 다양한 플랫폼에서 제공되며, 다음과 같은 필수 기능을 갖추고 있는지 확인하는 것이 중요합니다. + +- **레이어**: + - 항목을 논리적으로 나누고, 숨김/표시를 조정하여 세부 정보를 간단히 관리할 수 있습니다. + - 프레젠테이션 준비 시, 단계별로 그림을 그려서 시각적 자료로 사용 할 수 있습니다. +- **스텐실/템플릿**: + - 스텐실(stencil)은 자주 사용되는 시각적 컴포넌트를 조합하여 라이브러리화할 수 있는 도구입니다. + - 공통적인 패턴이나 아티팩트를 스텐실로 구축하면, 조직 내 아키텍처 다이어그램을 일관되게 작성하고 빠르게 생성할 수 있습니다. +- **마그넷** + - 마그넷은 도형 간 선을 쉽게 연결하도록 돕는 기능으로, 자동 정렬과 시각적 효과를 지원합니다. + - 일부 도구는 마그넷 추가 및 커스터마이징을 통해, 더욱 유연하게 도형을 연결할 수 있습니다. + +다이어그램 도구는 이러한 보조 기능 외에도, 선, 색상, 그 밖의 시각적인 아티팩트를 지원해야 하며, 다양한 포맷으로 내보내기도 가능해야 합니다. + +### 21.1.2 도식화 표준: UML, C4, ArchiMate + +#### UML + +통합 모델링 언어(UML)는 한때 널리 사용되었으나, 현재는 UML 클래스와 시퀀스 다이어그램을 제외한 다른 UML 다이어그램은 거의 쓰이지 않습니다. + +#### C4 + +C4는 UML을 현대적인 방식으로 개선한 다이어그램 기법입니다. +C4에서 ‘C’ 4개는 다음을 의미합니다. + +- **Context**: 유저 역할, 외부 의존성 등 시스템의 전체 컨텍스트 +- **Container**: 아키텍처 내부의 물리적 배포 경계로, 운영자와 아키텍트의 공통 관심사 +- **Component**: 시스템의 컴포넌트 뷰. +- **Class**: UML과 동일한 스타일의 클래스 다이어그램을 사용 + +C4 모델은 전사적 수준에서 도식화 표준으로 적합하지만, 모든 설계 요구를 충족하기에는 한계가 있습니다. +모놀리식 아키텍처에는 적합할 수 있지만, 마이크로서비스 같은 분산 아키텍처에는 적합하지 않습니다. + +#### 아키메이트 + +**비즈니스 도메인 중심으로 아키텍처를 기술, 분석, 시각화**하는 오픈 소스 엔터프라이즈 아키텍처 모델링 언어입니다. +경량 모델링 언어를 제공하며, 단순함을 강점으로 가집니다. + +### 21.1.3 도식화 지침 + +다음은 기술 다이어그램 작성 시 참고할 수 있는 일반적인 가이드라인 입니다. + +- **제목** + - 청중이 쉽게 이해할 수 있도록 **다이어그램의 모든 요소에 제목**을 붙입니다. + - **제목은 관련 항목에 고정**하고, 회전이나 이펙트를 활용하여 공간을 효율적으로 사용합니다. +- **선** + - 선은 적절히 굵게 하여 가독성을 높입니다. + - **정보의 흐름을 나타낼 때는 화살표**로 트래픽 방향을 표시합니다. + - **화살표 머리의 모양은 종류별로 의미가 다를 수 있으므로 일관성 있게 사용**해야 합니다. + - **동기 통신은 실선, 비동기 통신은 점선**으로 나타냅니다. +- **셰이프** + - 소프트웨어 업계 전체에서 통용되는 표준 셰이프는 없기 때문에, 아키텍트는 자신의 표준 셰이프 세트를 만들어 필요시 조직 전체에 전파하여 사용하도록 합니다. + - 일반적으로 배포 가능한 아티팩트는 3차원 상자로, 컨테이너는 직사각형으로 표현합니다. +- **레이블** + - 다이어그램의 각 항목에 레이블을 붙입니다. + - 청중이 모호하게 느낄 수 있는 항목에는 반드시 레이블을 추가합니다. +- **색상** + - 색상을 활용하여 서로 다른 상태를 명확히 나타내고, 아티팩트를 구분하기 쉽습니다. + - ex) 서로 다른 마이크로서비스의 인스턴스를 색상으로 구별 +- **키** + - 셰이프가 모호할 경우, **다이어그램에 키를 추가해 각 셰이프의 의미를 명확히** 합니다. + +## 21.2 프레젠테이션 + +아키텍트는 PowerPoint나 Keynote 같은 프레젠테이션 도구를 효과적으로 활용하는 능력이 필요합니다. +문서와 프레젠테이션에는 시간 조작이라는 근본적인 차이가 있다는 점에 주목할 필요가 있습니다. +프레젠테이션에서 발표자는 아이디어 전개의 속도를 스스로 조절할 수 있지만, 문서는 독자가 속도를 조절합니다. +시간을 효과적으로 관리해야 프레젠테이션에서 성공할 수 있습니다. + +### 21.2.1 시간 조작 + +프레젠테이션 도구는 **전환(transition)**과 **애니메이션(animation)**을 통해 슬라이드의 시간을 조작합니다. + +- **전환**: 한 슬라이드에서 다른 슬라이드로 이동합니다. +- **애니메이션**: 슬라이드 내 요소에 움직임을 부여합니다. 나타내기, 사라지기, 이동, 크기 조정 등 다양한 동적 효과를 포함합니다. + +한 슬라이드를 과도하게 채우지 말고, **아이디어를 여러 슬라이드로 나누어 표현**하고, **전환과 애니메이션을 활용해 자연스럽게 연결**하는 것이 중요합니다. +`디졸브`와 같은 전환 효과를 활용하면 슬라이드 경계를 감추며 스토리를 전달할 수 있고, 주제 전환 시에는 `도어`, `큐브` 같은 전환 효과로 새로운 주제를 시각적으로 알릴 수 있습니다. + +### 21.2.2 점진적 빌드 + +**총알투성이 시체(Bullet-Riddled Corpse)**라는 안티패턴은 **텍스트로 가득 찬 슬라이드를 청중에게 보여주고 발표자가 이를 읽는 방식의 프레젠테이션**을 말합니다. +청중은 이미 슬라이드를 읽고, 발표자의 느린 설명을 수동적으로 듣게 되어, 지루함을 느낄 수밖에 없습니다. +발표자는 **구두(언어)**, **시각** 두 가지 정보 채널을 통해 슬라이드를 점진적으로 빌드하여, **필요한 정보만 단계적으로 제시**해야 합니다. + +예를 들어 기능 브랜칭을 주제로 프레젠테이션을 만들 때, 브랜치를 오래 유지하면 부정적인 결과를 초래한다는 메시지를 전달하려고 합니다. +이 때 전체 슬라이드를 즉시 보여주면, 청중이 결말을 예상하게 되고, 발표자가 설명할 때까지 이를 기다려야 합니다. +그 대신, 흰색 상자로 일부 그림을 가린 후 점진적 빌드와 빌드 아웃 애니메이션을 활용해 일부분만 순차적으로 보여주면, 청중에게 기대감과 긴장감을 줄 수 있습니다. +이를 통해 발표를 더욱 흥미롭고 매력적으로 만들 수 있습니다. + + + +### 21.2.3 인포덱스 VS 프레젠테이션 + +프레젠테이션을 청중에게 직접 보여주지 않고, 이메일로 전달해 각자가 읽도록 하는 방식도 있습니다. +`인포덱스`는 **프레젠테이션 도구를 데스크탑 출판 도구처럼 활용해 정보를 시각적으로 요약**해줍니다. + +인포덱스와 프레젠테이션의 주요 차이점에는 **콘텐츠의 종합성**과 **전환/애니메이션 효과**에 있습니다. +인포덱스는 독자가 잡지 기사처럼 훑어보는 자료로, 시간 요소 없이 모든 정보를 포함시켜서 구성합니다. +반면, 프레젠테이션은 슬라이드에 일부 정보만 담고 나머지는 발표자가 직접 설명하기 때문에, 전달 방식이 구두 발표에 의존합니다. + +### 21.2.4 슬라이드는 절반의 스토리 + +주요 논점을 강조하려다 과도한 자료를 슬라이드에 넣는 경우가 많습니다. +**발표자는 슬라이드와 구두 설명이라는 두 가지 정보 채널을 전략적으로 활용해 메시지의 효과를 극대화**해야 합니다. +`불가시성 전략`은 이러한 접근법의 좋은 사례입니다. + +### 21.2.5 불가시성 + +**불가시성(Invisibility)** 은 발표자에게만 청중의 주목이 집중되도록 **슬라이드에 빈 검정 화면을 삽입**하는 전략입니다. +핵심 요점을 전달할 때 이 방법을 활용하면, 청중의 관심을 자연스럽게 발표자에게 집중시킬 수 있습니다. diff --git "a/ch21_\354\225\204\355\202\244\355\205\215\354\262\230_\353\217\204\354\213\235\355\231\224_\353\260\217_\355\224\204\353\240\210\354\240\240\355\205\214\354\235\264\354\205\230/ch21_eden/21-1.png" "b/ch21_\354\225\204\355\202\244\355\205\215\354\262\230_\353\217\204\354\213\235\355\231\224_\353\260\217_\355\224\204\353\240\210\354\240\240\355\205\214\354\235\264\354\205\230/ch21_eden/21-1.png" new file mode 100644 index 0000000..dad940c Binary files /dev/null and "b/ch21_\354\225\204\355\202\244\355\205\215\354\262\230_\353\217\204\354\213\235\355\231\224_\353\260\217_\355\224\204\353\240\210\354\240\240\355\205\214\354\235\264\354\205\230/ch21_eden/21-1.png" differ diff --git "a/ch21_\354\225\204\355\202\244\355\205\215\354\262\230_\353\217\204\354\213\235\355\231\224_\353\260\217_\355\224\204\353\240\210\354\240\240\355\205\214\354\235\264\354\205\230/ch21_eden/21-4.png" "b/ch21_\354\225\204\355\202\244\355\205\215\354\262\230_\353\217\204\354\213\235\355\231\224_\353\260\217_\355\224\204\353\240\210\354\240\240\355\205\214\354\235\264\354\205\230/ch21_eden/21-4.png" new file mode 100644 index 0000000..5f6bd46 Binary files /dev/null and "b/ch21_\354\225\204\355\202\244\355\205\215\354\262\230_\353\217\204\354\213\235\355\231\224_\353\260\217_\355\224\204\353\240\210\354\240\240\355\205\214\354\235\264\354\205\230/ch21_eden/21-4.png" differ diff --git "a/ch22_\352\260\234\353\260\234\355\214\200\354\235\204_\355\232\250\354\234\250\354\240\201\354\234\274\353\241\234/ch22_eden.md" "b/ch22_\352\260\234\353\260\234\355\214\200\354\235\204_\355\232\250\354\234\250\354\240\201\354\234\274\353\241\234/ch22_eden.md" new file mode 100644 index 0000000..b0b7a62 --- /dev/null +++ "b/ch22_\352\260\234\353\260\234\355\214\200\354\235\204_\355\232\250\354\234\250\354\240\201\354\234\274\353\241\234/ch22_eden.md" @@ -0,0 +1,267 @@ +# 개발팀을 효율적으로 + +아키텍트는 기술 아키텍처를 정립하고 결정할 뿐만 아니라, **개발팀이 이를 올바르게 구현하도록 지원**해야 합니다. +폐쇄적인 환경에서 독단적으로 아키텍처을 작업할 경우 개발팀이 구현 과정에서 어려움을 겪게 됩니다. +이번 장에는 개발팀을 생산적으로 만들기 위한 기본적인 테크닉을 다룹니다. + +## 22.1 팀 경계 + +개발팀이 아키텍트와 아키텍처로부터 멀어지면, **시스템의 제약 조건에 대한 이해와 경험 부족**으로 인해 아키텍처를 제대로 구현하지 못하는 경우가 많습니다. +아키텍트는 개발팀이 **아키텍처 구현과 관련된 제약조건과 틀**을 통해 개발팀과 소통합니다. +이 경계가 너무 빡빡하거나 느슨해지면 개발팀의 아키텍처 구현 능력에 부정적인 영향을 미칠 수 있습니다. +아키텍트가 제약조건을 과도하게 설정하면, 개발자는 필요한 도구와 라이브러리를 활용하지 못해 효과적으로 시스템을 구현할 수 없습니다. +반대로 제약이 너무 느슨하거나 아예 없는 경우, 중요한 아키텍처 결정을 개발팀이 떠맡아야 하고, 명확한 지침이 없어 비생산적이게 됩니다. + +아키텍트는 팀이 올바른 도구와 라이브러리를 통해 아키텍처를 잘 구현할 수 있도록, 적절한 지침과 제약조건을 제공해야 합니다. + +## 22.2 아키텍트 성향 + +아키텍트는 3가지 유형을 보이며, `내 맘대로 아키텍트`는 빡빡한 경계, `유체이탈 아키텍트`는 느슨한 경계, `유능한 아키텍트`는 적합한 경계를 설정하는 특징이 있습니다. + +### 22.2.1 내 맘대로 아키텍트 + +`내 맘대로 아키텍트(Control Freak Architect)` 는 **소프트웨어 개발의 세부 사항까지 지나치게 통제**하려는 경향이 있습니다. +이들은 오픈 소스나 서드파티 라이브러리 사용을 제한하고, 명명 규칙, 클래스 설계, 메서드 길이 등을 엄격히 제한하며, 심지어 의사코드까지 제시하는 등 과도한 간섭을 합니다. +이러한 통제는 개발자들이 아키텍트에 대한 존중을 잃게 만듭니다. +특히 개발자에서 아키텍트로 전향한 경우, 개발자 역할에 익숙해 컴포넌트 설계와 구현에까지 관여하고 싶어지기 쉽습니다. +그러나 구현 방안을 결정하는 건 개발자의 역할임을 명심해야 합니다. +아키텍트는 시스템의 컴포넌트 별 핵심 기능과 컴포넌트간 상호작용을 정의하는 선에서 역할을 다 해야 합니다. + +### 22.2.2 유체이탈 아키텍트 + +유체이탈 아키텍트는 코딩 경험이 부족하거나 세부 구현 사항에 무관심한 아키텍트로, 아키텍처 초안만 완성한 뒤 개발팀과 소통 없이 다른 프로젝트로 떠납니다. +유체이탈 아키텍트는 기술이나 비즈니스 측면에서 팀을 리드하거나 가이드하기 어렵습니다. +아키텍트는 다이어그램과 설계를 주로 다루게 되는데, 아키텍트의 경험과 소통이 부족하면 다이어그램이 실제로 실행 가능한지 확인하기 어렵습니다. + +예를 들어 주식 거래 시스템 같은 복잡한 솔루션을 설계할 때, 다음과 같이 지나치게 고수준의 다이어그램만 작성하면 세부 구현에 대한 구체성이 부족하게 되어, 개발에 실질적인 도움이 되지 않는다는 한계가 있습니다. + + + +또한 유체이탈 아키텍트는 개발팀과의 소통과 역할 분담에 소홀하여, 개발팀이 아키텍트의 일을 대신하게 만듭니다. +이로 인해 프로젝트 진척과 생산성이 떨어지고, 시스템 작동 방식을 이해하는데 혼란이 발생합니다. +개발팀은 아키텍트의 기술적 지원, 가이드, 그리고 기술·비즈니스 관련 문의에 대한 답변을 필요로 합니다. + +다음은 유체이탈 아키텍트의 징후들입니다. + +- 비즈니스 영역, 비즈니스 문제, 기술을 온전히 이해하지 못한다. +- 소프트웨어 개발 실무 경력이 부족하다. +- 아키텍처 솔루션 구현에 함축된 의미를 전혀 신경 쓰지 않는다. + +### 22.2.3 유능한 아키텍트 + +유능한 소프트웨어 아키텍트는 개발팀에 **명확한 제약조건과 경계를 설정**하고, **협력을 독려**하며 **적절한 가이드를 제공**합니다. +또한, **팀이 필요한 도구와 기술을 갖췄는지 확인**하고, **장애 요소를 제거해 목표 달성을 지원**합니다. +개발팀과 긴밀히 협력하며 존경을 얻는 리더십은 하나의 예술이라 할 수 있습니다. + +## 22.3 얼마나 제어해야 하나? + +유능한 소프트웨어 아키텍트는 개발팀을 적절히 제어할 줄 알아야 합니다. +이는 다음의 다섯 가지 핵심 팩터에 따라 달라지며, 해당 팩터들은 아키텍트가 한 번에 관리할 수 있는 팀이나 프로젝트의 범위를 결정합니다. + +- **팀원 간 친밀도** + - 팀원들이 서로 얼마나 잘 알고 있는지, 이전에 함께 프로젝트를 진행한 경험이 있는지 + - 팀원 간 친밀도가 높을수록, 이미 자율적으로 조직화되기 시작하므로 제어가 덜 필요. + - 친밀도가 낮을수록 협업 촉진과 파벌 방지를 위해 더 많은 제어가 필요. +- **팀 규모** + - 팀에 몇 명의 개발자가 있는가? + - **작은 팀**: 4명 이하 + - **큰 팀**: 12명 이상 + - 팀 규모가 클수록 제어가 더 많이 필요. + - 팀 규모가 작을수록 제어가 덜 필요. +- **전체적인 경험** + - 팀원 중 시니어/주니어 개발자의 비율은 어느 정도이고, 기술 및 비즈니스 영역에 대한 팀원들의 숙련도는 어느 정도인가? + - **주니어 개발자가 많은 팀**: 제어와 멘토링이 더 필요. + - **시니어 개발자가 많은 팀**: 제어가 덜 필요하며, 아키텍트는 멘토보다 조정자(facilitator) 역할에 집중. +- **프로젝트 복잡도** + - 프로젝트의 복잡성은 얼마나 높은가? + - **복잡한 프로젝트**: 아키텍트가 팀에 더 많이 관여하고 더 많은 제어 필요. + - **단순한 프로젝트**: 별도의 많은 제어 없이 진행 가능. +- **프로젝트 기간** + - 프로젝트의 기간은 얼마나 되는가? - **짧은 프로젝트**: 2개월, **보통 프로젝트**: 6개월, **긴 프로젝트**: 2년 이상 + - **긴 프로젝트**: 더 많은 제어가 필요. + - **짧은 프로젝트**: 제어가 덜 필요. + +단기 프로젝트(예: 2개월)는 일정이 빠듯해서 개발팀은 이미 압박을 느껴 효율적으로 작업하기 때문에, 아키텍트가 지나치게 개입하면 오히려 방해가 될 수 있습니다. +반대로 장기 프로젝트(예: 2년)는 초기 단계에서 긴박감이 적어, 개발자들이 느긋해질 가능성이 있으므로, 아키텍트가 프로젝트를 적시에 진행시키기 위해 더 많은 제어와 관리가 필요합니다. + +프로젝트 초기에 팩터들을 기반으로 제어 수준을 결정한 뒤, 프로젝트 진행에 따라 제어 수준도 점진적으로 조정해야 합니다. +이를 위해 각 팩터에 20점 단위로 값을 매겨 평가하고, 최종 결과가 음수(-) 이면 제어를 덜 해야 함, 양수(+) 이면 제어를 더 해야 함을 나타내는 것으로 정의할 수 있습니다. +프로젝트 진행 중 지속적으로 지표를 분석해, 적절한 제어 수준을 유지하는 것이 중요합니다. + +예를 들어 프로젝트 시나리오에서 각 팩터를 평가한 결과, 각 팩터마다 점수(+20, -20)가 부여되었고, 최종적으로 누적 점수가 -60점으로 나타났습니다. +이는 아키텍트가 개발팀의 업무를 가급적 방해하지 않고, 자율적으로 진행하도록 하는 것이 바람직함을 의미합니다. +이 경우 유능한 소프트웨어 아키텍트라면, 초기에는 조정자 역할을 수행하며, 팀원들의 업무에 깊이 개입하지 않습니다. +그 대신 질문에 답변하고, 프로젝트가 정상적으로 진행되는지 확인하면서, 숙련된 팀원들이 각자의 전문성을 발휘해 소프트웨어 개발을 신속히 진행할 수 있도록 지원합니다. + +| 팩터 | 평가 기준 | 평점 | +| --------------- | ------------- | ---- | +| 팀원 간 친밀도 | 신규 팀원들 | +20 | +| 팀 규모 | 작음 (4명) | -20 | +| 전체적인 경험도 | 모두 유경험자 | -20 | +| 프로젝트 복잡도 | 비교적 단순함 | -20 | +| 프로젝트 기간 | 2개월 | -20 | +| **총합** | | -60 | + +이와 달리 이번 시나리오에서는 팀 규모가 크고(12명), 팀원들은 친밀하지만 대부분 주니어 개발자로 구성되어 있습니다. +프로젝트는 6개월 동안 진행되며, 복잡도는 꽤 복잡한 수준입니다. +누적 점수는 -20점으로 계산되었으며, 이에 따라 아키텍트는 팀 업무에 일정 부분 관여하여 멘토와 코치 역할을 수행하는 것이 더 효과적이라는 결론이 도출됩니다. + +| 팩터 | 평가 기준 | 평점 | +| --------------- | ----------------- | ---- | +| 팀원 간 친밀도 | 서로 잘 아는 사이 | -20 | +| 팀 규모 | 큼 (12명) | +20 | +| 전체적인 경험도 | 대부분 주니어급 | +20 | +| 프로젝트 복잡도 | 아주 복잡함 | +20 | +| 프로젝트 기간 | 6개월 | -20 | +| **누적 점수** | | -20 | + +## 22.4 팀의 이상 징후 + +팀 규모는 아키텍트의 제어 수준에 영향을 미치는 중요한 요인입니다. +팀이 클수록 더 많은 제어가 필요하며, 작을수록 제어가 줄어듭니다. +**효율적인 개발팀의 규모**는 다음 세 가지 요인에 의해 결정됩니다: + +- 프로세스 손실 +- 다원적 무지 +- 책임 확산 + +#### 프로세스 손실 + +**프로세스 손실(Process Loss)**은 프로젝트에 인력을 더 많이 투입할수록 프로젝트 완료 시간이 길어지는 현상을 의미합니다. +팀의 **그룹 잠재력(Group Potential)**은 팀원들의 집합적 노력으로 정의되지만, **실제 생산성은 이 잠재력에 미치지 못하며**, 이 차이가 바로 프로세스 손실입니다. + +아키텍트는 팀을 관찰하여 프로세스 손실을 식별하고, 이를 통해 적절한 팀 규모를 결정해야 합니다. +예를 들어, 코드 커밋 과정에서 **병합 충돌**이 자주 발생하면, 이는 팀원들이 동일한 코드 작업을 하며 발이 엉키고 있다는 신호입니다. +이를 방지하려면 **팀 내에서 병렬 작업이 가능한 부분을 찾아 각자 다른 영역에서 작업**할 수 있도록 해야 합니다. +팀원이 새로 합류했는데도 병렬 작업 흐름에 기여할 여지가 없다면, 신규 인력이 프로젝트에 부정적 영향을 미칠 수 있음을 설명해야 합니다. + +#### 다원적 무지 + +팀 규모가 너무 커지면 **다원적 무지(Pluralistic Ignorance)** 현상이 발생할 수 있습니다. +이는 **팀원들이 개인적으로 반대 의견을 가지고 있지만, 뻔한 것을 놓치고 있다고 비난받을까 두려워 마지못해 동의**하는 상황을 말합니다. + +예를 들어, 큰 팀에서 대부분의 팀원이 두 원격 서비스가 메시징으로 통신해야 한다고 생각하지만, 한 팀원은 보안 방화벽 문제로 비현실적이라고 판단합니다. +그러나 비난받을까 두려워 의견을 말하지 않고 동의하게 되고, 결국 메시징이 불가능하다는 사실이 나중에 밝혀져 개발을 다시 하게 됩니다. +팀 규모가 작았다면 초기 단계에서 문제를 지적하고 대안을 논의하기 더 수월했을 것입니다. + +아키텍트는 회의나 토론에서 참가자의 표정과 몸짓을 관찰하여, **다원적 무지가 발생할 조짐이 보이면 조정자로 나서야** 합니다. +중간중간 논의된 해결책에 대해 팀원들에게 의견을 묻고, 그들이 발언할 때 지지해줌으로써 **자유롭게 의견을 낼 수 있는 분위기를 조성**합니다. + +#### 책임 확산 + +적절한 팀 규모를 결정하는 세 번째 요인은 **책임 확산**입니다. +의사소통이 어려워지고, 팀원들 간에 누가 어떤 업무를 담당하는지 혼란스러워진다면, 이는 팀이 너무 커졌다는 신호입니다. + +## 22.5 체크리스트 활용 + +체크리스트는 문제를 해결하고 업무를 철저히 준비하는 데 효과적인 도구입니다. +다만 소프트웨어 개발의 모든 작업에 체크리스트가 필요하지는 않습니다. +개발팀의 효율성을 높이기 위해서는 **체크리스트를 활용해야 할 상황과 그렇지 않을 상황을 명확히 구분**하는 것이 중요합니다. + +체크리스트에는 잇따라 실행되는 종속적인 작업이나, 간단하고 빈번하게 실행되는 프로세스는 포함되지 않아야 합니다. +예를 들어 아래의 데이터베이스 체크리스트에는 `폼작성 및 전달` 같은 종속적인 작업들이 포함되어 있고, `생성된 테이블 확인` 처럼 간단한 작업도 포함되어 있습니다. + +- [ ] 데이터베이스 컬럼 필드명과 타입을 결정한다 +- [ ] 데이터베이스 테이블 요청 폼을 작성한다 +- [ ] 새 데이터베이스 테이블의 퍼미션을 얻는다 +- [ ] 데이터베이스 그룹에 요청 폼을 전달한다 +- [ ] 생성된 테이블을 확인한다 + +체크리스트는 단순히 작업 단계를 나열하는 것이 아니라, 중요한 확인 사항을 효율적으로 관리하는 데 초점을 맞춰야 합니다. +순서나 종속 작업이 없으며, 에러가 발생하기 쉽거나 누락되기 쉬운 작업들을 포함해야 합니다. +이 때, 너무 복잡하거나 방대한 체크리스트는 개발자들이 활용하지 않을 가능성이 높기 때문에, 모든 것을 체크리스트로 만들려 하지 않아야 합니다. + +경험 상 가장 효과적인 체크리스트 3가지는 다음과 같습니다. + +1. 개발자 코드 완료 체크리스트 +2. 단위/기능 테스트 체크리스트 +3. 소프트웨어 릴리스 체크리스트 + +### 22.5.1 개발자 코드 완성도 체크리스트 + +`개발자 코드 완성도 체크리스트`는 개발자가 코드 작업을 ‘완료’했음을 판단하는 도구이며, 다음 내용이 포함됩니다: + +- 자동화 도구에 포함되지 않은 코딩 및 포매팅 표준 +- 자주 간과되는 항목(예: 로그에 숨겨진 오류) +- 프로젝트별 표준 +- 팀의 특별 지침이나 절차 + +예시는 다음과 같습니다. + +- [ ] 코드를 깨끗이 정리하고 포매팅한다. +- [ ] 커스텀 소스 검증 도구를 실행한다. +- [ ] 모든 업데이트에 감사 로그가 기록됐는지 확인한다. +- [ ] 예외가 묻혀버리는 코드가 없는지 검사한다. +- [ ] 하드코딩된 값이 있는지 체크해서 상수로 바꾼다. +- [ ] 블릭 메서드만 `setFailure()`를 호출하는지 확인한다. +- [ ] 서비스 API 클래스에 `@ServiceEntrypoint`를 붙인다. + +체크리스트는 코드 정리와 포매팅, 예외 처리 확인 같은 기본적이고 명확한 항목을 포함합니다. +기본적인 작업도 종종 놓치는 경우가 있기 때문에, 당연히 해야 할 일도 체크리스트로 관리하는 것이 중요합니다. + +2, 3, 6, 7번 항목은 프로젝트에 특정한 태스크로, 체크리스트에 포함하기 적합하지만, 체크 작업을 자동화하거나 플러그인 기반 유효성 검증기로 대체하여 체크리스트의 분량을 줄이는 것이 좋습니다. +예를 들어, setFailure() 호출을 체크하는 것은 IDE에서 자동화가 가능합니다. + +### 22.5.2 단위 + +`단위/기능 테스트 체크리스트`는 엣지 케이스와 같이 개발자가 놓치기 쉬운 테스트와, QA팀이 발견한 테스트 이슈 등 모든 종류의 테스트를 포괄합니다. +이 체크리스트의 목표는 가능한 완전한 코드를 보장하여, 프로덕션 배포가 가능한 상태로 만드는 것입니다. + +체크리스트에는 다음 항목들이 포함됩니다: + +- 텍스트 필드의 특수 문자와 숫자 필드 확인 +- 최솟값/최댓값 범위 검증 +- 드물고 극단적인 테스트 케이스 확인 +- 누락된 필드 처리 확인 + +자동화 테스트로 확인 가능한 항목은 체크리스트에서 제거해야 합니다. +예를 들어, 주식 거래 앱에서 매입 주식 수의 마이너스 여부를 테스트하는 로직이 테스트 스위트에 포함되어 있다면, 해당 항목은 체크리스트에서 제외합니다. + +단위/기능 테스트 체크리스트는 개발자가 수행해야 하는 단위 테스트의 방법과 범위를 명확히 합니다. +체크리스트를 통해 테스트 시나리오가 소프트웨어 개발 프로세스에 포함되었는지 확인할 수 있어, 테스트팀은 체크리스트에 없는 비즈니스 시나리오에 집중할 수 있습니다. + +### 22.5.3 소프트웨어 릴리스 체크리스트 + +소프트웨어 릴리스는 개발 라이프 사이클에서 에러가 발생하기 가장 쉬운 단계입니다. +체크리스트 작성을 통해 빌드 및 배포 실패를 방지하고 출시 관련 리스크를 줄일 수 있습니다. +릴리스 체크리스트는 배포 중 발생하는 에러와 이슈를 해결하며 지속적으로 업데이트되므로, 변화가 많이 발생합니다. + +체크리스트에는 일반적으로 다음 내용이 포함됩니다: + +- 서버 또는 외부 구성 서버의 설정 변경 +- 프로젝트에 추가된 서드파티 라이브러리(JAR, DLL 등) 확인 +- 데이터베이스 업데이트 및 마이그레이션 스크립트 점검 + +## 22.6 지침 제시 + +소프트웨어 설계 원칙을 명확히 전달하는 것은 팀의 성공에 중요한 요소입니다. +아키텍트는 애플리케이션에서 사용 가능한 서드파티 라이브러리에 대한 지침을 제공하여, 개발팀이 사용 가능한 라이브러리와 금지된 라이브러리를 명확히 구분하도록 도와야 합니다. +다음의 두 질문을 통해 지침을 제시할 수 있습니다. + +1. 제안하신 라이브러리와 기존 시스템의 내부 기능 사이에 중첩돠는 부분이 있나요? +2. 제안하신 라이브러리를 반드시 사용해야 하는 당위성은 무엇인가요? + +첫번째 질문은 개발자가 기존 라이브러리나 기능으로도 충족이 가능한지를 검토하도록 유도하여, 프로젝트에서 기능 중복 문제를 예방합니다. +두번째 질문은 새 라이브러리 도입의 기술적 및 비즈니스적 타당성을 모두 검토하도록 요구하여, 비즈니스적 정당화의 중요성을 인식시킵니다. + +개발팀이 **결정 가능한 사항과 불가능한 사항을 시각적으로 설명**하면 설계 원칙을 효과적으로 전달할 수 있습니다. +다음 예시는 레이어드 스택 구조를 시각화하여, 서드파티 라이브러리의 각 범주에 무엇이 포함되는지, 개발자가 무엇을 할 수 있고 무엇을 할 수 없는지를 보여줍니다. + +