현대의 소프트웨어 개발 생태계에 몸담고 있는 대부분 아키텍트는 두 가지 궁금증을 갖기 마련이다. 매 순간 모든 것이 변하는 세계에서 어떻게 장기적인 계획을 세울 수 있는가? 또는 아키텍처를 구축한 뒤 시간의 흐름에 따른 질적 저하를 막으려면 어떻게 해야 하는가? 이러한 질문이 무엇을 의미하는지 자세히 살펴보자
우리가 사용하는 프로그래밍 플랫폼은 말 그래도 끊임없이 진화하고 있다. 프로그래밍 언어는 새로운 문제에 대처하는 유연성과 적용력을 높이기 위해 버전을 갱신하고 개선된 API를 제공한다. 완전히 새로운 프로그래밍 언어가 등장해 전혀 다른 패러다임과 집합 구조를 선보이기도 한다. 일례로 자바는 C++의 네트워킹 코드 작성 난이도를 완화하고 메모리 관리 기능을 개선한 대체재로 제작됐다. 지난 20년을 돌이켜보면 많은 기성 언어가 여전히 API를 발전시키는 한편, 완전히 새로운 언어가 꾸준히 등장하며 새로운 문제에 맞서는 모습을 관찰할 수 있다. 아래 그림은 이러한 프로그래밍 언어의 진화를 보여준다.
[프로그래밍 언어의 진화]
프로그래밍 플랫폼, 언어, 운영 환경, 퍼시스턴스 기술, 클라우드 서비스 등, 소프트웨어 개발의 여러 측면은 분야를 가리지 않고 지속적으로 변화할 것으로 예상된다. 기술 또는 도메인 환경의 변화가 언제 발생할 것인지, 어떤 변화가 살아남을 것인지 예측할 수는 없지만 변화의 불가피함만큼은 확실히 알 수 있다. 결론적으로 우리는 기술 환경의 변화를 기정사실화하고 시스템을 설계해야 한다.
생태계가 예상치 못한 방식으로 끊임없이 변화한다면 또는 예측이 불가능하다면, 기존에 수립하던 확정적 계획의 대안은 무엇일까? 이제 엔터프라이즈 아키텍트와 개발자는 새로운 환경에 적응해야 한다. 전통적인 개발 환경에서 장기 계획을 수립했던 관행의 이면에는 소프트웨어 변경 비용이 매우 높다고 여겼던 재정적인 동기가 있다. 그러나 현대의 엔지니어링 관행은 프로세스 자동화와 데브옵스 기술의 발전을 통해 소프트웨어 변경 비용을 낮춤으로써 기존의 전제를 무효로 만든다.
그동안 현명한 개발자들은 시스템 일부가 다른 부분보다 유독 수정하기 어렵다는 사실을 인지하고 있었다. 소프트웨어 아키텍처가 ‘나중에 변경하기 어려운 부분’으로 정의된 이유가 바로 여기에 있다. 이러한 정의는 손쉽게 수정할 수 있는 것들과 실제로 변경하기 어려운 부분을 구분하는 편리한 수단이었다. 그러나 안타깝게도 이 정의는 아키텍처를 설계할 때 맹점으로 작용한다. 변경이 어렵다는 가정 자체가 개발자의 자기실현적 예언이 되고 마는 것이다.
몇 년 전부터 일부 혁신적인 소프트웨어 아키텍트들은 ‘나중에 변경하기 어려운’ 문제를 재고하기 시작했다. 아키텍처에 변경 가능성을 탑재할 수 있을까? 손쉬운 변경이 아키텍처의 기본 원칙이 된다면 변경은 더 이상 어려운 문제가 아니다. 아키텍처에 진화성이 더해지는 순간, 완전히 새로운 행동 양식이 등장하며 동적 균형을 다시금 무너뜨리게 된다.
생태계의 변화는 차치하고, 아키텍처 특성의 점진적 저하는 어떻게 대처할 것인가? 최초 설계한 아키텍처는 이윽고 복잡한 실제 세계에 노출되며 다양한 구현을 덧붙이게 된다. 이러한 상황에서 아키텍트가 정의했던 핵심부를 보호하는 방법은 무엇일까?
흔히 비트 부패라 불리는 현상은 많은 조직에서 발생한다. 아키텍트는 비즈니스 요구 사항과 ‘~성’에 맞추어 아키텍처 패턴을 선택하지만 시간이 지남에 따라 이러한 특성은 의도치 않게 저하되는 경우가 많다. 가령 프레젠테이션과 퍼시스턴스 계층을 각각 상, 하단에 두고 그 사이에 다양한 계층이 구현된 아키텍처가 있다고 하자. 간혹 이러한 구조를 무시하고 중간 계층 없이 프레젠테이션에서 퍼시스턴스 계층으로 직접 접근할 권한을 요청하는 개발자가 종종 등장한다. 대부분은 성능이라는 명분을 내세운다. 그러나 아키텍트가 계층을 분리한 이유는 변경 사항을 격리하기 위해서다. 개발자의 요청은 이러한 계층을 우회하며 커플링을 늘리고 계층의 존재 의의를 무위로 돌리려는 시도나 다름없다.
한 번 정의한 아키텍처의 핵심 특성이 추후 저하되지 않도록 보호하려면 아키텍트는 어떠한 조치를 취해야 할까? 진화성을 아키텍처 특성으로 추가한다는 것은 시스템이 진화하며 나머지 특성을 보호한다는 의미다. 만일 아키텍트가 확장성에 중점을 두고 아키텍처를 설계했다면 시스템이 진화하더라도 확장성이 저하되는 것을 원치 않을 것이다. 이렇듯 진화성은 다른 모든 아키텍처 특성을 보호하는 메타적 성격을 띤 아키텍처 래퍼 wrapper다.
진화적 아키텍처의 메커니즘은 아키텍처 거버넌스의 목표 및 관심사와 많은 부분에서 중첩된다. 아키텍처 거버넌스는 설계, 품질, 보안 등의 요소로 정의한다. 이 책은 진화적 아키텍처의 관점에서 아키텍처 거버넌스를 자동화하는 다양한 기법을 설명한다.
진화적 아키텍처라는 명칭 자체에 궁금증을 갖는 이가 많다. 다른 이름도 아니고 꼭 진화적 아키텍처evolutionary architecture라고 부르는 이유는 무엇인가? 점진적incremental, 지속적continual, 애자일agile, 반응형reactive, 창발적emergent 등의 여러 후보가 있지만 이들은 모두 핵심에서 비켜나 있다. 이 책이 설명하는 진화적 아키텍처의 정의는 점진적 아키텍처, 유도된 guided 아키텍처라는 두 가지 핵심 특성을 동시에 포함한다
지속적, 애자일, 창발적 등의 용어는 모두 시간에 따른 변화의 개념을 내포한다. 이들은 모두 진화적 아키텍처의 중요한 특성이다. 그러나 이들 중 어느 것도 아키텍처가 어떻게 변하는지, 바람직한 최종 상태가 무엇인지에 대한 명시적인 의미를 담고 있지 않다. 변화하는 환경을 암시하고는 있지만 그 속에서 아키텍처가 어떤 모습이어야 하는지는 설명하지 않는다. 유도된 아키텍처는 우리가 달성해야 할 아키텍처, 즉 최종 목표를 나타내는 정의다.
적응보다 진화라는 단어를 선호하는 이유는, 점층적인 불가해함과 우발적인 복잡성을 덧대고 받아들인 아키텍처가 아닌, 근본적 진화가 유발하는 변화에 순응하는 아키텍처에 관심을 두기 때문이다. 적응이란 솔루션의 우아함이나 수명과 관계없이 그저 무언가를 작동시키는 방법을 찾아냈음을 의미한다. 진정으로 진화하는 아키텍처를 구축하기 위해 아키텍트는 임기응변이 아닌 진실된 변화를 추구해야 한다. 생물학적 비유로 돌아가, 진화는 목적에 부합하고 끊임없이 변화하는 환경에서 살아남을 수 있는 시스템을 갖추는 과정에 주목한다. 시스템 내부에서 벌어지는 개별적인 적응 과정과 별개로, 아키텍트로서 우리는 진화 가능한 시스템 전반에 관심을 두어야 한다.
진화적 아키텍처와 창발적 설계의 차이, ‘창발적 아키텍처’가 존재하지 않는 이유도 아키텍트에게 중요한 주제다. 애자일 소프트웨어 개발에 대한 대표적인 오해 중 하나는 아키텍처의 부재라는 특징이다. ‘일단 코딩을 시작하면 아키텍처는 자연히 생겨난다’라고 말하는 이가 많다. 그러나 이러한 주장의 설득력은 해결하고자 하는 문제가 얼마나 단순한지에 달려 있다. 개집을 짓기 위해 설계도를 그리는 사람은 별로 없다. 철물점에서 목재를 구해 몇 번 두드리기만 해도 완성되기 때문이다. 반면 50층짜리 빌딩을 지어야 한다면 건축 설계가 반드시 필요하다. 마찬가지로 소수의 인원이 사용할 간단한 카탈로그 시스템은 거창한 계획이 없어도 구축할 수 있다. 그러나 많은 대중에게 엄밀한 성능을 보장하는 대규모 시스템을 설계할 때는 반드시 사전 계획이 있어야 한다. 애자일 아키텍처의 목표는 아키텍처의 부재 자체가 아니라 소프트웨어 개발 과정에 존재하는 무가치한 관료적 행태를 배제하는 것이다.
대규모 시스템은 50층짜리 빌딩을 짓는 것과 비슷하다. 반드시 사전 계획이 있어야 하기 때문이다.
소프트웨어 아키텍처가 복잡해지는 이유는 아키텍트가 반드시 설계해야 할 복잡성의 유형이 다양하기 때문이다. 시스템 설계 원칙의 트레이드오프 trade-off를 저울질할 때는, 단순함과 복잡함을 가르기보다 복잡한 시스템을 다양한 방식으로 구분하는 경우가 많다. 즉 성공적인 시스템을 판가름하는 기준은 시스템마다 고유하게 존재한다. 마이크로서비스처럼 하나의 아키텍처 스타일을 논의한다 해도 이는 복잡한 시스템이 시작되는 하나의 출발점에 불과하다. 시스템은 각기 다른 모습으로 발전한다.
매우 단순한 시스템을 구축할 때는 아키텍처의 고려 사안들에 크게 신경을 쓸 필요가 없다. 그러나 정교한 시스템은 목적에 부합하는 설계와 함께 정확한 출발점이 필요하다. 창발성은 무(無)로부터의 시작을 의미하지만, 아키텍처는 시스템의 여타 모든 부분이 의지할 만한 발판과 기본 구조를 제공한다. 일을 시작하려면 최소한의 준비는 있어야 하는 법이다.
창발성의 개념은 이상적인 아키텍처 솔루션을 향해 점차 설계를 발전시킨다는 의미도 담고 있다. 그러나 건축과 마찬가지로 완벽한 아키텍처란 존재하지 않는다. 아키텍처마다 설계자의 트레이드오프 취급 방식이 다를 뿐이다. 아키텍트는 다양한 아키텍처 스타일을 통해 대부분 문제를 구현하고 해결할 수 있다. 그러나 그중에서도 특정 문제에 더 잘 어울리며 부작용이 없고 손이 덜 가는 해결책이 존재하기 마련이다.
장기적인 목표를 뒷받침할 만한 구조와 거버넌스를 확보하는 것, 또한 이들이 불필요한 형식과 저항을 낳지 않을 정도로 제한하는 것, 이 두 조건 사이에 균형을 유지하는 것이 바로 진화적 아키텍처의 핵심이다.
이 글은 도서 『진화적 아키텍처』 내용에서 일부를 발췌, 작성하였습니다. 변화가 빠른 시대에 살고 있는 모든 개발자를 위해 진화하는 소프트웨어를 개발하는 방법을 안내하는 『진화적 아키텍처』에서 더 많은 내용을 확인해 보세요.
이전 글 : AWS로 구성하는 데이터 과학 파이프라인 및 워크플로우
다음 글 : 메이커 컨퍼런스 서울 2016이 열리던 날!
최신 콘텐츠