swsnu / swpp2019-team6

Triplannet helps you to share and organize your travel plans easily.
3 stars 1 forks source link

[Backend] Travel Model Structure #50

Open deploy-soon opened 4 years ago

deploy-soon commented 4 years ago

What is the problem? google API도 연결하고 싶고 프론트 개발중 직관적으로 이해가 쉽지 않아 travel 모델 관련 백엔드를 먼저 개발하고 싶습니다. 다만 travel이 만들어지고 이후 edit하거나 merge 혹은 fork할 때를 대비하기 위해 travel item(여행 세부 요소)별로 따로 model을 만들기로 했던 것 같은데(ER diagram 참고) 아직 팀원 사이에 합의가 부족한 것 같습니다. 이를 구현하기 위해 깊은 고민하고 아래와 같이 구현하고자 하는데 의견 듣고 싶습니다.

Travel Model Outline

User Scenario

  1. Create Travel
    • 사용자가 입력한 travel item이 TravelBlock 테이블에 저장
    • TravelBlock에 저장된 정보의 id로 여행계획 정보를 구성하고 이 정보와 등록 시간을 TravelCommit 테이블에 저장
    • 현재 여행 정보를 담은 TravelCommit id와 제목을 Travel 모델에 저장
    • 만약 TravelDetail등 페이지를 통해 Travel 관련 정보를 사용자가 요청할 경우 Travel, TravelCommit 테이블을 조인해서 여행정보를 얻고 각 travel item을 다시 TravelBlock select해서 서빙
  2. Edit Travel
    • Create Travel과 비슷하지만 만약 사용자가 수정하지 않은 Travel Item이 있다면 그대로 id를 두어야 한다(나중 conflict 대비).
    • 새로 Item을 추가하거나 수정한 Item은 id를 새로 부여하고 이를 묶어 다시 TravelCommit 테이블에 삽입
    • Edit의 경우 Commit이 달라진 전후 관계를 TravelCommitLog 테이블에 저장한다. 이는 이후 공동작업의 commit 트리 구조 유지를 위한 작업.
  3. Fork Travel
    • 사용자가 fork를 요청할 경우 travel 정보를 다시 저장할 이유가 없다.
    • 이때 다른 테이블은 그대로 유지하고 Travel에만 삽입하는데 이때 head를 original repo의 head와 같게 설정한다.
    • 만약 fork한 사용자가 수정할 경우 travel은 다른 분기를 가진 tree를 갖게 된다.
  4. Merge Travel1 - conflict 없을 때
    • 사용자가 fork를 받고 그 사용자가 collaborator인 경우 merge를 요청할 수 있다.
    • 만약 원래 repo에 수정사항이 없고 fork한 사용자가 여행정보를 수정했을 경우 merge 가능하다.
    • 충돌여부 확인은 어떻게?
      • travel id를 통해 TravelCommitLog 테이블에 있는 모든 commit을 select
      • parent commit 정보를 통해 백엔드에서 tree build
      • 만약 fork한 commit의 parent 경로중에 원래 repo commit이 없으면 충돌
    • merge하면 TravelCommitLog에 머지 정보를 입력
    • 원래 repo가 merge되었으니Travel에도 HEAD를 머지한 레포로 수정
  5. Merge Travel2 - 충돌
    • 만약 충돌이 감지 되었을 경우 사용자는 충돌을 해결해야 한다.
    • 백엔드에서는 충돌된 두 commit 정보를 모두 프론트로 전달
    • 두 TravelCommit 중 같은 TravelBlock을 제외한 모든 Item은 선택 대상이다.
    • ex) TravelCommit1: [1, 2, 3, 4, 5, 7], TravelCommit2: [1, 2, 3, 4, 6, 7] 인 경우 5, 6이 충돌된 경우고 사용자는 모두 수정할 필요 없이 5, 6 TravelBlock 중 하나를 선택한다.
    • 사용자가 선택 후 저장할 때는 새로 TravelCommit, TravelCommitLog에 저장하고 Travel에 HEAD 정보 업데이트
    • 충돌 TravelBlock 중 적용할 블럭 선택하는 UI 추가 필요

