Spring - CQS(Command-Query Separation)

Stella·2022년 5월 6일
0

Java

목록 보기
7/18

CQS(Command Query Separation)

  • Command와 Query를 분리.

  • 모든 method는 상태를 변경하는 command 또는 데이터를 반환하는 query 중 한가지 기능만 시실행해야함.

  • Method는 값을 반환 할 때, referentially transparent(시스템의 상태를 변경하지 않을 때 함수)해야하며, side effect 발생 하면 안됨.

  • side effect가 없음 -> 내부에서 변경이 발생하지 않음

  • Query: 결과 값을 반환. 시스템의 상태를 변화 시키지 않음. free of side effect.

    • i.e. max() -> max 값을 반환.
  • Command: 결과를 반환 하지않고, 시스템의 상태 변경.

    • i.e. reverse() -> 값을 반환하지않고, 리스트의 배열을 변경.
  • Query는 상태를 바꾸지 않기 때문에 안전하고 신뢰성을 갖고, 원하는 대로 사용가능.

  • Command는 함수간 사용순서를 신중하게 짜야하고, 잘못 사용한다면 예상치 못한 결과가 나올 수 있기 때문에 사용시 주의를 기울여야함.

CQS 예외사항

  • stack의 pop
    • pop은 가장 최근에 push된 값을 반환하고 stack에서 제거함.
    • stack에서 제거하면서 상태변경(command)와 최근 push된 값을 반환(query)

JPA로 보는 예제

INSERT

  • id만 반환.
  • insert는 db 상태에 변경을 일으키면서 id를 반환함. CQS원칙을 깸.
private EntityManger em;

@Transactional
public Long save(User user) {
	em.persist(user);
    User findUser = em.find(User.class, id);
    return findUser.getId();
 }
    public Long save(HelloController.Member member) {
        em.persist(member);
        return member.getId(); //command랑 query를 분리.
    }

Update

  • 반환 하지않음.
  • db 데이터를 변경하지만, 아무것도 반환하지 않음 -> command
private EntityManger em;

@Transactional
public void update(User user) {
	em.persist(user);
 }

Select

  • db 데이터를 변경하지않고, 결과값만 반환 -> query
private EntityManger em;

@Transactional
public User findOne(Long id) {
    User findUser = em.find(User.class, id);
    return findUser;
 }

https://www.inflearn.com/questions/27795
이 메서드를 호출 했을 때, 내부에서 변경(사이드 이펙트)가 일어나는 메서드인지, 아니면 내부에서 변경이 전혀 일어나지 않는 메서드인지 명확히 분리하는 것.
그렇게 되면 데이터 변경 관련 이슈가 발생했을 때, 변경이 일어나는 메서드만 찾아보면 됨.
정말 크리티컬한 이슈들은 대부분 데이터를 변경하는 곳에서 발생.
변경 메서드도 변경에만 집중하면 되기 때문에 유지보수가 더 좋아짐.
권장방법 : insert는 id만 반환하고(아무것도 없으면 조회가 안되니), update는 아무것도 반환하지 않고, 조회는 내부의 변경이 없는 메서드로 설계.

Ref:
https://hardlearner.tistory.com/383
https://www.inflearn.com/questions/27795

profile
Hello!

0개의 댓글