日々常々

ふつうのプログラマがあたりまえにしたいこと。

脱ブランチファースト

あるいは「プルリクエストをやめてみた」

チーム構成とかにもよるんだろうけど。Gitかつフォークされないプロダクトでの話です。OSSとかは全然話は変わります。

問題とアプローチ (2019-10-25T15:20 追加)

表出している問題と、ここでのアプローチを書いておきます。

ブランチファースト(造語)

「ブランチファースト」はこのエントリでの造語です。コードベースに変更を加える際に「まずブランチを作成する」から始めることを指します。 作業単位でブランチを作成、ブランチでコードを変更してプルリクエスト、レビューを経てメインライン( master ブランチ)に反映までがブランチファーストのスコープになります。 よくあるスタイルだと思いますし、ブランチだけ作成して変更せずプルリクエストを作成する拡張もありますね。

プルリクエストを挟まずにメインラインにマージするものは含みません。 ……名前微妙な気がしてきた。

表出し ている がちな問題

  • マージに時間がかかっている
  • マージミスが起こりがち
  • マージしたらテストが通らない(個々のブランチは通るのに)
  • フィーチャーブランチの生存期間が長い
  • フィーチャーブランチが乱立している
  • リリースブランチにしかないスクリプトが忘れられがち
  • ボーイスカウトルール的なリファクタリングが重量プロセスになる
  • プルリクエストが滞留している
  • プルリクエストのレビューは変更部分以外にコメントしづらい

アプローチ

  • 全員がメインラインに直接 commit して push しよう

と言うことで続きをどうぞ。

フィーチャーブランチをやめてみた

フィーチャーブランチ。タスクブランチとかいろんな呼び方があると思うけど、特定の作業毎に作るブランチ。チケットやissue単位で作るブランチもこれに該当します。

フィーチャーブランチを作るとメインラインとの間でマージが必要になる。メインラインにフィーチャーブランチをマージする際の負荷を制御するために、メインラインからフィーチャーブランチへのマージを頻繁に行っておくとかあるけど、フィーチャーブランチを作るから発生する作業にみえるんです。やること増やしちゃってないかなって。

リリースブランチをやめてみた

リリース作業を行うためのブランチ。 開発できたものを取り込んで、リリースのための作業をして、えいやとリリース。 リリース先はステージング環境だったり、プロダクション環境だったり。 環境ごとにリリースブランチを作って、今どんなソースがリリースされてるかわかる。

OKなるほど。タグでよくないかな。

メインラインとリリースブランチに差があることがある。その差分をメインラインに入れれないのはなんでだろうって見てみると、リリース用の設定だとかスクリプトとか。他にもフレームワークなどがメインラインに入れづらい設計だったりすることもある。かもしれない。少なくとも私はリリースブランチがなかったら不可能というのは記憶にないです。

メインラインとリリースブランチが一致すると、ほんとタグがわりに使ってるだけになる。無駄にブランチの形してるから、リリースのたびにマージが発生する。FastForwardで済むんだけど、リリースの記録とか残したいし、で --no-ff したりする。いやほんとタグでいい。

リリースのための設定やスクリプトであってもメインラインに置いて、リリース以外の時も使えるものってあったりするので、メインラインに置いて目に入りやすくしておくのがいいかな。

使いたくなるのはわかる

ブランチ。使いたくなるのはわかるつもりです。私も「ブランチが軽量に使えるGit超便利!」とか思ってました。

ブランチって機能があるし、どこでも使ってるし、それなりに上手くいってる(上手くいくってなんだ?)ように見える。なんちゃらフローとか実績のあるブランチ戦略もある。 ブランチ戦略って言葉格好いい。 使うには十分な理由かもしれません。

ブランチを使うことで作業が独立して行えて、変更差分のレビューがしやすい。なるほどわかる。

けど。けどね。

ブランチを使うと背負いこむこと

ブランチを使うと作業がブランチに閉じます。閉じるのがいいって話があるのかもしれないけれど、例えばフィーチャーブランチならそのフィーチャーと関係のないリファクタリングがしづらくなります。

例えば名前変更、パッケージ変更なんて顕著ですね。フィーチャーブランチの効果の一つに「差分がわかりやすくなる」と言うのがあるので、フィーチャーブランチの中でその手の作業をするのは抵抗が生じてきます。

この例だと、

  1. フィーチャーブランチの外でリファクタリングのフィーチャーブランチを別に作成
  2. リファクタリングのフィーチャーブランチで作業してメインラインにマージ
  3. メインラインからフィーチャーブランチにマージ

