Refactoring

리팩터링 2판 - 02. 리팩터링 원칙 키워드 정리

HaningYa 2021. 10. 14. 21:49
728x90

리팩터링 정의

  • 명사: 소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 것
  • 동사: 소프트웨어의 겉보기 동작은 그대로 유지한 채, 여러 가지 리팩터링 기법을 적용해서 소프트웨어를 재구성 하는것.

단순히 코드를 정리하는 작업이 아닌, 특정 리팩토링 방식에 따라 코드를 정리하는 것.
동작을 보존하는 작은 단계들을 거쳐 코드를 수정하고, 순차적으로 연결하여 큰 변화를 만들어 내는 것.

리팩토링 과정은

  • 잘게 나눠진다.
  • 과정 중에 코드는 항상 동작해야 한다.

* 코드베이스를 정리하는건 재구성이라는 포괄적인 용어이고 리팩터링은 재구성 중 특수한 형태
* 리팩토링은 성능 최적화가 아니다. 리팩토링에 따라 성능이 좋아질 수도 나빠질 수도 있다.

리팩토링하다 코드가 깨지는 건 리팩토링이 아니다.
  • Restructuring: 코드베이스를 정리하거나 구조를 바꾸는 모든 작업
  • Refactoring: 모든 restructoring 중에서 도중에 중단되더라도 동작이 유지되는 것.

결국에 리팩토링은 무엇을 하느냐가 아니라 어떻게 하느냐가 중요하다.


두개의 모자

  • 기능 추가의 모자: 기존 코드 건들이지 말고 기능만 추가한다.
  • 리팩터링 모자: 기능추가는 절대 하지말고 코드 재구성만 한다.

예를들어 리팩토링과 기능추가를 동시에 할 경우 PR을 만들었을때 코드가 통으로 빠지고 추가되는 경우를 볼 수 있다.

이 경우에 추가된 코드라인이 리팩토링인지 기능추가인지 구분이 불가능하다.

리팩토링을 통해 코드의 어느 부분을 A파일에서 B파일로 옮기고 기능추가를 했을때
어떤 코드가 추가된 기능관련 부분인지 diff로 파악할 수 없다.

리팩터링하는 이유

  • 소프트웨어 설계가 좋아짐
  • 소프트웨어를 이해하기 쉬워짐
  • 쉽게 버그를 찾을 수 있음
  • 프로그래밍 속도를 높일 수 있음

언제 리팩터링 해야할까

비슷한 일이 세번 반복되면 리팩토링 한다.

  • 준비를 위한 리팩토링: 기능을 쉽게 추가하게 만들기
    코드베이스에 추가되지 직전 현재 코드에서 구조를 개선하면 다른 작업을 하기가 쉬워질 것 같은 부분을 찾는다.
  • 이해를 위한 리팩터링: 코드를 이해하기 쉽게 만들기
    코드의 의도가 더 명확하게 들어나도록 수정
  • 쓰레기 줍기 리팩토링
    비효율적으로 처리하는 코드나 쓸때없이 복잡한 코드를 봤을 때 간단히 수정할 수 있는 건 즉시 고치고, 시간이 좀 걸리는 일은 메모
  • 계획된 리팩터링과 수시로 하는 리팩터링
    리팩터링은 수시로 하는게 좋다. 계획된 리팩토링은 최소로 줄이자
  • 오래 걸리는 리팩토링
    팀 전체가 리팩토링에 매달리는 것 보단 주어진 문제를 몇주에 걸쳐 조금씩 해결해가는 편이 효과적임
    (리팩토링 자체가 코드 동작이 깨지지 않는 범위 내에서 작업)
  • 코드리뷰에 리팩토링 활용하기

*리팩토링하지 말아야 할때
- 굳이 수정할 필요가 없을 때
- 처음부터 새로 작성하는게 쉬울 때

리팩터링 시 고려할 문제

  • 새 기능 개발 속도 저하
  • 코드 소유권
  • 브랜치
  • 테스팅
  • 레거시 코드
  • 데이터베이스

리팩터링, 아키텍처, YANGNI(애그니)

코드를 작성 하기 전 아키텍쳐를 완료해야되는게 기존 관점이였다면 리팩토링 이후에는 수년동안 운영되는 소프트웨어도 아키텍쳐를 변경할 수 있다. 

소프트웨어 요구사항은 항상 변하기 떄문에 사전에 모두 파악하는게 불가능하다.

향후 변경에 유연하게 대처할 수 있는 유연성 매커니즘을 활용한다.

하지만 유연하게 대처하기 위해서 코드를 짜다보면 당장의 요구사항에 비해 코드가 복잡해져 역효과를 낼 수 있다.

리팩터링을 활용하면 변화에 대해 추측하지 않고 현재까지 파악된 요구사항만을 해결하는 소프트웨어를 구축한다.

이런식의 설계 방식을

YAGNI: You aren't going to need it)

이라고 부른다.

아키텍쳐와 설계를 개발 프로세스에 녹이는 방식이다.

처음부터 MVVM, VIPER, Clean Swift 등등 아키텍쳐를 고려하지 않고 MVC 부터 문제가 생기고 문제를 깊이 이해했을 때 처리하는 것을 진화형 아키텍쳐라고 한다.

아키텍쳐에 완전히 소홀해도 된다는게 아닌 어느정도 균형을 잡아야 한다.

리팩터링과 성능

리팩터링은 이해하기 쉬운 코드를 위해 속도가 느려지는 방향일 수 있다.
예시) 맥락을 나누기 위해 하나의 loop를 두개로 나누는 경우

  • 성능이 느려져도 상관 없으니 보기 좋은 코드가 좋다X
  • 하드웨어가 발전해서 그정도 성능 저하는 문제없다X
  • 성능을 튜닝하기 쉬워지기 때문에 오히려 성능 개선시 성능이 좋아진다.

결국에 리팩토링을 통해 코드를 나눈 뒤, 성능 최적화 단계에서
프로파일러를 통해 코드를 분석하여 시간을 잡아먹는 상위 모듈들을 최적화 해주는게 훨씬 낫다.

* 리팩토링이 잘된 코드 = 성능 분석에 유리한 코드

리팩터링과 소프트웨어 개발 프로세스

XP(익스트림 프로그래밍): CI + 자가 테스트 코드 + 리팩토링

TDD(테스트 주도 개발): 자가 테스트 코드 + 리팩토링

CI는 왜 중요? -> 팀으로 리팩토링을 하려면 각자 수행한 리팩터링 결과를 빠르게 공유해야함


리팩토링은 코드베이스를 예쁘게 꾸미거나 클린코드와 같이 바람직한 엔지니어링 습관과 같은 도덕적인 이유로 정당화 되는게 아니다.

오로지 개발 기간을 단축하고, 기능 추가 시간을 줄이고, 버그 수정 시간을 줄이는 경제적인 이유로 하는 것 이다.!

728x90