Spring 1주차 - DDD, REST APi

김건우·2023년 12월 20일

개발 공부

목록 보기
9/13
post-thumbnail

DDD (Domain Driven Design) 기획

해결하려는 분야(Domain)의 핵심 문제와 비즈니스 요구사항을 이해하고,
이를 소프트웨어 모델에 명확히 반영하는 것을 최우선으로 한 소프트웨어 개발 방법론이다.
요구사항을 명확히 이해하고, 정의해야한다.

DDD의 과정

  • 전략적 설계(Strategic Design)와 전술적 설계(Tactical Design) 두 가지 주요 과정으로 나뉜다.
    • 전략적 설계 : 개념에 대해 정의하고 설계하는데 중점. 소프트웨어를 설계하기 전 요구사항에 대해 명확하게 정의하고, 개념적인 설계를 하는 과정.
    • 전술적 설계 : 각 영역 도메인 모델을 만들고 구현하는 방법에 중점. 애플리케이션을 개발하기 위한 구체적인 설계 과정.

Strategic Design, 전략적 설계

용어 정의

  • Ubiquitous Language: 공통된 언어(단어)를 통해 개발자와 도메인 전문가를 포함한 팀원들 간에 일관된 용어를 사용하자는 개념이다. 이 언어는 모델링에 사용되고, 코드와 문서에도 반영된다.
  • Actor: 도메인에 속해있는 사용자 이다.
  • Domain Event: 도메인에서 발생하는 사건들 이다. 주로 과거 시제로 기록한다. (e.g. 로그인에 성공함, 상품이 배송됨)
  • Command: Domain Event를 유발시키는 명령이다. 주로 API와 대응된다.
  • Policy: 도메인 내의 규칙으로, Domain Event뒤에 따라오는 하나의 비즈니스 로직이라고 볼 수 있다. Policy에 의해 다른 Event가 Trigger될 수 있다. ****(e.g. 매월 카드 결제일이 되면 계좌에서 결제대금이 빠져나간다)
  • External System: 이메일 전송 시스템, 결제 시스템과 같은 외부 시스템이다. 외부 시스템에 의해 Event가 트리거 되기도 한다.
  • Hotspot: 의문 혹은 질문, 미결정 사항 이다.
  • Aggregate: 비즈니스 로직 수행을 위한 데이터 객체의 집합이라고 할 수 있다. (e.g. 주문이라는 agreegate는 배송정보, 결제정보와 같은 Domain Model(Entity)로 이루어져 있다.)
    Aggregate를 정의함으로써, 모델간의 경계를 잘 정의 할 수 있고, 코드의 일관성을 유지할 수 있다.
  • Bounded Context: Actor, Domain Event, Command를 고려한 하나의 집합 이라고 볼 수 있다. (e.g. 쇼핑몰을 예로 들면, 회원 가입, 정보 수정등을 담당하는 회원 Context, 상품의 주문 및 결제를 담당하는 상품 Context, 배송을 담당하는 배송 Context가 있다.) Bounded Context는 복잡한 비즈니스 도메인에서 이를 구분하고, 관리하기 위해 사용되며 각 컨텍스트 별로 담당하는 조직이 나뉘기도 한다. 또한, Architecture로 분리되기도 한다.

디자인 과정 : Event Storming

  1. 각 요소 별로 다른 색의 포스트잇을 설정한다. 여기서 요소는 위에서 정의된 Actor, Domain Event, Command, Policy, External System, Hotspot, Aggregate이다.
  2. Actor를 정의한다.
  3. Domain Event를 모두 나열한다.
    • Event의 순서를 고려하여 나열한다.
    • Event를 정의하는 중간에 필요할 시, Policy와 Hospot을 정의다.
  4. Event 앞에 Command를 붙인다.
  5. Event 뒤에 External System이 필요할 시 표기한다.
  6. Command앞에 Actor를 설정한다.
  7. Event들을 그룹핑하여 Domain Model 및 Aggregate를 정의한다.
  8. 필요할 시, Bounded Context를 정의한다.
  9. Model의 Data(Model이 담고 있는 정보)에 대해 정의한다.