PS1. Git의 경우 모든 변경 로그를 sha1 hashkey로 저장합니다. 저도 구상하면서 hash key로 저장하려고 하다가 현재 시스템에서는 우리 백엔드에서만 정보가 다루어지기 때문에 고유 아이디로 바꿨는데 이 부분 이야기가 필요할 것 같습니다. 현재 hash가 필요한 부분은 travel 전체에 대한 정보, travelblock에 대한 정보 2가지 입니다. PS2. 현재 repo가 여러 사람에 의해 변경될 경우 전체 레포 commit은 트리 구조를 가지게 됩니다. 이를 mysql에 저장하려고 생각해보니 애매해서 위와 같은 TravelCommitLog 테이블을 만들게 되었습니다. 각 tuple은 parent node만을 저장하고 있는데 혹시 효율적으로 이를 저장할 다른 방법이 있으면 수정해도 좋을 것 같습니다.

jang1suh commented 4 years ago

하던 작업이 길어져서 확인이 늦었네요 :crying_cat_face: 내일 더 자세히 읽고 코멘트 또 달겠습니다. 일단 생각나는 것만 몇 가지 적어두면 1) 저는 솔직히 깃허브에서처럼 commit log가 남고 merge하는 기능까지 생각하진 않았고, fork도 그냥 게시물 복사해서 자기가 고칠 수 있도록 하는 것 정도로만 생각하고 있었습니다. 그런데 적어주신 기능들을 구현한다면 정말 좋을 것 같네요! 쉽진 않을 것 같긴 하지만요... 깃허브 생각하면서 읽으니까 어떤 식으로 작동할지 감은 잡히는데, 내일 아침에 다시 제대로 이해해 보겠습니다!

2) 다시 정리가 필요하겠지만 제가 현재까지 UI를 짜면서 사용했던 travel model의 field 중 적어주신 글에 명시되지 않은 것들은

summary: 여행의 전체적인 느낌을 서술한 짧은 글. 미리보기 블록에서 노출됨.
period: 전체 여행의 기간
likes: 받은 추천 수
photo: 여행의 대표 사진
is_public: public repo인지 private repo인지
allow_comment: 댓글을 허용할지 허용하지 않을지
collaborator: 여행 수정 권한이 있는 공동 작업자들

가 있습니다. 여기에 태그도 추가되어야 할 거고요. ER diagram엔 collaborator가 다른 model로 구분되어 있지만 일단 적었습니다. 이 필드들도 어디에 넣어야 할지 정해야 할 것 같네요.

3) Fork - Merge가 가능하도록 한다면, merge 권한이 누구에게 부여되는지도 중요할 것 같습니다. Original repo를 소유하고 있는 author와 collaborators만이 merge를 허용하도록 하는 게 좋을 것 같은데, 이렇게 되면 차라리 collaborator 개념을 없애고 깃허브처럼 여러 user들이 공동 author가 되는 방식을 써도 괜찮지 않을까 싶습니다.

jangdonghae commented 4 years ago

엄청 좋은 아이디어들이 많네요.

  1. commit과 merge의 아이디어는 매우 좋지만 version control에 익숙하지 않은 유저들도 쉽게 사용할 수 있게 하는 방향도 좋은 것 같아요.
  2. commitlog를 이용해서 트리 구조를 구현하는 건 매우 좋은 것 같아요!
deploy-soon commented 4 years ago
  1. 네 이전에 같이 말했던 것처럼 저도 clone까지 기능구현하면 좋겠다고 생각했었는데 이번 피드백 보면서 merge기능이 필요해보여 위와 같이 생각하게 되었습니다.
  2. 네 저도 travel에 들어갈 사진, private 정보 등 넣어야 할 정보가 많은 것 같다고 생각했는데 적어주신 부분도 백엔드 개발할 때 반영해야 겠네요
  3. git 같은 경우는 공동으로 작업하여 프로젝트를 만들어낸다면 여행 계획은 보다 private한 느낌이 있다고 생각합니다. 처음 보는 사람이 git 프로젝트에 pr 올려 주는 건 감사한 일이지만 다른 사람이 내 여행 계획을 수정하려고 하는 건 정서에 맞지 않는 것 같아서요. collaborator만 merge 권한을 주는 것이 좋을 것 같습니다.

