리팩터링 (2판) 1장에서는 앞으로 배울 리팩터링 기법을 한 데 모은 예시에 대해 소개한다.
다양한 공연을 외주 받아서 운영하는 극단의 충성도 프로그램이 소개된다. 이 프로그램에서는 연극의 장르와 관객의 규모에 따라 비용을 책정하는 비즈니스 로직이 존재하며, 이를 리팩터링하는 것이 이 장의 핵심 내용이다.
코드의 변화 과정을 훑으면서, 여기서 어떤 기법을 통해 바꾸었는지를 확인해보면 된다. 읽으면서 기억에 남는 부분들을 몇 가지 기록해보고자 한다.
나는 수백 줄 짜리 코드를 수정할 때면 먼저 프로그램의 작동 방식을 더 쉽게 파악할 수있도록 코드를 여러 함수와 프로그램 요소로 재구성한다.프로그램의 구조가 빈약하다면 대체로 구조부터 바로잡은 뒤에 기능을 수정하는 편이 작업하기 훨씬 수월하다.
프로그램이 새로운 기능을 추가하기에 편한 구조가 아니라면, 먼저 기능을 추가하기 쉬운 형태로 리팩터링하고 나서 원하는 기능을 추가한다.
리팩터링의 첫 단계를 항상 똑같다. 리팩터링할 코드 영역을 꼼꼼하게 검사해줄 테스트 코드들부터 마련해야 한다. 리팩터링에서 테스트의 역할은 굉장히 중요하다. 리팩터링 기법들이 버그 발생 여지를 최소화하도록 구성됐다고는 하나 실제 작업은 사람이 수행하기 때문에 언제든 실수할 수 있다.
한 가지를 수정할 때마다 테스트하면, 오류가 생기더라도 변경 폭이 작기 때문에 살펴볼 범위도 좁아서 문제를 찾고 해결하기가 훨씬 쉽다. 이처럼 조금씩 변경하고 매번 테스트하는 것은 리팩터링 절차의 핵심이다. 한 번에 너무 많이 수정하려다 실수를 저지르면 디버깅하기 어려워서 결과적으로 작업 시간이 늘어난다. 조금씩 수정하여 피드백 주기를 짧게 가져가는 습관이 이러한 재앙을 피하는 길이다.
하나의 리팩터링을 문제없이 끝낼 때마다 커밋한다. 그래야 중간에 문제가 생기더라도 이전의 정상 상태로 쉽게 돌아갈 수 있다. 이렇게 자잘한 변경들이 어느 정도 의미 있는 단위로 뭉쳐지면 공유 저장소로 푸시한다.
컴퓨터가 이해하는 코드는 바보도 작성할 수 있다. 사람이 이해하도록 작성하는 프로그래머가 진정한 실력자다.
좋은 코드라면 하는 일이 명확히 드러나야하며, 이때 변수 이름은 커다란 역할을 한다. 그러니 명확성을 높이기 위한 이름 바꾸기에 조금도 망설이지 말기 바란다.
지역 변수를 제거해서 얻는 가장 큰 장점은 추출 작업이 훨씬 쉬워진다는 것이다. 유효범위를 신경 써야 할 대상이 줄어들기 때문이다. 실제로 나는 추출 작업 전에는 거의 항상 지역 변수부터 제거한다.
이름짓기는 중요하면서도 쉽지 않은 작업이다. 긴 함수를 작게 쪼개는 리팩터링은 이름을 잘 지어야만 효과가 있다. 이름이 좋으면 함수 본문을 읽지 않고도 무슨 일을 하는지 알 수 있다. 물론 단번에 좋은 이름을 짓기는 쉽지 않다. 따라서 처음에는 당장 떠오르는 최선의 이름을 사용하다가, 나중에 더 좋은 이름이 떠오를 때 바꾸는 식이 좋다. 흔히 코드를 두 번 이상 읽고 나서야 가장 적합한 이름이 떠오르곤 한다.
반복문이 중복되는 것을 꺼리는 이들이 많지만, 이 정도 중복은 성능에 미치는 영향이 미미할 때가 많다. (중략)
똑똑한 컴파일러들은 최신 캐싱 기법 등으로 무장하고 있어서 우리의 직관을 초월하는 결과를 내어주기 때문이다.
...
하지만 '대체로 그렇다'와 '항상 그렇다'는 엄연히 다르다. 때로는 리팩터링이 성능에 상당한 영향을 주기도 한다. 그런 경우라도 나는 개의치 않고 리팩터링한다. 잘 다듬어진 코드라야 성능 개선 작업도 훨씬 수월하기 때문이다. 리팩터링 과정에서 성능이 크게 떨어졌다면 리팩터링 후 시간을 내어 성능ㅇ을 개선한다.
따라서 리팩터링으로 인한 성능 문제에 대한 내 조언은 '특별한 경우가 아니라면 일단 무시하라'는 것이다.
이렇게 모듈화하면 각 부분이 하는 일과 그 부분들이 맞물려 돌아가는 과정을 파악하기 쉬워진다. 간결함이 지혜의 정수일지 몰라도, 프로그래밍에서만큼은 명료함이 진화할 수 있는 소프트웨어의 정수다. 모듈화한 덕분에 계산 코드를 중복하지 않고도 HTML 버전을 만들 수 있었다.
리팩터링은 대부분 코드가 하는 일을 파악하는 데서 시작한다. 그래서 코드를 읽고, 개선점을 찾고, 리팩터링 작업을 통해 개선점을 코드에 반영하는 식으로 진행한다. 그 결과 코드가 명확해지고 이해하기 더 쉬워진다.
좋은 코드를 가늠하는 확실한 방법은 '얼마나 수정하기 쉬운가'다.
프로그래머 사이에서 어떤 코드가 좋은 코드인지에 대한 의견은 분분하다. (중략)
미적인 관점으로 접근하면 좋고 나쁨이 명확하지 않아서 개인 취향 말고는 어떠한 지침도 세울 수 없게 된다. 하지만 나는 취향을 넘어서는 관점이 분명 존재하며, 코드를 '수정하기 쉬운 정도'야말로 좋은 코드를 가늠하는 확실한 방법이라고 믿는다.
이번 예시를 통해 배울 수 있는 가장 중요한 것은 바로 리팩터링하는 리듬이다.
리팩터리을 효과적으로 하는 핵심은, 단계를 잘게 나눠야 더 빠르게 처리할 수 있고, 코드는 절대 깨지지 않으며, 이러한 작은 단계들이 모여서 상당히 큰 변화를 이룰 수 있다는 사실을 깨닫는 것이다.
아래 이 장의 핵심 내용과는 큰 관련은 없지만, 재밌어서 기록에 남겨두었다. 나의 습관과 비슷한 부분도 더러 있다.
나는 함수의 반환 값에는 항상 result라는 이름을 쓴다. 그러면 그 변수의 역할을 쉽게 알 수 있다.
가변 데이터는 금방 상하기 때문에 나는 데이터를 최대한 불변처럼 취급한다.
'Programming > Refactoring' 카테고리의 다른 글
테스트 구축하기 (0) | 2025.03.20 |
---|---|
코드에서 나는 악취 (1) | 2025.03.13 |
리팩터링 2판 공부를 시작하며 (0) | 2025.02.24 |