리팩터링 Chapter 3

·2021년 12월 25일
0

REFACTORING

목록 보기
2/2
post-thumbnail

Refactoring :

  • [명사] 소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하기 수정하기 쉽도록 내부 구조를 변경하는 기법
  • [동사] 소프트웨어의 겉보기 동작은 그대로 유지한 채, 여러 가지 리팩터링 기법을 적용해서 소프트웨어를 재구성하다

작성중

Chapter 3 코드에서 나는 악취

기이한 이름 Mysterious Name

코드를 명료하게 표현하는 데 가장 중요한 요소 하나는 '이름'이다. 그래서 함수, 모듈, 변수, 클래스 등은 그 이름만 보고도 각각이 무슨 일을 하고 어떻게 사용해야 하는지 명확히 할 수 있도록 엄청나게 신경 써서 이름을 지어야 한다.

명확한 이름이 떠오르지 않는다면 설계에 문제가 있을 가능성이 높다

  • 함수 선언 바꾸기
  • 변수 이름 바꾸기
  • 필드 이름 바꾸기
    위와 같은 리팩터링 기법을 많이 사용하게 된다

중복 코드 Duplicated Code

코드가 중복되면 각각을 볼 때마다 서로 차이점은 없는지 주의 깊게 살펴봐야 하는 부담이 생긴다.
똑같은 코드가 반복된다면 하나로 통합하여 더 나은 프로그램을 만들 수 있다.

  • 예를들어 한 클래스에 딸린 두 메서드가 똑같은 표현식을 사용하는 경우 함수 추출하기를 써서 양쪽 모두 추출된 메서드를 호출하게 바꾸면 된다.
  • 코드가 비슷하지만 완전히 동일하지 않다면 문장 슬라이드하기로 비슷한 부분을 한 곳에 모아 함수 추출하기를 더 쉽게 적용할 수 있는지 살펴본다.
  • 같은 부모로부터 파생된 서브 클래스들에 코드가 중복되어 있다면 메서드 올리기로 부모로 옮긴다.

긴 함수 Long Function

긴 매개변수 목록 Long Parameter List

매개변수 목록이 길어지면 그 자체로 이해하기 어려울 때가 많다

  • 종종 다른 매개변수에서 값을 얻어올 수 있는 매개변수가 있을 수 있는데, 이럴 땐 매개변수를 질의 함수로 바꾸기로 제거 할 수 있다.
  • 사용중인 데이터 구조에서 값들을 뽑아 각각을 별개의 매개변수로 전달하는 코드라면 객체 통째로 넘기기를 적용해서 원번 데이터 구조를 그대로 전달한다.
  • 항상 함께 전달되는 매개변수들은 매개변수 객체 만들기로 하나로 묶는다
  • 함수의 동작 방식을 정하는 플래그 역할의 매개변수는 플래그 인수 제거하기로 제거한다
  • 여러개의 함수가 특정 매개변수들의 값을 공통으로 사용하면 여러 함수를 클래스로 묶기 를 이용하여 공통 값들을 클래스의 필드로 정의한다

전역 데이터 Global Data

우리가 겪을 수 있는 가장 지독한 축에 속한다. 전역 데이터는 코드 베이스 어디에서든 건드릴 수 있고 값을 누가 바꿨는지 찾아낼 메커니즘이 없다는 게 문제다. 버그는 끊임없이 발생하는데 그 원인이 되는 코드를 찾아내기가 굉장히 어렵다.

  • 이를 해결하기 위해 대표적인 방법으로 변수 캡슐화하기를 사용한다. 다른 코드에서 오염시킬 가능성을 있는 데이터를 발견할 때마다 이 기법을 가장 먼저 적용한다

가변 데이터 Mutable Data

코드의 다른 곳에서는 다른 값을 기대한다는 사실을 인식하지 못한 채 수정해버리면 프로그램이 오작동한다. 특히 이 문제가 아주 드문 조건에서만 발생한다면 원인을 알아내기가 매우 어렵다.

이런 이유로 함수형 프로그래밍에서는 데이터는 절대 변하지 않고, 데이터를 변경하려면 반듯이 (원래 데이터는 그대로 둔 채) 변경하려는 값에 해당하는 복사본을 만들어서 반환한다는 개념을 기본으로 삼고있다.

  • 변수 캡슐화하기를 적용하여 정해놓은 함수를 거쳐야만 값을 수정할 수 있도록 하면 값이 어떻게 수정되는지 감시하거나 코드를 개선하기 쉽다
  • 하나의 변수에 용도가 다른 값들을 저장하느라 값을 갱신하는 경우는 변수 쪼개기를 이용하여 용도별로 독립 변수에 저장 하게 하여 값 갱신이 문제를 일으킬 여지를 없앤다
  • 갱신 로직은 다른 코드와 떨어뜨려 놓는게 좋다 문장 슬라이드하기함수 추출하기를 이용해서 무언가를 갱신하는 코드로부터 부작용이 없는 코드를 분리한다
  • API를 만들 때는 질의 함수와 변경 함수 분리하기를 활용해서 꼭 필요한 경우가 아니라면 부작용이 있는 코드를 호출할 수 없게 한다

