(번역) 자기가 작업하지 않는 소프트웨어는 설계할 수 없습니다

TapK·2026년 3월 16일
post-thumbnail

원문: https://www.seangoedecke.com/you-cant-design-software-you-dont-work-on/

대규모 소프트웨어 시스템의 설계 과정에 의미 있게 참여할 수 있는 사람은 해당 시스템을 직접 작업하는 엔지니어뿐입니다. 시스템의 구체적인 세부 사항을 속속들이 이해하지 못하면 좋은 소프트웨어 설계를 할 수 없기 때문입니다. 다시 말해, 일반적인 소프트웨어 설계 조언은 대부분의 실질적인 설계 문제에 쓸모가 없습니다.

일반적인 소프트웨어 설계

일반적인 소프트웨어 설계란 무엇일까요? "문제에 맞춰 설계하기", 즉 도메인은 어느 정도 이해하지만 기존 코드베이스에 대한 지식은 거의 없을 때 할 수 있는 종류의 조언입니다. 안타깝게도 소프트웨어 관련 서적이나 블로그 글에서 읽을 수 있는 조언은 이런 종류뿐입니다. 엔지니어들은 모든 기술 전문가가 "업계 이야기"를 좋아하는 것과 같은 이유로 일반적인 소프트웨어 설계 조언을 즐겨 합니다. 하지만 일반적인 조언을 실제 일상 업무에 적용할 때는 매우 신중해야 합니다.

실제 업무에서는 구체적인 요소가 일반적인 요소보다 압도적으로 중요합니다. 코드가 지금 어떤 모습인지 명확하게 파악하는 것이 일반적인 설계 패턴이나 원칙을 잘 아는 것보다 훨씬, 훨씬 더 중요합니다. 예를 들면 다음과 같습니다.

  • 대규모 코드베이스에서는 일관성이 "좋은 설계"보다 중요합니다. 여기서 이 점을 논증하지는 않겠지만, 대규모 기존 코드베이스에서 엔지니어들이 저지르는 실수에서 자세히 다룬 바 있습니다.
  • 실제 코드베이스는 보통 복잡하고 예측하기 어려운 결과로 가득합니다. 변경을 안전하게 적용하려면 구현 선택지가 극소수로 제한되기 마련입니다.
  • 대규모 공유 코드베이스는 단일 설계를 반영하는 법이 없으며, 항상 서로 다른 소프트웨어 설계 사이의 중간 상태에 놓여 있습니다. 따라서 이상적인 "북극성"을 향해 나아가는 것보다, 개별 변경 후 코드베이스가 어떻게 맞물리는지가 훨씬 더 중요합니다.

전체 시스템을 마음대로 재작성할 수 있는 세상이라면 일반적인 소프트웨어 설계 조언이 훨씬 실용적일 것입니다. 실제로 그런 프로젝트도 있습니다! 하지만 소프트웨어 엔지니어링 업무의 대부분은 안전하게 재작성할 수 없는 시스템에서 이루어집니다. 이런 시스템은 "소프트웨어 설계"에 의존할 수 없으며, 내부 일관성과 엔지니어의 신중함에 의존해야 합니다.

구체적인 소프트웨어 설계

그렇다면 좋은 소프트웨어 설계란 어떤 모습일까요?

제 경험상, 가장 유용한 소프트웨어 설계는 시스템을 깊이 이해하는 소수의 엔지니어들 사이의 대화에서 이루어집니다. 매일 그 시스템을 직접 작업하는 사람들이기 때문입니다. 이런 설계 논의는 외부인이 보기에 정말 지루한 경우가 많습니다. 기술적 배경이 있는 사람이라면 누구나 이해하고 의견을 낼 수 있는 일반 원칙이 아니라, 시스템의 난해한 구체적 세부 사항을 중심으로 돌아가기 때문입니다.

논의되는 주제는 "DRY가 WET보다 나은가"가 아니라, "이 새로운 동작을 서브시스템 A에 넣을 수 있을까? 안 돼, 정보 B가 필요한데 컨텍스트 C에서는 해당 서브시스템에서 사용할 수 없거든. 서브시스템 D를 재작성하지 않으면 노출할 수가 없어. 하지만 서브시스템 E를 여기와 여기서 분리하면…" 같은 것입니다.

