チーム境界をメンテナンスし続ける営み

この記事は10X 新春ブログリレー 2026の1月22日分の記事です。


ドメインベースの開発体制から3年

10Xの開発チームがドメインベースの開発体制へ移行してから、約3年が経過しました。

product.10x.co.jp

改めて当時と比較してみると、認知負荷の増大やオーナーシップの欠如といった課題は大きく改善したと感じています。もちろん新たな課題や難しさもありますが、ドメインベースへの移行自体は、総じて進めてよかったなと言い切れる試みでした。

この記事では、そんなドメインベースの体制の「チームの境界」という点にフォーカスして体制移行時にどのように初期的な境界を決めたのか、そしてこの3年間でその境界をどう見直してきたのかについてお話をしてみようと思います。

初期的な境界の決め方

初期のチーム境界と担当ドメインは、以下のような手順で定義しました(実際には1〜4がスムーズに進んだというよりは、何度か行き来しながら議論を繰り返して初期的な形に着地しました)。

続きを読む

Cloud Pub/Sub の Ordering Key によるレースコンディションの解消(Firestore -> Elasticsearchのデータ同期)

この記事は、10X 新春ブログリレー 2026 の1月21日の記事です。


はじめに

CXチームでソフトウェアエンジニアとして働いている@kotaroooo0です。 本記事では、FirestoreからElasticsearchへのリアルタイムデータ同期において発生したレースコンディションの問題と、それをCloud Pub/Sub(以下、Pub/Sub)のOrdering Keyを活用して解消した事例について紹介します。

システムの前提

10Xが提供する「Stailerネットスーパー」では、商品の検索や推薦にElasticsearchを利用しています。 一方で、マスターデータとして汎用的に使用しているデータベースはFirestoreです。 検索の精度を高く保つためには、Firestoreの更新を可能な限り速やかにElasticsearchへ反映させる必要があります。

データ連携アーキテクチャは次のとおりです。

  1. Firestoreのドキュメントが更新される
  2. 更新イベントをトリガーに、Pub/Subへメッセージをパブリッシュする
  3. SubscriberがメッセージをPullし、Elasticsearchへインデキシングを行う

大量に更新が発生した時もSubscriberがオートスケールすることで、キュー内でのメッセージの滞留を防ぎ、ニアリアルタイムなデータ同期を可能にしています。

※説明を分かりやすくするため、実際のアーキテクチャや事象については簡略化して記載しています。

発生した問題と原因

あるとき、「管理画面で商品のステータスを変更したのに、Elasticsearch側で古いステータスのままになっている」という事象が発生しました。 調査の結果、同一の商品に対して短時間に連続した更新が行われた際に、レースコンディションが発生していることが判明しました。

具体的な発生シナリオ

  1. 管理画面から、商品を「ステータスA」に変更。
  2. その直後に、同じ商品を「ステータスB」に変更。

このとき、2つのメッセージがほぼ同時にPub/Subに届き、複数のSubscriberが並列で処理を開始します。

  1. (Subscriber-1) ステータスAのメッセージをPullし、処理を開始
  2. (Subscriber-2) ステータスBのメッセージをPullし、処理を開始
  3. (Subscriber-2) 処理が先に完了し、Elasticsearchドキュメントを「ステータスB」に更新
  4. (Subscriber-1) 遅れて処理が完了し、Elasticsearchドキュメントを「ステータスA」に更新

結果として、Firestore側は「ステータスB」であるにもかかわらず、Elasticsearch側は古い「ステータスA」で確定してしまいます。 Subscriberはバッチ処理を行っており、Subscriber-1の処理件数がSubscriber-2より極端に多かった場合などに、この逆転現象が発生しやすい状況でした。

解決策: Pub/SubのOrdering Keyを導入

この問題を解決するには、「同じ商品に対するメッセージは、必ずパブリッシュされた順序で処理する」必要があります。 ここで役立つのが、Pub/Subのメッセージの順序付け機能です。

