리펙토링 2판 읽고 요약해보기 (Chapter 3 ~ 4)

‘리펙토링’ 책을 읽고 3장부터 4장까지 요약해보려고 합니다.

코드에서 나는 악취

  • 냄새 나면 당장 갈아라

기이한 이름

  • 세계적인 기인이라는 느낌을 풍기고 싶더라도 꾹 참고 코드는 단순하고 명료하게 작성해야 한다.

  • 이름만 보고도 각각 무슨 일을 하고 어떻게 사용해야 하는지 명확히 알 수 있도록

  • 리펙토링

    • 함수 선언 바꾸기
    • 변수 이름 바꾸기
    • 필드 이름 바꾸기

중복 코드

  • 코드가 중복이라면 서로 차이점이 없는지 주의 깊게 살펴봐야 하는 부담 발생

  • 리펙토링

    • 함수 추출하기
    • 문장 슬라이스하기
    • 메소드 올리기

긴 함수

  • 간접 호출의 효과로 코드를 이해하고, 공유하고, 선택하기 쉬워진다는 장점은 함수를 짧게 구성할 때 나오는 것

  • 함수를 짧게 만드는 작업의 90%는 함수 추출하기 차지
    • 임시 변수를 질의 함수로 바꾸기
    • 매개변수 객체 만들기
    • 객체 통째로 넘기기
  • 함수를 명령으로 바꾸기도 고려

  • 주석을 참고해서 코드만으로는 목적을 이해하기 어려운 부분을 함수로 빼고 함수 이름은 주석 내용을 토대로 작명

  • 조건문, 반복문도 작업 분리

긴 매개변수 목록

  • 매개변수 목록이 길어지면 그 자체로 난해
    • 매개변수를 질의 함수로 바꾸기
    • 객체 통째로 넘기기
    • 매개변수 객체 만들기
    • 플래그 인수 제거하기
  • 클래스로 매개변수 목록을 줄이는 데 효과적인 수단

전역 데이터

  • 겪을 수 있는 가장 지독한 축

  • 전역 데이터는 코드 베이스 어디에서든 건드릴 수 있고 누가 값을 바꿨는지 찾아낼 메커니즘이 없다.

  • 변수 캡슐화

가변 데이터

  • 데이터를 변경했더니 예상치 못한 결과나 골치 아픈 버그로 이어지는 경우
    • 변수 캡슐화하기
    • 변수 쪼개기
  • 문장 슬라이드, 함수 추출로 갱신 코드 분리

  • 세터 제거

  • 값을 다른 곳에서 설절할 수 있는 가변 데이터가 풍기는 악취
    • 파생 변수를 질의 함수로 바꾸기
    • 여러 함수를 클래스로 묶기
    • 여러 함수를 변환 함수로 묶기
  • 구조체처럼 내부 필드에 데이터를 담는 경우
    • 참조를 값으로 변경

뒤엉킨 변경

  • 코드를 고치고 싶은 부분만 고칠 수 없으면 뒤엉킨 변경과 산탄총 수술 중 하나가 풍긴다.

  • 뒤엉킨 변경 발생 경우
    • 단일 책임 원칙이 잘 지켜지지 않을 때
  • 단계 쪼개기
  • 함수 옮기기
  • 함수 또는 클래스 추출하기

산탄총 수술

  • 뒤엉킨 변경과 비슷하지만 정반대

  • 코드를 변경할 때마다 자잘하게 수정해야 하는 클래스가 많을 때

  • 바꾸는 대상을 함수 옮기기 또는 필드 옮기기로 모두 한 모듈에 묶어두면 좋다.

  • 함수가 많다면 여러 함수를 클래스로 묶기

  • 데이터 구조를 바꾸면 여러 함수를 변환 함수로 묶기

  • 함수 인라인 또는 클래스 인라인도 산탄총 수술에 대처하는 좋은 방법

기능 편애

  • 어떤 함수가 자신의 모듈의 함수나 데이터보다 다른 모듈의 함수나 데이터와 상호 작용할 일이 더 많을 때
    • 소원대로 근처로 함수 추출해서 옮기기

데이터 뭉치

  • 필드 형태의 데이터 뭉치는 클래스 추출하기로 하나의 객체 묶기

  • 매개변수는 매개변수 객체 만들기 또는 객체 통째로 넘기기

  • 데이터 뭉치인지 확인하는 방법

    • 값 하나를 삭제해서 나머지 데이터만으로 의미가 없어지는지 확인

기본형 집착

  • 문자열로만 표현하는 악취

  • 기본형을 객체로 바꾸기

  • 조건부 동작을 제어하는 타입 코드

    • 타입 코드를 서브 클래스로 바꾸기
    • 조건부 로직을 다형성으로 바꾸기

반복되는 스위치문

  • 1990년대 후반까지 다형성의 가치가 적었지만, 지금은 단순히 스위치문을 썼다고 해서 자동으로 검토되지 않는다.

  • 중복된 스위치문

    • 조건을 하나 추가할 때마다 다른 스위치문도 모두 찾아서 함께 변경

반복문

  • 반복문을 파이프라인으로 바꾸기

