코딩 컨벤션
카테고리 | 기술 |
---|---|
태그 | |
수정일 | Dec 10, 2023 |
작성일 | Nov 23, 2023 |
코딩 컨벤션은 코드 가독성과 이해를 증진시키며, 일관된 스타일을 통해 협업과 유지보수를 용이하게 만듭니다. 자바스크립트의 유연성과 특성으로부터 오는 혼란을 줄여주고, 효율적인 코드 작성을 돕습니다.
[적용효과]
코딩 컨벤션을 준수하면 가독성이 좋아지고, 성능에 영향을 주거나 오류를 발생시키는 잠재적 위험 요소를 줄여줍니다. 특히 프로젝트의 규모가 커질 수록 유지보수 비용을 줄이는 데 도움이 된다.
프로그램의 성능을 해치지 않은 범위 내에서 가독성과 관리 용이성을 우선하여 작성하였습니다.
목차
참고 이 문서는 ES5 이상을 다루며 ES6를 기준으로 작성하였다. ES5에서 지켜야할 컨벤션은 (ES5)태그를 달아 구분하였다.
들여쓰기 (Indentation)
1. 들여쓰기 스타일:
-
공백 문자(스페이스)를 사용하거나 탭(Tab) 문자를 사용할 수 있습니다. 중요한 것은 일관된 스타일을 유지하는 것입니다.
// 스페이스를 사용한 들여쓰기 (권장) function exampleFunction() { if (condition) { // 코드 블록 } } // 탭을 사용한 들여쓰기 function exampleFunction() { if (condition) { // 코드 블록 } }
2. 들여쓰기 크기:
-
들여쓰기 크기는 2개의 스페이스를 사용합니다.
// 2개의 스페이스를 사용한 들여쓰기 (권장) function exampleFunction() { if (condition) { // 코드 블록 } }
3. 중괄호 위치:
-
중괄호를 열린 줄의 끝에 두어 작성합니다.
// 좋은 예 function exampleFunction() { if (condition) { // 코드 블록 } } // 좋지 않은 예 function exampleFunction() { if (condition) { // 코드 블록 } }
4. 콤마 위치:
-
객체 리터럴이나 배열 등에서 콤마는 항상 요소 뒤에 위치합니다.
// 좋은 예 const myArray = [1, 2, 3]; const myObject = { property1: 'value1', property2: 'value2', }; // 좋지 않은 예 const myArray = [1, 2, 3,]; const myObject = { property1: 'value1', property2: 'value2', };
명명 규칙 (Naming Conventions)
카멜(Camel)식: userLoginLog
파스칼(Pascal)식: UserLoginLo
케밥(Kebab)식: user-login-log
스네이크(Snake)식: user_login_log 또는 USER_LOGIN_LOG
- 변수 (Variables):
- Camel Case를 사용하며, 변수명은 명사나 명사구로 지정합니다.
- 해당 변수가 나타내는 데이터 또는 역할을 명확하게 표현해야 합니다.
-
약어는 최소화하며 가능한한 의미 있는 단어를 사용합니다.
// 좋지 않은 예 let x = 10; // 좋은 예 let itemCount = 10;
- 상수 (Constants):
-
상수는 대문자와 언더스코어를 사용하여 명명하며, 단어 사이에 언더스코어(_)를 삽입합니다.
const MAX_COUNT = 100;
-
- 함수 (Functions):
- Camel Case를 사용하며, 함수명은 동사나 동사구로 지정합니다. - 함수는 해당 함수가 수행하는 작업을 나타내는 의미 있는 이름을 가져야 합니다.
// 좋은 예 function calculateTotalAmount() { // function logic } // 좋지 않은 예 function calc() { // function logic } function CalculateTotalAmount() { // function logic }
- 클래스 (Classes):
-
Pascal Case를 사용하며, 클래스명은 명사나 명사구로 지정합니다.
class UserProfile { // class logic }
-
- 메서드 (Methods):
-
Camel Case를 사용하며, 메서드명은 동사나 동사구로 지정합니다.
class Calculator { addNumbers() { // method logic } }
-
- 함수 매개변수 (Function Parameters):
-
Camel Case를 사용하며, 매개변수명은 명사나 명사구로 지정합니다.
function greetUser(userName) { // function logic }
-
- 객체 (Objects):
-
Camel Case를 사용하며, 객체의 속성명은 명사나 명사구로 지정합니다.
let userInformation = { firstName: "John", lastName: "Doe" };
-
- 이벤트 핸들러 (Event Handlers):
-
Camel Case를 사용하며, 이벤트 핸들러 함수명은 “handle”로 시작합니다.
function handleButtonClick() { // event handling logic }
-
- 콜백 함수 (Callback Functions):
-
Camel Case를 사용하며, 콜백 함수명은 동사나 동사구로 지정합니다.
fetchData((data) => { // callback logic });
-
- Promise 객체 (Promises):
-
Camel Case를 사용하며, Promise 객체의 메서드명은 동사나 동사구로 지정합니다.
fetchData() .then(processData) .catch(handleError);
-
- 불린 변수 (Boolean Variables):
-
명사나 명사구를 사용하며, 변수명은 일반적으로 상태나 속성을 나타내도록 합니다.
let isCompleted = false;
-
- 약어 (Abbreviations):
-
가능한 약어를 피하고, 사용해야 할 경우 일관된 방식으로 사용합니다.
// 좋은 예 let itemCount = 10; // 좋지 않은 예 let itmCnt = 10;
-
변수 (Variables)
- 변수 선언:
const
를 사용하여 변수를 선언하며, 재할당이 필요한 경우에만let
을 사용한다.- 각 변수는 한 줄에 하나씩 선언하는 것이 가독성을 높인다.
-
변수를 선언할 때 가능하면 초기값을 할당합니다.
// 권장 const myVariable = 10; // 특별한 이유가 있는 경우에만 사용 let mutableVariable = 20; // 피해야 할 예 let myVariable = 10, mutableVariable = "Hello";
- 변수 그룹화:
-
유사한 성격이나 목적을 가진 변수는 그룹화하여 선언할 수 있습니다.
// 그룹화되지 않은 변수 let firstName = "John"; let lastName = "Doe"; let age = 25; // 그룹화된 변수 let person = { firstName: "John", lastName: "Doe", age: 25 };
-
- 명시적인 타입 선언:
-
타입스크립트 잘 쓰자!
// 명시적인 타입 선언 let myNumber: number = 42;
-
상수 (Constants)
- 가급적 상수를 사용하여 매직 넘버를 피함
함수 (Functions)
- 함수 선언:
- 함수를 선언할 때
arrow function
표현식을 사용합니다. -
함수에 필요한 매개변수를 명확하게 정의하고, 필요에 따라 기본값을 사용하여 함수를 호출할 수 있도록 합니다.
// 권장 const add = (a, b) => { return a + b; } function greet(name = "Guest") { return `Hello, ${name}!`; }
- 함수를 선언할 때
- 단일 책임 원칙 (Single Responsibility Principle):
-
함수는 하나의 기능 또는 작업에만 집중되어야 합니다.
// 좋은 예 function calculateTotalAmount(items) { // calculate logic } // 좋지 않은 예 function processAll() { // 여러 작업을 처리 }
-
주석 (Comments)
1. 주석 스타일:
- 주석은
//
또는/* */
스타일을 사용합니다. -
단일 라인 주석(
//
)은 한 줄 주석에 사용되며, 다중 라인 주석(/* */
)은 여러 줄에 걸쳐 사용됩니다.// 단일 라인 주석 /* * 다중 라인 주석 * 여러 줄에 걸쳐 설명 */
2. 주석 위치:
-
주석은 주석이 설명하는 코드 바로 뒤에 위치해야 합니다.
// 올바른 위치 const result = calculateTotalAmount(); // 결과를 계산합니다. // 피해야 할 위치 // 결과를 계산합니다. const result = calculateTotalAmount();
3. 설명적 주석:
-
주석은 코드를 설명하는 데 사용되며, 단순히 “무엇”이 아니라 “왜”에 대한 설명을 포함해야 합니다.
// 좋은 예 const result = calculateTotalAmount(); // 세금 및 할인을 고려한 총 금액 계산 // 좋지 않은 예 const result = calculateTotalAmount(); // 결과 계산
4. 임시 주석:
-
TODO
또는FIXME
와 같은 임시 주석을 사용하여 나중에 수정해야 할 부분이나 개선이 필요한 부분을 표시합니다.javascriptCopy code // TODO: 나중에 최적화 const result = calculateTotalAmount(); // FIXME: 이 버그 수정 function fixBug() { // 코드 수정 }
5. 문제 해결 주석:
-
코드에서 문제가 발생한 이유와 문제를 해결한 방법에 대한 주석을 작성합니다.
// 이 코드는 IE에서 작동하지 않습니다. IE에서는 대신 다른 방법을 사용합니다.
6. 버전 주석:
-
코드의 변경 사항과 관련하여 버전 주석을 작성합니다.
// v1.2.0: 새로운 기능 추가 - 사용자 로그인 기능
7. 문서 주석:
-
코드에 대한 자동 생성 문서 (예: JSDoc)를 사용하고, 주석을 통해 API나 함수에 대한 문서화를 진행합니다.
/** * 사용자의 총 금액을 계산합니다. * @param {number} price - 제품 가격 * @param {number} quantity - 제품 수량 * @returns {number} 총 금액 */ function calculateTotalAmount(price, quantity) { // 함수 구현 }
8. 불필요한 주석 제거:
- 주석이 더 이상 필요하지 않은 경우 삭제하거나 업데이트합니다.
9. 협업 주석:
-
팀 협업을 위해 특정 작업에 대한 주석을 추가하거나 코드의 일부를 잠시 비활성화하는 주석을 추가할 수 있습니다.
// 협업 중 - 다음 작업에 대한 주석 // TODO: 이 부분은 개선이 필요함
클래스 (Classes)
- 클래스 정의와 사용에 대한 규칙
- 클래스명의 명확성과 클래스 멤버에 대한 주석 작성
이벤트 핸들링 (Event Handling)
1. 인라인 이벤트 핸들링 피하기:
-
가능한 경우 인라인 이벤트 핸들링을 피하고, JSX에서 직접 함수를 호출하는 대신 컴포넌트 메서드나 외부 함수를 참조합니다.
// 좋은 예 <button onClick={handleButtonClick}>Click Me</button> // 피해야 할 예 <button onClick={() => handleClick()}>Click Me</button>
2. 이벤트 객체 명명:
-
이벤트 핸들러 함수에서 이벤트 객체를 사용할 경우,
event
로 명명합니다.function handleInputChange(event) { // 이벤트 처리 로직 }
3. 이벤트 핸들러 함수에 매개변수 전달:
-
이벤트 핸들러 함수에 매개변수를 전달해야 할 경우, 익명 함수를 사용하여 함수에 매개변수를 전달합니다.
<button onClick={() => handleButtonClick(param)}>Click Me</button>
4. preventDefault
사용:
-
이벤트 핸들러 함수 내에서 기본 동작을 방지해야 할 경우,
preventDefault
를 사용합니다.function handleFormSubmit(e) { e.preventDefault(); // 폼 제출 로직 }
5. bind
메서드 사용 피하기:
-
함수가 호출될 때
this
를 바인딩하기 위해bind
메서드를 사용하는 대신, 화살표 함수를 활용합니다.// 좋은 예 handleButtonClick = () => { // 이벤트 처리 로직 } // JSX에서 사용 <button onClick={this.handleButtonClick}>Click Me</button> // 피해야 할 예 <button onClick={this.handleButtonClick.bind(this)}>Click Me</button>
6. event.target
사용:
-
이벤트 핸들러 함수 내에서
event.target
을 사용하여 이벤트가 발생한 엘리먼트에 접근합니다.function handleInputChange(event) { const value = event.target.value; // 입력 필드 값에 대한 로직 }
조건문과 반복문 (Conditional Statements and Loops)
조건문 (Conditional Statements):
- 중괄호 사용:
-
항상 중괄호를 사용하여 코드 블록을 감싸는 것이 좋습니다.
// 권장 if (condition) { // 조건이 참일 때 실행되는 코드 } // 피해야 할 예 if (condition) // 조건이 참일 때 실행되는 코드
-
- 삼항 연산자 활용:
- 간단한 조건문은 삼항 연산자를 사용하여 간결하게 표현할 수 있습니다.
-
복잡한 조건의 경우 가독성 측면에서 중첩 삼항 연산자가 아닌 논리 연산자 혹은 변수를 사용합니다.
// 권장 const result = condition ? '참' : '거짓'; // 피해야 할 예 const result = (condition) ? '참' : '거짓'; const result = condition ? '참' : condition2 ? '거짓' : '보류';
- 복잡한 조건식:
-
복잡한 조건을 평가할 때는 명시적인 논리 연산자나 조건을 변수에 할당하여 가독성을 높입니다.
// 권장 if (condition1 && condition2) { // 조건이 참일 때 실행되는 코드 } const isConditionMet = (condition1 && condition2); if (isConditionMet) { // 조건이 참일 때 실행되는 코드 } // 피해야 할 예 if (condition1 || condition2) { // 조건이 참일 때 실행되는 코드 }
-
반복문 (Loop Statements):
-
로직 혹은 성능 상의 이유 등의 특수한 상황이 아닌 일반 로직에서는,
forEach
,map
,filter
,reduce
등의 배열 메서드를 사용합니다.const myArray = [1, 2, 3]; myArray.forEach(item => { // 배열 요소에 대한 작업 수행 }); const transformedArray = myArray.map(item => { // 각 요소에 대한 변형 작업 수행 return item * 2; }); const sum = myArray.reduce((acc, item) => { // 누적된 합산 작업 수행 return acc + item; }, 0);
while
및do...while
사용:-
특정 조건이 충족될 때까지 반복해야 할 때는
while
또는do...while
을 사용합니다.// while문 while (condition) { // 반복 작업 수행 } // do...while문 do { // 반복 작업 수행 } while (condition);
-
모듈화 (Module Pattern)
- 코드를 모듈화하는 방법과 모듈 간의 의존성 처리에 대한 규칙
에러 핸들링 (Error Handling)
- 예외 처리와 에러 메시지 작성에 대한 규칙
포맷팅 (Formatting)
- 코드 블록의 중괄호 위치, 줄 바꿈 등에 대한 규칙
- eslint + Prettier 설정에 기반함.
스마일드래곤 ESLint
🔗 @smiledragon-corp/eslint-config-frontend
테스트 (Testing)
- 유닛 테스트, 통합 테스트 등을 위한 규칙
- 버그리포트 Template
**버그 상세 내용:** (버그에 대한 자세한 설명을 제공해 주세요. 가능한 한 세부적으로 기술해 주시면 도움이 됩니다.)
-
**재현 단계:**
1. (버그를 재현하기 위한 첫 번째 단계를 설명해 주세요)
2. (두 번째 단계)
3. (계속해서 필요한 단계를 나열해 주세요)
**예상 결과:** (정상적으로 작동해야 하는 경우, 어떤 결과가 나와야 하는지 설명해 주세요)
**실제 결과:** (버그가 발생하면 어떤 결과가 나타난 것인지 설명해 주세요)
성능 최적화 (Performance Optimization)
- 성능을 향상시키기 위한 최적화에 대한 규칙
접근성 (Accessibility)
- 웹 접근성을 고려한 코딩 규칙
버전 관리 (Version Control)
- Git 또는 다른 버전 관리 시스템을 사용할 때의 브랜치, 커밋 메시지 등에 대한 규칙
- 커밋 메세지 :
{이슈번호}-{종류} : {내용}
- 예 : 11-feat : 로그인 페이지 구현
feat | 기능 추가 |
---|---|
fix | 버그 수정 |
design | CSS 등 사용자 UI 디자인 변경 |
docs | README, comment 수정 |
build | 코드 변경이 아닌 config 위주의 변경, 패키지 매니저 수정 |
refac | 내부 코드 리팩토링 (로직 변화 없음) |
style | 코드 포매팅, 코드 린팅, indent 등 (로직 변화 없음) |
test | 테스트 코드 추가 및 수정 (Cypress, Jest 등 테스트 프레임워크에 대한 코드 작업) |
perf | 성능 향상을 위한 코드 교체 |
revert | 예전 버전으로 돌아가는 변경 |
remove | 파일 삭제 |
etc | 위 항목들을 제외한 사항에 대한 변경 ( 커밋 메시지 좀 더 상세히 작성 필요, 최대한 지양 ) |
라이브러리 및 프레임워크 사용 (Library and Framework Usage)
React
### 1. **컴포넌트 파일 및 폴더 구조:**
- 컴포넌트는 기능 또는 도메인에 따라 폴더로 구분될 수 있습니다.
- 컴포넌트 파일은 Pascal Case로 명명되며, 해당 컴포넌트의 기능을 나타내는 이름을 사용합니다.
```javascript
// 폴더 구조 예시
/src
/components
/Header
Header.tsx
Header.styled.ts
Header.types.ts
```
<div class="callout" style="display:flex;width:100%;border-radius:4px;background:rgb(241,241,239);padding: 16px 16px 16px 12px;">
<div style="display:flex;align-items:center;justify-content:center;height:24px;width:24px;border-radius:0.25em;flex-shrink:0;">💡</div>
<div style="white-space:pre-wrap;word-break:break-word;caret-color:rgb(55, 53, 47);margin-left:8px;padding-left:2px;padding-right:2px;">2개 이상의 컴포넌트에서 사용되는 컴포넌트는 전역 컴포넌트(<code class="language-plaintext highlighter-rouge">/src/components</code>)로 변경합니다.</div>
</div>
<div class="callout" style="display:flex;width:100%;border-radius:4px;background:rgb(241,241,239);padding: 16px 16px 16px 12px;">
<div style="display:flex;align-items:center;justify-content:center;height:24px;width:24px;border-radius:0.25em;flex-shrink:0;">💡</div>
<div style="white-space:pre-wrap;word-break:break-word;caret-color:rgb(55, 53, 47);margin-left:8px;padding-left:2px;padding-right:2px;">하위 컴포넌트는 상위 컴포넌트의 네이밍을 prefix로 사용<br />(ex. Form ⇒ FormRow, FormLabelWithButton …) </div>
</div>
### 2. **컴포넌트 명명 규칙:**
- 컴포넌트명은 Pascal Case로 작성하며, 명사나 명사구로 지정합니다.
```javascript
// 좋은 예
function Header() {
// 컴포넌트 로직
}
// 좋지 않은 예
function headerComponent() {
// 컴포넌트 로직
}
```
### 3. **함수형 컴포넌트와 훅 사용:**
- 가능한 경우 함수형 컴포넌트와 훅을 사용하고, 클래스형 컴포넌트 대신 최신의 리액트 기능을 활용합니다.
```javascript
// 함수형 컴포넌트와 훅 사용 (권장)
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [data, setData] = useState([]);
useEffect(() => {
// 컴포넌트 마운트 시 또는 데이터 변경 시 수행되는 로직
}, [data]);
return (
<div>
{/* 컴포넌트 렌더링 로직 */}
</div>
);
}
```
### 4. **컴포넌트 Props:**
- 컴포넌트의 속성명은 Camel Case로 작성합니다.
- PropTypes를 사용하여 속성에 대한 타입을 명시하는 것이 좋습니다.
```javascript
import type { Props } from './Component.types';
function MyComponent({ propOne, propTwo }: Props) {
// 컴포넌트 로직
}
```
### 5. 선언 순서:
1. hooks → state → 일반 변수 순으로 선언 (1순위)
2. useQuery, useMutation, react-hook-form (2순위)
3. 메소드 → eventListener (3순위)
4. Lifecycle Methods
5. JSX
```javascript
'Sample.tsx';
import { moduleA } from 'import/module/path';
export default function Sample() {
// Hooks 선언
const router = useRouter();
// State 선언
const [loading, setLoading] = setState(false);
// 내부 변수 선언
const myVariable = 'string';
//...
// 내부 메소드 선언
const myMethods = () => {};
// 이벤트 핸들러 선언
const handleButtonClick = (event) => {};
// Lifecycle 메소드 선언
componentDidMount() {}
componentDidUpdate() {}
componentWillUnmount() {}
//...
// JSX 선언
return (
<>
</>
);
}
```
### 7. **CSS-in-JS 또는 CSS 모듈 사용:**
- 컴포넌트 스타일링은 CSS-in-JS 라이브러리 styled-components를 사용하여 작성합니다.
```javascript
// Component.styled.ts
import styled from 'styled-components';
export const StyledBox = styled.div`
// 상세 스타일 정의.
`;
```
Next
<div class="callout" style="display:flex;width:100%;border-radius:4px;background:rgb(241,241,239);padding: 16px 16px 16px 12px;">
<div style="display:flex;align-items:center;justify-content:center;height:24px;width:24px;border-radius:0.25em;flex-shrink:0;">💡</div>
<div style="white-space:pre-wrap;word-break:break-word;caret-color:rgb(55, 53, 47);margin-left:8px;padding-left:2px;padding-right:2px;">기본적으로 Next 13 공식 가이드를 따릅니다.</div>
</div>
### 1. app router
- Client Page 사용을 위해 `_components/[경로명]ClientPage/` 컴포넌트 작성 후 사용한다.
```yaml
app/
pathA/
_components/
PathAClientPage/
index.ts
PathAClientPage.tsx
PathAClientPage.styled.tsx
page.tsx
layout.tsx
```
```javascript
// pathA/page.tsx 예시
import { PathAClientPage } from './_components/PathAClientPage';
export default function PathA() {
return <PathAClientPage />;
}
```
Styled Component
AppRouter 내 페이지 최상단 Element의 경우 `{Page명}Container` 를 사용합니다.
<div class="callout" style="display:flex;width:100%;border-radius:4px;background:rgb(241,241,239);padding: 16px 16px 16px 12px;">
<div style="display:flex;align-items:center;justify-content:center;height:24px;width:24px;border-radius:0.25em;flex-shrink:0;">💡</div>
<div style="white-space:pre-wrap;word-break:break-word;caret-color:rgb(55, 53, 47);margin-left:8px;padding-left:2px;padding-right:2px;">디버깅 시 dom에서 styled 컴포넌트의 이름으로 요소를 찾기 용이합니다.</div>
</div>
### 1. **컴포넌트 네이밍:**
Styled Components의 네이밍 규칙은 일반적인 React 컴포넌트 네이밍과 동일합니다. 컴포넌트 이름은 Pascal Case를 사용합니다.
```javascript
const StyledButton = styled.button`
/* 스타일 정의 */
`;
```
### 2. **태그 선택자 사용:**
Styled Components는 태그 선택자를 사용하여 스타일을 정의하는데, 이는 해당 컴포넌트의 HTML 태그에 스타일을 적용하는 데 도움이 됩니다.
```javascript
const StyledButton = styled.button`
background-color: #3498db;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
background-color: #2980b9;
}
`;
```
### 3. **재사용 가능한 스타일 구성:**
스타일을 여러 컴포넌트에서 재사용할 수 있도록 스타일 구성을 고려하세요. `css` 템플릿 리터럴을 사용하여 스타일을 변수로 추출할 수 있습니다.
```javascript
const buttonStyles = css`
background-color: #3498db;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
background-color: #2980b9;
}
`;
const StyledButton = styled.button`
${buttonStyles}
`;
const StyledInput = styled.input`
${buttonStyles}
/* 추가적인 스타일 정의 */
`;
```
### 4. **테마 활용:**
테마를 활용하여 애플리케이션 전체의 일관된 스타일을 관리할 수 있습니다.
```javascript
const theme = {
primaryColor: '#3498db',
secondaryColor: '#2980b9',
};
const StyledButton = styled.button`
background-color: ${props => props.theme.primaryColor};
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
background-color: ${props => props.theme.secondaryColor};
}
`;
// ThemeProvider를 통해 테마 전달
<ThemeProvider theme={theme}>
<StyledButton>Click me</StyledButton>
</ThemeProvider>
```
React-query
empty…
빌드 시스템 (Build System)
- 프로젝트의 빌드 시스템에 대한 설정과 사용에 대한 규칙
보안 (Security)
- 보안에 취약한 패턴을 피하고 안전한 코딩 규칙
문서화 (Documentation)
- 코드와 프로젝트에 대한 문서 작성에 대한 규칙