정적 분석

study, share · 2018-10-24

← 리스트로

정적 분석

목차

  • 개요
    • 정적 분석 도구의 역할
    • 대표적인 정적 분석 도구
  • ESLint
    • eslint 설치 방법
    • 사용법
  • Prettier
    • prettier 설치 방법
    • 사용법

개요

Javascript는 다른 언어에 비해 유연한 문법구조(동적 타입핑, this바인딩, 네이티브 객체 변경 가능)를 가지고 있기 때문에 협업자 간의 코드 의도 파악이나 오류 파악이 힘들다. 이러한 부분의 해결 방법으로 협업자 간에 코딩 컨벤션을 준수하면 가독성과 유지보수에 도움이 되며 성능에 영향을 주거나 버그를 유발하는 안티코드가 미연에 방지된다. 하지만 Javascript는 컴파일 단계가 없어서 코드를 실행하기 전까지는 오류를 확인할 수 없으며, 코딩 컨벤션이 있어도 협업자들이 코딩 컨벤션을 잘 따르고 있는지 검증할 수 없다. 정적 분석을 이용하면 코딩 컨벤션에 대한 검증을 자동화할 수 있으며 문법 오류나 오타 등의 잠재적인 에러를 찾아내기 쉽다.

정적 분석 도구의 역할

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

대표적인 정적 분석 도구

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

ESLint

ESLint는 니콜라스 자카스(Nicholas C. Zakas)가 만든 도구로 최근 가장 널리 사용되고 있으며 특히 누구나 알만한 소프트웨어 기업인 Airbnb, PayPal, facebook 등에서 적극 사용됨으로 신뢰할 수 있다. Javascript 파서 Espree를 사용해 AST(Abstract Syntax Tree)를 만들어 코드를 직접 평가하는 것으로 알려져 있고 방대한 규칙(Rule), 다양한 환경, 포맷터를 지원한다. 규칙이나 포매터를 직접 만들 수 있는 기능도 제공하기 때문에, 프로젝트의 특성에 따라 다양한 방식으로 커스터마이징할 수 있다. 자세한 규칙이나 데모는 연결된 링크를 통하여 확인할 수 있다.

eslint 설치 방법

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

npm install --save-dev eslint

사용법

각종 편집기에서도 eslint가 통합되어 있는 경우가 많다. 설정 파일을 만들어 두면 프로젝트마다 다른 규칙을 가지고 정적 분석을 수행할 수가 있다. 이 경우 편집기는 프로젝트 폴더에 설정된 eslint 규칙을 읽어 들여 편집기에 오류를 바로 표시해 줌으로써 상당히 도움이 된다. 또한 웹팩과 같은 번들러에 통합하여 development 모드와 production 모드에서 다르게 동작시킬 수가 있으며 특히 production 모드에서 에러 레벨 이상이 정적 분석에서 발생할 경우 빌드 과정을 중단시키도록 할 수도 있다.

옵션

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

CLI 사용방법

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

npx eslint --init

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

npx eslint a.js

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

2015-03-05 3 40 04

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

추가적인 옵션들은 ESLint 공식 사이트(http://eslint.org/docs/command-line-interface/)에서 자세한 설명을 볼 수 있다.

프로젝트 적용방법

1. .eslintrc.js 파일 생성 (앞에서 설명한 CLI의 --init 옵션을 통해 대략적인 기본 규칙을 설정할 수도 있다)

  1. parserOptions속성 - 지원하려는 Javascript 언어 옵션을 지정할 수 있다 ecmaVersion, sourctType, ecmaFeature 등을 지정할 수 있으며 자세한 옵션은 여기 에서 확인할 수 있다.
  2. env속성 - 코드가 실행되는 환경을 지정할 수 있다. 예시에서는 browser, es6, jasmine을 설정하였다.
  3. extends속성 - 미리 지정해 놓은 규칙 세트를 사용할수 있다. 예시에서는 FE개발랩 내에서 정한 규칙 세트(eslint-config-tui)를 설정하고 있다. (2. 이미 잘 정의된 eslint 규칙을 활용하기에 보다 자세히 설명하였다.)
  4. rules속성 - extends에서 지정한 규칙세트에서 새로운 규칙을 확장하거나 재정의 할 수 있다. 예시에서는 문장의 끝에 세미콜론을 강제하는 규칙(semi) 을 적용하여 세미콜론의 적용여부를 지정하였다. 또한 들여쓰기규칙(indent)으로 2 space를 지정하였고 옵션으로 switchCase(swith문에서 적용여부), ignoreComments(주석 줄에서의 적용여부), ImportDeclaration(import문에서의 들여쓰기 수준) 을 true로 설정하고 있다.

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

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
  }
};

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

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

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

eslint-congfig 사용 방법은 사용하고 싶은 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의 module 시스템을 사용하면 아래와 같이 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


데모 Demo 페이지는 연결된 링크를 통하여 확인할 수 있다.

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에 Prettier를 통합하는 것이 수월하며 단지 eslint-plugin-prettier를 설치하는 것 만으로 쉽게 통합하여 사용할 수 있다. 이 장에서는 Prettier 설정 파일을 추가하고 ESLint에 통합하여 사용하는 부분까지 알아보기로 한다.

설정파일 추가하기

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

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

{
  "trailingComma": "none",
  "printWidth": 120,
  "singleQuote": true,
  "bracketSpacing": false,
  "tabWidth": 2,
  "jsxBracketSameLine": false
}
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"
  }
};
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규칙의 중복되는 규칙을 해제한 구성을 사용하도록 도와준다.

권장 설정을 이용하여 불필요한 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 사용방법은 공식 문서에서 확인할 수 있다.