코드는 컴퓨터가 아니라 사람을 위한 매체라는 관점에서, 저맥락과 고맥락 코드베이스를 대비하고 디자인 원칙의 한계를 비판한다. 타입·데이터·함수 설계를 통해 의도와 맥락을 내장해 협업과 개발자 경험을 향상하자고 촉구한다.
코드는 컴퓨터를 위한 것이 아니다. 그것은 동료, 협업자, 그리고 창의적 공모자들을 위한 것이다. 기계가 아니라 프로그래머가 우리의 작업의 주요한 청중이다. 너무도 자주, 그들은 적대적이고 버그로 들끓는 늪—내가 저맥락(low-context) 코드베이스라 부르는 것—을 헤쳐 나가라는 임무를 받는다. 한 줄 한 줄이 해를 끼치려는 듯하다. 모기처럼 쏘아대는 시그니처의 함수 호출, 의식을 흐리게 하거나 맹독성 뱀의 이빨처럼 염증을 키우는 매복한 부작용. 셀 수 없이 많은 이들이 ‘대개편’을 시도하다 이 전설적인 레거시의 땅에서 길을 잃었고—결국 “다른 우선순위”에 굴복하여—다음 사람을 가두어 버릴 미완성 작업의 반쯤 헤집어진 오솔길만 남겼다. 우리는 선의로 들어가지만, 더 나쁘게 만들 위험을 감수한다.
인간의 소통 매체로서 코드는 복잡한 상호작용, 도메인, 데이터 흐름을 서술한다. 물론 코드는 컴퓨터에서 반드시 실행되어야 한다. 짜증을 잘 내는, 달래고 다그쳐야만 하는 반항기 가득한 실리콘 조각들 위에서 말이다. 그렇다고 인간 청중을 희생해야 하는 것은 아니다. 그렇다고 해서 모든 함수를 난해하고 추상적이며 혼란스러운 방식(역방향 루프, 언어 기능 금지, 인라이닝 등)으로 마이크로 최적화해야 한다는 뜻도 아니다. 적어도 그것이 우리의 첫 번째 선택이어서는 안 된다1. 에디터와 IDE 안에서 들이는 노력은 사람을 위한 것이어야 한다.
사람을 위한 코딩은 직관적이고 자명해 보이지만, 종종 무시되거나 과소평가된다2. 코드에서 의도와 맥락을 전달하는 일은 빠른 납품 뒤로 밀리거나, 다른 이들이 우리의 코드를 어떻게 인지하고 상호작용할지에 대한 빈약한 이해에 의해 좌우된다. 기능을 끝내거나 성능을 개선하거나 ‘디자인 원칙’을 적용하는 것 정도가 우리가 허용받는 전부인 경우가 많다. 우리는 피상적인 “모범 사례”로 인간에게 잘 보이려고 애쓴다. SOLID, DRY, KISS, YAGNI 같은 깔끔한 약어들로 코드를 “올바른 상자”에 넣고, 원칙 빙고에서 만점 게임을 노린다: “모든 칸을 다 채웠으니, 내 코드는 분명 고품질이고 읽기 쉽다.”3 코드를 이해하는 일은 주관적이다. 우리는 그 반대로 행동하는 것을 멈춰야 한다. 디자인 원칙은 당신이 코드를 얼마나 훌륭하고 깨끗하고 우아하게 “쓸 수 있는지”에 지나치게 집중하고, 누가 이 코드를 읽을지, 그들이 어떻게 찾아낼지, 우아함 따위에 관심이나 있을지를 너무 적게 고민한다. 자아를 북돋우는 실천인 디자인 원칙은 더 이상 청중을 섬기지 못한다—애초에 그랬는지도 의문이다. 그것들은 코드를 해독하려는 이들에게는 너무 단순해서 도움이 되지 못하고, 의도와 맥락을 전달하는 근본 문제를 해결하지 못한다. 디자인 원칙은 자신들만의 간접화 층을 보태어 늪지 같은 코드의 팔림프세스트를 더 두껍게 만든다. 이렇게 더해진 층위(사실상 혼선)는 “클린 코드,” 이를테면 “변경 용이성” 같은 모호한 유지보수 이상에 지나치게 초점을 맞추고, 코드를 이해시키는 데에는 너무 적게 기여한다. 그것들은 이해하기 어려운 코드베이스 문제에 대한 인기 있는 “해결책”이다. 우리는 그것들을 적용하고, 새로운 수준의 품질에 도달했다고 자신하며, 코드 리뷰에서 그 중요성을 설파함으로써 그 믿음을 영속시킨다. _그 길_에서 벗어나는 일은 무능하고 사악한 프로그래머의 짓이라고 넌지시 암시하면서 말이다. 종교적 성전과 교리의 표지를 두르고 있지만, 디자인 원칙에는 덕목의 기미가 없진 않다. 그러나 우리는 단지 적용했다는 말을 하기 위해서 우리의 사용 사례를 억지로 늘려야 한다. 너무 단순하고 너무 구체적이라, 코드를 읽는 진짜 청중을 외면한다.
코드베이스가 SOLID하고 DRY하더라도, 여전히 늪 같고 위험천만할 수 있다. 감각이 박탈된 프로그래머는 악어 꼬리를 밟지 않기, 타르 웅덩이나 유사(流砂)에 빠지지 않기를 기도하듯 바라며 버그를 고치거나 새 기능을 추가하라는 임무를 맡는다. 우리는 저맥락 늪지에서 고유한 끝없는 기만적 방해물들에 압도되어 허우적댄다. 거기서 멀리—마른 땅 위—에는 고맥락 코드베이스가 있다. 위험한 형제와는 정반대로, 그것은 인간적이고 사려 깊으며 청중에 맞춤화되어 있다. 그것은 어떤 원칙의 성경에서 체크박스를 채우는 데 집중하지 않는다. 약어 주도 개발이 아니다. 억지로 꾸며낸 사용 사례 미신에도 집착하지 않는다. 고맥락 코드는 수십, 수백 명의 협업자가 사는 크고, 화려하고, 낡아가는 코드베이스 안의 도메인과 기능에 대해 사전 지식이 없는 청중을 배려한다. 고맥락 코드는 사람들이 그 코드를 어떻게 추론하는지를 활용한다. 우리가 미래의 어떤 이들이 우리 작업의 어느 부분에 걸려 넘어질지 알지 못하더라도, 그들의 성공을 안무한다.
누군가 코드를 추론하는 모습을 떠올리면, 나는 셜록 홈즈가 생각난다. 감지하기 힘든 단서를 집어내어 근거 있는 결론을 내리고 사건을 해결하는 그의 모습 말이다. 그는 타고난 탐정이지만, 우리의 코드베이스가 그런 드문 천재성을 요구해선 안 된다. 아니다, 고맥락 코드베이스는 평범한 우리 같은 이들이 추론할 수 있도록 설계되어야 한다. 홈즈의 충실한 동료 왓슨처럼, 우리는 명시적인 단서가 필요하다.
고맥락 코드베이스에서는 그러한 단서들이 의도적으로 코드의 모양, 데이터 구조, 값 속에 인코딩되어 있다. 그것들은 확실성을 전달하고, 추론 가능성을 증폭한다.
실천적으로는, 이것은 우리의 코드를 한발 물러서서 바라보는 것을 의미한다. 청중—우리의 동료들—을 고려하고, 그들의 관점에서 질문하는 것이다. 누군가가 1년 뒤 이 코드를 어떻게 읽을까? 어떻게 확장할까? 어떻게 디버깅할까? 그들이 데이터 구조의 가능성이나 함수나 클래스의 책임을 오해하게 되지는 않을까? 미끼는 무엇인가? 의도에 빛을 비추는 진실, 불변식, 단서는 무엇인가? 무엇이 그들을 길을 잃게 만들 수 있는가? 따를 특정한 코드 패턴 따위는 없다. 시카고 스타일 매뉴얼을 지키거나 Grammarly 점수 100점을 받는다고 글이 좋은 것이 아닌 것과 같다. 좋은 코드는 엄격한 규칙이나 디자인 원칙을 따른다고 나오지 않는다. 청중에 공감하는 결과물이다. 다음 프로그래머가 우리의 작업을 어떻게 이해할지—그들에게는 문맥이 거의 없거나 전혀 없을 것임을 인정하고—예측함으로써, 우리는 그들의 좌절과 맹점을 예상하고 그것을 분명한 단서로 상쇄할 수 있다. 늪지에 포장도로를 내어 그들을 올바른 해결로 안내하는 것이다.
단서는 신중히 선택된 코드 구조와 명확한 데이터 흐름의 형태로 나타날 수 있다. 순수 함수(pure function)의 평온한 자신감4, 상태 기계(state machine)의 기계학. 잘못된 필드 조합을 피하고 가능한 모든 값을 명시적으로 열거하기 위한 레코드와 합타입(sum types)의 적절한 적용5. 합성, 파이핑, 체이닝을 위해 설계된 함수. 불가능한 상태를 제거하기 위한 데이터 구조의 선택과 설계. 키워드 인자(keyword args)로 불리언 맹목(boolean blindness)을 피하는 것. 고맥락 코드베이스는 보장을 염두에 두고 설계되어, 시그니처와 명시적 상태, 타입만 힐끗 보아도 독자가 무엇을 걱정하고 무엇을 무시해도 되는지 직감할 수 있게 한다6.
맥락이 데이터 타입, 함수, 데이터 흐름, 불변식 속에 내장되면, 코드는 평평한 모서리의 알아볼 수 없는 네모난 퍼즐 조각에서 의도적이고 구체적인 방식으로 맞물리는 정밀한 홈과 패턴으로 변모한다. 맥락과 의도가 코드베이스의 직물에 꿰매져, 국소적 그리고 체계적 확실성을 낳는다. 추론할 때 우리는 이 맥락적 직물을 신뢰할 수 있다. 가느다란 섬유와 실 한 올에서부터 큰 폭의 천에 이르기까지, 그것은 이해와 협업의 주된 원천이 된다. 이런 방식으로—코드를 통해—우리는 사람들이 찾아내고 이어갈 수 있도록 작은 빵부스러기들을 남김으로써 시공을 넘어 협업한다.
협업적이고 고맥락인 코드베이스를 설계하려면 자아를 내려놓고 당신 역시 누군가의 코드의 청중임을 인정해야 한다(얼마나 자주, 당신은 어떤 코드를 이해할 수 없다고 여겼다가, 나중에 알고 보니 그게 바로 당신 자신의 작업이었다는 사실을 깨달았는가). 코딩은 이런 식으로 기만적이다. 당신의 코드가 자명하다고 믿게 만든다. 그러나 한 발 물러서서 청중의 시각에서 코드를 바라보면, 당신의 코드가 실제로 얼마나 늪 같은지 드러난다.
이제 당신 안의 ‘10배 개발자’를 내려놓을 때다. 그들은 무턱대고 코드를 찍어 내며, “팀의 다른 사람들은 그저 내 코드를 이해할 만큼 영리하지 않을 뿐”이라고 말한다. 문제는 그들의 “1배”가 아니라, 당신의 자아다. 개발자 경험(DX)을 설계하라: 코드 변경, 버그 수정, 삭제, 리팩터를 위한 설계다.
사람을 위해 설계하라. 사람을 위해 코드를 쓰라.