본문 바로가기
독서에서 한걸음

Refactoring .Chapter 01

by oncerun 2022. 8. 6.
반응형

클린 코드를 읽으면서 리팩터링에 대한 배경지식을 알고 읽으면 더 좋은 시너지를 낼 것 같아 동시에 읽기 시작하였다.

이 책은 리팩터링 원리와 좋은 리팩터링 습관을 설명하며, 언제 어떤 상황에 코드를 분석해서 개선해야 하는지 알려준다.

지식을 얻으러 출발해보자.

 

1장은 리팩터링 예제를 보며 책의 전반적인 내용을 훑어보는 느낌이 강했다. 

 

리팩터링은 겉으로 드러나는 코드의 기능은 바꾸지 않으면서 내부 구조를 개선하는 방식으로 소프트웨어 시스템을 수정하는 과정이다.

 

프로그램이 잘 작동하는 상황에서 그저 코드가 지저분하다는 이유로 불평하는 것은 잘못된 것인가?

잘 돌아가면 되는 것아닌가?

설계가 나쁜 시스템을 수정하기 어려운 이유는 명확하다. 원하는 동작을 수행하도록 하기 위해 수정해야 할 부분을 찾고, 기존 코드와 잘 맞물려 작동하게 할 방법을 강구하기가 어렵다. 설계가 나쁜 시스템이 잘 짜인 테스트 코드가 있을 리 만무하다. 

 

저자는 만약 수백 줄짜리 코드를 수정할 때면 먼저 프로그램의 작동 방식을 더 쉽게 파악할 수 있도록 코드를 여러 함수와 프로그램 요소로 재구성한다고 한다.
즉 기능을 추가하기에 편리한 구조가 아니라면, 먼저 기능을 추가하기 쉬운 구조로 리팩터링 한 후 원하는 기능을 추가한다.

 

저자는 켄트 벡과 그의 팀이 기존에 부서진 프로젝트를 다시 짓는 모습을 보고 해당 책을 써야겠다고 맘먹었다고 한다. 수많은 프로그래머들에게 자문을 구해 정리되어 나온 이 책에는 리팩터링의 단계가 있다고 말한다.

 

그 첫 단계는 리팩터링 할 코드 영역을 꼼꼼하게 검사해줄 테스트 코드들부터 마련해야 한다고 한다. 

우리는 사람이기에 반드시 실수를 한다는 가능성이 존재한다고 생각한다. 이를 최대한 방지하기 위해 우리는 깔끔하고 목적이 있는 테스트 케이스를 작성하여 수정 과정에서 예상치 못한 문제를 방지하려 하기 때문이다.

 

만약 우리가 긴 함수를 리팩터링 해야 한다고 가정하자.

함수의 목적을 알기 위해 우리가 코드를 분석해서 정보를 얻었다면?

코드를 분석해야만 비즈니스 로직을 파악할 수 있다면?

이것은 빨리 리팩터링을 해야 한다는 신호일 수 있다고 말한다. 왜냐하면 그 기억은 금방 휘발되기 때문이다. 

큰 메서드가 SRP 원칙을 지킬 수 있도록 코드 블록의 내용을 함수로 분리하여 좋은 네이밍이 지어 분리하였다. 

변경되지 않는 변수는 매개변수로 넘기고, 결과를 도출하기 위한 지역 변수를 다시 재정의하여 사용했다. 

성공적으로 작은 리팩터링이 끝났다면 리팩터링의 첫 단계로 만든 테스트 코드를 돌려본다. 

 

이처럼 조금씩 변경하고 매번 테스트하는 것은 리팩터링 절차의 핵심이다. 그래서 중간에 실수하더라도 버그를 쉽게 찾을 수 있다.

 

저자는 긴 함수를 잘게 쪼갤 때마다 임시 변수를 질의 함수로 바꾸는 방법을 사용한다고 한다.

꼭 해당 변수를 매개변수로 넘겨야 하는지 고민하는 것이다.

내부적으로 계산할 수 있는지 확인하는 것이다. 이러한 임시 변수들 때문에 로컬 범위에 존재하는 이름이 늘어나서 추출 작업이 복잡해진다고 한다. 

최대한 변수를 없애고 인라인으로 된 변수는 제거한다. 

 

나랑 반대의 스타일을 가지고 있다. 나는 변수에 값을 할당해 표현하는 것이 좀 더 가독성이 좋다고 생각했다. 

물론 그 과정에서 로컬 변수는 증가한다 해도 코드를 읽기 더 쉽다고 생각했기 때문이다. 

 

저자가 질의 함수로 임시 변수를 변경함으로 써 함수의 매개변수가 줄어드는 과정을 보면 왜 변경했는지 한눈에 보인다. 확실하게 유효 범위를 가진 대상이 줄음으로 인해 추출 작업이 상당히 수월해졌다.

 

