조지 페어뱅크스의 "Just Enough Software Architecture: A Risk-Driven Approach"[1]은 성공적으로 소프트웨어를 만드는 것이 "가능한 실패를 예상하고 실패할 수 있는 설계를 피하는 것을 의미"한다고 이야기 한다. 그렇기 때문에 실패 리스크를 찾고 이것에 매핑하는 소프트웨어 설계 테크닉을 적용하는 것이라고 한다.

 

책에서 말하는 리스크 주도 모델의 경우는 다음과 같은 단계를 거치면서 반복하는 과정이라고 말한다.

  1. 리스크 식별/우선 순위 지정
  2. 적용할 테크닉 선택/적용
  3. 리스크 감소의 평가

소프트웨어 개발은 설계만으로 끝나는 것이 아니고 구현을 해야 한다. 그러므로 다음과 같은 예의 논리를 바탕으로 진행하는 것을 제안한다.

 

"A, B 그리고 C를 리스크로 식별하고, B는 매우 중요하다. 이를 위한 테크닉 X와 Y를 통해 B의 리스크를 줄일 수 있다고 판단했다. 결과물인 설계를 평가했을 때, B의 리스크가 충분히 완화되어 구현을 계속 했다."

 

리스크란 무엇인가?

책에서 이야기 하는 리스크의 정의는 "인지된 실패 확률*인지된 영향"이라고 정의 한다. 즉, 인지되지 않은 실패 혹률을 리스크로 판단할 수 없고, 실패로 인한 소프트웨어 프로젝트로의 영향도 파악할 수 없다면 리스크는 확인할 수 없는 것이다.

 

리스크의 구분은 크게 엔지니어링 및 프로젝트 관리 리스크로 나눈다. 일반적으로 엔지니어링 리스크는 제품의 분석, 설계 및 구현과 관련된 사항이고, 프로젝트 관리 리스크는 일정, 작업 순서, 팀 규모 등과 관련된 것들이다. 여기서 말하는 리스크는 엔지니어링 리스크와 관련되고 이를 해결하기 위한 엔지니러링 테크닉을 적용하는 것이 일반적이다.

 

리스크의 식별의 경우는 요구 사항에서 하는 것이 일반적이다. [2]에서 설명한 것과 같이 소프트웨어의 요구 사항에서 아키텍처적으로 중요한 요구 사항(Acrhitectural Significant Requirement, ASR)을 추출과 연결 시켜 보면, 추출된 요구 사항(기능적 그리고 비기능적 요구사항/품질 속성)에서 중요한 것을 찾는 것이 기존 방법과 다르게 리스크라는 관점에 중점에 두고 선정하는 것이 차이일 수 있다. 여기서 가장 달성하기 어려운 것을 찾는 것이 방법이라고 할 수있다.

 

개발하는 소프트웨어의 도메인에 따라 주로 발생하는 원형적 리스크(Prototypical Risk)도 있다. 예로는 아래와 같은 것들이 있다.

프로젝트 도메인 원형적인 리스크
정보 기술(IT) 복잡하고 잘 이해되지 않은 문제
실제 문제를 해결하고 있는지 확실하지 않음
잘못된 상용 기성품(COTS) 소프트웨어를 선택
잘 이해되지 않은 기존 소프트웨어와 통합
사람들에게 흩어져 있는 도메인 지식
수정가능성(modifiability)
시스템 성능, 신뢰성, 크기, 보안
동시성(concurrency)
구성(composition)
보안
애플리케이션 규모확장성(scalability)
개발자 생산성/표현성(expressability)

 

적용 테크닉

리스크를 인식하고 나면 리스크를 줄일 수 있을 것으로 예상 되는 테크닉(Techique)을 적용할 수 있다. 조지 페어뱅크스는 기존에 방식에서 지혜를 얻고 있다. 소프트웨어 아키텍처 설계에서 사용되는 전술(Tactics)[3] 혹은 패턴(Pattern)을 예로 들고 있다.

 

이와 같은 테크닉은 수 없이 많을 수 있다. 하지만, 시간과 돈을 낭비하지 않으려면 우선 순위가 지정된 리스크 목록을 가장 잘 줄이는 테크닉을 선택해야 한다. 즉, 최적화 문제로 생각하고 접근해야 한다. 이러하듯, 엔지니어링 리스크를 완전히 제거할 수 없는 이유는 주로 프로젝트 관리 리스크인 비엔지니러링 리스크와 균형르 이루어야 하기 때문이라고 책[1]에서는 이야기한다.

 

