정적 분석


자바스크립트는 다른 언어에 비해 유연한 문법구조를 갖는다. 이런 특징이 가끔 뜻하지 않은 문제를 일으킨다. 가령, 문법적 오류가 아니라서 찾기 어려운 버그를 만들거나, 개발자의 의도를 파악하기 어려운 코드를 만들거나, 컴파일 단계가 없어서 코드를 실행하기 전까지는 알 수 없는 오류를 만든다. 코딩 컨벤션을 준수하면 가독성이 좋아지고 안티 패턴의 코드를 예방할 수 있으므로 어느 정도 해결 방법이 될 수 있다. 하지만 개발자가 코딩 컨벤션을 잘 따르고 있는지는 여전히 확인하기 힘들다. 하지만 정적 분석을 이용하면 코딩컨벤션을 자동으로 검증하고 잠재에러를 찾아내 자바스크립트의 단점을 보완한다.

목차

정적 분석 도구

정적 분석 도구의 역할

  • 코드를 정적으로 분석해서 문법 오류나 오타 등의 잠재적 에러를 찾아낸다.
  • 코딩 컨벤션 검증을 자동화할 수 있다.
  • 개발도구와 연동해서 빠른 피드백을 줄 수 있다.

대표적인 정적 분석 도구

  • ESLint : 가장 최근에 만들어졌고, 유연성/확장성 높다.
  • Prettier : 코드 스타일과 자동 포맷팅 기능만을 강조해서 나온 도구이다.
  • JSLint : 더글라스 크록포드가 2002년에 만들었다. 설정이나 확장이 불가능하다.
  • JSHint : JSLint를 발전시켜 설정이나 확장성을 추가하였다.
  • JSCS : 코딩 컨벤션 체커로 ESLint로 통합되었다.

ESLint

ESLint는 니콜라스 자카스(Nicholas C. Zakas)가 만든 도구로 최근 가장 널리 사용된다. 특히 Airbnb, PayPal, facebook 와 같은 대형회사에서도 활발하게 사용될 정도로 신뢰할 수 있는 도구이다. 자바스크립트 구문 분석기인 Espree를 사용해 AST(Abstract Syntax Tree)를 만들어 코드를 직접 평가하는 것으로 알려져 있고 방대한 규칙(Rule) 뿐만 아니라 다양한 환경과 포맷터를 지원한다. 규칙이나 포맷터를 직접 만들 수 있는 기능도 제공하기 때문에, 프로젝트의 특성에 따라 다양한 방식으로 커스터마이징할 수 있다. 자세한 규칙이나 데모는 연결된 링크를 통하여 확인할 수 있다.

설치 방법

npm을 사용하여 간단하게 설치할 수 있다.

npm install --save-dev eslint

사용법

설정 파일을 만들어 프로젝트마다 다른 규칙으로 정적 분석을 수행할 수 있다. ESLint를 지원하는 에디터는 프로젝트 폴더에 설정된 ESLint 규칙을 가지고 코딩 컨벤션을 검증하여 오류를 빠르게 확인하고 수정할 수 있다. 또한 Webpack과 같은 번들러에 통합하여 development 모드와 production 모드에서 다르게 동작시킬 수 있다. 특히 production 모드에서는 경고 레벨 이상의 에러가 정적 분석에서 발생할 경우 빌드 과정을 중단시킬 수 있다.

옵션

옵션은 큰 분류로 Possible Errors, Best Practices, Strict Mode, Variables, Stylistic Issues, ES6로 나누어져 있으며 규칙이 방대하기 때문에 자세한 규칙은 공식 문서에서 확인하기 바란다. .eslintrc.js 설정 파일을 통해 옵션을 적용할 수 있으며 프로젝트 적용 방법에 간략하게 설명하였다. 공식 문서에 보다 상세한 적용 방법이 설명되어 있다.

CLI 사용 방법

ESLint를 사용하기 위해서는 기본 규칙을 포함하는 설정 파일(.eslintrc.js)이 필요하다. 아래와 같이 CLI에서 제공하는 --init 옵션(설정 마법사)을 사용하여 간단하게 설정 파일을 만들 수 있다.

npx eslint --init

이제 CLI를 통해 ESLint를 실행할 수 있다.

npx eslint app.js

CLI를 수행하고 나면 ESLint는 app.js 파일을 정적 분석하여 규칙에 맞지 않는 부분들을 오류로 검출하고 아래와 같이 출력한다.

filterimage

자주 사용되는 CLI옵션으로는 --fix가 있다. --fix를 사용하면 자동으로 잘못된 부분을 수정하여 저장해준다. 자동 저장을 원하지 않고 변경된 부분만 보고 싶다면 --fix-dry-run을 사용할 수도 있다.

