중요한 챕터만 요약
I. 코드 변경의 메커니즘
Chapter 1. 소프트웨어의 변경
1.
기존의 동작을 그대로 유지한다는 것은 단순히 코드를 그대로 두는 것 이상의 의미를 가진다.
2.
안전한 변경을 수행하기 위해서는 영향이 미치는 범위를 정확히 이해하는 것이 중요하다.
3.
다음 세 가지 질문을 할 수 있는가?
a.
어떤 변경을 해야 하는가?
b.
변경이 정확하게 이뤄졌는지 어떻게 확인할 수 있는가?
c.
무언가를 손상시키지 않았는지 어떻게 확인할 수 있는가?
Chapter 2. 피드백의 활용
•
레거시 코드의 딜레마
◦
코드를 변경하려면 테스트 코드를 배치해야 한다.
◦
그런데 테스트 코드를 배치하려면 코드 변경이 필요할 때가 많다.
•
의존관계는 개발에서 가장 중요한 문제 중 하나이다.
◦
의존 관계를 제거하는 작업 자체가 코드를 변경하기 쉽도록 만드는 작업이다.
•
변경하는 순서
1.
변경 지점을 식별한다.
2.
테스트 코드 작성할 위치를 찾는다.
3.
의존 관계를 제거한다.
4.
테스트 코드를 작성한다.
5.
리팩토링을 수행한다.
생각 정리
•
대부분의 경우 테스트 코드가 작성되어있지 않은 프로젝트에서 테스트 코드 작성을 시작하기 마련이다.
•
처음 시작하는 프로젝트는 너무나도 행운이다.
•
우선 테스트에 용이한 설계를 확보하고 테스트를 먼저 작성하는 테스트 주도 개발을 하는 것이 중요하다.
Chapter 3. 감지와 분리
•
제거 이유에는 2가지가 있다.
1.
감지: 코드 내에서 계산된 값에 접근할 수 없을 때, 이를 감지하기 위해 의존 관계를 제거한다.
2.
분리: 코드를 테스트에 넣어서 실행할 수 없을 때, 코드를 분리하기 위해 의존 관계를 제거한다.
Chapter 4. 봉합 모델
•
봉합
◦
봉합 지점이란 코드를 직접 편집하지 않고도 프로그램의 동작을 변경할 수 있는 위치를 말한다.
◦
쉽게 말해, 의존성을 주입받아 실행하는 부분을 말한다.
▪
그리고 의존성을 받는 부분, 함수나 메서드의 인자로 인터페이스를 받는 부분을 활성화 지점이라고 한다.
▪
실제 구현을 내부에서 호출하는게 아니라, 인터페이스를 받도록 하고 외부에서 구현을 받는다.
•
전처리기 봉합
◦
바벨과 같은 컴파일러에게 지시하여 런타임의 의존성을 교체하는 것
◦
jsdom, happy-dom
•
링크 봉합
◦
테스트 환경과 제품 환경 간에 차이가 있도록 구성한다.
◦
이 지점은 소스 코드의 외부에 위치하게 된다. 빌드 스크립트나 배치 스크립트에 존재하기도 한다.
•
객체 봉합
◦
의존성 주입
•
링크 봉합과 전치리기 봉합은 객체 봉합이 불가능할 경우에만 사용한다.
Chapter 5. 도구
(skipped)
II. 소프트웨어 변경
Chapter 6-10, 고칠 것은 많고 시간은 없고/코드 하나를 바꾸는데 왜이리 오래 걸리지?/어떻게 기능을 추가할까?/뚝딱 테스트에 클래스 제대로 넣기/테스트에서 이 메소드를 실행할 수 없다
•
코드가 좋은지 나쁜지 여부는 한 개의 책임과 관련된 코드가 얼마나 커지는지, 그리고 나머지 코드와 얼마나 얽혀 있는가에 따라 결정된다.
•
이름을 바꾸면 코드를 바라보는 관점이 달라진다.
◦
이름에 얽매여 리팩토링에 한계를 갖지 말자.
•
private 메소드를 테스트해야 한다면 그 메소드를 public으로 만들어야 한다.
◦
이 때, public으로 만드는 것이 꺼려진다면,
▪
꺼려지는 이유 1. 단순 유틸리티임.
▪
꺼려지는 이유 2. 이것이 노출되면 클래스의 다른 메소드의 결과값에 영향을 미칠 수 있다. -> 사이드 이펙트를 내포하고 있다.
◦
이는 곧 모듈이 너무 많은 책임을 갖고 있음을 의미한다.
◦
이 때는 모듈을 수정해야 한다.
▪
꺼려지는 이유 2번째는 매우 심각한 이유이며 이 경우 새로운 모듈로 이동시켜야 한다.
•
당장 분리할 수 없다면? (클래스 기준 기법)
◦
protected 라는 접근 제어자가 이래서 있는 것.
◦
private -> protected
◦
상속받는 클래스를 만든다.
◦
캡슐화를 위반하긴 하지만 테스트가 가능하다.
◦
명령과 쿼리의 분리
▪
명령은 객체의 상태를 변경할 수 있지만 값은 반환하지 않으며
▪
쿼리는 값을 반환하지만 객체를 변경하지 않는다.
Chapter 11. 코드를 변경해야 한다. 어느 메소드를 테스트해야 할까?
•
캡슐화는 그 자체가 목적이 아니다. 코드에 대한 이해를 돕기 위한 도구일 뿐이다.
•
캡슐화는 우리가 코드에 대해 추론하는 것을 도와준다.
•
캡슐화가 잘 되었다면 변경에 따른 영향을 추론할 때 적은 수의 경로만 따라가면 된다.
Chapter 12. 클래스 의존 관계, 반드시 없애야 할까?
•
상위 수준에서의 테스트는 리팩토링 시 유용하다.
•
세부 수준에서의 테스트 보다 상위 수준의 테스트를 선호한다.
•
상위 수준 테스트는 단위 테스트를 작성하기 위한 첫 단계로 간주하자.
•
교차지점
◦
특정 변경에 의햔 영향을 감지할 수 있는 소스 코드 내 위치
◦
대부분의 경우, 변경 작업을 위한 가장 좋은 교차 지점은 변경 대상 클래스의 public 메소드 중 하나.
•
조임지점
◦
모든 영향을 검출할 수 있는 지점
•
직접(directly) 의존하고 있지 않는 경우를 발견했을 때
◦
실제로는 숨어있는 것이 아니지만 정보를 숨기고 있는 것이기 때문에 캡슐화의 경계가 존재한다고 볼 수 있다.
◦
의존 관계를 통해 이를 확인할 수도 있으며
◦
네이밍을 잘했다면 이름에서도 캡슐화의 경계가 드러나기도 한다. (힌트가 될 수 있다.)
▪
네이밍은 의존 관계를 잘 드러낼 수 있어야 한다.
생각
•
리팩토링에 임하는 자세
◦
장기적으로는 낙관적이며(우린 해낼 수 있다는 자신감) 단기적으로는 보수적으로(이 변경은 어려우니 테스트부터 차근차근) 접근한다.
•
하나를 더 만들어서 이를 참조하게 끔 하여 의존 관계를 제거한다. (한꺼번에 다 바꾸지 말고)
•
컴포넌트에서 hook을 두 가지로 나눌 수 있겠다.
◦
쿼리: 리소스에 접근하는 것 const { data, status } = useResource
◦
리소스에 접근하면서 변경도 하는 것: [resource, commands] = useResource
•
양방향에서 접근하기
◦
안에서 밖으로
◦
밖에서 안으로
Chapter 13. 변경해야 하는데, 어떤 테스트를 작성해야 할지 모르겠다.
•
레거시 시스템에선 '어떻게 동작해야 하는지'보다 '실제로 어떻게 동작하고 있는지'가 중요.
•
변경 작업을 명확히 하기 위한 테스트 코드를 정확한 위치에 작성하는 것을 목표로
•
문서화 테스트
◦
기존 동작 유지에 필요한 테스트
◦
시스템의 현재 동작을 그대로 문서화 한다.
◦
즉, 코드의 실제 동작을 기록한다.
◦
그 동작이 버그일지라도.
◦
단계별 접근
1.
코드의 동작에 호기심을 갖는다.
2.
코드의 동작을 완전히 이해할 때까지 작성한다.
3.
변경으로 인해 문제점을 발견할 수 있는지 조사해본다.
4.
전부 감지할 수 있다는 확신이 들 때까지 테스트 코드를 추가한다.
•
테스트 코드를 의사소통 수단으로서 사용할 수 있도록 한다.
Note
•
문서화 테스트로 문서화 하기
◦
Documentation using documentation testing
◦
유스케이스가 떠오른다.
Chapter 14-17. 나를 미치게 하는 라이브러리 의존 관계/내 애플리케이션엔 API호출이 너무 많다/변경이 가능할 만큼 코드를 이해하지 못하는 경우/내 애플리케이션은 뼈대가 약하다
•
스크래치 리팩토링
◦
브랜치를 새로 체크아웃하고 메소드 추출이든 변수 이동이든 자유롭게 리팩토링 후 변경 사항을 그냥 버린다.
◦
이리 저리 리팩토링을 30분 정도 하면서 코드에 대해 높은 수준으로 이해하게 되었다.
Chapter 18-20 테스트 코드가 방해를 한다/내 프로젝트는 객체지향이 아니다. 어떻게 안전하게 변경할 수 있을까?/이 클래스는 너무 비대해서 더 이상 확장하고 싶지 않다
•
너무 많은 것을 캡슐화하게 되면 그 안의 내용물은 썩거나 고이게 된다.
•
변경의 영향을 쉽게 감지할 수 없게 된다.
•
책임
◦
목적이 무엇인가
◦
메소드 그룹화를 해본다.
▪
이 메소드는 클래스를 위해 무슨 일을 할까?
▪
이 함수, 이 상태는 컴포넌트를 위해 무슨 일을 할까?
◦
변수와 함수를 엮어본다.
▪
덩어리화 해본다.
◦
문과 능력 발휘: 한 문장으로 표현이 가능한가
생각
•
잘못된 테스트 코드 제거하기도 시급.
•
잘못됐다라는 것은 올바르지 않은데 올바르다고 하는 것
•
여러 가지 mocking으로 인해 변경으로 인한 문제를 감지할 수 없는 것
•
객체가 한 가지 역할을 하도록 분리하는 것은 매우 중요하다.
◦
재사용 여부와는 관계없이
•
하나의 책임만 갖도록 한다는 것은 책임이 두 개 이상일 때 비로소 이해할 수 있다.
Chapter 21-24. 괴물 메소드를 변경해야 하는데 테스트 코드를 작성하지 못하겠다./기존 동작을 건드리지 않았음을 어떻게 확인할 수 있을까/어찌해야 할지 모르겠다 나아질 것 같지 않아
•
불릿 메소드: 처리 시퀀스 발견: 조건과 동작을 함께 분리
•
혼잡 메소드(분기 개많음): 뼈대 메소드 기법: 조건과 동작을 따로 분리
Chapter 25. 의존 관계 제거 기법
•
인터페이스에는 세부 구현이 아니라 책임을 전달하도록 한다.
•
적절한 위치에 테스트 루틴을 가질 수 있을 정도로 의존 관계를 제거하는 것
•
확신을 주는 방향으로 변경해야 한다.
•
초기엔 서명을 유지하면서 리팩토링을 하자. (점진적 개선)
End.