이와 같은 제약 뿐 아니라 적용할 테크닉의 선택을 위해서 문제의 종류(답을 찾는 문제/증명 문제), 모델의 종류(분석 모델 및 유추 모델)에 따라 다르다고 한다. 그리고, 설계를 바라 보는 관점이라고 할 수 있는 뷰타입(Viewtype)의 경우는 리스크와 테크닉의 쌍(Pair)에 효과를 다르게 하기 때문에 어떤 것이 적절한지 매칭(matching)을 고려해야 한다고 이야기 한다.

언제 멈추는가?

소프트웨어 아키텍처를 설계에는 중요한 두가지 질문은 "어떤 테크닉을 사용하는가?" 그리고 "얼마나 설계와 아키텍처를 수행하는가?"라고 할 수 있다. 리스크 주도 설계에서는 아주 단순히 답한다면 "충분히 리스크가 줄어 들 때까지 설계한다"가 답일 수 있다.

 

이를 위해서는 설계에 들이는 노력은 "리스크에 상응해야 한다"라고 한다. 저자는 아버지의 집앞에 우편함을 만드는 이야기를 하면서 단순하게 땅을 파고 우편함을 묻기만 하면 될 일을 위해서 측량을 한다거나와 같은 높은 건물 건축에서 사용되복잡한 설계나 리스크를 측정하는 테크닉을 적용할 필요가 없다는 것이다.

 

불완전해 보일 수 있지만, 리스크 모델에서는 리스크가 인식되는 영역만 설계한다는 부분과 리스크 평가가 주관적인 평가라는 부분 또한 언급한다. 이 부분은 단점일 수 있지만, 여전히 장점이기도 하다. 

계획된 설계와 진화적 설계

책[1]에서는 소프트웨어 개발에 사용되는 설계 접근 방식을 계획된 설계(Planned design)과 진화적 설계(Evolutionary design)으로 나눈다. 리스크 주도 설계는 이 두가지 설계 방식에 모두 적용 가능하다고 책에서는 주장한다.

 

진화적 설계의 경우, 주로 애자일 소프트웨어 개발 방식에서 사용하는 방식이다. 시스템이 구현됨에 따라 설계가 확장되기 때문에 지협적이고 파편화된 설계 결정이 여러 문제를 발생 시킨다. 이러한 단점을 해결하는 방법으로 리펙터링(Refactoring), 테스트 주도 설계(Test drivn design), 지속적인 통합(Continous integration)이 제안되어 채영되고 있다. 여전히 아키텍처적 입장에서는 좋은 지침에 제공되고 있지 않다고 지적하고 있다.

 

계획된 설계는 진화적 설계의 반대쪽 끝에 있다고 설명하며, 실재 구현 이전에 설계를 자세하게 작성하는 것이다. 하지만, 이는 지나친 선행 설계(Big Design Up Front BDUF)라고 비판을 받는다. 앞에서도 이야기 한 저자의 아버지 우편함에 대한 예가 주요 내용이라고 볼 수 있다.

 

위의 두 가지는 양쪽 극단이다. 마치 스펙트럼 같은 것일 수 있다. 이 중간에는 최소 계획된 설계(Minimal planned design) 또는 작은 선행 설계(Little Design Up Front LDUF)가 있다. 

 

이러한 접근 방법들은 서로 다른 지지자들이 있다. 또한 책에서는 만병통치약이 없듯이 다른 시스템에서는 다른 방법이 적절하다고 이야기 한다. 또한 둘은 다르고, 장점 또한 다르다. 이케텍처 설계를 한다는 것은 장기적인 관점을 가지고 시스템 전체의 속성을 보장하는 장점을 가진다. 진화적 설계는 앞에서 살펴 보았듯이 리펙터링, TDD 그리고 지속적 통합(CI)의 장점을 활용할 수 있다.

프로세스에 적용하기

리스크 주도 소프트웨어 설계를 여러 프로세스에 적용하기 위해서 몇가지 프로세스의 특징을 우선 아래와 같이 정리하고 있다.

 

프로세스 선행 설계 설계 본질 작업 우선순위 반복 길이
폭포수 분석 및 설계 단계 계획된 설계, 재설계 없음 개방적 개방적
반복적 선택적 계획 또는 진화, 재설계 허용 개방적이고 종종 기능 중심 개방, 보통 1-8
나선 없음 계획 또는 진화 가장 위험한 작업부터 개방적
UP/RUP 선택적, 사전 설계 전반부 배치 계획 또는 진화 가장 위험한 작업 후, 가장 높은 가치 보통 2~6
XP 없음, 일부 반복 제로(Iteration zero) 진화적 설계 가장 높은 고객 가치 우선 보통 2~6

우선 애자일 개발 프로세서인 eXtream Programming(XP)에서는 일반적으로 설계 작업이 없지만 반복 제로(Iteration zero)를 두고 설계 작업을 할 수 있다. 이렇게 반복적인 작업에서 리스크 주도 기반 접근법은 각 단계에서 필요한 만큼 설계 작업을 진행할 수 있다.

 

