유난한 도전을 꿈꾸는 당신을 위한 프레임워크, Moonshot
ㄴ moonshot thinking을 바탕으로 목표를 설정하는 이들
ㄴ objective를 설정하는 google의 기업 정신으로, 10%의 개선 보다는 10배의 혁신에 도전한다는 뜻
팀원 | 조연서 | 신수연 | 전언석 | 최준민 |
---|---|---|---|---|
팀원 소개 | ||||
역할 |
Add-OKR Preview-OKR Celebrate-Motion |
Dashboard - Drawer Dashboard - SideSheet Social |
Login(KaKao/Google) Nickname Modal Error |
History My |
역할 | 종류 |
---|---|
Library | |
Programming Language | |
Styling | |
Data Fetching | |
Formatting | |
Package Manager | |
Version Control |
"vite-plugin-svgr": "^4.2.0"
1️⃣ Commit 컨벤션
- 커밋 메시지 형식
[커밋메시지-소문자로]: 구현 기능설명
ex. feat: 회원 가입 기능 구현
- 커밋 메시지 종류
제목 | 내용 |
---|---|
init | 브랜치 첫 커밋 |
feat | 새로운 기능에 대한 커밋 |
fix | 버그 수정에 대한 커밋 |
build | 빌드 관련 파일 수정에 대한 커밋 |
chore | 그 외 자잘한 수정에 대한 커밋 |
docs | 문서 수정에 대한 커밋 |
style | style: 코드 스타일 혹은 포맷 등에 관한 커밋 |
refactor | 코드 리팩토링에 대한 커밋 |
2️⃣ Branch 전략
- 기본적으로
git flow
전략을 따른다. - 세부 브랜치 전략
- 브랜치 종류
main
: 우리가 최종 개발 시 Merge 하는 곳 → main 브랜치 보호 : 1명 이상 assign시에만 merge 가능하도록 막아두겠습니다develop
: 개발 중 merge하는 최상위 브랜치feat
: 기능을 개발하면서 각자가 사용할 브랜치- 페이지 단위로 구분해 사용한다. ex. feat/loginPage
- feat 브랜치 하위로 이슈에 따라 이슈 브랜치를 분기하여 사용한다.
hotfix
: 급한 수정사항 및 QA를 반영할 때 사용할 브랜치
- 브랜치 전략
- 다음 분기 규칙을 따른다.
feat/페이지명
: feature 브랜치 = 페이지 브랜치페이지명/#이슈번호/기능명
: 이슈 브랜치
// 분기 그래프 main ㄴ develop ㄴ feat/페이지명(camelCase) ㄴ 페이지명(camelCase)/#이슈번호/기능명(camelCase)
// 브랜치 전략 예시 main ㄴ develop ㄴfeat/loginPage //페이지 브랜치 ㄴloginPage/#1/kakaoOauth //이슈 브랜치
3️⃣ ISSUE & PR
- 최대한 작게 Issue 생성한다.
- Issue 먼저 다 생성 후 작업한다.
- 리뷰어를 위해 최대한 친절하게, 자세하게 작성한다.
- 트러블 슈팅 및 고민사항을 공유한다.
1️⃣ 폴더 구조
- 지역성에 따른 분리.
- 같은 페이지에 위치한 파일들끼리 한 폴더로 묶는다.
- 폴더명 === 파일명, 즉 페이지의 파일명은
index.tsx
로 짓는 것을 원칙으로 한다.
├── public 🗂 썸네일 이미지, 로고 이미지 저장
├── .eslintrc.cjs ✨ 린트 설정
├── .prettierrc.json ✨ 프리티어 설정
├── .stylelintrc.json ✨ 스타일린트 설정
├── package.json 📦 설치된 패키지를 관리하는 파일
└── src
├── App.tsx ✡️ 앱의 라우팅과 글로벌 스타일 지정
│
├── main.tsx
│
├── Router.tsx ✡️ 라우터 설정
│
├── common 🗂 공통으로 사용되는 파일들 저장
│ ├── apis 📂 (1) 공통 api 관련 파일들 저장
│ │
│ ├── assets 📂 (2) 공통 asset 파일 저장
│ ├── └──imgs 🖼 이미지 파일들 저장
│ └── └── svgs 🌁 svg 파일들 저장
│ │
│ ├── components 📂 (3) 공통 컴포넌트 관련 파일들 저장
│ │
│ ├── constants 📂 (4) 공통 상수 관련 파일들 저장
│ │
│ ├── hooks 📂 (5) 공통 hooks 관련 파일들 저장
│ │
│ ├── styles 📂 (6) 공통 style 관련 파일들 저장
│ ├── └── emotion.d.ts
│ ├── └── globalStyles.ts
│ ├── └── reset.ts
│ └── └── theme.ts
│ │
│ ├── type 📂 (7) 공통 type 관련 파일들 저장
│ │
│ └── utils 📂 (8) 공통 util 관련 파일들 저장
│
├── AddOkr 🗂 OKR 추가 페이지 관련 파일들 저장
│ ├── index.ts OKR 추가 페이지(AddOkr) 파일
│ └── //세부 폴더구조 common과 동일
│
├── DashBoard 🗂 대시보드 페이지 관련 파일들 저장
│ ├── index.ts 대시보드 페이지(Dashboard) 파일
│ └── //세부 폴더구조 common과 동일
│
├── History 🗂 히스토리 페이지 관련 파일들 저장
│ ├── index.ts 히스토리 페이지(History) 파일
│ └── //세부 폴더구조 common과 동일
│
├── Home 🗂 홈(온보딩) 페이지 관련 파일들 저장
│ ├── index.ts 홈 페이지(Home) 파일
│ └── //세부 폴더구조 common과 동일
│
├── My 🗂 마이 페이지 관련 파일들 저장
│ ├── index.ts 마이 페이지(My)
│ └── //세부 폴더구조 common과 동일
│
└── SignIn 🗂 로그인 페이지 관련 파일들 저장
│ ├── index.ts 로그인 페이지(SignIn) 파일
│ └── //세부 폴더구조 common과 동일
│
├── Social 🗂 소셜 페이지 관련 파일들 저장
│ ├── index.ts 소셜 페이지(Social)
│ └── //세부 폴더구조 common과 동일
│
2️⃣ 기타 컨벤션
구분 | 네이밍 규칙 |
---|---|
상수 | UPPER_CASE (모두 대문자) |
리액트 컴포넌트 파일 명 | PascalCase |
그 외(컴포넌트 x) 파일 명 (ex. 하위 폴더, 페이지) | camelCase |
폴더 명 = 파일 명 (page) | index 파일 생성 |
- 폴더/파일 네이밍 상세
// 페이지별 분리 폴더링 src ㄴ common // 공통 요소들 묶는 폴더 ㄴ components ㄴ util ㄴ constants ㄴ styles ㄴ assets // 공통 에셋 ㄴ images ㄴ icons ㄴ index.ts -> svgr 설정! ㄴ Login ㄴ index.tsx // 폴더명 = 파일명인 경우, 페이지만 (LoginPage) ㄴ components ㄴ loginBtn // 컴포넌트 내 하위 폴더 ㄴ LoginBigBtn.tsx // 컴포넌트 명만 파스칼 주의 ㄴ LoginSmallBtn.tsx ㄴ LoginHeader.tsx ㄴ api ㄴ hooks ㄴ useLoginModal.tsx ㄴ assets // 에셋도 페이지 별로 정리 ㄴ images ㄴ icons ㄴ index.ts -> svgr 설정! ㄴ Main ....
구분 | 네이밍 규칙 |
---|---|
컴포넌트 파일 작성 | rsc (rafce) 단축키 = 즉, 화살표 함수 |
내부 함수 | 화살표 함수 |
코드 작성 순서 | import → 컴포넌트 함수(화살표) → export → styled-component |
스타일드 컴포넌트 네이밍 | Container - Wrapper - Box |
인터페이스 네이밍 | Prefix : I / Postfix : Props (props인 경우) |
-
컴포넌트 파일 작성 상세
// 화살표 함수 rsc(rafce) import React from 'react'; const index = () => { return <div></div>; }; export default index; // 스타일드 컴포넌트 -> const StContainer= styled.main``,
-
스타일드 컴포넌트 네이밍 상세
- 감싸는 태그는 **
Conatiner - Wrapper - Box
의 네이밍 위계를 따른다.Container
: 하나 이상의 요소를 포괄하는 개체Wrapper
: 하나의 개체를 포함하는 개체
- 태그에 맞는 네이밍을 사용한다.
- button은
btn
으로 축약하여 사용한다.
- button은
- div가 4번 이상 중첩시 컴포넌트 분리를 검토한다.
- 감싸는 태그는 **
-
인터페이스 네이밍 상세
-
인터페이스 이름 작성 시 컴포넌트의 이름과 동일하게 작성 후 prefix와 postfix를 추가한다.
-
prefix:
I
, postfix:Props
(props인 경우에만) -
ex) MyComponent 컴포넌트의 props에 대한 인터페이스
interface IMyComponentProps { … }
-
이에 해당하지 않는 경우, 뒤에 Types를 붙인다
interface IJustTypes {} interface IMainPageProps extends IJustTypes {} export default function MainPage({ color, title }: IMainPageProps) {}
-
Props 받아오는 형식 :
{ props1, props2 } : Interfacea명
-
Props 등 객체나 배열로 받아오는 데이터는
구조분해할당
을 사용한다.
-
-
-
기타 함수 네이밍 상세
컴포넌트(PascalCase),변수명(CamelCase)
: 동사 -명사 중요한게 앞으로 오게 사용한다.- ex. UserImg, DeleteBtn, useInfo
- button은 : btn으로 축약하여 사용한다.
함수명
: 어떤 일을 하는지 명확히 묘사한다.get
: 어떤 값을 얻는 함수create
: 갖고 있는 변수를 활용, 새로운 값과 변수를 만듦check
: 함수 안의 로직을 확인. → 그외, 기능을 분명하게 드러내도록 네이밍
handler함수명
: handler naming →handle{Action명}{styled-component명}
- ex. handleClickCard
- 스타일링 라이브러리는 emotion을 사용한다.
- styled-component로, 컴포넌트 파일 내부에 선언하여 사용한다.
- st 객체로 묶지 않으며, 대안으로 styled-component 앞에는
‘St’ 키워드
를 붙인다.- ex.
StLoginWrapper
- ex.
css 속성
: stylelint의 autofix 된 속성 순서를 따른다.- 단, scpt로 생성하는 theme 객체 (font, props를 받는 조건부 스타일링 등)는 autofix가 먹히지 않으므로 최하단에 위치시키고, autofix시에는 주석 처리 후 처리한다.
단위
:rem
을 사용한다.- 보다 편리한 rem 사용을 위해 전역적으로
font-size: 62.5%
설정을 해주어 브라우저의 기본 폰트 크기를 10px로 바꾸고 작업한다. - 예외) border, border-radius**와 같이 반응형이 필요 없는 속성은 px 사용을 허용한다.
- 보다 편리한 rem 사용을 위해 전역적으로
- 선택자, 클래스 네임을 지양한다.
- 복잡한 스타일링은 반드시 styled-component로 선언하여 사용한다.
- 작은 규모의 스타일링은 선택자와 클래스네임이 아닌, css prop을 적극 활용한다.
-
변수 선언
: 변수를 선언할 때는 const 사용을 기본으로 한다. 단, 변수의 값이 바뀌는 경우 let을 사용한다. 두 가지 명령어가 모두 사용되는 경우 const 선언문을 먼저 그룹화하고 이후에 let 선언문을 그룹화한다.// good const goSportsTeam = true; const items = getItems(); let dragonball; let i; let length; let a = 1, b = 3; // bad // bad let a = 1; const b = 2; ```
-
if문 규칙
:
- 암시적 반환을 최대한 활용한다
(early return)
if someCondition { return } // do something if someOtherCondition { return } // do something if someOtherOtherCondition { return } // do something if someOtherOtherOtherCondition { return } // ...
- 동시에, if문에서 else, else-if 문의 사용을 최대한 지양한다.
- 삼항연산자를 주로 사용하거나, if문을 여러개로 early return 시켜 사용한다.
-
async-await (데이터 패칭)구문
:try & catch문
을 사용한다. -
구조분해할당
을 적극 이용하자. -
변수 등을 조합해서 문자열을 생성할 때는
무조건 리터럴
을 이용한다- X) var1 + “ “ + var2 - O) `${var1} ${var2}`
-
switch-case
사용시break를 강제
하자. case문 사이들끼리는 가독성을 위해 띄어주자 -
조건문은
삼중 등호 연산자
를 지향하자 -
for는 지양하고 forEach, map을 사용하자.
-
img태그
:alt
꼭꼭 넣어주기,띄어쓰기 지양
(문샷-웨비), 되도록한글
로. -
button 태그
에는type을 명시
합시다!<button type=”button”>버튼</button>
-
버튼, 헤더와 같이 common component에서는
children
적극 활용. -
props interface 속성
:- 컴포넌트에서 props로 전달받은 interface를 선언해줄때, 컴포넌트명+Props로 선언한다.
- Props가 2개 초과하면 따로 interface 생성하여 사용하고, 구조분해할당으로 props를 받는다.
ex. const Header = ({ color, text }: interface명) => {}
-
기본 값 argumnet 배치
: 기본값이 존재하는 argument는 parameter의 후방에 배치한다.// bad const func: (a?: number, b: number) => number = (a, b) => { return a + b; }; // good const func: (a: number, b?: number) => number = (a, b = 0) => { return a + b; };
-
함수 몸체가 하나의 식으로 구성된 경우 중괄호와 return문을 생략할 수 있다. 중괄호를 생략하지 않을 경우 return문을 포함시킨다.
const func = (a: number, b: number) => a + b; // ok interface IPow2 { (a: number): number; } const pow2: IPow2 = (a) => a * a; // ok
-
식이 여러 줄에 걸쳐있을 경우 가독성을 위해 소괄호로 감싸 사용한다.
// bad [1, 2, 3].map( (number) => 'As time went by, the string containing the ' + `${number} became much longer. So we needed to break it over multiple ` + 'lines.', ); // good [1, 2, 3].map( (number) => `As time went by, the string containing the ${number} became much ` + 'longer. So we needed to break it over multiple lines.', );
-
객체를 이용할 시 속성 단축 구문을 사용한다. 단, 선언의 시작 부분에 그룹화하여 작성한다.
const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { lukeSkywalker: lukeSkywalker, }; // good const obj = { lukeSkywalker, }; // bad const obj = { episodeOne: 1, twoJediWalkIntoACantina: 2, lukeSkywalker, episodeThree: 3, mayTheFourth: 4, anakinSkywalker, }; // good const obj = { lukeSkywalker, anakinSkywalker, episodeOne: 1, twoJediWalkIntoACantina: 2, episodeThree: 3, mayTheFourth: 4, };
-
한 줄에는 하나의 구문 만을 작성한다.
🤙 칸반보드 사용 규칙
-
효율적인 작업 관리를 위해 github Projects 중 Board Template을 사용한다.
Todo
: 작업 해야 할 태스크- 각자의 뷰에서 나올 수 있는 Issue들을 먼저 전부 생성한다.
- Issue는 가능한 작은 단위로 생성한다.
- 생성한 Issue들은 Projects의 Todo에 위치시킨다.
InProgress
: 작업 중인 태스크- 사전에 나눠 놓은 Issue 단위를 기준으로 작업을 하나씩 진행한다.
- 한 사람이 여러 개의 issue를 진행 하지 않는다. (한 Issue가 끝나고 PR을 올려야 다음 Issue 진행 가능)
- 한 Issue 단위의 작업이 끝나면 Pull Request를 올린다.
Review
: PR이 open 되어 리뷰를 기다리고 있는 태스크- PR에 리뷰어를 달고, 코드 리뷰를 받는다.
- 2명 이상 리뷰시 merge 가능하며, 리뷰 반영은 필수!
- 리뷰가 완료 되면 PR을 merge 시킨다.
Done
: PR이 merge 되어 close 된 태스크- PR은 각자 구현 중인 중간 페이지 브랜치(
feat/~
)로 merge 시킨다. → 필요 시 (ex. common 컴포넌트) 중간 페이지 브랜치를develop
에도 merge한다.. - close 된 PR은 Done 상태로 이동시킨다.
- PR은 각자 구현 중인 중간 페이지 브랜치(
BackLog
: 작업 중이었으나 작업을 중단하고, 추후 작업으로 미룬 태스크\- 작업을 시작 했으나 다른 작업을 먼저 진행 해야 하는 등 중단 후 추후 다시 진행 해야 하는 작업이 있을 때 사용한다.
-
작업(이슈)의 상태에 따라 칸반보드의 알맞은 field로 옮겨준다.
``` [Project 활용 예시] 이슈 생성 → Todo 브랜치 파서 작업 중 → InProgress PR 날린 후 → Review PR 닫힌 후 → Done 디자인 요청사항 기다리는 중이라 다른 작업을 먼저 수행할 때 → BackLog ```