본문 바로가기
우테코 자유테크 스터디/자유주제

[스터디] 일급 컬렉션 발표 자료

by ♡˖GYURI˖♡ 2023. 11. 9.

일급 컬렉션이란?

규칙 8 : 일급 컬렉션 사용

이 규칙의 적용은 간단하다.
컬렉션을 포함한 클래스는 반드시 다른 멤버 변수가 없어야 한다.
각 컬렉션은 그 자체로 포장돼 있으므로 이제 콜렉션과 관련된 동작은 근거지가 마련된 셈이다.
필터가 이 새 클래스의 일부가 됨을 알 수 있다.
필터는 또한 스스로 함수 객체가 될 수 있다.
또한 새 클래스는 두 그룹을 같이 묶는다든가 그룹의 각 원소에 규칙을 적용하는 등의 동작을 처리할 수 있다.
이는 인스턴스 변에 대한 규칙의 확실한 확장이지만 그 자체를 위해서도 중요하다.
컬렉션은 실로 매우 유용한 원시 타입이다.
많은 동작이 있지만 후임 프로그래머나 유지보수 담당자에게 의미적 의도나 단초는 거의 없다.

- 소트웍스 앤솔로지 객체지향 생활체조편

 

한 마디로 Collection을 Wrapping하면서, 그 외의 다른 멤버 변수가 없는 상태를 일급 컬렉션이라고 합니다.

 

 

아래의 코드를

Map<String, String> map = new HashMap<>();
map.put("1", "A");
map.put("2", "B");
map.put("3", "C");

 

이와 같이 Wrapping하는 것을 이야기합니다.

public class GameRanking {

    private Map<String, String> ranks;

    public GameRanking(Map<String, String> ranks) {
        this.ranks = ranks;
    }
}


특징

  • 컬렉션 객체는 변수나 매개변수에 할당할 수 있다.
  • 컬렉션 객체는 다른 객체와 동등한 지위를 가진다.
  • 컬렉션 객체는 반환값으로 사용할 수 있다.
  • 컬렉션 객체는 필요한 경우 메서드에서 생성할 수 있다.

 

이점

  1. 비즈니스에 종속적인 자료구조
  2. Collection의 불변성을 보장
  3. 상태와 행위를 한 곳에서 관리
  4. 이름이 있는 컬렉션

+ 가독성과 유지보수성 향상, 유효성 검증 용이 등등...

 

 

1. 비즈니스에 종속적인 자료 구조

<로또 게임 예시>

로또 복권은 다음의 조건이 있습니다.

  • 6개의 번호가 존재
    • 보너스 번호는 이번 예제에서 제외
  • 6개의 번호는 서로 중복되지 않아야 함

일반적으로 이런 일은 서비스 메소드에서 진행합니다.

 

이처럼 서비스 메소드에서 비지니스 로직을 처리했을 때 문제들이 생깁니다.

바로 로또 번호가 필요한 모든 장소에선 검증로직이 들어가야만 한다는 점입니다.

  • List<Long> 으로 된 데이터는 모두 검증 로직이 필요할까요?
  • 이 코드를 처음 본 사람들은 어떻게 이 검증로직이 필요한지 알 수 있을까요?

모든 코드와 도메인을 알고 있지 않다면 언제든 문제가 발생할 여지가 있습니다.

그렇다면 어떻게 해야할까요?

  • 6개의 숫자로만 이루어져야만 하고
  • 6개의 숫자는 서로 중복되지 않아야만 하는

이런 자료구조를 만들면 됩니다.

 

아래와 같이 해당 조건으로만 생성 할 수 있는 자료구조를 만들면 위의 문제들이 모두 해결됩니다.

그리고 이런 클래스를 일급 컬렉션이라고 부릅니다.

 

 

 

 

2. 불변

일급 컬렉션은 컬렉션의 불변을 보장합니다.

Java의 final은 불변을 만들어주는 것은 아니며, 재할당만 금지합니다.

 

@Test
public void final도_값변경이_가능하다() {
    //given
    final Map<String, Boolean> collection = new HashMap<>();

    //when
    collection.put("1", true);
    collection.put("2", true);
    collection.put("3", true);
    collection.put("4", true);

    //then
    assertThat(collection.size()).isEqualTo(4);
}

 