반복적 프로세스에서 단계별 설계의 양이 다른 예

대표적인 애자일 프로세스인 스크럼은 기능 중심적 접근 방법으로 백로그에 구현할 기능을 관리한다. 여기에도 리스크 주도 접근법을 적용할 수 있다. 일반적인 기능 백로그는 제품 책임자(Product Owner)가 담당한다. 재품 책임자는 엔지니러링 리스크를 파악하기 어렵다. 대신 소프트웨어 팀이 리스크를 파악하고 이를 시스템의 테스트 가능한 기능으로 만들어 백로그에 넣을 수 있다. 이는 각 반복이 끝날 때 회고(Reflection/Retrospective)의 결과로 도출될 수 있다. 제품 책임자는 백로그 중에서 우선 순위에 따라 각 단계에 수행할 내용을 결정할 수 있다.

기능 및 리스크 백로그 활용방안

 

정리해보면...

리스크 주도 설계 접근 방식의 주요 내용은 설계에 많은 비용이 들기 때문에 리스크를 찾아 내고 이에 적절한 테크닉을 필요한 만큼 반복적으로 적용한다는 것이다. 이는 현재 소프트웨어 개발에서 적용되고 있는 양극단의 소프트웨어 개발 방법에서 모두 적용할 수 있다고 책에서는 주장하고 있다.

 

특히, 애자일 혹은 반복적 개발에서 알 수 있는 주요한 내용 중 하나가 설계가 항상 개발 프로세스의 앞부분에서만 진행되어야 하는 것은 아니라는 점이다. 후반부에 설계를 하게 되면설계를 변경하기 어려운 부분도 있을 수 있으나 구현하려고 하는 소프트웨어를 초기에는 잘 알지 못하는 문제점도 있다는 것을 책에서는 지적하고 있다. 소프트웨어 개발이 지식을 얻어 가는 과정이라면, 이를 이를 소프트웨어 설계 및 아키텍처링에 적용하는 방법으로서 리스크 주도 접근 방식의 장점과 적용하는 방법에 대해서도 흥미로운 재안을 하고있다.

참고 도서

[1] George Fairbanks, "Just Enough Software Architecture: A Risk-Driven Approach," 2010

[2] "Software Architecture: 어떻게 설계 할 것인가?," https://technical-leader.tistory.com/35

[3] 렌 베스 , 폴 클레멘츠 , 릭 캐즈먼, "소프트웨어 아키텍처 이론과 실제, 개정판 3판" 2015년, 에이콘출판

[4] Design Pattern 배우기, https://technical-leader.tistory.com/7?category=1015396 

 

 

소개

이 글[1]은 2015년도 글이기는 해도, 최근에 발견했다. 애자일 과정과 기존의 Software Architecture 접근법에 대한 고찰이 포함되어 있어 참고할만한 글이다.

 

Towards an Agile Software Architecture

소프트웨어 아키텍처는 시스템의 골격(Skeleton)이다. 다른 기능적 요구 사항(Functionall Requirements)과 비기능적 요구 사항(Non-functional requirements)으로 시스템이 작동하는 방식을 정의한다. 한편으로 전통적인 워터폴 방식은 프로젝트 개발의 모든 단계에 강한 제약을 가하기 때문에 엄격하다. 반면에 애자일 접근법은 개발 단계 후반에도 변경 사항을 환영한다. 우리는 견고한 개발에서보다 유연한 개발로 전환하고 있지만, 소프트웨어 아키텍처는 골격(Skeleton)이라는 태생상 기본 특성으로 인해 변화에 민감하다. 따라서 애자일 접근법을 따라갈 때 핵심 요소는 지속 가능한 소프트웨어 아키텍처의 개념을 수용하는 것이다. 이는 프로젝트의 복잡성 증가와 함께 시스템 확장이 점진적이고, 쉽고, 유지 보수 가능한 방식으로 이루어질 수 있도록한다.

이 글에서는 기존의 워터폴 소프트웨어 아키텍처와 애자일 아키텍처 모두에서 작업 할 때의 경험을 다룬다. 나는 세 가지 영역에 중점을 둔 이들의 유사점과 차이점을 묘사한다.

 

  • 소프트웨어 아키텍트 역할의 세부 사항
  • 소프트웨어 아키텍처의 타임스팬(Timespan)
  • 소프트웨어 아키텍처의 결과물

소프트웨어 아키텍처란 무엇인가?

