Javascript 코드 품질 [1]

WonCheol Park·2021년 2월 11일

Javascript 기본

목록 보기
5/7

앞으로 사용하게 될 코딩 관례에 대해서 설명할 것이다.

1. Chrome으로 디버깅하기

디버깅: 스크립트 내 에러를 검출해 제거하는 과정

모던 브라우저에서는 브라우저의 개발자 도구 안에 UI형태로 디버깅 툴을 제공하는데, 이를 사용하면 쉽게 디버깅이 가능하다.여기서는 chrome 브라우저에서 제공하는 디버깅 툴을 사용한다.

Source 패널

  • chrome으로 예시페이지를 연다.
  • 개발자 도구를 연다.(window: F12, macOS: Cmd+Opt+I)
  • Sources탭을 연다.

해당 부분에서 파일 탐색 및 파일의 소스 코드를 확인 가능하다.

콘솔(console)

개발자 도구 하단부에 이러한 콘솔 창이 있다. 여기에 명령어를 입력하고 Enter를 누르면 입력한 명령어가 실행된다.
테스트를 해보고싶은 간단한 코드의 경우 해당 콘솔에서 테스트 가능하다.

중단점(breakpoint)

예시페이지Sources 탭에서 hello.js스크립트 코드를 확인해본다.

코드가 아닌 줄 번호를 클릭하면 위 처럼 중단점을 추가할 수 있다.
중단점(breakpoint)는 자바스크립트 실행이 중단되는 코드 지점을 지정한다는 뜻이다.

이를 통해 중단된 시점의 변수값, 중단된 시점 기준으로 새로운 명령어 실행 등의 디버깅 작업이 가능해진다.
더 자세한 작업은 Breakpoints 탭에서 핸들링 가능하다.

조건부 중단점(Conditional breakpoint)


줄 번호 오른쪽 클릭으로 조건부 중단점(conditional breakpoint)를 선언할 수도 있다.
조건부 중단점은 변수에 특정 값에 따라 실행을 중단시킬 수 있어 디버깅 시 유용하게 사용 가능하다.

debugger 명령어

스크립트에 debugger 명령어를 추가해 breakpoint를 설정한 것과 같은 효과를 볼 수 있다.

function hello(name) {
  let phrase = `Hello, ${name}!`;

  debugger;  // <-- 여기서 실행이 멈춥니다.

  say(phrase);
}

멈추면 보이는 것들

중단점을 설정했으면 F5(Windows, Linux)나 Cmd+R(macOS)를 통해 새로고침하여 breakpoint를 확인해보자.
중단점을 설정한 곳에서 코드 실행이 멈추게 된다.

이 상태로 하단 탭의 메뉴들을 살펴보자.

  1. Watch: 표현식을 평가하고 결과를 보여준다.
    + 버튼으로 표현식을 입력하면 중단 시점에서의 값을 확인할 수 있다.
    입력한 표현식은 실행 도중 계속 재평가된다.

  2. Call Stack: 코드 중단점까지 실행한 경로를 역순으로 보여준다.
    index.html > hello 함수 > say 함수 순서대로 호출되었기 때문에 다음과 같은 순서로 Call stack이 나온다.

  3. Scope: 현재 정의된 모든 변수를 보여준다.
    Local: 지역 변수를 보여준다.
    Global: 전역 변수를 보여준다.
    Local하위에 this정보도 있는데, 이는 추후 공부하겠다.

실행 추적하기

