読者です 読者をやめる 読者になる 読者になる

gitの良さは未だに分からないがPullRequestの良さはちょっとだけ分かるぞい

スマートニュース見てたらこんな記事が上がってました。

crapp.hatenablog.com

まあ、gitの良いところはそれなりにありますがローカルコミットを上手に使えるようになるまでの壁はとても高いですよね。

正直言えば私もrebaseとかなるべく打ちたくないし、使いこなせてるとは言い難い。

とはいえPR(本文中はマージリクエスト)がレビューを強制するので良くないとか、trunkに直接コミットすれば良くないとかはどうなん? と思ったり。

そもそも個人的にはSVNとgitで運用方式がさほど変わるとは思えないのですよ。実際変えなかったし。

というわけで、私が使ってるコード管理方式について語りたいと思います。タイトルはちょっと釣り... というかぞいぞい言いたかっただけです!

そもそもSVNでどう運用していたか?

たぶん、多くのサービスがそうであるようにSVNからGitに移行しました。もっと言うとさらに昔はCSVでした。

それも、色々な理由でSVNから短期間でgitの運用らしくないところもありますが、今は当時無理やりgit-flowとか入れなくて良かったなぁとは思ってます。

じゃあ、そもそもSVNでどんな運用してたのよ? という話になりますがおおむね下記のような運用でした。

  1. trunkは常に本番環境と一致。リリース時にはタグを打つ
  2. 開発時にはプロジェクト毎にtrunkから開発ブランチを作る。これが同時並行で大量にできる
  3. 検証環境向けのブランチに開発ブランチをマージしてテストする。検証期間/環境の都合でリリース日の異なる複数のプロジェクトがマージされる事がある
  4. 3の前後でtrunkと開発ブランチとの差分をとってReviewBoardとかでレビューする
  5. 3,4の完了したら開発ブランチをtrunkにマージ。タグ打ってリリース

f:id:pascal256:20161004032717p:plain

実のところ結果としてGitHub Flowに結構近い運用だと思っています。違うところは3の検証ブランチでしょうけど、検証ブランチ自体はどこにもマージされないので大差は無いんじゃないかと。 まあ、この手のベストプラクティスは似通ってくるものなので不思議ではないですね。

なんで移行したのか?

移行した理由は2つあります。一つはSVNがあまりにとろく、特にマージやDiffが地獄のような重さでした。普通に数分から十数分オーダー。

これはおそらく大量のブランチを運用してたり、用意されていたインフラと管理していたリポジトリ規模がアンマッチだったことがあります。

当時の私はレビューアーとライブラリアンも担当してたので、gitに移行前からsvn-gitとかを使ってローカルリポジトリを運用してました。パフォーマンスマジ大事。

もう1点はPRですね。会社で共通基盤としてStashを導入することは知ってたので、上記のパフォーマンスの理由もあって協力に推進しました。

Gitでどのように運用しているのか?

では、本題のGitでの運用方式です。正直、パフォーマンスがダメダメなだけで運用プロセスには大きな不満があった分けではないので、ほぼそのまま移行しました。

  1. masterは常に本番環境と一致。リリース時にはタグを打つ
  2. 開発時にはプロジェクト毎にmasterから開発ブランチを作る。これが同時並行で大量にできる
  3. 検証環境向けのブランチに開発ブランチをマージしてテストする。検証期間/環境の都合でリリース日の異なる複数のプロジェクトがマージされる事がある
  4. 3の前後でmasterと開発ブランチとのPRでレビューする
  5. 3,4の完了したらPRをマージしてmasterにマージ。タグ打ってリリース

f:id:pascal256:20161004032835p:plain

外部システムのReviewBoardがPRになり、マージ依頼と統合されました。なにこれ便利すぎる! と狂喜乱舞したのは私です。

それ以外は、まったくと言って良いほど同一プロセスです。gitの操作が独特だったり複雑ってのもTortoiseSVNからTortoiseGitに変わっただけなので、あまり大きな変化はありません。

まあ「Pushを忘れるな!」と徹底するくらいですかね。rebaseでコミットログを綺麗にしようとすると、ドキドキする運用がいっぱい待ってますが「そんなことしなくて良いんです」。

確かに残念なログは入り込みますしが、良くわかってないメンバーが使ってリポジトリがぶっ壊されるよりはマシです。

別に、コミットログが多少汚れてても、リリースのタグだけ適切に管理できてればそんなに困りません。clone/checkout/pull/merge/commit/pushくらい使えれば十分ですね。

なので、これ以外の操作をするときは権限を与えた特定メンバーに依頼しろという運用にしています。ちょっと窮屈だけど、窮屈だと思える程度にスキルがある人には権限与えれば良いですしね。

で、基本的にこれで運用してましたが、いきなり5の手順でmasterに取り込んでリリースをしてましたが、切り戻しが大変というリスクがありました。

特に、一日に何度もリリースする時に朝のリリースがこけると午後のリリースの準備がパーになるのでツラい。

なので、現在はリリースブランチを作って下記のように運用しています。

  1. masterは常に本番環境と一致。リリース時にはタグを打つ
  2. 開発時にはプロジェクト毎にmasterから開発ブランチを作る。これが同時並行で大量にできる
  3. 検証環境向けのブランチに開発ブランチをマージしてテストする。検証期間/環境の都合でリリース日の異なる複数のプロジェクトがマージされる事がある
  4. 3の前後でmasterと開発ブランチとのPRでレビューする
  5. 3,4の完了したらmasterからリリースブランチを作成して開発ブランチを取り込む。3のPRは破棄。
  6. リリースブランチをリリース。無事リリースされたらmasterにマージしてタグを打つ