소프트웨어 아키텍처에 대한 정의는 수백 가지가 있다 (실제로 새로운 본인의 정의를 직접 추가 할 수도 있음). 그 이유는 모든 사람이 자신의 상황에 따라 정의하기 때문이다. 나는 특히 IEEE의 정의를 좋아하는데, 기본 개념을 설명하고 머리에서 쉽게 그려 볼 수 있기 때문이다. 또한 소프트웨어 아키텍처의 생성 방식이 아니라 소프트웨어 아키텍처의 본질을 묘사하기 때문에 워터폴 및 애자일 프로세스에 모두 적용된다. 이 글의 나머지 부분에서 나는 이 정의를 언급 할 것이다.

 

구성 요소(Components) 서로와 그리고 환경(Environment)과의 관계(Relationship), 설계 및 진화(Evolution)를 안내하는 원칙으로 구현되는 시스템(System)의 기본 구조(Fundamental Organization)

 

워터폴 소프트웨어 아키텍처

기존의 워터폴 개발은 시작 날짜와 종료 날짜가 명확한 일련의 단계로 구성되며, 각 단계에는 특정 활동 세트가 포함된다. 모든 단계는 서로 연결되어 있으며 각각의 단계는 이전 단계에서 생성된 결과물에 크게 의존한다. 그림 1은 폭포 개발과 관련된 일반적인 단계를 보여준다.

 

 

전통적 워터폴 개발방식

소프트웨어 아키텍처에 대한 작업은 일반적으로 소프트웨어 요구 사항이 정의 된 후에 시작된다. 이 시점에서 시스템은 수행해야 할 작업에 대해 잘 정의되어 있다고 가정한다. 다음 단계는 소프트웨어 아키텍처를 정의하는 담당자와 이 단계의 실제 결과를 조사하는 것이다.

 

전통적인 소프트웨어 아키텍트

소프트웨어 아키텍처는 실제로 소프트웨어 아키텍트가 수행한다. 기술 지식과 경험이 풍부한 사람이다. 일반적으로 회사의 특정 수준에 도달한 후 승진 한 개발자이다. 이 사람은 소프트웨어 요구 사항을 분석하고 이러한 요구 사항을 기반으로 미래 시스템에 대한 특정 기술 결정을 담당한다. 많은 회사에는 일반적으로 프로젝트 당 하나의 소프트웨어 아키텍트가 있지만 일부 대기업에는 소프트웨어 설계자 팀이 함께 작업 할 수 있다. 이는 일반적으로 프로젝트 도메인이 복잡하거나 프로젝트의 기간이 더 큰 경우 (예 : 2-3 년 이상)이다. 모든 회사에 지정된 소프트웨어 아키텍트 역할이있는 것은 아니다. 많은 회사에서 이러한 책임을 경험 많은 개발자(Senior Developer)에게 위임한다. 이 글의 나머지 부분에서는 명시적으로 언급하지 않는 한 소프트웨어 아키텍트는 다른 누군가가 하지 않고 소프트웨어 아키텍트가 수행하는 특정 활동을 언급한다.


전통적인 소프트웨어 아키텍트는 다음과 같은 네 가지 주요 기능을 담당한다.

  • 큰 그림에 초점을 맞춘다. - 소프트웨어 아키텍트는 시스템이 향후 몇 달 (때로는 몇 년)처럼 어떻게 보일지 고려해야한다. 또한 관련된 다른 모든 시스템 (예 : 타사 시스템 및 데이터 저장소)과 시스템 간의 통신이 어떻게 진행 될지 고려해야 한다.
  • 규정 준수 지향 - 소프트웨어 아키텍트는 가능한 규정 준수 문제를 고려해야 한다. 이것은 입법 규범, 라이센스, 표준 또는 기타를 포함하여 미래의 시스템이 이러한 중요한 기준을 충족하도록 해야한다.
  • 청사진을 생성한다. - 중요한 산출물은 다양한 관점에서 아키텍처를 설명하는 문서 및 다이어그램 모음이다. 개발 팀은 이러한 결과물을 사용하여 시스템 구축을 시작한다.
  • 실무 경험이 많지 않음 - 소프트웨어 아키텍트의 목표는 개발 팀을위한 최종 문서를 작성하는 것이다. 소프트웨어 아키텍트는 일반적으로 개발자로서의 경험이 있지만 개발 프로세스에는 거의 관여하지 않으며 개발자가 설계 시스템을 구축하도록 유도한다. 어느 시점에서 그는 개발자는 남겨 두고, 다른 프로젝트로 이동할 수 있다. 
실제 사례의 고통 