メッセージの順序付けは Pub/Sub の機能であり、パブリッシャー クライアントによってパブリッシュされた順序でサブスクライバー クライアントでメッセージを受信できます。 たとえば、あるリージョンのパブリッシャー クライアントがメッセージ 1、2、3 を順番にパブリッシュするとします。メッセージの順序付けを使用すると、サブスクライバー クライアントはパブリッシュされたメッセージを同じ順序で受信します。

Pub/Sub での順序付けは、次の要素によって決定されます。

順序付けキー: Pub/Sub メッセージ メタデータで使用される文字列であり、メッセージの順序付けが必要なエンティティを表します。並べ替えキーの長さは最大 1 KB です。リージョンで順序付きメッセージのセットを受け取るには、同じ順序付けキーを使用して、同じリージョンにすべてのメッセージをパブリッシュする必要があります。順序付けキーの例としては、お客様 ID やデータベース内の行のプライマリ キーがあります。

cloud.google.com

導入後のフロー

各メッセージに商品IDをOrdering Keyとして設定することで、同じ商品に関するメッセージは必ず「前のメッセージがAckされてから次のメッセージが配信される」ようになります。

  1. (Subscriber-1) ステータスAを処理開始
  2. (Pub/Sub) Subscriber-1がステータスAのメッセージに対してAckするまで、同一KeyをもつステータスBのメッセージを配信せず待機
  3. (Subscriber-1) ステータスAの処理を完了し、Ackを返す
  4. (Pub/Sub) ステータスBのメッセージを配信可能にする
  5. (Subscriber-x) ステータスBの処理開始

これにより、処理順序が保証され、データの不整合が解消されました。

Ordering Keyの挙動について深掘り

導入にあたり、公式ドキュメントだけでは確証が持てなかった挙動について検証しました。

Q. Ack前に次のメッセージをPull可能か?

A. 不可。Ackを返すまで、同一Keyの次のメッセージはブロックされる

「配信順序を保証するだけ(受け取り側で頑張る必要があるのか)」のか、「処理の完了を待ってくれるのか」を確認するため、次の環境でテストしました。

  • メッセージ数: 10
  • Subscriber: 3並列
  • それぞれのSubscriberは1メッセージずつ処理
シナリオ 結果
すべて同じOrdering Key 前のメッセージのAck完了まで、後続はブロック。1つのSubscriberのみが順次処理を行う。
すべて異なるOrdering Key 順序制約がないため、3つのSubscriberが並列でフル稼働する。
2つのKeyグループ(メッセージ5個はKey1, メッセージ5個はKey2) Key1とKey2のそれぞれの系列は順次処理されるが、Key1とKey2同士は並列で処理される。2つのSubscriberが稼働する。

Q. キューに溜まっている同一Keyのメッセージを「同時Pull」するか?

A. 同時にPullするが、別個のSubscriberが同時に処理できない

1つのSubscriberが「一度に最大10件メッセージ取得する」設定でPullした場合、複数の同一Keyのメッセージを含むことがあります。 また、そのSubscriberがAckを返さない限り、他のSubscriberインスタンスが同じKeyのメッセージを奪うことはありません。

おわりに

本記事では、Pub/SubのOrdering Keyを用いて、FirestoreとElasticsearch間のレースコンディションを解消した事例を紹介しました。 ドキュメントから読み取りにくかった部分を調査し紹介したので、Pub/Subを使う方々の参考になれば幸いです。


僕が所属しているCXチームではエンジニアを募集中です! 少しでも気になった方はぜひカジュアル面談をしましょう!

product.10x.co.jp open.talentio.com

ドメインイベントのデータ上の扱いについて紹介 (CQRS+ES conf 2026の補足)

この記事は、10X 新春ブログリレー 2026の記事です。


鈴木です。2026年1月に開催されたCQRS+ES Conference 2026にて「ネットスーパー事業におけるCQRS+ES的アプローチの取り組み紹介」というタイトルで登壇しました。 cqrs-es-con.jp