のようなステップを踏むことで、フィーチャーブランチはフィーチャーに閉じれます。うまくいくように見えますが、全体に渡る大規模な名前変更の場合、3のマージのコストが高くなりがちです。その場合にマージを諦めてフィーチャーブランチを破棄してやり直すと言う手が取れますが、なかなか捨てづらいようでマージ頑張るのをよくみます。で、破棄しやすいようにフィーチャーブランチの生存期間を短くするルールが作られて、これはこれでいいと思うんですが、ルールでがんじがらめになっていくのはあまり好きじゃない。

と言うか名前変更のためにこんなステップ踏みたくないし、これを終えるまでフィーチャーブランチの中は違和感ある名前でやることになる訳だし、フィーチャーブランチで作業してる中で見出した名前変更を単独で適用するのもなんだかなーとか……。

ともかく、ブランチを作るとマージのコストとリスクを背負いこみます。 マージはメインライン origin/master からローカルブランチ master へのマージ以外でやりたくない。

つまり、プルリクエストをやめてみた

プルリクエストのような差分だけに注目するレビューが無駄とは言わないのですけど、いつも必要な訳でもないと思うんです。

差分レビューの欠点の一つはボリュームが大きくなったらみづらくなる、場合によっては見なくなること。変更差分が大きいほどしっかり確認する必要があると思うんですが、差分が小さい時だけ見るのを促進する仕組みには疑問を感じています。

もう一つは差分を含めた全体のレビューがしづらいこと。差分だけだと見づらいぎこちなさは気づけませんし、プロダクトとしては個々の差分より全体に価値があると思うのですよ。そして差分で出ていないところへのコメントもつけづらい。コードのリンク併用で書けばいいんだけど、そういう特別な対応が必要になるんですよね。

なので とっととメインラインに入れてしまって、必要ならそこから直してしましょう でいいと思う。

「それだとどんなことするかわからない」とかお声が聞こえてくる気がします(実際言われたこともある)が、それって何をするかわからないメンバーを既にチームに入れてるってことですよね。コードだけ取り繕ってる場合ではないのでは……。

チームに入ったばかりだとかでお互い様子見してるときは「閉じた安全な環境」としてブランチ+プルリクエストもいいと思います。でも最初のうちだけかな。 ブランチ+プルリクエストをやってるうちは、プロダクト全体への責任感なんて出てきづらいと思う訳です。 ペアプロでもモブプロでもなんでもして、早くメインライン直接触ってもらえるようにする。で、コードのどこでも自分の意思で触っていい、触ってダメなら戻せばいい、とかやってるうちに「ちょっと名前わかりづらいかな」とかをカジュアルにリファクタリングできるようになってくるかなーと。

この辺り、根底には「できるようになってからやりましょう」ではなく「やってることしかできるようにならない」という考え方があります。失敗しても死なないんだから、準備はそこそこにしてやっちゃえばいいと思うんだ。

例えば、作りかけがコミットできなくなると言う話

抽象化によるブランチ でなんとかなるはずです。橋の架け替えとか、ストラングラーパターンとか。色々手はあります。

「いろんなところを一度に変えなきゃいけないからブランチが適切」はたぶん変更箇所を局所化するリファクタリングを先に行うのが適切なんですが、コストがかかるのも事実。でもそう言うのに挑むことで付く設計力とかもあると思います。ブランチファーストはそれを阻害してるんじゃないかなって。

「レガシーコードからの脱却」にも記述があるので引用しておきます。

コードがシステムに統合されると、リスクはほぼゼロになる。コンポーネントが別ブランチになっていてリリース前に統合される場合、リスクは統合されるまでわからない。ブランチを使う代わりに、フィーチャーフラグを使用して、使う準備のできていない機能を無効にしよう。

7章 プラクティス3 継続的に統合する/ 7.7 実践しよう/ 7.7.2 リスクを減らす7つの戦略 / ブランチを避ける

レガシーコードからの脱却 ―ソフトウェアの寿命を延ばし価値を高める9つのプラクティス

レガシーコードからの脱却 ―ソフトウェアの寿命を延ばし価値を高める9つのプラクティス

もちろん、適切な場合には使う

ブランチがあっているものもあります。なので禁止したいわけじゃない。 ブランチファーストになっているのに違和感があって、必要な時だけ使うのがいいなと思ったのでやめてみたと言う話です。 禁止したいわけではありません。 作り捨ての実験とか。複数バージョンをメンテナンスしなきゃいけないとか。抽象化によるブランチの設計コストが全く見合わないとか。他にも色々あると思う。「ブランチが適切」となる場合もあります。適切なら素直に使うのは当然のお話。

参考

このエントリには直接関係ないし、私が読んだのも結構前でだいぶ忘れてるけど、構成管理本挙げておきます。

