📋 목차
🚩 기술 스택 🚩 코드 컨벤션📌 코딩스타일📌 네이밍 컨벤션📌 스타일 컴포넌트 컨벤션🚩 디렉터리 구조🚩 Git 컨벤션📌 Git Flow 브랜치 전략📌 커밋 컨벤션📌 ESLint 및 Prettier 설정 파일📌 PR 컨벤션📌 깃허브 이슈, 프로젝트 칸반보드└ 깃허브 이슈└ 프로젝트 칸반보드[부록] 팀 회의 내용
🚩 기술 스택
구분 | 기술 | 비고 |
번들러 | Vite | CRA vs Vite
- CRA는 무겁고 느린 단점이 있다.
- 가볍고 추후 배포 연계를 위해 가벼운 Vite를 선택했다. |
라이브러리 | React | ㅤ |
슈퍼셋 | TypeScript | - 동적 타입핑으로 일어날 수 있는 이슈를 막을 수 있다.
- 일관성 있는 코드를 작성할 수 있다.
- 미리 타입을 지정함으로서 코드 자동완성을 통해 개발 경험을 향상시킬 수 있다.
- 협업에 있어 팀원이 작성한 코드에 대한 이해도를 높여준다. |
라우터 | React-router | ㅤ |
스타일링 | styled-components, MUI | styled-components (결정) vs Emotion |
코드 포맷팅 | ESLint, prettier, husky | ㅤ |
배포 | Vercel | ㅤ |
API | axios | axios vs fetch
- axios interceptor 기능을 활용하면 에러 핸들링, 응답 처리를 한 번에 할 수 있다. |
서버 상태 관리 | React-query | ㅤ |
전역 상태 관리 | Zustand | - recoil에 비해 번들 사이즈가 작음, recoil은 업데이트 된 지 오래됨
- store와 action을 한 번에 관리할 수 있다. |
협업 툴 | Github, Slack, Gather, Discord, Notion, FigJam, Figma | 원활한 문서화 및 회의를 위해 목적에 따라 다른 협업 툴을 사용했다. |
🚩 코드 컨벤션
📌 코딩스타일
풀네임 사용 여부 | 축약형보다는 풀네임을 권장 |
길이 제한 | 4음절로 제한 |
컴포넌트 작성 순서 | styled-components > hook(상태) > 상수 > 변수 > 함수 > jsx |
JSDoc | 공통 컴포넌트, 함수 등 |
함수 형태 | 컴포넌트는 함수 선언식 export default function Component(){}
그 외 함수는 함수 표현식 export const Fn = () ⇒ {} |
📌 네이밍 컨벤션
분류 | 규칙 | 예시 |
상수 | SNAKE_CASE | const MAX_USERS = 10; |
변수 | camelCase | let userName = 'JohnDoe';
let isActive = true;
let hasLoggedIn = false; |
함수 | camelCase, 동사+명사 | const getUserProfile = () ⇒ { ... } |
이벤트 핸들러 | camelCase
컴포넌트에 props 넘겨줄 때는 on 접두사
이벤트 함수는 handle 접두사 | props -> onChangeHandler
func -> handleChange |
타입, 인터페이스 | - type : 유니언 타입, 유틸리티 타입
- interface : 타입 외 나머지
- 접미사 Props | interface AvatarProps {…}
type AvatarProps {…} |
타입 별칭 | - 접미사 Type | type ButtonType = …; |
인터페이스 | PascalCase | ㅤ |
컴포넌트 | PascalCase | Avatar |
📌 스타일 컴포넌트 컨벤션
- tsx 컴포넌트 파일에서 기본값 설정, 스타일 분기 처리
- 스타일 컴포넌트에서는 props를 사용하기만 하는 방식으로 props 및 theme은 상단에서 선언한 것을 재사용하기 위해 css 선택자로 묶어주기
export default function Button({ type = 'button', disabled = false, width = '13.3rem', height = '4.3rem', shape, ...props }: ButtonProps) { const theme = useTheme(); return ( <BaseButton type={type} disabled={disabled} $width={width} $height={height} $shape={shape || theme.shape.round} {...props} > {isLoading && <CircularProgress size={20} />} {!isLoading && children} </BaseButton> ); }
import styled, { css } from 'styled-components'; export const BaseButton = styled.button<StyledButtonProps>` ${({ $width, $height, theme, }) => css` width: ${$width}; height: ${$height}; // theme 사용 예시 border-radius: ${$theme.shape.round}; color: ${theme.color.black_primary}; `} `;
🚩 디렉터리 구조
AlgoBaro ├─ 📂 public // 파비콘 등 자료나 이미지 │ └─ favicon.ico └─ 📦 src ├─ 📂 assets ├─ 📂 components ├─ index.ts └─ 📂Common // 공용 컴포넌트 폴더 └─ 📂Avatar ├─ index.ts // 폴더 내 .tsx 파일이 하나일 경우 생략 ├─ Avatar.tsx └─ Avatar.style.ts ├─ 📂 constants ├─ 📂 hooks ├─ 📂 pages ├─ 📂 routes ├─ 📂 services ├─ 📂 auth └─ apiconfig.ts ├─ 📂 store ├─ 📂 styles ├─ 📂 types ├─ 📂 utils ├─ App.tsx └─ main.tsx ├─ .gitignore ├─ index.html └─ README.md
// component를 관리하는 index.ts 는 배럴 export 구문을 사용 // src/components/index.ts export { default as Modal } from './Modal';
# src/components/Avatar if) Avatar 폴더 내부에 추가적인 .tsx 파일이 있다 ? => index.tsx 파일을 생성해준다 else if) ( 폴더 내부에 추가적인 .tsx 파일이 없다 ? || 폴더 내부에 추가적인 .ts 파일이 있다 ? ) => index.tsx 파일 생성 X
🚩 Git 컨벤션
📌 Git Flow 브랜치 전략
main | 최종 배포용 |
dev | 개발 단계 |
release | release-{버전명}
• 백업 용도로 사용
시맨틱 버전으로 버전명 기술
◦ major.minor.patch // 주.부.수 |
feature | 이슈 생성 ⇒ feature/{이슈번호}-{핵심작업내용(파스칼케이스)}
ex) feature/#1-MainPage , feature/#2-LoginError
(fix, refactor 사용 여부는 프로젝트 중후반 추가 결정 )
핵심작업내용은 선택 사항, 이슈 내 2개 이상의 브랜치가 존재할 경우는 필수적으로 추가 작성 |
hotfix | main 브랜치에서 정말 사소한 수정들 위주로 사용 |
📌 커밋 컨벤션
# <타입>: <제목> 형식으로 작성하며 제목은 최대 50글자 정도로만 입력 # 제목을 아랫줄에 작성, 제목 끝에 마침표 금지, 무엇을 했는지 명확하게 작성 ################ # [✨feat]: 새로운 기능 추가 # [🐛fix]: 버그 수정 # [📝docs]: 문서 수정 # [♻️refactor]: 코드 리팩토링 (기능에 영향을 주지 않을 때) # [💄style]: 코드 포맷팅, 세미콜론 누락, 코드 변경이 없는 경우 # [🎨design]: CSS 등 사용자 UI 디자인 변경 # [🔨chore]: 빌드 부분 혹은 패키지 매니저 수정사항 # [🔥remove]: 파일을 삭제하는 작업만 수행하는 경우 # [🚚rename]: 파일 혹은 폴더명 수정하거나 옮기는 경우 # [💬comment]: 필요한 주석 추가 및 변경 ################
📌 ESLint 및 Prettier 설정 파일
.eslintrc.json
{ "env": { "browser": true, "es6": true, "node": true }, "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": "latest", "sourceType": "module", "project": ["tsconfig.json"], "createDefaultProgram": true }, "plugins": [ "react", "react-hooks", "react-refresh", "prettier", "unused-imports", "simple-import-sort" ], "extends": ["plugin:prettier/recommended"], "settings": { "react": { "version": "detect" } }, "rules": { "react/jsx-key": "error", "no-unreachable": "warn", "react-refresh/only-export-components": [ "warn", { "allowConstantExport": true } ], "no-unused-vars": "warn", "no-console": "warn", "unused-imports/no-unused-imports": "warn", "unused-imports/no-unused-vars": [ "warn", { "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" } ], "simple-import-sort/imports": "warn", "simple-import-sort/exports": "warn" }, "globals": { "React": "writable" } }
.prettierrc
{ "printWidth": 80, "tabWidth": 2, "useTabs": false, "semi": true, "singleAttributePerLine": true, "singleQuote": true, "trailingComma": "es5", "endOfLine": "auto", "bracketSameLine": false, "jsxBracketSameLine": false, "bracketSpacing": true, "arrowParens": "avoid" }
📌 PR 컨벤션
assignee
는 자기 자신,reviewer
는 전체 팀원
label
구분
예) Feat, Fix, Refactor, Docs 등
📌 깃허브 이슈, 프로젝트 칸반보드
└ 깃허브 이슈
이슈 생성 ~ PR 생성 ~ Merge 흐름
[사용방법]
- 이슈 생성 (템플릿은 PR 컨벤션과 동일)
- 우측 하단의 Development 항목의 create a branch 클릭
feature/#이슈번호-기능
규칙으로 브랜치 생성
- 해당 브랜치로 개발한 내용 push
# 브랜치 전환 방법 git fetch origin // 원격 저장소와 연동 git checkout -t origin/feature/#이슈번호-기능 // 해당 원격 브랜치를 로컬에 만들고 해당 브랜치로 이동
- PR 생성 (템플릿 이용)
- 코드 리뷰 후 1명 이상 approve 시 Merge
- 개발 중에는 dev 브랜치로 병합
└ 프로젝트 칸반보드
[사용방법]
- 레포의 [Project] 탭에서 칸반보드를 생성
- 이슈, PR 생성할 때마다 오른쪽의 Projects 항목에서 등록
- 이슈 Closed시에 자동으로 칸반보드도 Done 상태로 변경
[부록] 팀 회의 내용
기술스택
ESLint & Prettier
(내일까지 각자 조사해보기)
윤호팀 Eslint & Prettier- ESLint plugin
- eslint-plugin-import
- unused-import
- css 자동정렬
- eslint 커스텀화
ESLint
박수현
- simple-import-sort
- 저장 시 그룹에 맞게 import문을 자동 정렬 해줌
- 그룹: 외부 라이브러리/절대경로/상대경로 등..
- unused-imports
- 저장 시 사용하지 않는 import 코드 제거
배건호
{ // map과 같은 배열 내에서 key 값 사용하지 않을 시 에러 "react/jsx-key": "error", // 코드 블록의 return 문 이후로 작성되는 코드는 경고를 띄우게끔 "no-unreachable": "warn", }
신수영
- 논의: 스니펫
- 논의: 컴포넌트 방식
rules: { // React export 규칙 - airbnb "react-refresh/only-export-components": [ "warn", { allowConstantExport: true }, // 상수 컴포넌트 허용 ], "no-unused-vars": "warn", // 사용하지 않은 변수 경고, 프로덕션 코드 "no-console": "warn", // 디버깅용 콘솔 문 경고, 프로덕션 코드 },
Prettier
박수현
// 취향에 따라서 선택해서 사용하면 좋을거 같아요! { "printWidth": 80, "tabWidth": 2, "semi": true, "singleAttributePerLine": true, "singleQuote": true, "jsxSingleQuote": true, "trailingComma": "all", "endOfLine": "lf", }
배건호
{ "tabWidth": 2, "bracketSameLine": true, // 오른쪽 꺽쇠괄호(>)를 다음 줄에 혼자 놓지 않고 마지막 줄 끝에 놓음 "singleQuote": true, "endOfLine": "lf", // 파일 맨 아래줄에 자동 개행을 해줍니다. "trailingComma": "none", // 객체나 코드 맨 마지막에 , 를 나오지 않게끔 수정해 줍니다. // 스타일코드 컨벤션 추가 예정입니다~ // 아래는 import 순서 지정해주는 예시 $ npm install -D @trivago/prettier-plugin-sort-imports "plugins": ["@trivago/prettier-plugin-sort-imports"], "importOrder": [ "@storybook*", "@emotion*", "^react*", "^@*", "^[../]", "^[./]" ], // 위 예시의 순서대로 정렬되게 됩니다 "importOrderSeparation": false, // import 구문 사이에 공백이 들어갈지 유무입니다. "importOrderSortSpecifiers": true // true로 해줘야 설정한대로 정렬되어요! }


신수영
{ "printWidth": 80, // 한 줄 최대 길이, 길이 초과 시 줄 바꿈 (기본값: 80) "tabWidth": 2, // 탭 간격 (기본값: 2) "semi": true, // 세미콜론 (기본값: true) "singleQuote": false, // quote 스타일 (기본값: false) "trailingComma": "es5", // 객체 등 마지막에 붙이는 , 여부 (기본값: es5) "endOfLine": "auto" // os마다 다른 마지막 줄 통일 (기본값: lf) "useTabs": false, // tab 사용 여부 (기본값: false) "bracketSpacing": true, // 객체 리터럴({}) 사이에 공백 설정 (기본값: true) "arrowParens": "avoid", // 화살표 함수의 인자에 괄호 여부 (기본값: always) }
- preserve
const url = ("https://api.example.com/endpoint?param1=value1¶m2=value2&" "param3=value3")
- never
const url = "https://api.example.com/endpoint?param1=value1¶m2=value2¶m3=value3"
조익준
prettier
,eslint-config-prettier
패키지 설치
.prettierrc
파일 생성
- 옵션 작성
{ // 쌍따옴표 대신 홑따옴표 사용 "singleQuote": true, // 모든 구문 끝에 세미콜론 출력 "semi": true, // 탭 대신 공백으로 들여쓰기 "useTabs": false, // 들여쓰기 공백 수 "tabWidth": 2, // 가능하면 후행 쉼표 사용 "trailingComma": "all", // 줄 바꿈할 길이 "printWidth": 80, // 객체 괄호에 공백 삽입 "bracketSpacing": true, // 항상 화살표 함수의 매개 변수를 괄호로 감쌈 "arrowParens": "always", // OS에 따른 코드라인 끝 처리 방식 사용 "endOfLine": "auto" }
- eslint와 충돌 방지 추가
.eslintrc.js
파일에서 수정
extends: [{기존 eslint 스타일}, 'prettier'] // 순서 잘 지키기, prettier가 가장 마지막이어야 함.
프리티어 옵션
브랜치 전략
(각자 조사 및 정리)
윤호팀 FE 브랜치 전략박수현
- main (실제 배포용)
- dev (코드 합체용)
- 그 외 브랜치는 이슈별로 생성
- 브랜치명 규칙
- 커밋 컨벤션/#이슈번호
- 예: feat/#1
- 멘토님께서 슬래시(/)는 폴더 구조에서 많이 사용되기도 하고 에러가 발생할 수도 있어서 대시 또는 언더바를 권장한다고 말씀하셨다고 합니다..!
- 에러 발생 블로그
배건호
- main (실 배포용)
- hotfixes
- release branches (배포 전 최종 테스트)
- develop
- feature/ 주제 - 항목
- ex) 해당 스프린트 기간동안 공통 컴포넌트의 Spinner 컴포넌트를 만든다고 가정할 때 ⇒ feature/Common-Spinner
신수영
- git flow
- main
- feature
- develop
- release
- hotfix
- github flow : main, feature
- 이전 팀: main, dev, feature
- 시맨틱 버전(Semantic Versioning)
major.minor.patch // 주.부.수
조익준
- 2차 팀에서는 git-flow 전략에서 약간 변형해서 사용 release 브랜치 미사용
상태 관리 라이브러리
(각자 조사 및 정리)
박수현
- Recoil
- 장점
- 러닝커브 낮음
- 자식 컴포넌트를 모두 리렌더링하는 Context API에 비해
- 구독된 컴포넌트만 렌더링하기 때문에 성능상 이점
- 단점: 업데이트 된지 오래 됨 (안정성 이슈)
- Zustand
- 장점
- 러닝커브 낮음
- recoil과 마찬가지로 성능상 이점
- recoil의 store와 action이 분리된 단점을 해결할 수 있음
- 단: 공부할 수 있는 최신 한글 자료가 많이 없다고 함
배건호
zustand, react-qeury
상태관리에 대한 공부도 좋지만, 추가적인 기능을 조금 더 만들어보는 것도 좋다고 생각합니다.
때문에 프로젝트에 대한 목적을 정하고 난 후 상태관리를 선택하는 것은 어떠실까요 ?
- Zustand vs Jotai 고민 중이심!
- Jotai
- 러닝커브 낮음
- bottom-top은 Jotai (Atomic)
- 장: 자유도 굳
- 단: 어디서든 변경될 수 있음
- top-bottom은 zustand (Flux)
신수영
- 공통점: TS 지원, 최적화
ㅤ | Redux-Toolkit(RTK) | Recoil | Zustand |
개발 | Dan Abramov | 페이스북 | 일본 개발자 jotai |
사용 기업 수
(codenary) | 105 | 27 | 5 |
특징 | - 점유율이 높다
- 액션으로 상태 변경→상태 쉽게 예측 가능, 유지보수 하기 좋다
- Redux Devtools 제공→디버깅이 편리하다 | - hook 기반
- Selector로 비동기 처리가 가능하다 | - redux 기반
- hook 기반
- Redux Devtools 제공 → 디버깅이 편리하다
- Provider가 필요 없다 → 불필요한 리렌더링 최소화 |
단점 | 러닝 커브가 높다 | - Devtool이 없어 디버깅이 불편하다
- 어느 컴포넌트에서라도 상태를 변경할 수 있기 때문에 추적이 어렵다 | - 최신 한글 자료가 많이 없다. |
추천 | - 비동기 상태 관리 tanstackQuery
- 새로고침 시 store state 증발→ redux-persist | - 클라이언트 데이터 상태 관리 추천
- 새로고침 시 store state 증발→ recoil-persist | ㅤ |
조익준
https://velog.io/@iberis/상태관리-라이브러리-비교-Redux-vs-Recoil-vs-Zustand-vs-Jotai
https://velog.io/@jaewoneee/번역-Zustand-vs-Redux

짧은 개발 기간(1달 반)을 생각했을 때 zustand나 recoil이 적합한 것 같고 업데이트를 생각해보면 zustand가 가장 최적이라고 생각이 듭니다…! redux도 꼭 알아야 하는거 같아요! 길게 잡고 공부를 해야 할 거 같습니다.
emotion vs styled components
Styled-Components (최종 결정)
신수영
styled-components vs Emotion
- 기능: 거의 유사
- 추세: styled-components가 우세
- 해외 사용률: stateofcss에 의하면 styled-components 50% emotion 21%
- 국내 사용 기업 수: codenary에 의하면 styled-components 156개 emotion 33개
- 성능: styled-components가 emotion에 비해 가볍고 빠르다고 하지만 거의 차이는 없다.
- 결론: 뭘 써도 상관없을 것 같다. 취업 용도 styled-components가 유리해 보인다.
조익준
https://80000coding.oopy.io/7ad296c7-8832-4951-9cf7-074a196d42ea
큰 차이는 없으나 label을 통한 emotion의 디버깅 지원 기능이 나름 괜찮은거 같다!
박수현
배건호
CSS 라이브러리
React Bootstrap, MUI, Ant Design 등
신수영
- 컴포넌트 단위 개발에 유용하다.
- 가장 인기와 성숙도가 높다.
- 예제가 많다.
- 완전한 커스텀 스타일링이 어렵다. | |
- 중국 프로덕트라서 동양적인 사이트에 어울린다.
- 어드민 페이지 개발에 유용하다. | |
- 컴포넌트 단위 개발에 유용하다.
- 디자인 변경 시 인라인 속성으로 css를 넣는다. 가상선택자는 사용할 수 없다.
- Slider가 없다. |
조익준


- 테일윈드를 사용하지 않기로 한 이상 MUI, Ant design, react-bootstrap은 다운로드 수로는 고만고만합니다.
- 대신 가장 업데이트가 활발히 되고 있는건 Ant design입니다.
- 가장 커뮤니티가 활발하고 안정성 있는 건 MUI입니다.
- MUI 나 Ant design 중에 선택하면 좋을 거 같습니다.
ㅤ | MUI | Ant Design |
장점 | - Google의 Material Design을 기반으로 풍부한 디자인 보유(안정성 갑)
- 컴포넌트의 일관성과 다양성, 문서화가 잘 되어 있음.
- 크고 활발한 커뮤니티에 따른 다양한 지원과 확장성 | - 최신 트렌드가 잘 적용되어 있음.
- 컴포넌트가 다양하고 광범위한 기능이 있음
- 중국꺼라 업데이트가 활발함 |
단점 | - 지나치게 디자인에 대한 일관성이나 제한이 있을 수 있음.
- 디자인 표준화에 대한 호불호가 갈림 | - 디자인이 중국스러울 수 있음
- 문서화가 좀 덜 되어 있음
- 커스터마이징이 힘들 수 있음 |
npm (최종 결정)
- 노드 버전 맞춰야 함
코드 컨벤션
조익준
- eslint와 prettier로 대략적인 코드 컨벤션은 완성이 된 거 같아서 함수명 및 변수명과 같은 네이밍 규칙과 같이 정하지 않은 부분들을 체크해보았습니다.
- 중첩 레벨 if문과 같은 조건문을 사용할 경우 몇 단계 중첩까지 허용할 것인지 결정 → return, continue를 이용해서 중첩 피하기 권장 코드 리뷰에서 즉각적으로 피드백 가능하기에 굳이 빡빡하게 정할 필요가 없을 수도 있음
- 함수의 위치 컴포넌트 파일에서 함수의 위치를 어디에 둘지?
수영, 수현: styled-components, hook(상태), 상수, 변수, 함수, jsx
// 화살표 함수 사용: 선언문이 항상 위에 있어야 함 // --- 헬퍼 함수 --- let 헬퍼함수에만 = 0; const setHandler = (elem) => { ... } const createElement = () => { ... } // 헬퍼 함수를 사용하는 코드 let elem = createElement(); setHandler(elem); walkAround();
- JSDoc 사용 복잡한 함수나 컴포넌트의 사용법 및 매개변수나 return 값들에 대한 타입들을 명시하기 좋아서 사용해보면 좋을 것 같습니다. 레퍼런스, 타입스크립트를 위한 JSDOC 레퍼런스, 공식문서
/** * @brief 전체 사용자 목록을 불러옵니다. * @details 디폴트 값은 offset = 0, limit = 10 입니다. * @params {number} offset - 현재 위치 * @params {number} limit - 불러올 최대 개수 * @return Promise<UserType[] | never> * 반드시 {} 중괄호 내부에 offset, limit 설정해야 합니다. */ export const getUsers = async ({ offset = 0, limit = 10, }: GetUserListRequestType): Promise<UserType[] | never> => { ... }; @brief : 간략하게 함수를 소개합니다. @details : 함수에 대해 상세하게 설명 합니다. 로직이 복잡한 경우 함수의 로직을 간단히 설명합니다. 해당 함수를 사용하며 주의 해야할 사항이 있다면 적어주는 것이 좋습니다. 매개변수와 리턴값에 대한 자세한 설명을 해도 좋습니다.
- 네이밍 컨벤션
- 변수명, 함수명 : carmelCase
최대 길이 및 함수명은
동사 + 명사
형태가 보편적 4음절 이상 ex) addButtonChangeHandler 동사에 대한 팀만의 규칙도 있으면 좋음. (ex. get, fetch 등) - 상수명: SNAKE_CASE, 구분은 언더스코어(
_
) 사용, I_AM_SHANGSOO - 컴포넌트명: PascalCase가 일반적
- 이벤트 함수 네이밍
prop -> onChangeHandler // 컴포넌트 넘겨줄 때
func -> handleChange // 이벤트 함수 연결
const handleChange = () => { } return( <Avatar onChange={handleChange} /> <Button onChange={handleButtonChange} /> <Input onChange={handle기능} /> ); return( <Child onChangeHandler={handleChange} /> )
interface props
interface AvatarProps { } export default Avatar(props: AvatarProps){ }
Styled components 규칙
import Styled from './Avatar.styled'; const Avatar = styled.div`~` export default Avatar(props: AvatarProps){ // 컴포넌트 return( <Styled.Avatar> <Styled.Title>...</Styled.Title> </Styled.Avatar> ) }
import { AvatarWrap, Title } from './Avatar.styled'; const AvatarWrap = styled.div`~` export default Avatar(props: AvatarProps){ // 컴포넌트 return( <AvatarWrap> <Title>...</Title> </AvatarWrap> ) }
신수영
- 축약형, 풀네임 여부 ex) btn, button
*길지만 모두가 아는 param의 경우 허용하는 방향
- 축약형은 레퍼런스 표 정리 필요하다는 의견
- TypeScript 타입, 인터페이스 용도 구분
- 타입 : 유니언 타입, 유틸리티 타입
- 인터페이스 : 나머지
type FruitsType = 'apple' | 'banana'; type FruitsType = string | number; // Omit과 같은 유틸리티 타입은 type을 사용해야 함 type FruitsType = Omit<BasketProps, 'count'>; interface BasketProps { fruits: FruitsType; count: number } const Basket = (props: BasketProps) => {...}
- 주석 삭제 방법 여부 → 멘토님 질문! ex) - feature 주석 삭제 후 dev merge할지 - PR 전 주석 삭제할지 - 나중에 dev에서 배포 전 일괄 삭제할지
이전 파일 구조
/public -> favicon, logo 등 이미지 /src │ /api | | /queries | /assets | /component | | /Login -> 고유한 컴포넌트 (단일 페이지 내에서 사용) | | /common -> 복수 페이지에서 사용, 다른 컴포넌트에서 사용되는 컴포넌트 | | | /Layout | | | /Navigator | | | /Post | | | | /modules | | | | | /PostPhotoBox | | | | | /index.ts | | | | /Post | | | | /index.ts | | | /Card | | | | /Card.styles.ts | | | | /Card.tsx | | | | /index.ts | | | /Header | | | /Button | /hooks | /constants | | /index.ts -> 길어지면 분기 | /pages | | /profilePage/Post | /types | | / index.ts | /utils -> 유틸리티 함수 | /styles | | /Theme.ts | | /GlobalStyle.ts
박수현
- 컴포넌트만 함수 선언식으로!
- 컴포넌트: 함수 선언식 export default function Main(){}
- 그 외 함수: 함수 표현식 export const Fn = () ⇒ {}
*스니펫 찾아보기
- src 경로 alias 설정 (tsconfig.json, vite 설정 필요)
- @/components ✅
- 상수 관리
- constants 폴더에 ts 파일 선언 후 사용
- 폴더구조
- src/constants/api.ts
API_ENDPOINT
BASE_URL
- 컴포넌트 및 페이지 작업 방식 (디렉토리)
- 컴포넌트 파일: 디렉토리이름.tsx
- styled 파일: 디렉토리이름.styled.ts
- index.tsx, styled.ts로 작업하면 디버깅 어려운 문제 😭
📦 src └── 📂 components (컴포넌트) └── 📂 Avatar . ├── Avatar.tsx (<- index.tsx: 컴포넌트 파일) └── Avatar.styled.ts (<- styled.ts: styled 파일)
배건호
분류 | 규칙 | 예시 |
상수 | UPPER_SNAKE_CASE | const MAX_USERS = 10; |
변수 | camelCase
boolean은 접두사 사용 | let userName = 'JohnDoe';
let isActive = true;
let hasLoggedIn = false; |
함수 | camelCase, 동사+명사 | const getUserProfile = () ⇒ { ... } |
이벤트 핸들러 | camelCase
handle+명사+동사
props는 on 사용 | 낙타의 경우
const handleButtonClick = () ⇒ { ... }
<button onClick={handleButtonClick}>Click me</button> |
컴포넌트 | PascalCase | const UserList = () ⇒ { ... } |
type 별칭 | Type 접미사 | type UserResponseType = ...
type ButtonClickType = ... |
interface | PascalCase | const IButton {} |
styled-component | ㅤ | ㅤ |
함수 인자 구조분해 | 규칙 없음 (모든 컨벤션 무시) | const createUser = ({ userName, userEmail }) ⇒ { ... } |
디렉터리 구조
- 조익준
- 디렉터리 구조 레퍼런스
Component 별 폴더를 생성할지?
ComponentName - index.tsx, style.ts, type.ts 와 같은 구조?
- 박수현
- Component 폴더 내부에서 관심사별로 폴더 생성하는 것 좋습니다!
- 컴포넌트에서 사용하게 되는 type은 주로 props일 것 같아서 type.ts 폴더 없이 index.tsx, style.ts 두 가지 파일만 가져가도 괜찮을 것 같아요!
- 그리고 익준님이 적어주신 폴더구조로 가는 것 동의합니닷
- 배건호
- type.ts의 경우 interface 갯수가 많아지면 별도의 파일에 분리하는 것이 좋아보입니다만, 크게 많아질 것 같진 않아 컴포넌트명.tsx 와 style.ts로 가면 좋을 것 같습니다.
- 신수영
- common 컴포넌트는 components/common 폴더
- 익준님 폴더구조 의견 동의합니다
- 파일/폴더 이름 Case
- 컴포넌트는 컴포넌트명과 동일하게 PascalCase.tsx 그 외 소문자.ts
PR 컨벤션
조익준
- assignee는 자기 자신, reviewer는 전체 팀원
- 제목 : 대표적인 작업으로 축약하여 한 줄 요약, 이슈번호까지 같이? ex. #1 초기 환경 설정, #17 메인 페이지 구현
- 설명: 구체적인 설명을 기술
- 주요 작업사항 및 변경사항 : 관련 커밋 링크 첨부해주면 좋을듯
- 레퍼런스 출처
<!-- 제목은 `[(키워드)] (작업한 내용) - (PR 순서)` 로 작성해 주세요 키워드 예시: feat/qa/sentry 등 --> ## 설명 ### 작업 티켓 or 동기 <!-- (Optional) 작성한 작업에 대한 티켓 번호나, 티켓이 없는 경우라면 작업을 왜 하게 되었는지 서술합니다. --> ### 스크린샷 <!-- (Optional) UI가 변경되었다면 사진이나 Gif를 추가해 주세요. --> ### 작업 내용 <!-- PR 본문을 입력하세요. --> ### 주안점 <!-- (Optional) 리뷰 시에 유심히 봐주었으면 하는 부분을 설명합니다. --> ## 연관 PR <!-- (Optional) 이 PR과 연관되어있는 다른 PR을 기입합니다. 예) - meshkorea/prime-api-client#15 : 연관된 API 변경점 --> ## 연관 티켓 <!-- (Optional) 이 PR과 연관되어있는 에픽 링크, 연관되어있는 QA 이슈 등을 기입합니다. 예) - 에픽 티켓: PP-9999 --> ## 체크리스트 - [ ] 무엇을 변경했는지 충분히 설명하고 있나요? - [ ] 새로운 기술을 사용했다면, 그 기술을 설명하고 있나요? - [ ] 이해하기 어려운 비즈니스 로직에 관해서 부연 설명을 하고 있나요? - [ ] 팀원 두명을 Assign하고, Review Request에는 web-front 팀을 추가했나요? - [ ] 작업을 설명하는 Jira 티켓을 추가했나요? - [ ] 작업 범위에 대해서 테스트를 작성하셨나요? - [ ] 인프라 작업, 릴리즈 PR이라면, Review Skip 레이블을 추가했나요?
배건호
- assignee는 자기 자신, reviewer는 전체 팀원, label도 같이
- PR 네이밍 : 맨 앞에 feat, fix, chore 등을 붙이고 #17 한줄요약?
## 개요 <!-- 작업 티켓 or 동기처럼 PR을 작성하게 된 계기에 대하여 기술할 수 있는 부분입니다. --> ## PR 유형 <!-- 팀원이 어떤 작업을 하였는지 쉽게 알아볼 수 있게 도와주는 부분입니다. --> [] 새로운 기능 추가 [] CSS 등 사용자 UI 디자인 변경 [] 코드 리팩토링 [] 파일 혹은 폴더명 수정/삭제 [] 기타 ## 주안점 <!-- 리뷰 시에 유심히 봐주었으면 하는 부분을 설명합니다. --> ## etc <!-- 작성한 내용 외 정보들을 기입할 수 있습니다. -->
박수현
- PR 템플릿 내용
- 기능 설명
- UI 구현 등 필요한 경우에 이미지 첨부
- 변경 사항
- 체크리스트
- PR 템플릿 규칙
- assignee는 본인, reviewer 팀원들 모두로 설정하기
- Label 만들어서 설정 (FEAT, FIX, DOCS 등)
- n명 이상 approve하면 머지 가능 (과반수인 2명으로 해볼까요?!)
신수영
PR규칙
- assignee, reviewer 설정
- Label : Feat, Fix, Refactor 등
- 2명 이상 approve하면 merge
merge는 2명 째에서 approve 하는 사람이 merge할지(저는 여기), merge 담당자를 따로 정하는 게 나을지
PR 템플릿
- PR 작성 시간을 고려하여 간략하게 설명, 작업내용, PR포인트 외 선택사항으로 두는 방안
## 설명 <!-- PR에 대한 설명입니다. --> 이 부분은 PR에 대한 설명입니다. ### 작업 내용 - 작업 내용입니다. - 작업 내용입니다. - 작업 내용입니다. ### 사용방법(선택) <!-- 공용 컴포넌트 작업 시 사용 방법을 알려줄 수 있습니다. --> ### 스크린샷(선택) <!-- 이해를 돕기 위한 스크린샷을 첨부할 수 있습니다. --> ## PR 포인트 <!-- PR 리뷰 시 공유 사항 또는 유심히 보면 좋을 부분을 설명합니다. -->
깃허브 이슈, 프로젝트 칸반보드 사용
박수현
Github 이슈
- 이슈도 PR 컨벤션이랑 동일한 내용으로 가져가면 작성할 때 편할 것 같아요!
- 이슈 생성 ~ PR 생성 ~ Merge 흐름
- 이슈 생성 (템플릿 이용)
- 우측 하단의 Development 항목의 create a branch 클릭
feature/#이슈번호-기능
규칙으로 브랜치 생성- 해당 브랜치로 개발한 내용 push
- PR 생성 (템플릿 이용)
- 코드 리뷰 후 n명 이상 approve 시 Merge
- 개발 중에는 dev 브랜치로 병합
# 브랜치 전환 방법 git fetch origin // 원격 저장소와 연동 git checkout -t origin/feature/#이슈번호-기능 // 해당 원격 브랜치를 로컬에 만들고 해당 브랜치로 이동
Github 칸반보드
- 레포의 Project 탭에서 칸반보드를 생성하면 됩니다!
- 이슈, PR 생성할 때마다 오른쪽의 Projects 항목에서 등록을 해주어야 하는 것으로 알고 있어요
- 생성할 때마다 자동으로 등록하게 하는 방법이 있을 것 같은데 저번에는 못찾고 그냥 진행했어유 ㅠ
- 한 번만 등록해주면 Closed시에 자동으로 칸반보드도 Done 상태로 변경됩니다