CQRS+ES conf 2026の当日は

  • Stailerにある注文を中心とした業務影響がある課題の共有
  • 共有した課題がCQRSとイベントソーシングにある要素でどう解決できるのか

この2点にフォーカスして話をさせていただきました。

当日使った資料はこちらです。

speakerdeck.com

この記事では当日話きれなかった具体的な方法を紹介しようと思います。

続きを読む

"攻めの開発"を支える安全安心なリリース

この記事は、10X 新春ブログリレー 2026の記事です。前日は、jojoさんによる「バージョンアップ手作業のつらみから解放された4つの自動化施策」でした。自動化って尊い!


もう1月中旬!早いですね。 id:hisaichi5518 です。

2025年は、Stailer ネットスーパーの店内業務・配達用アプリのリアーキテクチャに伴う作り直しを主に進めていました。特に店舗で注文された商品を集めるときに利用するピッキングリストというStailer ネットスーパーを利用する小売企業のほとんどが利用する部分の作り直しを行いました。

この作り直しを"攻めた開発"として、安全安心なリリースとの両立を強く意識して進めていたので、それについて書きます。

なぜ安全安心なリリースが必要なのか?

Stailer ネットスーパーの店内業務・配達用アプリは、注文された商品を集める(ピックする)ときに利用する機能や配達に関する機能などを持っています。多くの小売企業がこの機能を利用しており、1日にたくさんの注文がこのアプリを通じて処理されています。

そのアプリでもし不具合が発生したら

  • 店舗スタッフの業務が遅延*1
  • お客様への配達が遅延
  • お客様・店舗からの問い合わせが殺到

つまりネットスーパーを利用するお客様の食卓はもちろん、小売企業の生産性、10Xの生産性、間接的には売上など影響が大きいです。なので、安全安心なリリースをしていく必要があります。

安全安心なリリースをするために

安全安心なリリースは、以下を満たすものだと考えています。

  • なるべく早く開発チームが問題に気付くこと
    • リリース後よりはリリース前、実装後よりは実装前などなるべく早いことが望ましい
  • リリース後に問題があったら1分1秒でも早く元に戻せること
  • リリース後に問題があったら1分1秒でも早く原因を特定できること

これらを満たすためにやっていることを書いていきます。

機能が持つ概念をまとめる

今回の作り直しでは、ただ機械的に既存実装を新しいアーキテクチャに置き換えていくというよりは、改めて「この機能はどういう概念を持っているか」をDesign Docに書いてから実装しています。例えば「商品のバーコードを読み取ってピックしたことを記録する」という機能を扱う時、以下のように捉えました。

  1. 読み取る
    • Android は 内蔵カメラを使ってバーコードを読み、 MLKitを利用してバーコードを読み取る
    • iOS は内蔵カメラを使ってバーコードを読み、AVFoundationを利用してバーコードを読み取る
    • 外付けスキャナは外付けカメラを使ってバーコードを読み、外付けスキャナ独自の方法でバーコードを読み取る
  2. 変換する
    • AVFoundationは、12桁のバーコードを読み取った時、13桁に自動的に変換する。Stailer的には、12桁として扱いたいので13桁かつAVFoundationで読み取りかつ最初の桁が0の場合は、12桁に変換する
  3. 処理する*2
    • アプリ内に保持されたリストの中から読み取ったバーコードに一致するものを見つけて、結果によってピックを記録する

「商品のバーコードを読み取ってピックしたことを記録する」は、1.読み取る, 2.変換する, 3.処理するによって構成されており、1, 2, 3はそれぞれが疎結合になっているべし!というのが整理することで見えてきます。

このあたりを整理せずに実装し始めると、既存実装に引っ張られて密結合した状態の実装が出来上がって残念なことになるみたいなことがありました。

整理した内容はDesign Docに記載して、実装前にQAE, SWEにレビューしてもらっています。

実装時に何を検討するかを書く