@Test
public void final은_재할당이_불가능하다() {
    //given
    final Map<String, Boolean> collection = new HashMap<>();

    //when
    collection = new HashMap<>();

    //then
    assertThat(collection.size()).isEqualTo(4);
}

 

이 코드는 컴파일 에러가 발생합니다.

 

final로 할당된 코드에 재할당은 불가하기 때문입니다.

 

불변 객체는 사이드 이펙트를 최소화시키기 위해 중요합니다.

 

불변 객체란?

1) 객체를 변경하는 메소드를 제공하지 않는다.
2) 재정의할 수 있는 메소드를 제공하지 않는다.
3) 모든 필드를 final로 만든다.
4) 모든 필드를 private으로 만든다.
5) 가변 객체를 참조하는 필드는 배타적으로 접근해야 한다.


즉, 객체의 상태를 바꿀 수는 없으므로 새로운 상태로 변경해야 할 경우 새로운 불변 객체를 만들어 기존의 불변 객체를 대체 시켜야 한다. 이를 통해 불변객체는 사이드 이펙트 및 동시성 이슈에 노출되지 않는다. 따라서 함수형 프로그래밍에서 Side-effect를 발생시키지 않기 위해 불변객체를 사용하는 것이지, 일급 컬렉션의 특징이 불변성을 보장하는 것은 아니다. 

 

 

Java에서는 final로 그 문제를 해결할 수 없기 때문에 일급 컬렉션래퍼 클래스 등의 방법으로 해결해야합니다.

 

그래서 아래와 같이 컬렉션의 값을 변경할 수 있는 메소드가 없는 컬렉션을 만들면 불변 컬렉션이 됩니다.

 

이 클래스는 생성자와 getAmountSum() 외에 다른 메소드가 없습니다.
즉, 이 클래스의 사용법은 새로 만들거나 값을 가져오는 것뿐입니다.
List라는 컬렉션에 접근할 수 있는 방법이 없기 때문에 값의 변경/추가가 안됩니다.

이렇게 일급 컬렉션을 사용하면, 불변 컬렉션을 만들수 있습니다.

 

 

3. 상태와 행위를 한 곳에서 관리

일급 컬렉션의 3번째 장점은 값과 로직이 함께 존재한다는 것입니다.

 

예를 들어 여러 Pay들이 모여있고, 이 중 NaverPay 금액의 합이 필요하다고 가정해보겠습니다.

 

이 상황에는 문제가 있습니다.
결국 pays 라는 컬렉션과 계산 로직은 서로 관계가 있는데, 코드로 표현이 안됩니다.

Pay타입의 상태에 따라 지정된 메소드에서만 계산되길 원하는데, 현재 상태로는 강제할 수 있는 수단이 없습니다.
지금은 Pay타입의 List라면 사용될 수 있기 때문에 히스토리를 모르는 분들이라면 실수할 여지가 많습니다.

  • 똑같은 기능을 하는 메소드를 중복 생성할 수 있습니다.
    • 히스토리가 관리 안된 상태에서 신규화면이 추가되어야 할 경우 계산 메소드가 있다는 것을 몰라 다시 만드는 경우가 빈번합니다.
    • 만약 기존 화면의 계산 로직이 변경 될 경우, 신규 인력은 2개의 메소드의 로직을 다 변경해야하는지, 해당 화면만 변경해야하는지 알 수 없습니다.
    • 관리 포인트가 증가할 확률이 매우 높습니다.
  • 계산 메소드를 누락할 수 있습니다.
    • 리턴 받고자 하는 것이 Long 타입의 값이기 때문에 꼭 이 계산식을 써야한다고 강제할 수 없습니다

결국에 네이버페이 총 금액을 뽑을려면 이렇게 해야한다는 계산식을 컬렉션과 함께 두어야 합니다.

만약 네이버페이 외에 카카오 페이의 총금액도 필요하다면 더더욱 코드가 흩어질 확률이 높습니다.

 

그래서 이 문제 역시 일급 컬렉션으로 해결합니다.

public class PayGroups {
    private List<Pay> pays;

    public PayGroups(List<Pay> pays) {
        this.pays = pays;
    }

