[pre_onboarding] 1차 과제 study

On a regular basis·2021년 11월 3일
0
  • 1차 과제를 수행하며 부족했던 부분들 채워넣기.
  • 프로젝트의 구조는 django의 프로젝트 구조를 따름.
  • 4개의 앱 사용.
  • bulletin: bulletin board라는 게시판 프로젝트의 구체적인 설정 파일 및 각 앱으로의 요청 라우팅 역할을 맡습니다.
  • member: 게시판의 회원에 대한 요청을 처리합니다.
  • post: 게시글에 대한 조작 요청을 처리합니다.
  • security: 인증 및 인가와 관련된 요청을 처리합니다.
  • 게시물 등록 기능으로 코드 분석

# dto/post_content.py 데이터베이스만 담당해주는 곳

from dataclasses import dataclass

@dataclass # 데코레이터를 클래스 위에 붙여준다. 이는 데이터 클래스를 보다 용이하게 선언해주는 데코레이터.
class PostContents: # 이 클래스가 밑에서 views.py, serives.py에서 db가 필요할 때마다 불려질 것.

    title: str
    category: str
    content: str

# views.py : 내 생각엔 여기는 전체적인 명세표 같다. 어디서 데이터 가져와서 어디에 담고 무슨 기능을 구현할 지 설명해주는 느낌

class PostView(View):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.post_service = PostService()

    @authorize
    def post(self, request, member):
        data = json.loads(request.body) # json으로 데이터 받아오기
        post_contents = PostContents(**data) # dto에 있는 데이터들 post_contents 변수에 담고
        self.post_service.write(post_contents, member) # service.py에 있는 post_service 클래스의 write 메소드를 부르고 거기에 dto에서 가져온 post_contents와 멤버를 게시글에 등록할 것.
        return JsonResponse(data={}, status=HTTPStatus.CREATED) # 리턴값으로 HTTPStatus.CREATED 반환

# service.py : 여기서 로직을 담당

class PostService: # 클래스 만들고
    def write(self, contents: PostContents, author: Member): #write라는 메쏘드에 dto에서 만든 PostContents 담아주고 member 앱에 있는 Member 파라미터로 받기
        new_posting = Posting(
            member=author,
            title=contents.title,
            content=contents.content
        ) # new_posting이라는 변수에 Posting을 담을 건데, 그 안에는 게시물 쓰기에 필요한 내용들, member, title, content가 들어감.
        Posting.add(new_posting) # model에 있는 Posting에 new_posting을 추가시켜줄거야!!

# models.py

class Posting(Document): # Posting이라는 클래스 만들어주고 mongoengine에서 지원하는 Document를 상속받음
    id = IntField(primary_key=True)
    member = ReferenceField(Member)
    title = StringField(max_length=100)
    content = StringField(max_length=500)
    created_at = DateTimeField(default=datetime.utcnow)
    updated_at = DateTimeField(default=datetime.utcnow)
    comments = ListField(Comment)
    hits = IntField(default=0)
    category = StringField(max_length=50)
    hit_members = ListField(Member)
# 필요한 컬럼들을 mongodb에서 원하는 타입으로 넣어줌. 신기한게 referenceField(Member)하면 ForeignKey 기능이 됨.
    meta = {'collection': 'postings'} # meta를 써서 postings라는 테이블을 만들어줌.

🪓 추가: CQRS

  • CQRS는 Command Query Responsibility Segregation 의 약자로 단어 그대로 해석하면 "명령 조회 책임 분리". Command와 Query의 분리. 이는 애플리케이션들을 구성하는 아키텍처에 대한 하나의 패턴이라고 함. 즉, 애플리케이션을 구현함에 있어 명령과 조회에 대한 책임을 분리하는 것이 CQRS.
  • 일반적인으로 데이터를 연결된 데이터베이스에 레코드로써 생성(Create)하거나 조회(Read)하거나 갱신(Update)하거나 삭제(Delete). 장고 orm같이. 그리고 이렇게 데이터를 레코드로 저장하는 과정에서 데이터는 특정한 모델(Model)로써 다뤄짐. 이러한 모델은 초기 용도와는 다르게 다양한 레코드가 저장되어 조회/갱신/삭제 될 수 있다. 그러면 그 모델은 그대로 데이터에이스에 저장되겠지. 그럼 하나의 모델이 다양한 요구사항을 녹여내기 위해 거대해지거나 처음과는 다르게 변질 될 수 있음.
  • 그렇기때문에 이런 모델을 재가공할 필요성이 있음. 모델이 변화함에 따라 실질적으로 데이터를 저장, 갱신, 삭제하는 모델과 조회해서 사용하는 모델 간 차이 발생. 그래서 개발자들은 하나의 데이터에 대해 저장, 갱신, 삭제하는 명령 부분과 조회해서 사용하는 조회 부분에 관한 모델을 분리하여 관리하게 된다. 이것이 CQRS가 등장하게 된 배경.
  • CQRS 패턴은 다른 패턴들과 마찬가지로 어떠한 문제를 해결하는 하나의 방법. 그렇기 때문에 CQRS 패턴은 반드시 적용해야하는 패턴이 아닐 수도 있음. 아직 많은 애플리케이션은 CQRS를 적용하지 않는 CRUD 아키텍처가 적합. 게다가 CQRS 패턴은 쉽게 구현할 수 있는 패턴이 아니기에 불필요한 시스템 복잡도를 야기할 수 있음. 예를 들어, 모델의 적절한 경계를 구분하기 위해 DDD 방법론이 기반된 도메인 모델링이 필요할 수 있는 것 처럼.


  • 최종적으로 명령과 조회에 대한 책임이 별도의 애플리케이션으로 완벽히 분리된 형태로 구현될 수 있음.

참고: https://always-kimkim.tistory.com/entry/cqrs-pattern

profile
개발 기록

0개의 댓글