025. (Clean Architecture) 1. 설계와 아키텍처란?

1. 설계와 아키텍처란?

오랫동안 설계(design)란 무엇이고 아키텍처(architecture)란 무엇인지? 그리고 둘 사이에는 어떤 차이가 있는지 많은 혼란이 있었다.

본 포스팅을 통해 설계와 아키텍처가 무엇인지 정확하게 정의해보도록 하자.

먼저 설계와 아키텍처 사이에는 아무런 차이점이 없다.

좀 더 명세해보자면

아키텍처는 저수준의 세부사항과는 분리된 고수준의 무언가를 가리킬 때 많이 쓰이고,

설계는 저수준의 구조 또는 결정사항 등을 가리킬때가 많다.

하지만 실제 아키텍트의 업무 측면에서 본다면 이러한 구분은 무의미하다.

이는 아키텍처를 통해 모든 고수준의 결정사항을 지탱하는 모든 세부사항을 확인할 수 있기때문이다.

소프트웨어 설계도 마찬가지이다.

저수준의 세부사항과 고수준의 구조는 모두 소프트웨어 전체 설계의 구성요소이며, 양쪽 다 단절없이 이어져 있다.

그리고 이를 통해 대상 시스템의 구조를 정의하며, 개별적으로는 존재할 수 없다.

문제는 이 둘을 구분 짓는 경계가 뚜렷하지않다는 점이다.

단지 고수준에서 저수준으로 향하는 의사결정의 연속성만이 존재한다.

1.1. 목표는?

고수준에서 저수준으로 향하는 의사결정의 목표는 무엇일까?

좋은 소프트웨어 설계의 목표는 무엇일까?

이상적일 수 밖에 없는 이 목표는 아래와 같이 정의한다.

소프트웨어 아키텍처의 목표는 필요한 시스템을 만들고 유지보수하는 데 투입되는 인력을 최소화하는 데 있다.

따라서 설계 품질을 재는 척도는 곧 고객의 요구를 만족시키는 데 드는 비용을 재는 척도이며,

당장 들어가는 비용이 낮고 시스템의 생명주기에 따른 유지보수 비용마저 낮게 유지할 수 있다면 좋은 설계인 것이다.

반대로 초기 비용과 유지보수 비용이 계속해서 증가한다면 나쁜 설계이다.

1.2. 사례 연구

아래 사례를 살펴보자.

해가 갈수록 제품을 유지보수는 엔지니어링 직원 수가 폭발적으로 늘어나고 있다.

마치 엄청난 성공을 이룩한 제품으로 보일 수 있다.

Growth of the engineering staff

이번엔 동일한 기간의 해당 제품을 유지보수하는 회사의 생산성을 살펴보자.

Productivity over the same period of time

점차 생산성이 둔화되다가 어느 순간 유지만 하고 있다.

늘어난 직원 수를 생각해보면 직원당 생산성이 떨어지고 있는 것이다.

이번엔 작성한 코드의 라인당 비용이 얼마나 들었는지를 확인해보자.

Cost per line of code over time

막대한 비용을 치르고 있는 이 제품은 당장의 수익성이 문제가 아닌, 회사의 성장을 멈추게 하거나 망하게 만들 것이다.

이렇게 생산성을 변화시킨 요인은 무엇일까?

최초 출시 제품보다 여덟번째로 출시한 제품의 비용은 왜 40배나 많이 증가했을까?

1.2.1. 엉망진창이 되어가는 신호

위에서 살펴본 그래프들은 엉망진창이 되어가는 신호다.

시스텝을 급하게 만들거나, 결과물의 총량을 단순히 개발자의 수로만 결정하거나,

코드와 설계의 구조를 깔끔하게 만드려는 생각을 하지 않으면 위와 같이 파국을 향해 치닫는 그래프를 보게 된다.

아래 그래프는 이 비용 곡선을 개발자 관점에서 보여준다.

Productivity by release

개발자의 생산성은 거의 100%로 시작했지만 4번째 출시부터 바닥을 치기 시작해 0으로 수렴해가고 있다.

개발자 입장에서는 매우 절망적인 상황일 것이다.

모두가 놀아서 생산성이 저해되거나 비용이 증가하는 게 아닌 다같이 열심히 하고 있을 것이기 때문이다.

위와 같은 상황이 되면 결국 개발자의 노력은 기능 개발보다는 엉망진창이 된 현재 상황을 수습하는 데 소모되어 노력의 가치가 떨어지게 된다.

1.2.2. 경영자의 시각

이번엔 개발자가 아닌 경영자의 시각으로 동일한 상황을 살펴보자.

아래 그래프는 같은 기간에 개발하는 데 쓰인 인건비를 표현한 것이다.

Monthly development payroll by release

첫 번째 출시에서는 수십만 달러의 인건비로 제품을 만들어냈다.

이후 출시때마다 인건비가 기하급수적으로 증가한다.

특히 마지막 출시에서는 2천만 달러를 지출했는데, 얻은 게 거의 없다.

어떤 조치를 취해야할까?

1.2.3. 무엇이 잘못되었나?

대다수의 개발자들은 열심히 일을 한다.

이 개발자들이 코드의 정리보다 제품의 출시가 우선순위가 높다고 착각한다.

코드의 정리를 나중으로 미루는 것이다.

하지만 나중은 절대 오지 않는다.

참고 (Clean Code) 1. 클린 코드 - 1.1. 나쁜 코드

결국 개발자는 이 착각을 부정하지 못하고

엉망진창인 코드 베이스에서도 자신의 생산성을 유지할 수 있다고 생각하며, 생산성은 0을 향해 수렴하기 시작한다.

여기서 한 번 더 착각을 하게 되는데, 지저분은 코드라도 단기적인 측면에서는 빠른 출시를 위한 좋은 방법이며 장기적인 측면에서만 생산성이 낮아진다고 믿는 것이다.

하지만 진실은 하나다.

엉망진창이 코드는 깔끔하게 유지한 코드보다 항상 더 느리다는 것이다.

Time to completion by iterations and use/non-use of TDD

위의 그래프는 한 가지 실험의 결과이다.

간단한 프로그램을 그냥 개발하는 경우와 TDD 기반으로 개발하는 경우의 개발 속도를 측정한 것이다.

동일한 기능을 반복적으로 구현하며 쌓인 숙련도로 점차 구현에 걸리는 시간이 줄어듦을 확인할 수 있다.

심지어 테스트 코드의 선작성 및 검증이라는 절차가 하나 더 추가되었음에도 오히려 더욱 빠르게 구현하는 것을 확인할 수 있다.

소프트웨어 개발의 단순한 진리다. 빨리 가는 유일한 방법은 제대로 가는 것 이다.

다시 경영자의 입장으로 돌아가자.

개발자들로 하여금 전체 시스템을 재설계하도록 지시해야할까?

착각속에 빠진 개발자들이 스스로 변하지않는 이상, 재설계의 결과물도 똑같이 엉망진창일 것이다.

따라서 개발 조직이 할 수 있는 최고의 선택지는 조직에 스며들 수 있는 과신을 미리 인지하여 차단하고, 소프트웨어 아키텍처의 품질에 대한 고민을 심각하게 시작하는 것이다.

소프트웨어 아키텍처의 중요성을 깨달았다면 앞으로 나가갈 방향도 정해졌다.

좋은 소프트웨어 아키텍처를 달성하기위해

최소화된 비용과 최대화된 생산성을 보장할 수 있는 설계와 아키텍처를 가진 시스템을 만들고,

이 결과를 위한 시스템 아키텍처가 지닌 속성을 인지해야한다.