설계에 대한 깊은 철학적 논점은 논의에서 좀처럼 중요하지 않습니다. 오히려 가장 핵심적인 기여는 구체적인 사항에 대한 작은 오해를 지적하는 것입니다. 예를 들면 이런 것입니다. "아, 컨텍스트 C에서 B를 사용할 수 없다고 생각했나 보네. 그런데 최근에 C를 리팩터링해서 이제 필요하면 B를 연결할 수 있어."

일반적인 소프트웨어 설계가 유용할 때

일반적인 소프트웨어 설계 조언은 실질적인 설계 문제에는 유용하지 않지만, 완전히 쓸모없는 것은 아닙니다.

완전히 새로운 프로젝트를 만들 때 유용합니다. 앞서 주장했듯이, 기존 시스템에서 새로운 기능을 설계할 때는 시스템의 구체적인 요소가 지배적입니다. 하지만 새로운 시스템을 설계할 때는 구체적인 요소가 없으므로, 전적으로 일반적인 조언에 따를 수 있습니다.

구체적인 설계 결정에서 우열을 가릴 때 유용합니다. 일반적인 설계부터 시작해야 한다고 생각하지는 않지만, 모두 수용 가능해 보이는 몇 가지 구체적인 경로가 있을 때 일반 원칙이 그 사이에서 결정을 내리는 데 도움이 될 수 있습니다.

이 점은 회사 전체 차원에서 특히 그렇습니다. 즉, 일반적인 소프트웨어 설계 조언은 서로 다른 코드베이스 간의 일관성을 보장하는 데 도움이 됩니다. 이것이 공식적인 "소프트웨어 아키텍트" 역할의 가장 유용한 기능 중 하나입니다. 일반 원칙의 체계를 제공하여 개별 엔지니어들이 구체적인 결정에서 우열을 가릴 때 모두 같은 방향으로 판단할 수 있게 하는 것입니다.

이런 설계 원칙은 회사 차원의 아키텍처 결정을 안내하는 데도 도움이 됩니다. 서비스를 자체 데이터센터에서 운영해야 할까, 아니면 클라우드에서 운영해야 할까? 쿠버네티스를 사용해야 할까? AWS인가 Azure인가? 충분히 넓은 범위에서 보면 개별 서비스의 구체적인 세부 사항은 거의 중요하지 않습니다. 어느 쪽이든 막대한 양의 작업이 필요하기 때문입니다. 그래도 이런 결정에서조차 구체적인 세부 사항은 매우 중요합니다. 클라우드에서는 할 수 없는 것(맞춤형 하드웨어 구성에 의존하기 등)이 있고, 자체 데이터센터에서는 할 수 없는 것(12개 리전의 엣지에 서비스를 배포하기 등)이 있습니다. 코드베이스의 구체적인 세부 사항이 그런 것들에 의존한다면, 회사 차원의 아키텍처 결정을 내릴 때 이를 무시하면 곤란해질 것입니다.

아키텍트와 로컬 미니마(local minima)

위에서 언급한 것들은 모두 일반적인 소프트웨어 설계를 해야 할 좋은 이유입니다. 회사들이 일반적인 소프트웨어 설계를 하는 나쁜 이유 하나는, 현업 소프트웨어 엔지니어가 아닌 사람들에게 그냥 정말 좋은 아이디어처럼 들린다는 것입니다. 일단 시작하면 인센티브 구조 때문에 멈추기 어렵습니다. 많은 테크 기업이 이 로컬 미니마에 빠집니다.

최고 연봉을 받는 소프트웨어 엔지니어가 가장 추상적이고 영향력이 큰 결정을 내리는 데만 시간을 쓰게 하면 안 될 이유가 있을까요? 구조 엔지니어는 벽돌을 쌓는 게 아니라 도면을 그려야 하지 않겠습니까? 구조공학이 실제로 그렇게 돌아가는지는 모르겠지만, 소프트웨어 엔지니어링은 그렇지 않다는 것은 압니다. 실제로 현장의 엔지니어들은 소프트웨어 아키텍처 조언을 무시할 수밖에 없는 경우가 많습니다. 현재 시스템의 맥락에서 아키텍처 조언을 실제 구현으로 옮길 방법이 없기 때문입니다.