    public Long getNaverPaySum() {
        return pays.stream()
                .filter(pay -> PayType.isNaverPay(pay.getPayType()))
                .mapToLong(Pay::getAmount)
                .sum();
    }
}

 

만약 다른 결제 수단들의 합이 필요하다면 아래와 같이 람다식으로 리팩토링 가능합니다.

public class PayGroups {
    private List<Pay> pays;

    public PayGroups(List<Pay> pays) {
        this.pays = pays;
    }

    public Long getNaverPaySum() {
        return getFilteredPays(pay -> PayType.isNaverPay(pay.getPayType()));
    }

    public Long getKakaoPaySum() {
        return getFilteredPays(pay -> PayType.isKakaoPay(pay.getPayType()));
    }

    private Long getFilteredPays(Predicate<Pay> predicate) {
        return pays.stream()
                .filter(predicate)
                .mapToLong(Pay::getAmount)
                .sum();
    }
}

 

이렇게 PayGroups라는 일급 컬렉션이 생김으로써, 상태와 로직이 한곳에서 관리 됩니다.

 

 

4. 이름이 있는 컬렉션

마지막 장점은 컬렉션에 이름을 붙일 수 있다는 것입니다.

같은 Pay들의 모임이지만 네이버페이의 List와 카카오페이의 List는 다릅니다.
그렇다면 이 둘을 구분할려면 어떻게 해야할까요?
가장 흔한 방법은 변수명을 다르게 하는 것입니다.

  • 검색이 어려움
    • 네이버페이 그룹이 어떻게 사용되는지 검색 시 변수명으로만 검색할 수 있습니다.
    • 네이버페이의 그룹이라는 뜻은 개발자마다 다르게 지을 수 있기 때문에, 이 상황에서 검색은 거의 불가능합니다.
  • 명확한 표현이 불가능
    • 변수명에 불과하기 때문에 의미를 부여하기가 어렵습니다.
    • 중요한 값임에도 이를 표현할 명확한 단어가 없는것이죠.

위 문제 역시 일급 컬렉션으로 쉽게 해결할 수 있습니다.

네이버페이 그룹과 카카오페이 그룹 각각의 일급 컬렉션을 만들면 이 컬렉션 기반으로 용어사용과 검색을 하면 됩니다.

 

 

 

 


https://jojoldu.tistory.com/412

 

일급 컬렉션 (First Class Collection)의 소개와 써야할 이유

최근 클린코드 & TDD 강의의 리뷰어로 참가하면서 많은 분들이 공통적으로 어려워 하는 개념 한가지를 발견하게 되었습니다. 바로 일급 컬렉션인데요. 왜 객체지향적으로, 리팩토링하기 쉬운 코

jojoldu.tistory.com

https://tecoble.techcourse.co.kr/post/2020-05-08-First-Class-Collection/

 

일급 컬렉션을 사용하는 이유

일급 컬렉션이란? 본 글은 일급 컬렉션 (First Class Collection)의 소개와 써야할 이유를 참고 했다. 일급 컬렉션이란 단어는 소트웍스 앤솔로지의 객체지향 생활체조 규칙 8. 일급 콜렉션 사용에서 언

tecoble.techcourse.co.kr

https://brainbackdoor.tistory.com/140

 

일급컬렉션에 대하여

https://edu.nextstep.camp/c/8fWRxNWU/ 클린코드를 위한 TDD, 리팩토링 with Java edu.nextstep.camp TDD, 클린코드 코드리뷰를 하다보면 '원시값과 문자열을 포장하라', '일급콜렉션을 쓴다'와 같은 피드백을 주곤한

brainbackdoor.tistory.com

https://dkswnkk.tistory.com/696

 

일급 컬렉션(First-Class Collection)이란?

서론 실무를 진행한 지 3개월,, 실력 있는 개발자란 유지보수와 확장성을 고려하여 작성하는 사람이라는 것을 깨닫게 된 이후로 저도 그렇게 되기 위해 다양한 방면으로 레퍼런스를 찾아보며 노

dkswnkk.tistory.com

https://velog.io/@jhp1115/%EC%9D%BC%EA%B8%89%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%ED%95%84%EC%9A%94%EC%84%B1