Be-Developer

Refactoring 03 코드에 나는 악취

03 코드에서 나는 악취

기이한 이름

  • 함수 선언 바꾸기 (이름바꾸기)
  • 변수 이름 바꾸기
  • 필드 이름 바꾸기
  • 마땅히 이름이 떠오르지 않는다면 설계에 더 근본적인 문제가 숨어있을 가능성이 높다.

    중복코드

  • 함수 추출하기
  • 문장 슬라이드하기 (비슷한 부분만 모아서)
  • 메서드 올리기 (서브클래스에서 중복이라면)

    긴 함수

  • 주석이 달릴만한 부분은 함수로
  • 함수 추출하기
  • 임의 변수를 질의함수로 바꾸기 (임시 변수 줄이기)
  • 매개변수 객체 만들기, 객체 통째로 넘기기 (매개변수 수 줄이기)
  • 함수를 명령으로 바꾸기
  • 조건문 분해하기
  • 조건부 로직을 다형성으로 바꾸기 (switch문이 여러개라면)
  • 반복문 쪼개기 (반복문을 메서드로 분리후 메서드명이 떠오르지 않는다면)

    긴 매개변수 목록

  • 매개변수 객체 만들기
  • 함수 동작방식을 정하는 플래그 인수 제거하기
  • 여러 함수를 클래스로 묶기
  • 매개변수를 질의함수로 바꾸기 (다른 매개변수에서 값을 얻어올 수 있는 매개변수가 있을때)
  • 객체 통채로 넘기기

    전역 데이터

  • 변수 캡슐화하기

    가변 데이터

  • 변수 캡슐화하기
  • 변수 쪼개기
  • 질의함수와 변경함수 분리하기
    • 문장 슬라이드하기
    • 함수 추출하기
  • setter 제거하기
  • 파생변수를 질의함수로 바꾸기
  • 여러 함수를 클래스로 묶기, 변환함수로 묶기.
  • 참조를 값으로 바꾸기. 내부 필드를 직접 수정하지않고 구조체를 통채로 교체하자.

    뒤엉킨 변경

  • SRP가 잘 지켜지지 않을때 나타난다.
  • 한 코드에 섞여들어감 - 맥락별로 분리
  • 단계쪼개기
  • 함수 옮기기 (처리과정의 맥락이 보이도록)
  • 함수 추출하기 (여러 맥락에 관여하는 함수라면)
  • 클래스 추출하기 (모듈이 클래스라면)

    산탄총 수술 (shotgun surgery)

  • 여러코드에 흩뿌려짐 -> 맥락별로 모음
  • 코드 변경시 수정해야할 클래스가 많을때.
  • 함수 옮기기, 필드옮기기
  • 여러 함수를 클래스고 , 변환함수로 묶기
  • 함수, 클래스 인라인하기
  • 리팩터링 당시에는 커질 수 있으나, 중간과정일뿐 나중에는 리팩터링으로 더 좋은 형태로 분리할 수 있다.

    기능 편애

  • 함수가 속한 모듈보다 다른 모듈과의 상호작용이 더 많을때
  • 함수 옮기기, 추출하기

    데이터 뭉치

  • 항상 같이다이는 데이터세트가 있는경우
  • 클래스 추출하기
  • 매개변수 객체만들기
  • 객체 통채로 넘기기
  • 데이터 뭉치인지 판별하려면 값 하나를 삭제해보자. 그랬을 때 나머지 데이터만으로는 의미가 없다면 데이터 뭉치라는것.

    기본형 집착

  • 화폐,좌표,구간 등을 if(a < uppper && a > lower) 처럼 단위를 무시하고 처리하는 경우가 생길수있음.
  • 기본형을 객체로 바꾸기.
  • 타입코드를 서브클래스로 바꾸기(12.6절)
  • 조건부로직을 다형성으로 바꾸기

    반복되는 스위치문

  • 조건절을 추가할때마다 다른 switch문도 챙겨 수정해야하기때문에, 반복되는경우 코드스멜이다.
  • 조건부 로직을 다형성으로 바꾸기.

    반복문

  • 반복문을 파이프라인으로 바꾸기. (stream)

    성의없는 요소

  • 메서드가 하나뿐인 클래스
  • 구조가 필요없어 보일때
  • 함수 인라인하기, 클래스 인라인하기
  • 계층 합치기

    추측성 일반화

  • 나중에 필요할거라는 생각으로 처리 로직을 작성한 경우.
  • 테스트코드말고는 사용하는 곳이 없는 함수나 클래스, 테스트먼저 제거하고 죽은코드 제거하기
  • 하는일이 없는 추상클래스는 계층 합치기
  • 함수 인라인하기. 클래스 인라인하기
  • 보눔ㄴ에서 사용되지않는 매개변수는 함수선언 바꾸기

    임시 필드

  • 특정 상황에서만 값이 설정되는 필드
  • 클래스 추출하기
  • 함수 옮기기
  • 특이케이스 추가하기 (필드들이 유효하지 않을때는 대안클래스로 제거하자)

    메시지 체인

  • 한 객체를 통해 다른 객체를 요청하는 작업이 연쇄적으로 발생하는 경우. getter의 연속
  • 위임 숨기기
    • a.manager.name -> a.managerName
  • 함수 추출하기
  • 함수 옮기기

    중재자

  • 클래스가 제공하는 메서드중 절반이 다른 클래스에 구현을 위임하고있다면, 중재자 제거하기.

    내부자 거래

  • 클래스끼리 교류가 많다면, 함수 옮기기, 필드 옮기기
  • 3의 모듈을 만들어 위임 숨기기
  • 상속구조에서 부모클래스를 이상으로 알려고 하고 부모품을 떠나야할때? 서브/슈퍼클래스를 위임으로 바꾸기

    거대한 클래스

  • 클래스 추출하기
    • 접두어나 접미어가 같은 필드들
  • 상속이 유리하다면, 슈퍼클래스 추출하기, 타입코드를 서브클래스로 바꾸기

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

  • 동일한 인터페이스를 추출하기위해
  • 함수선언 바꾸기
  • 함수 옮기기
  • 슈퍼클래스 추출하기

    데이터 클래스

  • 게터와 세터 메서드로만 구성된 클래스.
  • public 필드는 레코드캡슐화하기, setter 없애기
  • 필요한 동작이 엉뚱한곳에 있을수도 있다.
    • 함수 옮기기
    • 함수 추출하기
  • 데이터가 모두 불변일 경우 캡슐화하지 않아도 좋다.

    상속 포기

  • 서브클래스가 부모의 동작은 필요로 하지만, 인터페이스는 따르지 않을때
  • 서브/슈퍼클래스를 위임으로 바꾸기

    주석

  • 주석이 많으면 코드스멜이 나기 쉽다.
  • 주석을 남겨야겠다는 생각이 들면, 가장 먼저 주석이 필요없는 코드로 리팩터링 해본다.
    • 함수 추출하기
    • 함수 선언 바꾸기
    • 선행조건 assertion 추가하기
  • 코드를 작성한 이유에 대한 히스토리는 좋은 주석.