하지만 효과가 없는 관행치고, "최고의 엔지니어에게 일반적인 설계만 하게 하라"는 발상은 놀라울 정도로 끈질기게 살아남습니다. 아키텍트에게는 아무런 이해관계가 없기 때문입니다. 설계는 실제 엔지니어링 팀에 넘겨져 구현됩니다. 그 설계가 완벽하게 구현될 수는 없기 때문에, 아키텍트는 성공에 대해서는 공을 차지하고(결국 자기 설계였으니까), 실패에 대해서는 책임을 회피할 수 있습니다(저 바보들이 내 설계대로만 했더라면!).

요약

대규모 기존 코드베이스에서 작업할 때, 유용한 소프트웨어 설계 논의는 많은 사람이 생각하는 것보다 훨씬, 훨씬 더 구체적입니다. 보통 개별 파일이나 코드 한 줄 단위로 이야기합니다. 따라서 코드베이스를 속속들이 알지 못하면 유용한 소프트웨어 설계를 할 수 없습니다(실질적으로 이는 거의 항상 활발한 기여자여야 한다는 뜻입니다).

순수하게 일반적인 아키텍처가 쓸모없지는 않지만, 그 역할은 다음으로 한정되어야 합니다. (a) 완전히 새로운 시스템을 위한 정비된 경로 제시, (b) 기존 시스템에서의 결정에서 우열 가리기, (c) 회사의 광범위한 기술 선택 지원.

제 의견으로는, 프로젝트의 초기 설계를 짜는 데만 모든 시간을 쏟는 공식적인 "거시적 소프트웨어 아키텍트" 역할은 실패할 수밖에 없습니다. 좋은 아이디어처럼 들리고(비난의 위험 없이 공을 차지할 수 있으니 아키텍트에게는 좋은 거래이기도 하지만), 실제로 코드를 작성해야 하는 엔지니어링 팀에는 거의 가치를 제공하지 못합니다.

개인적으로 저는 소프트웨어 프로젝트의 설계를 구상했다면, 그 프로젝트의 성패에 책임을 져야 한다고 생각합니다. 그렇게 하면 소프트웨어 시스템을 설계하는 사람이 소프트웨어 시스템을 출시하는 방법을 아는 사람이 되도록 빠르게 보장할 수 있을 것입니다. 또한 코드베이스의 온갖 거친 면과 결점을 고려해야 하는 진짜 소프트웨어 설계자들이 자신이 수행하는 어려운 설계 작업에 대해 인정받을 수 있을 것입니다.


각주

  1. 솔직히 말해서, 저는 "훌륭한 API 설계에 대해 내가 아는 모든 것", "훌륭한 시스템 설계에 대해 내가 아는 모든 것", "훌륭한 소프트웨어 디자인은 겉보기에는 평범해 보인다", 그리고 아마 그 밖에도 십여 군데에서 제 나름대로의 일반적인 소프트웨어 설계 조언을 해왔습니다.

  2. "실제 업무 문제"라고 할 때, 여기서 말하는 것은 순수하지 않은(impure) 소프트웨어 엔지니어링입니다. 실제 비즈니스 요구를 해결하기 위한 코드베이스, 즉 (a) 타협으로 가득하고 (b) 끊임없이 변화하는 상태에 놓인 코드베이스를 말합니다. 우아한 단일 목적의 라이브러리나 우주 탐사선용 소프트웨어를 작업하고 있다면, 이 조언의 상당 부분은 해당되지 않을 것입니다.

  3. 정말 끔찍한 결정만 아니라면, 그 일반 원칙이 좋은지 나쁜지는 거의 중요하지 않습니다. 개별 코드베이스와 마찬가지로, 일관성의 이점이 "최고의" 설계를 갖추는 이점보다 큽니다.

  4. 여기서 말하는 아키텍트란 그런 뜻입니다. "아키텍트"라는 직함은 매우 다양한 종류의 업무를 포괄하며, 그중에는 "일반적인 엔지니어링 업무를 하는 아주 시니어한 엔지니어"도 포함됩니다. 많은 아키텍트는 "아키텍트" 직함이 전혀 없고, 실제 구현을 넘어선 시니어/스태프/디스팅귀시드 소프트웨어 엔지니어일 뿐입니다.

profile
누구나 읽기 편한 글을 위해

0개의 댓글