パターンによるソフトウェア構成管理 (IT Architects’ Archive―ソフトウェア開発の課題)

パターンによるソフトウェア構成管理 (IT Architects’ Archive―ソフトウェア開発の課題)

2006年(原著は2002年)、10年以上前ですか。古い本に挙げていいと思うけれど、それほど陳腐化してないと思います。一読しておくと整理しやすくなるんじゃないかな。

「レガシーコードからの脱却」を読みました

頂きまして、ようやく一通り目を通したので書きます。ありがとうございます。 どこを切り取っても話題の中心に置ける、そう言う本でした。

ざっくりどんな本かと言うと

原著「Beyond Legacy Code」が2015年とそこそこ新し目の本ではありますが、目新しいことは書いていません。見たことも聞いたこともないようなものは書かれていませんでした。プラクティス自体は目新しくはないですが、プラクティスの出自や必要とされた背景、実践における戦略などに焦点が置かれている点は目新しいと言えます。

この本の価値は様々なプラクティスから9つだけピックアップされていること。少ないことに価値があります。数を絞った上で個々の背景をしっかり書いたものになっています。

タイトルの「脱却」はレガシーコード改善ガイドのような既存のレガシーコードとの戦い方を彷彿とさせますが、帯には「レガシーコードを初めから作らない」と新規プロジェクトの序盤のように取れることが書かれています。実態は レガシーコードを産み育てる土壌がターゲット で、フェーズに関係なく参考にできる内容となっています。

本書2章に「本物の虫と同じように、バグには繁殖に最適な条件がある。」とありましたが、レガシーコードも同じでしょう。土壌改善なので、別に序盤でしかできないものでも、既にレガシーコードが存在していないといけないものでもありません。流石にプラクティス9の「レガシーコードをリファクタリングする」はレガシーコードが存在しないとできませんが。

面白いのが「人が一度に記憶できるのは7プラスマイナス2個」という数へのこだわり。 副題にある「ソフトウェアの寿命を延ばし価値を高める9つのプラクティス」は当然9つなのですが、各プラクティスの「実践しよう」には7つの戦略が2セットぶら下げられています。例えば。

  • 5章 やり方より先に目的、理由、誰のためかを伝える
    • プロダクトオーナーのための7つの戦略
    • より良いストーリーを書くための7つの戦略
  • 6章 小さなバッチで作る
    • ソフトウェア開発を計測する7つの戦略
    • ストーリーを分割する7つの戦略

といった感じ。目次に無い物としては12章に6つの「変更を難しくするプラクティス」があるなど。まあ7±2個覚えられるからといって、9+(7*2)なんて覚えられない訳ですが、ややもすれば10を超えそうな列挙に数の制限がつけられています。(戦略の方は無理矢理増やした感のあるものがないとは言わないけれど。)

たぶん読まなくていい方

新しい知識が欲しい方で、ある程度の読書家な方。たとえば以下の本のほとんどを読了しかつ実践されている方が新しい手段を求めて読むと、イマイチという感想になると思います。

(参考文献に上がっているもののうち私が読んだことがあるもので、内容のリンクが強いと感じたものを選びました。オブジェクト指向入門やデザインパターンも参照されていますが、それらはそこまででもないかなって。)

あと、アジャイルって文字を見るだけアレルギー反応が出るような方も読まなくていいと思います。徹頭徹尾アジャイルラクティスです。

たぶん読んだらよさそうな方

伝聞や表層だけのなんちゃってアジャイルに騙されて(言い方が悪い)上手くいかず、アジャイルを仕事では役に立たないおもちゃのように感じている方。読めば誤解が解ける可能性があります。

知識や実践を通じた理解は十分でも、自分の考えの整理などを改めてしたい方。プラクティスと原則の話あたりを踏まえて、個々のプラクティスや戦略を読んでいくといい整理になるんじゃないでしょうかね。おさえてないところや捉え方の違いなどもあって、いい壁打ちになると思います。

あまり知識がなかったり、経験の浅い方。冒頭で書いたように様々なプラクティスから9つだけをピックアップした、新設の高速道路です。掘り下げの方向は違いますが、サイズや値段的にも達人プログラマーなどの古典・鈍器本に対するリーダブルコードのような印象。鈍器本に抵抗があるなら是非。

蛇足

タイトルを見た時の感想は「またレガシーシリーズか」でしたね。 とはいえ訳者の方々が方々なので期待せざるをえず、そればかりか頂けてしまったのでこうして読んだわけです。

