5부 15장 아키텍처란
소프트웨어 아키텍처란 무엇인가? 소프트웨어 아키텍트는 무슨일을 하는가?
소프트웨어 아키텍트는 코드와 동떨어져서는 안된다. 계속 프로그래머로 남는다. 코드에서 탈피하여 고수준의 문제에 집중해야한다는 거짓말에 절대 속아넘어가서는 안된다.
앞으로도 계속 프로그래밍 작업을 할 뿐만아니라, 나머지 팀원들이 생산성을 극대화할 수 있는 설계를 하도록 방향을 이끌어 준다.
다른 프로그래머 만큼 코드를 많이 작성하지 않을 수도 있지만, 프로그래밍 작업에는 지속적으로 참여한다. 프로그래밍 작업을 계속 하지 않으면, 발생하는 문제를 경험해보지 못하게 되고, 다른 프로그래머를 지원하는 작업을 제대로 수행할 수 없다.
소프트웨어 시스템 아키텍처란 시스템을 구축했던 사람들이 만들어낸 시스템의 형태이다.
- 모양이 정해지는 방식 : 시스템을 컴포넌트로 분할하는 방법, 분할된 컴포넌트를 배치하는 방법, 컴포넌트가 서로 의사소통하는 방식에 따라 정해진다.
- 형태 : 아티텍처 안에 담긴 소프트웨어 시스템이 쉽게 개발 배포, 운영, 유지보수되도록 만들어진다.
“이러한 일을 용이하게 만들기 위해서는 가능한 한 많은 선택지를, 가능한 한 오래 남겨두는 전략을 따라야한다.”
형편없는 아키텍처를 갖춘 시스템은 배포, 유지보수, 계속되는 개발 과정에서 어려움을 겪게 된다.
아키텍처의 주된 목적은 시스템의 생명주기를 지원하는 것이다. 좋은 아키텍처는 시스템을 쉽게 이해하고, 쉽게 개발하며, 쉽게 유지보수하고, 또 쉽게 배포하게 해준다.
아키텍처의 궁극적인 목표는 시스템의 수명과 관련된 비용은 최소화하고, 프로그래머의 생산성은 최대화하는데 있다.
개발
시스템 아키텍처는 개발팀들이 시스템을 쉽게 개발할 수 있도록 뒷받침해야한다.
팀 구조에 따라 아키텍처도 차이가 있다.
- 개발자 5명으로 구성된 팀 : 모노리틱(통짜 구조) 시스템으로 개발할 수 있다. 개발 초기에는 아키텍처 관련 제약들이 오히려 방해된다고 여기기 쉽다. 팀 규모가 작고 상위 구조로 인한 장애물이 없기를 바라기 때문이다.
- 7명씩 구성된 팀이 5팀 : 시스템을 신뢰할 수 있고, 안정된 인터페이스를 갖춘, 잘 설계된 컴포넌트 단위로 분리하지 않으면 개발이 진척되지 않는다. 다섯개의 컴포넌트로 발전할 가능성이 높다(각 팀마다 하나씩), 팀별 단일 컴포넌트 아키텍처가 최적의 아키텍처일리 없다.
배포
배포 비용이 높을수록 시스템 유용성은 떨어진다.
소프트웨어 아키텍처는 시스템을 단 한 번에 쉽게 배포할 수 있도록 만드는 데 그 목표를 두어야한다.
초기 개발 단계에서는 배포 전략을 거리 고려하지 않는다. 이로인해 개발은 쉬울지 몰라도 배포하기는 상당히 어려운 아키텍쳐가 만들어진다.
예) 초기 개발자가 ‘마이크로서비스 아키텍처’를 사용하자고 결정하였다고 가정, 이 접근법을 사용하면 컴포넌트 경계가 뚜렷해지고 인터페이스가 대체로 안정화되므로 시스템을 매우 쉽게 개발할 수 있다고 판단했을지도 모른다. 하지만 배포 시기가 되면 위협적일 만큼 늘어난 수많은 마이크로서비스를 발견하게 될지도 모른다. 마이크로서비스들을 서로 연결아기 위해 설정하고 작동순서를 결정하는 과정에서 오작동이 발생하게 만드는 원인을 제공할 수 있다.
초기에 배포문제를 고려했다면 더 작은 서비스를 사용하고, 서비스 컴포넌트와 프로세스 수준의 컴포넌트를 하이브리드 형태로 융합하여 좀 더 통합된 도구를 사용하여 상호 연결을 관리했을 것이다.
운영
아키텍처가 시스템 운영에 미치는 영향은 개발, 배포, 유지보수보다 덜 극적이다. 운영에서 겪는 대다수의 어려움은 하드웨어를 단순히 더 투입해서 해결할 수 있다.
소프트웨어 시스템의 아키텍쳐가 비효율적이라면 단순히 스토리지와 서버를 추가하는 것만으로 제대로 동작하게 만들 수 있을 때가 많다.
운영을 방해하는 아키텍처가 개발, 유지보수를 방해하는 아키텍쳐보다는 비용이 덜 든다.
그렇더라도 좋은 소프트 웨어 아키텍처는 시스템을 운영하는 데 필요한 요구를 알려준다. 시스템 아키텍쳐가 개발자에게 시스템의 운영 방식을 잘 드러내 준다고 할 수 있다. 유즈케이스, 기능, 시스템의 필수 행위를 일급(first-class)엔티티로 작성하고 이들이 개발자에게 주요 목표로 인식되도록 해야한다. 이를 통해 시스템을 이해하기 쉬워지며 따라서 개발과 유지보수에 큰 도움이 된다.
유지보수
소프트웨서 시스템에서 비용이 가장 많이 드는 것이 유지보수이다.
기존 소프트웨어에서 새로운 기능을 추가하거나 결함을 수정할 때 소프트웨어를 파해쳐서 어디를 고치는 게 최선인지, 그리고 어떤 전략을 쓰는 것이 최적일지를 결정(=탐사 spelunking)할 때 드는 위험부담이 유지보수의 가장 큰 비용이다.
주의를 기울여 신중하게 아키텍쳐를 만들면 이 비용을 줄일 수 있다. 시스템을 컴포넌트로 분리하고 안정된 인터페이스를 두어 서로 격리하면 미래에 추가될 기능에 대한 길을 밝혀 둘 수 있을 뿐아니라 의도치 않은 장애가 발생할 위험을 크게 줄일 수 있다.
선택사항 열어두기
소프트웨어는 행위적 가치와 구조적 가치를 지닌다.
구조적 가치는 소프트웨어를 부드럽게 만들기 때문에 더 중요하다.
소프트웨어를 부드럽게 유지하는 방법은 선택사항을 가능한 한 많이, 오랫동안 열어두는 것이다.
모든 소프트웨어 시스템은 주요한 두 가지 구성요소로 분해할 수 있다. : 정책과 세부사항이다.
- 정책 : 모든 업규 규칙과 업무 절차를 구체화한다. 시스템의 진정한 가치가 살아있는 곳이다.
- 세부사항: 사람, 외부 시스템 프로그래머가 정책과 소통할 때 필요한 요소지만, 정책이 가진 행위에는 조금도 영향을 미치지 않는다. 입출력 장치, 데이터 베이트, 웹 시스템, 서버, 프레임워크, 통신 프로토콜 등이 있다.
아키텍트의 목표 : 시스템에서 정책을 가장 핵심적인 요소로 식별하고, 동시에 세부사항은 정책에 무관하게 만들 수 있는 형태의 시스템을 구축하는 데 있다.
예시)
- 개발 초기에는 데이터베이스 시스템(관계형, 분산형, 계층형, 플랫 파일)을 선택할 필요가 없다.
- 고수준의 정책은 어떤 디비를 사용하는지 관련없도록 만들어야한다.
- 개발 초기에는 웹 서버를 선택할 필요가 없다.
- 고수준의 정책은 자신이 웹을 통해 전달된다는 사실을 알아서는 안된다. HTML, AJAX, JSF같은 기술들에 대해 고수준의 정책이 전혀 알지 못하게 만들면 프로젝트 후반까지는 어떤 종류의 웹 시스템을 사용할지를 결정하지 않아도 된다. 심지어는 시스템을 웹을 통해 전송할 것인지조차도 결정할 필요가 없다.
- 개발 초기에는 REST를 적용할 필요가 없다.
- 고수준의 정책은 외부 세계로의 인터페이스에 대해 독립적이거야 하기 때문이다.
- 마이크로서비스 프레임워크 또는 SOA프레임워크도 적용할 적용할 필요가 없다.
- 개발 초기에는 의존성 주입 프레임 워크를 적용할 필요가 없다. 고수준의 정책은 의존성을 해석하는 방식에 대해 신경써서는 안된다.
선택사항을 더 오래 열어둘 수 있다면 다양한 실험을 시도해볼 수 있는 선택지도 열어 둘 수 있게 된다.
“좋은 아키텍트는 결정되지 않은 사항의 수를 최대화한다.”
장치 독립성
오늘날 운영체제에서는 동일한 프로그램을 아무런 변경없이도 다양한 레코드 장치에 읽고 쓸 수 있다. 1960년대 후반에 장치 독립성을 생각해 냈다.
오늘날의 운영체제는 입출력 장치를 소프트웨어 함수로 추상화 했고, 해당 함수는 천공카드와 같은 단위 레코드를 처리한다. 프로그램은 운영체제의 서비스를 호출하고, 해당 서비스가 추상화된 단위레코드 장치를 처리한다. 그리고 오퍼레이터가 해당 추상화 서비스를 카드 판독기, 자기 테이브, 또는 다른 단위 레코드 장치중 어디에 연결해야하는 지를 운영체제에게 알려주었다.
광고 우편
장치 독립성이 지닌 가치를 확인할 수 있는 예시
물리적 주소 할당
소프트웨어가 디스크 상세 구조를 알도록 만들었다. 즉 소프트웨어는 200개의 실린더와 10개의 헤드로 구성되고 각 실린더는 헤드별로 수십 개의 섹터로 구성된다는 사실을 알게되었다. 소프트웨어는 어느 실린더가 어떤 Agent, Employer, Member를 포함하는지 알게 되었다 이 정보는 모두 하드 코딩이었다.
그리고 특정 레코드를 탐색할 수 있도록 디스크에 색인을 저장했다. ( 추가적으로 설명이 더 있음….아주 복잡하고 세부사항을 모든 규칙이 알고 있는 상황…)
어느 날 우리보다 노련한 프로그래머가 우리 조직에 합류해서 주소 할당 체계를 변경하여 상대 주소를 사용하라고 충고해 주었다.
각 섹터의 주소는 순차적인 정수를 이용해 지정할 수 있으므로 디스크를 섹터로 구성된 하나의 거대한 선형 배열로 취급할 것을 제안했다.
루틴은 디스크의 물리적 주소를 알 고 있으며, 상대 주소가 필요하면 즉시 실린더. 헤드. 섹터 번호로 변환 할 수 있었다.
시스템에서 고수준의 정책이 디스크 물리적 구조부터 독립되도록 수정했다. 그 덕분에 우리는 디스크 드라이브 구조에 대한 결정사항을 애플리케이션으로부터 분리할 수 있게 되었다.
결론
원칙은 아키텍트가 대규모 시스템에 적용할 수 있는 예를 봤다.
좋은 아키텍트는 세부사항을 정책으로부터 신중하게 가려내고 정책이 세부사항과 결합되지 않도록 엄격하게 분리한다.
정책은 세부사항에 관래 어떠한 지식도 갖지 못하게 되며, 어떤 경우에도 세부사항에 의존하지 않게된다.
좋은 아키텍트는 세부사항에 대한 결정을 가능한 오랫동안 미룰 수 있는 방향으로 정책을 설계한다.
'IT 서적 > Clean Architecture' 카테고리의 다른 글
[클린 아키텍처] 14장. 컴포넌트 결합 (4부. 컴포넌트 원칙) (0) | 2022.08.15 |
---|---|
13. 컴포넌트 응집도 (0) | 2022.05.08 |
4부 12장. 컴포넌트 (링킹로더, 링커, 컴포넌트) (0) | 2022.04.10 |
11장. DIP: 의존성 역전 원칙(Dependency Inversion Principle) (0) | 2022.03.21 |
10장. ISP: 인터페이스 분리 원칙(interface Segregation Principle) (0) | 2022.03.21 |
댓글