디자인 예시

  1. Actor 정의

    • 우리의 도메인에서 Actor는 먼저 수강신청을 하는 학생(Student)가 있. 그리고, 강의를 제작하고 질문에 답변을 해주는(Tutor)가 있다. Tutor는 또한, 학생의 수강신청을 승인하거나 거절하는 역할도 한다고 가정한다.
  2. Domain Event 나열

  • 수강신청 Application에서 생길 수 있는 모든 Event나열

    • Student의 회원가입 - 로그인 - 로그아웃 - 프로필 입력
    • Tutor의 회원가입 - 로그인 - 로그아웃 - 프로필 입력
  • 수강신청관련 Event

    • 강의 모음을 Course, 각 코스에 속해있는 영상 강의를 Lecture
    • Course를 생성, 수정, 삭제, 조회, Lecture도 동일
    • 수강신청 -> 신청됨 Event 이후 조회 후 승인, 거절.
    • 신청 승인 인원이 30명이 되면 Course가 마감된다 -> Policy로 작성

  1. Command 설정
  • 이 Event를 일으키는 Command 설정.

  • 이 Command는 추후 API가 된다.

  1. External System 표시

    • 현재는 존재하지 않는다. Lecture를 추가하거나 수정할 시 외부 Storage System 이용 가능성
  2. Actor 표기

    • Actor는 Command를 수행하는 주체. 우리가 붙인 Command를 수행하는 Actor가 Student인지, Tutor인지 구분

  1. Event Grouping 및 Model, Aggregate 정의

    • 이제 비슷한 Event끼리 Grouping 할 수 있다다. 이미 시간순서로 나열하면서 어느정도 비슷한 Event끼리 가까이 위치하는걸 볼 수 있다.
    • 회원가입, 프로필 수정 등은 통틀어서 User 라는 Model 로 표현할수있고, 이 Model에 대해 각종 Command가 실행되고, Event가 발생한다고 볼 수 있다.
    • CourseLecture Model을 정의할 수 있는건 아주 명확하다.
    • 한 가지 헷갈릴 수 있는 부분은 Course 신청 및 승인/거절 부분인데, Course 신청은 하나의 신청 내역이 남고, 우리는 이 신청 내역을 조회하여 승인 및 거절을 하기 때문에 Corse 신청 == Course 신청 내역 생성 이라고 볼 수 있다. 결론적으로, Course Application 이라는 Model을 하나 더 정의할 수 있다.

  • Aggregate는 비즈니스 로직 수행을 위한 데이터 객체의 집합.

  • 여기서는 Course Application, Lecture를 묶어 하나의 Aggregate로 정의할 수 있다.

  • 여기서 Course 자체가 진입점이 되고, Course에 의해 Lecture와 Course Application의 Lifecycle이 결정되기 때문에 Course를 Aggregate Root라고 부를 수 있다.

  1. BoundedContext

    • Bounded Context는 시스템적으로 범위를 나누고, 이를 조직 구조 혹은 아키텍쳐를 나누기 위해 사용한다. 여기서 굳이 나누자면 수강 신청을 하는 Application Context와 Course 및 신청 내역을 관리하는 Management Context로 나눌 수 있다.
  2. Data 정의

    • 크게 User, Course, Lecture, Course Application Model로 나눴고, 각각 담고 있는 정보에 대해 정하기.

    • User - 기본적으로 이메일, 비밀번호가 존재할 것이고, 닉네임을 추가한다. 또한, 해당 유저가 튜터인지, 학생인지 구분하기 위한 역할 데이터도 존재해야 한다.

      • id
      • 이메일
      • 비밀번호
      • 닉네임
      • 역할 (튜터 / 학생)
    • Course - 제목과 함께, 설명을 부가적으로 입력할 수 있다고 가정한다. 또한, 우리의 기획에 따라 신청내역과 강의 목록은 함께 조회를 할 수 있어야한다. 이와 별도로, 최대 수강 가능 인원 수 정보를 조회할 수도 있고, 현재 신청 승인된 인원 수도 조회할 수 있도록 데이터를 정의한다.

      • id
      • 제목
      • 설명 - 필수 아님
      • 마감 상태
      • 최대 수강 가능 인원 수
      • 현재 수강 인원 수
      • Lecture 목록
      • CourseApplication (신청내역 ) 목록
    • Lecture - 제목, 그리고 영상에 대한 URL이 존재한다

      • id
      • 제목
      • 영상 URL
    • CourseApplication - 신청한 User 정보, 그리고 어떤 Course 에 신청 했는지가 중요!

      • id
      • User
      • Course

