로버트 "엉클 밥" 마틴의 소프트웨어, 인종, 성별, 정치에 관한 견해를 비판적으로 살펴봅니다.
로버트 "엉클 밥" 마틴이 다시 논의의 중심에 섰다. 이번에는 컨퍼런스에서 발표할 자리를 제안받았다가 나중에 취소되면 컨퍼런스 주최자와 발표자들을 고소할 계획을 세웠기 때문이다. 마틴은 애자일 선언문을 공동 작성하고, 여러 권의 책을 쓰고, 많은 강연을 해 온 인물로서 소프트웨어 업계에서 널리 존경받고 추종된다. 그러나 나는 개인적으로 그의 기술적 아이디어가 일관되게 독단적이고 부정확하다고 느꼈고, 그가 반복해서 성차별적 발언을 하며 자신이 속한 컨퍼런스와 커뮤니티에서 많은 사람이 불편함과 환영받지 못한다는 느낌을 갖게 했다고 본다. 또한 인종과 정치에 대한 그의 견해는 극도로 해롭다고 생각한다. 이 글은 마틴의 소프트웨어에 관한 견해가 왜 자주 도움이 되지 않고 잘못되었다고 생각하는지에 대한 입문서이자, 인종·성별·정치에 관한 그의 발언 몇 가지를 개괄하는 글이다.
먼저 마틴의 조언을 그 자체의 장점으로 검토해 보자. 그는 코드에 관해 무엇을 믿으며, 그것을 어떻게 정당화하는가?
마틴이 코드 작성에 대해 어떻게 생각하는지 소개하기 위해, 그의 2009년 저서 클린 코드1를 살펴보자. 샘 휴스는 이 책을 완전히 해부하고 싶다면 읽을 만한 상세한 블로그 글을 썼지만, 여기서는 인용문 몇 개만 가져오자.
마틴은 함수가 중첩된 제어 구조(조건문과 반복문)를 담을 만큼 커서는 안 된다고 말한다. 달리 말해 들여쓰기가 두 단계보다 깊어서는 안 된다는 것이다. 블록은 아마도 단일 함수 호출로 이루어진 한 줄이어야 한다고 말한다. 이상적인 함수는 _인자가 0개_여야 한다고 말하며(그런데도 부수 효과는 없어야 한다??), 인자가 세 개뿐인 함수도 혼란스럽고 테스트하기 어렵다고 한다. 가장 기이하게도, 마틴은 이상적인 함수의 길이가 _코드 2줄에서 4줄_이라고 단언한다. 이 조언은 실제로 장의 첫머리에 놓여 있다. 첫 번째이자 가장 중요한 규칙이다.
휴스는 이어서 FitNesse에서 가져온 코드에 대한 마틴의 리팩터링 예시를 논한다.
다시 말하겠다. 이것은 마틴 자신의 코드이며, 그의 개인적 기준에 따라 작성된 것이다. 학습 예시로 우리에게 제시된 이상형이다.
이 단계에서 고백하자면 내 Java 실력은 낡고 녹슬었다. 2008년에 나온 이 책만큼이나 낡고 녹슬었다. 그러나 설령 2008년이었다 해도, 이 코드는 읽을 수 없는 쓰레기였던 게 분명하지 않은가?
와일드카드
import는 무시하자.공개 정적 메서드 둘, 비공개 생성자 하나, 비공개 메서드 열다섯 개가 있다. 비공개 메서드 열다섯 개 중 무려 열세 개는 인자로 전달되지 않은 변수를 수정하는 등 부수 효과를 갖거나(
buildIncludeDirective는newPageContent에 부수 효과를 낸다), 부수 효과를 갖는 다른 메서드를 호출한다(include는buildIncludeDirective를 호출한다).isTestPage와findInheritedPage만이 부수 효과가 없는 것으로 보인다. 이들 역시 전달되지 않은 변수(각각pageData와testPage)를 사용하지만, 겉보기에는 부수 효과 없이 사용한다.
더 많은 예시를 원한다면 원문 글을 추천하지만, 요지는 사실상 책 전체가 이런 식의 나쁜 조언으로 가득하다는 것이다. 이제 _클린 코드_를 살펴봤으니, 그의 좀 더 최근 견해로 시선을 돌려 보자.
마틴은 2017년 블로그 글 "어두운 길"에서 특정 종류의 오류를 불가능하게 만드는 프로그래밍 언어를 논한다(Swift와 Kotlin의 예시를 살펴보며). 소프트웨어 결함이라는 주제에 대해 그는 다음과 같이 쓴다.
우리가 왜 언어 기능으로 결함을 막으려 하는지 스스로에게 물어보라. 답은 분명해야 한다. 이런 결함이 너무 자주 발생하기 때문에 막으려 하는 것이다.
이제 왜 이런 결함이 너무 자주 발생하는지 스스로에게 물어보라. 만약 언어가 이를 방지하지 않기 때문이라고 답한다면, 나는 당신에게 직장을 그만두고 프로그래머가 될 생각을 다시는 하지 말라고 강력히 권한다. 결함은 절대로 언어의 잘못이 아니기 때문이다. 결함은 _프로그래머_의 잘못이다. 결함을 만드는 것은 _프로그래머_이지 언어가 아니다.
사람들에게 "직장을 그만두고 프로그래머가 될 생각을 다시는 하지 말라"고 하는 문지기식 태도는 제쳐 두더라도, 이 견해는 명백히 터무니없다. 그는 바로 같은 블로그 글 앞부분에서 이렇게 말한다.
[Swift와 Kotlin]은 몇 가지 함수형 특성을 통합했다. 예를 들어 둘 다 람다를 갖는다. 이는 일반적으로 좋은 일이다. 함수형 프로그래밍에 대해 더 많이 배울수록 더 좋다.
함수형 프로그래밍은 왜 정적 타이핑과 다른가? 그는 이에 관해 사실상 아무런 근거도 제시하지 않는다. 그의 논리대로라면 함수형 프로그래밍도 프로그래머의 실수를 덮는 임시방편 아닌가? 더 나아가, 언어가 오류를 방지하기에 올바른 장소가 아니라면 왜 고수준 언어를 쓰는가? 프로그래머들이 좀 더 신중하기만 하다면 모두 기계어를 직접 작성하면 될 것이다!
이것은 마틴 이데올로기의 일관된 부분이다. "도구는 답이 아니다"에서 그는 이렇게 쓴다.
소프트웨어 대재앙의 해결책은 더 많은 도구가 아니다. 해결책은 더 나은 프로그래밍 규율이다.
[...]
그리고 바로 여기서 여러분은 대재앙의 원인과 명백한 해결책을 모두 볼 수 있다.
원인:
너무 많은 프로그래머가 일정 압박 아래에서 엉성한 지름길을 택한다.
너무 많은 다른 프로그래머가 그것이 괜찮다고 생각하고, 이를 비호한다.
명백한 해결책:
- 소프트웨어 규율과 전문성의 수준을 높인다.
- 엉성한 작업을 변명하지 않는다.
이런 사고방식은 마틴의 글 전반에 만연해 있다. 그는 더 나은 도구가 더 나은 코드를 작성하도록 돕는다는 사실을 무시한 채, TDD와 "규율"을 모든 프로그래밍 문제의 독단적 해결책으로 일관되게 내세운다. 물론 그것들이 "규율"을 완전히 대체하는 것은 아니다. 나쁜 코드를 개별 프로그래머 탓으로 돌리는 일은 쉽고 편안하다. 그러나 실제로 소프트웨어를 더 낫게 만드는 데 관심이 있다면, 신중함과 실수를 방지하는 도구의 사용은 상호 배타적이지 않다는 점을 깨달아야 한다. 실수를 방지하는 도구를 사용하면 널 포인터 예외와 이중 해제를 걱정하는 대신 더 높은 수준의 오류 방지에 정신적 에너지를 집중할 수 있다.
마틴은 테스트가 타입보다 우월한 이유를 그토록 많이 말하지만, 타입 시스템이 실제로 무엇을 하는지는 잘 이해하지 못하는 듯하다. 예를 들어 그는 이렇게 쓴다.
따라서 테스트 부담은 타이핑과 무관하다. 작성하고 실행하는 테스트의 수는 언어의 타입 시스템에 영향을 받지 않는다.
이에 대해 슈리람 크리슈나무르티는 이것이 사실적으로 틀린 이유를 설명하는 훌륭한 답변을 내놓았다.
건전한 타입 시스템은 특정 행위를 문자 그대로 배제한다. 따라서 그러한 행위가 배제될 때 작성하는 테스트 집합은 달라질 수 있을 뿐 아니라, 극단적으로는 반드시 달라져야 한다(예를 들어, 타입이 맞지 않는 테스트는 작성할 수 없다).
[...]
다른 이들도 지적했듯 매개변수성은 적절한 사례다. 관계적 매개변수성을 갖춘 언어와 매개변수적 타입(예: 모든 T에 대해)이 있다면, 이는 모든 T에 대한 강력한 보장을 지닌 전칭 한정자다. 전부를 테스트할 필요가 없다.
흥미롭게도 T에 대해 여러 타입에서 그렇게 하는 데는 _가치_가 있다. 테스트를 읽는 독자가 함수(예: 문서에서)를 이해하도록 설명력을 제공하기 때문이다. 실제로 @PyretLang의 테스트 기반 타입 추론은 그런 다형적 사용으로부터 한정자를 추론한다! [...]
좀 더 흥미로운 사례로 넘어가자. 장치 드라이버, 패킷 필터 등을 작성하고 있다고 가정하자. 특히 신경 쓰는 것 중 하나는 종료다. 그러므로 테스트하고 싶은 것 중 하나도 종료다.
종료는 재미있다. 원래 스레드에서처럼 증명과 테스트 가능성의 문제로 곧장 이어진다. 항상 종료한다는 것을 증명할 수는 없다. 여러 테스트를 실행하고 모두 종료했는지 확인할 수 있을 뿐이다. 시간 제한이 필요하다. 그것은 단지 "빨리 종료하지 않았다"는 뜻이다. 조금 뒤에는 종료했을 수도 있다.
물론 내가 거짓말을 하며 함정을 팠다. 정지 문제는 특정 언어에 대해서는 결정 불가능하다. 언어를 바꾸면 정지 문제를 쉽게 풀 수 있다. 모델 검사 수업에서 내가 내는 재미있는 퍼즐 하나는 정지 문제를 인코딩하고 그것이 자명하게 결정 가능해 보임을 보이는 것이다. 뭐라고.
그러니 이를 타입으로 되돌려 보자. 프로그래밍 언어 이론에서 표준적으로 연구하는 언어 중 하나는 단순 타입 람다 대수다. 그리고 단순 타입 람다 대수는 그 안의 모든 프로그램이 종료하도록 보장된다는 영광스러운 속성을 지닌다. 그 속성을 누리는 것은 타입 시스템 덕분이다.
이는 꽤나 놀라운 결과다. 완전한 람다를 포함하더라도 상당히 강력한 언어를 가질 수 있으며, 무엇을 하든 무한 루프에 빠지게 만들 수 없다.
[...]
어쨌든, 나는 이것이 결정적인 반박이라고 믿는다. "작성하고 실행하는 테스트의 수는 [분명히 영향을 받는다]"는 것이다. 언어의 타입 시스템에 의해.
물론 이것이 마틴이 나중에 같은 주장을 반복하는 것을 막지는 못한다.
이런 종류의 부정확함은 마틴에게서 지극히 흔하다. 다른 트윗 스레드에서는 정지 문제가 무엇인지, 그리고 그것이 증명 가능성과 어떻게 관련되는지를 근본적으로 오해한다.
마틴은 테스트와 규율이 소프트웨어 품질을 개선하기 위해 추구해야 할 주요 방법이라고 믿는 것으로 보이므로, 테스트에 관한 그의 생각을 살펴보자.
이는 자명하게 틀렸다. 무한한 출력을 생성할 수 있는 코드를 작성한다면 모든 출력을 테스트할 수 없기 때문이다. 마틴은 이에 응답하면서, 우리는 무한 상태 기계가 아니라 유한 상태 기계로 작업하므로 상관없다고 말한다. 이는 큰 입력 집합을 테스트하는 현실 세계의 비실용성을 완전히 무시한다. 64비트 숫자 두 개의 곱셈을 테스트하고2, 각 테스트에 1나노초가 걸린다면 답을 얻기까지 10²²년을 기다리게 된다(약 1해 년이다). 개인적으로 내가 테스트를 작성하는 프로그램 대부분은 64비트 숫자 두 개를 곱하는 것보다 복잡하므로, 코드가 보게 될 모든 경우를 테스트하는 것보다 더 강력한 도구가 필요하다. 크고 복잡한 시스템을 테스트하는 데 도움이 될 도구를 실제로 배우고 싶다면, 단위 테스트에 더해 속성 기반 테스트와 생성 테스트를 사용하는 것을 고려하라.
마틴은 코드를 더 좋게 만들기 위한 작고 독단적이며 잘못된 기술적 아이디어 집합을 옹호하지만, 대부분의 사람이 그에게 화를 내는 이유는 그것이 아니다. 사람들이 그의 인종과 성별에 관한 견해, 특히 권력의 위치에 있는 사람이 그러한 견해를 표현하는 방식이 그가 속한 커뮤니티의 사람들에게 끼치는 해악에 불쾌감을 느끼는 경우가 훨씬 더 많다. 이런 견해 몇 가지를 빠르게 둘러보자.
마틴은 트럼프의 인용문을 트윗했고, 트럼프에게 투표했으며, 트럼프 정책에는 "동의할 것이 많다"고 말해 왔다.
마틴은 컨퍼런스 강연과 블로그 글에서 성차별적 발언을 해 온 길고 잘 알려진 이력이 있다. 그는 2009년 RailsConf 기조연설 중 성차별적 발언을 했다. 이후 "말실수를 했다"고 말했지만, 강연에서 해당 부분을 제거하지는 않았다. 2012년 그는 더 많은 성차별적 발언을 한 것에 대해 사과했지만, 그 발언에 대한 사과가 여성 비서, 하렘, 첩에 관한 여러 성차별적 비유가 담긴 블로그 글을 쓰는 일을 막지는 못했다. 그는 사과했지만, 그렇다고 제임스 데모어를 옹호하는 것을 멈추지는 않았다. 그는 성차별적 발언을 하고, 사과한 뒤, 정확히 같은 일을 계속해서 반복해 온 오랜 이력이 있다.
마틴은 국가 연주 중 기립하지 않은 NFL 선수들이 "혐오스럽다"며 해고되어야 한다고 말한다(다만 그는 취소 문화에는 반대하고, 논쟁 때문에 사람을 해고하는 일은 "악하다"고 생각한다). 또한 경찰은 유색인종을 표적으로 삼지 않으며, 미국은 노예제를 기반으로 건국되지 않았다고 쓴다.
나는 왜 এত 많은 사람이 로버트 마틴을 따르고 존경하는지 계속해서 이해할 수 없다. 그의 기술적 견해는 독단적이고 자주 틀리며, 그는 일관되게 성차별적이었고 인종주의와 권위주의를 변호해 왔다. 마틴의 작업을 존경하고 따른다면, 왜 그런지 평가해 볼 가치가 있다고 생각하며, 이 글이 그렇게 하는 데 도움이 되기를 바란다.
마틴은 이 글에 불쾌해하지 않을 것이라 믿는다.
이 글의 출처·논평·피드백·토론에 도움을 준 힐렐 웨인, 댄 루, 그리고 익명을 선호하는 한 명 이상의 사람에게 감사한다
나는 _클린 코드_를 읽지 않았지만, 내가 신뢰하는 사람들의 발췌문과 서평을 바탕으로 볼 때 굳이 읽을 필요를 느끼지 않는다. 직접 인용문을 통해 명백히 나쁜 조언을 충분히 읽었기에, 책 전체를 읽는 데 시간을 쓰고 싶지는 않다.↩
이런 종류의 테스트가 비실용적이며 아무도 하지 않을 일이라고 생각한다면, CPU 제조업체가 이런 종류의 동작을 정기적으로 테스트하며, 잘못되었을 때 상당한 대가를 치른다는 점을 고려하라.↩