"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > Linting을 통한 코드 품질 향상

Linting을 통한 코드 품질 향상

2024-11-06에 게시됨
검색:852

Whenever I start a new project, one of the first things I do is put in place a code linter. For the uninitiated, linters analyze your project and call out potential issues. They can provide guidance on everything from how much spacing is used between lines to specific implementation details, such as restricting the usage of certain patterns and habits. You can take these tools one step further by making them part of your CICD workflow, so your build fails if it detects non-compliant code.

Improving Code Quality with Linting

To many, this may seem like a hassle, but depending on the scale of the project and the number of people working on it, using these tools is a way to standardize shared best practices and opinions across a whole team. After all, everyone is opinionated when it comes to writing code. You can take two completely different code bases written in the same language, and neither would look the same. In JavaScript, there are multiple ways to write the same thing. There are various ways of writing loops, defining functions, and even variables. As more people work on the same code base, their opinions come with them, and without a way to standardize, you'll soon end up in a hellhole of pull requests where people constantly leave unproductive "/nitpick" comments for basic things. 

Linting and Formatting JavaScript

Setting up these types of tools is typically straightforward; you'll install a package, often from a registry, and then run something either on the command line or directly within your IDE with the help of a plugin.

One prevalent linting option for JavaScript is ESLint. ESLint is based on a shared configuration file you provide in your repository. Let's look at a relatively simple example of a configuration that inherits a series of grouped recommended rules for best practices. The community drives these recommended rules and even provides a mechanism for auto-fixing some of them with the –-fix flag.

import js from '@eslint/js';
import globals from 'globals';

export default [
  js.configs.recommended,
  {
    languageOptions: {
      ecmaVersion: 12,
      globals: {
        ...globals.browser,
      },
    },
  }
];

In addition to using the recommended rules, I also like to expand on them by adding several optional, more opinionated rules. For example, I'm not too fond of functions with many parameters as I've found that in the past, they can cause problems and generally become hard to follow, so in most of the codebases I work on, I enforce this using the max-params rule. I also like to ensure that my code is formatted a certain way, so I use the Prettier plugin to ensure that everything matches my Prettier config file, preventing discrepancies around commas and spacing.

import js from '@eslint/js';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
import globals from 'globals';

export default [
  js.configs.recommended,
  eslintPluginPrettierRecommended,
  {
    languageOptions: {
      ecmaVersion: 12,
      globals: {
        ...globals.browser,
      },
    },
  },
  {
    rules: {
      'max-params': ['error', 3],
      'no-unused-vars': 'error',
    },
  },
];

With this configuration, the following function will flag an error directly in my IDE or when I run ESLint via the command line, as it does not adhere to my max-param restrictions or the prettier configuration. If I were to run the linter in my CICD workflow, it would cause the build to fail, preventing me from merging it upstream, which is crucial if we want to ensure our shared branches are always in a good state.

const fetchData = async (endpoint, token, headers, params) => {
  try {
          const response = await fetch(endpoint, {
      headers: Object.assign({
        Authorization: `Bearer ${token}`
      }, headers),
      params
    });

const data = await response.json();


const newData = {
      ...data,
    additionalProperty: 'newValue',
    };

                return newData;
  } catch (error) {
    console.error('Error fetching data:', error);
  }
};

fetchData('https://api.example.com', 'token', { 'Content-Type': 'application/json' }, { page: 1 });
/Users/jives/fetch.js
   1:60  error  Async arrow function has too many parameters (4). Maximum allowed is 3                                                                                                                                                                  max-params
   2:3   error  Delete `··`                                                                                                                                                                                                                             prettier/prettier
   2:11  error  'cat' is assigned a value but never used                                                                                                                                                                                                no-unused-vars
   3:3   error  Delete `··`                                                                                                                                                                                                                             prettier/prettier
   4:1   error  Delete `········`                                                                                                                                                                                                                       prettier/prettier
   5:1   error  Replace `········headers:·Object.assign(` with `······headers:·Object.assign(⏎········`                                                                                                                                                 prettier/prettier
   6:43  error  Insert `,`                                                                                                                                                                                                                              prettier/prettier
   7:11  error  Replace `·headers)` with `⏎········headers`                                                                                                                                                                                             prettier/prettier
   8:7   error  Replace `··params` with `),⏎······params,`                                                                                                                                                                                              prettier/prettier
   9:1   error  Replace `······` with `····`                                                                                                                                                                                                            prettier/prettier
  10:1   error  Replace `······⏎` with `⏎··`                                                                                                                                                                                                            prettier/prettier
  12:1   error  Delete `··`                                                                                                                                                                                                                             prettier/prettier
  13:5   error  Delete `··⏎······`                                                                                                                                                                                                                      prettier/prettier
  15:7   error  Replace `········additionalProperty:·'newValue'` with `additionalProperty:·'newValue',`                                                                                                                                                 prettier/prettier
  16:1   error  Replace `······` with `····`                                                                                                                                                                                                            prettier/prettier
  17:1   error  Delete `··`                                                                                                                                                                                                                             prettier/prettier
  18:5   error  Delete `··············`                                                                                                                                                                                                                 prettier/prettier
  19:1   error  Replace `····` with `··`                                                                                                                                                                                                                prettier/prettier
  20:1   error  Delete `··`                                                                                                                                                                                                                             prettier/prettier
  21:3   error  Delete `··`                                                                                                                                                                                                                             prettier/prettier
  22:1   error  Delete `··`                                                                                                                                                                                                                             prettier/prettier
  23:1   error  Delete `··`                                                                                                                                                                                                                             prettier/prettier
  24:1   error  Replace `··fetchData('https://api.example.com',·'token',·{·'Content-Type':·'application/json'·},·{·page:·1·});` with `fetchData(⏎··'https://api.example.com',⏎··'token',⏎··{·'Content-Type':·'application/json'·},⏎··{·page:·1·},⏎);⏎`  prettier/prettier