REST API 설계하기

REST(REpresentational State Transfer) 란?

  • 상태의 전이(State Transfer)를 표현하기 위한 HTTP 아키텍쳐 스타일

  • 여기서 State는 Resource의 State를 의미한다. 이 Resource는 파일, 문서, 데이터 등을 모두 포함한다. 우리는 데이터를 응답해주는 역할을 하고, 이 데이터는 우리가 정의한 Domain Model에 대한 데이터이기 때문에, Resource가 Domain Model을 칭한다고 봐도 무방하다.

  • Respresentation(표현)이 핵심! HTTP를 사용하기 떄문에 이 프로토콜을 활용해 표현한다.

    • URI(Resource) - 먼저 URI 를 통해 Resource 이름을 표현합니다. /models
    • Method(Verb) - HTTP의 Method를 사용해 상태를 변경하는 행위(Verb)를 표현한다. HTTP Method는 GET, POST, PUT, PATCH, DELETE, OPTIONS 로 구성된다.
      • GET : Read 요청이다.. Resource의 정보를 획득하기 위해 사용한다.
      • POST : Create 요청이다. 새로운 Resource를 생성하기 위해 사용한다.
      • PUT : Update 요청이다. Resource에 대한 정보를 수정하기 위해 사용한다. 수정되는 정보를 포함한 모든 Resource의 정보를 포함하여 요청한다.
      • PATCH : Update 요청다. Resource에 대한 정보를 수정하기 위해 사용한다. 수정되는 정보만을 요청한다.
      • DELETE : Delete 요청이다. Resource를 삭제하기 위해 사용한다.
      • OPTIONS : 서버와 클라이언트 사이의 통신 옵션을 확인하기 위해 사용한다. REST에서 표현을 위해 사용하진 않고, HTTP에서 보안 및 효율성을 위해 자동적으로 생성되는 요청이다.
    • JSON, XML 등(Representation of Resource) - Resource의 상태를 표현하는 방법이다. 어떤 형태의 데이터 구조를 사용해도 무방하지만, JSON을 사용할 예정이다

