설계와 아키텍처란?
‘아키텍처’는 저수준의 세부사항과는 분리된 고수준의 무언가를 가리킬 때 흔히 사용되고 ‘설계’는 저수준의 구조 또는 결정사항 등을 의미할 때가 많다. 하지만 실제 아키텍트 관점에서 본다면 이러한 구분을 무의미하다.
실제로 내가 접한 대부분의 프론트엔드 아키텍처에 대한 담론의 대부분은 인지적으로 좀 더 쉽고 빠르게 맥락을 제공하고 파일의 역할과 책임을 잘 구분하기 위한 하나의 멘탈 모델을 폴더 구조로 녹여내거나 역으로 폴더 구조를 리팩토링하면서 어떻게 하면 좀 더 우리가 갖고 있는 멘탈 모델을 적용할지에 관한 것이었다.
서비스와 인프라 레벨로 올라가야만 진짜(?) 아키텍처라고 할만한 것들이 눈에 보이는데 그런 것들은 대체로 내가 관여할 수 없거나 굳이 건드릴 이유가 없는 영역이었다. 반면 미시적인 관점에서의 컴포넌트나 피쳐 단위의 설계는 매 스프린트마다 행했던 일이기도 하다.
집으로 예를 들자면 집의 아키텍처에는 집의 형태, 외관, 입면도, 공간이나 방의 배치 등이 포함된다. 하지만 아키텍트가 만든 도면을 살펴보면 무수히 많은 저수준의 세부사항(콘센트, 전등 스위치, 전등 등)도 확인할 수 있다.
모든 고수준의 결정사항과 그것을 지탱하는 모든 저수준의 세부사항은 집 전체 설계의 구성요소가 된다. 이 둘을 구분짓는 경계는 뚜렷하지 않다. 고수준에서 저수준으로 향하는 의사결정의 연속성만 있을 뿐이다.
아키텍처는 고수준과 저수준, 이분법적으로 명확히 갈라지는 것이 아니라 정책에서 세부 구현까지 연속적인 의사결정의 스펙트럼을 다루는 일이라 볼 수 있다.
1.1 목표는?
고수준에서 저수준으로 이어지는 의사결정의 목표는? 좋은 소프트웨어 설계의 목표는? 아래와 같다.
필요한 시스템을 만들고 유지보수하는 데 투입되는 인력의 최소화
회사에서 조직도를 어떻게 구성하고 자리를 어떻게 배치하느냐는 업무에서의 커뮤니케이션 비용을 줄이고 협업의 효율성을 높여서 결과적으로 비용을 최소화하고 생산성을 최대화하는 목표를 갖고 있다고 생각한다. 개개인의 역량에 앞서 잘 만들어진 구조 또한 중요하다. 소프트웨어의 아키텍처도 마찬가지이다.
설계 품질의 척도는 고객의 요구를 만족시키는 데 드는 비용을 재는 척도와 다름없다. 이 비용이 낮을 뿐만 아니라 시스템의 수명이 다할 때까지 비용을 낮게 유지할 수 있다면 좋은 설계라고 할 수 있다. 새로운 기능을 출시할 때마다 비용이 증가한다면 나쁜 설계다.
1.2 사례 연구

위 그래프로 유추할 수 있는 것은 직원 수가 폭등하며 회사가 엄청 성장하고 있음(또는 그렇게 보임)을 알 수 있다.

같은 기간 동안의 제품의 크기이다. 5년차부터는 사실 상 성장이 멈췄다. 엔지니어링 스태프의 수는 많이 늘어났지만 제품의 성장은 이와 반비례하고 있음을 알 수 있다.

앞선 두 그래프로 예상할 수 있듯이 개발자 수가 늘어남에 따라서 코드 라인당 비용 또한 급증했다. 이 추세가 계속 가다간 회사의 성장이 꺾이거나 레이오프를 해야할 수도 있겠다.
제품의 성장할수록 비용이 많이 드는 것이 당연하다고 생각할 수도 있지만 무엇이 이렇게 비용을 많이 들게 했을까?
1.2.1 엉망진창이 되어가는 신호
시스템을 급하게 만들거나, 결과물의 총량을 개발자의 수로만 결정하거나 구조를 깔끔하게 만드려는 생각을 하지 않는다면 이와 같이 파국으로 치닫는 그래프를 볼 수 있다.

