안티 바이크쉐딩
파킨슨의 사소함의 법칙 (Parkinson’s law of triviality) 으로도 잘 알려져 있는 바이크쉐딩 (Bikeshedding)1 은 조직이 중요한 일은 방치한 채 사소하고 작은 일에 불균형적으로 많은 시간을 할애하는 경향이 있음을 설명하는 단어입니다. 소프트웨어 프로젝트를 진행하면서 사소하거나 전체 프로젝트의 목표 달성에 비교적 중요하지 않은 세부 사항에 지나치게 시간을 쏟게 되었던 경험이 한 번쯤은 있을 것입니다.
프로젝트에 장기적으로 영향을 미치는 아키텍처나, 프레임워크 선택과 같은 중요한 부분들은 관습적인 부분이나 이전에 경험했던 프로젝트의 사례를 그대로 답습하거나 모호한 부분으로 남겨두고, 대신 변수나 클래스 네이밍, 코드 스타일, 패키지 구성, 테스트 커버리지 비율, 버저닝 컨벤션 등 비교적 덜 중요한 문제를 고민하는데 많은 시간을 보내게 되는 경우가 발생하곤 합니다. 그렇다면 우리는 어떻게 중요한 문제와 사소한 문제를 잘 구분하고, 이러한 함정에 잘 빠지지 않을 수 있을까요?
바이크쉐딩 피하기
많은 경우 바이크쉐딩은 조직 내에서 아래 조건들이 갖추어 질 때 발생합니다.2
- 어떤 안건의 내용이 상대적으로 쉽고, 대다수가 이해하고 있음
- 어떤 안건의 결정 방향에 대해 의견을 제시하고자 하는 사람들이 많음
- 어떤 안건에서 내릴 수 있는 결정 옵션간의 이득 차이가 크지 않음
- 어떤 안건에 대한 최종 결정을 내릴 수 있는 권한을 가진 사람이 없거나, 결론을 제시하지 않는 경우
바이크쉐딩은 문제가 되는 안건이 최종적으로 결론나거나 사라지기 전까지는 쉽게 해결되지 않습니다. 이러한 상황에서의 가장 쉬운 해결책은 결정을 내릴수 있는 독재자를 두는 것입니다. 그렇다면 누가 독재자가 되어야 할까요? 구성원을 리드할 수 있는 카리스마 있는 리더가 있다면 다행이지만, 매니저가 일일히 결정 사항에 개입하기 어려운 소규모 프로젝트거나 조직 구성이나 문화적인 영향 등으로 결정의 총대를 맬 사람이 나타나기 어려운 경우가 많습니다.
그러한 상황에서는 아래 세 가지 스텝으로 문제를 해결해 볼 수 있을 것입니다.
- 문제의 비용과 중요성 파악하기
- 중요하지 않은 문제는 중요한 문제와 같이 논의하지 않기
- 도구와 휴리스틱의 도움을 빌리기
문제의 비용과 중요도 파악하기
바이크쉐딩을 유발하는 문제들이라도 해결함으로써 프로젝트에 도움이 되지 않는 것은 아닙니다. 일관적인 코드스타일이나 규칙을 전체 프로젝트에 유지하는 것은 분명 코드의 유지보수에도 이득이 됩니다. 다만 어떤 스타일과 규칙을 적용할지에 대한 세부 사항에 대해 지나치게 많은 시간을 쏟는 것이 문제가 될 뿐이죠.
결국 결론을 내려야 하거나 해결해야 하는 하는 문제가 쏟는 비용대비 프로젝트의 성공에 얼마만큼 기여하는지 가늠하는 것이 필요합니다. 프로젝트의 성공이란 특정 시점에서 측정하기 어렵고 그 매트릭도 다양하므로 명확한 상관관계는 알 수 없어도 괜찮습니다. 단지 비용에 따라 기여도가 어떤 추이로 변화하는지 살펴볼 수 있으면 됩니다.
개별 문제에 대해 대략적인 비용-효율을 가늠해 봤다면 이를 아이젠하워 매트릭스3를 벤치마킹해서 사분면에 놓아 볼 수 있을 것입니다.
먼저 1사분면에 놓아지는 고비용-고기여 항목들은 논의나 결정에 필요한 비용이 크지만 그만큼 프로젝트의 성공에 중요한 것들입니다. 소프트웨어 아키텍처를 결정하거나, 핵심 기능을 구현하기 위한 프레임워크나 라이브러리를 결정하는 문제이지요. 고비용-고기여 항목들의 특징은 대부분 나중에 결정을 되바꾸기 어려운 항목이라는 것입니다. 데이터베이스와 같은 핵심 인프라스트럭처는 아무리 소프트웨어를 유연하게 설계해도 나중에 바꾸려면 많은 비용이 수반됩니다. 그래서 가장 중요한 문제들입니다.
다음으로 2사분면에 놓아지는 고비용-저기여 항목들은 비용이 크지만 사실 프로젝트의 성공에 크게 기여하지 않는 문제들입니다. 도메인 주도 설계에서 말하는 지원/일반 서브도메인에 해당하는 영역이라고 볼 수도 있습니다. 기여도가 작으니 아무리 획기적으로 개선해도 전체 프로젝트에 개선에 미치는 영향은 미미합니다.4 일년에 한두번 호출되는 아주 느린 운영용 API 가 있는데 이를 각종 기술을 동원해 수초내로 동작하도록 개선한다고 해서 비즈니스에 큰 도움이 되진 않을 것입니다.
그 다음으로는 3사분면에 놓아지는 저비용-저기여 항목들입니다. 이 항목들은 해결하는데 그다지 많은 비용이 들지는 않지만 그렇다고 결정 방향에 따라서 큰 차이가 없는 경우가 많습니다. 목표 테스트 커버리지를 70% 에서 80% 로 늘린다고 해서 프로젝트가 10%p 만큼 개선될까요? 일정 수준 이상의 테스트 커버리지 목표는 존재하는 것 만으로도 프로젝트의 안정성에 많은 기여를 할 수 있지만 세부적인 수준이 어떤지 중요한 것은 아닙니다.
마지막으로 4사분면에 놓아지는 저비용-고기여 항목들입니다. 이곳에 존재하는 항목들은 단순히 어떤 방식이던 적용하는 것만으로도 프로젝트에 많은 잇점을 가져다줍니다. 코드 스타일 규칙 정하기, 브랜치 전략 정하기, CI 과정에 테스트 커버리지 게이트 도입하기등이 이에 해당합니다.
위 사분면에서 바이크쉐딩은 저비용-고기여 항목들의 세부사항인 저비용-저기여 항목에 집착하면서 리소스를 낭비하는 것들로 정의할 수 있습니다. 중요한 것은 저비용 항목들은 말 그대로 결정을 바꾸는데 드는 비용도 적다는 것입니다. 어떤 결정이 중요한지 판별하는데 비용을 들이는 것보다 일단 어떤 결정을 내리고 유연하게 결정을 변경하는 자세가 필요합니다.
중요하지 않은 문제는 중요한 문제와 같이 논의하지 않기
사실 거창하게 사분면에 문제들을 분류하지 않아도 대다수의 사람들은 직관적으로 어떤 문제가 중요하고 그렇지 않은지 알고 있습니다. 다만 의식적으로 그 중요도에 따라 리소스를 분배하기가 어려운 것이 문제입니다. 조직 환경에서 우리는 참여의 표시로 자신의 의견을 표현해야 한다는 압력을 받습니다. 이때 잘 이해하고 있는 간단한 문제에 대해 이야기하는 것이 훨신 쉽기 때문에 더 중요한 문제가 있더라도 비교적 간단한 문제에 대해 이야기할 가능성이 높습니다. 이러한 상황에서 10 만큼 중요한 문제와 1 만큼 중요한 문제를 같은 자리에서 논의할 때 정확히 10:1의 시간을 분배할 수 있을까요?
따라서 명확하게 논의의 컨텍스트를 분리하는것도 바이크쉐딩을 피하는데 도움이 될 수 있습니다. 회의 자리라면 단일 안건 항목으로 회의를 진행하는 것이 좋습니다. 그것이 어렵다면 최소한 중요도와 비용이 비슷한 문제들끼리 비슷하게 묶는것이 좋습니다. 특히 저비용 문제들이라면 따로 회의를 할 것도 없이 간단하게 팀 메신저안에서 제안-채택하는 것 만으로도 충분할 수 있습니다. 무엇보다 중요한 것은 회의 참석자 수를 최소한의 핵심 관계자만으로 제한하는 것입니다.
만약 풀 리퀘스트를 요청하는 상황이라면 마찬가지로 하나의 풀 리퀘스트 안에 여러 변경사항을 섞지 않는 것이 좋습니다. 특히 바이크쉐딩이 발생할만한 사소한 변경 사항이 최소한으로 포함되도록 하나의 풀 리퀘스트에서 변경하는 코드 라인의 수를 최대한 작게 유지하는것이 중요합니다.
도구와 휴리스틱의 도움을 빌리기
바이크쉐딩을 피하기 위해서는 개개인이 바이크쉐딩의 존재를 인지하고 있는것이 가장 중요하지만 모든 상황에서 이를 의식하고 있는 것은 어렵습니다. 특히 풀 리퀘스트를 적게 유지하자, 코드 스타일은 어떻게 하자와 같은 구두로 합의한 모호한 규칙들은 언제라도 깨지기 쉽습니다.
따라서 도구로 해결할 수 있는 부분들은 최대한 그 힘을 빌려 인지적 비용의 낭비를 줄이는 것이 중요합니다. 코드 스타일은 언어별 공식 가이드나 구글, 에어비엔비와 같은 규모 있는 기업에서 배포한 스타일 가이드를 참고하되 통합 개발환경에서 스타일 위반 여부를 자동으로 교정해주는 플러그인을 활용하거나, 빌드 과정에서 위반 여부를 자동으로 검사하도록 강제하는것이 좋습니다. 만약 풀 리퀘스트의 규모를 제한하고 싶다면 깃허브 봇등을 활용해 풀 리퀘스트 이벤트를 받아서 총 변경 라인수가 400 라인이 넘으면 요청이 승인되지 않도록 제한해야 하고, 테스트 작성을 독려하고 싶다면 테스트 커버리지를 70% 이상 만족시키지 못하면 병합을 금지하세요.
여기서 중요한 것은 어떤 코드 스타일을 적용할 것인지, 라인 수 제한을 얼마로 할 것인지, 테스트 커버리지 제한이 구체적으로 얼마인지 당장은 중요하지 않다는 것입니다. 일단 적용하고, 불편하다면 그 시점에 개선하세요. 변경의 비용은 적습니다. 그러나 아마 미리 걱정한 것과 달리 불편함이 발생하는 상황은 많지 않을 것입니다.
도구의 힘을 빌리기 어려운 결정의 경우 일종의 휴리스틱을 적용하면 도움이 됩니다. 지금 당장 결정하기 어려우면 가장 간단한 방법을 일단 채택하는 것이죠. 프로젝트의 브랜치 전략을 결정해야 한다고 생각해봅시다. git-flow, github-flow, gitlab-flow, trunk-based 등 각 상황에 따라 장단점이 있는 브랜치 전략이 있고 저울질 해볼 수 있지만 특정한 시점에서는 충분한 정보가 없을 수 있습니다. 프로젝트 시작 시점에서 규모가 커질지 작아질지는 알 수 없습니다. 반드시 두 세개의 배포 페이즈에서 다중 릴리즈를 관리하는 것이 필요할지 알 수도 없고요.
많은 경우 이전에 경험했던 브랜치 전략이 익숙하다는 이유로 비슷한 전략을 선택할 수 있습니다. 혹은 기존에 사용했던 브랜치 전략이 마음에 안 들어서 필요 이상으로 복잡한 전략을 채택하려 할 수 있고요. 하지만 가장 최적의 전략은 프로젝트를 어느 정도 진행해보기 전까지 알기 어려운 경우가 대부분입니다. 그렇다고 아무 규칙없이 개발을 진행할 수는 없죠. 따라서 가장 간단하게 주 브랜치와 기능 브랜치 정도만 사용하면서 시작하는 것이 좋습니다. 반드시 처음부터 TBD 의 철학을 모두 따를 필요도 없습니다. 피처 플래그 관리와 즉각적인 배포가 힘든 프로젝트라면 그 시점에 브랜치 전략을 수정하면 됩니다.