f:id:pascal256:20161004032842p:plain

この手順にすることで、リリース失敗時の切り戻しが簡単になる上に、リリース前にリリースブランチをリグレッションテストできるので品質面でも貢献できました。

ちなみにこの改良版の手順も含めてSVNでできないのはPRくらいでしょう。これもReviewBoardとかの外部ツールで代替はできますが。

PRによるレビューはなぜ重要なのか?

元記事ではさんざん言われてるPRによるコードレビューだけど、これは超重要だと思っています。「あなたがgitに移行するべきたった一つの理由」とか言うそれっぽい記事のタイトルにできそなほどに。

重要な理由は2点あります。

1. 保守性の担保

元記事では「採用ミスの尻ぬぐいだ!」と言わんばかりのコードレビューですが、確かに読んでバグ見つけるよりは動かして見つけた方がずっと早いし合理的です。

が、コードレビューはバグ発見より可読性や設計レベルの保守性を主にチェックする行為だと考えています。コードは読み物なので第三者が読んで読みづらいのはダメです。

これは私やおそらく元記事の方を含むほとんどのエンジニアに必要な行為で、当然ですが自分より優秀な人が書いたコードのレビュー指摘なんていくらでもしたことがあります。

静的解析で基本的な部分はかなり潰れるんですが、設計レベルに由来するところは人が見ないと分からないですがねー。

一応、高いスキルを持ったエンジニアがお互いのコンテキストを良く理解しあった上で開発すればレビューとかいらない気がしますが、 そんな事例1ケースしか私は聞いたことが無いのと、それこそハイスキルな行為ですね。

2. 適切なマージがされるかの確認

これはPR最大の利点ですね。なんとgitはPR出た差分の通りにマージされるんです! ライブラリアン的な作業をしないと気づきづらいかもしれませんが、マージってのは「コンフリクトもせずに開発者の意図とは違うマージになる」可能性があり得るんです 。 gitはsvnよりずいぶんマシとはいえ、しょせんテキストベースのマージですからね。同じコードの一番上と一番したに同じメソッドを追加しても追加したら両方正しく取り込まれますけど、コンパイルエラーになりますよね?

これを防ぐにはSemanticMergeみたいなもう少しインテリジェンスなツールを使う必要があります。

通常は同じ行を修正してれば正しくコンフリクトしますが、コンフリクトの解決を適当にされると稀に「マージの時系列」や「同じ行としての判定」が狂う可能性があります。

この場合、何が怖いってSVNとかの場合は「Diffツールで見た結果と実際のマージ結果が異なる可能性がある」ってことです。せっかくレビューしたのにマージ結果が異なるとかツラい。

そのためリリース時のマージではマージした後に想定したマージ内容になってるかを差分確認という二度手間になっていました。

PRであれば、そもそもマージ申請なので見た目の差分通りに取り込まれるので、初回のレビューしっかりやるだけで良いので簡単ですし、安心感がありますね!

GitではなくSVNに回帰するべきなのか?

正直、管理をしない側がGitとSVNでたいそうな差があるとは思えません。

プロジェクト規模や体制にもよるでしょうが50%から80%くらいの人はrabaseがどうの以前にlogコマンドすら打たないんじゃないかな?

なので、管理者/ヘビーユーザに都合が良いGitから回帰するメリットは特に無いのだけど、全員がrebaseを使うような複雑な運用プロセスはやめたほうが良い気がしますね。

少数精鋭チームなら問題ないかもだけど、大半が初心者なら入れるメリットのがデメリットを上回らない気がします。

あと、これは私が「システムの整合性を保つ唯一の機械的な方法はリポジトリである」という単一リポジトリ教に入ってるせいもありますが、

SVNのようにディレクトリ単位で落とせてもいいんじゃないかなー、とは思ったり。あとshallow cloneにcommitできるとか。

正直、10GB級の巨大リポジトリを運用しようとするとcloneがHTTP Proxyに切断されるとか、サーバの方でハングするとかツラい事象が...

その辺を考慮したツールが欲しいなぁ。

余談

>コードレビュー導入は終局的には「コードはできるだけ書かない」という境地に至る。

本題とは本当に関係ないのだけど、元記事の人と意見が真逆で面白かったのでピックアップ。

「コードはできるだけ書かない」はプログラマーが目指すべき一つの境地だと思ってます。ここだけの秘密ですがコードを書くとバグが発生する可能性が上がるんですよ?

まとめ

元記事で言う「中規模以上のプロジェクトのリリースを本格的に管理する側」を経験した人間なので、ちょっとカウンター記事を書いてみました。

正直、10個も20個もあるそんなに短くないプロジェクトを並行運用するのをみんなどうやってるんだろう? という疑問をずっと持ってたので、 とりあえず自分の現状を公開してあわよくばコメントをもらおうという算段もあったります。

というか、そういうツラい運用したくないからリリーススケジュールをシリアライズして並行稼働開発をしないのが正しい組織運用かもしれないデス。

それでは、Happy Hacking!