[프로그래밍 초식] 왕 파라미터는 사용하지 말라

해로(haero77)·2022년 12월 22일
0

들어가며

이펙티브 자바 아이템 51. 메서드 시그니처를 설계하라 를 읽으며 ‘매개변수는 짧게 유지하라’라는 항목에 대한 공부 중 최범균님의 프로그래밍 왕초식: 왕파라미터X 을 보게 되었다.

내용을 요약하면 ‘여러 메서드에서 파라미터로 같은 클래스 타입으로 선언된 변수를 받는 경우’를 심심치 않게 볼 수 있고, 이같은 방식은 메서드와 필드의 매핑을 기억력에 의존하게 되므로 향후 유지보수하기 어려운 코드를 작성하게 될 수 있어 메서드에 맞는 파라미터를 사용 하는 것을 권장한다는 것이다. 본 포스팅에서는 해당 유튜브 강의를 들으며 배운점과 느낀점을 간단히 정리해본다.


왕 파라미터를 사용하며 생기는 문제

여기서 말하는 ‘왕 파라미터’ 란 여러 메서드에서 파라미터로 사용되는 몸집이 큰 파라미터(일종의 ’GOD클래스’)를 말한다. 아래 예시를 보면 이해하기가 더 쉬울 것이다.

public class Data {
		
		private Long id;
		...

		// Getter, Setter
}

// 한 파라미터 타입(Data)을 여러 메서드에서 공유하는 구조 
public void update(Data data) {
    Some some = getSome(data); // Data 파라미터 사용 

    data.setKey(some.getKey());

    int ret = otherDao.update(data); // Data 파라미터 사용 

    if (ret == 1) {
        data.setReg(new Date());
        anyDao.insert(data); // Data 파라미터 사용 
    }
}

Data 타입은 getSome(), otherDto.update(), anyDao.insert() 등 여러 메서드에서 파라미터로 쓰이는 ‘왕 파라미터’ 이다. 이 때 anyDao.insert() 메서드에 ‘ip’ 라는 값이 필요하다면 어떻게 할까? 단순히 Data 클래스에 ip 필드를 추가해줌으로써 해결할 수 있다.


public class Data {
	
		private Long id; 
		...
		private String ip; // 파라미터로 사용하는 Data 클래스에 추가 값을 위한 필드 'ip' 추가

		// Getter, Setter
}

public void update(Data data) {
    Some some = getSome(data);

    data.setKey(some.getKey());

    int ret = otherDao.update(data);

    if (ret == 1) {
        data.setReg(new Date());
				data.setIp(some.getIp()); // anyDao.insert()에서 필요한 'ip' 값 세팅
        anyDao.insert(data);
    }
}

파라미터로 사용하는 클래스에 새롭게 필요한 필드만 추가(private String ip;)해주었다. 또한 메서드에서도 필요한 필드의 값을 세팅하기 위한 코드만 추가(data.setIp(some.getIp());)하면 되므로 전체 코드 작성량도 줄어드는 것처럼 보인다. 즉 이와 같은 한 ‘파라미터 타입을 여러 메서드에서 공유하는 구조’는 편하고 좋아보인다.

(이미지 출처: https://www.youtube.com/watch?v=MIYwej-VodE)


그러나 이 방식은 치명적인 단점이 있다. 사람인 이상, 어느 메서드에서 Data 클래스의 어느 필드값을 사용할지 모두 기억할 수 없기 때문이다.

즉, ‘파라미터 타입을 여러 메서드에서 공유하는 구조’ 를 사용하게 되면

  • 각 메서드에서 어떤 값을 사용하는지 알 수 없고, 이것은 데이터 흐름을 추적하기 어렵게 만든다.
  • 머리로 메서드와 필드간 매핑을 기억해야한다.

당장은 위와같은 방식이 쉽고 편리하지만, 향후 유지보수성을 떨어뜨리는 결과를 초래한다.

다행히, 메서드에 맞는 파라미터를 사용함으로써 이같은 문제를 해결할 수 있다.


조금 귀찮아도 메서드에 맞는 파라미터를 사용하자

(이미지 출처: https://www.youtube.com/watch?v=MIYwej-VodE)


‘한 파라미터 타입을 여러 메서드에서 공유하는 구조’ 대신 메서드에 맞는 파라미터(타입)를 사용하자.

update() 메서드의 파라미터 타입으로 UpdateReq 을, otherDao.update()의 파라미터 타입으로 OtherUpdate를, anyDao.insert()의 파라미터 타입으로 AnyData를 사용했다.

이렇게 함으로써, 각 메서드에서 어떤 값을 사용하는지 알기 쉬워졌다.

즉, 메서드에 맞는 파라미터(타입)를 사용 하면

  • 명시적인 데이터 변환으로 흐름 추적이 쉬워진다.
  • 머리로 메서드와 필드 간 매핑을 기억하지 않아도 된다.

결론: 파라미터 타입 만드는데 인색하지 말 것

메서드에 맞게 새로운 파라미터 타입을 정의하는데 인색하지 말아야한다.

아래 두 가지 핵심 원칙을 지키며 개발함으로써 (시간을 포함한)개발 비용을 현저히 낮출 수 있다.

  • 여러 메서드를 위한 값을 한 파라미터 타입(예: 예시 코드의 Data 클래스)에 우겨넣지 말 것
  • 메서드에서 필요한 값만 파라미터로 받을 것

마치며

이전까지는 메서드에서 어떤 클래스의 어느 필드를 사용할 것인지는 해당 메서드를 뜯어보면 알 수 있는 것 아닌가라고 생각했었다. 그렇지만 내부 코드를 들여다봐야하는 것은 그 자체로 개발 생산성을 떨어뜨린다. 또한 메서드를 사용할 때 메서드 시그니처만 보고도 해당 메서드가 어떻게 동작할 지를 유추할 수 있어야 한다는 점에서 메서드에 맞는 파라미터(타입)를 사용 하는 것이 향후 유지보수성을 높이는 방법 중 하나임을 알 수 있었다. 이렇게 프로그래밍 초식을 하나씩 쌓아가다 보면 필자도 언젠가 보기 좋고 쓰기도 좋은 코드를 작성할 수 있게 되지 않을까라고 기대하며 이만 본 포스팅을 마친다.

참고
프로그래밍 왕초식: 왕파라미터X

profile
Every Run, Learn Counts.

0개의 댓글