この投稿ではシフトレフトの原則を検討し、スタックされた PR がますます有用になることを示唆しています。
ピアコードレビュープロセスはソフトウェア開発の重要な部分です。ソフトウェアの品質を維持し、標準、プロジェクト要件、スタイル ガイドへの準拠を促進し、学習と知識の伝達を促進します。
十分に小さなコード変更をレビューする場合は有効性が高くなりますが、変更のサイズが大きくなると有効性は指数関数的に低下します。効果を発揮するために必要な精神的な集中力を維持するには、大規模なコード レビューを行うのは大変な作業です。
通常、レビュー期間が長くなるほど、全体的なレビューの効果は低下します。
では、なぜプル リクエスト (PR) のサイズを制限できないのでしょうか?多くの変更は小さく始めることができますが、小さな 2 行の変更が突然、レビュー担当者との何度もやり取りを含む 500 行のリファクタリングに成長する可能性があります。
一部のエンジニアリング チームは、作業を継続しながら長期間実行される機能ブランチを維持するため、レビューが困難になります。
では、どのようにして適切なバランスをとればよいのでしょうか?単純。スタックされた PR を使用します。
スタックされたプル リクエストは、単一のプル リクエストに大規模なモノリス変更をバンドルするのではなく、小規模な反復的な変更を加え、互いに積み重ねられます。スタック内の各 PR は 1 つの論理変更のみに焦点を当てているため、レビュー プロセスが管理しやすくなり、時間が短縮されます。
また、私たちは昨年、このヘルプがコードの変更をファイルや機能ごとに分類するのではなく、物語としてどのように表現するかを説明する記事を書きました。
より効果的なコードレビューの文化を構築する以外にも、スタック型 PR にはいくつかの利点があります。
大規模な機能を実装していると想像してください。機能全体を作成してからコードレビューをリクエストするのではなく、最初のフレームワークを切り出し、すぐにフィードバックに出すことを検討してください。
これにより、設計に関するフィードバックを早期に取得できるため、膨大な時間を節約できる可能性があります。
スタックされた PR は、変更が継続的に統合およびテストされるため、シフトレフトの実践をサポートし、問題の早期検出と修正が可能になります。
変更は、問題を早期に発見するために少しずつマージされますが、本番環境がダウンしないことを祈りながら 1 つの大きな変更をマージするのではありません。
コードレビューは後世にとっても素晴らしいものです。コードの変更は、機能の実装の背後にある思考プロセスを物語るものであるため、変更の内訳によって、より効果的な知識の伝達が行われます。
チームメンバーが変更を理解しやすくなり、将来に向けた知識の共有が促進されます。
コードのレビューと承認を待つのは、イライラするプロセスになる可能性があります。スタックされた PR を使用すると、開発者はレビュー担当者が以前の PR を承認するのを待たずに、機能の複数の部分に取り組むことができます。
では、なぜもっと多くの開発者がコードレビューにスタックされた PR を使用しないのでしょうか?
この積み重ねられた PR ワークフローは、コード レビューを管理しやすくし、開発者の生産性を維持するという望ましい実践の両方に対応していますが、残念ながら、Git または GitHub のどちらでもネイティブに十分にサポートされていません。
その結果、エンジニアがこのスタッキング技術を既存の Git および GitHub プラットフォームに組み込めるように、オープンソース コミュニティ全体でいくつかのツールが開発されました。しかし、PR を積み重ねることは話の一部にすぎません。
コードレビューのフィードバックを受け取り、スタックの一部に変更を加えると、後続のすべてのブランチでリベースして競合を解決する必要があります。
例を挙げてみましょう。スキーマの変更、バックエンドの変更、フロントエンドの変更を必要とする変更に取り組んでいることを想像してください。
これにより、最初に簡単なスキーマ変更をレビュー用に送信し、それがレビューされている間にバックエンドとフロントエンドでの作業を開始できるようになりました。スタックされた PR を使用すると、これら 3 つの変更すべてを 3 つの異なるレビューでレビューできます。
この場合、次のようなスタックが作成される可能性があります。 ここで、 demo/schema
、 demo/backend
、 demo/frontend
は、互いに積み重ねられた 3 つのブランチを表します。
ここまでは理にかなっていますが、新しいコミットの作成が必要なスキーマ変更に関するコード レビュー コメントを受け取った場合はどうなるでしょうか?突然、コミット履歴は次のようになります。
ここで、後続のすべてのブランチを手動でリベースし、すべての段階で競合を解決する必要があります。 10 個のスタックされたブランチがあり、競合を 10 回解決する必要がある場合を想像してください。
しかしそれだけではありません。PR をスタックにマージするのは本当に悪夢になる可能性があります。 PR をマージするには、 squash
、 merge
、およびrebase
の 3 つのオプションがあります。それぞれの舞台裏で何が起こっているのかを理解してみましょう。
squash
コミットの場合、Git は PR の既存のすべてのコミットから変更を取得し、それらを 1 つのコミットに書き換えます。この場合、それらの変更がどこから来たのかに関する履歴は保持されません。
merge
コミットは、2 つ以上のコミットの組み合わせで表される特別なタイプの Git コミットです。つまり、 squash
コミットと非常によく似た動作をしますが、その親に関する情報もキャプチャします。一般的なシナリオでは、マージ コミットには 2 つの親があります。ベース ブランチ (PR がマージされる) の最後のコミットと、マージされたフィーチャー ブランチの最上位のコミットです。
このアプローチではコミット履歴により多くのコンテキストが与えられますが、望ましくない非線形の git 履歴が誤って作成されてしまいます。
rebase
とマージの場合、Git はコミットをベース ブランチに再書き込みします。したがって、 squash
コミット オプションと同様に、元のコミットに関連付けられた履歴はすべて失われます。
通常、PR をスタックするときにmerge
コミット戦略を使用している場合、作業は少し簡素化されますが、ほとんどのチームは、git 履歴をクリーンに保つためにその戦略を使用することを推奨しません。つまり、 squash
またはrebase
マージのいずれかを使用している可能性があります。
これにより、後続のマージされていないスタックされたブランチすべてに対してマージ競合が発生します。
上の例では、最初のブランチのdemo/schema
メインラインにスカッシュ マージするとします。 A1
とA2
の変更を含む新しいコミットD1
が作成されます。
Git はD1
どこから来たのかを知らず、 demo/backend
はまだA2
に基づいているため、 demo/backend
メインラインの上にリベースしようとするとマージ競合が発生します。
同様に、 demo/frontend
リベースした後にdemo/backend
をリベースすると、同じ問題が発生します。したがって、10 個のスタックされたブランチがあり、そのうちの 1 つをマージした場合、これらの競合を 9 回解決する必要があります。
私たちはまだ表面をなぞったばかりです。コミットの並べ替え、ブランチの分割、折りたたみ、名前変更など、他にも多くのユースケースがあり、スタックされた PR を処理するときに管理するために膨大なオーバーヘッドが発生する可能性があります。
そのため、Aviator の一部としてスタック型 PR 管理を構築しました。
Aviator は、既存のツールの上に位置する拡張レイヤーと考えてください。 Aviator は、GitHub、Slack、Chrome、および Git CLI に接続して、強化された開発者エクスペリエンスを提供します。
Aviator CLI は他のすべてのものとシームレスに動作します。 CLI は Git 上の単なるレイヤーではなく、GitHub 全体のスタックのコンテキストも理解します。例を考えてみましょう。
スタックの作成は非常に簡単です。この場合を除き、 av
CLI を使用してブランチを作成し、スタックが確実に追跡されるようにします。たとえば、スキーマ ブランチと対応する PR を作成するには、次の手順に従います。
av stack branch demo/schema # make schema changes git commit -a -m "[demo] schema changes" av pr create
Aviator は GitHub にも接続されているため、スタックを簡単に視覚化できます。
または、ターミナルから視覚化したい場合でも、CLI コマンドを使用して実行できます。
スタックの使用は簡単になります。任意のブランチに新しいコミットを追加し、スタック内のどこからでもav stack sync
を実行するだけですべてのブランチを同期できます。 Aviator はすべてのブランチを自動的にリベースするため、実際にマージ競合が発生した場合は、一度解決するだけで済みます。
これは、Aviator ツールが既存のツールよりも優れている点です。 Aviator では、数千もの変更の自動マージを大規模に管理するために、最も高度な MergeQueue の 1 つを構築しました。
Aviator は、CLI およびスタックされた PR とのシームレスな統合をサポートしています。したがって、PR の部分スタックまたは完全スタックをマージするには、CLI av pr queue
を使用するか、GitHub にコメントを投稿することで、PR を Aviator MergeQueue に割り当てることができます: /aviator stack merge
。
Aviator は、キューに入れられたすべてのスタックの検証、更新、自動マージを順番に自動的に処理します。
PR がマージされたら、今度はav stack sync --trunk
を実行してすべての PR を更新し、マージされたすべての PR を消去します。
スタックされた PR は、変更をより小さな部分に分割する必要があるため、最初はより多くの作業のように思えるかもしれません。ただし、コード レビューの効率の向上、フィードバック ループの高速化、学習の機会の強化は、確実にこのオーバーヘッドを上回るでしょう。
私たちがシフトレフトの原則を受け入れ続けるにつれて、スタック型 PR はますます有用になるでしょう。
Aviator CLI は、スタックされた PR をはるかに簡単に管理するための優れた方法を提供します。 CLI はオープンソースで完全に無料です。ぜひお試しいただき、ディスカッション掲示板でフィードバックを共有していただければ幸いです。
Aviator では、開発者がより速く、より優れたものを構築できるように、第一原則に基づいて開発者生産性ツールを構築しています。