두 가지 가치에 대한 이야기
모든 소프트웨어 시스템은 이해관계자에게 서로 다른 두 가지 가치를 제공한다. 바로 행위(behavior)와 구조(structure)이다. 개발자는 두 가지 가치를 모두 반드시 높게 유지해야하는 책임을 진다. 불행하게도 개발자는 한가지 가치에만 집중하고 나머지 가치는 배제하곤 한다.
2.1 행위
소프트웨어의 첫 번째 가치는 바로 행위다. 프로그래머는 이해관계자가 기능 명세서나 요구사항 문서를 구체화할 수 있도록 돕는다. 그리고 이해관계자의 기계가 이러한 요구사항을 만족하도록 코드를 작성한다.
기계가 이러한 요구사항을 위반하면, 프로그래머는 디버거를 열고 문제를 고친다.
많은 프로그래머가 이러한 활동이 자신이 해야 할 일의 전부라고 생각한다.
나 또한 이 때까지 개발을 하며 대부분은 '행위'에 전념했고 이러한 일이 나의 일의 전부는 아니지만 많은 비중을 차지한다고 생각했다.
2.2 아키텍처
소프트웨어의 두 번째 가치는 Software라는 단어와 관련이 있다. 소프트웨어가 갖는 절대불변의 진리 중 하나는 변하지 않는 소프트웨어는 없다는 것이다. 소프트웨어를 만든 이유는 기계(하드웨어)의 행위를 쉽게 변경할 수 있도록 하기 위해서다.
소프트웨어가 가진 본연의 목적을 추구하려면 소프트웨어는 반드시 ‘부드러워’야 한다. 다시 말해 변경하기 쉬워야 한다. 이해관계자가 기능에 대한 생각을 바꾸면, 이러한 변경사항을 간단하고 쉽게 적용할 수 있어야 한다. 이러한 변경사항을 적용하는 데 드는 어려움은 변경되는 범위(scope)에 비례해야하며, 변경사항의 형태(shape)와는 관련이 없어야한다.
소프트웨어 개발 비용의 증가를 결정 짓는 주된 요인은 바로 이 변경사항의 범위와 형태의 차이에 있다. 이 때문에 개발 비용은 요청된 변경사항의 크기에 비례한다.
문제는 당연히 시스템의 아키텍처다. 아키텍처가 특정 형태를 다른 형태보다 선호하면 할수록 새로운 기능을 이 구조에 맞추는 것이 힘들어진다. 따라서 아키텍처는 형태에 독립적이어야 하고, 그럴수록 더 실용적이다.
추가 또는 수정해야할 코드의 양이 많을수록 개발 비용이 증가하는 것은 당연하다. 내 경험상 흔히 개발 범위가 넓다고 표현했었다.
형태는 세부사항과도 같다. 세부 구현의 변화가 스코프에 영향을 주어서는 안된다. 또한 세부사항이 경직되어 있다면 새로운 기능이 생겼을 때도 유연하게 대응하기 힘들어진다.
// UseCase가 Stripe 구현에 직접 결합됨 (형태 선호)
import Stripe from "stripe";
export class PayOrder {
constructor(private stripe: Stripe) {}
async execute(orderId: string, amount: number) {
// 정책: 주문 결제
// 세부: Stripe charge 생성 (형태)
await this.stripe.charges.create({ amount, currency: "usd" });
// ... 주문 상태 업데이트 등
}
}위 코드는 Stripe에 강하게 의존하는 경직된 형태를 갖고 있어서 변경이 필요할 시 UseCase 뿐 아니라 테스트 및 의존성 교체 등 다양한 스코프를 침범하여 코드를 수정해야한다.
2.3 더 높은 가치
기능인가 아키텍처인가? 둘 중 어느 것의 가치가 더 높은가? 소프트웨어가 동작하도록 만드는 것이 중요한가? 아니면 더 쉽게 변경할 수 있도록 하는 것이 중요한가?
업무 관리자에게 묻는다면 동작하는 것이 더 중요하다 할 것이고 대부분의 개발자들은 그것에 동조하는 태도를 취하겠지만 이는 잘못된 태도다.
어느 하나 덜 중요한 것은 아니지만 장기적인 관점에서 보았을 때 변경하기 쉬운 시스템을 만드는 것이 지향해야할 방향이다. 그러나 비즈니스는 급박하고 당장 클라이언트에게 약속한 기능 개발의 마감시한은 눈 앞에 있다. 대표를 위시한 대부분의 경영진이나 관리자들은 이것의 중요성을 모른다. 안다면 알면서도 외면할 수 밖에 없다.
개발자들이 이러한 중요성을 강조해도 아키텍처만을 점검하고 다듬을만한 시간을
부여받는 것은 현실적으로 어렵다. 이러한 이유로 빠르게 사업을 키우는
스타트업에서는 어느정도 수준의 기술부채를 떠안을 수 밖에 없다. 빠르게 달리는
기차 앞에 레일을 깔면서 기차 내부도 보수하는 것을 어떤 비율로 할 것이냐는
영원히 난제로 남을 것 같다. (아직까지는)
- 완벽하게 동작하지만 수정이 아예 불가능한 프로그램을 내게 준다면, 이 프로그램은 요구사항이 변경될 때 동작하지 않게 되고 결국 돌아가도록 만들 수 없게 된다. 따라서 이러한 프로그램은 거의 쓸모가 없다
- 동작은 하지 않지만 변경이 쉬운 프로그램을 준다면 나는 프로그램이 돌아가도록 만들 수 있고 변경사항이 발생하더라도 여전히 동작하도록 유지보수 할 수 있다. 따라서 이러한 프로그램은 앞으로도 유용한 채로 남는다.
물론 이러한 주장이 설득력이 떨어진다고 생각할 수도 있다. 어쨌든 지나치게 극단적인 예시이고 변경이 완전히 불가능한 프로그램은 존재하지 않기 때문이다. 하지만 수정이 현실적으로 불가능한 시스템은 존재하기 마련인데, 변경에 드는 비용이 변경으로 창출되는 수익을 초과하는 경우이다.
2.4 아이젠하워 매트릭스
노르망디 상륙 작전의 지휘했던 장군이자 미국의 34대 대통령 아이젠하워가 고안한 중요성과 긴급성에 대한 매트릭스를 살펴보자.

