리팩터링 5가지 핵심 결정 원칙

김영웅·2025년 4월 3일

코드 세분화 vs 코드 통합

코드 세분화

  • 함수 추출하기
    하나의 함수가 여러개의 일을 할 때 분리 해주기

  • 변수 추출하기
    간단한 계산식이어도 이게 다른 일을 할 때 분리해 어떤 계산을 하는건지 표현하기

  • 클래스 추출하기
    하나의 클래스가 여러개의 일을 하지 않게 분리해 관리하기

코드 통합

위와는 또 정반대의 법칙이다;;

  • 함수 인라인하기
    함수로 만들어봤자 사실상 별 작업을 안하면 인라인하기

  • 변수 인라인하기
    굳이 한번만 쓰는 변수는 그냥 인라인 해버리기

  • 클래스 인라인하기
    클래스가 너무 의미없이 나눠져있으면 인라인하기

결정 기준

세분화가 적합한 상황통합이 적합한 상황
코드가 복잡하고 이해하기 어려울 때추상화가 오히려 복잡성을 증가시킬 때
재사용 가능성이 있을 때간단한 로직이 불필요하게 분리되어 있을 때
변경 가능성이 높은 부분사용되는 곳이 한 곳뿐인 단순한 코드
의도와 구현을 분리할 필요가 있을 때함수/변수 이름이 실제 로직에 가치를 더하지 않을 때


결국 리랙터링이란 균형이 중요하다
너무 나눠도 문제고 너무 통합해도 문제다


객체 세분화 vs 객체 통합

객체 세분화

단일책임의 원칙을 지키는 방식인거 같다

  • 매개변수 객체 만들기
    어떤 함수를 호출하는 등의 일에 매개변수가 너무 많아지면 가독성이 떨어지므로 struct 같은걸로 하나로 모아 전달하기

  • 단계 쪼개기
    한개의 함수에서 많은 단계를 거칠 때 단계별로 함수를 쪼갠다

  • 반복문 쪼개기
    반복문에서 여러 작업을 할 때 쪼개기

객체 통합

  • 여러 함수를 클래스로 묶기
    관련된 여러 함수를 묶어서 클래스로 만들어 버리기
    ex) Timer를 각 함수로 관리하지 말고 class로 만들어서 관리해버리기

  • 여러 함수를 변환 함수로 묶기
    여러 함수로 분할되어 있으며 오히려 알아보기 힘드니까 차라리 하나로 묶기
    ex) 쓸데없이 나눠져있는 데미지 계산

결정 기준

세분화가 적합한 상황통합이 적합한 상황
책임이 명확히 분리될 때강한 응집력이 필요할 때
다른 용도로 재사용 가능할 때관련 데이터와 동작이 함께 있는 것이 자연스러울 때
독립적으로 테스트하고 싶을 때공유 상태에 대한 관리가 필요할 때
복잡한 단계를 나누어 명확히 하고 싶을 때여러 작은 함수들이 항상 함께 사용될 때

간접 접근 vs 직접 접근

간접 접근

  • 변수 캡슐화하기
    변수에 직접 값을 대입하게 되면 부가 처리같은 것이 불가능하고 추적이 힘들다
    Setter로 접근하게 만들기

  • 레코드 캡슐화하기
    데이터 접근을 항상 함수로만 가능하게 만들기

  • 컬렉션 캡슐화하기
    Array 같은 컬렉션은 직접 접근이 가능하면 여러 다른 일들이 가능해져 위험하다.
    필요한 기능만 함수로 노출하기
    ex) Inventory컬렉션에 직접 접근하게 만드는게 아닌 AddItem() 을 추가하기

직접 접근

  • 중개자 제거하기
    함수를 계속 타면서 함수를 호출하면 복잡하고 알아보기 어려울 수 있다. (World->GameState->PlayerState->PlayerController 처럼)
    이런걸 함수로 줄여 중간에 타게되는 중개자를 제거해 보기 편하게 만드는거다

  • 위임 숨기기
    객체 내부 구조가 전부 보이는걸 함수로 감춰 간단하게 만들기
    ex) player.contactInfo.Address.zipCode; 이걸 player.GetZipCode(); 로 끝낼 수 있게 정리하기

결정 기준

간접 접근이 적합한 상황직접 접근이 적합한 상황
데이터 검증이나 부가 처리가 필요할 때과도한 래퍼가 복잡성만 증가시킬 때
변경 추적이 필요할 때성능이 중요한 핫스팟일 때
향후 구현 변경 가능성이 있을 때단순한 데이터 구조에서
중복된 접근 로직이 여러 곳에 있을 때위임 체인이 너무 길어질 때


데이터를 보호해야 되냐 아니냐로 판단하는게 좋다고 함


조건문 vs 다형성

조건문

  • 조건문 분해하기
    조건문의 조건이 여러개 있어 뭐하는건지 모르겠을 때 그냥 함수로 분리해서 한눈에 이해하기 쉽게 만들기

  • 조건식 통합하기
    어차피 같은 행동을 하는 조건문이라면 조건식을 통합해 보기 쉽게 만들기

다형성

  • 조건부 로직을 다형성으로 바꾸기
    새로운 뭔가 추가됬을 때 계속 수정해줘야 된다면 다형성으로 만들어 중복을 줄이고 명확하게 만들기

  • 특이 케이스 추가하기
    null 체크 등을 할 떄 if문으로 구별하는데
    (예를들어 player가 null이라면 "Guest"를 띄어주기)
    아싸리 해당 케이스의 class를 추가해 나올 결과를 설정해두기
    (nullplayer 같은걸 만들고 GetName을 "Guest"로 반환해두는 방식으로)

결정 기준

조건문이 적합한 상황다형성이 적합한 상황
단순한 분기 로직일 때타입별 동작 차이가 뚜렷할 때
일회성이거나 지역적인 결정일 때타입 추가가 자주 발생할 때
성능이 매우 중요한 곳일 때타입별 코드가 반복적으로 나타날 때
타입 배열이 고정적일 때동작이 확장될 가능성이 높을 때

상속 vs 위임

상속

  • 메서드 올리기
    중복된 함수는 부모로 올리기

  • 필드 올리기
    중복되는 변수는 부모로 올리기

  • 슈퍼클래스 추출하기
    같은 일을 하는 클래스 같으면 부모로 따서 그걸 상속받게 만들기

위임

  • 서브클래스를 위임으로 바꾸기
    소리, AI 등 같은 것을 재사용할만한 것들이 있을 때 전략 패턴같이 공통되는 것들을 분리해 그곳에서 관리하게 만들기

  • 슈퍼클래스를 위임으로 바꾸기
    Component마냥 상속만 쓰지 말고 가지고 잇는 객체 등으로 만들어 거기서 실행하는 식으로 분리하기

결정 기준

상속이 적합한 상황위임이 적합한 상황
명확한 "is-a" 관계가 있을 때"has-a" 관계나 행동 공유일 때
공통 기능이 많고 타입 계층이 필요할 때런타임에 동작을 변경해야 할 때
다형성을 활용한 확장이 자연스러울 때다중 상속과 같은 효과가 필요할 때
코드 재사용이 수직적일 때기존 클래스 변경 없이 기능 확장이 필요할 때
profile
게임 프로그래머

0개의 댓글