프론트엔드 코딩 컨벤션

Thomas·2023년 8월 17일
1
coding-convention

Intro

해당 코딩 컨벤션은 회사 동료분과 함께 정의한 코딩 컨벤션입니다.
구글링을 통해 toast.ui의 컨벤션을 베이스로, 일을 하며 느꼈던 점을 반영해 저희 팀만의 컨벤션을 정의 했습니다.

프론트엔드 코딩 컨벤션

기본적으로 프로젝트에 ESLint 규칙과 Prittier 의 포멧팅이 반영되어 있지만, 개발자가 지켜야할 프론트엔드 파트의 컨벤션을 정의했습니다.

좋은 코드 퀄리티와 원활한 프론트엔드 개발자의 협업을 위해서 아래의 코딩 컨벤션을 준수해주시기 바랍니다.

들여쓰기

  • 들여쓰기는 space 2문자를 사용합니다.

문자열

  • 특별한 경우를 제외하고 문자열은 작은 따옴표를 사용합니다.
var text = '123';
var html = '<a href="#">link</a>';
var style = {
  'left': '100px',
  'top': '100px'
}

문장의 종료

  • 한 줄에 하나의 문장만 허용하며, 문장의 종료 시에는 반드시 세미콜론 ; 을 사용합니다.

식별자 Naming Convention

  • 직관적으로 의미를 파악할 수 있도록 가급적이면 약어를 사용하지 않습니다.
  • 한글을 직번역한 변수명을 사용하지 않습니다.
    // Bad
    const BunYukByunSoo = '번역변수';
  • 공백을 허용하지 않습니다.
  • 언어에서 사용하는 예약어 를 사용하지 않습니다.
  • 변수, 함수는 소문자 카멜 케이스로 선언합니다.
  • 배열은 복수형으로 선언합니다.
  • private 변수는 _ 를 접두사로 선언합니다.
  • HTML 태그는 소문자로 작성합니다.
    // Good
    <div></div>
    
    // Bad
    <DIV></DIV>
  • 상수는 스네이크 케이스를 활용해 대문자와 _ 를 사용해 선언합니다.
    const THIS_IS_CONSTANT = 'string';
  • props 로 전달되는 핸들러 함수는 on 으로 시작합니다.
    interface Props {
      onClick: (event) => void;
    }
    
    function Component(props: Props) {
      return <></>;
    }
    
    const Component = (props: Props) => <></>;
  • 컴포넌트 내부에서 직접 정의하는 이벤트 핸들러 함수는 handle 로 시작합니다.
    function Component(props) {
      const handleClick = (event) => console.log(event);
    
      return <></>;
    }
  • Boolean 타입 변수의 식별자 명은 가급적이면 부정형으로 선언하지 않는 것을 권고합니다. 또한 Boolean 타입의 변수의 식별자는 is, has, can 의 접두사를 사용하여 선언합니다.
    const isNotBoolean = false; // 옳지 않은 선언
    cosnt isBoolean = true; // 옳은 선언
    const canOpen = true;
    const hasChildren = true;
  • Enum 선언은 파스칼 케이스로 선언합니다. https://www.typescriptlang.org/docs/handbook/enums.html
    // 잘못된 선언
    enum FORM_MODE {
      CREATE = 'create',
      EDIT = 'edit',
      ADD = 'add',
    }
    
    // 컨벤션을 지킨 선언
    enum FormMode {
      Create = 'create',
      Edit = 'edit',
      Add = 'add',
    }
  • Interface, type 선언 시 접두사를 붙이지 않습니다. 헝가리안 표기법을 사용하지 않습니다.
    // Bad Case
    interface IServer {
      title: string;
      value?: string;
    }
    
    // Good Case
    interface Server {
      sample: string;
    }

React and Typescript

  • 컴포넌트는 항상 파스칼 케이스로 선언합니다.
  • Inline Style 을 하지 않습니다.
  • 스타일 변수는 기본적으로 분리해서 사용합니다. ( Component.style.ts )
  • 기본적인 컴포넌트는 function 으로 선언합니다.
    function Component(props) {
      return (<div></div>);
    }
  • children 을 props 로 포함 할 경우 React.ReactNode 로 타이핑 합니다.
    type Props = {
      children: React.ReactNode;
    }
    
    function Component(props: Props) {
      return <div>{props.children}</div>;
    }
  • 정말 타입이 난해하지 않는 경우를 제외하고는 any 를 사용하지 않습니다.
    • any 사용시 eslint warning을 무시할 수 있도록 아래의 주석을 명시합니다.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
  • 묵시적인 타입 캐스팅을 사용하지 않습니다. 타입 캐스팅은 항상 명시적으로 합니다.

Style


Css in JS

  • Emotion 의 css 를 선언 시 식별자 명은 변수의 카멜 케이스로 선언합니다.
  • css 를 사용할 땐 가급적 object 가 아닌 template string 을 활용합니다.
