리팩터링 2판을 회사 팀 내 스터디로써 진행한다. 스터디에선 따로 책 내용을 정리를 하지 않고 주마다 정해진 분량까지 읽고 감상을 나눈다. 여기선 개인적으로 매 분량에 대한 정리와 짧은 감상을 올린다.
03 코드에서 나는 악취
•
악취 → 리팩터링은 언제 시작할 지 시점을 알려줌
•
언제 그만둘지는 더 어려운 문제
아래 하위 챕터에선 악취, 어떤게 리팩터링 해야할 안 좋은 코드인지, 에 집중하여 정리했다.
특히 아직 읽지 않은 리팩터링 기법을 사용한 설명은 배제했다
(아마 이 부분에 “경험”이 중요하다고 한걸 보아 어떤 수정을 할지 알아야 보일거 같기도 하다).
3.1 기이한 이름
•
“이름만 잘 지어도 나중에 문맥을 파악하느라 헤매는 시간을 크게 절약할 수 있다”
◦
잘못 지으면 남이나 나나 개고생시킨다
•
이름이 떠오르지 않는다 → 설계에 문제가 있는 것일 수도
3.2 중복 코드
•
반복을 하나로 모으는 것
3.3 긴 함수
•
짧은 함수로 잘 구성된 코드는 계속하여 위임한다; 간접 호출
•
코드의 위치가 나뉘어 지는 점 → lsp의 선언과 호출(참조)를 넘어다니는 기능을 활용하자
•
함수의 긴 주석
◦
의도(목적): 함수 이름 짓기로 해결; 무엇을 하는 함순지 이름으로 설명할 수 있어야 함
◦
동작(구현): 길면 쪼갤 수 있어야 하고 그 동작을 계속 위임하는 함수들이 많아야 한다(작아질테니)
3.4 긴 매개변수 목록
•
객체나 클래스로 만들어 통째로 넘기는 것을 생각해보자
3.5 전역 데이터
•
가장 지독한 악취
•
변경 시 이력을 추적할 수 있게 함수로 감싸고 호출로 참조한다
◦
그 함수를 모듈이나 클래스에 넣어 접근 범위를 제한한다
3.6 가변 데이터
•
함수형 프로그래밍을 이젠 적절히 섞어 쓸 수 있지 않나
•
(리팩터링 기법이 이름만 보곤 아직 잘 이해가 안감)
3.7 뒤엉킨 변경
•
변경을 할 때(e.g. 기능 추가) 딱 한군데만 수정할 수 없는 상황
•
SRP가 지켜지지 않았을 때, 단일 모듈 여러 이유로 여러 방식으로 변경될 때
◦
SRP: 단일 모듈은 변경의 이유가 오직 하나여야만 한다.
▪
클린 아키텍처 - 단일 모듈은 오직 하나의 액터에 대해서만 책임져야 한다
3.8 산탄총 수술
•
변경을 할 때, 여러 클래스에 자잘한 수정을 많이 할 때 뒤엉킨 변경과 반대
•
변경되는 부분을 한 모듈로 묶자
•
함수, 클래스를 작게 쪼개는 것만큼 필요에 따라 뭉칠줄도 알아야 한다
3.9 기능 편애
•
모듈 바깥, 다른 모듈끼리의 상호작용을 최소화해야 한다
•
다른 모듈과 너무 많이 소통하는 함수는 그쪽 모듈로 보내준다
•
반대되는 디자인 패턴; 전략 패턴, 방문자 패턴
◦
“함께 변경할 대상을 한데 모으는 것”
◦
오버라이드해야 할 동작 코드를 각각 클래스로 격리하여 수정이 쉬워짐(간접 호출은 늘어남)
3.10 데이터 뭉치
•
몰려다니는 데이터를 뭉쳐주자
◦
클래스(객체)로 뭉치기
◦
메서드 시그니처를 매개변수 객체로 뭉치기 또는 통째로 넘기기
•
판별법: 뭉쳐 있는 데이터 중 값 하나를 삭제해서 문제가 된다면
3.11 기본형 집착
•
기본형 대신 객체 쓰기, 특히 문자열에서 “문자열화된 타입”이 문제(e.g. 타임스탬프를 그냥 string으로 쓴다)
3.12 반복되는 switch 문
•
모든 조건문을 없애야 하는 건 아니다(과거엔 의도적으로 그런 의식을 심어줬고, 지금은 의도대로 객체를 통한 다형성이 잘 정착된거 같다)
•
비슷한 패턴이 반복되는 조건문은 문제다
•
중첩 조건문도 비슷하게 문제다
3.13 반복문
•
map filter를 쓰자
3.14 성의 없는 요소
•
메서드나 클래스가 아주 짧은게 지나치게 구조화된 객체(yagni?)
3.15 추측성 일반화
•
당장은 필요 없는 모든 종류의 후킹 포인트와 특이 케이스 처리 로직을 작성한 코드
•
한번도 사용한 적 없는 매개변수가 있을 수도
3.16 임시 필드
•
특정 상황에서만 값이 있는 필드를 위해 나머지 경우 임시 필드를 채운 경우
3.17 메시지 체인
•
함수 체이닝이 너무 길어지는 경우 → 위임으로 가리자
3.18 중개자
•
메서드 절반 이상이 중개(다른 클래스 구현을 위임)라면 → 제거
3.19 내부자 거래
•
(거래)결합도를 낮춰야 한다
◦
그런 코드를 떼어 놓거나
◦
중개자를 만든다
◦
상속 구조에서 그렇다면 상속 구조로(서브/슈퍼클래스 위임) 해결하도록 바꾼다
3.20 거대한 클래스
•
클래스 쪼개기
◦
접두, 접미사가 같은 필드들이 후보이다
•
클래스 안의 자체적인 중복을 줄이기
•
클래스가 사용되는 패턴에 따라 쪼갤 수도 있다
3.21 서로 다른 인터페이스의 대안 클래스들
•
인터페이스(메서드 시그니처)가 같아질 때까지 동작을 클래스(메서드?) 안으로 몰아 넣는다
•
중복되는 부분을 슈퍼클래스로 추출한다
3.22 데이터 클래스
•
의도한게 아닌데 게터/세터만 있는 클래스
•
게터/세터 없이 public 접근하고 있다면 더 문제이다
•
데이터가 불변이라면 예외이다
3.23 상속 포기
•
상속 받아 쓰지 않고 코드를 다시 만들어 쓰고 있다면 구조에 문제가 있는 것
•
(원리주의자?: 부모 클래스는 모두 추상클래스여야 한다)
3.24 주석
•
주석은 향기지만 탈취제처럼 쓰려하면 문제가 된다
•
주석을 남기기 전에 리팩터링을 해보자
느낀점
•
공감이 많이 가는 것
◦
3.1 기이한 이름
▪
이름이 기이한 줄 모르고 진행하다가 나중에 알게 된다
▪
타입, 특히 서버 - 클라이언트처럼 코드 바깥으로 공유하는 것들의 이름을 바꾸기 어렵다 → protobuf 사용해봐야겠다
◦
3.5 전역 데이터: vue의 pinia나 리액트 zustand 같은 전역 state
▪
데이터도 코드도 오염되기 쉽다
▪
불필요하게 메소드를 공유해서 쓰게 된다
•
서로 배타적인 경우
◦
3.18 중개자 3.19 내부자 거래
◦
3.8 산탄총 수술 3.9 기능 편애; 책에서도 콕 집어 그렇다고 말하지만 경험이나 사례에서 떠오르지 않는다
전략 패턴과 방문자 패턴을 살펴보자
◦
산탄총 수술은 대부분의 것, 쪼개고 구조화하는 리팩터링과, 반대처럼 느껴지기도 한다
◦
이런 점이 리팩터링을 덜 원리주의로 빠지게 하는과 동시에 수정하기 좋은 코드의 절대적 지표를 만들기 어렵게 하는 것 같다.
•
주석 활용하기
◦
주석을 남겨서 커밋을 하고 바로 다음 커밋에 다음 리팩터링을 적용하는 식으로 리팩터링 호흡을 짧게 해보았다
▪
마침 HACK 과 TODO가 아~~주 잘보이는 구성으로 코딩 중이다.
gitlab MR은 선언/참조 점프해 다니기 좋은가?
•
브랜치에서 edit하면 모나코 에디터가 뜨는 것 같았다