///
Search
Duplicate
📕

[요약] 레거시 코드 활용 전략

중요한 챕터만 요약

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.

마무리