$30 off During Our Annual Pro Sale. View Details »

そのCIは本当に役に立ってますか?~ 高品質なCIプロセスを実現する設計術 ~

Haruka Sakihara
November 28, 2024
1.6k

そのCIは本当に役に立ってますか?~ 高品質なCIプロセスを実現する設計術 ~

24/11/29 CloudNative Days Winter 2024にて発表
https://event.cloudnativedays.jp/cndw2024/talks/2416

Haruka Sakihara

November 28, 2024
Tweet

Transcript

  1. 自己紹介 Haruka Sakihara <主な取得資格> • ネットワークスペシャリスト試験(IPA) • AWS Certified 13資格

    • Google Cloud Certification 4資格 <所属> • アクセンチュア株式会社 テクノロジー コンサル ティング本部 (2021年新卒入社) • クラウドの部署にいます <趣味> • Go言語が好きです • フィギュアスケートとサンリオも好きです <その他表彰> • 2023 Japan AWS Jr.Champion • 2024 Japan AWS All Certifications Engineer
  2. 今日の話題 話すこと (In Scope) • 快適かつ意味のあるCIを作るための要件 • 各種静的解析SaaSツールへの期待設定・付き 合い方 話さないこと

    (Out of Scope) • 各種静的解析SaaSツールの比較検討 • 具体的にどんな解析ルールを選定・使用する のがいいか • 今静的解析ツールを全く利用していなかっま でた環境にどうやって円滑にツールを導入す るか • 静的解析ツールを使ってコード品質を整える ことで本当に組織の生産性が上がるのか
  3. 2. 静的解析ツールの設定 設定フェーズ一覧 静的解析ツールの良さを生かすためには、実行・設定の際に以下のフェーズを意識するとよいでしょ う。 解析範囲の決定 解析ルールの 決定 実行 検知結果の

    抑制有無判断 終了コード設定 • 特定ファイルの除 外 • 特定ディレクトリ の除外 • 再帰的なチェック が可能か • 解析でチェックす るルールの選定 • 意図的に推奨設定 に従わない場合の 検知抑制 • 誤検知結果の抑制 • 閾値以上のIssueが 検知された場合に 異常終了
  4. 2. 静的解析ツールの設定 解析範囲の決定 ビルド成果物に影響を及ぼさないテストファイルや、自分たちでコードコントロールすることが不可 能である自動生成コードをチェック対象から外したい場合があります。 解析範囲の決定 解析ルールの 決定 実行 検知結果の

    抑制有無判断 終了コード設定 • 特定ファイルの除外 • 特定ディレクトリの除外 • 再帰的なチェックが可能か • 特定のファイル・ディレクトリをチェック対象から外したいというニーズが存在 • テストファイル • 自動生成コード • 自チームで責任を持たないsubmodule など • ツールによってファイル・ディレクトリを解析対象から除外指定する方法が異なる • PMD CPD (https://pmd.github.io/pmd/pmd_userdocs_cpd) • --excludeオプションで除外ディレクトリを指定 • errcheck (github.com/kisielk/errcheck) • --ignoregeneratedオプションで自動生成コードを除外 • --ignoretestsオプションでテストコードを除外 • gofmt (https://pkg.go.dev/cmd/gofmt) • 特定ファイルを除外する実行オプション無し、どうしてもやるなら引数 指定で頑張る
  5. 2. 静的解析ツールの設定 解析範囲の決定 また、チェックしたいコードがきちんと解析範囲に入っているかどうかを確認する必要があります。 よくある落とし穴は「再帰でチェックされていると思っていたサブディレクトリが解析されていな かった」というものです。 解析範囲の決定 解析ルールの 決定 実行

    検知結果の 抑制有無判断 終了コード設定 • 特定ファイルの除外 • 特定ディレクトリの除外 • 再帰的なチェックが可能か • 解析実行ディレクトリを指定した際に、その直下にあるサブディレクトリまで再帰 的に解析対象となるのかどうかはツールによって異なる • PMD CPD (https://pmd.github.io/pmd/pmd_userdocs_cpd) • --non--recursiveオプションがついていると再帰探索を行わない • goimports (golang.org/x/tools/cmd/goimports) • 引数で解析範囲としてディレクトリを指定した場合にはサブディレクト リ以下も再帰で解析実行される • gosec (github.com/securego/gosec/v2) • デフォルトで再帰実行を行わない • 再帰実行させることができないのであれば、探索対象ディレクトリを別で洗いだし た上で個別にツール実行させるという一工夫を挟む必要が出る
  6. 2. 静的解析ツールの設定 解析ルールの決定 たった一つのフォーマット・ルールを強制するツールもあれば、利用する側がどのルールを使用する のかある程度カスタムを行う場合もあります。 解析範囲の決定 解析ルールの 決定 実行 検知結果の

    抑制有無判断 終了コード設定 • 解析でチェックするルール の選定 • 静的解析ツールのチェックルール全てをチェックする必要もなく、またデフォルト ではチェックしないoptional項目もチェックしたいという場合もある • staticcheck (github.com/dominikh/go-tools/cmd/staticcheck) • デフォルト設定ではチェックを行わないルール項目が存在し、それらを 有効化するためには明示的な設定が必要 • 両立しえないチェック項目がある場合には、チームとしてどちらの方針に寄せるか 意思決定をする必要がある • ESLint (https://eslint.org/) • シングルクオーテーションとダブルクオーテーションどちらに統一する べきかなど、統一するべきコードフォーマットをまず人間が決める必要 がある
  7. 2. 静的解析ツールの設定 検知結果の抑制有無判断 ツールによって検知された内容には常に・すべて従わなければならないわけではありません。意図的 にツール推奨とは異なる実装を行う場合には、それ以降ツールには該当箇所に対するIssue起票をし ないように設定したいです。 解析範囲の決定 解析ルールの 決定 実行

    検知結果の 抑制有無判断 終了コード設定 • 意図的に推奨設定に従わな い場合の検知抑制 • 誤検知結果の抑制 • エッジケースにおいて意図的にツール推奨フォーマットを採用しない場合や、誤検 知が起こった場合など、ツールによるIssue起票を抑制したいというケースがある • ツールによって特定のコードスニペットにおけるIssue検知を抑制する方法は異な るうえ、そのようなオプションが存在しない場合も • gosec (github.com/securego/gosec/v2) • (例)unsafeパッケージによる直接的なメモリ操作はG103ルールでアラー ト検知されるが、意図的にこれを行いたい場合もある • gocyclo (github.com/fzipp/gocyclo) • コードの循環的複雑度をこれ以上下げられず、可読性の観点でメソッド 分割も望ましくない場合にはアラート抑制したい • //gocyclo:ignoreディレクティブによって検知抑制が可能 • PMD CPD (https://pmd.github.io/pmd/pmd_userdocs_cpd) • CPD-OFFコメント記載によるsupress機能が存在
  8. 2. 静的解析ツールの設定 終了コード設定 異常が検知されたとしても、それに気づくことができないのならば意味がありません。ルール逸脱が 見つかり修正が必要になったときにはプロセスを異常終了させてCI failするように組んでおくことが 重要です。 解析範囲の決定 解析ルールの 決定

    実行 検知結果の 抑制有無判断 終了コード設定 • 閾値以上のIssueが検知され た場合に異常終了 • ツールによって異常終了させるoptionがあったりなかったりします • gosec (github.com/securego/gosec/v2) • -no-failオプションで検知時に異常終了させない挙動にできる • gocyclo (github.com/fzipp/gocyclo) • -over Nで複雑度N以上のロジック検知時に異常終了させるという閾値を 調整することができる • misspell (github.com/client9/misspell) • デフォルトではexit 0だが、-errorオプションを付けることでmisspell県知 事に異常終了させられる • そもそも異常終了させられないツールもあるので、そういう場合はシェルスクリプ トでラップするなどする必要があります
  9. 2. 静的解析ツールの設定 まとめ 静的解析ツールを利用するためにはこれら4つの項目の設定をツールごとに行っていくことになりま すが、その方法やそもそもチューニングできるかどうかはツールによってやり方がバラバラなのが現 状です。 解析範囲の決定 解析ルールの 決定 実行

    検知結果の 抑制有無判断 終了コード設定 • 特定ファイルの除 外 • 特定ディレクトリ の除外 • 再帰的なチェック が可能か • 解析でチェックす るルールの選定 • 意図的に推奨設定 に従わない場合の 検知抑制 • 誤検知結果の抑制 • 閾値以上のIssueが 検知された場合に 異常終了
  10. 2. 静的解析ツールの設定 まとめ 静的解析ツールを利用するためにはこれら4つの項目の設定をツールごとに行っていくことになりま すが、その方法やそもそもチューニングできるかどうかはツールによってやり方がバラバラなのが現 状です。 解析範囲の決定 解析ルールの 決定 実行

    検知結果の 抑制有無判断 終了コード設定 • 特定ファイルの除 外 • 特定ディレクトリ の除外 • 再帰的なチェック が可能か • 解析でチェックす るルールの選定 • 意図的に推奨設定 に従わない場合の 検知抑制 • 誤検知結果の抑制 • 閾値以上のIssueが 検知された場合に 異常終了 ツールごとに仕様・設定方法・オプション有無が全く異なる!!
  11. 3. 静的解析ツールのストレスレス実行 実行フェーズのチューニング 静的解析ツール自体の設定がきちんとできたとしたら、次に大事になるのは以下に気軽にそのチェッ クを実行し、結果を適切な形で活用できるかどうかです。ストレスなくツールを利用し続けるために は、実行フェーズのチューニングも重要になってきます。 解析範囲の決定 解析ルールの 決定 実行

    検知結果の 抑制有無判断 終了コード設定 • 特定ファイルの除 外 • 特定ディレクトリ の除外 • 再帰的なチェック が可能か • 解析でチェックす るルールの選定 • 意図的に推奨設定 に従わない場合の 検知抑制 • 誤検知結果の抑制 • 閾値以上のIssueが 検知された場合に 異常終了
  12. 3. 静的解析ツールのストレスレス実行 実行フェーズのチューニング 静的解析ツール自体の設定がきちんとできたとしたら、次に大事になるのは以下に気軽にそのチェッ クを実行し、結果を適切な形で活用できるかどうかです。ストレスなくツールを利用し続けるために は、実行フェーズのチューニングも重要になってきます。 解析範囲の決定 解析ルールの 決定 実行

    検知結果の 抑制有無判断 終了コード設定 • 特定ファイルの除 外 • 特定ディレクトリ の除外 • 再帰的なチェック が可能か • 解析でチェックす るルールの選定 • 意図的に推奨設定 に従わない場合の 検知抑制 • 誤検知結果の抑制 • 閾値以上のIssueが 検知された場合に 異常終了 • 並列実行による高 速化 • 類似後続チェック が発生したときの キャンセル処理 • 差分実行やキャッ シュの利用
  13. 3. 静的解析ツールのストレスレス実行 並列実行による高速化 解析プロセスが遅いとそれがブロッカーとなり開発効率が下がります。そのためにはツール実行の高 速化が重要になりますが、並列実行をすることで実現することができます。 解析範囲の決定 解析ルールの 決定 実行 検知結果の

    抑制有無判断 終了コード設定 • 並列実行による高速化 • 類似後続チェックが発生し たときのキャンセル処理 • 差分実行やキャッシュの利 用 • 複数個のツールを同時に実行する場合、ツールごとの結果は互いに独立であるため 並列に実行することができる • (例) gosecとstaticcheckを並列に回す • 単独のツール実行に時間が掛かってしまう場合には、inputを複数個に分割しそれら を並列実行することで実行時間短縮を図る手法がある • (例)以下のようなディレクトリ構成だったとする • root • dirA • dirB • dirC • この場合、rootから1回で実行するのではなく、dirA/dirB/dirCと3回に分けて並 列実行させると早くなる
  14. 3. 静的解析ツールのストレスレス実行 リソース管理 限られたリソースを数多くの解析プロセスで取り合う形になると、効率的な静的解析を行うことがで きなくなります。不要なプロセスはキャンセルを徹底することで、並列実行数やコストの節約にもつ ながります。 解析範囲の決定 解析ルールの 決定 実行

    検知結果の 抑制有無判断 終了コード設定 • 並列実行による高速化 • 類似後続チェックが発生し たときのキャンセル処理 • 差分実行やキャッシュの利 用 • コミットが短い期間に連続して行われた場合では、本当に必要なのは最後の最新コ ミットに対する解析結果のみ。コストやコンピューティングリソース・並列実行数 の節約のためにも、不要になった先行解析プロセスはキャンセルしたい • 例えばGitHub Actionsの場合には同種ワークフローの実行数を制限するcancel-in- progressという機能があり、それにて先行プロセスのキャンセルを実現することが できる
  15. 3. 静的解析ツールのストレスレス実行 差分実行 1回の実行ごとにすべてのファイルを解析しなくてもよい場合があります。その場合、差分が生じた ファイルのみ実行することで解析時間の短縮を図ることができます。ただし、常に解析実行結果の冪 等性が担保できるとも限らないため、適切な形で利用することが大事です。 解析範囲の決定 解析ルールの 決定 実行

    検知結果の 抑制有無判断 終了コード設定 • 並列実行による高速化 • 類似後続チェックが発生し たときのキャンセル処理 • 差分実行やキャッシュの利 用 • 個別のファイルに対する解析結果に、他ファイルが影響を及ぼさないようなツール が存在する(例: gofmtのようなフォーマッター) • そのような場合は1コミットごとにすべてのファイルをチェックする必要はなく、 diffが生じたファイルのみ解析を行うことで解析時間を短くすることができる。 • ただし、常に同じファイル内容に対して同じ解析結果が出る(冪等性)とは限らない 場合が存在するため、mainブランチやreleaseブランチといった重要なブランチで は常に全文解析を行い、差分実行はfeatureブランチ等のコミット頻度が高いところ に限定するなどの適材適所が重要 • (例) 解析ツールの設定変更を行った場合には、解析対象ファイルそのものに diffがなくても解析結果が変わりうる
  16. 4. コードレビューサービスの価値 快適な解析環境に求められることの多さ 静的解析ツールを快適に運用し続けるためには求められることが多く、ツールごとにその設定方法も 異なります。SaaSの静的解析ツール等を用いることで、ツールごとの仕様の違いを吸収した画一的 な解析ワークフローの設計を行うことができます。 解析範囲の決定 解析ルールの 決定 実行

    検知結果の 抑制有無判断 終了コード設定 • 特定ファイルの除 外 • 特定ディレクトリ の除外 • 再帰的なチェック が可能か • 解析でチェックす るルールの選定 • 意図的に推奨設定 に従わない場合の 検知抑制 • 誤検知結果の抑制 • 閾値以上のIssueが 検知された場合に 異常終了 • 並列実行による高 速化 • 類似後続チェック が発生したときの キャンセル処理 • 差分実行やキャッ シュの利用
  17. 4. コードレビューサービスの価値 快適な解析環境に求められることの多さ 静的解析ツールを快適に運用し続けるためには求められることが多く、ツールごとにその設定方法も 異なります。SaaSの静的解析ツール等を用いることで、ツールごとの仕様の違いを吸収した画一的 な解析ワークフローの設計を行うことができます。 解析範囲の決定 解析ルールの 決定 実行

    検知結果の 抑制有無判断 終了コード設定 • 特定ファイルの除 外 • 特定ディレクトリ の除外 • 再帰的なチェック が可能か • 解析でチェックす るルールの選定 • 意図的に推奨設定 に従わない場合の 検知抑制 • 誤検知結果の抑制 • 閾値以上のIssueが 検知された場合に 異常終了 • 並列実行による高 速化 • 類似後続チェック が発生したときの キャンセル処理 • 差分実行やキャッ シュの利用 ツールごとに設定方法が異なるこれらの要件を SaaS静的解析ツールが吸収し画一的な設定を実現
  18. 4. コードレビューサービスの価値 コードレビューサービスに求められる価値 ここまでの考察を踏まえて、快適なCI実行環境を整えるためにSaaSの静的解析ツールにアウトソー スしたい事柄は以下の3点に絞られます。 解析の前後処理 解析の実行 • 特定ファイル・ディレクトリ除 外といった直感的かつ統一的な

    解析範囲の指定 • 検知結果の抑制機能を提供して いないツールに対しては当該機 能を代わりに提供 • 検出Issue数の閾値設定および それを上回った場合の異常終了 の担保 画一的な設定の提供 柔軟な実行戦略の策定 容易かつ高度な並列度の確保 • 独立した異なるツールを並列に 動かす • 1つの解析ツールへのinputを分 割しそれぞれのプロセスを並列 に動かすオプションの提供 • 連続コミット実行時に先行解析 プロセスをキャンセル・必要な プロセスのみ優先的に実行 • 差分検知機能を必要なときに正 確な解析範囲で提供 • ブランチごとに実行戦略や実行 ツールを分ける 解析ツールに求める価値
  19. 4. コードレビューサービスの価値 コード品質の「ランク」に対する考え方 コード品質に関する様々な見解を聞いてみると、「悪い点数・評価が出たときに人間によるリスク許 容判断が確実に入るようにするために、閾値そのものよりも点数の出し方に妥当性があるほうが重要 である」と筆者は感じました。 • GoogleのCode Coverage Best

    Practice (https://testing.googleblog.com/2020/08/code-coverage-best-practices.html) • すべての製品に普遍的に適用される「理想的なコードカバレッジの数値」は存在しない。閾値をいくつにするかは そのビジネスをよく知る人が個別に意思決定するべき • ある一定の閾値を超えてしまったら、コードカバレッジを上げることにあまり固執しないほうがいい。なぜならカ バレッジを上げることで得られるメリットの量は対数的に増加していくものだから • UTによってカバーされているコードよりも、カバーされていないコードが本当に大丈夫なのかどうか・リスク許容 できるかどうかが重要である • 某セキュリティプラットフォームの中の方に某カンファレンスで聞いたお話 • 「CIをPASSさせるスコアの閾値をいくつにすればいいのか」というのは実際によく聞くお悩み • 「XX点に設定すればいいですよ!」という統一見解はないが、「どうしてこの点数になっているのか」は確認でき るようにしているため、点数が高いほど緊急度が高い脆弱性であるという点に関しては信用してもらえると思う 点数が悪かったときに「何かあるかも?」と人間が疑えることが重要 そのためには点数の出し方に妥当性・納得感があるかどうかがキーとなる
  20. まとめ • 静的解析ツールを意義のある形で使い続けるためには、FAILする文化を生まないこと & 快適かつ 自然に回し続けられる環境を整えることが重要 • FAILする文化を生まないためには、解析範囲や使用するルール・誤検知や例外的に許容した書き 方のIssue報告抑制といったチューニングを施していくことになる •

    日々の開発を邪魔することなく快適に解析ツールを回すためには、並列実行や差分実行といった 実行フェーズのパフォーマンスチューニングも必要 • このように、快適かつ意義のあるCIを実現するために考慮しないといけないことは意外と多い • 「ツールで引っかかった部分のリスク許容判断」という本当に人手を使うにふさわしい作業にリ ソースを割くために、よきCIを作るところはコードレビューサービスに任せるのがよいのでは