[Programming] 검색? 조회? 에 대한 네이밍 컨벤션

김대니·2023년 1월 23일
0

Programming

목록 보기
2/2

들어가며

어떤 프로젝트의 백엔드 개발을 하게 되면 CRUD API 는 무조건적으로 개발하게 됩니다. 데이터 생성, 조회, 업데이트, 삭제는 기본 기능입니다.

데이터 조회 API

CRUD 에서 R (Read) 에 해당하는 데이터 조회는 크게 2가지 기능이 있습니다.
1) PK 기반으로 작동하는 데이터 조회
예: userId 100 에 해당하는 데이터 조회

2) 페이징이 필요한 데이터 검색
예: userName 에 "김" 이 포함되어 있고, age 가 20세 이상인 user 모두 검색 (1페이지, 페이지당 10개)

네이밍 컨벤션

위와 같은 데이터 조회 API 를 개발할 때, 메소드의 이름은 주로 어떻게 설정하시나요?
보통 findBy..., getBy..., fetchBy..., searchBy... 등 다양한 이름이 있을 수 있습니다.

정답은 없지만 간단한 rule 을 정해두고 개발을 한다면 헷갈리지 않고 좀 더 정리된 코드를 작성할 수 있을 것입니다.

예시. User 엔티티

(예시를 위해 간단하게 작성합니다.)

@Entity
public class User {
	@Id
	private final Long userId;
    
    @Column
    private final String userName;
    
    @Column
    private final String mobile;
    
    @Column
    private final String email;
    
    @Column
    private final ZonedDateTime lastLogginedAt;
    
    @Column
    private final Boolean valid;
}

Rule 1. Find

nullable 한 데이터를 조회할 때 활용합니다.

public interface SearchUserPort {
	Optional<User> findByUserId(Long userId);
    ...
}

Rule 2. Get

not null 데이터를 조회할 때 활용합니다. 반환 데이터가 null 이라면 exception 을 발생시킵니다.

public interface SearchUserPort {
	Optional<User> findByUserId(Long userId);
    
	default User getByUserId(Long userId) {
    	return Optional.ofNullable(userId)
        			.flatMap(this::findByUserId)
                    .orElseThrow(() -> new UserNotFoundException(userId));
    }
}
public class UserNotFoundException extends RuntimeException {
	private final Long userId;
    public UserNotFoundException(Long userId) {
	    super(String.format("사용자 %d 를 찾을 수 없습니다.", userId));
    	this.userId = userId;
    }
}

Rule 3. Search

검색을 하기 위해 활용합니다. 페이지네이션 기능이 함께 구현되어야 합니다.

Page<User> search(UserSearchQuery query, Pageable pageable);

...SearchQuery

검색하고자 하는 조건이 포함되어 있습니다.

@Getter
public class UserSearchQuery {
	private final List<Long> userIds;
    private final String userName;
    private final String mobile;
    private final String email;
    private final ZonedDateTime lastLogginedAtFrom;
    private final ZonedDateTime lastLogginedAtTo;
}

Pageable

pageable 에는 몇 번째 페이지를 조회할 지 (pageNumber), 한 페이지당 조회하고자 하는 아이템은 몇 개 인지 (pageSize) 가 포함되어 있습니다.

검색 코드

public class UserSearchRepository implement SearchUserPort {
	...
    
	@Override
    Page<User> search(UserSearchQuery query, Pageable pageable) {
		BooleanBuilder condition = new BooleanBuilder();
        condition.and(user.valid.isTrue);

        if (CollectionUtils.isNotEmpty(query.getUserIds())) {
            condition.and(user.id.in(query.getUserIds()));
        }

        if (StringUtils.isNotBlank(query.getUserName())) {
            condition.and(user.name.like("%" + query.getUserName() + "%"));
        }

		var result = from(plan)
            .where(condition);

        long totalItemCount = result.fetchCount();

        var items = result
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .fetch();

        return new PageImpl<>(items, pageable, totalItemCount);
    }
}
profile
?=!, 물음표를 느낌표로

0개의 댓글