나는 세계에서 가장 큰 맥주 회사 중 하나를 위한 소프트웨어 프로젝트를 진행하고 있다. 이 프로젝트를 완료하는 데 2-3 년이 걸렸으며 일반적인 워터폴 방식으로 수행 되었기 때문에 소프트웨어 아키텍트, 개발자, 테스터 등 여러 단계를 담당하는 사람들이있었다. 나는 소규모 팀의 개발자였으며 ​​소프트웨어 아키텍트로부터 시스템 개발 수행 방법에 대한 지시와 가이드라인을 받았다. 처음에는 소프트웨어 아키텍트가 우리를 지원하기 위해 팀에 있었지만 나중에 그 프로젝트의 작업량이 줄어들면서 다른 프로젝트로 옮겼다. 제안 된 소프트웨어 아키텍처는 정의된 경계에 맞지 않는 새로운 종속성이 등장함에 따라 어느 시점에서 따르기가 어려워졌다. 수석 개발자가 아키텍처 비전을 인수하려고 했지만이 프로젝트는 소위 스파게티 코드로 성장했다.이 프로젝트는 다른 곳에서 문제를 일으킬 수 있으므로 모든 사람이 변경을 두려워 했다. 불행히도 프로젝트를 정상 괘도에 올릴 수 있는 과감한 변화를하기에는 너무 늦었었다. 우리는 프로젝트를 출시했지만 나중에 결국 종료되었다.


애자일 접근법

기존의 워터폴 구조는 시작 날짜와 종료 날짜가 명확한 일회성 활동이지만, 애자일 소프트웨어 아키텍처는 진행중인 프로세스이므로 결코 끝나지 않을 수 있다. 이를 통해 필요한 경우 아키텍처 변경 사항을 정기적으로 적용 할 수 있다. 프로젝트의 변화를 환영하는 메커니즘 중 하나는 반복적이고 점진적인 개발을 적용하는 것이다. 스크럼에서는 이러한 반복을 스프린트라고하며 하나의 스프린트는 일반적으로 그림 2에 표시된대로 2-4 주 사이에 지속된다. 이러한 작은 간격을 사용하면 발생하는 모든 변경 사항에 대해 바로 바로 논의 할 것이다. 또한, 팀 협업에 중점을 두고 있으며 오해와 의사 소통이 원활치 않은 것을 방지하며 팀원 간의 문제를 즉시 해결한다.


스크럼의 일반적인 스프린트


애자일 접근법을 통해 프로젝트의 변화를 환영할 수 있지만 얼마나 빠르게 대응해야하는지 알려주지는 않는다. 소프트웨어 아키텍처는 시스템의 백본이므로 변경에 따라 움직인다. 예를 들어, 프로젝트 중간에 사용하는 플랫폼이나 언어를 변경할 수 있다고 생각하는가? 드물기는하지만 이러한 변경에는 많은 추가적인 이터레이션을 필요로 한다. 심지어 프로젝트의 시작 부분으로 돌아갈 수도 있다. 소프트웨어 아키텍처와 관련하여 일부 유형의 변경은 고통스럽고 구현하는 데 시간이 걸린다.

 

애자일 소프트웨어 아키텍트

스크럼은 세 가지 유형의 역할을 정의한다.

  • 제품 소유자(Product Owner) - 특정 비즈니스 도메인에 대한 정보를 제공한다.
  • 스크럼 마스터 - 팀의 의사 소통 및 협업 촉진 한다.
  • 개발팀 - 사용자 스토리을 구현하고 작동하는 소프트웨어를 제작한다.

전통적인 소프트웨어 아키텍트 역할을 애자일 개발에 맞는 역할로 변환하기 위해 가능한 변형을 살펴 봐야한다. 스크럼 팀을 구성하는 한 가지 방법은 개발자 팀과 별도의 소프트웨어 아키텍트 팀이 긴밀하게 협력하는 것이다. 그림 3은 이 시나리오를 여러 스크럼 팀에 적용한 것을 보여준다.

 

열 개발팀과 함께 작업하는 별도의 소프트웨어 아키텍트 팀

이것이 팀을 구성하는 올바른 방법이지만 두 가지 문제가 있다.

  • 소프트웨어 아키텍트 팀은 수요자(Demander)가 될 수 있지만 개발자 팀은 일반적으로 워터폴 접근 방식의 경우 생산자(Producer)입니다. 소프트웨어 아키텍트는 비전을 정의하고 개발자는 비전을 구현해야한다. 이는 개발자를 관여시키지 않고 정중하게 다루지 않으면 개발자 간의 동기를 감소시킬 수 있다.
  • 위의 결과로 일부 개발자는 다른 개발자가해야 할 일을 선택할 수 있도록 소프트웨어 설계자 팀의 일원이되기를 원할 수 있다. Trustpilot은 핵심 팀과 개발 팀을 보유한 사례를 제시했지만, 이는 작업장과 공동 작업에 대한 도덕을 감소 시켰기 때문에 핵심 팀의 각 구성원을 하나의 개발 팀으로 옮겼다. 이는 긍정적인 결과를 낳았다.

