: 모듈간 통신이나 함수간 호출에서 연결부 역할을 하는 것이 API이다. 인터페이스가 복잡할 때 이 장의 리팩터링을 적용하면 전반적인 API가 이해하기 쉬워진다.
1. 질의 함수와 변경 함수 분리하기
: 질의(값 반환)하는 부분과 상태를 변경하는 부분을 분리한다.
- side effect 없이 값 반환만 해주는 함수를 추구할수록 언제 호출해도 문제가 발생하지 않기 때문에 개발자가 신경써야하는 부분이 줄어든다.
- 명령-질의 분리 원칙: 질의 함수는 Side effect가 없어야 한다. 즉, 질의 함수와 변경 함수는 분리되어야 한다.
2. 함수 매개변수화하기
: 함수 로직이 같고 리터럴만 다르다면, 그 다른 값을 매개변수로 받아 공통된 함수 하나로 처리한다.
- 리팩터링 전과 후를 비교했을 때, 무엇이 더 이해하기에 명확한 코드인가를 기준으로 판단해야 할 것 같다.
- 만약 매개변수로 넘기는 값에 따라 로직이 달라진다면, 그 매개변수를 알고 있다가 로직에 적용하며 코드를 이해해야한다.
3. 플래그 인수 제거하기
: 플래그 인수로 로직이 제어가 되는 구조라면 해당 함수를 어떻게 호출해야하는지 알기 어렵고, 전해지는 리터럴이 무슨 의미인지 명확하게 전달하기 어렵다.
- 플래그 인수가 둘 이상이라면 모든 조합의 함수를 만들기보다 플래그 인수를 써야할 수도 있다. 그런데, 이런 경우 함수의 역할이 너무 크지 않은지 고민을 해봐야한다.
4. 객체 통째로 넘기기
: 레코드의 값을 여러개 넘길바에 레코드 자체를 넘긴다.
- 장점: 함수가 필요로하는 데이터가 다양해져도 API는 바뀔 필요 없고, 매개변수가 짧아져서 함수가 이해하기 쉬워진다.
- 별도의 모듈이라 해당 레코드에 의존하지 않도록 해야한다면 그냥 데이터들을 전달해준다.
- 데이터 더미들을 전달해주는 공통 부분이 많다면, 데이터들을 하나의 객체로 만들어주고, 그 데이터들을 다루는 로직을 객체의 로직으로 바꾼다.
5. 매개변수를 질의 함수로 바꾸기
: 호출자가 값을 결정해 매개변수로 전달하는 대신 피호출자가 값을 결정하도록 하는 리팩터링
- 참조 투명성: 같은 값을 넣으면 항상 같은 결과를 반환한다. 함수 내부의 특정 표현식을 그 표현식의 결과로 치환해도 프로그램의 동작에는 영향이 없다. 이게 가능하려면 해당 함수 외부의 영향을 전혀 받지 않아야한다.
순수함수: 함수 f(x)가 모든 x에 대해 참조에 투명하면 함수 f는 순수함수이다.
6. 질의 함수를 매개변수로 바꾸기
: 값을 결정하는 책임을 호출자가 갖고 피호출자에게 전달하도록 하는 리팩터링
- (전역 변수) 만약 함수가 참조 투명성을 보장하지 못하거나 (의존 관계) 제거하기를 원하는 원소를 참조하는 경우, 호출자가 값을 결정하는 책임을 가지도록 한다.
- 이 리팩터링을 수행하면, 보통 해당 함수는 전보다 다루기 어려워지지만, 참조 투명하도록 메서드를 개선할 수 있다는 장점이 있다. -> 테스트도 용이해진다.
매개변수 vs 질의 함수
: “결합도를 풀어내되 매개변수를 복잡하게 하기 vs 수많은 결합을 유지하기’’ 에서 적절한 균형을 찾아야 하는 문제
7. 세터 제거하기
: 세터를 없애, 인스턴스 생성 시점 외에는 필드가 변경될 가능성을 아예 제거한다.
- 필요한 경우: 너무 세터를 남발하는 경우, 생성자를 활용하지 않고 생성 후에 세터들을 호출해 객체를 완성하는 경우
8. 생성자를 팩터리 함수로 바꾸기
- 장점: 적절한 이름을 가질 수 있다. 서브 클래스를 반환할 수 있다. 꼭 생성자를 호출하지 않고 그냥 인스턴스를 반환할 수도 있다.
9. 함수를 명령으로 바꾸기
: 복잡한 함수를 위한 객체를 만들고, 그 객체의 메서드를 수행하도록 한다. 필드를 이용하고 메서드를 잘게 나누어 복잡한 로직을 이해하기 쉽게 만들 수 있다.
- 하나만의 메서드를 갖는 이 객체를 전달하고, 반환한다는 측면에서 일급함수의 특징을 어느정도 얻을 수도 있다.
10. 명령을 함수로 바꾸기
: 명령(객체)로 바꾼 함수는 분명 복잡도가 줄어든다는 장점이 있지만, 로직이 비교적 간단한 편이라면 굳이 함수를 객체로 만드는 것 자체가 오버엔지니어링일 수 있다. 이 때는 명령을 함수로 바꿔준다.
11. 수정된 값 반환하기
: 값을 새롭게 갱신하는 함수인 경우, 여러 곳에서 사용될 수 있는 값을 바꾸려 하지 말고, 수정된 값을 반환하도록 한다. 이렇게 하면, 해당 함수를 호출하는 호출부에서는 값이 새롭게 갱신될 것임을 개발자가 인지할 수 있다.
- 단 한번 갱신이 필요할만한 값들에 이 리팩터링이 유용하게 사용된다.
12. 오류 코드를 예외로 바꾸기
: 에러 코드를 일일이 코드로 검사해 처리하기보다는 에러 대신 예외를 throw해, 적절한 핸들러가 처리할때까지 콜스택을 타고 위로 올라가도록 한다.
- 이러한 종류의 예외는 프로그램의 정상 동작 범주에 들지 않는 에러 때에만 쓰여야 한다. 즉, 예외를 던지는 코드를 프로그램 종료 코드로 치환한다 하더라도 프로그램은 여전히 정상 동작 해야한다.
13. 예외를 사전확인으로 바꾸기
: 문제가 될 수 있는 부분을 함수 호출 전에 or 함수 내에서 검사해, 어느정도 예상이 가능한 예외를 로직으로 처리한다.
Reference)
리팩터링 2판