アイザック エンジニアの金井です。 私の所属しているチームでは高頻度デプロイを伴う良い開発体験で開発ができていると感じております。
前回書いた記事はこちらですね。
前回は高頻度デプロイに貢献するスモールチーム体制・裁量の高さなどの視点を紹介してみましたが、今回は開発のプロセス面で継続的インテグレーションの実践状況について紹介できればと思います。
といいますのも、MartinFowlerの継続的インテグレーションの最新化された記事が上がっておりましたので、こちらを参考・引用しつつ私の所属しているチームの状況を伝えてみたいと思います。
事業・システム環境
- 2年目グロースフェーズの新規事業
- CtoCサービス、24h365d利用ユーザがいる
- シンプルなモノレポ・モノリスサービス
- React Native, NestJS, Next.Js, Hasura, GCP
チーム構成
- PdM1名
- エンジニア フルタイム2名・パートタイム3名
- マーケター 2名
- デザイナー 1名
- CS 2名
継続的インテグレーションとは何でないか
まず、継続的インテグレーションとは何でないか。が重要に思いますが、
- チームが全員自動テストを書いている
- PUSHしたら自分の作業ブランチでCI Service(Jenkinsなど)にてBuild & Test が実行され、Feedbackを得ている
記事にもある通り、これは継続的インテグレーションができている状態ではありません。
その本質は、チームの全員が管理されたソース コード リポジトリに対して、少なくとも毎日、頻繁に統合するという単純な実践にあります。この実践は「継続的インテグレーション」と呼ばれます。
こちらですね。全員が頻繁に統合することで、統合のコストの低減、改善したコードの即共有など、利益を得ます。 頻繁な統合による利益の詳細は元記事を参照いただければと思います。
フィーチャーブランチは利用しております
3つの統合スタイル: プレリリース統合, フィーチャー ブランチ, 継続的インテグレーション
1つのブランチに全員でPUSHし続ける方向の "継続的インテグレーション" のスタイル。私の所属しているチームではこちらは採用しておりません。 業務委託パートタイムのメンバもおり、働き方を一緒に揃えていくところまで時間を使えない部分もあるため、"フィーチャーブランチ" スタイルを採用しております。
main (prod deploy) <- develop (stg deploy) <- features の形ですね。各メンバがfeatureブランチを利用してdevelopへのPRを出しますが、そのブランチはできる限り短命になるように意識しております。 統合がディレイすると予期せぬ追加作業が増えるためです。
この短命にするための方法・チームの動きがいくつかあります。
Hide Work-in-Progress. デプロイ != リリース
継続的インテグレーションとは、少し前進し、ビルドが正常になったらすぐに統合することを意味します。多くの場合、これは、ユーザーに表示される機能が完全に形成され、リリースの準備が整う前に統合することを示唆しています。
完成していない機能も統合する。こちらを実践できるかどうかがポイントに思います。
デプロイとリリースの分離と言われるものですね。デプロイ=本番環境にコードを載せること。リリース=ユーザに公開すること。
踏まえて、チームとしては、完成していない機能でもdevelopにマージして良い。キリの良いタイミングでPRを作成して良い。という動きになります。
完成しないとマージできない => 大きなPRになりがち, 寿命が長くなりがち, レビューが重くなりがち => 統合がディレイし、統合に伴うExtraWorkが増えがちなためです。
Keystone インターフェイスを使用することで、本番環境でコードが実行されるのを防ぐことができます 。新しい機能へのパスを提供するインターフェイスがコードベースに追加される最後のものになるようにします。
Keystone インターフェイスという言葉はわからないですが、実際に呼び出されないコードとして開発を進める
こちらのようなアプローチもよく利用していると思います。Backendで言えば、Presentation層をSkipしてのTestなどで、ほとんどの開発を進めることができますし、単純にフロントからまだ呼び出していない状態のものもあります。
誰もが、開発を進めている間に、リファクタリングをしたり、共通化が進んだりすることがあります(むしろ推奨)。そういったコードはできるだけ早く統合して、全員の持ち物にしていきたいので、早期に統合する価値があります。統合されない大きなコード改善はとても怖いものです。小さく頻繁にすることを大切にする姿勢です。
2週間のリファクタリング セッションでコードは大幅に改善される可能性がありますが、他の全員が過去 2 週間を古い構造の作業に費やしているため、マージに時間がかかります。これにより、リファクタリングのコストが法外なレベルまで上昇します。頻繁な統合により、リファクタリングを行う者と他の全員の作業が定期的に同期されるようになり、このジレンマが解決されます。
この辺りにとても共感できます。
Dark Launching を使用すると、一部の変更をユーザーに表示する前に実稼働環境でテストできます。
ダークローンチの定義は揺れがありそうですが、ここでは本番でユーザには影響がない形で新しい処理を実行してみることと置いてみます。 こちらも実践しております。例えば、DBレコードに基づく複雑なロジック新しいリード系のAPIがあった際に、実際のユーザの操作トリガで裏では新しいAPIを実行しておきます。 ユーザには影響はないですが、ログの結果などからAPIの結果が正しいものか、本番環境のデータに基づいて検証ができたりします。
複雑な本番データに基づく処理は、テストの準備が難しく大変なことがあります。もちろん自動テストを伴いながら実装にて、基本的なケースは抑えるわけですが、それでもUnknownなものを全て潰したかどうかは自信が持てないこともあります。
そんな時は、ダークローンチを利用して本番でテストをしたりしております。本番環境には”完璧に完成させてからでないとデプロイしてはいけない”という考えから少し離れている感覚です。
ダークローンチでのテストを通して発見したコーナーケースを自動テストと実装に落とし込みます。
逐次的な 実装 => Test => リリースというプロセスと比較すると、何が”実装フェーズ”なのかという見方も少し変わっているかもしれません。本番からもFeedbackを得て実装を確かなものにしていきます。
これは前提として、本番デプロイにかかる労力がとても小さく、大きなイベントとして捉えていないことが可能にさせる部分もあります。デプロイの自動化や、このようなアプローチを可能にできるチームの裁量がアイザックにはあり、とても柔軟に働けています。
少し統合への貢献から逸れたかもわかりませんが、完璧にしないとマージしてはいけない。を軽減するところにリーチしていると思います。
Keystone は潜在コードのほとんどのケースをカバーしますが、それが不可能な場合には、Feature Flagsを使用します。
Feature Flagも採用しております。
ReactNativeでのNativeAppがフロントですが、特別なツールは使っておらずフロントから、現状のFlag状況を取得するAPIを用意しております。
これにより、新しい画面、新しいフロントの機能もLocal, STG環境ではフラグをオンにして開発検証を進めつつ、デプロイはブロッキングせずに、本番にはデプロイ可能になります。ユーザへの公開はしません。
また、本番環境にて、社内ユーザだけの先行公開も可能です。こちらもダークローンチと同じ理屈で、本番で新しい外部連携などを伴う複雑な機能を安心して確認できます。 例えば、新しく決済周りの機能を増やした際に利用しました。外部連携の設定状況などが本番でしっかり疎通できているかは、やはり試してから公開したいためです。
他にも、やはり本番の実際のユーザのデータ入っている環境で触るとUI/UX面などで見えてくることもあるので、そこの期待で利用することもあります。 カナリアリリースにあたるような部分の狙いでしょうか。
NativeAppですが、RemoteConfigとして審査リリースを通さずに、機能状況を切り替えができるのもついてくる利点ですね。
また、少し話がそれますが、IOSのみの機能、特定のエリアのユーザだけの機能などもフィーチャーフラグによって管理しています。
継続的インテグレーションでは、機能の完了やリリース頻度に束縛しないことが重要です。
統合を早めて、統合というイベントに伴う追加作業や、ストレスをなくしていくことを最大化していくには、完了していないものを統合してはいけない、デプロイしてはいけない。から離れる必要があると思いますし、この点なのかと思います。
よく継続的インテグレーションをしたいが、大きな機能の開発ブランチは寿命が長くなってしまうので難しいという会話が起きます。それはこの前提が持てていないためと思います。 大きな機能でも自動テストを伴い、上述のテクニックなどを利用し、ユーザに影響がない状態があればマージは可能です。
作っているプロダクトは1つです。1つのプロダクトが動作できることを全員で育てていけば良い、していきたいという感覚です。ブランチが分かれている間はコピーされたプロダクトを複数育てているという感覚でしょうか、それをできるだけ避けたい気持ちです。
適切なテストがなければ健全なメインラインを維持できないため、継続的インテグレーションは自己テストコードなしでは機能しません (実装と共に自分で作る自動テスト)
統合した影響範囲がわからないような状態では継続的インテグレーションの実践は難しいです。
常に統合し、他に影響がないことを自信が持てるような、自動テストを伴う開発をチームが習慣を持っている必要があります。 私の所属しているチームではテストを書く習慣を皆で意識し合っております。
ここで強調したいのは、CI サービスを使用するときは、バージョン管理システムの参照インスタンス上のメイン ブランチであるメインラインでのみ使用することです。CI サービスを使用して複数のブランチを監視および構築するのが一般的ですが、統合の重要な点は、すべてのコミットが 1つのブランチに共存することです。CI サービスを使用してさまざまなブランチの自動ビルドを実行すると便利な場合がありますが、それは継続的インテグレーションとは異なります。
こちらはチームの状況・人数など文脈影響はありそうですが、私の所属しているチームでは、CIサービスによる自動ビルド、テストはdevelopブランチ1つでしか動かしておりません。
そもそもブランチが短命であること、軽微な修正をマージするにもCIの完了を待たなければならないこと、結局developで統合されたCIの結果が重要であること、(お金を少し節約したいこと)。 一般的に早期にチェックができる方が良いという考え方があると思いますが、今のチーム人数、テストに対する習慣。
などなどを踏まえて、フィーチャブランチに対してのCI実行はしていない状態ですが、現状困りごとは感じておりません。
しかし、それは継続的インテグレーションがすべての人に適しているという意味ではありません。「献身的で熟練したチームがそれを利用することにマイナス面はほとんどない 」と私が言ったことにお気づきかもしれません。 「熱心に取り組んでいる」とは、製品にフルタイムで取り組んでいるチームを意味します。これに対する良い反例は、1 人か 2 人のメンテナと多数の貢献者がいる古典的なオープンソース プロジェクトです。このような状況では、メンテナーですらプロジェクトに週に数時間しか携わっていず、コントリビューターのことをよく知らず、コントリビューターがいつコントリビュートを行うか、コントリビューターがコントリビュートを行う際に従うべき標準についてよく把握していません。これは、フィーチャー ブランチのワークフローとプル リクエストにつながる環境です。 チームのコミットメントに合ったどの統合ポリシーを使用するかについては、私たちの判断が必要です。
最初に触れた通り、業務委託パートタイムメンバもおりますので、フィーチャーブランチスタイルかつ、ブランチを短命にする努力をする。という選択をして見ております。
上記のような実践状況を踏まえての所感
いかがでしたでしょうか、元記事の観点を踏まえつつ私の所属しているチームの実践状況を紹介してみました。
上記のようなテクニックなど駆使してまで頻繁に統合することに価値を感じているのか、という点でいうと、開発体験は良い状態に感じております。 メンバ間の作業の状態、STG環境の状態に依存して、待ちが発生したりしないことがストレスがないですし、結果としてそれが継続的デリバリ、高頻度な本番デプロイ、リリースに繋がり、ユーザに迅速に機能を提供しやすい状態を作れていると感じます。
実践ができる前提の組織環境がアイザックにはあります
高頻度のデプロイの実践、それに貢献する継続的インテグレーションの実践。 これらはテクニック面はもちろんあるのですが、それ以上に、チームに開発の進め方の裁量が与えられていること、開発のプロセスについて開発メンバに任せてもらえるBizメンバとの関係性などが合ってこそだと思います。
リリース!=デプロイという言葉があるわけですが、リリース当然Biz側と連携して戦略的に行いますが、デプロイは開発チームで判断して実行できる。ここがKeyFactorなのかなと思います。
アイザックには沢山の事業がありますが、組織全体として、そのような文化あると思います。
いかかだったでしょうか!
いかがだったでしょうか、アイザックの開発現場のイメージが伝わればと思います。
アイザックの文化などがわかる記事もたくさんありますので、ぜひ読んでみていただければと思います!
記事のような環境・考え方に共感いただける、興味がある方や一緒に作り・良い事業作りを目指し続けていける方とぜひ一緒に働きたいと思っております!
アイザックでは、一緒に「世の中を実験する」仲間を募集しています!ご興味を持ってくださった方は、こちらのお問い合わせフォームからエントリーください。
採用に関する詳細は以下のページをご覧ください。