cc. @RXWE

deploy-soon commented 4 years ago
  1. 네 익숙하지 않은 fork같은 표현을 다른 단어로 바꾸거나 버튼에 hover를 만들어서 설명을 추가해야 할 것 같습니다. 또한 git에서 제공하는 모든 기능을 반영할 이유는 없어서 최대한 이용하기 쉽게 만들어야 할 것 같아요. command line에서 쓰는 부분을 모두 UI로 만들어야 할 것 같은데 예를 들어 pycharm에서 git conflict 생길 때 해결해주는 페이지처럼 쓰기 간편하게 개발하면 좋을 것 같습니다.
  2. 트리 구조는 백엔드 개발하면서 이슈 계속 공유하면 좋겠습니다 ㅎㅎ

cc. @jangdonghae

jang1suh commented 4 years ago
3. git 같은 경우는 공동으로 작업하여 프로젝트를 만들어낸다면 여행 계획은 보다 private한 느낌이 있다고 생각합니다. 처음 보는 사람이 git 프로젝트에 pr 올려 주는 건 감사한 일이지만 다른 사람이 내 여행 계획을 수정하려고 하는 건 정서에 맞지 않는 것 같아서요. collaborator만 merge 권한을 주는 것이 좋을 것 같습니다. 

생각해보니 그 지점에서 깃이랑 완전 다르겠네요. 그럼 어떤 사용자가 모르는 사람으로부터 fork해온 계획을 수정하고 원래 계획(source repo)에 merge 요청을 보내는 행동은 구현하지 않는 게 좋겠네요. 그러면 1) fork는 누구나 할 수 있지만 2) merge 요청과 확인은 collaborator만 가능한 게(또는 확인은 author만 가능하게) 되는 거겠죠? (쓰고 나니까 이미 user scenario 4에 적어두신 거네요:smile:)

그리고 충돌에 대해서도 조금만 더 확실히 해두면 좋을 것 같은데, 1) 깃처럼 다른 사람이 커밋한 것과 내가 커밋한 것이 겹치지만 않으면 통과되는 것이 아니라 내가 fork받아 온 후에 누군가 수정해서 반영(커밋)했으면 무조건 충돌이 발생하게 되는거죠? 2) 그리고 충돌을 처리하는 데 있어서 최종 결과물들(travel block)을 하나하나 비교해서 다른 게 있는 경우 둘 중 하나를 선택하도록 하는 수준에서만 resolve하는 게 맞나요? 3) commit의 시점은 사용자가 내용을 수정하고 저장할 때마다이고 그 때마다 TravelCommit, TravelCommitLog가 하나씩 생기는 게 맞죠? 4) commit 정보를 남긴다는 건 과거 상태로 되돌리는 기능도 지원하는 것으로 생각이 되는데, 과거 상태로 갔다 다시 현재 상태로 돌아오는 기능 구현도 고려하신 건가요? 만약 과거 상태로 돌아가서 수정하면 새로운 forked repo가 생기도록 구현해야 하는 걸까요?

개발하면서 같이 의논해야 할 사항들이라 더 이야기해봐야겠지만, @deploy-soon 님께서 구상하셨던 것이 무엇인지 알려주시면 이해하는 데 도움이 될 것 같습니다!ㅎㅎ

deploy-soon commented 4 years ago

생각해보니 그 지점에서 깃이랑 완전 다르겠네요. 그럼 어떤 사용자가 모르는 사람으로부터 fork해온 계획을 수정하고 원래 계획(source repo)에 merge 요청을 보내는 행동은 구현하지 않는 게 좋겠네요. 그러면 1) fork는 누구나 할 수 있지만 2) merge 요청과 확인은 collaborator만 가능한 게(또는 확인은 author만 가능하게) 되는 거겠죠? (쓰고 나니까 이미 user scenario 4에 적어두신 거네요😄)

