Upgrade to Pro — share decks privately, control downloads, hide ads and more …

チーム開発における自作ESLintルールの活用と戦略

SansanTech
PRO
September 12, 2023

 チーム開発における自作ESLintルールの活用と戦略

■イベント
TypeScriptを活用した型安全なチーム開発
https://sansan.connpass.com/event/292695/

■登壇概要
タイトル:チーム開発における自作ESLintルールの活用と戦略
登壇者:技術本部 Digitization部 Bill One Entryグループ 薩󠄀田 和弘

■Digitization部 エンジニア 採用情報
https://media.sansan-engineering.com/digitization

SansanTech
PRO

September 12, 2023
Tweet

More Decks by SansanTech

Other Decks in Technology

Transcript

  1. チーム開発における
    ⾃作ESLintルールの活⽤と戦略
    TypeScriptを活⽤した型安全なチーム開発
    Sansan 株式会社
    Digitization部 Bill One Entry Group
    &⽥ 和弘

    View Slide

  2. !⽥ 和弘
    Sansan株式会社
    Digitization部 Bill One Entry Group
    2021年 Sansan中途⼊社。
    以降Bill One Entry Groupとして、請求書のデータ化に向き合う。

    View Slide

  3. はじめに
    (ES)Lint、使っていますか?

    View Slide

  4. はじめに
    (全員の⼿が挙がる予定✋)
    (ES)Lint、使っていますか?

    View Slide

  5. ESLintを使うと⾔っても、さまざまな使い⽅がある。
    - 検索したままにとりあえずルールを⼊れてみる
    - @typescript-eslint
    - eslint-plugin-react
    - 強⼒なルールプリセットを使う
    - eslint-config-airbnb
    - XO
    - チームの癖に合ったルールを設定する/外す
    はじめに

    View Slide

  6. - ESLintのルールを「作る」
    - ⾃作ESLintを使う前に確認するべき点
    - ⾃作ESLintの活⽤と戦略
    本⽇話すこと

    View Slide

  7. ESLintを「使う」から「作る」へ

    View Slide

  8. Lint
    - コードのパターンによって検証を⾏う
    - 静的解析である
    - バグを事前検知する

    View Slide

  9. 環境変数に現在の環境を記載している。それを利⽤する⽅法。
    ルール例
    - nodeEnvは内部的にNODE_ENVの値を取得する
    - 挙動の違いにより、ヒヤリハットが発⽣
    × NG
    - process.env.NODE_ENV
    ○ OK
    - nodeEnv()

    View Slide

  10. 作り⽅
    process.env.NODE_EN
    V
    ASTを探索し、特定のパターンが現れたらエラーを上げる

    View Slide

  11. 実装(実際にはもうちょい多いです)
    MemberExpression(node: MemberExpression & Rule.NodeParentExtension) {
    const { object: parentNode, property: targetProperty } = node;
    const { object: parentObject, property: parentProperty } = parentNode;
    if (
    parentObject.name === "process" &&
    parentProperty.name === "env" &&
    targetProperty.name === "NODE_ENV"
    ) {
    // エラーレポート
    }
    }

    View Slide

  12. ⾃作ESLintルールを作る前に

    View Slide

  13. ⾃作ESLintルールを作る前に
    1. すでに同じルールが作られていないか

    View Slide

  14. - ESLintの持つデフォルトのルールで 266 個
    - eslint-plugin-から始まるnpm packagesは 6500 個以上
    すでに同じルールが作られていないか
    ⼤体の場合解決するためのルールは存在する

    View Slide

  15. すでに同じルールが作られていないか
    ファイル名に関するルール
    ⾃作してみたが、調べてみると存在した。
    - eslint-plugin-unicornのルールの1つ
    - 他にもファイル名に関するLintは多かった
    × NG
    - snake_case_file_name.ts
    - camelCaseFileName.ts
    ○ OK
    - kebab-case-file-name.ts

    View Slide

  16. ⾃作ESLintルールを作る前に
    2. ESLint以外で解決できないか?

    View Slide

  17. - JavaScriptのエコシステムはかなり成熟している
    - TypeScriptの型チェックで⼤概は事⾜りる
    ESLint以外で解決できないか?
    ハンマーだけを持っていたら全てが釘に⾒える

    View Slide

  18. ESLint以外で解決できないか?
    expressのハンドラの型はデフォルトで⾮常に緩い
    × NG ○ OK
    (req: Request) => {
    req.params // => any
    }
    (req:
    Request) => {
    req.params // => { userId: string }
    }
    最初はESLintでRequestの型引数を強制しようと思ったが...。

    View Slide

  19. ESLint以外で解決できないか?
    我々は習慣的にexpressのRequestHandlerを利⽤していた
    type RequestHandler =
    express.RequestHandler;
    const handler: RequestHandler = (req) => {
    req.params // never
    }
    より厳しい型のRequestHandlerを⽤意することで解決した。

    View Slide

  20. ESLint以外で解決できないか?
    加えて@types/express/index.d.ts に下記を記載すると、
    RequestHandlerがdeprecated扱いになり誤って使うことはない
    declare module "Express" {
    /** @deprecated */
    interface RequestHandler {}
    }

    View Slide

  21. ⾃作ESLintルールの活⽤と戦略

    View Slide

  22. ⾃作ESLintルールの活⽤と戦略
    - ESLintでなければならないルール
    - 今まで誰も書いていないルール

    View Slide

  23. Lintとは
    - コードのパターンによって検証を⾏う
    - 静的解析である
    - ロジックに関してはテストで回避する
    - バグを事前検知する
    - 今まで発⽣したバグや、チーム内で統⼀するべきもの
    に対して⾏う
    - フォーマット等例外もある
    ESLintでなければならないルール

    View Slide

  24. 今まで誰も書いていないルール
    我々のチームではArray#reduceを使うケースが有る。
    ⼀⽅でArray#reduceで第⼆引数の値を誤って利⽤してしまう場
    合がある。これを早期発⾒したい。
    const sum = 0;
    [1, 2, 3].reduce((acc, val) => {
    return sum + val; // sumではなくacc
    }, sum);
    // => expected: 6, actual: 3

    View Slide

  25. 今まで誰も書いていないルール
    Array#reduceは「利⽤してはいけない」というルールはよく
    ⾒かける。
    が、第⼆引数を利⽤してはいけないというルールはなかった
    ため作った。

    View Slide

  26. 最も機会があるのは
    「チーム内で発⽣したインシデント」
    に対するルール
    ⾃作ESLintルールの活⽤と戦略

    View Slide

  27. チーム内で発⽣したインシデント
    エラーが発⽣した場合、res.sendがされていなかった。
    結果動作が想定した挙動にならなかった。
    × NG ○ OK
    const handler = (req, res) => {
    try {
    const result = someFunction();
    res.send(result);
    } catch (e) {
    return;
    }
    }
    const handler = (req, res) => {
    try {
    const result = someFunction();
    res.send(result);
    } catch (e) {
    res.sendStatus(500);
    }
    }

    View Slide

  28. チーム内で発⽣したインシデント
    我々のチームの習慣に合わせてルールを作成。
    全てのフローでsendが送られていることを確認している。

    View Slide

  29. チーム内特有のバグ・事象は、仕組みとして⽤意しないと、⼈
    間が注意するしか無い。
    - 古参メンバーがレビューなどを通して⾒つけるしか無い
    - 新⼈メンバーはドキュメントやレビューなどを通して知る
    しか無い
    仕組み化できるのであれば、⼩さな落とし⽳でも避けられる。
    チーム内で発⽣したインシデント

    View Slide

  30. - ESLintのルールを作るという発想を持つ
    - 作るルールは考える
    - すでに同じルールが作られていないか
    - ESLintで本当に解決すべきか?
    - チーム特有の事象はベスト
    - ESLintは基本はコードのパターンに対する注意
    - インシデント・ヒヤリハットの再発防⽌策として仕組
    み化できないか、1つの⼿札として使う
    まとめ

    View Slide

  31. ハンマーを増やす

    View Slide

  32. ESLintを⾜がかりに「エコシステムを活⽤する」
    - VSCode / Vim / Emacsの拡張・プラグイン
    - TypeScript Language Service Plugin
    - 意外に使い所は少ないので使ったことはないけど...。
    ハンマーを増やす

    View Slide

  33. VSCode拡張紹介
    js-teleporter
    JavaScriptのテストと実装を
    ⾏き来する。
    やってることはディレクトリ
    検索なのでJavaScript以外で
    も使えはする。

    View Slide

  34. VSCode拡張紹介
    js-test-outline
    テストケースをリストアップ
    する。
    jest拡張機能にも似たような
    機能があるが、そちらは単純
    にリストアップするわけでは
    ない。

    View Slide

  35. - ESLintのルールを作るという発想を持つ
    - 作るルールは考える
    - すでに同じルールが作られていないか
    - ESLintで本当に解決すべきか?
    - チーム特有の事象はベスト
    - ESLintは基本はコードのパターンに対する注意
    - インシデント・ヒヤリハットの再発防⽌策として仕組
    み化できないか、1つの⼿札として使う
    まとめ

    View Slide