またDesign Docには「より詳細な設計をする実装時に何を検討するか」も書いていています。

例えば、「商品のバーコードを読み取ってピックしたことを記録する」という機能を整理した結果、1.読み取る、2.変換する、3.処理するというのがあることがわかりました。また読み取る部分では複数の読み取り方法があり、今後も新しい読み取り方法が追加されうることがわかりました。

そこで「バーコード読み取り方法の追加にはどのように備えておくか?」という疑問が出てくるのですが、これはクラス設計など詳細設計時に色々試しながら決めたいので、それは未確定の論点としてDesign Docに記載しておき、プルリクエストを出すときに一緒にDesign Docに結論を追記してレビューを依頼するとしています。

実装前にリリース計画と切り戻し方法を書く

実装前にリリース計画をDesign Docにまとめていて、そこに問題が起きた時どうやって切り戻すかを書いています。実装してから切り戻し方法を考えるよりは、実装する前に考えておくとそれを踏まえて作るので後から継ぎ足しにならないので考えることが少なくていいです。

自動テストを書く

今までテストが書けてなかったのがリアーキテクチャによって書きやすくなったので書くようになりました。単体テストとWidgetテスト(ゴールデンテスト)を書いています。

意味のあるテストであることが重要だと思っていて、QAEが行ったテスト設計を元に単体テストを書き足したりすることもあります。またあえてテストを書く作業を見積もり時に考慮していて、実装は2ポイントテストはその半分くらいの作業量だからこのチケットは3ポイントみたいなことを見積もり時に考えています。

本番に近いデータで単体テストする

商品に付いてるバーコードをアプリで読み取ってピックを記録するいう機能があるのですが、バーコードは様々なデータがあり標準的なパターンだけではなく小売企業が独自に定義したパターンもあったりするので、本番に近いデータを利用して単体テストを動かすことで知らなかったパターンを見つけたり、作り直す前と後で動作に予期しない変化がないことを確認しています。

しかし、店頭に並んでいる実際の商品のバーコードはStailerは持っておらずわからないので、あくまで実際にスキャンするバーコードに近いだけであるというのは念頭においておく必要はあります。

シャドウテストをする

特定のリストから条件によってデータを抽出するというような表示や直接データ変更を行わないロジックはシャドウテストを行うようにしています。

シャドウテストは、本番環境で新旧両方の実装を並行して動かし、新しい実装の結果を実際には使わずに記録・比較するテスト手法です。ユーザーには旧実装の結果だけが返されるため、新実装に問題があってもユーザー影響はゼロで、本番の実データで新実装を検証できるのが最大のメリットです。

シャドウテストを行ったおかげで既存実装と作り直し後の実装で動作に差異があることがわかり、事前にプロダクトマネージャーに「リリース後、こういう変化があります。これは新しい実装が仕様に沿っているので正しい変化です」というコミュニケーションが取れて、リリース後にドタバタせずに済みました。

Feature Flagで機能の有効無効を切り替える

モバイルアプリはリリースするのにも審査などで早くても1日くらいかかるので、Feature Flagで機能の有効無効を切り替え出来るようにしてリリースして、有効後に安定していると判断できたらFeature Flagの利用をやめるようにしています。問題が合ったときは、Feature Flagをオフにするだけで切り戻しが高速に行えます。

調査用のログを出す

とにかくログを出して問題が起きてそうな時に何が起きてるのかを把握できるようにしています。何をログとして記録するかがポイントだと思いますが、自分は以下を意識して記録するようにしています。

  • いつ
  • 誰が
  • 何が起きたか
  • 変化がある場合は、変化前と変化後の値
  • 異常がある場合は、なにが異常で異常とした根拠

一方でこのログはあくまで不具合の調査用です。分析用のログは極力サーバーサイドで記録するべきです。「A画面を開いた」など分析用にどうしてもモバイルアプリ側で記録する必要があるときは、別の仕組みを利用しています。

DataDog RUMに記録出来ることは記録する