더 많은 옵션은 ESLint 공식 사이트에서 자세한 설명을 볼 수 있다.

프로젝트 적용 방법

1. .eslintrc.js 파일을 생성하기

참고 앞에서 설명한 CLI의 --init 옵션을 통해 기본 규칙을 설정할 수도 있다

아래는 설정파일에 간단한 규칙을 적용한 예시이다.

module.exports = {
  parserOptions: {
    sourceType: 'module'
  },
  env: {
    browser: true,
    es6: true,
    jasmine: true
  },
  extends: ['tui'],
  // add your custom rules here
  rules: {
    'indent': [2, 2, {SwitchCase: 1, ignoreComments: false, ImportDeclaration: 1}],
    'semi': 2
  }
};
  • parserOptions속성 지원하려는 자바스크립트 언어 옵션을 지정할 수 있다. ecmaVersion, sourceType, ecmaFeatures 등을 지정할 수 있으며 자세한 옵션은 여기 에서 확인할 수 있다.
  • env속성 코드가 실행되는 환경을 지정할 수 있다. 예시에서는 browser, es6, jasmine을 설정하였다.
  • extends속성 미리 지정해 놓은 규칙 세트를 사용할 수 있다. 예시에서는 FE개발랩 내에서 정한 규칙 세트(eslint-config-tui)를 설정하고 있다. (뒤의 내용인 '2. 이미 잘 정의된 ESLint 규칙을 활용하기' 에 보다 자세히 설명하였다)
  • rules속성 extends에서 지정한 규칙 세트에서 새로운 규칙을 확장하거나 재정의 할 수 있다.

예시에서는 문장 끝에 세미콜론을 강제하는 규칙(semi)을 적용하여 세미콜론의 적용여부를 지정하였다. 또한 들여쓰기규칙(indent)으로 2 space를 지정하였고 옵션으로 switchCase(swith문에서 적용여부), ignoreComments(주석 줄에서의 적용여부), ImportDeclaration(import문에서의 들여쓰기 수준)을 true로 설정하고 있다.

2. 이미 잘 정의된 ESLint 규칙을 활용하기

ESLint는 매우 많은 규칙이 있기 때문에 프로젝트를 시작할 때부터 모든 규칙을 검토하고 적용하기는 어렵다. 구글이나 마이크로소프트, airbnb와 같은 대형 개발회사는 자체 코딩 컨벤션과 그에 따른 ESLint 규칙도 공개하고 있으므로 활용하면 좋다.

FE개발랩에서 사용하는 코딩 컨벤션은 규칙 항목별로 사용 여부를 토론하고 합의를 통해 결정한 규칙이므로 유용한 가이드가 될 수 있다. 잘 정의된 ESLint 규칙도 제공하고 있으므로 활용하면 좋다. FE개발랩의 코딩 컨벤션과 eslint-config-tui는 아래 링크에서 확인할 수 있다.

eslint-config 적용 방법은 사용하고 싶은 config를 npm을 사용해 설치한 후 설정 파일(.eslintrc.js)의 extends 속성에 추가하면 된다. extends 속성 값은 패키지 이름의 접두어인 eslint-config-를 생략할 수 있다.

// config 설치
npm install --save-dev eslint-config-tui
// .eslintrc.js 수정
module.exports = {
  extends: ['eslint-config-tui']
};

위와 같은 추천 설정은 보통 단독으로 사용하지 않고 프로젝트의 기본 속성에 추가로 확장되는 부분임을 잊지 말아야 한다. 상세한 기본 설정 속성들은 앞에서 더 자세히 설명하였다. 프로젝트에서 ECMAScript의 모듈 시스템을 사용하면 아래와 같이 parserOptions.sourceTypemodule로 설정해야 한다.

// .eslintrc.js 수정
module.exports = {
  parserOptions: {
    "sourceType": "module"
  },
  extends: ['eslint-config-tui']
};

또 다른 예로 browser와 ES6의 전역변수를 사용해야 한다면 env 속성을 아래와 같이 추가해야 한다.

// .eslintrc.js 수정
module.exports = {
  parserOptions: {
    "sourceType": "module"
  },
  env: {
    browser: true,
    es6: true
  },
  extends: ['eslint-config-tui']
};

3. 여러 개의 추천 설정을 사용하기 위한 팁

실제 프로젝트에서는 여러 가지 추천 설정을 상속받아서 쓰는 경우가 있다. 아래의 예는 FE개발랩의 ESLint 규칙을 정리한 TOAST UI 규칙vue 프레임워크의 추천 설정을 같이 사용한 모습이다.

module.exports = {
  ..
  extends: ['tui', 'plugin:vue/recommended'],
  ..
};

이처럼 여러 추천 설정이 사용될 때, 뒤에 선언된 규칙이 우선순위가 높다.

4. npm 스크립트 추가하기

