HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
👻
개발 기록
/
📕
리팩터링 2판
/
코드에서 나는 악취

코드에서 나는 악취

 
기이한 이름
  • 마땅한 변수명이 떠오르지 않는다면 코드에 여러 기능이 있기 때문은 아닌지 의심하기.
  • 동의어 (display, show / render, paint, print)를 통일하고 풍부한 어휘력은 숨기기..
  • 함수 선언 바꾸기, 변수 이름 바꾸기, 필드 이름 바꾸기
중복 코드
  • 똑같은 코드 구조가 여러 곳에서 반복된다면 하나로 통합하자.
  • 함수 추출하기, 문장 슬라이드하기, 메서드 올리기
긴 함수
  • 주석을 달아야 할 만한 부분은 무조건 함수로 만든다.
  • 무엇을 하는지 코드가 설명해주지 못한다면 함수로 만들자.
  • 함수 추출하기, 임시 변수를 질의 함수로 바꾸기, 매개변수 객체 만들기, 객체 통째로 넘기기
긴 매개변수 목록
  • 매개변수 목록이 길어지면 그 자체로 이해하기 어렵다.
  • 매개변수를 질의 함수로 바꾸기, 객체 통째로 넘기기, 매개변수 객체 만들기, 플래그 인수 제거하기, 여러 함수를 클래스로 묶기
전역 데이터
  • 전역 데이터는 코드베이스 어디에서든 건드릴 수 있고 값을 누가 바꿨는지 찾아낼 메커니즘이 없다.
  • 변수 캡슐화하기
가변 데이터
  • 데이터 변경으로 인한 버그때문에 함수형 프로그래밍에서는 데이터는 절대 변하지 않고, 데이터를 변경하려면 반드시 변경하려는 값에 해당하는 복사본을 만들어서 반환하고 있다.
  • 하지만 함수형 언어가 프로그래밍에서 차지하는 비중은 적고 변수 값을 바꿀 수 있는 언어를 사용하는 프로그래머가 더 많다.
  • 변수 캡슐화하기, 변수 쪼개기, 문장 슬라이드하기, 함수 추출하기, 질의 함수와 변경 함수 분리하기, 세터 제거하기, 파생 변수를 질의 함수로 바꾸기, 여러 함수를 클래스로 묶기, 여러 함수를 변환 함수로 묶기, 참조를 값으로 바꾸기
뒤엉킨 변경
  • 단일 책임 원칙(SRP)이 제대로 지켜지지 않을 때 나타난다.
  • 하나의 모듈이 서로 다른 이유들로 인해 여러 가지 방식으로 변경되는 일이 많을 때 발생한다.
  • 단계 쪼개기, 함수 옮기기, 함수 추출하기, 클래스 추출하기
산탄총 수술
  • 코드를 변경할 때마다 변경할 부분이 코드 전반에 퍼져 있어 찾기 어렵고 수정할 곳을 놓치지 쉬운 경우다.
  • 작은 함수와 클래스를 권장하지만, 코드를 재구성하는 중간 과정에서는 큰 덩어리로 뭉쳐져도 된다.
  • 함수 옮기기, 필드 옮기기, 여러 함수를 클래스로 묶기, 여러 함수를 변환 함수로 묶기, 단계 쪼개기, 함수 인라인하기, 클래스 인라인하기
기능 편애
  • 프로그램을 모듈화할 때는 코드를 여러 영역으로 나눈 뒤 영역 안에서 이뤄지는 상호작용은 최대한 늘리고 영역 사이에서 이뤄지는 상호작용은 최소로 줄이는 데 주력한다.
  • 기능 편애는 자기가 속한 모듈 함수, 데이터보다 다른 모듈의 함수, 데이터와 상호작용 할 일이 더 많을 때 풍기는 냄새다.
  • 함수 옮기기, 함수 추출하기, 전략 패턴, 방문자 패턴
데이터 뭉치
  • 몰려다니는 데이터 뭉치는 보금자리를 따로 마련해줘야 한다.
  • 클래스 추출하기, 매개변수 객체 만들기, 객체 통째로 넘기기
기본형 집착
  • 금액을 숫자형으로 계산하거나, 물리량을 계산할 때 단위를 무시하고, 범위도 if(a < upper && a> lower)처럼 처리하는 코드가 많다.
  • 전화번호를 단순히 문자 집합으로만 표현하기엔 아쉬움이 많다.
  • ex) 인치를 숫자로 쓰지말고 인치 객체를 만들자. inch.value를 비교하란 뜻인듯.
  • 기본형을 객체로 바꾸기, 타입 코드를 서브클래스로 바꾸기, 조건부 로직을 다형성으로 바꾸기, 클래스 추출하기, 매개변수 객체 만들기
