15. 아키텍처란?
아키텍처(architecture)라는 단어는 중대한 결정과 심도 있는 기술적 기량을 떠올리게 한다.
이 연상 작용처럼 소프트웨어 아키텍처는 기술적 성취의 정점에 서있다.
소프트웨어 아키텍트를 생각할때면, 권한을 가지며존경심을 불러일으키는 사람을 떠올린다.
그렇다면 소프트웨어 아키텍처란 무엇인가?
그리고 소프트웨어 아키텍트는 무슨 일을 하며, 언제 그 일을 하는가?
소프트웨어 아키텍트는 프로그래머이며, 앞으로도 계속 프로그래머로 남아야 한다.
프로그래밍 작업을 계속하는 이유는, 발생하는 문제를 경험해보지 않는다면 다른 프로그래머를 지원하는 작업을 제대로 수행할 수 없기 때문이다.
소프트웨어 시스템의 아키텍처란 시스템을 구축했던 사람들이 만들어낸 시스템의 형태로
시스템을 컴포넌트로 분할하는 방법, 분할된 컴포넌트를 배치하는 방법, 컴포넌트가 서로 의사소통하는 방식에 따라 그 모양이 정해진다.
그리고 그 형태는 아키텍처 안에 담긴 소프트웨어 시스템이 쉽게 개발, 배포, 운영, 유지보수되도록 만들어진다.
위의 업무들이 잘 돌아가게 만들기 위해서는 가능한 한 많은 선택지를, 가능한 한 오래 남겨두는 전략이 필요하다.
여기까지 살펴보면 소프트웨어 아키텍처의 목표가 시스템을 제대로 동작하는 데만 있는 것은 아니다.
물론 시스템이 제대로 동작하는 것은 중요하다.
다만, 시스템 아키텍처는 유일한 목표가 아닌 최우선 목표 중 하나로 취급되어야 한다.
재미있는 것은 형편없는 아키텍처를 가진 시스템이라고 할지라도 운영에서는 별 문제가 없다.
문제가 되는 부분은 운영보다는 배포, 유지보수, 계속되는 개발 과정에서 발생하는 어려움이다.
결론적으로 아키텍처의 주된 목적은 시스템의 생명주기를 지원하는 것이다.
좋은 아키텍처를 시스템을 쉽게 이해하고, 쉽게 개발하며, 쉽게 유지보수하고, 쉽게 배포할 수 있게 해준다.
아키텍처의 궁극적인 목표는 시스템의 수명과 관련된 비용은 최소화하고, 프로그래머의 생산성을 최대화하는 데 있다.
15.1. 개발
개발하기 힘든 시스템은 수명이 짧다.
따라서 시스템 아키텍처는 개발팀 혹은 개발팀들이 시스템을 쉽게 개발할 수 있도록 뒷받침해야만 한다.
팀 규모가 작다면 모노리틱(monolithic) 시스템을 개발해서 오히려 효율적인 경우를 보일 수도 있다.
이게 바로 수많은 시스템에서 아키텍처가 결여된 이유이기도 하다.
팀 규모가 크거나 많은 팀이 협업하는 경우엔 시스템을 신뢰할 수 있도록 하고, 안정된 인터페이스를 갖추고, 잘 설계된 컴포넌트 단위로 분리해야한다.
15.2. 배포
소프트웨어 시스템이 사용될 수 있으려면 반드시 배포가 수반되어야 한다.
때문에 배포의 비용이 높을 수록 시스템의 유용성은 저하된다.
따라서 소프트웨어 아키텍처는 시스템을 단 한 번에 쉽게 배포할 수 있도록 만드는 데 그 목표를 두어야 한다.
안타깝게도 초기 개발 단계에서는 배포 전략이 거의 고려되지않는다.
이는 초기에 쉬운 개발 환경을 제공해주지만, 배포하기에는 상당히 어려운 아키텍처로 수렴하는 결과를 낳는다.
예를 들어 마이크로서비스 아키텍처를 초기부터 적용하는 경우, 뚜렷한 컴포넌트의 경계와 안정된 인터페이스로 쉬운 개발을 진행할 수 있다.
하지만 이후 배포시기가 되면 수많은 마이크로서비스를 배포해야하는 경우가 발생할 수 있다.
위의 문제를 초기부터 고려했다면 서비스를 더 적게 사용하고, 서비스 컴포넌트와 프로세스 수준의 컴포넌트를 하이브리드 형태로 융합하며,
좀 더 통합된 도구를 사용해 상호 연결을 관리했을 것이다.
15.3. 운영
아키텍처가 시스템 운영에 미치는 영향을 개발, 배포, 유지보수에 비하면 덜하다.
운영에서 겪는 대다수의 어려움은 소프트웨어 아키텍처에는 극적인 영향을 주지 않고도 단순히 하드웨어를 더 투입해서 해결할 수 있기 때문이다.
아키텍처는 비용 공식 관점에서 운영보다는 개발, 배포, 유지보수 쪽으로 좀 더 기울어있기 때문이지 쉬운 시스템 운영을 도와주는 아키텍처가 중요하지않은 것은 아니다.
좋은 아키텍처는 시스템을 운영하는 데 필요한 요구도 알려준다.
다르게 표현하면, 시스템 아키텍처가 개발자에게 시스템의 운영 방식을 잘 드러내 준다고할 수 있다.
시스템 아키텍처는 유스케이스, 기능, 시스템의 필수 행위를 일급(first class) 엔티티로 격상시키고, 이들 요소가 개발자에게 주요 목표로 인식되도록 한다.
이를 통해 시스템을 이해하기 쉬워지며, 따라서 개발과 유지보수에 큰 도움을 준다.
15.4. 유지보수
유지보수는 모든 측면에서 봤을 때 소프트웨어 시스템에서 비용이 가장 많이 들어가는 업무이다.
새로운 기능 및 요구사항은 끝없이 발생하고, 뒤이어 발생하는 결함을 회피가 불가능하며 이 결함을 수정하는 데도 많은 리소스가 소모된다.
유지보수의 가장 큰 비용은 탐사(spelunking)와 이로 인한 위험부담에 있다.
탐사란 기존 소프트웨어에 새로운 기능을 추가하가나 결함을 수정할 때,
소프트웨어를 파헤쳐서 어디를 고치는 게 최선인지, 그리고 어떤 전략을 쓰는 게 최적일지를 결정할 때 드는 비용이다.
이러한 변경사항을 반영할 때 의도치 않은 결함이 발생할 가능성은 항상 존재하며, 이로 인한 위험부담 비용이 추가된다.
주의를 기울여 신중하게 아키텍처를 만들면 이 비용을 크게 줄일 수 있다.
시스템을 컴포넌트로 분리하고, 안정된 인터페이스를 두어 서로 격리하여 추가될 기능에 대한 대비는 물론 장애 발생 위험을 크게 줄일 수 있다.
15.5. 선택사항 열어 두기
소프트웨어는 행위적 가치와 구조적 가치라는 두 종류의 가치를 지닌다.
이중 구조적 가치가 더욱 중요한데, 소프트웨어를 부드럽게 만드는 것이 구조적 가치이기 때문이다.
소프트웨어는 기계의 행위를 빠르고 쉽게 변경하기 위해 만들어졌는데, 이 유연성은 시스템의 형태, 컴포넌트의 배치 방식, 컴포넌트가 상호 연결되는 방식에 크게 의존한다.
이 소프트웨어를 부드럽게 유지하는 방법은 선택사항을 가능한 한 많이, 그리고 가능한 한 오랫동안 열어두는 것이다.
열어둬야할 선택사항이란 중요하지 않은 세부사항을 의미한다.
모든 소프트웨어 시스템은 정책과 세부사항이라는 두 가지 구성요소로 분해할 수 있으며, 정책 요소는 모든 업무 규칙와 업무 절차를 구체화한다.
세부사항은 사람, 외부 시스템, 프로그래머가 정책과 소통할 때 피룡한 요소지만 정책이 가진 행위에는 조금도 영향을 미치지않는다.
아키텍트의 목표는 시스템에서 정책을 가장 핵심적인 요소로 식별하고, 동시에 세부사항은 정책에 무관하게 만들 수 있는 형태의 시스템을 구축하는 데 있다.
이를 통해 세부사항을 결정하는 일은 미루거나 연기할 수 있께된다.
아래는 그 예시이다.
1. 개발 초기에는 데이터베이스 시스템을 선택할 필요가 없다.
고수준의 정책은 어떤 종류의 데이터베이스를 사용하는지 신경 써서는 안된다.
신중한 아키텍트라면 고수준의 정책을 데이터베이스가 분산형인지 계층형인지 아니면 플랫 파일인지와는 관련이 없도록 해야 한다.
2. 개발 초기에는 웹 서버를 선택할 필요가 없다.
고수준의 정책은 자신이 웹을 통해 전달된다는 사실을 알 필요가 없다.
웹 개발 기술들에 대해 고수준의 정책이 전혀 알지 못하게 만들면 프로젝트 후반까지는 어떤 종류의 웹 시스템을 사용할지를 결정하지 않아도 된다.
심지어는 시스템을 웹을 통해 전송할 것인지조차도 결정할 필요가 없다.
3. 개발 초기에는 REST를 적용할 필요가 없다.
고수준의 정책은 외부 세계로의 인터페이스에 대해 독립적이어야 한다.
4. 개발 초기에는 의존성 주입 프레임워크를 적용할 필요가 없다.
고수준의 정책은 의존성을 해석하는 방식에 대해 신경쓸 필요가 없다.
세부사항에 몰두하지 않은 채 고수준의 정책을 만들 수 있다면 이러한 세부사항에 대한 결정을 오랫동안 미루거나 연기할 수 있다.
이 결정을 미루는 만큼, 더 많은 정보를 얻을 수 있고 이를 기초로 제대로 된 결정을 내릴 수 있다.
또한 다양한 실험을 해볼 수 있는 선택지도 열어둘 수도 있다.
좋은 아키텍트는 결정되지 않은 사항의 수를 최대화한다.