package.json

{
  "scripts": {
    "lint": "eslint src"
  }
}

5. CLI 명령 실행하기

npm run lint
npm run lint -- --fix // (자동 수정)

Prettier

Prettier는 다른 정적 분석 도구와 같이 모든 문법 상황을 분석하기보다는 엄격한 코드 스타일에만 초점을 두어 탄생한 도구이다. 가장 큰 장점은 코드 스타일을 자동으로 정리해주기 때문에 이와 관련된 불필요한 노력이 없어지는 것이다. 따라서 개발자는 프로젝트의 코드 스타일에 대한 걱정은 Prettier에게 맡기고 오직 코드의 로직에만 집중할 수 있게 된다. 다만, 포맷팅과 관련된 부분만 도움이 되므로 코드 품질 규칙과 관련해서는 ESLint와 같은 도구와 함께 사용하는 것이 좋다. Prettier는 다양한 언어(Javascript, JSX, Flow, TypeScript, CSS, Less, SCSS, JSON, GraphQL)를 지원하며 대부분의 에디터에서 통합 사용이 가능하다.

아래 이미지는 왼쪽이 포맷팅이 적용되지 않은 코드이고, 오른쪽이 Prettier를 거쳐 자동으로 포맷팅된 코드이다.

demo_image


다음 페이지에서 Prettier를 사용해볼 수 있다.

설치 방법

npm

npm install --save-dev --save-exact prettier
# or globally
npm install --global prettier

yarn

yarn add prettier --dev --exact
# or globally
yarn global add prettier

사용법

에디터에 Prettier를 적용하는 방법

Atom, Emacs, Vim, Visual Studio, Sublime, JetBrains WebStorm 등의 에디터에 통합하여 사용할 수 있다. 에디터의 통합된 플러그인을 설치하면, 소스 코드를 저장하려고 할 때 자동으로 Prettier를 실행한 다음 포맷팅이 변경된 결과를 저장해준다. 자세한 적용 법은 여기를 참고하기 바란다. 아래는 JetBrains WebStorm 에디터에서 파일 저장 시 자동으로 포맷팅해주는 모습이다.

preview

프로젝트에 Prettier를 적용하는 방법

Prettier는 코딩 컨벤션에 대한 논쟁을 없애기 위한 도구이다. 따라서 스타일과 관련된 복잡한 옵션이 없다. 다만 탭 vs 스페이스, 큰따옴표 vs 작은따옴표, 들여 쓰기 수준과 같은 논쟁의 여지가 많은 부분에 대해서만 옵션을 제공하고 있다. 이미 ESlint를 사용한다면 단지 eslint-plugin-prettier를 설치하는 것 만으로 Prettier를 쉽게 통합할 수 있다. 이 장에서는 Prettier 설정파일을 추가하고 ESLint에 통합하여 사용하는 부분까지 알아보기로 한다.

1. 설정파일 추가하기

프로젝트 폴더에 .prettierrc 파일을 만들고 공식 문서를 참고하여 옵션을 만든다. 옵션에 대한 설명은 문서의 마지막에 추가하였다. 사용되는 .prettierrc 파일은 아래와 같은 모습이 될 것이다.

Prettier의 경우 ESLint에 비해 옵션이 많지 않다. 이유는 Prettier는 코드 스타일에 대한 논쟁을 멈추게 하기 위해 만들어졌고, 옵션을 많이 가지고 있을수록 원래의 Prettier을 사용하는 목적에서 더 멀어진다고 여기기 때문이다.

{
  "trailingComma": "none",
  "printWidth": 120,
  "singleQuote": true,
  "bracketSpacing": false,
  "tabWidth": 2,
  "jsxBracketSameLine": false
}

2. ESLint에 플러그인으로 Prettier를 추가하기

Prettier와 ESLint가 같은 문법에 대해서 다르게 처리될 수 있기 때문에 Prettier를 ESLint에 통합하여 사용하는 것이 좋다. eslint-plugin-prettier를 설치하고 .eslintrc.js파일의 프러그인에 추가하는 것 만으로 쉽게 확장하여 사용할 수 있다.

1) eslint-plugin-prettier 를 사용하여 ESLint 규칙에 Prettier를 추가한다.

npm install --save-dev eslint-plugin-prettier

2) .eslintrc.js에 Prettier플러그인을 추가한다.

module.exports = {
  ...
  "plugins": ["prettier"],
  "rules": {
    "prettier/prettier": "error"
  }
};

3. ESLint의 포맷팅 규칙 끄기

ESLint와 Prettier가 포맷팅 규칙을 중복해서 리포팅하기 때문에, ESLint의 포맷팅 관련 옵션은 비활성화하는 것이 좋다. eslint-config-prettier를 설치하면 중복되는 포맷팅 규칙은 비활성화해 줄 수 있다.

