포스트

클린 코드를 읽고, 읽기 쉬운 코드의 기준이 달라졌다

클린 코드를 읽고, 읽기 쉬운 코드의 기준이 달라졌다

나는 이전부터 다른 사람이 쉽게 이해할 수 있는 코드가 좋은 코드라고 생각했다. 실행 결과가 올바른 것은 기본이고, 이후에 코드를 읽을 사람에게 의도가 잘 전달되어야 한다고 보았다.

그래서 변수명과 메서드명을 가능한 한 구체적으로 짓고, 긴 메서드는 작은 단위로 나누려고 했다. 클래스와 DTO도 역할에 따라 분리하고, 하나의 코드가 너무 많은 책임을 맡지 않도록 신경 썼다. 방향은 틀리지 않았지만 당시의 기준은 아직 막연했다. “읽기 쉽다”는 느낌을 무엇으로 판단해야 하는지 분명하게 설명하기는 어려웠다.

『클린 코드』를 읽고 새롭게 얻은 것은 원칙의 목록보다 그 느낌을 점검할 수 있는 기준이었다. 의미 있는 이름, 작은 함수, 명확한 책임, 일관된 구조는 서로 떨어진 규칙이 아니었다. 코드를 읽는 사람이 적은 추론으로 작성자의 의도를 파악하게 만드는 방법들이었다.

가독성은 코드가 얼마나 짧은지가 아니라, 의도를 이해하기 위해 얼마나 적게 추론해도 되는지에 가깝다.

1. 막연했던 ‘읽기 쉬움’이 구체적인 기준이 되었다

예전에도 짧다는 이유만으로 좋은 코드라고 생각하지는 않았다. 다만 이름을 자세히 짓고 메서드를 나누면 읽기 좋아진다는 정도로 이해했다. 각각의 방법이 왜 필요한지, 어느 지점에서 오히려 복잡함을 만드는지까지는 깊이 생각하지 못했다.

책을 읽은 뒤에는 읽기 쉬운 코드를 조금 더 구체적으로 바라보게 되었다.

  • 이름을 읽었을 때 역할을 예상할 수 있는가
  • 한 함수 안의 코드가 같은 수준의 이야기를 하고 있는가
  • 변경 이유가 다른 책임이 한곳에 섞여 있지는 않은가
  • 비슷한 구조가 프로젝트 전반에서 일관되게 사용되는가

이 기준은 모두 같은 방향을 가리킨다. 코드를 처음 보는 사람이 머릿속에서 이름을 다시 해석하거나 여러 책임을 분리해 가며 읽지 않아도 되는 구조다. 좋은 이름 하나나 짧은 함수 하나만으로 가독성이 완성되는 것이 아니라, 이름과 구조와 책임이 함께 의도를 설명해야 한다.

2. 줄 수를 줄인다고 이해 비용까지 줄어들지는 않는다

짧은 코드는 한 화면에 들어오고 얼핏 간결해 보인다. 하지만 축약된 변수명, 여러 조건이 겹친 표현식, 조회와 검증과 저장을 한 번에 처리하는 메서드가 모이면 읽는 사람은 생략된 맥락을 직접 복원해야 한다.

예를 들어 한 메서드가 요청 검증, 비즈니스 규칙 확인, 데이터 변환, 저장을 모두 처리한다면 줄 수가 적어도 흐름을 한 번에 파악하기 어렵다. 각 단계에서 어떤 값이 바뀌는지, 실패할 수 있는 지점이 어디인지, 수정할 때 어디까지 영향을 받는지를 계속 추적해야 하기 때문이다.

반대로 메서드가 역할에 맞게 나뉘고, 이름만으로 다음 동작을 예상할 수 있다면 코드가 조금 길어져도 위에서 아래로 자연스럽게 읽힌다. 여기서 중요한 것은 무조건 잘게 쪼개는 일이 아니다. 메서드 이름이 실제 작업 단위를 설명하고 각 메서드가 비슷한 추상화 수준을 유지해야 한다.

짧지만 의도가 보이지 않는 코드와 역할과 흐름이 드러나는 코드 비교

코드의 길이보다 읽는 사람이 빈칸을 채우기 위해 수행해야 하는 추론의 양이 가독성을 더 잘 보여 준다.

이제는 코드를 얼마나 줄였는지보다 읽는 사람이 얼마나 적은 추론으로 의도를 이해할 수 있는지를 먼저 보려고 한다. 짧음은 결과일 수 있지만 목표가 되어서는 안 된다.

3. 주석을 줄이는 것이 아니라 코드가 먼저 설명하게 한다

