이 글은 몇 달 전 제 뉴스레터 독자들에게 보낸 내용을 바탕으로 작성되었습니다. 매주 이런 글을 받아보고 싶다면 여기서 구독하세요!
이전 글 '약간의 편의 기능으로 프로그래밍 흐름 지키기'에서는 가장 단순한 추상화조차도 코드베이스를 다루는 즐거움을 배가시킬 수 있다고 이야기했습니다.
그렇다면 나쁜 추상화를 만났을 때는 어떨까요?
분명히 leaderboard라고 지었어야 할 메서드의 실제 이름을 알아내려고 API 레퍼런스를 매번 펴놓고 뒤져야 한다면요? 리팩토링을 시도해도 코드의 한쪽에서는 구조화된 데이터를 넘겨주고 다른 쪽에서는 가공되지 않은 텍스트 줄을 던져줍니다. 그리고 그 코드를 건드릴 때마다 무언가가 깨지고, 하루 종일 디버깅에 시달리게 됩니다. position만 수정하고 score를 함께 업데이트하지 않았기 때문이죠.
그렇다면 어떻게 좋은 추상화를 만들면서 나쁜 추상화와는 거리를 유지할 수 있을까요?
좋은 은유로 더 명확한 코드 작성하기
좋은 추상화는 좋은 은유에서 태어납니다.
은유(metaphor)란 시스템 안의 무언가를 이미 머릿속에 있는 개념과 연결지어 설명하는 것입니다. 예를 들면 다음과 같습니다.
-
많은 커맨드라인 도구는 파이프(pipe)라는 은유를 사용합니다.
파이프 한쪽 끝에 데이터를 넣으면 반대쪽 끝에서 나옵니다. 상상하기 쉽고 사용하기도 쉽습니다.
-
동시성 프로그래밍에서 락(lock)은 훌륭한 은유입니다.
락이 내부적으로 어떻게 동작하는지 몰라도, 리소스가 잠겨 있으면 사용할 수 없고 잠금이 해제될 때까지 기다려야 한다는 것을 알 수 있습니다.
-
객체지향 프로그래밍(OOP)에서 메시지 전달(message passing)은 특정한 심상을 떠올리게 합니다. 한 객체가 다른 객체에게 메시지를 전달하면, 두 번째 객체는 그 메시지로 무언가를 하거나 다른 누군가에게 전달합니다.
구현 세부사항을 전혀 몰라도 개념을 파악할 수 있습니다. 덕분에 프록시 패턴 같은 것들도 훨씬 이해하기 쉬워집니다.
좋은 은유는 결정적인 역할을 합니다. 좋은 은유에 기반한 추상화를 마주치면 문서를 읽거나 소스 코드를 파헤치지 않고도 코드를 이해할 수 있는 경우가 많습니다. 더 좋은 은유를 떠올릴수록 시스템을 다른 사람에게 설명하기 쉬워지고, 나중에 그 시스템을 다룰 때도 훨씬 수월해집니다.
좋은 은유는 어떻게 떠올릴까?
좋은 은유는 구체적이고, 자기완결적이며, 설명하는 대상을 생생하게 머릿속에 그려줍니다. 오해의 여지를 남기지 않고, 코드의 실제 동작과 최대한 일치해야 합니다. 누군가 은유에 대한 이해를 바탕으로 코드에 대해 가정을 세운다면, 그 가정이 옳아야 합니다.
좋은 은유를 찾는 일은 쉽지 않습니다. 올바른 은유를 찾기 전까지 몇 번의 새는(leaky) 은유를 거치게 되곤 하는데, 괜찮습니다! 연습할수록 점점 쉬워집니다. 저에게 도움이 된 과정을 소개합니다.
먼저 코드가 어떻게 동작하는지는 잠시 잊고, 그 코드가 무엇을 하는지 생각해 보세요. 어떤 이미지가 떠오르나요? 다른 코드는 이것을 어떻게 사용하나요? 한두 단어로 설명해야 한다면 어떤 단어를 고르시겠어요? 그 단어를 적어두세요.
그다음, 그 이미지를 곱씹어 보세요. 실제 코드의 동작 방식과 맞나요? 은유가 새는 예외 사항(edge case)이 있나요? 새로운 기여자가 이 코드를 사용하려면 은유 외에 추가로 이해해야 할 것이 있나요? 은유를 떠올릴 때 머릿속에 선명한 그림이 그려지나요, 아니면 흐릿한가요?
이런 질문들은 은유가 코드와 충분히 잘 맞지 않는다는 신호입니다. 하지만 좋은 은유에 가까울수록, 목표 지점까지 도달하기 위해 필요한 도약의 폭은 줄어듭니다.
마지막으로, 은유를 문장으로 표현해 보세요. "이 코드는 ~이다. 왜냐하면…" 기술적인 배경지식이 없는 사람에게도 이 은유를 설명해서 코드의 역할을 이해시킬 수 있나요? 은유를 이해하는 데 필요한 배경지식이 적을수록, 그 은유는 더욱 유용합니다.
거의 다 왔는데 조금 아쉽다면 동의어 사전을 펴보세요. 비슷한 단어 사이의 미묘한 차이가 그저 그런 은유와 완벽한 은유를 가르는 결정적 차이가 됩니다.
은유와 객체지향 프로그래밍
객체지향 프로그래밍은 근본적으로 은유 위에 세워진 패러다임입니다. 바로 거기서 강력함이 나옵니다! 잘 설계된 클래스는 다른 클래스로부터 자신의 구현을 숨길 뿐만 아니라, 개발자 본인으로부터도 구현을 숨깁니다.
훌륭한 은유를 갖춘 클래스라면 클래스 이름만 봐도 객체를 어떻게 사용해야 하는지 알 수 있어야 합니다. 클래스 이름이 잘 지어져서 머릿속에 올바른 이미지를 불러일 수 있다면, 구현을 파헤치지 않고도 이해할 수 있습니다.
이제 최근에 다룬 코드 속 클래스들을 떠올려 보세요. 특히 명확한 은유를 가진 클래스가 있나요? 어떤 클래스는 함께 일하는 느낌이 들고, 어떤 클래스는 맞서 싸우는 느낌이 드나요? 그 클래스들을 사용하려고 구현을 뒤져본 적이 얼마나 자주 있나요?
여러분이 발견한 것들을 듣고 싶습니다. 댓글로 알려주세요.
훌륭한 소프트웨어 개발자로 빠르게 성장하려면, 자신이 작성하는 코드와 따르는 프로세스를 의식적으로 사고해야 합니다. 제가 도와드릴 수 있습니다.
『Practicing Rails』 32페이지 무료 샘플을 다운로드하고, 부담 없이 작은 규모로 이런 아이디어를 실험하는 방법을 배워보세요.