2주 프로젝트 다이어리 - sprint2

김수지·2020년 1월 21일
0

Dev Log

목록 보기
3/12

2 Weeks Project Diary

#Sprint2 - Day 3.
Javascript를 배우고 있습니다.
현재는 슬랙과 디스코드를 클론하는 2주 프로젝트 중입니다.


1. Sprint2

워킹 데이 10일짜리 프로젝트의 2번째 스프린트를 마쳤다. 첫번째 스프린트는 기획 및 기본 기능 구현까지 4일을 예상하였고, 두번째 스프린트는 기본적으로 기능하는 부분에 덧붙여서 부가적인 기능들을 구현하는 것으로 3일을 예상하였다.
실제는 어떠했나? 잠깐 되돌아 보면서 우여곡절을 풀어보겠다.

1. 소소한 버그 발견

  • 스프린트2에서는 스프린트 1에서 구현했던 기능들을 모두 합친 후에 기본적인 유저 생성, 메시지 생성, 실시간 메시지 보여주기 등을 구현했다. 그러던 과정에서 뭔가 소소한 버그가 발견되기 시작했다.
  • 예를 들어서 로그인을 했지만 페이지를 새로고침 할 때 app.js에서 가지고 있는 로그인 state 상태가 false로 틀어지는 경우나 내가 만든 워크스페이스가 다른 워크스페이스란에도 등록되는 등의 이슈였다.
  • 프론트 화면 상에는 소소한 버그 같아 보여 함께 프론트엔드를 맡은 동료와 디버깅에 들어갔다.
  • 로그인 상태 같은 것들은 localStorage나 세션에 저장하는 등의 방법을 찾았지만 그 외 이슈들은 component가 렌더됭 때 필요한 state를 상시 제공하지 못하는 부분들이 있었다.
  • react에서는 didcomponentmount 등 라이프사이클 패턴을 이용해서 비동기적 요청을 통해 페이지 내에 보여줄 값을 받아온다. 그런데 우리는 해당 이벤트에서(예를 들어서 생성 버튼 클릭을 했을 때) 비동기적 요청으로 rest api를 실행한 후 state를 업데이트 하는 방향으로 대부분 이벤트를 핸들링 했다.
  • 이러한 핸들링은 처음 예상했던 시나리오 [ "로그인 -> 워크스페이스 선택 -> 해당 워크스페이스로 이동 -> 메시지 남기기"] 에서는 제대로 작동했지만 예상치 못하게 페이지 자체를 새로고침한다거나 이전 페이지로 돌아가는 등의 이벤트는 렌더 전/후로 라이프사이클 함수에서 서버 등으로 비동기 요청을 하지 못해 렌더 자체에 문제가 생긴 것으로 보였다.

2. 소소하지 않았던 버그의 원인

  • 결국 작은 버그 같아 보였지만 컴포넌트에서 state관리를 하는 구조 상 문제가 있었다는 결론에 다다랐다.

  • 그럼 구조적으로는 무엇이 문제였을까? 다시 처음 구조로 돌아가서 가장 문제가 많이 발생했던 워크스페이스 리스트 페이지와 특정 워크스페이스 페이지 구조를 리뷰하게 되었다.

  • 최초 컴포넌트 구조 : image.png

  • 빨간색으로 표기한 2개의 상위 컴포넌트에서 앞서 말한 비동기 요청 구조나 렌더에 문제가 있었다는 점을 깨달았다.

  • 그리고 더불어서 잘못 짠 라우팅도 이 문제를 더 심각하게 만들고 있다는 사실을 깨달았다... 분명 라우팅은 지난 3일 간 이해한 것 같았는데 그렇지 않았나보다...ㅜㅜ

  • 스프린트2의 중간 지점 쯤 다시 살펴본 라우팅 및 props 구조: image.png

  • 홈에서의 이중라우팅 구조와 불명확한 비동기 요청/setState 시점이 가장 큰 문제였다. 홈(App)에서는 여러 페이지들을 준비해두고 라우팅을 해야 하는데 내가 맡은 프로젝트에서는 홈에서 렌더링 조건(현재 선택한 워크스페이스가 있는가 없는가)을 먼저 걸고 1)바로 해당 워크스페이스로 이동하게 하는 라우팅 구조와 2)그렇지 않을 경우 워크스페이스 리스트로 들어가는 이중 라우팅 구조를 구현했다... 아래 그림의 초록색이 1번째 라우팅이고 파란색이 2번째 라우팅이었다. image.png

  • 결국 스프린트2의 끝무렵 우리는 구조 리팩토링을 하기로 결정했다 ㅜㅜ