✖ 23 problems (23 errors, 0 warnings)

If I resolve these issues, I no longer get an error, and the build will pass.

const fetchData = async ({ endpoint, token, headers, params }) => {
  try {
    const response = await fetch(endpoint, {
      headers: {
        Authorization: `Bearer ${token}`,
        ...headers,
      },
      params,
    });

    const data = await response.json();

    const newData = {
      ...data,
      additionalProperty: 'newValue',
    };

    return newData;
  } catch (error) {
    console.error('Error fetching data:', error);
  }
};

fetchData({
  endpoint: 'https://api.example.com',
  token: 'token',
  headers: { 'Content-Type': 'application/json' },
  params: { page: 1 },
});

Linters can also be a great way to reinforce good habits. For example, having a linting rule in your project for no unused variables can be a great way to teach the practice of not leaving unused references in code. As a maintainer, it improves your quality of life, and it's one less thing you'll need to consider during the pull request process. You can even use a linter to enforce that any types aren't used in TypeScript and other harmful practices that can cause bugs in your code.

Over time, your configuration file will evolve as you form best practices and needs amongst your team; you may decide to add or even remove unnecessary rules. The ultimate goal is more approachable code and less wasted time—what's not to like?

You Can and Should Lint CSS

You can even lint your stylesheets if you're working with CSS. One of my favourite tools for that is Stylelint. Similar to ESLint, it's configuration-based and lets you define what rules you want to include, it also has a recommended configuration that you can extend from.

{
  "extends": "stylelint-config-standard"
}

For example, linting CSS can be beneficial in cases where you need to support legacy browsers. Downgrading JavaScript is pretty common, but it's not always as simple for CSS. Using a linter allows you to be honest with yourself by flagging problematic lines that won't work in older environments, ensuring your pages look as good as possible for everyone.

{
  "extends": "stylelint-config-recommended",
  "plugins": [
    "stylelint-no-unsupported-browser-features"
  ]
  "rules": {
    "plugin/no-unsupported-browser-features": [true, {
      "browsers": ["Chrome >= 66"]
    }]
  }
}

Using this Stylelint plugin, the following CSS would flag an error as you can't use flex-gap in older Chrome versions. These properties are commonplace in modern codebases and can be easily missed if you're not testing older browsers. You can catch these issues with a linter before they become a problem.

.container {
  align-items: center;
  display: flex;
  gap: 10px;
  justify-content: center;
}
[js] src/styles.css
[js]    4:1  ✖  Unexpected browser feature "flexbox-gap" is not supported by Chrome 66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83  plugin/no-unsupported-browser-features

CSS linting can also be leveraged to ensure that you stick to a single unit of measurement for things like font sizes and even enforce the usage of CSS variables for certain property types, like colours and padding. These rules go a long way to providing consistency, especially when you may have multiple views or components.

Lint Early, Lint Often

Creating a baseline set of standards around linting at the start of a project is much easier. Adapting code as you write is much more straightforward than retrofitting an existing project. If you're starting a new project and already have another application that uses a linter, add the same ruleset to your new one and adapt it as you go along. Just because it's harder to adapt a linter to something already established doesn't make it any less worth it, though; it's just more of a time sink.

Most linters allow you to mark a rule as a warning or an error; warnings inform you of the problem when the linter is run, whereas an error will break your build pipeline, preventing it from going any further. I typically avoid setting any rules as a warning unless I am actively migrating code to where I can turn it on as an error. My process is usually:

  1. Determine what rules should be enabled, discuss with your team if you're not working solo.
  2. Enable the rule as a warning.
  3. Fix the code that is flagging the warning.
  4. Enable the rule as an error once all the warnings are resolved.
  5. Avoid lint-ignore comments unless absolutely necessary.

