본문 바로가기
프로젝트 기록/기타

일급 컬렉션(First Class Collection)에 대해

by clean01 2024. 10. 9.

 

약 두달전 프로젝트를 하며 아래와 같은 복잡한 정렬 코드를 구현한 적이 있었습니다.

        // 액션 아이템 모두 뽑아오기
        List<Long> idList = doneRetrospects.stream().map(Retrospect::getId).toList();
        List<ActionItem> actionItemList = actionItemRepository.findAllByRetrospectIdIn(idList).stream()
                .sorted((a, b) -> {
                    if(a.getIsPinned() && b.getIsPinned()
                            && a.getActionItemStatus().equals(b.getActionItemStatus())) {
                        return b.getCreatedAt().compareTo(a.getCreatedAt()); // 둘다 핀 돼있고, 상태도 같으면 최신 순
                    } else if(a.getIsPinned() && b.getIsPinned()) {
                        return a.getActionItemStatus().getPriority() - b.getActionItemStatus().getPriority();
                    } else if(a.getIsPinned() || b.getIsPinned()) {
                        return a.getIsPinned() ? -1 : 1;
                    } else if(!a.getActionItemStatus().equals(b.getActionItemStatus())) {
                        return a.getActionItemStatus().getPriority() - b.getActionItemStatus().getPriority();
                    } else {
                        return b.getCreatedAt().compareTo(a.getCreatedAt()); // 둘다 핀 돼있고, proceeding 이면 최신 순
                    }
                }).toList();

 

그 당시 기획이 핀 여부와 status에 따라 정렬 순서가 바뀌는 방식이었기 때문에 위와 같은 복잡한 로직이 나왔는데, 저는 그 당시 해당 코드를 그대로 Service 클래스에 넣어놓은 채로 PR을 보냈고, 팀원분께서 아래와 같은 리뷰를 해주셨습니다

 

일급 컬렉션이 뭔지 몰랐던 저는 일급 컬렉션에 대해 검색해봤었는데요

오늘 그 내용을 복습 해보기 위해 포스팅 하려고합니다.

 

 

일급 컬렉션이란

일급 컬렉션이란 무엇일까요?

일급 컬렉션이란, 컬렉션을 멤버 변수로 포함한 클래스로 그 컬렉션 외에는 다른 멤버 변수가 없는 클래스를 의미합니다.

 

해당 아티클에 의하면, 일급 컬렉션으로 얻을 수 있는 장점은 아래와 같습니다.

 

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

2. Collection의 불변성을 보장

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

4. 이름이 있는 컬렉션

 

저의 경우 이 중에서 얻을 수 있는 가장 큰 이점은 1번이었습니다.

 

 


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

 

저처럼 정렬 코드를 서비스 클래스에서 관리한다면 어떤 일이 벌어질까요?

해당 컬렉션을 조회할 때마다 위의 복잡한 정렬을 해주어야합니다.

리스트를 응답으로 주기 전에 정렬해주는 것을 깜빡한다면 정렬이 잘못된 채로 응답이 내려가는 것이죠.

 

정렬 로직과 정렬이 필요한 컬렉션을 같은 일급 컬렉션 안에서 관리함으로써 비즈니스에 종속적인 자료구조를 만들 수 있습니다.

public class ActionItems {
    public ActionItems(List<ActionItem> actionItems) {
        this.actionItems = actionItems;
    }

    private final List<ActionItem> actionItems;

    public List<ActionItem> getActionItems() {
        return sortActionItems(this.actionItems);
    }
    
    private List<ActionItem> sortActionItems(List<ActionItem> actionItems) {
        return actionItems.stream()
                .sorted((a, b) -> {
            if(a.getIsPinned() && b.getIsPinned()
                    && a.getActionItemStatus().equals(b.getActionItemStatus())) {
                return b.getCreatedAt().compareTo(a.getCreatedAt()); // 둘다 핀 돼있고, 상태도 같으면 최신 순
            } else if(a.getIsPinned() && b.getIsPinned()) {
                return a.getActionItemStatus().getPriority() - b.getActionItemStatus().getPriority();
            } else if(a.getIsPinned() || b.getIsPinned()) {
                return a.getIsPinned() ? -1 : 1;
            } else if(!a.getActionItemStatus().equals(b.getActionItemStatus())) {
                return a.getActionItemStatus().getPriority() - b.getActionItemStatus().getPriority();
            } else {
                return b.getCreatedAt().compareTo(a.getCreatedAt()); // 둘다 핀 돼있고, proceeding 이면 최신 순
            }
        }).toList();
    }
}

 

이렇게 한다면 getActionItems()를 호출할 때마다 자동으로 정렬이 걸리기 때문에 깜빡하고 정렬을 하지 않을 경우가 생기지 않을 것입니다.

또한, 컬렉션이 클래스 안에서 final 멤버로 관리되고 있으며 setter가 존재하지 않으므로 컬렉션이 불변성을 지킬 수도 있으며

서비스 클래스에 있던 복잡하고 긴 코드가 일급 컬렉션에서 관리됨으로써 서비스 클래스 코드가 깔끔해지고 가독성이 좋아진다는 장점 또한 있을 것 같습니다.

 

 

Reference

https://jojoldu.tistory.com/412

 

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

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

jojoldu.tistory.com