또 다른 방법은 소프트웨어 아키텍트를 그림 4와 같이 개발 팀에 직접 배치하는 것이다.

각 개발 팀에는 하나의 소프트웨어 아키텍트가 있다.

이 경우 애자일 소프트웨어 아키텍트는 약간 다른 책임을 갖는다.

  • 큰 그림과 현재의 균형 – 민첩한 소프트웨어 아키텍트는 전체 시스템의 큰 그림에 맞춰 개발하는 동안 발생하는 상황을 고려해야 한다.
  • 실무 경험 – 애자일 소프트웨어 아키텍트는 개발자이며 시스템 구현 작업을 한다. 이것은 선택된 구조적 결정(architectural decision)에 대한 직접적인 피드백을 제공한다.
  • 결정 사항을 설명할 수 있도록 프로토 타입을 제작 - 중요한 기술적 결정을 내려야 할 경우, 빠른 프로토타입을 통해이 결정이 가능한지 여부와 기존 시스템에 어떤 영향을 미치는지 알 수 있다. 또한 전체 개발 팀과의 커뮤니케이션은 개인 개별 활동이 아닌 공동 노력해야 하는 것으로 필수적이다.
  • 지속 가능성에 초점 – 구조적 결정(architectural decision)이 지속 가능한 소프트웨어 아키텍처를 이끌어내는 것이 매우 중요하다. 이는 장기적으로 프로젝트를 지원할 것이다. 이것의 필수 부분은 개인적인 책임과 공감이다. 애자일 소프트웨어 아키텍트는 개발 팀의 일원이므로 위에서 설명한 의사 결정을 통해 직접적인 피드백을 받는다. 이는 워터폴에서 접근하는 방식과 달리 개인의 책임 수준을 높이며, 결정은 개발 팀에 전달되어 구현된다.

다른 개발 팀 (및 프로젝트)간에 구조를 공유하려는 경우 별도의 소프트웨어 설계자 팀과 함께 구조를 선택할 수 있다. 또한 많은 관점을 고려해야하는 복잡한 도메인에서 작업하는 경우, 이 구조를 적용 할 수도 있다. 그러나 이 경우 소프트웨어 아키텍트가 개발자와 긴밀하게 협력하고 지원하도록 해야한다. 애자일 방법론은 협업에 중점을 두므로 소프트웨어 아키텍트를 개발자와 분리하면 협업이 어려워진다. 결과적으로 개발 프로세스는 워터폴 모델에 가까워진다. 나는 개인적으로 팀 구성원 간의 의사 소통이 향상되기 때문에 각 개발 팀에 한 명의 소프트웨어 설계자가 존재하는 두 번째 변형을 선호한다. 선임 아키텍트(High level architects)는 여전히 서로 협력 할 수 있다 (꼭 그렇게 해야 한다).

 

애자일 소프트웨어 아키텍처의 타임스팬

애자일 소프트웨어 아키텍처의 중요한 측면은 언제 시작하는가 이다. 우리가 잘 정의 된 단계를 가지고있는 워터폴 모델과는 달리, 애자일 세계에서는 사람들이 시작 단계라 정의 하는 특정 항목이 없다. 일반적인 접근 방식 중 하나는 스프린트 #0을 진행하는 것이다. 개발 환경을 구성하고 프로그래밍 언어, 플랫폼, 데이터베이스 등과 같은 몇 가지 기본 결정을 내리는 특수 스프린트이다.

그러나 이러한 접근 방식의 일반적인 함정은 사람들이 항상 “거의 준비되었다”고하면서 이 기간을 연장하는 경향이 있다는 것이다. "일주일 더 있으면 정규 스프린트를 시작할 수 있다"라는 말이 종종 들린다. 많은 경우에, "사전 도움말 기능을 미리 구현하는 것이 정말 멋지므로"라며서 유저 스토리없이 시스템에 이미 작업하고있는 것을 알 수 있다. 이러한 상황에서는 스프린트 #0의 종료 날짜에 미리 동의해야 한다. 이는 스프린트 지속 시간 또는 그와 유사한 기간이 될 수 있다.

정규 스프린트가 시작될 때 아키텍처가 준비되지 않은 경우 어떻게 될지 궁금 할 것이다. 글쎄, 그래도 괜찮다. 실제로 준비되지 않았을 수 있다. 그리고 그것 또한 괜찮다. 소프트웨어 아키텍처는 지속적으로 진행되는 프로세스이다. 이것은 시스템의 골격이므로 항상 되돌아와 수정해야한다. 당신의 아키텍처가 필요한 것을 충분히 지원하지 않는다면 시스템을 개발할 여유가 없다. 사이먼 브라운(Simon Brown)의 말을 인용해 보자 :

 