2. To-do와 회고

1. To-do : 보조창 렌더링

  • 구조 리팩토링 전에 맡았던 투두가 있다. 슬랙의 구조를 보면 가장 윗쪽에는 네비게이션바가 있고 좌측에는 사이드바 그리고 가운데는 메시지 영역이 있다. 이 때 멤버 리스트를 클릭한다거나, 메시지에 댓글을 클릭한다거나 유저 창을 열 때에는 우측에 보조창이 렌더되는 것을 볼 수 있다.image.png image.png
  • 나는 이 보조창 ui 제작과 렌더링 구현을 task로 진행했다.
  • 처음에는 css display로 구현해주면 되지 않을까 생각했는데, 어쨌거나 보조창이 뜨기 직전에는 사용자 액션(보통은 클릭 이벤트)이 있고 이를 기억해서 해당 기능을 보여야 했다.
  • 그래서 내가 선택한 방법은 state이 보조 창에서 다루는 3가지 정보를 담고 클릭 이벤트에서 해당 정보를 불러올 수 있을 때 보조창이 열리게 하는 방식이었다.
  • 아래처럼 코드를 짰는데 아직도 정석으로 렌더한 것은 아닌 것 같아... 차후에 이 방법이 맞는지 엔지니어분들에게 문의를 해보려 한다.
            <Col span={6} style={{ height: "100%" }}>
              {clickedMsg.length || createdReply ? (
                <Thread
                  currentWorkspace={currentWorkspace}
                  currentDisplay={currentDisplay}
                  clickedMsg={clickedMsg}
                  replies={replies}
                  makeNoReplyMessage={makeNoReplyMessage}
                  handleClickReply={handleClickReply}
                  handleReplyClose={handleReplyClose}
                  handleClickProfile={handleClickProfile}
                  handleClickMemberList={handleClickMemberList}
                  handleReply={reply => {
                    this.setState({
                      replies: this.state.replies.concat(reply),
                    });
                  }}
                />
              ) : filteredMembers ? (
                <MemberList
                  filteredMembers={filteredMembers}
                  handleClickProfile={handleClickProfile}
                  handleMemberListClose={handleMemberListClose}
                />
              ) : clickedUser ? (
                <UserProfile
                  clickedUser={clickedUser}
                  handleProfileClose={handleProfileClose}
                  // dm 생성 함수 부분도 나중에 props로 내리기
                />
              ) : (
                <Row></Row>
              )}
            </Col>
  • css까지 입힌 화면 image.png image.png image.png

2. To-do : 프론트 구조 리팩토링

  • 주요 방향: 구조 정리를 하면서 이중 라우팅 구조를 해결하고, state 업데이트를 위해 적절한 라이프사이클을 배치하는 것이었다.
  • 최상단 App.js에서 라우팅을 정리하고 -> 복잡한 컴포넌트들이 여러 개 달려 있는 컴포넌트는 컴포넌트들을 나르는 컴포넌트들로 재구조화 -> component did mount, component did update 등을 다시 정리하는 것이 계획이었다.
  • 결론적으로 구조 리팩토링은 쉽지 않았다 : 제일 문제가 되었던 app.js와 workspace.js의 컴포넌트 재구조화는 성공했지만, 초기에 셋팅해두었던 2중 라우팅을 완전히 대체하기는 어려웠다. 대신 새로고침 시 필요한 비동기적 요청이 이루어지도록 클래스형 컴포넌트들의 component did mount 메소드를 활용하도록 구조를 변경하였다.