REST Style API 디자인 가이드

  • URI, 즉 Resource의 이름은 명사, 소문자, 복수형을 사용하길 권장한다. /posts 와 같은 식으로 사용한다. /getPosts 이런식으로 동사를 사용하는걸 지양해야한다.

  • / 를 통해 Resource 관의 계층 관계를 표현한다. /has 를 의미한다고 볼 수 있다! 예를 들어 특정 포스트에 달린 댓글들을 URI로 표현한다면, /posts/{id}/comments 이렇게 된다.

  • URI 마지막에 / 를 포함하지 않는다. /posts/ 이런 형태는 지양한다

  • 밑줄 (_)은 사용하지 않아야하고, 가독성을 높이려면 하이픈(-)을 사용한다 -> /posts/{id}/long-comments

  • 특정 Resource 하나를 가져올때에는 URI에 해당 Resource의 Identifier를 포함하여 표현한다. /posts/{id}

  • Resource 목록의 페이징(Paging), 필터링(Filtering), 정렬(Sorting), 검색(Searching)을 통해 정보를 가져올시, Path Variable을 활용한다. /posts?page=12 , /posts?order=latest

  • 적절한 Status Code를 응답한다.

    • 상태 코드의 분류
      • 1XX (Informational - 정보 제공)
        • 임시 응답. 요청이 수신되었으며 프로세스가 계속 진행 중임을 알다.
      • 2XX (Successful - 성공)
        • 요청이 성공정으로 처리되었음을 나타낸다.
      • 3XX (Redirection - 리다이렉션)
        • 클라이언트가 요청한 리소스의 위치가 변경되었음을 나타낸다.
      • 4XX (Client Error - 클라이언트 오류)
        • 클라이언트의 요청에 오류가 있음을 나타낸다.
      • 5XX (Server Error - 서버 오류)
        • 서버에서 요청을 처리 중에 문제가 발생한 경우. 서버 부하, DB 관련 오류 등 클라이언트에 의한 오류가 아닌 서버의 장애로 발생할 때 사용한다.
    • 자주 쓰는 상태 코드
      • 200 : OK
      • 201 : Created, 리소스가 정상적으로 생성 되었을 알림
      • 204: No Content, 리소스가 삭제 되었음을 알림
      • 400 : Invalid Request, 요청이 잘못됨을 알림
      • 401 : Unauthorized, 클라이언트가 인증되지 않았거나, 인증정보가 부족함을 알림
      • 403: Forbidden, 서버가 요청을 이해하긴 했으나, 권한이 없음을 알림
      • 404 : Not Found, 리소스를 찾을 수 없음
      • 500 : Internal Server Error, 서버의 내부 에러
      • 501 : Not Implemented, 요청한 URI의 메소드에 대해 서버가 구현하고 있지 않음을 알림
      • 502: Bad Gateway, 게이트웨이 역할을 하는 서버가 뒷단의 서버로 부터 잘못된 응답을 받았음을 알림.
  • 예시

    • 글 목록의 조회: GET /posts
    • 단일 글 조회: GET /posts/{id}
    • 글 생성: POST /posts
    • 글 수정: PUT /posts/{id}
    • 글 삭제: DELETE /posts/{id}
    • 특정 글의 댓글 목록 조회: GET /posts/{id}/comments
    • 특정 글에 댓글 추가 : POST /posts/{id}/comments
    • 특정 글의 댓글 수정: PUT /posts/{id}/comments/{id}
    • 특정 글의 댓글 삭제: DELETE /posts/{id}/comments/{id}

RESTful API

REST의 규칙을 잘 지킨다. 성숙도 모델

  • Level 0: The Swamp of POX
    • 소수의 URI를 갖고 있고, 일반적으로 POST만을 사용하는 스타일이다.
      RPC(Remote Procedure Call) 스타일과 유사하다.
  • Level 1: Resources
    • 위에서 설명한 REST와 유사하게 URI를 통해 Resource를 표현한다.
      하지만, Verb (HTTP Method)를 POST만 주로 사용한다.
  • Level 2: HTTP Verbs
    • REST Resource를 URI로 사용하면서, HTTP Method를 통해 행위(Verb)에 대해서도 표현한다.
  • Level 3: Hypermedia Controls
    - Level 2에 더하여 HATEOS(Hypertext As The Engine Of Application State) 를 잘 지킨 단계라고 볼 수 있다.
    클라이언트에게 응답을 할 시 다음 단계로 할 수 있는 작업에 대해 알려주기도 한다.
    Resource에 대한 데이터만 응답하는 것이 아니라, 클라이언트의 다음 작업을 위한 URL 도 함께 알려준다.
    예를들어, 댓글을 조회할 시 댓글에 좋아요를 달거나, 대댓글을 달 수 있는 API URL이 뭔지를 함께 알려준다.

    빠른 개발 생산성을 위해 일반적으로 Level2 까지만을 어느정도 준수한다

직접 API 설계하기

Command 를 API로 !

Course API

profile
즐겁게

0개의 댓글