Datadog RUMは以下のようなイベントを記録できます。これらを取ることで今までは時間がかかっていた調査もかなりスムーズにできるようになってきました。

  • ユーザーが表示したビュー / Dialog
  • タップイベントなどのユーザーアクション
  • エラー
  • APIリクエスト
  • Feature Flagの値
  • Shared Preferencesの値

今のところセッション数の制御はしておらず、toCサービスに比べてセッション数が多くならず突然跳ねることもないので、今はとにかく全て送るとしています。

モニタリングを行う

クラッシュ率、このログが大量に出たらアラートなど色々モニタリングしてます。 この辺りはRUMとログをDatadogに送っているので、Datadogで行っています。

俺たちの戦いはこれからだ!

安全安心なリリースのためにやれることはやり尽くしたように見えますが、作り直すこと以外も含めて攻め続けるにはまだまだやれることはあるはずです。例えば

  • APIリクエストはエラーによってはリトライが行われるがそれを考慮したモニタリングにはなってない。または考慮できていないため意味のあるモニタリングになりにくい。SLO化もまだ
  • ピックにかかる時間を監視して、一定の基準以上遅くなればアラート
  • E2Eテストがなく人間による手動の結合テストが必要

2026年も引き続き、攻めの開発と安全安心のリリースの両立をしていきたいと思います!!明日は、uraさんによる「仮)登壇資料をAIに作らせたら失敗した話」です。楽しみですね!

*1:完全な業務停止はしないように代替性を持たせています

*2:正確には、ここはもっと複雑なのですが、例なのでシンプルにしています

バージョンアップ手作業のつらみから解放された4つの自動化施策

バージョンアップ手作業のつらみから解放された4つの自動化施策

この記事は10X 新春ブログリレー 2026の1月13日分の記事です。


はじめに

こんにちは。10Xでソフトウェアエンジニアをしていますjojo(@joj0hq)です。

2025年4月にチームが合併し、それまで触れてこなかった商品データパイプライン(ETL処理をdbtで実装)の開発に携わるようになりました。チーム合併の詳細については、EMのfutaboooさんが書かれた以下の記事をご覧ください。

10x.co.jp

新しい技術領域に触れる中で、バージョン管理の運用負荷という課題が明らかになってきました。本記事では、十数パートナーに対する共通パッケージのバージョンアップ作業を自動化し、開発効率を大幅に改善した取り組みを紹介します。


システム構成の概要

改善内容に入る前に、私たちのアーキテクチャについて簡単に説明します。

私たちは、共通パッケージ(data-express)実装プロジェクト(stailer-dbt) という2層構造でマルチテナント型のデータパイプラインを運用しています。

アーキテクチャ図

graph TB
    subgraph "data-express (共通パッケージ)"
        DE[dbtパッケージ<br/>共通モデル・マクロ提供]
        style DE fill:#e1f5ff
    end

    subgraph "stailer-dbt (実装プロジェクト)"
        direction TB
        P1[パートナーA<br/>data-express v0.1.0使用]
        P2[パートナーB<br/>data-express v0.2.0使用]
        P3[パートナーC<br/>data-express v0.1.5使用]

        style P1 fill:#fff4e6
        style P2 fill:#fff4e6
        style P3 fill:#fff4e6
    end

    DE -->|パッケージとして利用| P1
    DE -->|パッケージとして利用| P2
    DE -->|パッケージとして利用| P3

    BQ[(BigQuery)]

    P1 --> BQ
    P2 --> BQ
    P3 --> BQ

構成要素

  • 共通パッケージ(data-express): 複数パートナーで共通利用できる再利用可能なdbtパッケージ。データ変換ロジックや集計処理などのコアロジックを提供
  • 実装プロジェクト(stailer-dbt): 各パートナーの個別要件に対応する実装。共通パッケージを参照し、パートナー固有の処理を追加
  • バージョン管理: 各パートナーは独立したバージョンの共通パッケージを利用可能。段階的なバージョンアップが実現

