비즈니스 성공을 위한 Java/Spring 기반 서비스 개발과 MSA 구축 #3 (주문 프로젝트 개발)

박주진·2021년 9월 10일
0

아래 내용은 비즈니스 성공을 위한 Java/Spring 기반 서비스 개발과 MSA 구축 강의를 기반으로 하여 정리한 내용입니다. 자세한 내용 및 코드가 궁금하면 위에 강의를 참고해주세요.

이번 강의는 라이브 코딩이 대부분이라 개인적으로 개발하면서 유념하면 좋을 만한 내용들 위주로 정리하였습니다.

네이밍 관례

  • getXxx (조회 결과가 없다면 exception을 발생하는 메서드 명)
  • findByXxx (조회 결과를 Optional반환 하는 메서드명)
  • makeXxx (DB와 같은 저장소와 무관하게 메모리상에서 객체를 생성하는 메서드명)
  • init엔티명 (makeXxx 메서드로 생성된 엔티티를 지칭하는 변수명으로 auto increment로 생성하는 pk 값은 null이다.)

대체키 사용

  • entity 식별자 (주로 table auto_increment)와 동급의 의미를 가진 추가 식별자.
  • 외부에 enity의 식별자를 노출해야 할때 대체키를 적극 사용한다.
  • string 기반의 randome 토큰형식으로 생성하고 테이블에는 unique index로 설정한다.
  • entity의 주 식별자(pk)를 외부에 공개하면 아래와 같은 단점이 있어 대체키가 필요하다.
    • 식별자는 주로 BigInt(Long) 형인데 이는 쉽게 유추 및 조작이 가능해 보안에 취약하다.
    • 식별자가 외부 연동 서비스에 공개되면 외부 시스템과 자사 시스템의 결합이 강해진다. 예를 들면 만약 자사 시스템에서 데이터베이스 변경과 같은 작업이 일어나면 이전 pk 값도 같이 가져가야하며 이를 위해 추가적인 공수가 발생한다.
  • string 기반의 대체키 성능은 생성시 timestamp위치를 조절하여 끌어올릴 수 있다. 자세한 내용 링크

순수한 도메인 모델 추구는 실용성이 떨어진다

  • 이상적인 entity(도메인 모델)은 databse영향으로 부터 독립적이어야 한다. 하지만 orm을 사용하다보면 완전히 독립적이게 구성하기 어렵다.
  • 순수한 도메인 모델을 추구하기 위해 별도의 DAO를 둘 수 있지만 이는 구현 비용이 너무 비싸 현실적이 않다.
  • 자세한 설명 링크

api 응답체계

  • 응답체계는 시스템 전체가 일관된 형태를 가져가야 에러 모니터링시 편하고 서버간 통신시에도 불필요한 의사소통 시간을 줄일 수 있다.
  • 예시 응답형태
 {
  "result": "SUCCESS", // (SUCCESS OR FAIL)
  "data": "plain text 또는 json 형태의 데이터",
  "messsage": "message", //에러 메세지
  "error_code": null // 에러코드
}

1. http status: 2xx 이면서 result: "SUCCESS"
→ 시스템 이슈 x, 비즈니스 로직도 처리 성공
2. http status: 2xx 이면서 result: "FAIL"
→ 시스템 이슈 x, 비즈니스 로직 처리 에러
→ 예시: 중복 데이터가  / 인증 이슈
3. http status: 4xx 이면서 result: "FAIL"
→ 잘못된 request 
→ 예시: 필수 요청 파라미터 누락
4. http status: 5xx 이면서 result: "FAIL"
→ 시스템 에러 상황. 집중적으로 모니터링
→ 예시: 시스템 장애

로깅의 중요성

  • 로그를 통해 버그 원인 파악이 가능하다.
  • 로깅 모니터링을 통해 에러 상황에 빠르게 대응이 가능하다.
  • 테스트가 없을때 API 레벨의 request, response 로그를 활용하면 전체 흐름을 파악할 수 있고 리팩토링을 진행할 수 있다.