const textFieldCss = css`
  font-size: 14px;
`;
  • Emotion 의 styled 를 활용해 스타일링을 할 때 변수명은 컴포넌트와 마찬가지로 파스칼 케이스로 선언합니다.
const Wrapper = styled.div``;
cosnt FormRow = styled.section``;

Sass

  • 클래스명 선언 규칙 (BEM 을 기초로 코딩)
    • 소문자, 숫자 만을 조합
    • 조합은 (하이픈)으로 연결하여 작명
// 기본적으로 .을 사용함
className={styles.test}

// class name에 - 이 포함될 경우 아래와같이 사용
className={styles[‘test-test’]}

Function

  • 함수의 식별자명은 항상 시멘틱하게 선언합니다. (어떤 기능을 하는 함수인지 함수명을 보고 알 수 있도록 선언합니다.)
  • Typescript 를 활용해 리턴 타입과 매개 변수를 정확하게 타이핑 해줍니다.
  • 이벤트를 핸들링 하는 함수는 handle 접두사를 이용합니다.
  • 반환값이 boolean 인 함수는 is 접두사를 활용하며, 어떤 값을 리턴하는 함수는 get 접두사를 활용합니다.

변수 선언 키워드

  • var 키워드를 사용하지 않고 const 와 let 을 사용하여 변수를 선언합니다.

전역변수

  • 네임스페이스를 사용하여 전역변수를 최소화하며 암묵적인 전역변수는 절대로 사용하지 않습니다.

배열과 객체

  • 배열과 객체는 반드시 리터럴 로 선언합니다. 배열 복사 시 순환문 을 사용하지 않습니다.

배열

# 선언예시
// Good
var emptyArr = [];
var arr = [1, 2, 3, 4, 5];

// Bad
var emptyArr = new Array();
var arr = new Array(1, 2, 3, 4, 5);

# 복사예시
var items = [1, 2, 3, 4];
var len = items.length;
var itemsCopy = [];

// Bad
for (var i = 0; i < len; i++) {
  itemsCopy[i] = items[i];
}

// Good
const arr = [...items];

객체

// Good
var emptyObj = {};
var obj = {
  pro1: 'val1',
  pro2: 'val2'
};

// Bad - 객체 생성자 사용
var emptyObj = new Object();
var obj = new Object();

함수

  • 함수는 함수 선언식과 표현식을 사용하여 선언합니다. 함수 표현식과 함수 생성자로 선언된 함수는 호이스팅 시 값이 할당되지 않습니다. 선언 이전에 사용 시 오류가 발생 하므로 함수는 사용 전에 선언해야 합니다. 함수 선언문은 변수 선언문 다음에 옵니다.
// Good(1)
function doSomething(param1, param2) {
  return param1 + param2;
}

// Good(2)
var doSomething = function(param1, param2) {
  return param1 + param2;
};

// Good(3) - 이름있는 함수 표현식
var doSomething = function doSomething(param1, param2) {
  return param1 + param2;
};

// Bad(1) - 함수 생성자 사용
var doSomething = new Function('param1', 'param2', 'return param1 + param2;');

// Bad(2) - IIEF
(function() {
  ...
}());
  • 함수표현식 대신 Arrow function을 사용합니다.
// Good
[1, 2, 3].map(x => {
  const y = x + 1;
  return x * y;
});

[1, 2, 3].map(function (x) {
  const y = x + 1;
  return x * y;
});
  • 함수의 본체가 하나의 식이면 중괄호 를 생략하고 암시적 return 을 이용합니다.
[1, 2, 3].map(number => `A string containing the ${number}.`);

Destructuring

  • 객체에서 여러 프로퍼티에 접근할 때는 Destructuring 을 이용합니다.
function Template({var, const, ...args}) {
  cosnt A = var;
};
  • 배열도 Destructuring 이 가능합니다.
const arr = [1, 2, 3, 4];

// Good
const [first, second] = arr;

// Bad
const first = arr[0];
const second = arr[1];

템플릿 문자열

  • 문자열을 생성하는 경우 template string 을 사용합니다.
// Good
function sayHi(name) {
  return `How are you, ${name}?`;
}

// Bad
function sayHi(name) {
  return 'How are you, ' + name + '?';
}

// Bad
function sayHi(name) {
  return ['How are you, ', name, '?'].join();
}

조건 확인하기

값이 있나요?

문자열: 빈 문자열이 인가요?

// Good(1)
if (string) ...

// Bad
if (string !== "") ...

배열: 순회할 요소가 있나요?

// Good(1)
if (array.length) ...

// Bad
if (array.length > 0) ...

객체: 순회할 속성이 있나요?

if (Object.keys(object).length) ...

값이 비어있나요?

문자열: 빈 문자열인가요?

// Good(1)
if (!string) ...

// Bad
if (string === '') ...

배열: 빈 배열인가요?

// Good(1)
if (!array.length) ...

// Bad
if (array.length === 0) ...

참조변수가 참(true)인가요?