네 마치 제 생각을 읽으신 것처럼 써주셨습니다. 그리고 충돌에 관해 말씀해주신 부분 기반으로 더 자세히 설명드리면

  1. 네 저는 이 부분을 생각할 때 하나의 travel을 git의 하나의 파일이라 생각했습니다. 만약 같은 파일에 동시에 복수의 누군가 수정하고 머지하면 충돌이 생기는데 이 부분을 반영하고 싶었습니다. 다만 원래 repo가 있고 내가 그 repo를 fork하고 수정한 뒤 merge 요청을 할 때 그 때까지 원래 travel owner가 수정을 하지 않았었다면 바로 merge되는 상황을 구상했습니다.
  2. 네 충돌일 경우 어떤 지점이 충돌인지 확인하는 방법을 생각해봤었는데요, 간단히 생각해봤던 거는 travel block을 시간 순서대로 읽어가며 id가 같은 부분을 기록하고 같은 부분 사이에 다른 travel block이 있으면 그 부분을 충돌 지점이라 생각했습니다. 충돌 지점을 어떻게 사용자에게 보여줄지는 더 이야기 해봐야할 것 같습니다.
  3. 맞습니다. TravelCommit 테이블은 여행의 snapshot이라 생각하시면 되겠고 TravelCommitLog 테이블은 snapshot을 시간순으로 이어준 relation이라 생각하시면 될 것 같습니다(트리 구조 유지를 위함). 여행 계획을 수정하는 경우 snapshot이 추가되는 것이기 때문에 TravelCommit이 추가될 것이고 기존에 있던 travel과 관계를 추가하기 위해 TravelCommitLog 데이터가 추가되는 것이라고 구상했습니다.
  4. commit 정보가 남아 있기 때문에 과거 자료도 확인할 수 있겠지만 과거 자료를 볼 일이 있을까 생각하여 돌아가는 기능은 생각하지 않았습니다. 다만 다른 커밋으로 돌아가는 기능을 구현할 경우 같은 travel 페이지에서 정보만 달라지게 해야할 것 같습니다.

덕분에 모델이 조금 더 구체화된 것 같습니다 😄 cc. @RXWE

jangdonghae commented 4 years ago

혹시 Travel edit을 할 때 기존에 있는 travel block을 고치면 다른 travel block id를 가지게 되나요? 예를 들면 들어주신 예시에서 TravelCommit1: [1, 2, 3, 4, 5, 7], TravelCommit2: [1, 2, 3, 4, 6, 7] 일 때 travel commit 2에서는 block 1이 수정된 상태라면 어떻게 되야할지 궁금하네요! 각각의 travel block도 commit log를 가지게 되는 걸까요?

deploy-soon commented 4 years ago

저도 생각하면서 그 부분이 정말 고민이었습니다. travel item 또한 시간에 따라 달라질 수 있기 때문에 commit log를 두어서 merge할 때 사용해야 하나 고민했는데요, 그렇게 되면 모델이 너무 복잡해서 수정하면 아예 다른 travel item으로 보도록 하려 했습니다. 예를 들어 말씀하신 것처럼 block 1이 수정되었을 경우 TravelCommit1: [1, 2, 3, 4, 5, 7], TravelCommit2: [8, 2, 3, 4, 6, 7] 이런식으로 다른 번호를 부여하도록 하려 했습니다. 이 부분이 관련해서 혹시 더 좋은 방법이 있을까요?

jangdonghae commented 4 years ago

git을 잘 모르지만 git은 그 부분을 최적화하기 위해 아마도 바뀐 부분만 저장하는 것 같은데, 그런 방법은 좀 구현하기 힘들 것 같아요

dreamsh19 commented 4 years ago

Travel Backend 아이디어 멋지네요 잘 읽었습니다 !

몇가지 궁금한 점이 있어서 올려봅니다.

  1. 사용자가 Edit travel 하고 confirm 하는 것과 merge하는 것이 다른 경우인건가요? 실제 git과 같은 version control에 익숙하지 않은 유저가 사용할 때 Edit-confirm이 결국 merge가 되도록 하는게 좋지 않을까요?

  2. Conflict를 체크할 때 TravelCommit의 content field에 있는 id 목록을 전부 비교하고 같은 걸 체크하는 건가요?

  3. 그럼 위와 같이 디자인했을 때 TravelCommit1 = [ 1,2,3,4] 에서 ---> TravelCommit2 = [5,2,3,4]로 바뀌었을 때 TravelCommit1과 TravelCommit2의 중복 블럭(2,3,4)도 같이 저장하도록 하는 방식으로 이해했는데 제대로 이해한게맞나요?