3. 회고

  1. 어려움을 느꼈던 부분들
    • 깨달은 줄만 알았던 라우팅: 아직 모르는 것이었다. 기본적으로 spa 구조는 각 페이지가 존재하고 이를 라우트 해놓은 후에 페이지 안에 컴포넌트를 배치하는 식이다. 이 구조가 잘 구성이 되어 있어야 했는데 처음 [홈-특정워크스페이스 or 워크스페이스리스트]로 짠 구조가 정상적이지 않은 flow를 만든다는 걸 깨달았다.
    • 이미 state와 props를 구현한 상태에서 [홈-워크스페이스-특정워크스페이스 구조]로 재구조화 하는 것 또한 쉽지 않았다.
    • 새로고침 이슈 : 유저가 새로고침이나 뒤로가기 등의 액션을 할 때에도 정상적 페이지 렌더링을 하는 것이 어려웠다.
  2. 극복을 위한 노력들
    • 리액트 라우터의 히스토리 객체 사용: 특정 워크스페이스의 URL은 “/main/6자리코드”로 구성했다. 이 페이지가 사실상 서비스에서 가장 nested 되어 있는 곳이었다. 이 때 새로고침 시 유저가 선택했던 페이지 정보를 렌더하기 위해서 URL의 6자리코드를 키로 받아오는 방법을 찾았다. 리액트 라우터에서 히스토리라는 객체에 주소를 담고 있어서 이 부분을 발췌하여 페이지가 새롭게 렌더된 후 componentDidMount 부분에 해당 값을 state에 저장시키는 시도를 했다.
    • 현재 구조 정리하고 리팩토링 방향 정하기: 어디가 문제인지 잘 모를 때는 현재 모습을 그려서 문제 파악을 하는 것이 가장 좋은 것 같다. 첫 프로젝트니까 열심히 만들어보고 싶은 마음에 버그를 잡고 그로 인해 발생하는 또 다른 버그를 잡는 패턴에 계속 빠졌는데, 이것보다 구조를 먼저 그렸다면 진짜 문제를 더 빨리 찾아낼 수 있지 않았을까 싶다. 실제로 다이어그램으로 라우트와 컴포넌트 관계를 그리고 나서 무엇이 문제인지 깨닫는게 되었다.
    • 대안 찾기! 훅스 or 리덕스 : 처음 프로젝트 시작 시에 리덕스가 필요할까?의 질문으로 일단은 리액트로만!!을 외쳤던 몇일 전의 내가 떠올랐다. 클로닝 범위가 넓지 않아서 별도 storage 개념이 필요하지 않을 것 같았는데, 막상 시작하니 state 관리는 쉽지 않다. 컴포넌트가 쪼개질 수록 nested 관계가 많아질 수록 더 어렵다. 그래서 나는 2주 프로젝트를 마치고 설에 리액트 훅스나 리덕스를 팔 생각이다.
  3. 배움
    • 구조의 중요성: 구조는 백 번 생각해도 중요하다. 클로닝이라 해서 '다 알잖아'라고 생각하지 말고, 구조 설계에 더 많은 노력을 쏟아야겠다.
    • 팀원들과 단계별로 코드 이해하기: 코드 리뷰를 하긴 했지만, 리뷰를 할 때도 함수로 인해 어디가 영향을 받는지, 어떤 플로우가 실행되는지 등을 단계적으로 공유해야겠다. 버그 발생 시 연달아 영향을 받는 범위를 한꺼번에 설명하려 하니 말하는 나도, 듣는 동료들도 이해가 쉽지 않았다. 먼저 팀원들 간 구조를 익힌 후에는 내가 어디를 어떻게 이어두었는지 단계별로 팀원들과 이해하고 블록을 쌓아가는 식으로 프로젝트를 진행해야겠다.
profile
선한 변화와 사회적 가치를 만들고 싶은 체인지 메이커+개발자입니다.

0개의 댓글