리펙토링 2판 읽고 요약해보기 (Chapter 3 ~ 4)
‘리펙토링’ 책을 읽고 3장부터 4장까지 요약해보려고 합니다.
코드에서 나는 악취
- 냄새 나면 당장 갈아라
기이한 이름
세계적인 기인이라는 느낌을 풍기고 싶더라도 꾹 참고 코드는 단순하고 명료하게 작성해야 한다.
이름만 보고도 각각 무슨 일을 하고 어떻게 사용해야 하는지 명확히 알 수 있도록
리펙토링
- 함수 선언 바꾸기
- 변수 이름 바꾸기
- 필드 이름 바꾸기
중복 코드
코드가 중복이라면 서로 차이점이 없는지 주의 깊게 살펴봐야 하는 부담 발생
리펙토링
- 함수 추출하기
- 문장 슬라이스하기
- 메소드 올리기
긴 함수
간접 호출의 효과로 코드를 이해하고, 공유하고, 선택하기 쉬워진다는 장점은 함수를 짧게 구성할 때 나오는 것
- 함수를 짧게 만드는 작업의 90%는 함수 추출하기 차지
- 임시 변수를 질의 함수로 바꾸기
- 매개변수 객체 만들기
- 객체 통째로 넘기기
함수를 명령으로 바꾸기도 고려
주석을 참고해서 코드만으로는 목적을 이해하기 어려운 부분을 함수로 빼고 함수 이름은 주석 내용을 토대로 작명
- 조건문, 반복문도 작업 분리
긴 매개변수 목록
- 매개변수 목록이 길어지면 그 자체로 난해
- 매개변수를 질의 함수로 바꾸기
- 객체 통째로 넘기기
- 매개변수 객체 만들기
- 플래그 인수 제거하기
- 클래스로 매개변수 목록을 줄이는 데 효과적인 수단
전역 데이터
겪을 수 있는 가장 지독한 축
전역 데이터는 코드 베이스 어디에서든 건드릴 수 있고 누가 값을 바꿨는지 찾아낼 메커니즘이 없다.
변수 캡슐화
가변 데이터
- 데이터를 변경했더니 예상치 못한 결과나 골치 아픈 버그로 이어지는 경우
- 변수 캡슐화하기
- 변수 쪼개기
문장 슬라이드, 함수 추출로 갱신 코드 분리
세터 제거
- 값을 다른 곳에서 설절할 수 있는 가변 데이터가 풍기는 악취
- 파생 변수를 질의 함수로 바꾸기
- 여러 함수를 클래스로 묶기
- 여러 함수를 변환 함수로 묶기
- 구조체처럼 내부 필드에 데이터를 담는 경우
- 참조를 값으로 변경
뒤엉킨 변경
코드를 고치고 싶은 부분만 고칠 수 없으면 뒤엉킨 변경과 산탄총 수술 중 하나가 풍긴다.
- 뒤엉킨 변경 발생 경우
- 단일 책임 원칙이 잘 지켜지지 않을 때
- 단계 쪼개기
- 함수 옮기기
- 함수 또는 클래스 추출하기
산탄총 수술
뒤엉킨 변경과 비슷하지만 정반대
코드를 변경할 때마다 자잘하게 수정해야 하는 클래스가 많을 때
바꾸는 대상을 함수 옮기기 또는 필드 옮기기로 모두 한 모듈에 묶어두면 좋다.
함수가 많다면 여러 함수를 클래스로 묶기
데이터 구조를 바꾸면 여러 함수를 변환 함수로 묶기
함수 인라인 또는 클래스 인라인도 산탄총 수술에 대처하는 좋은 방법
기능 편애
- 어떤 함수가 자신의 모듈의 함수나 데이터보다 다른 모듈의 함수나 데이터와 상호 작용할 일이 더 많을 때
- 소원대로 근처로 함수 추출해서 옮기기
데이터 뭉치
필드 형태의 데이터 뭉치는 클래스 추출하기로 하나의 객체 묶기
매개변수는 매개변수 객체 만들기 또는 객체 통째로 넘기기
데이터 뭉치인지 확인하는 방법
- 값 하나를 삭제해서 나머지 데이터만으로 의미가 없어지는지 확인
기본형 집착
문자열로만 표현하는 악취
기본형을 객체로 바꾸기
조건부 동작을 제어하는 타입 코드
- 타입 코드를 서브 클래스로 바꾸기
- 조건부 로직을 다형성으로 바꾸기
반복되는 스위치문
1990년대 후반까지 다형성의 가치가 적었지만, 지금은 단순히 스위치문을 썼다고 해서 자동으로 검토되지 않는다.
중복된 스위치문
- 조건을 하나 추가할 때마다 다른 스위치문도 모두 찾아서 함께 변경
반복문
- 반복문을 파이프라인으로 바꾸기
성의없는 요소
- 실질적으로 필요 없어진 프로그램 요소 제거
- 함수 인라인하기
- 클래스 인라인하기
- 계층 합치기
추측성 일반화
- “나중에 필요할 거야” 라는 생각
- 당장 필요없는 모든 처리 로직을 작성해둔 코드에서 풍긴다.
하는 일이 없는 추상 클래스는 계층 합치기
쓸데없이 위임하는 코드는 함수 인라인하기 또는 클래스 인라인하기
본문에서 사용하지 않는 매개변수는 함수 선언 변경
- 테스트 케이스부터 삭제한 뒤에 죽은 코드 제거
임시 필드
덩그러니 떨어진 필드들을 발견하면 클래스 추출하기와 함수 옮기기로 코드 조각을 모은다.
특이 케이스 추가하기로 필드가 유효하지 않을 때 사용할 대안 클래스 작성
메시지 체인
다른 객체를 요청하는 작업이 연쇄적으로 이어지는 코드
위임 숨기기
함수 추출하기 또는 함수 옮기기
중개자
객체의 대표적인 기능인 캡슐화하는 과정에서 위임이 자주 활용되지만, 지나치면 문제
중개자 제거하기로 실제 일하는 객체와 소통
내부자 거래
- 은밀히 데이터를 주고받는 모듈이 있다면
- 함수 옮기기
- 필드 옮기기
- 위임 숨기기
- 부모 클래스를 떠나야 한다면
- 서브클래스를 위임으로 변경 또는 슈퍼클래스를 위임으로 변경
거대한 클래스
하나의 클래스가 너무 많은 일을 하면 필드 수 증가
클래스 추출하기로 필드 일부를 묶는다.
클래스와 상속 관계로 만드려면 슈퍼 클래스 추출하기나 타입 코드를 서브클래스로 바꾸기가 쉽다.
클라이언트들이 거대 클래스를 사용하는지 패턴을 파악하여 단서를 얻을 수 있다.
- 클래스 추출하기
- 슈퍼클래스 추출하기
- 타입 코드를 서브클래스로 바꾸기
서로 다른 인터페이스의 대안 클래스
함수 선언 바꾸기로 클래스 메소드 시그니처를 일치시킨다.
부족하면 함수 옮기기로 인터페이스가 같아질 때까지 클래스로 밀어 넣는다.
데이터 클래스
다른 클래스가 너무 깊게 다룰 경우, 클래스에 퍼블릭 필드가 있다면 레코드 캡슐화하기로 숨기자
바꾸면 안되는 필드는 세터 제거하기로 접근을 원천 봉쇄한다.
다른 클래스에서 데이터 클래스의 게터나 세터를 사용하면 함수 옮기기로 추출
상속 포기
계층 구조를 잘못 설계했으면 같은 계층에 서브 클래스를 만들고 메소드 내리기 또는 필드 내리기
상속 메커니즘에서 벗어나기
- 서브클래스를 위임으로 바꾸기
- 슈퍼클래스를 위임으로 바꾸기
주석
주석을 탈취제처럼 사용
특정 코드 블록이 하는 일에 주석을 남기고 싶다면 함수 추출
이미 추출되어도 설명이 필요하면 함수 선언
선행 조건을 명시하고 싶으면 어서션 추가
주석을 남겨야겠다는 생각이 들면, 가장 먼저 주석이 필요 없는 코드로 리펙토링
테스트 구축하기
- 리펙토링을 잘 하려면 실수를 잡을 견고한 테스트 스위트 뒷받침
자가 테스트 코드의 가치
- 모든 테스트를 완전히 자동화하고 그 결과까지 스스로 검사
- 테스트가 컴파일만큼 쉽다.
- 테스트 스위트는 강력한 버그 검출 도구
- 버그를 찾는 데 걸리는 시간을 대폭 줄인다.
- 테스트를 작성하기 좋은 시점은 프로그래밍을 시작하기 전
- 코딩이 완료되는 시점을 정확하게 판단 가능
- 테스트 주도 개발
- 예시의 테스트 대상 코드
- 생산 계획 검토 애플리케이션
- 첫 번째 테스트
- 실패해야 될 상황에서는 반드시 실패하게 만들자
- 테스트 추가
- 완벽하게 만드느라 테스트를 수행하지 못하느니, 불완전한 테스트라도 작성해 실행하는 게 낫다.
픽스쳐 수정
- 경계 조건 검사
- 문제가 생길 가능성이 있는 경계 조건을 생각해보고 그 부분을 집중적으로 테스트하자.
어차피 모든 버그를 잡아낼 수 없다고 생각하여 테스트를 작성하지 않는다면 대다수의 버그를 잡을 수 있는 기회를 날리는 셈
- 버그 리포트를 받으면 가장 먼저 그 버그를 드러내는 단위 테스트부터 작성하자
다음 포스트에서 챕터 5 내용이 이어집니다.