この構成により、共通ロジックの品質を保ちながら、各パートナーの要件にも柔軟に対応できています。


直面していた課題

共通パッケージの新バージョンがリリースされるたびに、以下のような手作業が発生していました。

  1. PR作成の手間: 十数パートナーに対して、都度バージョンアップ用のPRを手動で作成
  2. レビュー負担: パートナーごとにレビューと差分検証(developブランチとfeatureブランチのBigQueryテーブル比較)を実施。レビュワーの負担が大きい
  3. 差分確認の煩雑さ: 差分結果を都度Looker Studioのダッシュボードを確認しに行く必要があり、結果の把握に時間がかかる
  4. 通知の不足: データ作成の検証をするためのdbt Cloudでの処理完了や失敗を能動的に確認する必要がある

この運用負荷により、バージョンアップのたびにSprintのチケットを切り、計画的に作業時間を確保する状態になっていました。


改善への取り組み

上記の課題に対して、4つの観点から改善に取り組みました。

改善後のワークフロー全体像

graph TB
    subgraph "改善後のワークフロー"
        V[共通パッケージ<br/>新バージョンリリース]

        subgraph Auto["自動フロー"]
            RN[Renovate<br/>PR自動生成]
            CR[Claude Code Review<br/>自動チェック]
            DC[差分検証<br/>自動実行]
        end

        Manual[スラッシュコマンド<br/>/diffcheck]

        subgraph Notification["通知"]
            Comment[PRコメント通知<br/>完了/失敗通知]
            Diff[差分結果表示<br/>差分の有無とサマリー]
        end

        V --> RN
        RN --> CR
        CR --> DC
        DC --> Comment
        DC --> Diff

        Manual -.->|手動実行| DC

        style V fill:#e3f2fd
        style RN fill:#c8e6c9
        style CR fill:#c8e6c9
        style DC fill:#c8e6c9
        style Manual fill:#fff9c4
        style Comment fill:#c8e6c9
        style Diff fill:#c8e6c9
    end

    Solution[✅ PR作成自動化<br/>✅ レビュー自動化<br/>✅ 差分確認自動化]

    Notification -.-> Solution

    style Solution fill:#e8f5e9

1. PR自動生成(Renovate導入)

課題

実装プロジェクトで適用する共通パッケージのバージョンを上げるために、パートナーごとにPRを手動で作成する必要がありました。十数パートナー分のPRを作成するのは非常に手間がかかります。

解決策

Renovateを導入し、共通パッケージのリリースと同じタイミングで各パートナー向けのPRを自動生成するようにしました。

実装詳細

  • Renovateの設定ファイルで、共通パッケージの更新を監視
  • 新しいタグがリリースされると、自動的にパートナーごとのPRを作成
  • PRには変更内容のサマリーを自動で含める

Renovateによる自動PR作成
Renovateによる自動PR作成

効果

  • PR作成作業がゼロに
  • リリース直後に即座にPRが作成されるため、バージョンアップの遅延を防止

2. レビュー自動化(Claude Code Review × reviewdog導入)

課題

バージョンを上げるごとにパートナーごとのレビューが必要で、レビュワーの負担が大きくなっていました。

解決策

Claude Code Reviewとreviewdogを組み合わせて導入し、PR作成時に自動で基本的なチェックを実施するようにしました。

実装詳細

  • GitHub ActionsでClaude Code Reviewを実行
  • 共通パッケージの変更内容を解析し、パートナー固有の実装に影響がないかチェック
  • reviewdogと連携することで、実装に紐づく細かいコメントをコードの該当行に直接投稿
  • 問題があればPRにコメントで指摘

Claude Code Reviewによる自動チェック
Claude Code Reviewによる自動チェック

効果

  • 基本的なチェックは自動化され、人間は最終確認のみに集中できるように
  • reviewdogにより、コードの該当箇所に直接コメントが付くため、レビュー内容が分かりやすい
  • レビュー時間の大幅な短縮

3. 差分検証の自動実行