디버깅 영역 상단의 버튼으로 실행 단계마다의 일을 추적하는 방법을 설명한다.

  1. Resume: 중단된 스크립트를 다시 실행한다.(F8)
    다음 중단점까지 이동하거나, 이후 중단점이 없으면 스크립트를 끝까지 실행시키고 종료한다.
  2. Step: 다음 명령어를 실행한다.(F9)
    스크립트를 문 단위로 하나씩 실행할 수 있다.
  3. Step over: 다음 명령어를 실행하되, 함수 안으로는 들어가지 않는다.(F10)
    Step과 유사하지만 다음 실행할 문이 함수인 경우 Step과 다르게 동작한다.(alert같은 내장함수의 경우는 해당하지 않고, 직접 작성한 함수인 경우만 동작이 다르다.)
    Step은 함수 내부로 들어가 함수 본문의 첫 줄에서 실행을 멈추지만, Step over는 내부적으로 함수를 실행하고 함수 실행이 끝난 직후 멈춘다.
    Step over는 함수 호출 시 함수 내부의 동작은 궁금하지 않는 경우 사용한다.
  4. Step into: Step과 유사하나 비동기 동작의 경우 동작에 차이가 있다.(F11)
    Step은 setTimeout같은 비동기 동작을 무시하나, Step into는 비동기 동작을 담당하는 코드를 진입하고, 필요한 경우 비동기 동작이 완료될 때까지 대기한다.
  5. Step out: 실행중인 함수의 끝까지 실행한다.(Shift+F11)
    현재 실행중인 함수 실행을 계속하다, 함수 본문 마지막 줄에서 실행을 멈춘다.
    실수로 Step으로 내부 동작을 알고싶지 않은 함수로 진입했거나, 실행중인 함수부분을 빨리 탈출하고 싶을 때 사용한다.
  6. 모든 중단점 활성화/비활성화
    모든 중단점을 일시적으로 활성화/비활성화한다.
  7. 예외 발생 시 코드를 자동 중지시켜주는 기능 활성화/비활성화
    에러와 함께 스크립트가 죽은 경우, 이 옵션을 활성화한 후 새로고침하면 에러 발생 시점의 컨텍스트를 확인할 수 있다.

Continue to here 옵션
특정 줄에서 마우스 우클릭으로 "Continue to here"옵션을 확인할 수 있다.
그냥 해당 줄까지 그대로 실행하는 옵션으로, breakpoint를 따로 설정하기 귀찮을 때 유용하게 사용할 수 있다.

console.log

console.log 함수를 통해 원하는 값을 콘솔에 출력할 수 있다.

// 콘솔창을 열어 결과를 확인해 보세요.
for (let i = 0; i < 5; i++) {
  console.log("숫자", i);
}

위와 같이 콘솔을 사용할 수 있다.

2. 코딩 스타일

개발자는 가능한 간결하고 읽기 쉽게 코드를 작성해야 한다.
좋은 코드 스타일은 이를 도와준다.
아래 대부분의 내용들이 prettier + eslint 조합으로 신경쓰지 않고 코딩이 가능하다. 이러한 규칙이 있다는 점만 알고 실제로 적용할 때는 auto formatting으로 코드 포맷을 맞추면 될 것이다.

문법


이러한 규칙들이 있는데 위 상세 규칙들이 생긴 이유를 소개한다.

무조건 따라야 하는 규칙은 없다.
스타일에 따라서, 선호하는 방식에 따라서 규칙을 따를 수도 있고, 따르지 않을 수도 있다.

중괄호

대부분 javascript 프로젝트에서 중괄호는 '이집션(Egyptian)'스타일로 키워드와 같은 줄에 작성한다.
여는 중괄호 앞에 공백이 하나 필요하다.

if (condition) {
  // 코드 1
  // 코드 2
  // ...코드 n...
}

만약 한 줄짜리 구문은 어떻게 다뤄야 할까?

if (n < 0) alert(`Power ${n} is not supported`);

이렇게 한 줄로 사용하는 것도 나쁘지 않고

if (n < 0) {
  alert(`Power ${n} is not supported`);
}

이런식으로 사용하는 방법이 가독성이 좋아 가장 추천된다.

가로 길이

가로로 코드가 길어지면 여러 줄로 나누어 작성해야 한다.

백틱을 통해서 문자열을 여러 줄로 나눌 수 있다.