deploy-soon commented 4 years ago

사용자가 Edit travel 하고 confirm 하는 것과 merge하는 것이 다른 경우인건가요? 실제 git과 같은 version control에 익숙하지 않은 유저가 사용할 때 Edit-confirm이 결국 merge가 되도록 하는게 좋지 않을까요?

Edit-confirm이 어떤 의미인지 정확하진 않지만 저는 edit이 사용자가 자신의 travel을 수정하는 행위라고 생각했습니다. 사용자는 edit 버튼을 누르고 수정한 후 confirm을 누르면 수정된 자신의 travel을 확인할 수 있을 것입니다. 이 과정을 git으로 생각하자면 수정 사항을 add하고 commit message를 적은 뒤 commit하고 push까지 하는 행위로 생각할 수 있겠는데요, 사실 version control이 익숙하지 않은 사용자에 commit message까지 적는 것은 의미가 없다고 생각했습니다. 그래서 모든 과정은 백엔드에서 이루어지겠지만 사용자에게는 이 과정이 보일 필요가 없을 것이고요. 이러한 의미에서 edit-confirm은 merge와 비슷하지만 일반적인 merge와는 차이가 있다고 봅니다. merge는 내 repo head와 merge 대상 repo head가 어딘지 모를 때 일반적으로 두 레포를 합치는 것이라면 edit은 충돌이 일어날 것을 고려하지 않아도 되는 경우라고 봅니다. 다만 말씀하신 것이 사용자가 travel edit 버튼을 누르고 열심히 travel 내용을 수정중일 때 공교롭게 collaborator가 merge를 해서 현재 repo head가 바뀐 것이라면 edit 후 confirm에도 문제가 생길 수 있을 것 같습니다. 이때는 merge와 같이 충돌을 피할 수 있는 페이지로 가서 수정을 edit을 마무리할 수 있겠네요. 결과적으로 travel edit을 하게 될 때 merge와 같이 conflict를 체크하는 과정이 필요하긴 하지만 그렇다고 edit 버튼을 merge로 바꾸는 것은 더 이야기 해봐야할 것 같습니다. 사용자 입장에서 수정을 하고 싶은데 merge만 가능하다고 하면 서비스 사용중 의아해 할 것 같기도 해서요. 제가 말씀하신 부분을 잘 이해한 건지 모르겠습니다.. 😖

Conflict를 체크할 때 TravelCommit의 content field에 있는 id 목록을 전부 비교하고 같은 걸 체크하는 건가요?

네 그렇게 하려고 생각했습니다. commit에 diff를 저장하는 것도 좋을 것 같다고 말씀하셨던 것 같은데 그것도 좋을 것 같고 사실 어떤 방법이 좋을지는 모르겠습니다. 일단 어떤 commit id가 주어졌을 때 그 commit의 내용을 빠르게 확인 가능하기 위해 현재 TravelCommit의 content field를 위와 같이 구성했습니다.

그럼 위와 같이 디자인했을 때 TravelCommit1 = [ 1,2,3,4] 에서 ---> TravelCommit2 = [5,2,3,4]로 바뀌었을 때 TravelCommit1과 TravelCommit2의 중복 블럭(2,3,4)도 같이 저장하도록 하는 방식으로 이해했는데 제대로 이해한게맞나요?

네 맞습니당. 중복저장하는 overhead가 존재하긴 하지만 tree 전체를 mysql 디비에서 읽고 싶지 않아 그렇게 했습니다.

cc. @dreamsh19

jangdonghae commented 4 years ago

단순히 블록 순서를 바꾼 경우에 대해서도 고려하면 좋을 것 같네요! 중복 저장이 너무 많아질 수 있으니..

jangdonghae commented 4 years ago

제가 잘 이해를 못한 걸수도 있는데 edit-confirm와 merge가 다른 기능을 하도록 구현한다면 pull도 구현해야지 않을까요? 바뀐 사항을 모든 collaborator이 가지고 올 수 있어야 할 것 같아요 ㅎㅎ

jang1suh commented 4 years ago