티스토리 뷰

728x90
반응형

마틴 파울러 - 리팩터링 (2판) 의 11장 내용 중 좋았던 것들 기록 ✏️✏️


 

11.4 객체 통째로 넘기기

 



객체를 통째로 넘기면
- 변화에 대응하기 쉽다.
- 매개변수 목록이 짧아져서 일반적으로 함수 사용법을 이해하기 쉬워진다.

하지만 함수가 객체 자체에 의존하기를 원치 않을 때는 이 리팩토링을 수행하지 않는다.
특히 객체와 함수가 서로 다른 모듈에 속한 상황이면 특히 더 그렇다.

어떤 객체로부터 값 몇 개를 얻은 후 그 값들로만 무언가를 하는 로직이 있다면
그 로직을 객체 안으로 집어넣어야함을 알려주는 악취로 봐야한다.


==>
'객체 통째로 넘기기 vs 객체에서 값 몇개를 꺼내 파라미터로 넘기기'는 개발하며 자주 고민되는 이슈이다.
나도 객체와 함수가 서로 다른 모듈에 속해있는 경우 통째로 넘기기를 안해서 의존성을 안만들어주는 게 좋다고 생각하고 있었다.
(파라미터가 너무 많아지지는 경우는 예외라고 생각)

11.5 매개변수를 질의 함수로 바꾸기 (Replace Parameter with Query)

 


매개변수 목록은 함수의 변동 요인을 모아놓은 곳이다.
다른 코드와 마찬가지로 이 목록에서도 중복은 피하는 게 좋으며 짧을 수록 이해하기 쉽다.

피호출 함수가 스스로 '쉽게' 결정할 수 있는 값을 매개변수로 건네는 것도 일종의 중복이다.
다른 매개변수에서 얻을 수 있는 값을 별도 매개변수로 전달하는 것은 아무 의미가 없다.

매개변수를 질의 함수(쿼리)로 바꾸지 말아야할 상황도 있다.
가장 흔한 예는 매개변수를 제가하면 피호출함수에 원치 않는 의존성이 생길 때다.

주의사항이 하나있다. 대상함수가 참조투명(referential transparency) 해야한다는 것이다.
참조투명이란 함수에 똑같은 값을 건네면 매번 똑같은 결과를 낸다는 뜻이다.

이런 함수는 동작을 예측하고 테스트하기가 훨씬 쉬우니 이 특성이 사라지지 않도록 주의하자.
따라서 매개변수를 없애는 대신 가변 전역 변수를 이용하는 일은 하면 안된다.

11.6 질의 함수를 매개변수로 바꾸기 (Replace Query with Parameter)

 


11.5와 반대되는 리팩터링이다.

참조투명하지 않은 원소(ex. 전역변수)에 접근하는 모든 함수는 참조투명성을 잃게 되는데,
이 문제는 해당 원소를 매개변수로 바꾸면 해결된다.
책임이 호출자로 옮겨진다는 점을 고려해야하지만 모듈을 참조투명하게 만들어 얻는 장점은 대체로 아주크다.

그래서 모듈을 개발할 때 순수함수들을 따로 구분하고,
프로그램의 입출력과 기타 가변 원소들을 다루는 로직으로 순수함수들의 겉을 감싸는 패턴을 많이 활용한다.

그리고 이번 리팩터링을 활용하면 프로그램의 일부를 순수함수로 바꿀 수 있으며
결과적으로 그 부분은 테스트하거나 다루기가 쉬워진다.

이 리팩터링에도 단점은 있다. 질의 함수를 매개변수로 바꾸면 어떤 값을 제공할지를 호출자가 알아내야한다.
결국 호출자가 복잡해지는데, 이왕이면 고객(호출자)의 삶이 단순해지도록 설계하자는 내 평소 지론과 배치된다.
'의존성을 모듈 바깥으로 밀어낸다' 함은 그 의존성을 처리하는 책임을 호출자에게 지운다는 뜻이기 때문이다.
결합도를 낮춘 효과에 대한 반대급부인셈이다.

이 문제는 결국 책임 소재를 프로그램의 어디에 배정하느냐의 문제로 귀결된다.
답을 찾기가 쉽지 않으며 항상 정답이 있는 것도 아니다.


두 극단 사이에서 적절한 균형을 찾아야한다.
한쪽 끝은 모든 것을 매개변수로 바꿔 아주 길고 반복적인 매개변수 목록을 만드는 것이고,
다른 쪽 끝은 함수들끼리 많은 것을 공유하여 수많은 결합을 만들어내는 것이다.

대다수 까다로운 결정이 그렇듯, 이 역시 한 시점에 내린 결정이 영원히 옳다고 할 수 없는 문제다.
따라서 프로그램을 더 잘 이해하게 됐을 때 더 나은 쪽으로 개선하기 쉽게 설계해두는 게 중요하다.

그리고 프로젝트를 진행하면서 균형점이 이리저리 옮겨질 수 있으니
이 리팩터링(11.6)과 그 반대 리팩터링(11.5) 과는 아주 친해져야한다.


11.11 수정된 값 반환하기

 


데이터가 어떻게 수정되는 지를 추적하는 일을 코드에서 이해하기 가장 어려운 부분 중 하나다.
계산이 변수 선언과 동시에 수행되도록 하고 변수에 const를 붙여서 불변으로 만든다.

11.12 오류 코드를 예외로 바꾸기

 


예외는 프로그래밍 언어에서 제공하는 독립적인 오류 처리 메커니즘이다.
오류가 발견되면 예외를 던진다. 그러면 적절한 예외 핸들러를 찾을 때 까지 콜스택을 타고 위로 전파된다.
예외를 사용하면 오류코드를 일일이 검사하거나 오류를 식별해 콜스택 위로 던지는 일을 신경 쓰지 않아도 된다.

예외에는 독자적인 흐름이 있어서 프로그램의 나머지에서는 오류 발생에 따른 복잡한 상황에 대처하는 코드를 작성하거나 읽을 일이 없게 해준다.

예외는 정확하게 사용될 때만 최고의 효과를 낸다.
예외는 정확히 예상 밖의 동작일 때만 쓰여야한다.
달리 말하면 프로그램의 정상 동작 범주에 들지 않는 오류를 나타낼 때만 쓰여야한다.

괜찮은 경험법칙이 하나있는데, 예외를 던지는 코드를 프로그램 종료 코드로 바꿔도 프로그램이 여전히 정상 동작할지를 따져보는 것이다. 정상 동작하지 않을 것 같다면 예외를 사용하지 말라는 신호다. 예외 대신 오류를 검출하여 프로그램을 정상 흐름으로 되돌리게끔 처리해야한다.


11.13 예외를 사전확인으로 바꾸기 (Replace Exception With Precheck)

 


예외라는 개념은 프로그래밍 언어의 발전에 의미 있는 한걸음 이었다.
오류를 연쇄적으로 전파하던 긴 코드를 예외로 바꿔 깔끔히 제거할 수 있게 되었으니 말이다. (11.12 오류 코드를 예외로 바꾸기)

하지만 좋은 것들이 늘 그렇듯, 예외도 (더 이상 좋지 않을 정도 까지) 과용되곤 한다.
예외는 '뜻밖의 오류' 라는 말 그대로 예외적으로 동작할 때만 쓰여야한다.
함수 수행시 문제가 될 수 있는 조건을 함수 호출 전에 검사할 수 있다면, 예외를 던지는 대신 호출하는 곳에서 조건을 검사하도록 해야한다.

반응형
댓글