I've made the mistake of doing large refactors to turn on linting rules and broken things. Play it safe and slowly make changes over time to avoid unnecessary headaches.

Closing Notes

Linting is a great way to ensure that your codebase is consistent and that you're following best practices; many options are available for different languages and frameworks that you can find with a quick search. They can be a pain to set up for established projects, but the benefits far outweigh the initial setup time. It's also a great way to reinforce good habits and ensure your codebase is clean and maintainable. If you're not already using a linter, I highly recommend you start. It's a small change that can positively impact your quality of life as a developer.

릴리스 선언문 이 글은 https://dev.to/jamesives/improving-code-quality-with-linting-4no1?1에서 복제됩니다. 침해 내용이 있는 경우, [email protected]으로 연락하여 삭제하시기 바랍니다.
최신 튜토리얼 더>
  • PHP 디자인 패턴: 어댑터
    PHP 디자인 패턴: 어댑터
    어댑터 디자인 패턴은 호환되지 않는 인터페이스를 가진 개체가 함께 작동할 수 있도록 하는 구조적 패턴입니다. 두 개체 사이의 중개자(또는 어댑터) 역할을 하여 한 개체의 인터페이스를 다른 개체가 예상하는 인터페이스로 변환합니다. 이를 통해 원래 코드를 수정하지 않고도 ...
    프로그램 작성 2024-11-06에 게시됨
  • PHP의 WebSocket 이해
    PHP의 WebSocket 이해
    WebSocket은 단일 TCP 연결을 통해 실시간 전이중 통신 채널을 제공합니다. 클라이언트가 서버에 요청을 보내고 응답을 기다리는 HTTP와 달리 WebSocket은 여러 요청 없이도 클라이언트와 서버 간의 지속적인 통신을 허용합니다. 이는 채팅 애플리케이션, 실시...
    프로그램 작성 2024-11-06에 게시됨
  • Visual Studio 2012에서는 어떤 C++11 기능이 지원됩니까?
    Visual Studio 2012에서는 어떤 C++11 기능이 지원됩니까?
    Visual Studio 2012의 C 11 기능최근 Visual Studio 2012 미리 보기 버전이 출시되면서 많은 개발자들이 C 11 기능 지원에 대해 궁금해하고 있습니다. Visual Studio 2010은 이미 부분적인 C 11 지원을 제공했지만 새 버전에서...
    프로그램 작성 2024-11-06에 게시됨
  • Windows 시작 시 Python 스크립트를 자동으로 실행하려면 어떻게 해야 합니까?
    Windows 시작 시 Python 스크립트를 자동으로 실행하려면 어떻게 해야 합니까?
    Windows 시작 시 Python 스크립트 실행Windows가 시작될 때마다 Python 스크립트를 실행하는 것은 작업을 자동화하거나 필수 프로그램을 시작하는 데 매우 중요합니다. 여러 접근 방식은 다양한 수준의 사용자 정의 및 사용자 제어를 제공합니다.스크립트 실행...
    프로그램 작성 2024-11-06에 게시됨
  • Astral.CSS 탐색: 웹 디자인을 혁신하는 CSS 프레임워크.
    Astral.CSS 탐색: 웹 디자인을 혁신하는 CSS 프레임워크.
    빠르게 변화하는 웹 개발 세계에서 프레임워크는 개발자가 시각적으로 매력적이고 기능적인 웹 사이트를 효율적으로 만드는 데 도움이 되는 중추적인 역할을 합니다. 현재 사용 가능한 다양한 프레임워크 중에서 Astral CSS는 독특한 디자인 철학과 사용 용이성으로 인해 단연...
    프로그램 작성 2024-11-06에 게시됨
  • ESnd Arrow 함수에 대한 종합 가이드
    ESnd Arrow 함수에 대한 종합 가이드
    ES6 소개 ECMAScript 2015(ES6(ECMAScript 6)라고도 함)는 JavaScript에 대한 중요한 업데이트로, 코딩을 더욱 효율적이고 관리하기 쉽게 만드는 새로운 구문과 기능을 도입합니다. JavaScript는 웹 개발에 사용되는 ...
    프로그램 작성 2024-11-06에 게시됨
  • 알고리즘 및 데이터 구조 탐색: 효율적인 프로그래밍의 기초
    알고리즘 및 데이터 구조 탐색: 효율적인 프로그래밍의 기초
    이번 게시물 시리즈에서는 학술 환경과 대규모 기술 회사에서 널리 논의되는 두 가지 주제인 알고리즘과 데이터 구조에 대한 학습 여정을 공유하겠습니다. 이러한 주제는 언뜻 보기에 어려운 것처럼 보일 수 있지만, 특히 다른 직업적 어려움으로 인해 경력 전반에 걸쳐 해당 주제...
    프로그램 작성 2024-11-06에 게시됨
  • Go 프로그램의 고루틴 수를 프로파일링하기 위해 pprof를 어떻게 사용합니까?
    Go 프로그램의 고루틴 수를 프로파일링하기 위해 pprof를 어떻게 사용합니까?
    pprof를 사용하여 고루틴 수 프로파일링Go 프로그램에서 잠재적인 고루틴 누출을 감지하려면 시간이 지남에 따라 활성화된 고루틴 수를 모니터링해야 합니다. 표준 go 도구 pprof 명령은 차단에 대한 통찰력을 제공하지만 고루틴 수를 직접적으로 다루지는 않습니다.고루틴...
    프로그램 작성 2024-11-06에 게시됨
  • 클래스 메서드를 콜백으로 전달하는 방법: 메커니즘 및 기술 이해
    클래스 메서드를 콜백으로 전달하는 방법: 메커니즘 및 기술 이해
    클래스 메서드를 콜백으로 전달하는 방법배경일부 시나리오에서는 효율적인 작업을 위해 클래스 메서드를 다른 함수에 대한 콜백으로 전달해야 할 수도 있습니다. 특정 작업의 실행. 이 문서에서는 이를 달성하기 위한 다양한 메커니즘을 안내합니다.호출 가능 구문 사용함수를 콜백으...
    프로그램 작성 2024-11-06에 게시됨
  • 웹 스크래핑 - 흥미롭네요!
    웹 스크래핑 - 흥미롭네요!
    멋진 용어: CRON = 지정된 간격으로 작업을 자동으로 예약하는 프로그래밍 기술 웹 뭐? 프로젝트 등을 조사할 때 일반적으로 일기, 엑셀, 문서 등 다양한 사이트에서 정보를 작성합니다. 우리는 웹을 스크래핑하고 수동으로 데이터를 추출하고 있습니다. 웹...
    프로그램 작성 2024-11-06에 게시됨
  • 사용후기 그리드 섹션
    사용후기 그리드 섹션
    ? CSS 그리드를 배우면서 이 추천글 그리드 섹션 구축을 완료했습니다! ? 그리드는 구조화된 레이아웃을 만드는 데 적합합니다. ? 라이브 데모: https://courageous-chebakia-b55f43.netlify.app/ ? GitHub: https://gi...
    프로그램 작성 2024-11-06에 게시됨
  • REGISTER_GLOBALS가 PHP의 주요 보안 위험으로 간주되는 이유는 무엇입니까?
    REGISTER_GLOBALS가 PHP의 주요 보안 위험으로 간주되는 이유는 무엇입니까?
    REGISTER_GLOBALS의 위험REGISTER_GLOBALS는 모든 GET 및 POST 변수를 PHP 스크립트 내에서 전역 변수로 사용할 수 있도록 하는 PHP 설정입니다. 이 기능은 편리해 보일 수 있지만 잠재적인 보안 취약성 및 코딩 관행으로 인해 사용을 권장...
    프로그램 작성 2024-11-06에 게시됨
  • Nodemailer 개요: Node.js에서 간편한 이메일 보내기
    Nodemailer 개요: Node.js에서 간편한 이메일 보내기
    Nodemailer는 이메일 전송을 위한 Node.js 모듈입니다. 간략한 개요는 다음과 같습니다. Transporter: 이메일 전송 방법을 정의합니다(Gmail, 사용자 정의 SMTP 등을 통해). const transporter = nodemailer.cre...
    프로그램 작성 2024-11-06에 게시됨
  • JavaScript의 간편한 오류 처리: 안전 할당 연산자가 코드를 단순화하는 방법
    JavaScript의 간편한 오류 처리: 안전 할당 연산자가 코드를 단순화하는 방법
    JavaScript의 오류 처리는 지저분할 수 있습니다. try/catch 문으로 큰 코드 블록을 래핑하는 것은 효과적이지만 프로젝트가 커짐에 따라 디버깅은 악몽이 됩니다. 다행히 더 좋은 방법이 있습니다. 안전 할당 연산자(?=)를 입력하세요. 오류를 처리하는 보다 ...
    프로그램 작성 2024-11-06에 게시됨
  • Javascript는 어렵습니다(ESadness 포함).
    Javascript는 어렵습니다(ESadness 포함).
    읽기에는 길겠지만 다시 한 번 말씀드리겠습니다. JAVASCRIPT는 어렵습니다. 마지막으로 만났을 때 저는 밝은 눈을 가진 희망에 찬 코더가 "얼마나 힘들 수 있니?"라고 말하면서 야생 정글에 들어서면서 자바스크립트의 세계로 들어서고 있었습니다. ...
    프로그램 작성 2024-11-06에 게시됨

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3