で、読んでみたらこれが面白くて仕方がない。第一部の導入が良すぎて、そのノリで第二部のプラクティスを読むとどこまでも潜っていくことになりました。時間かかるの仕方ない。 本当はもう少し早くブログ書きたかったんですが、いちいち考えちゃってツイートしたりしちゃって、いつ読み終わるかわからない感じになってしまった。いやページ数の割に考えられるネタ多過ぎるんですよ……

あと、Beyondの意味とか一通りみて考えてみたのですが、脱却以上にしっくりくるものは思いつかず……レガシーコードを超えて?レガシーコードの向こう側に??うーむ、やっぱ脱却が合ってそうだなぁ。

いくつかは私のこれまでのブログやセッションで話したことがほぼそのまま(少なくとも私にはそう見える)書かれていたり、今書いてる途中のブログとネタ被りしてるものとかもあって(近いうちに公開)。参考文献の傾向とか見ればそれはそうなんだろうって感じではあるんですが、なんか勝手にシンパシー感じたりしてました。

とりあえずもう一回読みます。

プルリクエストとマージリクエストと。

short answer

プルリクエストとマージリクエストに違いはありません。 同等の機能が別の呼び方をされているだけです。

名前の由来を考えてみる

名前の由来を考えてみるのも面白いと思うんです。 ここに書いているのは私の予想ですが、大外しはしていないはず。 仮に違ったとしても別に良くて、名前の由来を考えてみることは、名付けのいい訓練になります。なるはず。たぶん。

f:id:irof:20190929195255p:plain
こんな感じ。たぶんpullは使われてない。

プルリクエスト、通称プルリクは元々GitHubの言葉です。Gitの機能ではありません。 テキストではPRと略されることもあるけど、ピーアールって読むと何を宣伝したいんだろう(Public Relationsとは意味変わっちゃってますね)ってなるからか、発音はプルリクなことが多いと思います。

Gitのpullfetch+mergeなのだけど、このGitHubでForkしたリポジトリがフォーク元に対してpullを要求するのがプルリクエストと言う名付けの元。ちなみにForkはGitの機能でもGitHubの造語でもなく、元々OSS界隈で使われてた言葉。

GitHubは重々しく考えられていたForkを軽くできることに注力して、そのためにForkしたリポジトリからのフィードバックを扱いやすくすることを重視した結果、プルリクエストと言う名前を全面に出すことにしたんだと思います。 pullがボタン一発でできるならForkもしやすい……そんな感じでしょうかね。 なんのためにForkを軽くしたかったか、とかも妄想していくのも楽しいです。プルリクエストって名前からボトムアップでビジョンにたどり着けるかって感じで。

で、pullfetchは裏で走れば十分で、ユーザーに重視されるのはmergeの方。 単なるmergeをプルリクエストで扱うのは機能的に問題ないし、ユーザーとしても分ける必要はありません。 なので同じリポジトリ内の単なるmergeもプルリクエストで扱われています。

f:id:irof:20190929185249p:plain
Gitの文脈で捉えるとmergeなの?pullなの?ってなりそうなボタン

GitLabだとマージリクエスト。これはForkが重視されていないからだと思う。 fetchが要らないなら機能的にはこれが正しいと思います。 機能を重視してのネーミングだとしたら、fetchが必要なものもマージリクエストで扱うので、これはこれでどうなんだろうとなります。 操作として区別する必要のない 歴史的経緯は知りませんが(調べたらわかる話ですが)、Forkを後からできるようにしたのか、元々Forkを重視していなかった、とかでしょうかね。

Backlogだとプルリクエスト。 BacklogはクローズなリポジトリでそもそもForkは扱わないけれど、これは機能よりもよく知られてる言葉を採用したんだと思います。 マージリクエストよりもプルリクエストの方が知名度はありますしね。

他のGitサーバー(って呼び方でいいのかな)も、作成された時期や思想によってどちらかの名前がついていると思います。他の名前もあるのかもしれませんが、知りません。patchを押し出した名前があっても不思議ではないんだけど。

同等の機能に異なる名前がついているのは面白いのですが、混乱している方もいらっしゃるわけで、自身の知っている方の言葉で押し通している方(GitLabを使ってるのにプルリクと言い続けるとか)もあり、なんと言うか。そこまで悪影響を与えるものではないのですが、名前を重視する派を自称する身としてはちょっと悩ましいところですね。

どうでもいいんですが、マージリクエストがマジリクと略されてるのはみたことはありません。 マジなリクエストとか面白そうなんだけど、意味はわからないので使われなくていいと思います。 なおMRと略されることもありますが、この略称はの脳内第一候補はMedical Representativeになるので、ちょっと戸惑ってしまう私です。

pullだのmergeだのってそもそもなんだって方へ

レビューさせてもらった本です。