課題

バージョンアップ前後でのデータ差分を確認する作業が手動で、毎回実行するのが大変でした。

差分検証とは: developブランチとfeatureブランチでそれぞれdbt runを実行し、生成されたBigQueryのテーブルを比較することで、機能開発や修正によるデグレ(品質劣化)を検出する取り組みです。この検証により、意図しないデータの変更を早期に発見できます。

graph TB
    subgraph "差分検証の仕組み"
        subgraph Branch1["developブランチ"]
            D1[dbt Cloud<br/>dbt run実行]
            D2[(BigQuery<br/>developスキーマ)]
            D1 --> D2
            style D1 fill:#e3f2fd
            style D2 fill:#bbdefb
        end

        subgraph Branch2["featureブランチ"]
            F1[dbt Cloud<br/>dbt run実行]
            F2[(BigQuery<br/>featureスキーマ)]
            F1 --> F2
            style F1 fill:#fff3e0
            style F2 fill:#ffe0b2
        end

        Comp[BigQuery<br/>テーブル・カラム比較]
        D2 --> Comp
        F2 --> Comp

        Result{差分あり?}
        Comp --> Result

        Result -->|差分なし| OK[✅ デグレなし<br/>安全にマージ可能]
        Result -->|差分あり| NG[⚠️ 差分を確認<br/>意図した変更か検証]

        Visual[結果の可視化]
        OK --> Visual
        NG --> Visual

        subgraph "確認方法"
            V1[Looker Studio<br/>詳細ダッシュボード]
        end

        Visual --> V1

        style Comp fill:#f3e5f5
        style Result fill:#fff9c4
        style OK fill:#c8e6c9
        style NG fill:#ffccbc
        style Visual fill:#e1bee7
        style V1 fill:#c5cae9
    end

この差分検証を自動化するため、以下の2つのアプローチを取りました。

解決策

差分検証を2つの方法で実行可能にしました:

  1. Renovateとの連携による完全自動実行: RenovateがPRを作成すると、自動的に差分検証が実行される
  2. スラッシュコマンドによる手動実行: 必要に応じて /diffcheck コメントで差分検証を実行できる

実装詳細

  • dbt Cloudのジョブを呼び出すGitHub Actionsを作成
  • RenovateによるPR作成をトリガーに、自動で差分検証を実行
  • 必要に応じて /diffcheck コメントでも実行可能
  • 検証結果をPRにコメントで返す

スラッシュコマンドによる差分検証の自動実行
スラッシュコマンドによる差分検証の自動実行

効果

  • RenovateによるバージョンアップPRでは、完全自動で差分検証が実行される
  • 手動での確認作業を大幅に削減
  • 必要に応じてスラッシュコマンドで再実行も可能

4. 差分検証結果の通知と可視化

課題

差分検証の結果確認に関して、以下の問題がありました:

  1. 通知の不足: dbt Cloudで処理が実行されるため、処理の完了や失敗に気づきにくい
  2. 結果の確認が煩雑: Looker Studioのダッシュボードを見に行かないと差分の詳細が分からず、確認に時間がかかる

解決策

GitHub PRへのメンションコメント通知を導入し、差分検証の完了・失敗を自動的に通知するとともに、差分の詳細を可視化しました。

実装詳細

  • dbt Cloudのジョブ完了/失敗をトリガーにGitHub Actionsを実行
  • PRにメンションコメントで結果を通知
  • PRコメントに差分サマリーを含める
  • エラーの場合は詳細なログへのリンクも含める

実行結果のGitHubコメント通知
実行結果のGitHubコメント通知

効果

  • dbt Cloudを能動的に確認する必要がなくなった
  • 差分の有無とサマリーをPRコメント通知で即座に把握できるようになった
  • Looker Studioに確認しに行かなくても、意図しない差分にすぐ気づけるようになった

改善の効果

Before / After比較

