이 장에서 다룰 내용
•
리팩터링에 익숙해지기
•
큰 변화를 위해 점진적으로 리팩터링하기
•
코드를 더 빠르게 변경하기 위해 테스트 사용하기
•
종속성 주입하기
1. 우리는 왜 리팩터링을 하는가?
•
리팩터링으로 얻을 수 있는 것은 다음과 같다.
◦
반복을 줄이고 코드 재사용을 증가시킨다
▪
다른 구성 요소에서 재사용할 수 있는 클래스를 공통 위치로 이동시켜 다른 구성 요소에서도 사용할 수 있도록 한다.
▪
마찬가지로 코드에서 메서드를 추출하여 이것을 재사용할 수 있다.
◦
여러분의 정신 모델과 코드를 더 가깝게 한다
▪
이름이 중요하다. 어떤 이름은 쉽게 이해되지 않을 수도 있다. 객체 이름을 바꾸는 것은 리팩터링 과정의 일부이며, 여러분의 정신 모델과 더 잘 맞고 더 나은 설계를 달성하는 데 도움이 될 수 있다.
◦
코드를 더 이해하기 쉽고 유지관리하기 쉽도록 만든다
▪
긴 함수를 더 작고 유지관리하기 쉬운 함수로 분할하여 코드의 복잡성을 줄일 수 있다.
▪
마찬가지로 복잡한 데이터 타입을 더 작은 부분으로 그룹화한다면 모델을 더 쉽게 이해할 수 있다.
◦
특정 클래스에 버그가 발생하지 않도록 한다
▪
클래스를 구조체로 변경하는 것과 같은 특정 리팩터링 작업은 2장에서 다룬 것처럼 널과 관련된 버그를 방지할 수 있다.
▪
마찬가지로 프로젝트에서 널이 가능한 nullable 참조를 활성화하고, 데이터 타입을 널이 불가능한 참조로 변경하면 기본적으로 연산을 리팩터링하는 버그를 방지할 수 있다.
◦
중요한 아키텍처 변화를 준비할 수 있다
▪
변화를 위한 코드를 미리 준비한다면 코드가 크게 변경되더라도 더 빨리 일을 실행할 수 있다.
▪
다음 절에서 이러한 문제가 어떻게 발생할 수 있는지를 알아볼 것이다.
◦
코드의 경직된 부분을 없앨 수 있다
▪
종속성 주입을 통해 종속성을 제거하고 느슨하게 결합된 설계를 얻을 수 있다.
•
대부분의 리팩토링은 어떠한 지침도 필요없으나 코드 베이스에서 중요한 아키텍처를 변경해야하는 경우, 몇 가지 조언을 따르면 좋다.
2. 아키텍처 변경
•
한 번에 큰 아키텍처를 변경하는 것은 좋은 생각이 아닌데, 큰 변화는 수많은 버그와 통합적인 문제를 발생시키기 때문이다.
◦
여기서 통합 문제란 대규모 변경 작업이 수행되는 동안, 다른 작업자들과 병렬로 작업을 수행하지 못하는 것을 의미한다.
•
이러한 이유로 리팩터링은 점진적으로 수행하는 것이 좋다.
1. 구성 요소를 식별하라
•
대규모 리팩터링을 하는 가장 좋은 방법은 코드를 의미론적으로 다른 구성 요소로 나누는 것이다.
2. 작업량과 위험도를 측정하라
•
효율적인 리팩터링을 위해서는 작업량과 리스크를 평가하고 우선순위를 지정하는 것이 중요하다.
•
이를 위해 목표를 명확히 설정하고 프레임워크의 작동 방식을 이해하는 것이 필요하다.
•
작업 중 일부는 예상과 다를 수 있지만, 목표는 가능한 한 오랜 시간 동안 기존 기능을 유지하면서 필요한 작업을 단계적으로 진행하는 것이다.
3. 평판
•
리팩터링을 동료를 방해하지 않고 효과적으로 수행하려면 점진적이고 체계적인 접근이 중요하다.
•
이는 대규모 시스템에서 중요한 부분을 교체하면서도 기존 시스템이 계속 정상적으로 작동하도록 하는 과정과 유사하다
4. 더 쉽게 리팩터링되도록 리팩터링하라
•
대부분의 경우, 구체적인 종속성 대신 합성을 이용해 의존성을 약화시킬 수 있다.
•
의존성을 약화시키는 방향으로 리팩터링하라.
5. 마지막 코스
•
어떤 시점이 되면 다른 개발자와의 충돌 위험을 감수하고, 그 코드를 새로운 코드 베이스로 전송해야 한다는 것을 의미한다.
◦
저자는 이것을 마지막 코스라고 부른다.
•
마지막 단계에서는 모든 코드와 자산을 새 프로젝트로 전송한 다음, 모든 것이 잘 돌아가도록 만들어야 한다.
3. 신뢰할 만한 리팩터링
•
신뢰할 수 있는 리팩터링의 비결은 테스트이다.
•
코드의 테스트 범위가 양호하다면 코드를 훨씬 자유롭게 변경할 수 있다.
•
테스트가 없는 경우, 추가하는 프로세스를 도입하여 리팩터링을 진행하면 좋다.
4. 리팩터링을 하지 않는 경우
•
리팩터링의 좋은 점은 코드를 개선할 방법을 생각하게 한다는 것이다.
•
리팩터링의 단점은 어느 순간에, 그것이 Emacs처럼 수단이 아닌 목적이 될 수도 있다는 것이다.
◦
Emacs는 텍스트 편집기, 개발 환경, 웹 브라우저, 운영 체제, 그리고 포스트 아포칼립스 롤플레잉 게임이다.
•
이 거리에서 일할 때는 충분히 좋은 코드와 가치에 대한 이해를 기본으로 길러야 한다.
•
충분히 좋은 코드에 대한 기준은 다음과 같다.
◦
리팩터링하는 유일한 이유가 “이것이 더 우아한가”라면 이것은 커다란 위험 신호다.
▪
우아하다는 것은 주관적일 뿐만 아니라 모호하고 의미가 없기 때문이다.
▪
다음과 같이 확실한 이점이 담긴 리팩터링의 이유를 생각해 내도록 노력하라.
•
“리팩터링은 구성 요소를 사용할 때마다 작성해야 하는 상용 코드의 양을 줄임으로써 구성 요소를 사용하기 쉽게 만든다”
•
“리팩터링을 통해 새로운 라이브러리로 이동할 것이다”
•
“구성 요소 X에 대한 의존성을 없앨 수 있다”
◦
대상의 구성 요소가 최소한의 구성 요소 집합에 의존하는가?
▪
이는 나중에 쉽게 이동하거나 리팩터링할 수 있다는 것을 의미한다.
▪
책의 리팩터링 예제는 코드의 경직된 부분을 식별하는 데 도움이 되지 않을 수 있다. 그렇다면 좀 더 확실한 개선 방안이 떠오를 때까지 미루는 것이 좋다.
◦
테스트 범위가 아직 부족한가?
▪
특히 구성 요소에 너무 많은 종속성이 있는 경우, 이는 리팩터링을 피해야 하는 즉각적인 위험 신호이다.
▪
구성 요소에 대한 테스트가 부족하다는 것은 자신이 하고 있는 일을 모른다는 것을 의미하므로 리팩터링을 멈춰야 한다.
◦
공통적인 의존 관계인가?
▪
즉, 상당히 좋은 테스트 적용 범위와 정당성이 있더라도 팀원의 작업 흐름을 방해해 팀의 작업 환경에 영향을 미칠 수 있다.
▪
이러한 비용을 보상하기에 여러분이 추구하는 이득이 충분하지 않다면 리팩터링을 뒤로 미루는 것을 고려해야 한다.
5. 요약
•
표면에 드러난 것보다 더 많은 장점이 있으므로 리팩터링을 받아들여라.
•
점진적으로 대규모 아키텍처를 변경할 수 있다.
•
대규모 리팩터링 작업에서 발생할 수 있는 잠재적인 문제를 줄이기 위해 테스트를 사용하라.
•
비용뿐만 아니라 위험도 추정하라.
•
대규모 아키텍처를 변경할 때는 점진적인 작업을 위해 항상 마음 속에 혹은 어딘가 적힌 로드맵을 갖고 있어야 한다.
•
리팩터링할 때 밀접하게 연결된 종속성과 같은 장애물을 제거하기 위해 종속성 주입을 사용하라. 동일한 기술로 코드의 경직도를 줄이라.
•
득보다 실이 더 클 때는 리팩터링하지 않거나 뒤로 미루는 것을 고려하라.