Dev/Java

동작 파라미터화 코드 전달하기 (1)

아콩2 2022. 5. 20. 23:57
반응형

개요

우리가 어떤 상황에서 일을 하든 소비자 요구사항은 항상 바뀐다. 변화하는 요구사항은 소프트웨어 엔지니어링에서 피할 수 없는 문제다.
시시각각 변하는 사용자 요구 사항에 어떻게 대응해야 할까? 특히 우리의 엔지니어링적인 비용이 가장 최소화 될 수 있으면 좋을 것이다.
그뿐 아니라 새로 추가한 기능은 쉽게 구현할 수 있어야 하며 장기적인 관점에서 유지보수가 쉬어야 한다.
동작 파라미터화(Behavior Parameterization 을 이용하면 자주 바뀌는 요구사항에 효과적으로 대응 할 수 있다.
동작 파라미터화란 아직은 어떻게 실행할 것인지 결정하지 않은 코드 블록을 의미한다.
이 코드 블록은 나중에 프로그램에서 호출한다. 즉, 코드 블록의 실행은 나중으로 미뤄진다. 예를들어 나중에 실행될 메서드의 인수로 코드 블록을 전달할 수 있다. 결과적으로 코드 블록에 따라 메서드의 동작이 파라미터화된다.
동작 파라미터화를 추가하려면 쓸데없는 코드가 늘어나지만 자바 8은 람다 표현식으로 이 문제를 해결한다. 람다 표현식에 관한 내용은 3장에서 !

1. 변화하는 요구사항에 대응하기

  • 하나의 예제를 선정한 다음에 예제 코드를 점차 개선하면서 유연한 코드를 만드는 모범 사례
  • 기존의 농장 재고목록 애플리케이션에 리스트에서 녹색 사과만 필터링하는 기능을 추가한다고 가정해보자

1.1 첫번째 시도 : 녹색 사과 필터링

enum Color { RED, GREEN }
public static List<Apple> filterGreenApples(List<Apple> inventory){
    List<Apple> result = new ArrayList<>(); // 사과 누적 리스트
    for(Apple apple : inventory){
        if(GREEN.equals(apple.getColor()){ // 녹색 사과만 필터링
            result.add(apple);
          }
     }   
     return result;
}

그런데 갑자기 농부가 변심을 하여 녹색 사과 말고 빨간 사과도 필터링 하고 싶다고 한다.

왤캐 변덕스러워ㅡㅡ

크게 고민하지 않은 사람이라면 메서드를 복사해서 filterRedApples 이라는 새로운 메서드를 만들고, if 문의 조건을 빨간 사과로 필터링 할 수는 있겠지만 나중에 농부가 좀 더 다양한 색을 필터링 하는 등의 변화에는 적절하게 대응할 수 없다

거의 비슷한 코드가 반복되면 그 코드를 추상화 하자.

1.2 두번째 시도 : 색을 파리미터화

public List<Apple> filterApplesByColor(List<Apple> inventory, Color color){
    List<Apple> result = new ArrayList<>();
    for(Apple apple: inventory) {
        if(apple.getColor().equals(color)){
            result.add(apple);
        }
    }
    return result;
}    

List<Apple> greenApples = filterApplesByColor(inventory,GREEN);
List<Apple> rendApples = filterApplesByColor(inventory, RED);

그런데 또 갑자기 농부가 다시 나타나서는 색 이외에도 가벼운 사과와 무거운 사과로 구분하고 싶다고 한다. 무겁고 가볍고의 기준을 150 그램으로 하겠다고 한다. 이 농부를 보니 색과 마찬가지로 앞으로 무게의 기준도 얼마든지 바뀔수 있을 사람임이 분명하다.
그래서 아싸리 다양한 무게에도 대응할 수 있도록 무게 정보 파라미터도 추가하였다.

public List<Apple> filterApplesByWeight(List<Apple> inventory, int wegiht){
   List<Apple> result = new ArrayList<>();
      for(Apple apple: inventory) {
          if(apple.getWeight() > weight){
              result.add(apple);
          }
      }
      return result;

}

좋은 해결책이였다고 할 수 있지만 구현 코드를 자세히 보면 목록을 검색하고, 각 사과에 필터링 조건을 적용하는 부분의 코드가 색 필터링 코드와 대부분 중복된다. 이는 소프트웨어 공학의 DRY (Don't repeat yourself) 원칙을 어기는 것이다.
탐색 과정을 고쳐서 성능을 개선하려면 무슨 일이 일어날까? 한 줄이 아니라 메서드 전체 구현을 고쳐야 한다. 즉, 엔지니어링적으로 비싼 대가를 치러야한다.

색과 무게를 filter라는 메서드로 합치는 방법이 있다. 그러면 어떤 기준으로 사과를 필터링 할 지 구분하는 또 다른 방법이 필요하다. 따라서 색이나 무게 중 어떤 것을 기준으로 필터링 할지 가리키는 플래그를 추가 할 수 있다 (실전에서 절대 이 방법을 사용해선 안돼~

1.3 세 번째 시도: 가능한 모든 속성으로 필터링

public List<Apple> filterApples(List<Apple> inventory, Color color, int weight, boolean flag) {
    List<Apple> result = new ArrayList<>();
    for(Apple apple : invenotry){
        if((flag && apple.getcolor().equals(color)) || (!flag && apple.getWeight() > weight){
            result.add(apple)
        }
    }

    return apple;s

}


List<Apple> greenApples = filterApples(inventory,Green,0,true);
List<Apple> heavyApples = filterApples(inventory,null,150,false);

최1악이다. true와 false가 의미하는게 뭘까? 심지어 앞으로 저 변덕스러운 농부의 요구사항이 바뀌었을때 유연하게 대응할 수도 없다. 예를 들어 사과의 크기, 모양, 출하지 등으로 사과를 필터링 하고 싶다고 한다면? 심지어 녹색 사과 중에 무거운 사과를 필터링 하고 싶다면?? 결국 여러 중복된 필터 메서드를 만들거나 아니면 모든 것을 처리하는 거대한 하나의 필터 메서드를 구현해야 한다. 지금까지는 문자열,정수,불리언 등의 값으로 filterApples 메서드를 파라미터화 했다. 이렇게 코드를 짠다고 동작하지 않는것은 아니지만 동작 파라미터화 를 이용하여 유연성을 얻어보자~!

반응형