뒤엉킨 변경 Divergent Change

단일책임원칙(Single Reponsivility Prinsiple)이 지쳐지지 않을 때 나타난다.

  • 단계 쪼개기로 단계를 분리하거나
  • 전체 처리 과정 곳곳에서 각기 다른 맥락의 함수를 호출하는 빈도가 높다면 함수 옮기기로 관련 함수들을 모은다
  • 여러 맥락의 일에 관여하는 함수가 있다면 함수 추출하기부터 수행이 먼저다

산탄총 수술 Shotgun Surgery

뒤엉킨 변경과 비슷하면서 정반대이다. 코드를 변경할 때마다 자잘하게 수정해야 하는 클래스가 많을 때를 말한다.

  • 함께 변경되는 대상들을 함수 옮기기필드 옮기기로 모두 한 모듈에 묶어두며 좋다
  • 비슷한 데이터를 다루는 함수가 많다면 여러 함수를 클래스로 묶기를 적용한다
  • 데이터 구조를 변환하거나 보강하는 함수들에는 여러 함수를 변환 함수로 묶기를 적용한다
  • 이렇게 묶은 함수들의 출력 결과를 묶어서 다음 단계의 로직으로 전달 할 수 있다면 단계 쪼개기를 적용한다
  • 어설프게 분리된 로직을 함수 인라인하기클래스 인라인하기 같은 인라인 리팩터링으로 하나로 합치는것도 좋은 방법이다

기능 편애 Feature Envy

어떤 함수가 자기가 속한 모듈의 함수나 데이터보다 다른 모듈의 함수나 데이터와 상호작용 할 일이 더 많은것을 말한다.

  • 함수 옮기기, 함수 추출하기로 해결 할 수 있다.

데이터 뭉치 Data Clumps

몰려다니는 데이터는 분리해야한다

  • 필드 형태의 데이터 뭉치를 찾아서 클래스 추출하기로 하나의 객체로 묶는다
  • 매개변수 객체 만들기객체 통째로 넘기기를 적용해서 매개변수 수를 줄여본다

기본형 집착 Primitive Obsession

몇몇 프로그래머는 자신에게 주어진 문제에 딱 맞는 기초 타입(화폐, 좌표, 구간 등)을 직접 정의하기를 꺼려한다. 그래서 금액을 그냥 숫자형으로 계산하거나, 물리량을 계산할 때도 밀리미터나 인치같은 단위를 무시하는 등의 코드가 많다

  • 기본형으로 표현된 코드가 조건부 동작을 제어하는 타입 코드로 쓰였다면타입 코드를 서브클래스로 바꾸기, 조건부 로직을 다형성으로 바꾸기를 차례로 적용한다

반복되는 switch 문 Repeated Switches

반복문 Loops

과거와 다르게 일급 함수를 지원하는 언어가 많아졌기 때문에 반복문을 파이프라인으로 바꾸기를 적용해서 시대에 걸맞지 않은 반복문을 제거할 수 있게 되었다

성의 없는 요소 Lazy Element

본문 코드를 그대로 사용하는 것과 같은 함수도 있고, 메서드가 하나뿐인 클래스도 있다.
이런 구조는 나중에 본문을 더 채우거나 다른 메서드를 추가할 생각이었으나, 어떠한 사정으로 그러지 못한 결과일 수 있다.

  • 함수 인라인하기클래스 인라인하기로 처리한다
  • 상속을 사용했다면 계층 합치기를 적용한다

추측성 일반화 Speculative Generality

"나중에 필요할거야" 라는 생각으로 작성한 당장은 필요없는 모든 종류의 후킹 포인트와 특이 케이스 처리 로직을 작성해둔 코드를 말한다. 미래를 대비해 작성한 부분을 실제로 사용하게 된다면 다행이지만, 그렇지 않는다면 쓸데없는 낭비일 뿐이다. 당장 치워버리자

  • 하는일이 거의 없는 추상 클래스는 계층 합치기로 제거한다
  • 쓸데 없이 위임하는 코드는 함수 인라인하기클래스 인라인하기로 삭제한다
  • 사용하지 않는 매개변수는 함수 선언 바꾸기로 없앤다

임시 필드 Temporary Field

임시 필드를 갖도록 작성하면 코드를 이해하기 어렵다. 그래서 사용자는 쓰이지 않는 것처럼 보이는 필드가 존재하는 이유를 파악하느라 머리를 싸매게 된다.

  • 클래스 추출하기, 함수 옮기기로 임시 필드들과 관련된 코드들을 추출하고 새 클래스의 몰아넣는다
  • 특이 케이스 추가하기로 필드들이 유효하지 않을 때를 위한 대안 클래스를 만들어서 제거 할 수 있다

메시지 체인 Message Chains

중재자 Middle Man

내부자 거래 Insider Trading

거대한 클래스 Large Class

서로 다른 인터페이스의 대안 클래스들 Alternative Classes with Different Interfaces

데이터 클래스 Data Class

상속 포기 Refused Bequest

주석 Comments

profile
You only get one life. It's actually your duty to live it as fully as possible.

0개의 댓글