즉 추출 작업 전에는 지역 변수(추출할 코드 블록에 영향을 미치는 지역 변수)를 제거하는데, 해당 지역 변수 제거로 인해 유효 범위를 신경 써야 할 대상이 줄어들기 때문이다.

 

저자는 리팩터링에서 반복적으로 수행하는 것이 있는데 바로 컴파일- 테스트 - 커밋이다. 커밋 시 하나의 특정 의미가 있을 때만 원격 저장소로 보내고 나머지는 로컬에 커밋한다. 이는 아주 사소한 것의 변경이 끝났을 때도 마찬가지이다.

 

특이하게 반복문 내부에 값이 누적되는 변수도 제거하려고 시도한다. 그러기 위해 반복문을 분리하고, 변수 선언하는 문장을 반복문 앞으로 옮긴다. 왜 그럴까?

우선 반복문을 분리하고 변수 초기화 문장을 한 곳으로 모았기 때문에 이를 함수로 변경하기가 수월해진다. 

 

저자는 변수를 제거하기 위해 반복문을 분리하고, 초기화 문장과 관련 반복문을 논리적인 코드 블록으로 묶고 함수로 추출했다. 이후 해당 변수를 사용하지 않고 인라인 함수로 리팩터링 했다.  이를 반복해 최상위 함수를 매우 작게 줄이는 과정을 보여주는 예시는 직관적으로 매우 단조로워 보인다. 정해진 규칙에 따라 자신의 습관을 녹여내 리팩터링 한다. 

 

이러한 행위를 통해 프로그램의 논리적인 요소를 파악하기 쉽도록 코드의 구조를 보강하였다. 앞에서도 말했지만 기능을 추가하기 위해서 우선적으로 기능을 추가하기 쉽게 골격을 다듬는 일이 선행되어야 하기 때문이다.

이후 그는 기능을 변경하는 리팩터링을 보여준다.

보여주는 예시는 하나의 기능을 변형한 기능을 추가하는 것인데, 이때 저자는 기능을 위한 정보를 초기화하는 구간과 기능을 구현하는 부분 두 단계로 나누고, 그 사이를 중간 구조체를 활용하여 기존 기능에서 확장하는 모습을 보면 기분이 좋아진다.

 

다음으로 엿볼 리팩터링은 조건부 로직을 다형성을 통해 변형하는 것이다. 사실 여기까지 읽으면서 느낀 점은 기능 추가하기 위해 코드의 구조를 쉽게 만드니 기능이 추가되어야 할 때 정확히 어떤 부분을 건드려야 할지 직관적으로 보인다는 점이다.  나는 항상 이 부분에서 시간을 잡아먹었는데, 내가 봤던 코드는 해당 기능을 추가하기 위해 기존 코드를 고치거나 덧 붙여야 하는 지점을 찾는 게 매우 힘들었다. 

 

저자의 예시로 이야기하자면 큰 함수를 작은 함수로 분할하여 모듈화를 진행하고 Main메서드에서 각 단계를 나누어 관리하니 해당 기능을 위해 고쳐하는 부분이 정보를 취합하는 부분에서 다형성을 적용하면 된다는 것을 바로 알았고 기능이 추가됨에 따라 함수가 SRP 원칙을 지키기 위해 별도의 전용 클래스로 분할되어야 함을 알았다.

 

이번 1장의 예시를 통해 리팩터링의 다양한 기법을 보여주었다. 

리팩터링이 무엇인지 보여주기 위해 많은 예시와 설명을 해주었다.  

리팩터링 하는 과정을 보고 상당히 놀랐다 매우 짧은 주기로 단계를 나누고 테스트하는 사실은 나 자신이 초라해 보이기까지 한다. 

 

저자가 말하길 리팩터링은 코드가 하는 일을 파악하는 데서 시작한다. 코드를 읽고, 개선점을 찾고, 리팩퍼링 작업을 통해 개선점을 코드에 반영하는 식으로 돌아간다.  그 결과 코드가 명확해지고 이해하기 더 쉬워진다고 한다.

 

사실 나도 이 의견에 동의하는 것이 좋은 코드는 수정함에 있어서 매우 쉽다고 느껴야 한다고 생각한다. 

 

리팩터링의 핵심에 대해 정리하고 마무리한다.

 

단계를 더 작게 나누고, 이러한 작은 단계들이 모여서 상당히 큰 변화를 이룰 수 있다는 사실을 깨닫는 것이다.

  

 

 

 

반응형

'독서에서 한걸음' 카테고리의 다른 글

Clean Code .Part14 (1)  (0) 2022.08.15
Refactoring .Chapter 02  (0) 2022.08.15
Clean Code .Part13  (0) 2022.08.05
Clean Code .Part12  (1) 2022.08.04
Clean Code .Part11  (0) 2022.08.02

댓글