기민한 팀(Agile Team)이 반드시 기민한 소프트웨어 아키텍처(Agile Software Architecture)를 만들지는 않는다.
그러나 좋은 아키텍처는 기민성(Agility)을 가능하게한다.

 

관리 원칙

우리가 사는 세상은 복잡하며 모든 비즈니스 영역도 마찬가지이다. 소프트웨어 아키텍처를 구축 할 때는 처음부터 작업을 너무 복잡하게하면 결과적으로 오류가 발생하기 쉽다. 의사 결정시 두 가지 원칙이 사실상의 표준이되었다.

 

  • 바보야, 단순하게 해 (Keep It Simple, Stupid. KISS)
  • 넌 그것을 필요로하지 않을 거야 (Your Aren't Gonna Need It. YAGNI)

이 두 가지 원칙이 지키려고 하는 것이 바로 그 순간에 특정 기능이나 결정이 필요한지 생각하게 하는 것이다. 나중에 결정을 연기 할 수 있다면 아키텍처를 단순하게 유지하여 더 오랜 시간 동안 쉽게 관리 할 수 ​​있다. 소프트웨어 아키텍처가 복잡 해지는 일반적인 방법 중 하나는 추상화를 도입하는 것이다. 이 형식은 데이터를 한 형식으로 복사하여 다른 형식으로 변환하는 새로운 고급 레이어 일 수도 있고, 코드 100 % 테스트 가능하게 하기 위해 많은 클래스, 인터페이스, 팩토리 등을 생성하는 것일 수도 있다. .

 

그러나, 이 두 가지 원칙을 적용 할 때 한 가지 함정은 우리가 마지막 순간까지 모든 것을 지연시키는 경향이 있다는 것이다. 그때에는 필요한 변경을 구현하기가 이미 너무 어려워 졌을 수 있다. 대신 우리의 임무는 훨씬 더 어렵다. 왜냐하면:

 

우리는 마지막 순간이 아닌 가장 적정한 시간(Most Responsible Time)에 결정을 내려야 하기 때문이다 

 

구조적 결정을 내리려고 할 때, 결정의 확실성이 높은 경우, 일반적으로하는 일이 시간이 많이 걸리지 않는 작은 준비를하는 것이다. 나는 또한 동료들과 상의하고 함께 토론한다.

 

실제 상황의 고통

온라인 페리 티켓 판매에 관한 프로젝트를 진행하고 있었다. 다른 4 개의 타사 시스템과 통신해야했기 때문에 복잡한 시스템이었다. 처음에는 주로 사용자 스토리를 기반으로 기능을 구현하는 데 중점을 두었다. 우리는 정교한 캐싱 메커니즘이 필요하다는 것을 알고 있었지만 그 순간에 필요하지 않았기 때문에 이를 지연시켰다. 당시 사용자 스토리에 집중해야 했다. 그러나 나중에 다른 타사 시스템과의 광범위한 통신으로 인해 시스템 속도가 느려졌다. 우리는 다른 선택의 여지 없이 사용자 스토리에 대한 작업을 중단하고 캐싱 메커니즘에 초점을 맞추어야 했다. 그 때에는 이미 구현하기가 어려웠다.

문서를 작성하는 방법

워터폴 접근 방식은 단계 간에 정보를 전송하는 데 문서가 사용되므로 각 단계에 관련된 사람들이 광범위하게 문서를 작성해야한다. 이 작업은 시간이 많이 걸리는 프로세스 일뿐만 아니라 잘못 설명된 기능으로 인해 오해로 이어질 수 있다. 또한 개발 속도가 빨라지면, 문서가 더 이상 이를 반영하지 않기 때문에 문서를 최신 상태로 유지하기가 어렵다. 코드 작성하기 위해 반복(Iteration)을 하는 애자일 접근법을 사용하면, 문서 작성도 유사하게 수행할 수 있다. 우리는 시스템의 중요한 측면만을 설명하고 시작한 다음 필요할 때 지속적으로 더 많은 정보를 추가한다.

 

문서화 내용(What to Document)

동일한 형식을 여러 형식으로 여러 번 문서화하지 말자. 예를 들어 코드에서 다이어그램을 생성하는 데 도움이되는 도구가 있다. 이 도구는 사용되지 않는 경향이 있으므로 별도의 다이어그램을 만드는 대신 매우 편리 할 수 ​​있다. 또한 시스템의 특정 측면을 설명하기 위해 시각적 산출물을 작성한 경우 단어로 동일한 내용을 설명하는 광범위한 텍스트 문서를 작성할 필요가 없다 (세부 사항을 추가하지 않으면 시각적으로 표현할 수 없음). 여기서 중요한 점은 당신과 당신의  팀은 사용 된 도면 표기법에 대한 일반적인 이해가 필요하다는 것이다.

 

문서화하는 방법

소프트웨어 아키텍처를 문서화 할 때 UML이 최선의 방법이라고 생각할 수 있다. UML은 표준이며 모든 사람이 알고 있으며 대학에서 이를 가르치므로 조직의 모든 사람을 통합할 수있는 도구 중 하나다. 내 경험에 따르면 실제로 UML을 사용하는 사람은 거의 없다. 그 이유 중 하나는 다른 관점에서 시스템을 설명하는 많은 방법이 있기 때문에 정기적으로 사용하지 않으면 좌절 할 수 있습니다.

애자일 세계에서 소프트웨어 아키텍처를 문서화하기위한 특정 도구는 없다. 화이트 보드 그림, Post-It 메모, 텍스트 문서, 위키 등을 사용할 수 있다 (아래 그림 참조). 실제로 2-3 개의 다른 산출물 형식만 사용하는 것이 더 안전하다. 그렇지 않으면 해당 형식을 저장하고 정보를 검색하기가 어려워 질 수 있습니다. 예를 들어, 그림을 그린 후에 화이트 보드 사진을 찍어야 디지털 버전의 다이어그램을 만들 수 있다. 그러나 나중에 편집해야하는 경우 디지털 방식으로 편집 할 것인지 화이트 보드에 다시 그릴 것인지 새 사진을 찍을 것인지 선택해야한다.

화이트 보드 도면 및 포스트잇 형태의 문서

 

결론

소프트웨어 아키텍처는 미래 시스템의 골격(Skeleton)을 정의한다. 이것은 선과 점이있는 다이어그램이 아니라 코드 자체를 포함하여 시스템 개발을 관리하는 완전한 결정 세트(Decision Set)이다. 모든 결정은 타협이므로 신중하게 고려해야 한다. 애자일 사고 방식은 요구 사항이 다소 안정적 일 것으로 예상되는 기존 워터폴 모델과 달리 프로젝트 후반에도 변화에 개방적이어야 한다. 그러나 시스템 골격의 변경이 항상 구현하기 쉽지는 않으며 개발 프로세스를 이전으로 되돌릴 수도 있다. 따라서, 마지막 순간까지 결정을 지연시키지 말고 그 시점에 필요하지 않은 것을 구현할 위험이 적더라도 가장 적정한 결정(Most Responsible Decision)을 내리는 것이 중요하다. 또한 애자일 소프트웨어 아키텍처는 모든 사람이 구축 할 수있는 지속 가능한 플랫폼을 만들기 위해 큰 그림과 "지금"을 복합적으로 혼합해야 한다.

 

번역의 결론

이 글을 읽으면서 가장 기억에 남은 문구는 가장 적정한 결정(Most Responsible Decision)이라 번역한 표현이다. 외국에 있을 때, 음주 관련 공익 광고 중에 "Drink Responsibly"라는 광고 카피가 기억에 남는다. 이는 자기가 감당할 정도로만 마셔서, 자신의 생활과 관계를 잘 유지할 수 있도록 하자는 뜻이라고 한다. 나는 이와 일맥 상통한다고 생각했다. 즉, 구조적 결정을 하는 시간과 범위를 가능한 미루는 것이 아니고 알맞고 발라야 한다는 것이다.

 

또한, 토론에 대한 언급도 좋았다. 나는 애자일 접근법이 소통으로 이루어 지는 부분이 매우 훌륭하다고 생각한다. 특히, 애자일 12원칙 중 "최고의 아키텍처, 요구사항, 설계는 자기 조직적인 팀에서 창발한다."라는 구절을 매우 좋아 한다. 창발은 팀의 원할한 소통에서 나올 수 있다. 그러므로, 소통이 없는 팀에서는 좋은 아키텍쳐가 나오기 어렵다.

 

아쉬운 부분은 절차에 대한 이야기가 있지만, 어떻게 구조적 결정을 해야 하는지에 대한 기술적인 방법(Technical Method)에 대해서는 설명이 없다는 것이다. 이러한 부분은 아직 Design Pattern, Architectural Style, Aspect Driven Design(ADD) 혹은 AD를 활용해야 하는 것인지도 모르겠다. 이 부분은 숙제로 남겨두고 고민해도 좋겠다.

 

참고 문헌

[1] Boyan Mihaylov, "Towards an Agile Software Architecture," https://www.infoq.com/articles/towards-agile-software-architecture/?p13nId=6817&p13nType=followTopic#

 

+ Recent posts