// Good
if (variable) ...

// Bad
if (variable === true) ...

참조변수가 거짓(false)인가요?

// Good
if (!variable) ...

// Bad
if (variable === false) ...

반환

  • 특정 값을 반환해야 하는 경우, 함수의 맨 마지막에서 한 번만 return 합니다. 단, 예외 처리로 빠져나가기 위해 사용하는 return; 은 위 룰에서 제외됩니다.
  • 함수 내에서 if 문이 여러 번 호출되면, 함수로 분리해야 합니다.
// Good
function getResult() {
  var resultData;
  if (condition) {
    resultData = someDataInTrue;
  } else {
    resultData = someDataInFalse
  }
  return resultData;
}

// Allow
function foo(isValid) {
  if (!isValid) {
    return;
  }
  return someDataInTrue;
}

// Bad
function getResult() {
  if (condition) {
    return someDataInTrue;
  }
  return someDataInFalse;
}

순회

배열

const array = [1, 2, 3];

// Good
array.forEach((number) => {...});

// Bad
for (var i = 0; i < array.length; i++) ...

// Worse
for (var i in array) ...

객체

// Good
Object.keys(object).forEach(key => {...});

// Bad
var key;
for (key in object) ...

주석

  • 주석은 설명하려는 구문에 맞춰 들여쓰기 합니다. 문장의 끝에 주석을 작성할 경우, 한 줄 주석을 사용하며 공백을 추가 합니다.
  • 사용하지 않거나 의미 없는 주석은 항상 제거해서 커밋 합니다.

공백

  • 키워드, 연산자와 다른 코드 사이에 공백이 있어야 합니다.
// Good
var value;
if (typeof str === 'string') {
  value = (a + b);
}

// Bad
var value;
if(typeof str==='string') {
  value=(a+b);
}
  • 콤마 다음에 값이 올 경우 공백이 있어야 합니다.
// Good
var arr = [1, 2, 3, 4];

// Good
someFunction(a, b, {
  prop1: 1,
  prop2: 2,
  prop3: 3
});

// Bad - 괄호 안에 공백
if ( typeof str === 'string' )

// Bad - 괄호 안 공백, 콤마 뒤 공백 없음
var arr = [ 1,2,3,4 ];

// Bad - 객체의 닫는 괄호 다음에 개행
someFunction(a, b, {
        prop1: 1,
        prop2: 2,
        prop3: 3
    }
);

삼항 연산자 사용

  • 간단한 if 문의 경우 삼항 연산자 사용 합니다.
condition ? 'a' : 'b'

null 병합 연산자

  • 데이터에서 undefined 나 null 이 있을거라고 예상되는 경우, null 병합 연산자를 활용합니다.
const data = undefined;

const result = a ?? 'a'; // a 가 undefined 이거나 null 일 경우 'a' 를 리턴

옵셔널 체이닝

  • 서버 데이터가 undefined 일 경우를 예측하며 코딩 합니다.
const { data: subscription } = useSubscription();

<div>{subscription?.count}</div>

Boolean 캐스팅

  • Boolean 으로 타입 캐스팅이 필요한 경우 Wrapper 클래스를 활용하지 않고 !! (double negation) 를 활용합니다.
  • array.length 를 조건으로 사용할 경우 0 을 리턴하는 수를 참고하세요.
// Good
const condition = !!array.length;

// Bad
const conditon = new Boolean(array.length);

Number 캐스팅

  • Number 타입으로 캐스팅이 필요한 경우엔 Wrapper 클래스인 Number 를 활용할 수 있습니다.
const number = Number('1');
cosnt number = +'1';

조건문

  • if 문을 통해 조건 제어를 사용할 땐 항상 중괄호 를 사용합니다.
// Bad
if (condition) return;

// Good
if (condition) {
  return;
}

데이터형 확인하기

  • 암묵적 캐스팅으로 인한 혼동을 막기 위해 완전항등연산자인 ===, !== 만을 사용합니다.
  • 예외: null 또는 undefined를 한번에 확인
//[문자열]
typeof variable === 'string'

//[숫자]
typeof variable === 'number'

//[불린]
typeof variable === 'boolean'

//[객체]
typeof variable === 'object'

//[배열]
Array.isArray(arrayObject)

//[널 Null]
variable === null

//[미할당 Undefined]
typeof variable === 'undefined'
variable === undefined

//[null || undefined]
variable == undefined

//[엘리먼트 노드]
element.nodeType === 1

사용하지 않습니다!

  • 원시 래퍼 생성자는 절대 사용하지 않습니다. (Boolean, String, ...)
    • Number 클래스는 예외적으로 사용을 허용합니다.
  • eval 을 절대 사용하지 않습니다.
  • with 문 을 절대 사용하지 않습니다.

참고: https://ui.toast.com/fe-guide/ko_CODING-CONVENTION!

profile
안녕하세요! 주니어 웹 개발자입니다 😆

0개의 댓글