노마드코더 | 클린코드 챌린지 (17~18 / 21) - 10. 클래스

/// <summary>
/// Nomad Coder - 클린코드 챌린지 (17~18 / 21) - 10장. 클래스
/// @author         : CloudD
/// @last update  : 2025. 06. 10.
/// @update
///     - 2025. 06. 10 : 최초 작성. (10장. 클래스)
/// </summary>


Chat GPT 가 생성한 '개발자의 독서' 이미지 #9


어제와 오늘은 10장 "클래스" 를 읽었습니다.
읽는 동안 인상 깊었던 내용과 기억하고 싶은 문장들을 정리해 봅니다.


클래스 체계

클래스는 높은 추상화 단계에서 낮은 추상화 단계로 작성해야 합니다.
그래야 마치 신문 기사처럼 자연스럽게 읽힙니다. 책에서 추천하는 클래스 구성 순서는 다음과 같습니다:

  1. (있다면) 정적 공개 상수
  2. 정적 비공개 변수
  3. 비공개 인스턴스 변수
  4. (거의 필요 없지만) 공개 변수
  5. 공개 함수
  6. 비공개 함수

클래스는 작아야 한다

클래스를 설계할 때도, 함수와 마찬가지로, 작게가 기본 규칙이다.
함수는 행 수로 크기를 측정했지만, 클래스는 맡은 책임을 센다.
작명은 클래스 크기를 줄이는 첫번째 관문이다. 간결한 이름이 떠오르지 않는다면 클래스 크기가 너무 커서 그렇다. 클래스 이름이 모호하다면 필경 클래스 책임이 너무 많아서다.
클래스 설명은 if, and, or, but 을 사용하지 않고서 25 단어 내외로 가능해야 한다.
도구 상자를 어떻게 관리하고 싶은가? 작은 서랍을 많이 두고 기능과 이름이 명확한 컴포넌트를 나눠 넣고 싶은가? 아니면 큰 서랍 몇 개를 두고 모두를 던져 넣고 싶은가?
작은 클래스 여럿으로 이뤄진 시스템이 더 바람직하다. 작은 클래스는 각자 맡은 책임이 하나며, 변경할 이유가 하나며, 다른 작은 클래스와 협력해 시스템에 필요한 동작을 수행한다.
클래스가 응집력을 잃는다면 쪼개라! 그래서 큰 함수를 작은 함수 여럿으로 쪼개다 보면 종종 작은 클래스 여럿으로 쪼갤 기회가 생긴다. 그러면서 프로그램에 점점 더 체계가 잡히고 구조가 투명해진다.


응집도

책에서는 원칙을 어긴 코드와, 이를 리팩터링한 예시를 나란히 보여줍니다. 리팩터링 후 코드의 길이는 오히려 길어졌는데, 그 이유는 다음과 같습니다:

  1. 좀 더 길고 서술적인 변수 이름을 사용한다.
  2. 코드에 주석을 추가하는 수단으로 함수 선언과 클래스 선언을 활용한다.
  3. 가독성을 높이고자 공백을 추가하고 형식을 맞추었다.

리팩터링을 진행한 방식도 기억하기 위해 기록합니다:

  1. 원래 프로그램의 정확한 동작을 검증하는 테스트 슈트를 작성
  2. 그런 다음, 한 번에 하나씩 수 차례에 걸쳐 조금씩 코드를 변경
  3. 코드를 변경할 때마다 테스트를 수행
  4. 원래 프로그램과 동일하게 동작하는지 확인
  5. 조금씩 원래 프로그램을 정리한 결과 최종 프로그램을 도출


변경하기 쉬운 클래스

대다수 시스템은 지속적인 변경이 가해진다. 그리고 뭔가 변경할 때마다 시스템 이 의도대로 동작하지 않을 위험이 따른다. 깨끗한 시스템은 클래스를 체계적으로 정리해 변경에 수반하는 위험을 낮춘다.
새 기능을 수정하거나 기존 기능을 변경할 때 건드릴 코드가 최소인 시스템 구조가 바람직하다. 이상적인 시스템이라면 새 기능을 추가할 때 시스템을 확장할 뿐 기존 코드를 변경하지는 않는다.
테스트가 가능할 정도로 시스템의 결합도를 낮추면 유연성과 재사용성도 더욱 높아진다.
시스템 요소가 서로 잘 격리되어 있으면 각 요소를 이해하기도 더 쉬워진다.


회고 및 소감

최근까지 제가 작업하던 Unity 프로젝트를 열어보면, 저와 팀원들이 만든 '만능 클래스' 들이 여기저기에 자리 잡고 있습니다. 큰 서랍 몇 개에 여러 도구를 던져 넣은 것 같은 구조입니다.

각각의 클래스들은 여러 역할을 감당하고 있었습니다. 심지어 같은 기능을 하는 함수가 '만능 클래스' 마다 중복되어 있기도 했습니다. 인력과 시간이 부족했다는 이유도 있지만, 코드 리뷰와 테스트에 좀 더 집중했다면 충분히 피할 수 있었던 실수였습니다.

참 슬픈 결과물입니다.
S.O.L.I.D 원칙을 제대로 지키며 리팩터링을 해두었다면 지금보다는 더 나은 결과물을 만들 수 있었을 것 같습니다.

10장에서 가장 아프게 다가온 문장을 적으며 이 글을 마무리 하려고 합니다.

단일 책임 원칙은 객체 지향 설계에서 더욱 중요한 개념이다. 또한 이해하고 지키기 수월한 개념이기도 하다. 하지만 이상하게도 이 원칙은 클래스 설계자가 가장 무시하는 규칙 중 하나다. 우리는 수많은 책임을 떠안은 클래스를 꾸준하게 접한다.
문제는 우리들 대다수가 프로그램이 돌아가면 일이 끝났다고 여기는 데 있다. 깨끗하고 체계적인 소프트웨어라는 다음 관심사로 전환하지 않는다. 프로그램으로 되돌아가 만능 클래스를 단일 책임 클래스 여럿으로 분리하는 대신 다음 문제로 넘어가버린다.

과거의 저와 제가 속한 팀을 돌아보게 하는 문장들 이었습니다.
왜 몇 년 전 이 책을 읽었을 때는 그냥 흘려보냈을까요? 왜 이제야 이 문장이 이렇게 아프게 느껴질까요?

저의 실패한 결과물에는 ~Manager, ~Handler 라는 이름을 가진 클래스가 여럿 있습니다. 당시에는 가장 '간결한 이름' 이라고 생각했지만, 돌이켜 보면 그 클래스들은 너무 많은 책임을 지고 있었고, 동시에 커다란 문제를 만든 원인이었습니다.

프로젝트의 초기에는 '동작하는 코드'를 목표로 삼았기에 S.O.L.I.D 원칙이나 시스템 최적화에는 신경을 많이 쓰지 못했습니다. 결국 르블랑의 법칙처럼, 정리할 시간은 결코 오지 않았습니다.

다음 프로젝트에서는 이 원칙들을 실천하고, 팀을 더 좋은 방향으로 이끌 수 있는 사람이 되고 싶습니다.
동작만 하는 코드가 아니라 깨끗한 코드를 작성하고 유지하는 것도 목표로 삼도록 하겠습니다.

CloudD

예술하는 프로그래머, 코딩하는 예술가

댓글 쓰기

다음 이전