책에서 가장 인상 깊었던 부분은 주석보다 코드 자체로 의도를 표현해야 한다는 관점이었다. 나도 평소 주석을 많이 작성하는 편은 아니었다. 변수명과 메서드명, 클래스 분리로 역할을 드러내려고 했다. 다만 이번에는 “주석을 적게 쓰는 것이 좋다”보다 더 중요한 의미를 이해하게 되었다.

주석이 없으면 이해하기 어려운 코드라면 주석을 추가하기 전에 코드가 설명을 가로막는 이유부터 찾아볼 수 있다.

  • 변수명과 메서드명이 역할을 충분히 설명하는가
  • 하나의 메서드가 여러 작업을 동시에 처리하는가
  • 변경 이유가 다른 책임이 한 클래스에 섞여 있는가
  • 복잡한 조건이나 비즈니스 규칙을 별도 개념으로 표현할 수 있는가

예를 들어 긴 조건식 위에 “결제 가능한 주문인지 확인”이라는 주석을 붙이는 대신, 조건 자체를 isEligibleForPayment처럼 의도가 드러나는 개념으로 분리할 수 있다. 그러면 독자는 조건의 세부 구현을 모두 해석하지 않고도 현재 흐름을 이해할 수 있다. 세부 규칙이 바뀌어도 상위 흐름의 의미는 유지된다.

그렇다고 모든 주석이 불필요한 것은 아니다. 코드가 무엇을 하는지는 이름과 구조로 설명할 수 있지만, 왜 이렇게 해야 하는지는 코드만으로 남기기 어려울 때가 있다. 특정 비즈니스 정책의 배경, 외부 시스템의 특이사항, 기술적 제약, 여러 선택지 중 현재 방식을 택한 이유는 주석으로 남길 가치가 있다.

중요한 것은 주석의 개수가 아니라 역할이다. 코드의 모호함을 덮는 주석은 구현과 함께 낡기 쉽지만, 코드 밖의 맥락을 보존하는 주석은 다음 판단에 필요한 정보를 제공한다.

4. 이름, 함수, 책임은 따로 개선되지 않는다

의미 있는 이름, 작은 함수, 단일 책임, 중복 제거는 각각 독립된 체크리스트처럼 보이지만 실제로는 서로 영향을 준다.

메서드가 여러 일을 하면 하나의 이름으로 역할을 설명하기 어렵다. 모호한 이름으로는 의도가 전달되지 않으니 주석이 필요해진다. 반대로 책임을 나누면 각 작업의 경계가 보이고, 그 경계에 맞는 구체적인 이름을 붙일 수 있다. 작은 함수는 단순히 줄 수가 적은 함수가 아니라 하나의 이름으로 설명할 수 있는 함수에 가까웠다.

클린 코드 원칙이 가독성과 유지보수성으로 이어지는 연결 구조

명확한 책임은 함수와 이름의 경계를 만들고, 그 결과 코드 자체가 의도를 설명하면서 이해와 변경에 드는 비용을 낮춘다.

이 관점은 이전에 작성한 코드도 다르게 보게 했다. 검색 조건과 응답 DTO를 분리했던 회고에서는 클래스 수를 줄이기보다 서로 다른 조회 목적을 타입으로 드러내는 편을 선택했다. JWT 인증 필터의 검증 책임을 분리한 글에서도 검증을 하나로 합쳐 짧게 만드는 대신 실패 원인과 변경 범위를 구분했다. 당시에는 역할 분리와 유지보수성을 중심으로 판단했는데, 지금 돌아보면 둘 다 읽는 사람이 코드에서 의도를 바로 찾게 만드는 선택이기도 했다.

중복 제거도 같은 맥락에서 봐야 한다. 비슷해 보이는 코드를 하나로 합치면 줄 수는 줄어든다. 하지만 변경 이유가 다른 코드까지 재사용만을 목적으로 묶으면 조건 분기와 추상화 계층이 늘고 의미는 오히려 흐려진다. 중복을 없앴는데 이해하기 더 어려워졌다면 그 추상화가 실제 문제를 해결하는지 다시 살펴야 한다.

그래서 앞으로는 다음과 같은 코드를 특히 경계하려고 한다.

  • 주석이 없으면 의도를 파악하기 어려운 코드
  • 한 메서드가 여러 작업을 처리하는 코드
  • 이름은 짧지만 의미가 불분명한 코드
  • 중복을 없애기 위해 지나치게 추상화한 코드
  • 재사용만을 목적으로 서로 다른 책임을 억지로 묶은 코드