Aggregate

  • 연관객체의 묶음.
  • Root란 Aggregate 내부의 특정 하나의 엔티티.
  • Boundary란 경계안에 무엇이 포함되고 포함되지 않는지를 정의한다.
  • 경계 밖에서는 Root와만 직접 통신이 가능하다. (이렇게 되면 root에만 제약조건 등을 신경써서 적용하면 정합성을 맞추기 쉽다.)
  • 경계 안에서는 연관객체끼리 서로 통신이 가능하다.
  • 경계안에 객체(Aggregate 단위로) 변경에 대한 일관된 규칙을 지켜야 한다.
  • root을 제외한 Aggregate내부의 다른 객체는 대체키 속성이 필요없다. 왜냐하면 외부와 통신이 필요하지 않기 때문이다.
  • 외부에서는 객체 참조보다는 식별자로 참조해야 한다.

Factory

  • 메모리상에서 정합성에 맞는 객체를 생성하는 책임을 가지고 있다.
  • 복잡한 객체 생성로직을 담당하여 클라이언트에 설계가 지저분해지는 것을 막아준다.
  • Aggregate 또는 객체를 생성할때 복잡한 생성 로직을 일관성있게 유지할 수 있고 클라이언트와 강하게 결합되는 것을 막아준다.
  • Aggregate를 생성하는 일이 복잡해지거나 내부구조를 너무 많이 드러내야 하는 경우 적극적으로 사용하자.

Repository

  • 영속화된 도메인 객체에 대한 참조를 획득할 수 있게 해주는 객체.
  • 도메인 객체 조회, 추가, 제거와 같은 기술을 캡슐화하여 제공하는 객체.
  • 다양한 데이터베이스 관련 기술을 활용한 복잡한 구현은 infrastructure에서 위임한다.

연관관계 설정

  • JPA에서 1:n 관계에서 객체참조 관계를 맺어야 한다면 양방향 OneToMany를 사용하는 것을 권장한다.
  • OneToMany만 사용시 아래와 같은 문제가 발생할 수 있습니다.
    • 성능 자세한 내용 링크
    • 객체와 객체가 연관관계를 맺는방식과 테이블과 테이블이 연관관계를 맺는 방식의 차이로 혼란을 야기할 수 있다.
  • 개인적인으로는 외래키가 존재하는 곳을 주인으로 단방향으로 설정하고 정말 필요한 곳에만 양방향 관계를 설정을 추가한다. 왜냐하면 양방향 설정을 추가하면 로직의 복잡도가 올라가기 때문이다.

질문

  • 실제 현업에서 domain 레이어의 서비스에 인터페이스를 사용해서 얻는 이점이 많을까? Infrastructure레이어의 클래스들 처럼 특정 기술에 의존한게 아니라 어느정도 추상화가 되어 있는데 어떤 상황에서 유용할까?

  • xxxfactory는 메모리상에서 정합성에 맞는 객체를 생성하는 책임을 가진 객체라는데 ItemOptionSeriesFactoryImpl와 같은 객체는 실질적인 데이터베이스에 저장하는 로직을 포함해도 될까?

  • Xxxstore retun type을 void 가 아닌 저장한 객체로 하는 이유는 무엇일까?

  • itemReader.getItemOptionSeries(item)왜 필요할까? 단순히 item.getItemOptionGroupList()해서 ItemOptionGroupInfo로 컨버팅하는 로직을 한번 감싸기 위한 메서드 일까? 아님 item aggregate내부의 다른 객체들을 외부에 노출시키지 않기 위함인가? 그렇다고 하기에는 item.getItemOptionGroupList()로 얼마든지 aggregate내부 다른객체에 대한 참조를 얻을 수 있어 보인다.

  • Order.calculateTotalAmount() 메서드를 필요로 할때는 fetch join과 같은 방법을 이용해서 Order 객체를 조회하는 방식은 불필요한가? 보통 어떤 상황에서 현업에서는 많이 쓸까?

  • uuid만 사용하는 방법은 별로인가?

0개의 댓글