본문 바로가기

programming study/Refactoring

Refactoring - 코드에서 나는 악취(4)

본 내용은 마틴 파울러의 Refactoring 2판을 토대로 작성되었습니다.

 

코드에서 나는 악취

중개자

  • 객체의 대표적인 기능 중 하나는 외부로부터 세부사항을 숨겨주는 캡슐화
  • 캡슐화하는 과정에서는 위임(delegation)이 자주 활용
  • 클래스가 제공하는 메서드 중 절반이 다른 클래스에 구현을 위임하는 것은 문제가 됨
    • 중개자 제거하기를 활용하여 실제로 일을 하는 객체와 직접 소통하게 함
  • 위임메서드를 제거한 후 남는 일이 거의 없다면 호출하는 쪽으로 함수 인라인 하기

 

내부자 거래

  • 모듈 사이의 데이터 거래가 많으면 결합도가 높아짐
  • 데이터를 주고받는 모듈들이 있으면 함수 옮기기필드 옮기기 기법으로 떼어놓아서 처리하는 부분을 줄임
  • 여러 모듈이 같은 관심사를 공유한다면 공통 부분을 정식으로 처리하는 제3의 모듈을 새로 만들거나 위임 숨기기를이용하여 다른 모듈이 중간자 역할을 하게 만듦
  • 상속 구조에서는 부모 자식 사이에 결탁이 생길 때가 많음
    • 서브클래스를 위임으로 바꾸기 or 슈퍼클래스를 위임으로 바꾸기

 

거대한 클래스

  • 한 클래스가 너무 많은 일을 하려다 보면 필드 수가 상당히 늘어남
  • 클래스에 필드가 너무 많으면 중복 코드가 생기기 쉬움
  • 클래스 추출하기로 필드들 일부를 따로 묶음
    • 같은 컴포넌트에 모아두는 것이 합당해 보이는 필드들을 선택
  • 한 클래스 안에서 접두어나 접미어가 같은 필드들이 함께 추출할 후보
  • 분리할 컴포넌트를 원래 클래스와 상속 관계로 만드는 게 좋다면
    • 슈퍼클래스 추출하기
    • 타입 코드를 서브클래스로 바꾸기
  • 코드량이 너무 많은 클래스도 중복 코드와 혼동을 일으킬 여지가 큼
    • 클래스 안에서 자체적으로 중복을 제거
    • 메서드 다섯 개가 있으면 각각의 공통 부분을 작은 메서드로 뽑아내기

 

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

  • 클래스를 사용할 때의 큰 장점은 필요에 따라 언제든 다른 클래스로 교체
    • 교체하려면 인터페이스가 같아야 함
  • 함수 선언 바꾸기로 메서드 시그니처를 일치
  • 함수 옮기기를 이용하여 인터페이스가 같아질 때까지 필요한 동작들을 클래스 안으로 밀어 넣음
  • 대안 클래스들 사이에 중복 코드가 생기면 슈퍼클래스 추출하기를 적용할 지 고려

 

데이터 클래스

  • 데이터 클래스란 데이터 필드와 게터/세터 메서드로만 구성된 클래스를 말함
    • 그저 데이터 저장 용도로만 사용
    • 다른 클래스가 너무 깊이까지 함부로 다룰 때가 많음
  • public 필드가 있다면 레코드 캡슐화하기로 숨길 것
  • 변경하면 안 되는 필드는 세터 제거하기로 접근을 원천 봉쇄
  • 다른 클래스에서 데이터 클래스의 게터나 세터를 사용하는 메서드를 찾아 함수 옮기기로 그 메서드를 데이터 클래스로 옮길 수 있는지 살펴보기
  • 옮기기 어렵다면, 함수 추출하기를 이용해서 옮길 수 있는 부분만 별도 메서드로 뽑아냄
  • 데이터 클래스는 필요한 동작이 엉뚱한 곳에 정의되어 있다는 신호일 수 있음
    • 클라이언트 코드를 데이터 클래스로 옮기기만 해도 대폭 개선
    • 다른 함수를 호출해 얻은 결과 레코드 (데이터 객체)로는 동작 코드를 넣을 이유가 없음
    • ex) 단계 쪼개기의 결과로 나온 중간 데이터 구조는 불변이므로 캡슐화할 필요는 없음

 

상속 포기

  • 서브 클래스는 부모로부터 메서드와 데이터를 물려받음
    • 부모의 유산을 원치 않거나 필요 없는 경우
    • 몇 개만 받고 끝내려는 경우
  • 예전에는 계층 구조를 잘못 설계했기 때문으로 봤음
    • 먼저 같은 계층에 서브 클래스를 하나 새로 만들고 메서드 내리기필드 내리기를 활용해서 물려받지 않을 부모 코드를 모조리 새로 만든 서브 클래스로 옮김
    • 부모에는 공통된 부분만 남음
    • 부모 클래스는 모두 추상 클래스여야 한다고 말하는 경우도 있음
  • 일부 동작을 재활용하기 위한 목적으로 상속을 활용
    • 실무 관점에서 아주 유용한 방식
    • 상속을 포기할 시 혼란과 문제가 생긴다면 앞의 예전 방식을 따를 것
  • 상속 포기는 서브 클래스가 부모의 동작은 필요로 하지만 인터페이스를 따르고 싶지 않을 때
    • 서브클래스를 위임으로 바꾸기 또는 슈퍼 클래스를 위임으로 바꾸기를 활용해서 상속 메커니즘을 벗어날 것

 

주석

  • 주석은 악취가 아닌 향기
    • But. 탈취제처럼 사용하지 말 것
  • 주석이 장황한 경우 코드를 잘못 작성한 것
    • 온갖 악취를 풍기는 코드
  • 특정 코드 블록이 하는 일에 주석을 남기고 싶다면 함수 추출하기를 적용
  • 이미 추출되어 있는 함수임에도 여전히 설명이 필요하면 함수 선언 바꾸기
  • 시스템이 동작하기 위한 실행조건을 명시하고 싶다면 어서션 추가하기
  • 주석을 남겨야겠다는 생각이 들면, 가장 먼저 주석이 필요 없는 코드로 리팩터링
  • 무엇을 할 지 모를 때라면 주석을 달면 좋음
    • 현재 진행 상황
    • 확실하지 않은 부분
    • 코드를 지금처럼 작성한 이유를 설명하는 용도