리팩터링은?
코드를 깨끗이 만드는 작업.
→ 소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법
→ 함수, 모듈, 소프트웨어 전체적인 설계가 대상
💡목표:
복잡성 감소 → 모든 개발자들이 쉽게 이해할 수 있도록 함
가독성 향상 → 나를 포함한 개발자들이 쉽게 코드를 이해하고 유지보수를 잘 할 수 있음
유지보수성을 개선 → 버그가 생겼을 때 쉽게 다른 사람의 코드를 개선시킬 수 있음
확장성을 높임 → 새 기능을 추가할 때 짧은 시간안에 기능을 추가 가능해짐
⇒ 더 단순하고, 깔끔하고 표현력이 뛰어난 코드, 내부 아키텍처/객체 모델을 만듬
⚠️ 금지:
기능 변경/추가
버그 수정
성능 개선
(라이브러리, 디펜던시)버전 업데이트
리팩터링이 필요한 이유
- 개발 초기 단계부터 완벽한 코드/시스템 설계의 어려움: 클린코드, 클린아키텍처, 좋은 디자인패턴으로 프로젝트를 진행한다고 해도 중간중간 프로그램의 요구사항은 꾸준히 변경됨(기능 추가/변경). 앞으로를 미리 예상에서 설계를 과하게 해도 위험부담이 있을 수 있음(오버 엔지니어링).
- 더럽고 복잡한 코드는 이해하기 어려움
- 이해하기 어려우면 예상하지 못한 에러가 발생하기 쉬움, 대처하기도 어려움.
⇒ 복잡한 코드의 유지보수는 어려움(수정 시간이 오래걸림)
(파란선)내부구조가 잘 짜여진 소프트웨어: 처음엔 좀 느리지만 시간이 갈수록 확장성이 증가
(주황선)저품질의 소프트웨어: 처음엔 빠르지만 갈수록 확장 속도가 느려짐
- 소프트웨어 설계가 좋아짐
→ 모든 코드가 언제나 고유한 일을 수행함을 보장함
→ 이해해야 할 코드의 양이 작고, 실수없이 수정할 수 있음 - 소프트웨어를 이해하기 쉬워짐
→ 코드의 목적이 잘 드러나게, 의도를 더 명확하게 표현
→ 코드가 잘 읽힘, 가독성이 좋아짐 - 버그를 쉽게 찾을 수 있음
→ 코드가 하는 일을 깊이 파악할 수 있음 - 프로그래밍 속도를 높일 수 있음
→ 내부 설계가 잘 된 소프트웨어는 새로운 기능을 추가할 지점을 빠르게 찾음
→ 작은 일부의 코드만 이해하여 빠르게 수정이 가능
→ 디버깅이 쉬움
→ 새로운 기능을 손쉽게 추가 가능
리팩터링 방법
- 테스트 코드 작성: 기존에 동작하고 있는 기능을 그대로 유지할 수 있도록, 유지한다는 것을 보장할 수 있도록 테스트 코드를 작성해야 함. 함수, 특정 기능, UI, 성능, API 스펙 등이 대상.
- 코드의 나쁜 냄새에 따라 리팩터링 기법들을 점진적으로 적용해 나감.
- 이 때 버그 수정, 기능 추가와 같은 작업은 하면 안됨.
프로젝트 단계에 따른 리팩터링📈
1. 프로젝트 시작단계: 기능 구현을 위한 코드를 작성. 좋은 디자인패턴으로 코드를 깔끔하게 작성(하지만 쉽지 않음)
→ 테스트 코드를 작성. 테스트 가능한 코드를 만들기 위해서 리팩터링이 필요할 수도 있음. 새 함수 작성, 의존성 주입 등이 필요해짐.
- 3의 법칙: 비슷한 일을 세번째 하게 되면 리팩터링을 한다
- 코드리뷰를 진행: 코드리뷰를 위해서는 코드를 이해하기 쉽게 만들어야 함 → 좋은 문서화
- 기능 추가: 기능을 쉽게 추가하게 만들기 → 재사용성, 모듈성
2. 프로젝트 유지보수 단계
- 버그 수정: 버그를 검증할 수 있는 테스트 코드. → 코드를 이해하기 쉽게, 변경하기 쉽게 변경 → 리팩터링 → 버그를 쉽게 수정
- 기능추가, 디펜던시 마이그레이션: 기존의 기능들에 대한 테스트 확인 → 코드를 이해하기 쉽게, 변경하기 쉽게 변경 → 리팩터링 → 기능 추가
💡핵심은 어떤 단계든 지금 수정, 추가, 구현하고자 하는 기능을 좀 더 편하게 할 수 있도록 개발자를 위해서 개선해 나가는 것. 코드를 변경하기 전에 테스트코드를 작성함으로써 기존의 기능을 보장할 수 있다는 것. 앱을 일일이 실행하지 않아도 테스트코드를 통해 확인하여 더 간편하게 코드를 개선해 나갈 수 있음.
3. 오래된 프로젝트(레거시): 테스트코드가 하나도 없는 상태🚩
- 버그 수정 및 기능 추가시
- 수정이 필요한 모듈/코드 한정적으로 테스트코드 추가 → 리팩토링 → 코드 수정, 기능 추가.
- 오래된 코드는 스파게티 코드가 되어 테스트코드 작성이 어려울 수 있음. 이럴 때는 수정할 것의 중요도에 따라 우선순위를 정해야 함. 때로는 리팩터링보다 새로운 코드를 작성하는 것이 빠름.
💡‘항상 내가 거쳐간 곳은 깨끗하게 만든다’는 생각으로 코드를 개선
리팩토링의 포인트✨
- 리팩토링은 코드를 깨끗하게 만드는 작업.
- 결과/행동 변화 없이 코드의 구조를 재조정.
- 소프트웨어 기능을 보존하면서 설계, 구조 및 구현을 개선.
- 소프트웨어 기능 보존 확인을 위한 테스트코드 작성.
- ‘무결점 클린코드, 완벽한 설계는 존재하지 않는다’를 인정해야 함
→ 오늘 완벽하다고 생각했던 설계가 시간이 지나고 설계방식에 문제점이 발견될 수도 있음. 요구사항 변경에 따라서 기존 설계가 잘 맞지 않는 경우도 발생.
→ (처음부터 무결성, 클린코드 작성에 각박을 가지기 보다는)상황에 맞게 알맞고 적당한 좋은 디자인패턴으로 코드를 깔끔하게 작성. 기능 구현을 위한 코드를 작성.
→ 테스트코드를 작성
→ 리팩토링
→ 3의 법칙: 비슷한 일을 세번째 하게 되면 리팩토링 한다 - 야그니(You Ain’t Gonna Need It)
- 처음부터 깨끗하게, 변경이 쉽게, 유지보수 용이하게 코드를 작성해가는 것도 중요하지만.
- 지금 당장 필요하지 않은 기능에 집착해서 코드를 지나치게 복잡하게 만들거나, 사용하지 않는 기능을 구현하거나, 지나치게 미래지향적으로 소프트웨어를 설계해 나가서 복잡도를 높이지 않도록 해야 함
→ 오버 엔지니어링을 경계해야 함
(처음부터 지저분하게 작성해도 된다는 의미가 아님)