// 백틱(`)을 사용하면 문자열을 여러 줄로 쉽게 나눌 수 있습니다.
let str = `
  ECMA International's TC39 is a group of JavaScript developers,
  implementers, academics, and more, collaborating with the community
  to maintain and evolve the definition of JavaScript.
`;

if문은 다음과 같이 나눌 수 있다.

if (
  id === 123 &&
  moonPhase === 'Waning Gibbous' &&
  zodiacSign === 'Libra'
) {
  letTheSorceryBegin();
}

최대 가로 길이는 대게 80~120자로 제한하는게 일반적이다.

들여 쓰기

  • 가로 들여쓰기: space 2개 or 4개로 들여쓴다.
    space 갯수 혹은 tab키로 들여쓰는데, 요즘에는 탭 대신 스페이스를 이용하는 경우가 더 많다고 한다.
    space를 사용하면 들여쓰기 정도를 더 유연하게 변경할 수 있다.
show(parameters,
     aligned, // 스페이스 다섯 개를 이용해 들여쓰기 함
     one,
     after,
     another
  ) {
  // ...
}
  • 세로 들여쓰기: 논리 블록 사이에 코드를 분리해주는 새 줄이다.
    다음 예시처럼 변수 선언 부분, 반복문, 리턴문 부분별로 빈 줄을 넣어줘 가독성을 높힐 수 있다.
function pow(x, n) {
  let result = 1;
  //              <--
  for (let i = 0; i < n; i++) {
    result *= x;
  }
  //              <--
  return result;
}

세미콜론

javascript 엔진에 의해 자동으로 구문 끝에 세미콜론을 넣어주지만, 예외 상황도 있으므로 항상 세미콜론을 직접 넣어주는게 좋다.

중첩 레벨

가능한 깊은 중첩문은 사용하지 않도록 한다.
제외되는 상황은 early return하는 방식이나 continue 지시자를 통해서 중첩 레벨을 줄이는게 좋다.

for (let i = 0; i < 10; i++) {
  if (!cond) continue;
  ...  // <- 추가 중첩 레벨이 추가되지 않습니다.
}

함수의 위치

'헬퍼'함수 여러 개를 만들어 사용하는 경우 다음과 같은 방법으로 코드 구조를 정리할 수 있다.

  1. 헬퍼 함수를 사용하는 코드 에서 헬퍼 함수를 모아 선언
// 함수 선언
function createElement() {
  ...
}

function setHandler(elem) {
  ...
}

function walkAround() {
  ...
}

// 헬퍼 함수를 사용하는 코드
let elem = createElement();
setHandler(elem);
walkAround();
  1. 코드를 먼저, 함수는 나중에 선언
// 헬퍼 함수를 사용하는 코드
let elem = createElement();
setHandler(elem);
walkAround();

// --- 헬퍼 함수 ---
function createElement() {
  ...
}

function setHandler(elem) {
  ...
}

function walkAround() {
  ...
}
  1. 혼합: 코드 바로 위에서 필요한 헬퍼 함수 그떄그때 선언

대게 2번째 방법으로 정돈하는 것을 선호한다.
헬퍼 함수 이름을 잘 명명해 함수 역할을 쉽게 유추할 수 있는 상황이면, 함수 본문을 읽을 필요도 없이 코드를 읽어갈 수 있다.

스타일 가이드

코딩 스타일 가이드는 코드를 어떻게 작성할지에 대한 전반적인 규칙을 담은 문서다.
유명한 스타일 가이드 예시이다.

Linter

Linter를 사용하면 내가 작성한 코드가 스타일 가이드에 맞는지 자동으로 확인해준다.
스타일 체크 뿐만 아니라, 변수나 함수의 이름의 오타도 미리 발견할 수 있어 linter 사용을 권장한다.
유명 linter:

  • JSLint: 역사가 오래된 linter
  • JSHint: JSLint보다 셋팅이 더 유연한 linter
  • ESLint: 가장 최근의 linter
    나는 처음부터 ESLint로만 사용중이다.

3. 주석

