[소프트웨어아키텍처] 파트1
1장. 서론
아키텍트에 대한 기대치
소프트웨어 아키텍트에 바라는 핵심적인 요구사항은 다음 여덟가지로 정리 가능하다
- 아키텍쳐 결정을 내린다
- 아키텍트는 기술 선택을 가이드하는 사람이지 정해주는 사람은 아니다
- 아키텍처 결정과 설계 원칙을 통해 기술 선택을 가이드 하는 일은 생각보다 어렵다
- 아키텍처를 지속적으로 분석한다
- 끈임없이 아키텍처와 현재 기술 환경을 분석하고 개선하기 위한 해결 방안을 제시한다
- 대부분 아키텍처 구조는 쇠락하는 양상을 보인다
- 특히 성능, 가용성, 확장성 등 필수 아키텍처 특성에 영향을 미치는 코드를 작성하거나 변경할때 나타난다
- 최신 트렌드를 계속 따라간다
- 최신 기술과 업계 트렌드를 따라가야 한다
- 아키텍처 결정의 컴플라이언스를 보장한다
- 컴플라이언스 보장이란, 아키텍트가 정의하고 문서화하여 전달한 아키텍처 결정과 설계 원칙들을 개발팀이 제대로 준수하고 있는지 지속적으로 확인하는 것이다
- 다양한 기술과 경험에 노출된다
- 다양한 기술, 프레임워크, 플랫폼, 환경에 노출되어야 한다
- 모든것에 통달해야 할 필요는 없지만, 다양한 기술을 거리낌 없이 쓸 줄 알아야 한다
- 익숙한 영역을 점점 넓혀가는 것이 좋고, 한가지 기술이나 플랫폼에만 올인하는 것은 안일한 태도이다
- 비즈니스 도메인 지식을 보유한다
- 어느 수준 이상의 비즈니스 도메인 전문가여야 한다
- 유능한 아키텍트는 기술은 물론이고 문제 영역의 비즈니스 도메인도 잘 알고 있다
- 비즈니스 도메인 지식이 없으면 효율적인 아키텍처를 설계하기 어렵다
- 대인관계 기술이 뛰어나다
- 팀워크, 조정, 리더십을 포함한 대인 관계 기술이 뛰어나야 한다
- 기술자는 천성이 기술적인 문제 해결을 좋아해서, 사람에 관한 문제에는 크게 관심이 없다
- 하지만 리더십 스킬을 아키텍트로서 성공하기 위한 필수 조건이다
- 정치를 이해하고 처세를 잘한다
- 아키텍트가 내린 거의 모든 결정은 반발에 부딪히기 마련이다
- 각 이해 담당자들과 부딪힐 수 밖에 없고, 이런 상황에서 이해관계자들이 결정을 수용하도록 협상 기술을 발휘해야 한다
소프트웨어 아키텍처 법칙
소프트웨어 아키텍처 1법칙 : 소프트웨어 아키텍처의 모든 것은 다 트레이드 오프다
그 어느것도 깔끔하게 딱 맞아 떨어지는 것은 없다. 모든 결정은 여러 상충되는 팩터들을 고려해야 한다
2장. 아키텍처 사고
아키텍처의 사고 방식은 크게 네 가지로 나뉜다
- 아키텍처와 설계의 차이를 이해하고 개발팀과 어떻게 협력해야 하는지 아는것
- 어느 정도의 기술 깊이를 유지하며 폭넓은 기술 지식 확보
- 다양한 솔루션과 기술 간의 트레이드오프를 이해, 분석, 조율
- 비즈니스 동인의 중요성을 이해하고, 아키텍처 관심사로 해석할 줄 아는것
아키텍처 대 설계
어디까지가 아키텍처이고 어디부터 설계일까?
아키텍트가 하는 일과 개발자가 하는 일은 어떻게 다를까?
결론부터 말하면 그런 경계는 따로 없다
하지만 전통적인 아키텍트와 개발팀은 단방향 소통을 하여,
아키텍트가 내린 결정이 개발팀에서 전혀 쓸모가 없는 경우가 있음에도 불구하고 아키텍트에게 다시 전달되는 일은 거의 없다.
아키텍트가 개발팀과 완전히 단절되어 있기 때문에 원래 의도했던 아키텍처는 점점 요원해진다.
제대로 된 아키텍처를 만들려면 반드시 두 팀이 양방향으로 소통하는 관계를 정립해야 한다
요즘 시스템 아키텍처는 매 프로젝트 단계마다, 또는 매 이터레이션 마다 끊임없이 변화하고 발전하기 때문에 아키텍트와 개발팀이 뭉쳐서, 프로젝트 생명 주기의 일부로서 서로 동기화 되어야 한다
기술 폭
기술 세부의 범위 또한 개발자와 아키텍트가 다르다.
업무를 진행하기 위해 기술 깊이를 확호해야 하는 개발자와 달리, 아키텍트는 아키텍트답게 사고하고 아키텍처 시각을 유지하기 위해 상당한 기술 폭을 갖춰야 한다.
어떤 사람이 갖고 있는 지식은 '내가 알고 있는 것', '내가 모른다는 사실을 아는 것', '내가 모른다는 사실조차 모르는 것' 으로 분류할 수 있다.
개발 초심자 시절에는 이 피라미드의 꼭대기를 점점 넓혀 경험과 전문성을 쌓는 데 주력한다.
전문적인 기술은 중요하기 때문에 피라미드 꼭대기를 넓히는 건 이롭지만, 내가 알고 있는 것은 내가 계속 유지해야 할 것 이기도 하다.
소프트웨어의 그 어떤 것도 가만히 있지 않기 때문에, 시간을 들여서 전문성을 유지해야 하고, 피라미드 꼭대기의 크기가 그 사람의 기술의 깊이다
개발자가 아키텍트로 진로를 바꾸면 지식의 성격이 달라진다.
아키텍트의 가치는 대부분 기술에 대한 폭넓은 이해와 기술을 사용해서 특정한 문제를 해결하는 것이다.
즉 아키텍트는 어느 한 가지 문제만 해결 가능한 한 가지 전문 지식보다는, 문제를 해결할 수 있는 다섯 가지 솔루션을 알고 있는게 더 중요하다.
아키텍트에게는 깊이보다 폭이 더 중요하고, 기술적인 제약 하에 어떤 기능이 알맞을지 결정해야 하므로 폭넓은 솔루션을 두루 꿰고 있어야 한다. 이 과정에서 기존의 기술 깊이는 희생할수도 있다.
지식 피라미드는 아키텍트의 역할과 개발자의 역할이 어떻게 다른지 보여주는데, 개발자가 아키텍트로 전환할때 역효과가 일어난다.
첫째, 아키텍트가 되어 다양한 분야에서 전문성을 유지하려고 하나, 어느 하나도 성공하지 못한 채 지쳐버린다.
둘째, 김빠진 전문성이 나타난다. 자신의 낡은 정보가 아직도 첨단을 달리고 있는 것처럼 그릇된 인식에 사로잡힌다.
트레이드 오프 분석
아키텍트처럼 생각하는 것은 기술 여부와 상관없이 모든 솔루션의 트레이드오프를 분석하여 최선의 솔루션을 결정하는 것이다.
아키텍처는 모든게 다 트레이드 오프이다. 배포 환경, 비즈니스 동인, 회사 문화, 예산, 기간, 개발자 스킬 셋등 여러 팩터들이 영향을 미친다.
비즈니스 동인 이해
성공적인 시스템구축에 필요한 비즈니스 동인을 이해하고 요구사항을 아키텍처 특성으로 해석해야 한다.
따라서 어느 정도의 비즈니스 도메인 지식을 갖고서 비즈니스 핵심 인사들과 원만하고 협력적인 관계를 유지해야 한다
아키텍처와 코딩 실무 간 균형 맞추기
코딩 실무와 소프트웨어 아키텍처의 균형을 맞추는 것도 아키텍트가 극복해야 할 어려운 일중 하나다.
아키텍트는 병목 트랩에 빠져선 안된다. 아키텍트가 프로젝트의 크리티컬 패스에 있는 코드의 소유권을 갖고 있는 경우 발생한다.
아키텍트는 풀타임 개발자가 아니므로 개발자 역할과 아키텍트 역할의 균형을 잘 맞춰야 한다
만약 아키텍트가 개발팀과 함께 개발을 할수 없다면 어떻게 실무 능력을 잃지 않으며 일정 수준의 기술 깊이를 유지할 수 있을까?
첫째, 개념 증명 (POC) 를 자주 해본다
POC는 아키텍트가 소스 코드를 작성하며 구현 상세를 생각하게 되므로 아키텍처 결정을 검증하는 데 유용하다.
POC 작업을 할때엔 가능한 프로덕션 수준의 고품질 코드를 작성하는게 좋다
둘째, 개발팀이 중요한 유저 스토리 작업을 할 수 있도록 기술 부채 스토리나 아키텍처 스토리에 전념한다.
보통 우선순위가 낮기 때문에 이터레이션 내에 아키텍트가 끝내지 못한다 해도 괜찮다.
셋째, 버그를 잡는 일 역시 실무 능력을 유지하기에 좋은 방법이다
간단한 커맨드라인 도구나 분석기를 만들어 개발팀의 일상 업무를 간소화, 자동화 하는 것도 좋은 방법이다.
마지막으로, 자주 코드 리뷰를 하는 것이다.
3장. 모듈성
소프트웨어 시스템은 엔트로피(무질서)가 증가하는 방향으로 움직이는 복잡한 시스템을 모델링 한다
아키텍트는 끊임없이 에너지를 소비해서 시스템을 구조적으로 탄탄하게 유지해야 한다.
정의
클래스, 함수처럼 코드를 묶어 놓은 덩어리를 모듈성이라는 일반적인 용어로 나타낸다.
이것은 논리적인 구분이지 물리적인 구분은 아닌데, 이 차이가 중요한 경우가 있다.
모놀리식 애플리케이션은 편의상 꽤 많은 클래스를 한 덩어리로 묶어도 크게 상관없지만, 아키텍처를 재구축할 때에는 이렇게 커플링된 구조가 모놀리스를 나누는 데 걸림돌이 된다
모듈성은 특정 플랫폼에 함축되어 있거나 불가피한 물리적인 분리와 다른 개념으로 보는게 좋다
모듈성 측정
응집
응집은 한 모듈의 파트가 동일한 모듈 안에 얼마나 포함되어 있는지를 나타낸다.
모듈을 구성하는 파트가 서로 얼마나 연관되었는지를 의미한다.
- 기능적 응집
- 모듈의 각 파트는 다른 파트와 연관되어 있고 기능상 꼭 필요한 모든 것이 모듈에 들어잇다
- 순차적 응집
- 두 모듈이 한쪽이 데이터를 출력하면 다른 한쪽이 입력 받는 형태로 상호작용한다
- 소통적 응집
- 두 모듈이 각자 정보에 따라 작동하고 어떤 출력을 내는 형태로 통신 체인을 형성한다
- 예를들어, 데이터베이스에 레코드를 추가하면 그 정보에 따라 이메일이 만들어지는 식이다
- 절차적 응집
- 두 모듈은 정해진 순서대로 실행되어야 한다
- 일시적 응집
- 모듈은 시점 의존성에 따라 연관된다.
- 예를 들어, 많은 시스템들이 시동할 때 관련이 없어 보이는 것들을 쭉 초기화 하는 경우
- 논리적 응집
- 모듈의 내부 데이터는 기능적이 아닌논리적으로 연관되어 있다
- 동시적 응집
- 같은 소스 파일 모듈 구성 요소가 있지만, 그 외에는 아무 연관성이 없다
위 응집은 아래로 갈수록 좋지 않다
커플링
코드베이스 커플링은 그래프 이론에 기반한 좋은 분석 도구들이 많다
구심 커플링은(컴포넌트, 클래스, 함수 등) 코드 아티팩트로 유입되는 접속수,
원심 커플링은 다른 코드 아티팩트로 유출되는 접속 수를 나타낸다.
커네이선스
구심/원심 커플링 메트릭을 더욱 발전시킨 커네이선스란 개념이 있다.
두 컴포넌트 중 한쪽이 변경될 경우 다른 쪽도 변경해야 전체 시스템의 정합성이 맞는다면 이들을 커네이선스를 갖고 있는 것이다
커네이선스는 정적 커네이선스와 동적 커네이선스로 분류한다
정적 커네이선스
소스 코드 레벨의 커플링이다
- 명청 커네이선스
- 여러 컴포넌트의 엔티티명이 일치해야 한다
- 타입 커네이선스
- 여러 컴포넌트의 엔티티 타입이 일치해야 한다
- 의미 커네이선스 또는 관례 커네이선스
- 여러 컴포넌트에 걸쳐 어떤 값의 의미가 일치해야 한다
- 위치 커네이선스
- 여러 컴포넌트는 값의 순서가 일치해야 한다
- 알고리즘 커네이선스
- 여러 컴포넌트는 특정 알고리즘이 일치해야 한다
동적 커네이선스
런타임 호출을 분석하는 또다른 유형의 커네이선스다
- 실행 커네이선스
- 여러 컴포넌트는의 실행 순서가 중요하다
- 시점 커네이선스
- 여러 컴포넌트의 실행 시점이 중요하다
- 값 커네이선스
- 상호 연관된 다수의 값들을 함께 변경할 때 발생한다
- 식별 커네이선스
- 여러 컴포넌트가 동일한 엔티티를 참조할 때 발생한다
90년대 커네이선스의 문제점
이들 메트릭은 아키텍처 구조보단 저수준 코드의 세부분을, 코드 품질 및 정리 상태 위주로 관찰한다.
아키텍트 입장에서는 커플링 정도보다 모듈이 어떻게 커플링 되어 있는지 궁금한데, 이것이 어떻게 구현되어 있는지는 관심사가 아니다.
그리고 커네이선스는 요즘의 아키텍트가 내려야 할 근본적인 결정에 관한 문제는 다루지 않는다.
4장. 아키텍처 특성 정의
어떤 문제를 소프트웨어로 해결하려면 아키텍트는 먼저 시스템 요구사항을 취합하고 구현하는 데 필요한 다양한 기술을 소프트웨어 개발 프로세스에 따라 정리한다
소프트웨어 아키텍처와 코딩, 설계는 어떤 차이가 있을까? 아키텍처 특성을 정의하는 아키텍트의 역할부터 문제 영역 및 시스템 등 중요한 부분까지 많은 부분이 다르다.
보통 회사에서는 이런 소프트웨어 특성을 비기능 요구사항이라고 표헌하지만, 이런 스스로의 가치를 깎아내리는 용어를 좋아하지 않는다.
성공적인 아키텍처 구축에 중차대한 관심사임을 나타내고, 시스템을 전체적으로 바라보며 그 중요성을 폄하하지 않는 아키텍처 특성이라는 용어를 선호한다.
아키텍처 특성은 다음 세 가지 기준을 충족한다
비도메인 설계 고려 사항을 명시한다
애플리케이션으로 처리할 일은 구체적인 요구사항으로 정리한다.
아키텍처는 이 요구사항을 구현하는 방법, 어떤 선택을 하게 된 이유와 관련된 운영/설계 기준을 명시한다
설계의 구조적 측면에 영향을 미친다
아키텍처 특성을 기술하는 주된 이유는, '이 아키텍처 특성은 어떤 특별한 구조적 요소를 고려해야 하는가?' 하는 설계 고려 사항 때문이다.
애플리케이션 성공에 절대적으로 중요하다
애플리케이션이 무수히 많은 아키텍처 트특성을 전부 지원할 수도 있지만, 그러면 안된다.
가급적 아키텍처 특성을 적게 선정하는 일도 아키텍트의 중요한 책무이다
아키텍처 특성 일부 목록
운영 아키텍처 특성
가용성, 연속성, 성능, 복구성, 신뢰성/안정, 견고성, 확장성
구조 아키텍처 특성
설정성, 신장성, 설치성, 활용성/재사용, 지역성, 유지보수성, 이식성, 지원성, 업그레이드성
아키텍처 공통 특성
접근성, 보관성, 인증, 인가, 합법성, 프라이버시, 보안, 사용성/성취성
트레이드오프 및 나쁜 것 중에서 제일 나은 아키텍처
시스템을 설계하며 모든 아키텍처 특성을 빠짐없이 최상으로 반영하기란 불가능에 가깝다.
상충되는 여러 문제들이 뒤얽힌 트레이드오프로 귀결되는 경우가 많다.
아키텍처 특성을 너무 욕심내면 모든 비즈니스 문제를 해결하려고 시도하는 일반적인 솔루션이 되어버린다.
그런 아키텍처는 설계하기가 대단히 까다롭기 때문에 실현 가능성이 낮다
5장. 아키텍처 특성 식별
아키텍처를 구축하거나 기존 아키텍처의 타당성을 검증할 때 제일 먼저 해야 할 일은 아키텍처 특성을 식별하는 것이다.
주어진 문제 영역이나 애플리케이션에서 아키텍처 특성을 정확히 식별하기 위해 해당 도메인을 잘 이해하고 있어야 하며, 도메인 이해관계자들과 협력하여 도메인 관점에서 정말 중요한 것들을 결정해야 한다.
도메인 관심사에서 아키텍처 특성 도출
아키텍처에서 가장 흔한 안티패턴 중 하나는, 모든 아키텍처 특성을 지원하는 제네릭 아키텍처를 설계하려는 것이다
너무 많은 아키텍처 특성을 수용하면, 당초 의도했던 문제 영역의 해결을 시도하기도 전에 아키텍처가 너무 복잡해진다
아키텍트의 임무는 도메인 요구사항을 충족하는 전체 시스템을 코드 레벨로 설계하는 것이 아니다.
설계, 특히 구조와 관련이 있거나 영향을 미치는 것들을 찾아내는 것이다. 우선 아키텍처 특성이 될 만한 것들을 명시적인 것과 암묵적인 것으로 분류한다.
명시적 특성
명시적 아키텍처 특성은 요구사항 정의서에 기술 된다.
아키텍트가 가장 먼저 눈여겨 봐야 할 부분은 유저 수이다.
암묵적 특성
요구사항 정의서에 따로 없는 특성도 있지만 이들은 중요한 설계 요소가 된다.
대표적으로 가용성, 신뢰성, 보안 등이 있다.
8장. 컴포넌트 기반 사고
아키텍처 분할
소프트웨어 아키텍처 제1법칙에 따르면 소프트웨어는 만사가 다 트레이드 오프다. 컴포넌트를 만드는 방법도 다양하다
서로 다른 아키텍처 패턴 간의 근본적인 차이점 중 하나는 개별 패턴을 다루는 최상의 분할의 유형이다.
최상의 분할 유형은 기술적 분할/도메인 분할로 나눌 수 있다.
도메인 분할
도메인 분할 아키텍처는 최상위 컴포넌트를 도메인에 따라 나눈다.
장점
- 세부 구현보다 비즈니스 기능에 더 가깝게 모델링 된다
- 도메인별 다목적팀을 구성하기 쉽다
- 모듈러 모놀리스와 마이크로서비스 아키텍처 스타일에 더 가깝게 맞출 수 있다
- 메시지 흐름이 문제 영역과 일치한다
- 데이터와 컴포넌트를 분산 아키텍처로 옮기기 쉽다
단점
- 유저 정의 코드가 여기저기 널려 있다
기술 분할
최상위 아키텍처를 기술적인 능력에 따라 분리하므로 MVC 또는 상황에 맞게 분할된 레이어로 나눈다.
장점
- 커스텀 코드가 명확하게 분리된다
- 레이어드 아키텍처 패턴에 더 가깝게 맞출 수 있다.
단점
- 전역 커플링이 더 높다. 공통 또는 로컬 컴포넌트 중 하나라도 변경되면 다른 모든 컴포넌트가 영향을 받을 가능성이 높다
- 공통 레이어, 로컬 레이어 양쪽에 도메인 개념을 복제해야 할 수도 있다
- 일반적으로 데이터 레벨의 커플링이 높다. 나중에 분산 시스템 아키텍처로 옮기려고 할 경우 데이터 관계를 파헤치는 작업이 어렵다.
컴포넌트 식별 흐름
컴포넌트 식별은 후보를 도출하고 피드백을 통해 다듬어가는 과정을 반복하는 것이 좋다.
초기 컴포넌트 식별
프로젝트의 소스코드가 생기기 전에 적용할 최상위 분할의 유형에 따라 최상위 컴포넌트를 어디서 시작할지 결정한다.
원하는 컴포넌트를 자유롭게 구성하며 어느 기능을 어디에 둘지 도메인 기능을 맵핑한다
요구사항을 컴포넌트에 할당
초기 컴포넌트 식별 후 컴포넌트에 요구사항을 대입해 잘 맞는지 확인한다.
이 과정에서 컴포넌트를 새로 만들거나, 기존 컴포넌트를 통합하고, 하는 일이 너무 많은 컴포넌트는 분해할 수 있다
역할 및 책임 분석
컴포넌트에 스토리를 대입할 때 요구사항을 파악하는 단계에서 밝혀진 역할과 책임도 살펴보고 세분도가 적합한지 확인한다
아키텍처 특성 분석
앞서 식별한 아키텍처 특성들이 컴포넌트 분할 및 세분도에 어떤 영향을 미치는지 살펴본다
컴포넌트 재구성
소프트웨어 설계에서 피드백은 핫앙 중요하다. 지속적으로 컴포넌트 설계를 반복해야 한다
추후 재설계를 하게 만들지 모를 모든 발견과 특이 사례를 전부 다 고려하기란 사실상 불가능 하다
컴포넌트 세분도
적당한 세분도를 찾는 것은 가장 어려운 작업 중 하나다.
너무 잘게 나누어 설계하면 컴포넌트간 통신이 너무 많아지고, 너무 크게 나누면 내부적으로 커플링이 증가하여 배포, 테스트가 어려워지고
모듈성 관점에서도 부정적인 영향을 미친다
컴포넌트 설계
컴포넌트 설계에 있어 왕도는 없다