項目 Before After
PR作成 十数パートナー分を手動作成 完全自動化
レビュー パートナーごとに個別レビュー 基本チェックは自動化
人間は最終確認のみ
差分検証 手動で実行して結果確認 Renovate PRでは自動実行
必要時はコマンド1つで実行可能
結果確認 dbt Cloudで処理完了を確認
Looker Studioで差分を確認
PRコメント通知で即座に把握

得られた成果

  • 作業時間の大幅削減: バージョンアップに伴う手作業がほぼゼロに
  • リードタイムの短縮: リリースから適用までの期間を大幅に短縮
  • レビュー負荷の軽減: レビュワーは本質的な確認に集中できるように

まとめ

本記事では、マルチテナント型dbtプロジェクトにおける共通パッケージのバージョンアップ運用を自動化した取り組みについて紹介しました。

一度にすべてを自動化するのではなく、課題を分解して1つずつ改善することで、着実に効果を得られました。Renovate、Claude Code Review、dbt Cloud、GitHub Actionsなど、既存ツールを組み合わせることで、短期間でバージョンアップ作業を大幅に削減することができました。

マルチテナント型のデータパイプライン運用において、同じような課題を抱えている方の参考になれば幸いです。

私たちのチームでは、このようなdbtを活用した開発効率改善のほか、dbtとAIエージェントを組み合わせたデータ調査など、AIを拡張した取り組みも行っています。

speakerdeck.com

また、Podcastでチームの開発の裏側や働き方についても語っていますので、興味があればぜひご覧ください。

open.spotify.com


10Xはこの社会インフラとなるネットスーパーや、小売業のDXを通じて半径1mの人の生活を良くしていくために、仲間を募集しています。本記事のような開発効率を改善する取り組みに関心がある方は、ぜひカジュアル面談でお話ししましょう!

open.talentio.com

conftestによる自動レビュー

conftest は、Open Policy Agent (OPA) の Rego 言語を使って、構造化データ(YAML、JSON、Terraform、Dockerfile など)に対するポリシーテストを実行するCLIツールです。

よくあるユースケースとして、Kubernetes マニフェストや Terraform の設定ファイルに対して「コンテナは root で実行してはいけない」「すべてのリソースにタグが必要」といったルールの適用です。これらのルールを組織ポリシーとして定義して、それに適合しているかをconftestで検査できます。conftestをCIに組み込めば、PRに含まれた変更が問題ないかどうかを機械的にチェックできるというわけです。

これまでの10Xでも、Regoを書きconftestを使って検査してきていましたが、Rego言語のとっつきにくさ/学習コストの高さがネックでポリシーの追加が億劫でした。しかし最近はLLMがかなりマチュアになり記述コストがゼロになったので年末に一気に再整備しました。

conftest以外にも社内の組織ポリシーを評価してconfig類にapplyする手段はありそうですが、自然言語(AIによるRego記述)を通して「こう書いてほしい」を強制できているため今はconftestがお気に入りです。AIによる検査は、自然言語のみだと評価結果にゆらぎが出る可能性がありますが、RegoというDSLを通すことでAIと人間の共通プロトコルができ、毎回必ず同じ評価結果を得られます。conftestを使うことでレビューで人間が同じ指摘をする必要もなくなるし、例えば「ここハイフンを使ってほしくないんだよなぁ」みたいなもう申し訳ないnitsレビューもconftestを通して代弁することができます。裏を返せばtestが通ってconftestも通っているなら、問答無用にApproveできる状態というのが理想かもしれません。

今回は再整備して追加したポリシーなどを含めて、10Xでどんなポリシーを定めているのかを一部紹介します。

続きを読む

OpenSSL x509 コマンドはPEMのフォーマットの検証まで行っていない

10X SREの栗原です。
この記事は10X 新春ブログリレー 2026の1月7日分の記事です。

OpenSSLのコマンドではエラーにならなくても、Google Cloud側の証明書アップロードで弾かれることがあるため、PEMを厳密に検証するステップを追加して再発を防いだ、という話です。

続きを読む