-
Notifications
You must be signed in to change notification settings - Fork 5
[FE] 개발 문서
-
객체, 함수, 인스턴스의 이름은
camelCase
로 한다.// bad const haeng_dong = '행동대장'; // good const haengDong = '행동대장';
-
컴포넌트, 생성자, 클래스, 타입, 인터페이스명은
PascalCase
로 작성한다.// bad const userCard = () => { return <div /> } // good const UserCard = () => { return <div /> } // good interface Props { ... }
-
상수명은
UPPER_CASE
로 한다.// bad const lunchTime = '11시 30분'; // good const LUNCH_TIME = '11시 30분';
상수로 선언된 객체의 프로퍼티는
camelCase
로 작성한다.// bad const CAFE = { AMERICANO: 3800, LATTE: 5000, }; // good const CAFE = { americano: 3800, latte: 5000, };
-
이름에 축약어를 사용하지 않는다.
// bad const getBgColor = '#333333'; // good const getBackgroundColor = '#333333';
-
api 함수를 만들 때 http method를 접두사에 작성한다.
api 함수: 순수 api를 호출하는 함수를 말한다.
// bad const sendProfile = () => { ... } // bad const profilePost = () => { ... } // good const postProfile = () => { ... }
-
createHTML같은 기본으로 제공되는 webAPI의 경우는 카멜 케이스를 지키지 못하지만, 우리들이 자체적으로 HTML과 같은 이름을 네이밍에 넣을 경우 카멜 케이스를 사용한다.
// bad const ourHTML = // ...; // good const outHtml = // ...;
-
객체를 생성할 때 리터럴 구문을 사용한다.
// bad const obj = new Object(); // good const obj = {};
-
객체 프로퍼티가 2개 이상일 때는 개행한다.
// bad const obj = { a: 1, b: 2 }; // good const obj = { a: 1, b: 2, };
-
프로퍼티 값 단축형을 사용한다.
// bad const soha = 'soha'; // bad const crew = { soha: soha, }; // good const crew = { soha, };
-
객체 선언부에 단축형을 그룹화한다.
const soha = 'soha'; const todari = 'todari'; // bad const crews = { soha, cookie: '쿠키', todari, weadie: '웨디', }; // good const crews = { soha, todari, cookie: '쿠키', weadie: '웨디', };
-
객체의 프로퍼티를 새로운 변수에 할당할 경우 아래처럼 사용한다.
const {name: AName} = user;
-
항상 후행 쉼표를 붙인다.
// bad const crews = { soha, todari }; // good const crews = { soha, todari, };
-
콤마 다음 값이 올 경우 공백을 넣는다.
// bad const crews = ['todari','soha']; // good const crews = ['todari', 'soha'];
-
문자열은 기본적으로 single quotes 를 사용한다.
// bad const name = "soha"; // bad const name = `soha`; // good const name = 'soha';
-
문자열과 변수를 같이 사용할 경우 literal를 사용한다.
// bad const sayHi = 'Hello, ' + name + '!'; // bad const sayHi = ['Hello, ', name, '!'].join(); // bad const sayHi = `Hello, ${ name }!`; // good const sayHi = `Hello, ${name}!`;
-
기본적으로 문자열은 single quote(
''
)를 사용한다.// bad const name = "soha"; // bad const name = `soha`; // good const name = 'soha';
-
긴 문자열은 문자열 연결을 사용하여 여러 줄에 걸쳐 작성하지 않는다.
// bad const message = '이 편지는 영국에서 최초로 시작되어 일년에' + '한바퀴를 돌면서 받는 사람에게 행운을 주었고 지금은 당신에게로 옮겨진' + '이 편지는 4일 안에 당신 곁을 떠나야 합니다. 이 편지를 포함해서 7통을' + '행운이 필요한 사람에게 보내 주셔야 합니다. 복사를 해도 좋습니다.' + '혹 미신이라 하실지 모르지만 사실입니다.'; // good const message = '이 편지는 영국에서 최초로 시작되어 일년에 한바퀴를 돌면서 받는 사람에게 행운을 주었고 지금은 당신에게로 옮겨진 이 편지는 4일 안에 당신 곁을 떠나야 합니다. 이 편지를 포함해서 7통을 행운이 필요한 사람에게 보내 주셔야 합니다. 복사를 해도 좋습니다. 혹 미신이라 하실지 모르지만 사실입니다.'
-
jsx 문법 내의 attribute에서는 double quote(
””
)를 사용한다.const Weadie = () => { const name = '웨디'; return <input placeholder="이름을 입력해주세요" name={name} /> };
-
변수 선언시 const, let만 사용한다.
// bad var idx = 1; // good let idx = 1; // good const name = '행동대장';
-
전역 변수를 사용하지 않는다.
-
타입의 종류를 선언할 때는
type
을 사용한다.// good type ButtonStyle = 'primary' | 'secondary' | 'tertiary' | 'text';
-
프로퍼티를 포함하는 객체 타입을 선언할 때는
interface
를 사용한다.// good interface ButtonProps { style: ButtonStyle; text: string; disabled?: boolean; onClick?: () => void; }
-
타입 import할 때는 type only import를 한다.
import type { myType } from @types/myTypes
-
컴포넌트의 인수는 별도의
ComponentProps
의 이름으로 interface를 선언하여 사용한다.interface ButtonProps { size : ButtonSize; color : ButtonColor; } const Button = (props : ButtonProps) => { const {size, color} = props; // ... }
-
콤마 다음에 값이 올 경우 공백을 넣는다.
// bad const array = [1,2,3]; // good const array = [1, 2, 3];
-
모든 함수는 화살표 함수를 사용한다.
// bad function foo() { ... } // bad [1,2,3].map(function (x) { const y = x + 1; return x * y; } // good const foo = () => { ... } // good [1,2,3].map(x => { const y = x + 1; return x * y; }
-
함수 내에서 반환은 한 번만 하되, 빠른 함수 탈출의 경우는 허용한다.
// good const foo = () => { const boo = 1; // ... if(boo) return; return boo; }
-
return문 바로 위는 개행한다.
// good const getResult = () => { ... return someDataInFalse; }
-
arguments
를 사용하지 않고, rest 구문을 사용한다.// bad const getCrewNames = () => { const args = Array.proptotype.slice.call(arguments); return args.join(''); } // good const getCrewNames = (...args) => { return args.join('') }
-
매개변수를 절대로 변경하지 않고, 기본 매개변수 구문을 사용한다.
// bad const getName(name) { name = name || '' // ... } // bad const getName(name) { if (!name) { name = '' } // ... } // good const getName(name = '') { // ... }
-
기본 매개변수는 항상 마지막에 넣는다.
// bad const getDetails(name = '', age) { // ... } // good const getDetails(age, name = '') { // ... }
-
함수는 사용 전에 선언한다.
// bad const a = foo(); const foo = () => { // .. }; // good const foo = () => { // .. }; const a = foo();
-
화살표 함수의 파라미터가 하나면 괄호는 생략한다.
// bad foo.forEach((a) => a.name); // good foo.forEach(a => a.name);
-
암시적 반환을 최대한 사용한다. 함수 본체가 하나의 표현식이면 중괄호를 생략해 return문을 사용하지 않고 짧은 경우 개행없이 볼 수 있어 깔끔하다.
// bad foo.forEach((a) => { return a.name; }); // good foo.forEach(a => a.name);
-
객체의 여러 속성에 접근하여 사용할 때, 객체 분해를 사용한다.
// bad const getCrewDetails = (crew) => { const crewName = crew.name; const crewAge = crew.age; return `${crewName}:${crewAge}세` } // good const getCrewDetails = (crew) => { const {name, age} = crew; return `${name}:${age}세` } // best const getCrewDetails = ({name, age}) => { return `${name}:${age}세` }
-
배열 분해를 사용한다.
const crews = ['cookie', 'soha', 'weadie', 'todari']; // bad const first = crews[0]; const second = crews[1]; // good const [first, second] = crews;
-
여러 값을 반환할 경우 배열 분해가 아닌 객체 분해를 사용한다.
// bad const getCrews = () => { return [cookie, soha, weadie, todari]; } // good const getCrews = () => { return {cookie, soha, weadie, todari}; }
-
배열 선언은 리터럴을 사용한다.
// bad const array = new Array('r', 'g', 'b'); // good const array = ['r', 'g', 'b'];
-
배열 복사는 전개(spread) 연산자를 사용한다.
const arr = [1, 2, 3, 4]; // bad const newArray = arr.slice(); // good const newArray = [...arr];
-
특정 길이 만큼의 배열을 선언해야하는 경우 생성자를 사용해 선언한다.
// bad const array = [undefined, undefined, undefined, undefined, undefined]; // bad const array = Array.from({ length: 5 }); // good const array = new Array(5).fill();
-
조건 확인은
===
,!==
만 사용한다.==
,!=
는 사용하지 않는다. -
boolean에는 단축형을 사용한다.
// bad if (isTired === 'true') { // ... } // good if (isTired) { // ... }
-
switch문 사용시 case마다 개행을 둔다.
// good switch (value) { case 1: doSomething1(); break; case 2: doSomething2(); break; case 3: return true; default: throw new Error('This shouldn\'t happen.'); }
-
주석 기호 뒤에 공백을 넣는다.
//bad // good
-
설명 주석의 경우 2줄 이상 넘어갈 경우
/**/
를 사용한다.// bad // 이건 // 주석입니다. // good /* * 이건 * 주석입니다. */ // good /** * 이건 * 주석입니다. */
-
코드를 주석 처리한 경우에는 2줄 이상이라도
//
를 사용한다.// const hello = '안녕하세요!'; // const name = 'soha';
-
TODO 주석의 경우에는 작성자의 이름을 포함한다.
// good // TODO: (@soha) 내용 // 작서자 이름: soha, weadie, cookie, todari
-
항상 모듈(
import
)을 사용한다.// bad const HaengdongStyle = require('./HaengdongStyle'); module.exports = HaengdongStyle.button; // good import HaengdongStyle from './HaengdongStyle'; export default HaengdongStyle.button; // best import { button } from './HaengdongStyle'; export default button;
-
한 곳의 여러 모듈은 한 번에 가져온다.
// bad import haengdong from 'haengdong'; import { cookie, weadie } from 'haengdong'; // good import haengdong, { cookie, weadie } from 'haengdong'; // good import haengdong, { cookie, weadie, } from 'haengdong';
-
ts, tsx 파일 이름 확장자를 포함하지 않는다.
// bad import soha from './soha.ts'; import cookie from './cookie.tsx'; import haengdong from './haedong/index.ts'; // good import soha from './soha'; import cookie from './cookie'; import haengdong from './haedong';
-
component와 관련된(Button.tsx, Button.type.ts, Button.stories.tsx 등) 파일은 PascalCase를 사용한다.
-
그 외에는 camelCase를 사용한다.
-
참조 명명 시 React 구성 요소에는 PascalCase를 사용하고 인스턴스에는 camelCase를 사용한다.
// bad import button from './Button'; // good import Button from './Button'; // bad const Button = <Button />; // good const button = <Button />;
-
React 구성 요소 명명 시 파일 이름을 구성 요소 이름으로 사용합니다.
// bad import Button from './Button/Button'; // bad import Button from './Button/index'; // good import Button from './Button';
-
prop 이름에는 항상 camelCase를 사용하고, prop 값이 React Component인 경우 PascalCase를 사용한다.
// bad <User Name="weadie" phone_number={01011112222} card={Card} /> // good <User name="weadie" phoneNumber={01011112222} Card={Card} />
-
prop 값이 명시적으로 true인 경우 생략한다.
// bad <Button hidden={true} /> // true <Button hidden />
-
prop의 key에 배열 index를 사용하지 않는다. 고유하고 안정적인 ID를 할당한다.
// bad {cards.map((card, index) => <Card {...card} key={index} /> )}; // good {cards.map(todo => <Card {...card} key={todo.id} /> )};
-
필수가 아닌 prop에 대해선 명시적인 defaultProp을 정의한다.
// good const Item = ({id, name = 'todari'}: ItemProps) => { return // ... }
-
children이 없는 태그는 스스로 닫는다.
// bad <Card name="soha"></Card> // good <Card name="soha" /> // bad <Card name="soha" job="developer" /> // good <Card name="soha" job="developer" />
-
div
태그를 사용하는 것을 지양하고, 시멘틱 태그를 사용하는 것을 지향한다.// bad <div>hello</div> // good <p>hello</p>
-
css prop의 네이밍은 컴포넌트의 이름 + Style을 사용한다.
// bad const ButtonStyle = css` display: flex; `; const Wedy = () => { return ( <div css={ButtonStyle} /> ); } // good const buttonStyle = css` display: flex; `; const Wedy = () => { return ( <div css={buttonStyle} /> ); }
-
attribute 순서는 유사한 성격의
attribute
을 묶어 작성한다. 다른 성격의attribute
와는 개행으로 구분한다.순서 성격 대표 attribute 1 레이아웃 position, top, bottom, left, right, z-index, float, display, flex, flex-direction, grid, visibility 2 BOX width, height, margin, padding, border, outline, box-sizing 3 배경 background, box-shadow 4 폰트 font, color, text, line-height, letter-spacing, white-space, break-word 5 변형 transform, transition, animate 6 기타 overflow, opacity, cursor
절대 경로를 사용한다.
경로 | 위치 |
---|---|
./src/apis | @apis |
./src/assets | @assets |
./src/components | @components |
./src/constants | @constatns |
./src/hooks | @hooks |
./src/mocks | @mocks |
./src/pages | @pages |
./src/utils | @utils |
-
각 import group 간에는 개행을 한다.
그룹 패턴 1 React* 2 @hooks/* 3 @apis/* 4 @pages/* 5 @components/* 6 @assets/* 7 @utils/* 8 @constants/* 9 @mocks/*
- 사용할 스타일링 라이브러리 후보는 다음과 같아요. emotion, styled-components, css modules, panda css
- 이 중에서 스타일링 라이브러리는 emotion을 사용하기로 결정했어요!
- 행동대장들은 협업, 학습, 성장에 대한 경험을 우선순위로 생각하기 때문에, 모든 크루가 이미 많이 사용해 본 styled-components는 배제했어요.
- theme이나 component state에 따른 anatomy등을 동적으로 다양하게 적용하기 위해서 동적 스타일링이 불편한 module css는 사용하지 않기로 했어요.
- pandaCSS는 런타입 오버헤드가 없어 성능 최적화 면에서 매우 뛰어나지만, design foundation이나 static 파일들에 대한 러닝커브가 매우 높아 사용하지 않기로 했어요.
- styled-component와 css prop을 사용하는 emotion 모두 별도의 변수명을 지정해서 이를 할당해 줘야 하는 번거로움과 코드의 길이가 길어지는 문제가 있어요. 따라서 이 부분을 선택 기준으로 잡는 건 부적절 할 것이라 판단했어요.
- 하지만, html 태그가 바로 보여 웹 접근성을 고려하여 개발하기 좋다는 장점과, 점유율이 높고 정보가 높은 이유로 인해 emotion css를 사용하기로 결정했어요.
- react
- react-router-dom
- typescript
- emotion
- webpack
- esLint
- prettier
- storybook
- jest
- react-testing-library
- msw
- node 버전: v20.15.1 (LTS)
- npm 버전: v10.7.0
- 서비스 타겟 환경: 모바일
- 브라우저 지원 범위: 크롬, 사파리, 엣지
Last Updated: 2024-07-11