-
Notifications
You must be signed in to change notification settings - Fork 0
✍ 주간 리뷰 및 회고
Mina Seo edited this page Dec 13, 2023
·
14 revisions
서민아
-
react
랑ts
잘 사용해보기!
-
styled-component
어떻게 사용하냐,, styled-component -
ts
랑tsx
뭐가 다른거지? ts, tsx 차이 -
git license
뭐사용하지? Git License
- 원하는 부분만 렌더링하려면 어떻게 하지? ➡️
useState
를 해당하는 최소 부분에만 넣기 버튼 클릭 시 다른 컴포넌트 호출
김찬우
- React 의 동작원리 Deep-Dive
- Three.js 로 3D 모델 렌더링 익숙해지기
- FE 인프라 설계
- 클라이언트 성능 개선 경험
- 타입스크립트 익숙해지기
- 상태 관리 라이브러리의 사용은 언제 해볼까 ?
- Socket.io 말고 추가로 CRDT 를 적용해볼 수 있을까? 아니면 우리 서비스에 Socket.io 로 실시간 채팅 말고 다른 기능을 적용해볼 수 는 없을까?
- 모델링 클릭 이벤트시 여러번 이벤트 발생 → 모델링의 문제
- 시야에서 3D 모델링이 보이지 않아도 onClick 이벤트 적용되는 문제 →
Raycaster.params.DepthTest
보는 시야에서 광선을 쏘아 해당 모델이 보이는지 판단
오승엽
- React랑 TS사용에 익숙해지기
- Threejs, WebGL에 대해 학습하기
- SPAs, CSR 학습
- 이번주는 기획이나 디자인 위주로 고민해서 많이 없긴 함
- 프로토타입을 만들어보면서 성능적으로 고민을 많이 함
- 여러 환경(성능)에서 테스트 해보는 방법 알아보기
- 3d object 몇개까지 될지도 테스트 해봐야할거같음
- raycaster 학습 필요
- 장식 클릭 시 메시지 열려야 함
- useFrame 사용시 컴포넌트가 unmount되기 전까지 계속 돌아감
- 이 부분이 성능에 영향을 얼마나 줄지 알 수 없음
- 성능상 문제 발생 시 R3F대신 Threejs직접 사용하거나 커스텀훅을 이용해야 할 것 같음
- git branch 꼬여서 힘들었는데 찬우쿤이 도와줬다..
최진수
- Nest.js 딥다이브 한번 날잡고 달려야 할 것 같다
- 도커 공부를 하고
- 페이스를 좀 더 높여야겠다
- 배포는 어떻게 할것인지
- 트래픽이 몰리면 어떻게 해결 할 것인지
- 서버에 대한 공격에는 어떻게 대응을 해야할지
- 어느부분을 프론트가 하고 백이 하는지
- 아직 까지는 없다
송현우
- 서버, 배포, 도커, db에 대해 제대로 학습하기
- 다수의 사용자를 관리해본 경험 갖기 (로드테스팅이라도 꼭 해보기)
- 서버 부하를 줄이는 개인적인 기술적 도전 해보기
- 서버..도커.. 그게 뭔데..
- 트래픽에 대한 고민
- security를 어떻게 촘촘히 짤지
- 아직 없다 !
서민아
- 쉽게 이해할 수 있는 코드 작성하기❗
- 링크 전송 시 미리보기 구현 어떻게 하지❓ meta tag
- 공통으로 사용되는 부분
component
화 - 라우터 처리
- 애니메이션 구현
-
forwards
사용하면 애니메이션 마지막 상태 유지
@keyframes fadeInUp { // 위로 투명해지며 올라가는 애니메이션 from { opacity: 1; transform: translate(0, 0); } to { opacity: 0; transform: translate(0, -100%); } } @keyframes fadeOutDown { // 아래로 투명해지며 내려가는 애니메이션 from { opacity: 1; transform: translate(0, 0); } to { opacity: 0; transform: translate3d(0, 100%, 0); // 3차원 좌표계 } }
-
- 깊은 depth url일 경우
public
파일들 불러올 수 없었음 ➡️ 경로 설정의 문제 pr
김찬우
- useEffect 딥다이브
- 애니메이션 효과를 좀 더 부드럽게 구현
- 재활용 하기 좋은 컴포넌트는 어떻게 설계하여야 할까?
- 애니메이션을 렌더링하는 브라우저의 성능은 어떻게 최적화 할 수 있을까
- three.js 의 카메라 포지션이 벡터 오브젝트 였는데 이걸 깊은 복사를 하지 않아 계속 값이 변경되는 오류가 있었다 → 최대한 깊은 복사를 지향하자..
- 레이 캐스팅시에 리턴되는 mesh 오브젝트와 scene 내의 오브젝트는 달랐다. 3d 모델의 경우 mesh 오브젝트가 다수 일수 있어 해당 모델의 mesh를 순회하며 이벤트를 걸어주었습니다.
오승엽
- React랑 TS사용에 익숙해지기
- R3F, useFrame…
-
모델파일을 불러와서 사용하는데 scale이나 position을 조절하는게 힘들었음
- 스케일계를 확인하고 규칙을 세움
-
주사율에 따른 rAF속도 차이 해결
- 처음에는 delta라는게 있는지 모르고 직전 프레임의 시간을 window.performance.now()로 저장해놨다가 구현하려고 코드를 작성하다가 delta라는 인자가 있는것을 알게되어서 쉽게 해결 할 수 있었음.
-
내장그래픽 or 모바일에서 성능 최적화
- s10 모바일에서 확인결과 gpu사용량이 99퍼센트가 된다고 함
- 외장그래픽이 없는 노트북에서 cpu사용량이 너무 많아지고 느려진다고 함
- snow를 지워보기도하고 애니메이션을 제거해보기도 했는데 고쳐지지 않음
- 유리 재질을 가진 모델파일이 문제인가 싶어서 빼봤는데 빨라짐
- blender에서 만들어온 재질이 gpu연산량이 많다고 생각함
- 연산량이 적지만 유리처럼 투명함을 나타낼 수 있는 재질을 찾음
- basicMaterial : opacity는 있었는데 유리처럼 빤딱빤딲 해지지를 않음
- standardMaterial : basic보단 연산량이 많은것 같지만 유리재질을 비슷하게 표현할 수 있었음
- 연산량이 적지만 유리처럼 투명함을 나타낼 수 있는 재질을 찾음
- material뿐만 아니라 useFrame을 각컴포넌트에서 가지고 있어서 생기는 문제가 아닐까 생각함
- 이것을 해결하기위해 manager라는 컴포넌트를 만들어서 useFrame을 관리하려고 했음
- useRef에 콜백을 담아서 manager의 useFrame에서 콜백을 실행시키는 방법으로 구현했었음
- uesRAF = useFrame으로 생각하면됨
- 해당방법으로 snow 100개상단에 부하를 걸어보고 manager에서도 부하를 걸어서 테스트를 해봤음
- 본인 데스크톱기준 snow에서 for문 30만정도 해주니 프레임드랍이 생김
- 같은 로직을 snow가아니라 RAFManager에 등록하니 프레임드랍 사라짐
- 애니메이션을 한곳에 등록해서 사용하는 방식이 효과는 있을 수 있으나 callback 추가 삭제를 구현하기가 힘들 수 있음
- 본 프로젝트에서는 3D object가 많아져도 200개가 안될것으로 예상되는데 애니메이션이 연산이 복잡한게아니라서 효과가 유의미하지 않을것으로 예상되어서 본 프로젝트에 적용시키지 않았음 → 나중에 문제생기면 다시 부활시킬수도..?
-
붕어빵 안팜
- 집중안될때 모델링하면서 쉬었음…
- 이번주 고민거리가 다 트러블 슈팅이라 위의 내용과 동일함
최진수
- 금요일날 진행했던 현황공유에서 다른 팀들의 진행상황을 보면서 더 분발해야겠다는 생각이 많이 들었습니다.
- 주말까지 nest 공부 끝내자
- 구현은 빨리빨리 하자
- 인프라를 처음 접해보아서 엄청난 난항을 겪었습니다. Nginx, 도커가 왜 필요한가, 어떻게 해야 안전할까 등 많은 것들을 생각하면서 서버 아키텍쳐를 생각해서 만들었지만 아직도 내가 만든것에 대한 믿음이 가지 않습니다.
- github actions를 이용할때 백엔드 서버에서 도커 컨테이너가 풀 되지 않았습니다. 이유를 알아보다가 백엔드 서버가 private subnet에 들어가있어서 외부와 통신이 안되고 있었습니다. 이 부분을 해결하기 위해서 NAT gateway를 생성해서 백엔드 서버와 연결해주어서 아웃바운드 연결만 열어 주었습니다.
- ssh bruteforce 공격을 받아서 어떻게 해결해줄까 고민하다 root ssh 액세스를 막아놓고 ssh 로그인용 유저를 새로 생성해주었습니다.
송현우
- 기획단계에서 서버 구성에 대해 감을 잡기
- FE입장에서 생각해서 API 명세서와 erd를 작성할 수 있도록 하기
- 개발과정을 정리하고 블로그 포스팅 시도하기
- 서버를 효율적으로 구성하는 법
- redis 활용하여 로그인 인증 관리 로직짜기
- test코드 짜기
- NAT Gateway연결
- 서버 설계
- REST API 설계
- TypeORM 세팅
서민아
- 코드 작성 전 로직 생각하기
- 나중에 틀 바꾸기는 너무 고생💦
- 팀원분들께 배우기🙇
- 배경음악 설정 어떻게 하지❓ 배경음악 설정
- 라우터 처리 시
query string
적용하기- 라우터 변경 없이 세부 정보 추가하기 query string url
-
usecontext
로 상태 관리하기 useContext 상태관리 -
100vh
기기마다 다른 문제 100vh 기기 문제
// 🚨ERROR🚨
import { useContext } from 'react';
import { PrevProvider } from './PrevProvider';
const Visit = () => {
const { view, setView } = useContext(PrevContext);
// Provider태그 밖에서 사용 ➡️ 변경감지 ❌
// useContext를 Provider태그 안 자식들에서 선언❗
return (
<MessageProvider>
<SnowGlobeCanvas back={setView} />
<VisitHeader />
{view ? <VisitButton /> : null} // setView 변경해도 view 변경❌
</MessageProvider>
);
};
export default Visit;
김찬우
- 스노우볼 줌 아웃 기능 구현
- 라우팅 연결
- 메타 태그에 대한 이해
- 라우팅의 기준과 좋은 라우팅 설계란
- 깊게 고민하지 않은채 라우팅을 설계하여 SPA 느낌의 서비스가 드러나기 힘든것 같다.
오승엽
- 스노우볼 방문페이지 구현
- axios로 api연동 해보기
- useContext사용해서 상태관리 해보기
- context type선언하고 초기화하는게 어려웠음
- 초기값을 undefined로 하고싶었는데 그러면 type에 ‘ | undefined ‘ 를 추가해야함
- 또한 undefined일때를 처리해주는 로직이 추가로 필요한 것 같음
- 초기값을 목데이터로 해서 진행했음
-
usecontext
로 상태 관리하기 useContext 상태관리 -
100vh
기기마다 다른 문제- 사파리에서 주소창때문에 문제가 발생했음
- 주소창을 합친 높이가 100vh라서 주소창 유무에따라 문제가 생김
- 100%사용하니 해결되긴됐는데 … 찝찝함…
최진수
- 배포에 시간을 조금 덜 들이고 이제 서비스와 비즈니스 로직에 더 집중할것이다.
- 다음주에 예외처리와 벨리데이션을 완벽하게 해내겠다!
- 여태까지 인프라 관련된 것들에 집중을 많이 했었습니다. 하지만 서버측의 코드를 조금 더 꼼꼼하고 정확하게 작성해야 될것같습니다. 서비스 로직과 비즈니스로직이 현재 많이 부족한느낌이 전체적으로 들고있습니다.
- 레디스에 리프레시 토큰을 담아서 엑세스 토큰이 만료 되었을때 갱신해주는 방식으로 바꿔야 할 것 같다.
- 모르고 sudo chown -R proxyuser /. 를 그냥 실행해버렸다가 sudo su 가 실행이 안돼서 고치려고 서버를 포맷시킬까 생각했지만 같은 BE팀원 송현우님이 리커버리 모드로 들어가서 sudo 를 복구해주엇다!
송현우
- 테스트코드까지 완성하자!!
- 프론트 백 연동하는 법 익히자
- jwt token 관리하기 → refresh token redis로?
- 테스트 코드 작성하기 → jest사용법 ㅜ
- 프론트 배포 어떻게..?
- 복구모드..
- 쿼리 최적화
- 서비스 로직 설계시 모듈 관계가 꼬여서 다시 작성하는 일이 생겼음 → 급할 수록 돌아가자 !! 미리 설계후 코딩하기
서민아
- 백과 API 통신 연결하기
- 쿠키 저장을 백에서 해주다니❗🍪
- 리팩토링,,,♻️
- 로그인 쿠키 어떻게 처리하지❓
- 백에서 쿠키를 넘겨줌 ➡️ 자동으로 쿠키 저장됨
-
axios
소통 시 쿠키 값 자동 전달로 구현
axios .get('/api/user', { withCredentials: true // axios 쿠키 값 전달 }) .then(res => { if (res.status === 200) { // 로직 구현 } }) .catch(err => { console.log(err); });
axios
.get('/api/user', {
headers: {
Authorization: `Bearer ${cookieToken}`
// 이렇게 쿠키 값 넘겨주지 않고 자동으로 전달되도록 설정하기
}
})
.then(res => {
if (res.status === 200) {
// 로직 구현
}
})
.catch(err => {
console.log(err);
});
-
vite
,typescript
,react
에서.env
사용하기
// .env
VITE_APP_COOKIE_TOKEN = ABCDE
// 홑 '' , 쌍 "" 따옴표로 감싸지 않기
// 줄 끝에 , ; 를 붙이지 않기
// 실제 사용법
const cookieToken = import.meta.env.VITE_APP_COOKIE_TOKEN;
김찬우
- 스노우볼 생성 페이지 구현
- axios 를 통한 Login 연동
커스텀 훅 useSnowball 을 만들고 싶은데 어떻게 해야 효율적으로 커스텀 훅을 사용 할 수 있을까.
- 로그인 연동시 쿠키값 접근 문제 → httpOnly 시 쿠키값을 클라이언트에서 접근할 수 없음 → axios 의 속성으로 해결
withCredentials
HTTP Ajax 요청시 사용하는 withCredentials 옵션의 의미
오승엽
- API 연동 해보기
- 스노우볼 생성 기능과 스노우볼 조회 <> 버튼등 구현해보기
- 리팩토링도 해보면서 중복코드를 뺀다던지 불필요한 렌더링을 막아보고싶음
- API 연동
- visit페이지에선 authorize가 필요 없어서 구현하기 괜찮았음
- login기능이 구현되어야 나머지 api를 연동할 수 있는데 로그인이 잘 안됨
- 로그인 api를 axios로 요청하는줄 알았는데 그냥 a태그 등으로 이동시켜주면 되는거였음…
- 로그인 성공하면 백에서 쿠키에 담아줌
- 해당 쿠키를 포함해서 axios요청을 보내서 api통신에 성공함
최진수
- 요번주에는 작성한 코드를 롤백을 많이 했다. 다음주는 시작전에 한번더 확인한후 진행해야 겠다.
- /api/snowball/:snowball_id/decoration api를 나누어야 할지 하나로 그냥 둬야 할지 고민이다.
- 인터셉터, 커스텀 데코레이터, 파이프 개념들이 헷갈려서 여러번 잘못된 것으로 작성했다가 지우기를 반복했다.
송현우
- 트랜잭션 잘 활용해보자
- 트랜잭션 범위를 어떻게 해야할까?
- 격리 수준은 어떻게 해야할까?
- 인터셉터와 파이프등을 도입하는 과정에서 불필요한 작업들이 많았던 것 같다
서민아
- 에러 디버깅🔥
- 리팩토링,,,♻️
-
import
시 다 다른 depth로 인한 복잡함-
alias
설정으로 절댓값처럼 불러오기 import with alias 및 proxy 설정
-
-
ThemeProvider
-
context
사용해서 속성 전달 가능
import styled, { ThemeProvider } from 'styled-components'; import { theme } from './utils'; const App = () => { return ( <> <ThemeProvider theme={theme}> // 자식 태그 내에서 theme 사용 가능 <Outer> <Song /> <BrowserRouter> <Routes> <Route path="/" element={<Intro />} /> </Routes> </BrowserRouter> </Outer> </ThemeProvider> </> ); };
import styled from 'styled-components'; const StyledBox = styled.div` background-color: ${props => props.theme.colors['--black-primary']}; // 다른 파일에서 사용할 때 props.theme으로 접근 가능 `;
-
-
~~.d.ts
파일 ➡️ definition으로, 타입스크립트를 위해서 정의-
ThemeProvider
랑 같은 단에styled.d.ts
파일 생성
import 'styled-components'; import theme from './utils/theme'; type ThemeType = typeof theme; declare module 'styled-components' { export interface DefaultTheme extends ThemeType {} }
-
- 너비가 정해져있고 글자가 넘을 경우,
white-space: normal
속성으로 자동 줄바꿈 지원
김찬우
- useContext 에 대한 딥다이브
- useState 에 대한 딥다이브
- createPortal , memo 에 대한 딥다이브
- useContext 의 provider의 value 로 useState 의 사용에 대한 고민
- useState 의 set 함수를 provider 에 넣어 사용하는것보단 커스텀 훅을 만들어 상태관리를 시도하자.
- react.memo 의 다양한 사용법 고민
- props 의
참조
가 변경되었을때에만 감지함. 객체나 배열 내부의 값이 변경된것이라면 감지하지 못한다.
- props 의
- createPortal 은 특정한 컴포넌트도 등록할수 있는지 고민
- useEffect 와 useRef 를 통해 원하는 컴포넌트에도 포탈을 만들어 하위 컴포넌트로 연결이 가능하다.
- 직접 만든 모달이나 메세지 컴포넌트를 감싸는
div
영역에 클릭 이벤트를 걸어주었는데, 내부 컴포넌트까지 이벤트가 감지됨 (이벤트 버블링) → 내부 컴포넌트를 pointer-event : none 으로 시도해 보았지만, 해당 과정은 내부 컴포넌트의 이벤트를 무시하고 여전히 뒤 영역이 클릭됨 → 내부 컴포넌트에Event.stopPropagation()
메서드를 적용하여 이벤트 버블링을 막음
오승엽
- API연동 완료함
- 스노우볼 생성부터 메시지 작성, 읽음처리 까지 다 구현
- 무수히 많은 버그.. 잡기
- useContext를 아직도 완벽히 이해하지 못한것 같았음
- 메시지 읽음처리 할때 메시지읽음 api호출 후 다시 메시지정보를 받아오는 api를 호출해서 업데이트 시켜줘야하나?
- 해당 방법은 메시지를 읽을때마다 요청을 보내는것이 효율적이지 못하다고 생각해서 메시지 읽음처리 api가 성공한다면 다시 데이터를 받아오지는 않고 이미 가지고있는 데이터를 직접 바꿔주었음
- 어차피 새로고침이나 페이지 이동시에는 다시 fetch해오기때문에 정상적인 플로우에서는 문제가 없을것 같음
- 해당 방법은 메시지를 읽을때마다 요청을 보내는것이 효율적이지 못하다고 생각해서 메시지 읽음처리 api가 성공한다면 다시 데이터를 받아오지는 않고 이미 가지고있는 데이터를 직접 바꿔주었음
- 메시지 읽음처리 해서 느낌표 없애줄때 산타가 다시 위에서 떨어지는 문제 발생!!
- 원래 canvas내부에서 message정보를 가지고 map을사용해서 장식들을 생성해줬음
- 그래서 메시지 정보가 바뀌면 캔버스전체가 리렌더링 되면서 메인장식이 다시 떨어짐
- map함수로 장식을 생성해주는 컴포넌트를 별도로 분리했음
- 원래 있던 context에서 스노우볼 정보와 메시지 리스트까지 전부 가지고있었는데 분리가 필요했음
- snowBallData Context와 messageList Context를 분리했음
- provider내부에 있는데 context값이 업데이트 되어도 리렌더링 시키고 싶지 않은 부분이 리렌더링 됨
- 해당 컴포넌트에서 provider의 context값을 가져와서 사용하지 않으면 리렌더링이 일어나지 않을 줄 알았음
- 근데 계속 리렌더링 되는거야….
- 그래서 props로 data를 넘겨주고 React.memo를 사용해서 이전 props값과 비교해서 다를때만 리렌더링 되도록 해서 해결함
- 원래 canvas내부에서 message정보를 가지고 map을사용해서 장식들을 생성해줬음
최진수
- 시간이 없어서 테스트코드 까지 작성은 못하지만 마지막주에 부하테스트를 하고 조정을 해보도록 하자
- 현재 서버 한대에 백엔드 서버 하나를 돌리고 있는데 어디까지 감당이 가능한지와 안되면 다중화 어떻게 할지
- jwt 엑세스 토큰과 리프레시 토큰 관리 로직들을 authService에 넣어줬다authGuard에서는 authService를 이용해서 access 토큰이 만기 되었으면 refresh 토큰을 검증하고 토큰의 payload를 이용해 access토큰을 재발급 해주는 방식으로 진행하였다. 이 부분에서 엑세스 토큰이 재발급 되지 않고 있어서 디버깅 하다보니 jwtService 모듈을 사용해 payload를 사인해주면 iat과 exp 가 들어간다. 이부분을 갖고 그대로 또 jwtService.sign을 해주면 exp가 벌써 포함되어있어 에러가 뜬다. 따라서 사인을 할 payload는 항상 iat과 exp가 없는지 확인해야한다.
송현우
- 부하테스트 경험하기
- 트랜잭션 설정에 따른 부하 정도
- 동시성 제어 테스트
- 트랜잭션을 처음 적용해보면서 오해가 있던 개념들에 대해 다시 바로잡았다