메서드 파라미터로 객체를 전달할 것이냐? 객체의 프로퍼티를 전달할 것이냐?

아직 명확한 결론에 도달하지 못했다. 양쪽에 장단점이 있고, 컨텍스트에 따라 다르기 때문에 어느 하나의 정답이 존재하는 물음이 아니다.

 

일단 단순한 케이스에서 눈에 보이는 장단점을 정리하면,

아래와 같은 두 함수가 있다고 하자

fun doSomethingWithEachProperties(String arg1, Int arg2, Long arg3) {
	...
}

fun doSomethingWithWholeObject(ParamObject arg) {
	... // arg.getString(), arg.getInt(), arg.getLong() 을 필요할 때 알아서 호출하여 꺼내 씀
}

첫 번째 방법의 장점

- 정확히 필요한 인자만을 취하기에 유리하다. 함수를 호출하는 쪽에서도 어떤 값이 필요한지 정확히 알 수 있으며, 함수 코드의 응집성이 높아진다.

- 보통 첫 번째 접근법을 따를 때는, 일반적으로 메서드는 기본형(String 포함) 인자를 취한다. 때문에 하나의 객체 정의에 묶이지 않고, 보다 공통적으로 사용될 수 있는 함수를 정의하기에 유리하다.

 

첫 번째 방법의 단점

- 함수를 호출하는 쪽에서 어떤 값이 필요한지 정확히 안다는 사실은, 달리 말하면 함수가 '어떻게' 작동하는지 노출한다는 뜻이 될 수 있다. (함수가 private 이라면 이야기가 달라진다.)

- 함수의 작동 방법이 달라져 다른 인자를 추가로 필요로 하게되면 함수 시그니처를 변경해야 할 것이고, 그렇게 되면 이 메서드를 호출하는 모든 코드를 변경해야 한다.

 

 

두 번째 방법의 장점

- 일단 코드가 깔끔해진다. 함수 시그니처, 함수 호출 코드 모두 간결해진다.

- 함수 작동 방법이 달라져 다른 인자가 추가로 필요해져도 함수 시그니처 변경 없이 ParamObject 만을 변경해서 처리할 수 있다. 즉 함수 호출 코드를 변경하지 않을 수 있다. (언제나 그렇지는 않다.)

- 함수가 구체적인 값을 받지 않으므로, 함수의 클라이언트에게 함수가 어떻게 작동하는지에 관하여 '덜 노출하게 되는' 성질이 있다. (역시 함수가 private 이라면 이야기가 달라진다.)

 

두 번째 방법의 단점

- ParamObject 가 이 함수가 필요로 하는 값 외에 다른 값을 가지고 있다면, 이는 함수의 응집성이 낮아진다고 볼 수... 있을까?

- 함수 호출만을 위해 새로운 객체를 정의해야 할 수 있다. 이러면 오히려 더 많은 코드를 작성해야 한다. (물론 이는 추천하지 않는다.)

 

그래서?

예전에는 '코드(함수)가 꼭 필요한 것만을 알도록 한다' 에 중점을 두었었다. 응집성에 더 비중을 둔 것이었는데, 갈수록 생각을 달리하게 되는 케이스를 만난다. 클린 코드에서는 함수의 인자가 3개를 넘기지 않도록 하라는 이야기도 있고(물론 절대적인 것은 아니지만), 구현 캡슐화의 관점에서 보면 이것이 과연 옳은가 하는 생각이 든다.

코드 디자인은 '변경' 을 보다 잘 다루기 위한 일이라는 관점에서 보면, 인자가 추가될 경우를 고려하면 객체를 넘기는 편이 바람직해 보인다. 함수의 변경이 다른 코드의 변경을 유발하는 일은 기본적으로 안티 패턴으로 취급된다. (Shotgun Surgery)

 

 

+ Recent posts