위 그래프는 개발자 관점에서의 생산성 곡선이다. 생산성이 100%에서 시작했지만 세 번째 배포에서 급락하더니 네 번째부터는 바닥을 기고 있다.
이러한 상황에서 개발자는 기능 개발보다 엉망이 된 상황을 수습하고 대처하는 것에 시간을 소모한다.
구조가 난잡하고 어디에 어떤 코드가 있는지 알기 어려운 레거시를 이어받는다면 그것을 전면적으로 개선하기 전에는 영원히 비슷한 굴레에 빠질 수 밖에 없는 것 같다.
문제가 생겨 수습을 하기 위해서 이 폴더 저 폴더 다 뒤져가며 로그를 찍고 원인을 찾았던 경험이 있다. 그렇게 발생한 원인은 그렇게까지 대단한 게 아니었고 잘 설계되었다면 쉽게 찾을 수 있는, 어쩌면 문제가 발생조차 하지 않았을 수도 있을 법한 것이었다.
1.2.2 경영자의 시각

경영자 입장에서 본다면 말도 안되는 일이 벌어졌다고 생각할 수도 있다. 5년차부터는 매년 500만 달러씩 인건비가 증가했다. 이는 단순히 하루 아침에 벌어난 일이 아니다.
무엇이 잘못되었을까? 어떤 조치를 취해야 될까?
1.2.3 무엇이 잘못되었나?
대다수의 개발자들은 열심히 일을 한다.
이들은 코드는 나중에 정리하면 되고 당장은 시장에 출시하는 것이 먼저라는 착각에 빠진다.
그러나 코드를 정리할 그 '나중'은 절대 오지 않는다. 시장의 압박은 절대로 수그러들지 않기 때문이다.
무수히 많이 달곤했던 TODO 주석을 생각한다면 그리 쉽게 웃어넘길만한 사안은 아닌 거 같다. 농담이 아니라 정말로 그 나중이란 시간은 오지 않았다. 나중에 그거 할 시간 낼 수 있을 거 같고 부여받을 수 있을 거 같지만 그 때가 되면 또 그 때의 일이 있더라... 누구나 경험해봤을 거라 생각한다.
보안에 문제가 없어서 보안팀을 다 잘랐더니 보안 이슈가 폭발했다는 이야기는 유명하다. 이와 비슷하게 아키텍처 또한 잘 설계되었을 때의 효능보다는 문제가 있는 구조를 방치해서 더 이상 기능 개발이 어렵고 생산성이 역행할 때의 역체감이 더 크다고 생각한다.
결국 작성한 코드를 정리하는 일은 일어나지 않고 계속 기능이 추가되며 생산성은 0을 향해 수렴한다. 개발자가 생산성을 유지할 수 있다고 자신의 능력을 과신하기 때문이다.
개발자가 속는 더 큰 거짓말은 "지저분한 코드를 작성하면 단기간에 빠르게 갈 수 있고, 장기적으로 볼 때만 생산성이 낮아진다"는 견해다.
이 또한 자신의 능력을 과신하는 것이다. 하지만 엉망으로 만들면 깔끔하게 유지할 때보다 항상 더 느리다.

위 그래프는 제이슨 고먼(Jason Gorman)의 실험 결과이다. 단순한 프로그램의 개발 속도를 측정한 것인데 사전에 정의된 인수 테스트를 통과하면 완료된 것으로 보았다.
그냥 개발하는 것과 TDD로 개발하는 경우를 비교했을 때 TDD를 적용하는 것이 그냥 개발하는 것보다 더 빠르다는 것을 알 수 있다. 우리는 여기서 TDD라는 단어나 방식에 매몰되지 않아야한다.
이는 자신을 과신하지 않고 깔끔하게 코드를 작성하는 것이 단순한 작업에서도 더 생산성이 높다는 것을 말한다. 우리는 여기서 소프트웨어 개발의 단순한 진리 중 하나를 알 수 있다.
빨리 가는 유일한 방법은 제대로 가는 것이다.
그렇다면 처음부터 다시 시작하여 재설계하는 것이 해답일까? 개발자가 스스로를 과신하는 착각에서 벗어나지 못한다면 재설계하더라도 똑같이 엉망이 될 것이다.
따라서 개발 조직이 할 수 있는 최고의 선택지는 과신을 막고 소프트웨어 아키텍처의 품질에 대한 고민을 심각하게 시작하는 것이다.
소프트웨어 아키텍처를 진지하게 고려할 수 있으려면 좋은 소프트웨어 아키텍처가 무엇인지 이해해야 한다.
비용은 최소화하고 생산성은 최대화할 수 있는 설계와 아키텍처를 만드려면 이러한 결과로 이끌어줄 아키텍처가 지닌 속성을 알고 있어야 한다.