성의없는 요소

  • 실질적으로 필요 없어진 프로그램 요소 제거
    • 함수 인라인하기
    • 클래스 인라인하기
    • 계층 합치기

추측성 일반화

  • “나중에 필요할 거야” 라는 생각
    • 당장 필요없는 모든 처리 로직을 작성해둔 코드에서 풍긴다.
  • 하는 일이 없는 추상 클래스는 계층 합치기

  • 쓸데없이 위임하는 코드는 함수 인라인하기 또는 클래스 인라인하기

  • 본문에서 사용하지 않는 매개변수는 함수 선언 변경

  • 테스트 케이스부터 삭제한 뒤에 죽은 코드 제거

임시 필드

  • 덩그러니 떨어진 필드들을 발견하면 클래스 추출하기와 함수 옮기기로 코드 조각을 모은다.

  • 특이 케이스 추가하기로 필드가 유효하지 않을 때 사용할 대안 클래스 작성

메시지 체인

  • 다른 객체를 요청하는 작업이 연쇄적으로 이어지는 코드

  • 위임 숨기기

  • 함수 추출하기 또는 함수 옮기기

중개자

  • 객체의 대표적인 기능인 캡슐화하는 과정에서 위임이 자주 활용되지만, 지나치면 문제

  • 중개자 제거하기로 실제 일하는 객체와 소통

내부자 거래

  • 은밀히 데이터를 주고받는 모듈이 있다면
    • 함수 옮기기
    • 필드 옮기기
    • 위임 숨기기
  • 부모 클래스를 떠나야 한다면
    • 서브클래스를 위임으로 변경 또는 슈퍼클래스를 위임으로 변경

거대한 클래스

  • 하나의 클래스가 너무 많은 일을 하면 필드 수 증가

  • 클래스 추출하기로 필드 일부를 묶는다.

  • 클래스와 상속 관계로 만드려면 슈퍼 클래스 추출하기나 타입 코드를 서브클래스로 바꾸기가 쉽다.

  • 클라이언트들이 거대 클래스를 사용하는지 패턴을 파악하여 단서를 얻을 수 있다.

    • 클래스 추출하기
    • 슈퍼클래스 추출하기
    • 타입 코드를 서브클래스로 바꾸기

서로 다른 인터페이스의 대안 클래스

  • 함수 선언 바꾸기로 클래스 메소드 시그니처를 일치시킨다.

  • 부족하면 함수 옮기기로 인터페이스가 같아질 때까지 클래스로 밀어 넣는다.

데이터 클래스

  • 다른 클래스가 너무 깊게 다룰 경우, 클래스에 퍼블릭 필드가 있다면 레코드 캡슐화하기로 숨기자

  • 바꾸면 안되는 필드는 세터 제거하기로 접근을 원천 봉쇄한다.

  • 다른 클래스에서 데이터 클래스의 게터나 세터를 사용하면 함수 옮기기로 추출

상속 포기

  • 계층 구조를 잘못 설계했으면 같은 계층에 서브 클래스를 만들고 메소드 내리기 또는 필드 내리기

  • 상속 메커니즘에서 벗어나기

    • 서브클래스를 위임으로 바꾸기
    • 슈퍼클래스를 위임으로 바꾸기

주석

  • 주석을 탈취제처럼 사용

  • 특정 코드 블록이 하는 일에 주석을 남기고 싶다면 함수 추출

  • 이미 추출되어도 설명이 필요하면 함수 선언

  • 선행 조건을 명시하고 싶으면 어서션 추가

  • 주석을 남겨야겠다는 생각이 들면, 가장 먼저 주석이 필요 없는 코드로 리펙토링

테스트 구축하기

  • 리펙토링을 잘 하려면 실수를 잡을 견고한 테스트 스위트 뒷받침

자가 테스트 코드의 가치

  • 모든 테스트를 완전히 자동화하고 그 결과까지 스스로 검사
    • 테스트가 컴파일만큼 쉽다.
  • 테스트 스위트는 강력한 버그 검출 도구
    • 버그를 찾는 데 걸리는 시간을 대폭 줄인다.
  • 테스트를 작성하기 좋은 시점은 프로그래밍을 시작하기 전
    • 코딩이 완료되는 시점을 정확하게 판단 가능
    • 테스트 주도 개발
  • 예시의 테스트 대상 코드
    • 생산 계획 검토 애플리케이션
  • 첫 번째 테스트
    • 실패해야 될 상황에서는 반드시 실패하게 만들자
  • 테스트 추가
    • 완벽하게 만드느라 테스트를 수행하지 못하느니, 불완전한 테스트라도 작성해 실행하는 게 낫다.
  • 픽스쳐 수정

  • 경계 조건 검사
    • 문제가 생길 가능성이 있는 경계 조건을 생각해보고 그 부분을 집중적으로 테스트하자.
  • 어차피 모든 버그를 잡아낼 수 없다고 생각하여 테스트를 작성하지 않는다면 대다수의 버그를 잡을 수 있는 기회를 날리는 셈

  • 버그 리포트를 받으면 가장 먼저 그 버그를 드러내는 단위 테스트부터 작성하자

다음 포스트에서 챕터 5 내용이 이어집니다.

Written on September 20, 2022