다음 예는 함수명 뒤의 공백 규칙에 대하여 ESLint와 prettier가 중복으로 에러를 출력하는 상황을 보여준다. function 뒤의 공백이 없어야 함을 강제하는 ESLint 규칙인 space-before-function-paran error와 prettier의 DELETE '.' error가 중복해서 표시되고 있다.

2018-09-14 4 06 25

아래와 같이 설정하면 중복 리포팅에 대한 혼란을 해소할 수 있다.

1) 아래와 같이 eslint-config-prettier를 설치한다.

npm install --save-dev eslint-config-prettier

2) .eslintrc.js에 Prettier 설정을 추가한다.

module.exports = {
  ...
  "extends": ["prettier"]
};

ESLint는 사용자가 추가로 확장하고 싶은 기능을 직접 만들어 사용할 수 있도록 하는 플러그인을 지원한다. Prettier는 ESLint를 위한 eslint-plugin-prettier플러그인을 제공함으로써 ESLint 규칙으로 Prettier를 실행할 수 있게 하며, eslint-config-prettiereslint-plugin-prettier로 확장된 규칙과 기존 ESLint규칙의 중복되는 규칙을 해제한 구성을 사용하도록 도와준다.

4. 권장 설정을 이용하여 불필요한 config 없애기

아래와 같이 권장 설정을 사용하면 .eslintrc.js의 플러그인 프로퍼티에 prettier를 명시해 주지 않아도 된다. 하지만 이 경우에도 동일하게 eslint-plugin-prettiereslint-config-prettier를 둘 다 설치해줘야 한다. plugin:prettier/recommended는 플러그인에 자동으로 prettier를 추가하고 중복되는 포맷팅 규칙은 비활성화시켜준다.

module.exports = {
  ..
  "extends": ["plugin:prettier/recommended"]
  ..
};

옵션

  1. printWidth - 줄바꿈이 길이를 지정
  2. tabWidth - 들여쓰기 레벨 (공백수)
  3. useTabs - 스페이스 대신 탭으로 들여쓰기
  4. semi - 명령의 끝에 세미콜론여부
  5. singleQuote - 큰따움표 대신 작은따움표 사용
  6. trailingComma - 여러줄 입력시 후행 쉼표 사용
  7. bracketSpacing - 객체 리터럴 괄호 사이에 공백 여부
  8. jsxBracketSameLine - jsx의 닫는 꺽쇄를 홀로 남기지 않게 함
  9. arrowParens - arrow 함수의 파라미터에 괄호를 강제함
  10. parser - 구문 분석기 지정 (사용하는 언어를 설정)
  11. filepath - 구문 분석기 유추를 위한 입력파일 패스지정
  12. requirePragma - pragma 헤더 사용유무
  13. insertPragma - 자동 pragma 헤더 삽입 사용유무
  14. proseWrap - 줄바꿈 적용 여부

각 옵션은 Prettier 공식 문서에서 자세히 볼 수 있다.

CLI 사용 방법

Prettier은 보통 사용하는 에디터에 통합하여 사용하는 경우가 많지만 CLI 환경에서도 실행할 수도 있다. 아래는 CLI로 Prettier를 실행하는 예제이다 (--no-config 옵션을 사용하여 기본 설정으로 실행하고 있다)

prettier --no-config javascriptCode.js

특정 규칙을 추가하여 실행하고 싶을 때는 공식 옵션 문서를 참고하여 인자를 추가하면 된다. 아래 예는 --single-quote로 문자열 선언 시 작은 따옴표를 사용하며 --no-semi로 세미콜론을 생략하도록 코드 스타일을 정의하였고 --write 옵션을 사용하여 변경된 결과를 저장해주고 있다.

prettier --single-quote --no-semi --write javascriptCode.js"

좀 더 자세한 CLI 사용 방법은 공식 문서에서 확인할 수 있다.

맺음말

지금까지 정적 분석에 대해 알아보았다. 정적 분석은 코드의 일관성을 유지하고 버그를 피하기 위해 실행 전에 미리 코드를 분석하는 방법이다. 이 가이드는 정적 분석의 필요성과 도구에 대해 설명하였으며 특히 많이 사용되는 ESLint와 Prettier를 손쉽게 적용할 수 있도록 문서화했다. 이 가이드가 프로젝트에 정적 분석 도구를 보다 쉽게 적용하는데 도움이 되길 바란다.

이 문서는 NHN Cloud의 FE개발랩에서 작성하고 관리하는 공식 웹 프론트 개발 가이드이다. 가이드 적용 관련 문의나 문서의 오류, 개선 제안은 공식 문의 채널(dl_javascript@nhn.com)을 통해 할 수 있다.


Last Modified
2019. 04. 15
FE Development LabBack to list