리팩터링 2판 8ch

이종호·2022년 6월 11일
0

Refactoring

목록 보기
3/4

8장 기능 이동

목차

  1. 함수 옮기기
  2. 팔드 옮기기
  3. 문장을 함수로 옮기기
  4. 문장을 호출한 곳으로 옮기기
  5. 인라인 코드를 함수 호출로 바꾸기
  6. 문장 슬라이드하기
  7. 반복문 쪼개기
  8. 반복문을 파이프라인으로 바뀌
  9. 죽은 코드 제거하기

0. 기능이동

지금까지는 프로그램 요소를 생성 혹은 제거하거나 일므을 변경하는 리팩터링을 다뤘다.
여기에 더해 요소를 다른 컨텍스트*(클래스나 모듈
로 옮기는 일 역시 리팩터링의 중요한 축이 다.
다른 클래스나 모듈로 함수를 옮길ㄷ 때는 함수 옮기기를 사용한다. 필드 역시 필드 옮기기로 옮길 수 있다.

옮기기는 문장단위에서도 이뤄진다. 문장을 함수 안이나 바깥으로 옮길 떄는 문장을 함수로 옮기기나 문장을 호출한 곳으로 옮기기를 사요한다.
같은 함수 안에서 옮길 때는 문자으 슬라이드하기를 사용한다.
때로는 한 덩어리의 문장들이 기존 함수와 같은 일을 할 떄가 있다.
이럴 때는 인라인 코드를 함수 호추로 바꾸기를 적용해 중복을 제거한다.

반복문과 관련하여 자주 사용하는 리팩터링은 두 가지이다.
첫 번재는 각각 반복문이 단 하나의 일만 수행하도록 보장하는 반복문쪼개기고, 두 번째는 반복문을 완전히 없애버리는 반봅문을 파이프라인으로 바꾸기이다.

마지막으로 훌륭한 프로그래머가 즐겨 사용하는 리팩터링인 죽은 코드 제거하기가 있다. 필요없는 무장들을 디지털 화영방사기로 태워버리는 것만큼 짜릿한 일도 없다.

나는 여기서 아이러니함을 느낀다. 훌륭한 프로그래머가 즐기며 사용하는 리팩터링이 죽은 "코드 제거하기"라니, 코드를 그냥 짜는 것이 개발자가 아니라.
코드를 잘 짜는 것이 개발자임을.

1. 함수 옮기기

함수의 컨텍스트에 영향을 주는 요인 3가지
1. 대상함수를 호출하는 함수들
2. 대상함수가 호출해야하는 함수들
3. 대상함수가 사용하는 데이터들

모듈성
CSS..

distance()와 radians()를 totalDistance()안에 그대로 두어 가시성을 줄이는 쪽은 선호하는 이도 있을 것이다.
언어에 따라 이 방식도 고려해봄직하지만, ES2015이후의 js라면멋진 모듈 메커니즘을 이용해 함수 가시성을 제어할 수 있다.
중첩함수를 사용하다보면 숨겨진 데이터끼리 상호의존하기가 우주 쉬우니 중첩함수는 되도록 만들지 말자.

중첩함수는 되도록 사용하지 않는편이 나중에 수정할 때 용이하다
매개변수로 어떤 값들이 들어가야할지 알아야 나중에 옮길 때 알아챌 수 있어서?

2. 필드 옮기기

데이터 구조를 잘 짰다면,
동작 코드는 자연스럽게 단순하고 직관적으로 짜여진다.

데이터 구조를 잘못짜게 된다면,
잘못 선택한 아귀가 맞지 않는 데이터를 다루기 위한 코드로 범벅이되고,
데이터 주조 자체도 그 프로그램이 어떤 일을 하는지 파악하기 어렵게 한다.

=> 데이터 구조를 통해 그 프로그램이 어떤 일을 하는 지 충분히 유추해 낼 수 있다는것. 데이터 구조를 잘 짤 프로그램은.

접합한 데이터 구조를 알아내기 위한 스킬로
경험 + 도메일 주도 개발 설계

데이터 구조를 변경해야 할 냄새가 풍기는 예시
1. 함수에 어떤 레코드를 넘길 때 또 다른 레코드의 필드도 함께 넘기고 있다면 => 데이터뭉치와 비슷

  1. 변경? 한 레코드가 변경하려 할 떄 다른 레코드의 필드까기 변경해야만 한다면,

  2. 구조체가 여러 개에 정의된 똔같은 필드들을 갱신해야 한다면.
    -> 한 번만 갱신해도 되는 다른 위치로 옮기라는 신호

필드를 캡슐화 한다는 뜻은
== 값을 접근하는데 한단계 더 경로를 만든다 double dispatch
getter와 setter를 이용해 데이터를 조회하고 수정한다는 뜻
ex) 굳이

