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

10年もののAPIサーバーにおけるCI/CDの改善の奮闘

 10年もののAPIサーバーにおけるCI/CDの改善の奮闘

エブリーのメインサービスであるデリッシュキッチンのAPIサーバーは、Go・echoで構成されており、約10年の歴史の中で肥大化していくつも技術的な負債を抱えています。
本セッションでは、実際に直面している課題に焦点を当て、その解決策として取り組んだCI/CD高速化の全貌をお話します。
具体的な取り組みとして、デッドコードの削除や差分だけのテストへの変更などでビルドやテストを高速化する際に試行錯誤したことについて紹介します。

Avatar for masato hommaru

masato hommaru

September 27, 2025
Tweet

Other Decks in Programming

Transcript

  1. 2 Copyright © 2015 every, Inc. All rights reserved. 目次

    1. 自己紹介 2. デリッシュキッチンの紹介 3. 背景 4. やったこと 5. 結果 6. まとめ 7. 宣伝
  2. 3 Copyright © 2015 every, Inc. All rights reserved. 自己紹介

    経歴 - 2021~ 株式会社ハウテレビジョン - 就活生向けのサービスのバックエンド - 2023~ 株式会社エブリー - サーバーサイドエンジニアとして入社 - サーバーサイドとインフラをメインにデリッシュキッチンの機能開発やヘルシカ (ヘルスケアアプ リ)の認証・課金基盤の開発などを担当 - 2024年10月からマネージャー
  3. 5 Copyright © 2015 every, Inc. All rights reserved. 『デリッシュキッチン』について

    レシピ提案 / レシピ検索 / 
 献立機能 
 買い物リスト / チラシ / 
 店頭ビーコン連動 
 調理手順動画/キッチンモード / 
 作った・レビュー / お気に入り 
 菅原千遥 
 デリッシュキッチン
 カンパニー長
 料理研究家
 斎藤 香織
 副編集長
 管理栄養士
 • 30名以上の食のプロが、蓄積 データに基づきオリジナル 
 レシピを日々考案 
 • 月間1,500本以上の動画配信 
 サービス・機能 
 レシピ検討 
 買い物
 料理中・料理後 
 専門家によるレシピ考案・監修 
 ▪ 日本最大級のレシピ動画サービス 
 ▪ 「誰でも簡単においしく作れるレシピ動画」毎日配信 
 ▪ 全レシピ、管理栄養士が監修!蓄積データによるオリジナルレシピを考案 
 ▪ SNS/APP/WEBを通じて延べ56,000本以上のレシピ動画を提供 

  4. 8 Copyright © 2015 every, Inc. All rights reserved. 技術スタック

    - Go - Echo - レイヤードアーキテクチャ - handler - service - repository - infra - model - Github Actions(CI) - gomock - ブランチ戦略は git-flow
  5. 9 Copyright © 2015 every, Inc. All rights reserved. 背景

    - デリッシュキッチンのサーバー (delish-server)は9年目 - goのソースコードの行数は、約 70万行 - 1ヶ月で120時間、740回実行されている - CI/CDにかかっている時間 - master : 16分 - develop : 16分 - feature : 10分(deployを行わないため) CI/CDに時間がかかっていて、早くデプロイしたいのに待ち時間が発生する時があるので改 善したい!
  6. 10 Copyright © 2015 every, Inc. All rights reserved. 改善の体制

    - CI/CD改善プロジェクトのメンバー - 人数: 3人 - 期間: 約1ヶ月 - Github Actionsの結果を見ながら、時間がかかっている箇所に対して高速化の案を出して いった
  7. 11 Copyright © 2015 every, Inc. All rights reserved. 検討した改善事項

    - 検討したもの - デッドコードの削除 - テストの並列化の徹底 - 差分テスト - go tool系のキャッシュ - テストの際にbuildをやめてgo mod downloadにする+キャッシュさせる - 今回できていないこと - mockを使えていない箇所で使う - 依存関係の分離がうまくできていない箇所がある - グローバル変数を使用している箇所の並列化 - ツールで発見できないデッドコードの削除
  8. 12 Copyright © 2015 every, Inc. All rights reserved. 改善の結果

    最初: 16分 最終: 10分 - キャッシュなし - フルテスト: 13分 - 部分テスト: 8分 - キャッシュあり - フルテスト: 10分 - 部分テスト: 5分
  9. 14 Copyright © 2015 every, Inc. All rights reserved. デッドコードの削除(作業)

    - デッドコードの検出 - https://pkg.go.dev/golang.org/x/tools/cmd/deadcode - 偽陽性があることに注意! - ツールで抽出したデッドコードを本当に削除して良いか、確認し つつ削除
  10. 16 Copyright © 2015 every, Inc. All rights reserved. デッドコードの削除(結果)

    - テストの時間はほとんど変化なし - 約11,000行を削除(全体が70万行なので 1/70) 余談ですが、他のプロダクト (トモニテ)では135,000行のデッドコードを削除でき、 2~3分ほどはテストの時間を削減 (不要なテーブルやエンドポイントの削除まで対応した結果 )
  11. 18 Copyright © 2015 every, Inc. All rights reserved. テストの並列化の徹底

    (準備) - 対応が必要な pkgを抽出 - 直近のテストコードの結果をもとに確認
  12. 20 Copyright © 2015 every, Inc. All rights reserved. テストの並列化の徹底

    (実装) - t.Parallel()を使用することでテストを並列実行できるようにする - 230/4,800のテストでは元々利用していた - DBへのアクセスがあるものなどは t.Parallel()を使用する際に注意が必要なので対応し ない
  13. 21 Copyright © 2015 every, Inc. All rights reserved. time.Now()を使用するテストの並列化

    - 並列化をするにあたって Now()を利用するテストへの対応が必要になった util/time.go campaign_test.go(変更前)
  14. 22 Copyright © 2015 every, Inc. All rights reserved. time.Now()を使用するテストの並列化

    - テストの時に util/time.goに渡すTimeを 固定値にすることでも対応可能 - 今回はsynctestを使ってみる - util/time.goはテスト用に作成されたも のなので、わざわざ使用する必要がなく なる - せっかくなので使ってみたかった campaign_test.go(変更後)
  15. 23 Copyright © 2015 every, Inc. All rights reserved. テストの並列化の徹底

    (結果) - テストの時間が約 1分短縮 - テストの数 約4,800 - t.Parallel()に対応した数 約220-> 約2,200
  16. 24 Copyright © 2015 every, Inc. All rights reserved. テストの並列化の徹底

    (今後のための対応) - golangci-lintでt.Parallel()を利用しているか検知 - https://golangci-lint.run/docs/linters/configuration/#paralleltest - configファイルに linters/enableにparalleltestを追加 - 並列化できないものは //nolint:paralleltestをつける
  17. 26 Copyright © 2015 every, Inc. All rights reserved. 差分テスト対応(準備)

    - delish-serverのCI(/CD)のタイミング - featureブランチ(CI) - developブランチ(CI/CD) - masterブランチ(CI/CD) - 差分テストの方針について - 全てフルでテストするか差分のみテストするかは悩ましいところ - 今回はCI/CDを高速化しつつ、安全に運用できるラインを目指した - developブランチ以降のdeployまで動く環境ではフルでテストを行う - リスクの高い変更がある場合はフルでテストをするようにする - go listを利用して、差分ファイルに依存関係がある pkgまでカバーするようにする
  18. 27 Copyright © 2015 every, Inc. All rights reserved. 差分テスト対応(実装)

    - 差分テストの流れ - develop/masterのテストはフルで実行 - featureのテストは下記のフローで処理する 1. 実行対象のpkgを抽出 2. フルでテストなのか差分のみテストなのか判定 - 下記のようなリスクが高いケースではフルでテストする - go.modの変更 - migrationファイルの変更 - model/utilファイルの変更 - ci/cdのワークフロー関連の変更 - 関連するpkgが多い場合はフルでテストする - doc系のみの変更の場合はテストをスキップする 3. go test pkg名を実行することで差分があるパッケージだけをテストする
  19. 29 Copyright © 2015 every, Inc. All rights reserved. 差分テスト対応(結果)

    - featureブランチでのテストの時間が 8~10分→3~5分程度に - develop, masterブランチではフルでのテスト実行なので変化なし
  20. 31 Copyright © 2015 every, Inc. All rights reserved. その他の対応と結果

    - 不要なビルドをやめて go mod downloadにする - デプロイと関係ないところでgo buildを行っていた - go buildの時に必要なパッケージのダウンロードを行っていた → 1分短縮 - ダウンロードしたパッケージをキャッシュにのせる → 1分短縮 - テストが失敗した時に即終了するように変更 - go testのfailtestオプションを利用 - 複数failになる場合に一度のCIで確認できないのは許容 → 失敗時により早く気づけるように
  21. 32 Copyright © 2015 every, Inc. All rights reserved. 今回行った対応と結果

    改善施策 概要 効果 短縮時間 デッドコード削除 ツールを利用して検出したデッドコードの削 除 ❌ ほぼ変わらず テストの並列化 t.Parallel()を利用できていない箇所で利用す るように変更 ⭕ 1分短縮 差分テスト対応 featureブランチのテストを変更した差分のみ 実行するように変更 ⭕ featureブランチ 最大7分程度の短縮 不要なビルドをやめて go mod downloadに する テスト時には不要なデプロイを行っており、ダ ウンロードのみで十分だったため変更 ⭕ 1分短縮 pkgのバイナリキャッ シュ ダウンロードしたpkgをキャッシュしていな かったためキャッシュするように変更 ⭕ 1分短縮 failfastにする テスト失敗時にCIが早く終了するように変更 ⭕
  22. 34 Copyright © 2015 every, Inc. All rights reserved. まとめ

    まとめ - CIの時間が16分→10分に改善! - よくあるCI/CDの改善ではあったと思うが、整備できていない点も多かったのでこの機会 に対応できてよかった - 想定よりデッドコードが少なく、違いを見せられなかったのは残念 今後の課題 - mockを使ってテストしているが依存を分離できていない箇所があり、そこまでは手が回 らなかった - ツールで発見できないデッドコードの削除までは手が回らなかった
  23. 35 Copyright © 2015 every, Inc. All rights reserved. エブリーからのお知らせ

    Go Conference 2025 スポンサー 5社共催 アフターイベント開催します 🎉 🔍 compass go bash vol.2 🔍 エブリー オウンドメディア 🔍 エブリー テックブログ