결국 중요한 것은 원칙을 몇 개 지켰는지가 아니라 의도와 책임이 코드에 분명하게 드러나는지다.

5. 원칙은 정답이 아니라 판단을 돕는 질문이다

클린 코드의 원칙을 배웠다고 해서 모든 코드를 최대한 작은 단위로 나누고 새로운 추상화를 추가하는 것이 항상 좋은 선택은 아니다. 작은 메서드가 너무 많아지면 실제 흐름을 파악하려고 여러 파일을 오가야 할 수 있다. 아직 한 가지 사례밖에 없는 코드를 미리 일반화하면 사용되지 않는 확장 지점과 간접 계층만 남을 수도 있다.

개인 프로젝트에서는 이름 변경이나 책임 분리를 적극적으로 실험해 볼 수 있다. 실패하더라도 구조를 다시 바꾸기 쉽고, 그 과정 자체가 학습이 된다. 하지만 협업에서는 개인이 생각하는 이상적인 모양보다 팀의 컨벤션과 코드베이스 전체의 일관성이 더 중요할 때가 있다.

한 사람만 자신의 기준으로 메서드를 지나치게 세분화하거나 새로운 패턴을 도입하면 다른 팀원에게는 그 코드가 더 낯설어진다. 기존 코드와 다른 구조를 선택하려면 개인 취향이 아니라 해결하려는 문제와 얻는 이점을 설명할 수 있어야 한다. 코드 리뷰에서도 “클린 코드 원칙이니까”보다 현재 변경이 이해와 수정에 어떤 도움을 주는지 이야기하는 편이 더 생산적이다.

그래서 책의 원칙을 정답지보다 다음 질문을 꺼내는 도구로 사용하려고 한다.

  • 이 이름만으로 역할을 이해할 수 있는가
  • 이 메서드는 한 가지 책임에 집중하고 있는가
  • 이 추상화가 실제로 이해와 변경을 쉽게 만드는가
  • 팀원이 처음 읽어도 흐름을 따라갈 수 있는가
  • 현재 프로젝트의 규모와 요구사항에 적절한 설계인가

원칙을 적용하는 목적도 결국 사람과 상황에 맞는 판단을 내리는 데 있다.

6. 동작 확인 뒤에 한 번 더 읽어 보기

책을 읽기 전에는 구현을 마치면 요구사항대로 동작하는지, 예외 상황이 처리되는지, 테스트가 통과하는지를 먼저 확인했다. 앞으로는 여기서 끝내지 않고 다른 개발자가 이 코드를 처음 읽는다는 관점으로 한 번 더 살펴보려고 한다.

그때 확인할 질문은 다음과 같다.

  • 이름만 보고 역할을 예상할 수 있는가
  • 메서드의 시작부터 끝까지 하나의 흐름으로 읽히는가
  • 서로 다른 책임이 섞여 있지는 않은가
  • 주석 없이도 구현 의도를 이해할 수 있는가
  • 지나친 분리나 추상화로 오히려 복잡해지지는 않았는가

이 질문에는 모든 상황에 통하는 정답이 없다. 대신 코드를 작성할 때 놓쳤던 모호함을 리뷰하는 시점에 발견하게 해준다. 기능 구현자의 머릿속에는 이미 배경과 흐름이 들어 있지만, 처음 읽는 사람에게는 코드에 남아 있는 정보만 보인다. 잠시 구현자의 시선에서 벗어나 독자의 시선으로 읽는 과정이 필요한 이유다.

7. 다음 사람이 이해하고 변경하기 쉬운 코드

『클린 코드』를 읽고 완전히 새로운 목표가 생긴 것은 아니다. 다른 사람이 쉽게 이해할 수 있는 코드를 만들고 싶다는 생각은 이전에도 같았다. 달라진 점은 그 목표를 판단할 질문이 생겼다는 것이다.

좋은 이름은 책임의 경계를 드러내고, 명확한 책임은 함수를 자연스럽게 나누며, 잘 나뉜 흐름은 불필요한 설명을 줄인다. 반대로 원칙을 기계적으로 적용하면 작은 함수와 추상화가 늘어도 전체 흐름은 더 어려워질 수 있다. 결국 가독성은 특정 규칙 하나가 아니라 코드와 팀의 맥락을 함께 살피는 문제다.

앞으로는 정상 동작하는 코드를 완성점으로 보지 않고, 다른 사람이 적은 추론으로 이해하고 안전하게 바꿀 수 있는지도 함께 확인하려고 한다. 좋은 코드는 작성하는 순간 편한 코드가 아니라, 이후에 다른 사람이 읽고 수정하기 편한 코드이기 때문이다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.