setDiscountRate(aNumber){return this.discountRate = aNumber}

와 같은 메서드를 만들었다.

3. 문장을 함수로 옮기기

4. 문장을 호출한 곳으로 옮기기

5. 인라인 코드를 함수 호출로 바꾸기

뭔말이야?
6.1 함수 추출하기랑 다를게 뭐지?

옮긴이

함수 추출하기와 이럽 리팩터링의 차이는
인라인 코드를 대체할 함수가 이미 존재하느냐의 여부다.

아직 없어 새로 만들어야 한다면 함수 추출하기를 적용하고
이미 존재한다면 인라인 코드를 함수 호출로 바꾸기를 적용하면 된다.

사용중인 프로그래밍 언어의 표준 라이브러리나 플랫폼 이 제공하는 메ㅑ를 잘 파악하고 있을 수록 이번 리팩털잉의 활용빈도가 높아질 것이다.
보통은 직접 짠 코드보다 라이브러리가 제공하는 pi가 더 효율적일 가능성이 크니, 사용중인 언어와 ㅍ플랫폼 버전업될 때 어떤 기능이 새로 생기곡 변경되는지를 평소에 잘 챙겨두면 코드를 개선하는데 많은 도움이 된다. 물론 외부라이브러리에 지나치게 의존하면 설계 유연성이 떨어지니 처한 상황에 맞게 신중히 판단해야한다.

6. 문장 슬라이드 하기

문장 슬라이드를 포기해야할 때
1. 코드 조각에서 참조하는 요소를 선언하는 문장 앞으로는 이동할 수 없다.
2. 코드 조각을 참조하는 요소의 뒤로는 이동할 수 없다.
3. 코드 조각에서 참조하는 요소를 수정하는 문장을 건너뛰어 이동할 수 없다.
4. 코드 조각이 수정하는 요소를 참조하느 요소를 건너뛰어 이동할 수 없다.

저자는 선언 코드를 슬라이드하여 처음 사용하는 곳까지 끌어내리는 일을 자주함

코드 조각을 슬라이드하기로 했다면 다음엔, 그 일이 실제로 가능한지를 점검해야한다.
ex

retriveOrder()// 의 내부를 살펴보지 않아도 부수효과가 없음을 확신? 할 수 있다.

저자는 명령-질의 분리 함수는 모두 부수효과가 없음을 알고 있던것

슬라이드할 코드 조각과 건너뛸 코드 중 어느 한쪽이 다른 쪽에서 참조하는 데이터를 수정한다면 슬라이드를 할 수 없다.
이것이 가장 직관적인 규칙이다.
하지만 완벽한 규칙은 아니다.
ex)

a = a + 10;
a = a + 5;

슬라이드가 안전한지를 판단하려면 관련된 연산이 무엇이고 어떻게 구성되는지를 완벽히 이해해야한다.
상태 갱신에 특히나 신경 써야 하리깨문에

이 부분이 간단하지만, React를 쓰는 개발자에선 굉장히 자주 일어날만한 일인것 같다.
보통 state, redux는 가장 위로, 중간에 useEffect, useRef등등 모아서 써두긴했는데, 보기엔 이쁘지만, 사실 같이 존재하면 안되는 것들이 같이 존재하는 꼴이고
값을 구분하여 컴포넌트로 만들 순 없는지 만들어 놓는게 좋을 것 같다.

8. 반복문 파이프라인으로 바꾸기

js에서 배열 메서드종류를 찾아보면 좋을 것 같다.

// 원본 배열 자체를 변경하는 메소드
copyWithin() //메서드는 배열의 일부를 얕게 복사한 뒤, 동일한 배열의 다른 위치에 덮어쓰고 그 배열을 반환합니다. 이 때, 크기(배열의 길이)를 수정하지 않고 반환합니다.
fill()
splice()

pop() // last out
push() // last in
shift() // first out
unshift() // first in

reverse() // array
sort() // array


// 원본 배열에 변경이 없는 메서드
filter() // array
map() // array
reduce() // ? or array
reduceRight() // ? or array
flat() // array
flatMap() // map() + flat()
slice() // array
concat() // array
join() // string

forEach()

find() // 함수를 만족하는, 값 or undefined
findIndex() // 함수를 만족하는, index or -1
at()// Experimental 음수 인덱스로 배열의 값을 조회할 수 있다. 값
indexOf() // 인덱스
lastIndexOf() // 인덱스

entries()
keys()
values()

every()
some()
includes() // 특정 요소 포함?

toString()
toLocaleString() // todo:...

Array.from()
Array.isArray()
Array.of()

ref MDN

profile
코딩은 해봐야 아는 것

0개의 댓글