반복되는 switch문 📕
  • 조건절을 하나 추가할 때마다 다른 switch문들도 모두 찾아서 함께 수정해야 하는 문제가 있다.
  • 조건부 로직을 다형성으로 바꾸기
반복문
  • filter, map 같은 파이프라인 연산을 사용하면 코드에서 각 원소들이 어떻게 처리되는지 쉽게 파악할 수 있다.
  • 반복문을 파이프라인으로 바꾸기
성의 없는 요소
  • 만든 구조가 필요없어진다면 없애자.
  • 함수 인라인하기, 클래스 인라인하기, 계층 합치기
추측성 일반화
  • 미래를 대비해 당장은 필요 없는 모든 종류의 hooking 포인트와 특이 케이스 처리 로직을 작성해둔 코드는 좋지 않다.
  • 실제 사용하면 다행이지만, 그렇지 않는다면 시간 낭비일 뿐이다.
  • 계층 합치기, 함수 인라인하기, 클래스 인라인하기, 함수 선언 바꾸기, 죽은 코드 제거하기
임시 필드
  • 특정 상황에서만 값이 설정되는 필드를 가진 클래스의 경우 사용자에게 쓰이지 않는 것처럼 보이는 필드가 존재하는 이유를 파악하느라 시간을 써야하는 문제가 있다.
  • 클래스 추출하기, 함수 옮기기, 특이 케이스 추가하기
메시지 체인
  • 메시지 체인은 클라이언트가 한 객체를 통해 다른 객체를 얻은 뒤 방금 얻은 객체에서 또 다른 객체를 요청하는 식으로, 다른 객체를 요청하는 작업이 연쇄적으로 이어지는 코드를 말한다.
  • 내비게이션 중간 단계를 수정하면 클라이언트 코드도 수정해야 한다.
  • 위임 숨기기, 함수 추출하기, 함수 옮기기
중개자
  • 중개자가 지나치게 많을 경우(과반수) 중개자를 제거하여 실제로 일을 하는 객체와 직접 소통하자.
  • 중개자 제거하기, 함수 인라인하기
내부자 거래
  • 모듈 사이의 데이터 거래가 많으면 결합도가 높아진다. 그 양을 최소로 줄이자.
  • 함수 옮기기, 필드 옮기기, 위임 숨기기, 서브클래스를 위임으로 바꾸기, 슈퍼클래스를 위임으로 바꾸기
거대한 클래스
  • 한 클래스가 너무 많은 일을 하려다보면 필드 수가 늘어나고 중복 코드가 생기기 쉽다.
  • 클래스 추출하기, 슈퍼클래스 추출하기, 타입 코드를 서브클래스로 바꾸기
서로 다른 인터페이스의 대안 클래스들
  • 클래스는 필요에 따라 언제든 다른 클래스로 교체할 수 있다는 장점이 있다. 이를 활용하려면 교체하려는 인터페이스가 같아야 한다.
  • 함수 선언 바꾸기, 함수 옮기기, 슈퍼클래스 추출하기
데이터 클래스
  • 데이터 클래스란 데이터 필드와 게터/세터 메서드로만 구성된 클래스를 말한다.
  • 데이터 저장 용도로만 쓰이다 보니 다른 클래스가 너무 깊이까지 다룰 때가 많다.
  • 레코드 캡슐화하기, 세터 제거하기, 함수 옮기기, 함수 추출하기, 단계 쪼개기
상속 포기
  • 상속을 포기했을 때 문제가 생긴다면
    • 같은 계층에 서브클래스를 하나 만들고 메서드 내리기, 필드 내리기를 활용해서 물려받지 않을 부모 코드를 모조리 새로 만든 서브클래스로 넘긴다. 📕
  • 인터페이스를 따르지 않는다면
    • 서브클래스를 위임으로 바꾸기, 슈퍼클래스를 위임으로 바꾸기를 활용해 상속 매커니즘에서 벗어나보자.
    • 상속은 단일 책임 원칙에 위배된다. 부모에 대한 의존도가 높아진다.
주석
  • 주석이 장황하면 코드를 잘못 작성했기 때문인 경우가 많다.
  • 함수 추출하기, 함수 선언 바꾸기, 어서션 추가하기
얘기해보고 싶은 것
  • 클래스 형태의 코드를 짜려고 해야 할까?