주석은 코드가 어떻게 혹은 왜 동작하는지에 대한 설명을 추가하는데 쓰인다.
한 줄 짜리 주석은 //로, 여러 줄 짜리 주석은 /* ... */로 쓴다.

좋지 않은 주석

'코드에서 무슨 일이 일어나는지'에 대한 주석이 많아서는 안된다.
기본적으로 주석 없이 코드 자체만으로도 코드가 무슨 일을 하는지 쉽게 이해할 수 있어야한다.
코드가 불분명해서 주석 작성이 꼭 필요한 상태라면, 이는 코드를 다시 작성해야 한다는 뜻일 수 있다.

리팩토링 팁: 함수 분리하기

javascript 기본의 함수파트에서 소수 구하는 함수 내부의 로직을 새로운 함수로 분리해 가독성을 높였다.
함수 이름 자체가 주석 역할을 하므로 코드를 쉽게 이해할 수 있다. 이런 코드를 자기 설명적인(self-descriptive) 코드라고 부른다.

리팩토링 팁: 함수 만들기

다음처럼 코드가 늘어져있는 경우 새로운 함수를 만들고 코드 일부를 새로 만든 함수에 옮기는게 좋다.
before:

// 위스키를 더해줌
for(let i = 0; i < 10; i++) {
  let drop = getWhiskey();
  smell(drop);
  add(drop, glass);
}

// 주스를 더해줌
for(let t = 0; t < 3; t++) {
  let tomato = getTomato();
  examine(tomato);
  let juice = press(tomato);
  add(juice, glass);
}

// ...

after:

addWhiskey(glass);
addJuice(glass);

function addWhiskey(container) {
  for(let i = 0; i < 10; i++) {
    let drop = getWhiskey();
    //...
  }
}

function addJuice(container) {
  for(let t = 0; t < 3; t++) {
    let tomato = getTomato();
    //...
  }
}

함수는 주석이 없어도 존재 이유를 설명할 수 있어야 한다.
그러나 실무에서 '설명이 담긴'주석을 불가피하게 작성해야 하는 경우도 있는데, 알고리즘이 복잡하거나 최적화를 위해 코드를 비틀어 작성하는 경우에는 설명을 작성해주는게 좋다.
이런 경우를 제외하고는 코드 자체만으로도 이해할 수 있어야 한다.

좋은 주석

아키텍처를 설명하는 주석

고차원 수준의 컴포넌트 개요, 컴포넌트 간 상호작용, 상황에 따른 제어 흐름 등은 주석에 넣어주는 것이 좋다. 고차원 수준의 아키텍쳐 다이어그램을 그리는데 쓰이는 언어 UML도 공부해보는걸 추천한다.

함수 용례와 매개변수 정보를 담고 있는 주석

JSDoc이라는 문법으로 함수에 관한 문서를 쉽게 쓸 수 있다. 함수의 용례, 매개변수, 반환 값 정보가 들어간다.

ex)

/**
 * x를 n번 곱한 수를 반환함
 *
 * @param {number} x 거듭제곱할 숫자
 * @param {number} n 곱할 횟수, 반드시 자연수여야 함
 * @return {number} x의 n 거듭제곱을 반환함
 */
function pow(x, n) {
  ...
}

이렇게 주석을 달면 함수의 목적, 사용법을 한 번에 알 수 있다.

왜 이런 방법으로 문제를 해결했는지를 설명하는 주석

문제 해결 방법은 여러 가지 인데 왜 하필 이 방법을 선택했는지 의문이 들 때가 있다.
나중에 코드를 보며 더 올바른 방법이라고 수정한게, 이전에 시도했는데 먹히지 않았던 방법일 수가 있다.
이전의 실수를 방지하는 안내판 역할을 하는 주석이여서 유용하다.

미묘한 기능이 있고, 이 기능이 어디에 쓰이는지를 설명하는 주석

직관적인 부분과 다른 미묘한 동작을 하는 코드가 있다면 주석을 달아주는 것이 좋다.

profile
신입 개발자입니다~

0개의 댓글