프로젝트 개발 종료 후 팀원들과 함께 회고를 진행하고 다음 리팩토링을 준비하고 있습니다.
Table
Search
문항
정윤호
김다슬
배준형
구현은 다 했지만 깊게 그리고 깔끔하게 구현을 하지 못한 아쉬움이 크다.
일단 생각했던 기능을 대부분 구현해냈다는 것에 대한 후련한 마음이 있다. 하지만, 다시 코드를 보면 중복되는 부분도 많고 리팩토링해야할 부분이 많아서 아쉬움이 남는다. 회고하면서 나오는 부분에 대해서 조금씩 리팩토링해나가야겠다.
이번 프로젝트를 진행한 것에서 개발 외적으로도 배운게 많았다. 감사하게 생각하고 있고, 나중에 있을 새로운 프로젝트에서는 지금 프로젝트에서 배운 것들을 기반으로 잘 진행해 나갈 수 있을 것 같다.
[기획]
다슬님의 재미있는 아이디어에서 깊게 고민하고 더 좋은 서비스를 만들기 위해 고민했다.
루틴이라는 개념을 도입을 루틴을 미션을 쪼개어서 타이머라는 장치로 메인을 잡는것에 준비를 했었다.
[디자인]
초반에 가장 많이 공을 들인것은 디자인 파트였다. 우리가 기획한 아이디어를 유저가 편하게 사용할 수 있도록 UX를 고민하고 반응형을 쉽게 구현하기 위해 체계를 잡았다.
또한 재상용가능한 컴포넌트로 분리하여 개발을 편하게 하기위해 고민을 많이 했었다.
[프론트엔드 개발]
유저 관련 페이 (회원가입, 로그인, 마이페이지)
커뮤니티페이지, 커뮤니티 디테일페이지
캘린더, 루틴 히스토리 페이지
로그인 여부에 따른 라우팅 처리
인스턴스와 인터셉터를 활용한 네트워크 요청 모듈화
Redux를 활용한 전역상태 관리
초반부에는 우리 프로젝트의 초기 아이디어를 기획했고, 젠허브 등의 협업 관련 툴 세팅을 했다.
초중반에는 피그마를 참고하여 페이지별 세부 기능을 명확히 정리했고, 팀원들과 우선순위를 부여했다.
중후반에는 Atom 컴포넌트부터 Page 컴포넌트까지 바텀업 방식으로 개발을 진행했다.
초반에 기획은 다슬님이, 디자인은 윤호님이 하셔서 그 외 남는 부분을 많이 가져가고 싶었다.
그래서 프로젝트 초기 세팅을 완벽하게 하고싶었으나 프로젝트 초기 세팅도 사실상 윤호님이 거의 다 한듯 하다.
개발 외적으로는 다슬, 윤호님의 도움을 많이 받았고, 개발 파트를 나누어서 개발이 시작됐을 때 담당한 부분의 개발을 열심히 하는 것 정도를 담당했다고 생각한다..
[프론트엔드 개발]
유저 관련 페이 (회원가입, 로그인, 마이페이지)
커뮤니티페이지, 커뮤니티 디테일페이지
캘린더, 루틴 히스토리 페이지
로그인 여부에 따른 라우팅 처리
인스턴스와 인터셉터를 활용한 네트워크 요청 모듈화
Redux를 활용한 전역상태 관리
크게 페이지로 분류하자면 루틴 생성과 수정, 미션 생성, 루틴 포스트 등록, 온보딩, 루틴 리뷰 모달 등을 구현했다.
마이 루틴 페이지
루틴 세부 페이지 - 드래그 & 드롭으로 순서 변경
루틴 진행 페이지 - 미션 시작, 미션 진행, 미션 스킵, 되돌아가기 등
캘린더 구현
이전까지는 캘린더가 필요할 때 라이브러리를 활요했다.
하지만 이번 프로젝트에서는 우리서비스에 핏이 맞는 캘린더가 없어서 직접 구현을 했었다.
라이브러리를 찾기 전까지만 해도 구현이 어려워 보일것 이라고 생각이 들었다.
항상 라이브러리를 사용했기 때문이다.
하지만 직접 구현해보니 의외로 간단했고 앞으로도 어려워만 보이던 구현을 장벽처럼 느끼지 않고 시도해볼수 있는 용기를 얻게 된 계기가 되지 않았나 생각이 든다.
루틴 리뷰 모달의 복수개 사진 업로드 및 미리보기 구현
1개의 사진 미리보기와 업로드 기능은 쉽게 구현이 가능했지만, 복수개를 미리보기해주고 그 상태에서 삭제까지 구현해내는 것이 어렵다고 생각했었다.
하지만 막상 해보니 사진의 url 리스트를 상태로 잘 관리하고, 이를 폼데이터 형태로 넘겨주기만하면 됐다. 이제 사진 관련 기능은 어떤 요구사항이 와도 잘 해결해낼 수 있을 것 같다. ㅎㅎ
[내가 하지 않은 것]
index 파일을 활용한 모듈 관리
axios로 인증이 필요한 요청, 필요하지 않은 요청을 나눠서 분야별 모듈화한 것
→ 두 가지 모두 기존의 내가 활용하고 있지 않았던 부분이다. 이전 프로젝트에서 axios를 모듈화하긴 했는데 요청별 모듈을 나누지 않아서 아쉽다는 피드백을 받았으나 이를 고치지는 않았고, 이번 프로젝트에서의 코드 모습이 정답처럼 다가와서 기억에 많이 남는다.
[내가 한 것]
루틴 진행 페이지 미션 진행 로직
→ setInterval, setState를 동시에 사용했을 때 원하는 대로 동작하지 않아서 시간이 오래 걸렸고, 의도하지 않은 동작(버그 등)이 많이 나올 것이라 생각했는데 생각보다 잘 동작해서 기억에 남는다.
- 간결하고 읽기 좋은 코드 작성하기
- 재사용성을 고려한 적절한 모듈 분리하기
- 깔끔하게리액트 훅 활용하기
- 불필요한 props 제거하기
이전 프로젝트에서 바텀업 방식으로 프로젝트를 한번 진행해보긴했지만, 프로젝트 규모도 더 커지고 컴포넌트 개수도 많아져서 props를 넘겨주고 상태를 관리하는 부분에서 고민이 많았다 .
작은 컴포넌트들이 모여 페이지를 구성할 때 어떤 Props를 넘겨주고 이 상태는 어느 컴포넌트에서 관리하면 좋을지 등이 가장 고민되는 부분이었다. 그래도 연습하면서 점차 나아졌다!
컴포넌트를 작성할 때 props의 형태
props를 통해 외부에서 상태를 받을지, 내부에서 상태를 업데이트 할지 등을 고민하는 시간이 많았다.
Redux
context, redux, recoil 등 많은 상태관리 라이브러리가 존재한다.
context는 이전 프로젝트에서 경험을 해보았고 recoil은 구현이 쉬워서 언제든지 도입할 수 있을것 같았다.
Redux는 보일러플레이트만으로도 코드량이 많고 구현이 복잡하다는 이야기를 들었지만 기업에서 많이 사용하기 때문에 관심이 생겼고 이번 프로젝트에 도입을 하면서 학습을 해야하는 장치로 동기부여를 갖고 학습을 해보고 싶었다.
하지만 확실히 코드량이 심각하게 많이 증가하고 어떤 장점이 있을까 고민을 많이 했다.
내가 생각하는 redux의 장점은
코드량은 많지만 명확한 코드 패턴이 존재한다. - 리듀서, 액션, 디스패치
이는 어느 누가 코드를 작성하더라도 패턴이 존재하기 때문에 일관성 있는 코드를 작성할 수 있다고 생각이 들었다.
또한 DevTool을 지원하여 상태의 변화를 추적하기 매우 용이했다.
하지만 무엇보다 단점은 코드량이 많아지다보니 능숙하지 않으면 오히려 개발에 해매기 쉽고 코드가 지저분해질 수 있다.
Styled-Components
React 프로젝트 2개 진행하면서 Styled-Components를 둘 다 썼지만 좋은 기술스택이라고 생각한다.
CSS in JS, CSS in CSS 둘 다 장단점이 있고, 특히 CSS in CSS를 사용했을 때 마크업 구조를 명확하게 알 수 있고, CSS 전처리기 등을 사용할 수 있어서 장점이 크다고 생각한다.
그럼에도 Styled-Components가 기억에 남는 건 props로 받아온 상태를 기반으로 바로 CSS 속성을 적용시킬 수 있는게 좋아서 기억에 남는다.
프로젝트에 크게 영향을 끼칠 정도는 아니지만, 개발하는 것이 편해졌고, Typescript랑 합쳐지면서 안정성도 높아졌다고 생각한다.
테스팅 - cypress, jest
이번 프로젝트는 규모가 어느정도 있던 프로젝트였는데 어떠한 테스트 도구도 사용하지 못해 아쉬움이 크다.
테스트를 하면서 개발을 했다면 사전에 버그를 미리 발견하여 더 효율적으로 개발을 할 수 있었을거라는 생각이 든다.
[성능 측정]
리팩토링을 하면서 코드를 개선하고 성능도 개선이 되었는지 명확하게 수치로 확인하고 싶은 욕구가 있었다. lighthouse와 리액트 프로파일러를 가끔씩 보면서 진행을 했는데 경험과 지식이 부족하다보니 성능이 개선되었는지 명확하게 이해하기 어려웠다.
우리 프로젝트에서 redux를 사용했지만 내가 구현하지않아 사실 나의 기술 스택이라 말할 수 없을 것 같다. 해당 기술 스택의 장단점을 몸소 느끼지못했고, 제대로 공부하지 않았다. 윤호님의 코드도 참고하고, context API 등과 비교해보며 직접 구현해보고싶다.
Next JS로 구성해보기
create-react-app 없이 webpack, babel 등을 직접 설정하면서 프로젝트 세팅하기
useState, useEffect, useRef 등의 기본 리액트 훅을 활용하면서 어느정도 능숙해졌다고 생각이 들었는데 가끔은 예상치 못하게 동작하던 경우가 있었다.
기억에 남는 점은 useState에 초기값은 항상 맨 처음에만 유효하다. prop으로 전달 받은 상태를 useState의 초기값으로 주는 방식으로 구현을 했었는데 분명 prop으로 다른 값을 넘겼는데 왜 동작을 안하지? 싶은 적이 있었다. 이런 useState의 성질을 새로 알게되었고 useEffect를 통해서 해결을 했다.
useRef도 헷갈렸던 적이 많다. 분명 dom을 지정했는데도 current에 null이 잡히적이 많았다.
이는 current는 dom이 렌더링되고 할당이 되는데 그전에 로직을 짜다 보니 발생했던 실수였다.
마지막으로 useCallback, useMemo를 많이 활용하지 못했다.
최적화를 하기위해 고민을 더 해봐야할 것 같다.
이전 프로젝트에서도 고생했던 useState와 useEffect를 생각만큼 잘 활용하지 못했던 것 같다.
상태 업데이트 시기나 의존성에 따른 리렌더링을 머릿속으로는 알고있는데 막상 코드로 짜니 useState의 비동기성을 놓치는 경우도 많았고, 의존성 배열에 잘못된 디펜던시를 넣은 경우도 많았다.
또한 useCallback과 useMemo을 이용한 최적화를 어느 부분에서 적용해야하는지 잘 감이 오지 않는다.
useMemo, React.memo, useCallback 등을 활용한 최적화가 어렵다.
실제로 프로젝트에 하나도 사용하지 못했다.
내 PC에선 최적화가 필요할 만큼 느리진 않았지만 해당 내용들에 대해 익숙해질 필요가 있다고 생각한다.
setState가 비동기로 동작하면서 의도한 대로 동작하지 않을 때가 가끔 있는데, 아직도 익숙하지 않다.
type vs interface 를 언제 구분해서 사용해야할지 아직도 100% 명확한 기준이 없다.
또한 타입을 어떻게 재사용할지 아직 경험이 부족한것 같다.
같은 로직에서 같은 내용의 데이터를 사용하는데 그때 마다 타입을 지정했던 적도 있다.
DOM과 이벤트에 관련된 타입 - React.ComponentProps(’div’) vs React.ButtonHTMLAttributes<HTMLButtonElement>
그리고 MouseEvent처리에 대해 아직 개념이 적립이 되지 않아 어떤것을 사용해야할지 해맨다.
타입가드 - 타입이 null이거나 undefined일때 깔끔하게 타입가드를 하는 방법에 대해서 더 고민을 해야할 것 같다.
에러가 뜰 때 경험이 없다보니 무슨에러인지 이해가 안될 때가 많았다.
자바스크립트로 개발할 때와 다르게 데이터의 구조와 타입을 명확히 설정하고 개발을 진행하는 것이 생각보다 어려웠다.
타입스크립트를 말로만 들었을 때는 진짜 편하겠다고 생각했는데, 머릿속에 데이터의 구조가 명확히 잡혀있지않으니 수많은 에러를 만났다.
시간에 쫓겨 개발을 하다보니 많은 에러들을 깊게 고민해보지않고 any로 설정해두거나, 중복되는 타입을 많이 선언해서 쓴 것 같다.
원시 값, 객체 등에 대해서는 익숙해졌는데, 그 외 모르는 타입들이 많아서 사용하기 어려웠다.
지금은 조금 익숙해졌지만 HTMLElement 타입을 사용하는 게 처음에는 어려웠다.
event.target으로 node에 접근해서 메서드를 사용하려는데 지정한 타입에는 없다 그러고 처음에는 그냥 any로 작성했던 기억이 난다.
라이브러리를 사용하면서 해당 라이브러리와 관련된 타입이 필요할 때 특히나 많이 헤매었다.
대표적으로
- mui 타입을 갖고올 때
- react-router-dom으로 라우팅 구현할 때, 등등
라이브러리 의존도를 줄여서 직접 구현하면서 고민하고 익숙해질때 라이브러리를 도입해야겠다. 생각이있다.
API 응답 에러처리를 사전에 처리하면 좋을것 같다 생각했는데 아직 감이 안잡혔다.
하루종일 고민하던 문제가 팀원들과 이야기하니 풀릴 때, 그리고 다음날 일어나니까 갑자기 아이디어가 떠올라서 해결될 때... 그 고민의 과정이 어려웠다. 하지만 그 과정이 있어서 해결의 기쁨도 있었던 것 같다.
루틴 리뷰 모달에서 이미지 등록 후 스크롤 이동 문제
사용자가 등록된 리뷰를 수정하고 제출하기 안누르고 취소할 때의 상태 관리
지금 와서 보니 프로젝트 구조를 더 깔끔하게 개선할 수 있을것 같다 생각이 들었다.
- 스토리북파일을 컴포넌트 폴더로
- 스타일드컴포넌트를 분리하기
- 상수 분리하기
- 타입 분리하기
- 재사용이 안되는 컴포넌트는 굳이 atomic으로 분리하지 않아도 된는점
컴포넌트의 로직을 커스텀 훅으로 적극 분리하지 않은점
- 훅으로 분리하여 재사용
- 컴포넌트 로직의 간결성
전역상태를 적극적으로 활용하지 못한점
- 전역상태가 꼭 전역에서만 사용하는 상태를 관리하는게 아닌 지협적으로 하나의 큰 컨포넌트에서도 활용할 수 있는데 이 부분에서 적극 도입하지 못한점이 아쉬웠다.
- 컴포넌트의 재상용성을 전역상태 관리로 해결하지 못한점
개발할 때도 느끼긴했지만 다시 보니 중복되는 코드가 너무 많다
백엔드 쪽에서 필터 처리, 응답 데이터를 구성해서 보내주다보니 API 개수도 많고 요청도 많다
예를 들면 루틴 상태에 미션 상태가 들어있다면 API 요청을 한번만 보내면 됐을 경우!
Atomic 디자인 패턴의 기준을 명확히 세우지 못한 것 같다
redux를 직접 작성해보지 않은 것
많은 것을 배웠지만 redux 관련된 내용은 거의 모른 채로 프로젝트가 끝났다.
위에 내용들을 개선해보고 싶다.
각 컴포넌트별 중복 코드 최대한 줄이기
동영님 중간 점검 object.freeze ⇒ const assertion 문법으로 변경
API 요청 횟수 줄이기
루틴 진행 페이지에서 1초 단위로 카운트하지 않고 1밀리초 단위로 카운트해서 시간을 구체적으로 표현하고 싶다.
만약 사용자가 00:00:00.000 에 시작해서 00:00:00.999에 끝내면 사실상 1초 가까지 진행했는데 표현되는 것은 0초로 표현돼서 이 부분이 아쉽다.
1. 서비스 로직에 대한 이해가 동기화 되지 않았을 때
프론트쪽에서는 이렇게 생각하는데 백엔드 쪽에서는 저렇게 생각할 때
데이터 스키마를 미리 작성해서 소통하여 이해도를 높이려고 노력했던 점이 기억에 남는다.
2. 소셜로그인에 대한 이해 차이
이전에 소셜로그인을 구현할 때 소셜로그인 API처리를 프론트에서만 해봤었다. 그리고 이번에도 프론트에서 해줘야하는게 아닌가 생각했는데 백엔드에서 처리하는 방식도 있었다.
프론트의 생각만 하는게 아니고 백엔드의 입장이 되어서 생각해야겠다라는 생각이 들었고
백엔드와 협업을 해서 어떤 구현을 하게 되면 프론트의 입장과 백엔드의 입장을 모두 고려하여 생각하고 서치하도록 태도를 바꾸게 되었다.
3. api요청이 너무 쪼개지거나 복잡해졌을 때
한가지 아쉬운점은 백엔드에서 api를 페이지 단위로 구현하려고 하다보니 하나의 네트워크 요청으로 충분히 커버할 수 있는 부분을 여러개로 쪼개진것 같다라는 아쉬움이 든다.
이부분은 내가 백엔드의 상황을 잘 몰라 함부로 이야기 할 수 없는 부분이지만 덩달아 프론트에서도 네트워크 요청이 복잡해져서 어려웠던 적이 있기 때문에 백엔드의 개념까지 알고 있어야 피드백을 드리거나 제안을 하여 더 간결하게 네트워크 요청처리를 할 수 있게 되고 좋은 서비스가 될 수 있을것 같다느 생각이 들었다.
같이 기능을 정하기보다는 프론트엔드쪽에서 피그마를 그린 후에 기능을 설명하는 형식으로 초반 회의가 진행되다보니 서로 이해하고 있는 부분이 달라서 힘들었다.
API의 요청과 응답 데이터 구조를 좀더 빠른 시기에 그리고 명확하게 설정했다면 계속해서 API를 수정하는 일이 줄었을 것 같다.
계속해서 이해도를 높이기 위해 소통을 많이 했고, 최대한 백엔드에서 원하는 부분 그리고 백엔드가 프론트에게 원하는 부분을 맞춰주기위해 노력했다. 그리고 데이터의 구조나 필드명을 확실히 정하기 위해 API설계서를 꼼꼼하게 작성했다.
프로젝트 초반 프론트, 백 각자가 어디까지 작성이 완료됐고, 어느 부분을 할 차례인지 명확하게 공유가 되지 않은 것 같다.
다음에 같은 방식으로 프로젝트가 진행된다면 프론트, 백 모두가 얘기해야 할 시간에 각자가 어떤 부분까지 완료됐는지를 명확하게 공유하는 시간을 초반부터 가져갔을 것 같다.
코드를 작성해 가면서 API 호출 응답을 어떻게 가면 좋을지 점점 뚜렷해지는데, 그런 과정 없이 이런 데이터들이 있으면 좋겠다 싶은 내용들로 구상하다 보니까 백엔드에게 전달한 응답 형태에 대한 신뢰도가 막 높지는 않았던 것 같다.
트러블 슈팅을 함께 깊게 했으면 더 좋은 시너지가 발휘되었을 것 같다.
하나의 문제를 제기하여 같이 끝까지 파고들면 금방 해결하고 학습도 배가 되었을것 같다.
개발하면서 문제가 발생하면 혼자서 고민하는것도 좋지만 바로 공유해서 같이 고민하면 서로에게 도움이 확실히 된다고 생각한다.
서로의 코드와 로직 소개하기
이슈 기반, 바텀업 방식으로 프롱이들과 협업하며 프로젝트를 진행했는데, 실무에서 또는 다른 방식으로의 협업도 경험해보고싶다.
다른 사람이 코드를 작성하는 것을 실시간으로 보면 좋을 것 같다.
코드에 대한 설명을 듣는 것 보다 작성해가는 과정을 보면 새로운 것을 배울 수 있을 것 같아서
타입스크립트 고민하기
axios를 활용하여 네트워크 요청 깔끔하고 편하게 사용하기
유저 정보관리 - 라우팅 처리 (redux)
가장 크게 배운 것은 구현에 대한 두려움이 사라졌다. 중간 프로젝트 시작 전만해도 내가 이걸 구현할 수 있을까? 어렵겠다라는 생각을 많이 했는데 최종 프로젝트가 끝난 이후에는 열심히하면 뭐든 구현할 수 있어라는 생각으로 바뀌어있었다.
그리고 개발적인 부분에서는 리액트, 타입스크립트를 어느정도 다를 수 있게 됐다.
또한 컴포넌트를 분리하는 방식이나 프로젝트의 구조를 정하는 부분도 많이 배우게 됐다
다른 사람의 코드를 보고 배울 수 있는게 많다는 것을 많이 느꼈다.
코드 리뷰를 통해서 개선해야될 점을 알려주고 싶은데 거의 배우기만 한 것 같다.
그리고 프로젝트 폴더 구조, 모듈 관리 등에 대해 많이 배운것 같다.
하나의 큰 요구사항의 컴포넌트 덩어리를 잡고 상태를 전역으로 관리하여 코드의 간결성과 가독성 올리기
컴포넌트의 로직을 훅으로 분리하기, 훅을 타입스크립트로 변경하기
중복되는 코드 줄이기, 필요없는 코드 없애기(기존 타입 재사용, useForm 이용)
이 프로젝트에 필요한지는 모르겠지만 코드 스플리팅? 을 해보면서 배우면 좋을 것 같다.
칭찬해주기!, 나 자신에게 잘한 점, 각 문항별로 작성한 내용에 피드백 주기
우리 잘한점은 안쓴 것 같네요..회고하다보니 고쳐야할 것들 반성만 늘어나네요ㅎㅎ
우선 머리속으로만 생각을 갖고 있던 내용들을 풀어서 작성해보니 명확하게 보여져서 회고를 잘했다는 생각이 들었다. 또한 팀원들에게 공유하고 팀워들의 생각을 들을수 있어서 더 생각이 풍부해질수 있었다.
그리고 내가 작성했던 내용들을 더 다듬고 예시를 들어서 글로 정리해보면 좋을것 같다는 생각이 들어서
다음 Try로는 이것으로 해보면 좋을것 같다.
회고를 안하고 계속 기능 추가를 하면서 프로젝트를 이어가니 뭔가 정리가 안된 기분이었는데 짧게나마 회고하고나니 생각 정리가 됐다. 그리고 그런 만큼 아쉬운 부분 고쳐 나가야할 부분이 많이 생긴 것 같다. 언제쯤 고칠 부분이 없어질까ㅎㅎ 그리고 마지막으로 팀원들 모두 열심히 달려와줘서 고맙다.
프로젝트에 너무 만족했는데도 아쉬운점이 하나씩 생각나는 건 오히려 좋은점이라고 생각이 든다. 이번 프로젝트 이후에 발전할 수 있는 방향을 알게된다고 생각하고, 더 성장할 수 있는 부분이 보여서 좋은 시간이었다.