내겐 두 가지 유형의 문제가 있습니다. 하나는 긴급하며, 다른 하나는 중요합니다. 긴급한 문제는 중요하지 않으며, 중요한 문제는 절대 긴급하지 않습니다.
이 격언에는 엄청나게 중요한 진실이 담겨 있다. 긴급한 문제가 아주 중요한 문제일 경우는 드물고, 중요한 문제가 몹시 긴급한 경우는 거의 없다는 사실이다.
프로그래밍 뿐 아니라 실제로도 살다보면 긴급한 문제가 아주 중요한 문제인 경우는 극히 드물더라...
소프트웨어의 첫 번째 가치인 행위는 긴급하지만 매번 높은 중요도를 가지는 것은 아니다. 두 번째 가치인 아키텍처는 중요하지만 즉각적인 긴급성을 필요로 하는 경우는 절대 없다.
위 매트릭스에 의해서 일의 중요도로 순서를 매기자면
- 긴급하고 중요한
- 긴급하지는 않지만 중요한
- 긴급하지만 중요하지 않은
- 긴급하지도 중요하지도 않은
흔히 저지르는 실수는 세 번째에 위치한 항목을 첫 번째로 격상시키는 일이다. 업무 관리자는 보통 아키텍처의 중요성을 평가할만한 능력을 겸비하지 못하기 때문에 기능의 긴급성이 아닌 아키텍처의 중요성을 설득하는 일은 소프트웨어 개발팀이 마땅히 책임져야 한다.
요즘은 AI의 발달로 인해서 비개발자도 1인으로 서비스를 만드는 시대이다. 여러가지 역할을 하는 서브 에이전트를 회사 대표처럼 고용하여 일을 시키며 협업을 하는 것으로 하나의 작은 서비스가 뚝딱 나온다. 오히려 비개발자가 개발자보다 더 제품을 잘 만드는 것 같기도 하다. 그러나 그들에게 부족한 것이 있다면 아키텍처에 대한 이해도이다.
이것이 현 시대에서 개발자와 비개발자를 구분할 수 있는 수단 중 하나이지 않을까? 물론 이마저도 AI가 대체하게 될 수도 있다. 하지만 그 이전까지는 우리는 AI가 완성한 프로덕트의 아키텍처를 평가하고 보다 바람직한 방향으로 지침을 내려야한다. 그렇기 때문에 더더욱 아키텍처의 중요성이 대두된 시대에 살아가고 있지 않나 싶다.
2.5 아키텍처를 위해 투쟁하라
회사 내에서 각 팀들은 자신들이 가장 중요하다고 믿는 가치를 위해 투쟁한다. 개발자는 소프트웨어를 안전하게 보호해야할 책임이 있으므로 이해관계자 중 하나이다. 이것이 개발자의 책임이며 단순 행위에 집중하는 것만이 전부가 아니다.
아키텍처가 후순위가 되면 시스템을 개발하는 비용이 더 많이 들고, 일부 또는 전체 시스템에 변경을 가하는 일이 현실적으로 불가능해진다. 그래서 우리는 아키텍처를 위해 투쟁해야한다.
이런 점에서 본다면 개발자는 개발을 잘하기에 앞서 한 명의 사람으로서 누군가를 설득하는 능력이 필요하다. 글을 잘 쓰고 말을 잘 하는 것 또한 필요하다면 필요한 덕목이지 않을까. 하드스킬보다 더 중요한게 소프트스킬이라는 생각이 많이 드는 요즘이다.