会社で受託開発していて、gitを使った開発フローを考えることになった。
ニアショアに開発をお願いしていて、ニアショアからの受け入れタイミングが何回かあるから、それにあわせてブランチをわけている。
どういうフローで進めているかと、一番最後にやってみて思ったことを書いた。
どういうフローでやっているか
リポジトリの構成
下記モジュールを用意した。
- parent
- core
- entity
- common
- web
- batch
- tools
ニアショアにて開発するモジュールは『common』、『web』、『batch』で、
アーキにて開発するモジュールは『parent』、『core』、『entity』。
ブランチ
ブランチはこんな感じで分けている。
ちなみに、ソース管理はgitBucketを使った。
- masterブランチ … リリース可能な状態の資源のみを管理する。結合テスト実施時は、本ブランチから資源をリリースする。
- mainブランチ … masterブランチに対してマージしても問題がないことを検証する。受け入れテスト時に打鍵テストを実施する。
- developブランチ … 開発中に使用する。原則、レビューが済んでいるものを管理する。
- featureブランチ … 1機能単位で切り出し。レビュー前の資源を管理する。
developブランチは納品単位ごとに↓こんな感じで分けてる。
- develop-groupA … 1回目納品分の機能を管理
- develop-groupB … 2回目納品分の機能を管理
- develop-groupC … 3回目納品分の機能を管理
- develop-arch … アーキチーム提供の機能を管理
featureブランチは各業務機能作成者に作ってもらう。
ブランチの流れ
ブランチは↓こんな感じでやってってもらう。
受け入れはdevelopブランチからmainブランチへPullRequest投げる形でやってもらっていて、受け入れテストをPullRequestきているdevelopブランチで実施していく。
それぞれの役割の人が実際にやること
ニアショア管理者
新しいdevelopブランチが必要となるタイミングで、ブランチ追加依頼を出す。
(アーキチームにてJenkinsへのジョブ追加およびcore等のモジュールのバージョンアップを行う。)
成果物を受け入れ後、ブランチ作成から受け入れまでにあった資源の変更を、現在作業中のdevelopブランチへマージする。
developブランチの資源の品質を確保する。(Jenkinsのジョブが落ちていないこと。コーディング規約違反がないこと。など。)
納品時には、mainブランチに対してpull Requestを出す。
ニアショア開発者
機能単位でfeatureブランチを作成し、資源をfeatureブランチへpushする。
共通コンポーネントは各機能とは異なるfeatureブランチを作成する。
機能作成前には共通コンポーネントのレビューが完了し、developブランチに適用している状態にしておく。
機能作成完了後、developブランチへpull Requestを出す。
ニアショアレビュアー
ニアショア開発者からのpull Requestによるレビュー依頼を受け、レビューする。
レビュー指摘はpull Requestのコメント機能を使用する。
成果物に問題がないことを確認後、pull Requestを承認し、developブランチへ変更を適用する。
対象機能がサンプリングレビュー対象となっている場合は、pull Requestを承認せず、サンプリングレビュー依頼を出す。
受け入れ側ソースレビュー
ニアショアレビュアーからの依頼を受け、ソースコードレビューを行う。
レビュー指摘はpull Requestのコメント機能を使用する。
成果物に問題がないことを確認後、pull Requestを承認し、developブランチへ変更を適用する。
受け入れ担当者
- mainへのpull Requestを受け、資源の内容を確認する。
- 指摘がある場合は、pull Requestのコメント機能を使用して指摘をだす。
- 成果物に問題がないことを確認後、pull Requestを承認し、mainブランチへ変更を適用する。
- mainブランチにてマージによる問題が発生しないことを確認する。
- mainブランチにて受け入れテストを実施する。
- 不具合が発生したら、 不具合・仕様変更が発生したときは別でチケットを起票する。
- masterへ変更をマージする。マージ後、masterブランチのタグを切る。
アーキテクト
グループ切り替えのタイミングで、parentやcoreのバージョンを上げる。
受け入れ完了後、不要となったJenkinsタスクは削除する。
各モジュールのバージョンについて
1:develop-groupA作成から受け入れまで
- parent・core・entity:0.1.0を使用する。緊急リリースがあれば、0.1.1、0.1.2とバージョンアップを行う。
- common:『0.1.0-SNAPSHOT』を指定する。
- web・batch:『0.1.0-SNAPSHOT』を指定する。
develop-groupA受け入れ完了時
- parent・core・entity:受け入れ時のバージョンをそのまま使用する。
- common:『0.1.0』を指定する。
- web・batch:『0.1.0』を指定する。
3:develop-groupB作成から受け入れまで
- parent・core・entity:0.2.0を使用する。緊急リリースがあれば、0.2.1、0.2.2とバージョンアップを行う。
- common:『0.2.0-SNAPSHOT』を指定する。
- web・batch:『0.2.0-SNAPSHOT』を指定する。
4:develop-groupB受け入れ完了時
- parent・core・entity:受け入れ時のバージョンをそのまま使用する。
- common:『0.2.0』を指定する。
- web・batch:『0.2.0』を指定する。
5:develop-groupC作成から受け入れまで
- parent・core・entity:0.3.0を使用する。緊急リリースがあれば、0.3.1、0.3.2とバージョンアップを行う。
- common:『0.3.0-SNAPSHOT』を指定する。
- web・batch:『0.3.0-SNAPSHOT』を指定する。
6:develop-groupC受け入れ完了時
- parent・core・entity:受け入れ時のバージョンをそのまま使用する。
- common:『0.3.0』を指定する。
- web・batch:『0.3.0』を指定する。
実際にやってみて
ダメだったこと
gitのバージョン管理やmavenを使ったバージョニングで、(ニアショアだけでなくチーム全体で)メンバー間での知識の差もあり、こちらの意図がうまくつたわらなかったところがたくさんあった。その結果、こういう場合はどうするのかという質問が多くて、私も相手も不必要なところに時間をかけてしまうことになった。
特に、今回は開発はニアショアで、顔も合わせずに(運用フローをこうしますよ、ってドキュメントだけ用意していて、)開発をすすめる形になってしまい、ニアショアに対しても、受け入れチームに対しても、いっかい、ちゃんと説明する会を設けて、ガッツリ質問を受け付ければよかったなーと思う。
(そういった余裕が開発準備期間になかったのもあるけど。。。)
あと、ちゃんとフローをまわすときに、開発者側の立場からみてどういうふうにやるのがやりやすいか、っていうのをちゃんと聞けばよかった。
(gitとmavenを導入したチームの人や、相談役的なアーキ、チームリーダー、内製チームのリーダーには運用フローをレビューしてもらったけど。)
意見を伺わずにきめて、じゃあこれでやってください。となると、やっぱりわからないときに不満の向き先がこちらにくるので、事前に、「わからん!」→「じゃあどうすればわかりやすいですかね?」ってやりとりをすべきだった。きちんと意見を取り入れたうえで、『勝手に決められたわかりにくいフロー』から『ちゃんと一緒に考えたフロー』にするだけで、意識がかなり変わったと思う。
このへんは私のヒューマニティー高めていく必要ある。
よかったこと
知識を実際の開発に適用できたのはかなり勉強になった。
実際に、運用フロー考えるときも、うちのプロジェクトは受け入れがあるから、受け入れテストはこうやってやって。。。って感じで、受託+ニアショアっていう環境化でのフローを考えることができたのは、かなり良かった。
(だからといって、プロジェクト特性固有の、特段特殊なことをやったつもりもないけど。。。)
次回への知見たまったので、次回は特に↓をちゃんとやりたい。
- 開発が始まるまでに、基本的なgitの使い方とmavenの使い方をメンバーに知ってもらう。
- 運用フローは最初にしっかり説明をして、こういうパターンではこういった対処をするというのを知ってもらう。
- 運用フローを説明したときに、ちゃんと開発者側で何に困りそうか、どうすればもっとよくなるのかを聞く。
2015/07/27 追記
いくつか反応いただいたので、すこし追記
gitを導入しようと思った理由
ひとつ前のプロジェクトでsvnで開発してみて、コミットが気軽に出来なかったり、レビュー範囲がよくわかんなかったりしたのが経験として、あったから、git使ってみた( ´'ω'` )
あと、ニアショア他拠点で受け入れとかあったので、ブロックしてどーこーは厳しい+マージとかも厳しみだなー、というのがあった。
ただ、前提としてgit結構使えるメンバーが多いと思ってたというのがある。
(前のプロジェクトではgitやってたというひとがわりといた。)
developブランチ多くない?
これは、確かにその通りで、メンバーを混乱させる原因のひとつになった。
ただ、ニアショアからの受け入れ時に、検品+テストをしなければいけなかったので、ブランチをわけないと受け入れテスト対象がわからなくなる+受け入れテスト実行環境がむちゃくちゃになる恐れがあったので、そうしていた感じです。
さらにいい案があれば、マジで教えていただきたい><
おまけ
各メンバーにちゃんとgitとmavenを使う意図が伝わっていたかというと、伝わってませんでした。
mavenではなくproject.xmlと.classpathで依存関係とプロジェクト構成を管理した方がいいというひとが平気でいる。
公にではなく個人的に意図を説明したひとも何人かいるけど、やっぱりいままでのやり方を変えることに戸惑い(?)がある感じだった。
もっと事前にgitとmavenの良さみたいなものを伝えられていればよかったんだけど、というのが反省。
(伝えてはみたけど、やっぱり受け入れてもらえなかったというのはないと信じたいし、次はそこを頑張っていきたい。)
どういった質問が多かったか
個人的には、"こういう場合はどうするのかという質問が多くて、"←この部分がどんな感じだったのかと、 @syobochim さんがそれに対してどうやれば良かったと思ったのかとかが読みたかったなーと思いました。きっとこの"こういう場合"はみんな共通の悩みなんじゃないかと思うのでw
— Yusuke Ikeda (@yukung) 2015, 7月 27
たとえば、出てきた質問はこんなものがあります。。。
Q. 機能ごとにブランチを切る想定だが、業務ソースじゃなくてユーティリティの場合はどうすればいいか。ユーティリティに関しては他の業務ソースでも使うので、機能単位でブランチを切ると他で使えない。
A. ユーティリティは事前にブランチを切って、業務ソースを書き始める前にレビュー完了させてdevelopへマージしておいてください。
Q. commonに記載しているentityのバージョンを各開発者があげるのはわかりにくいのではないか。そもそも、マージするタイミングでうまくいかなかった場合はどうするのか。
A. こちらで依存関係のバージョンを上げてしまうと、リポジトリのブランチが急にコンパイルエラーになる可能性があります。きちんと、どのバージョンのモジュールを自分がいま使っているのかということを意識して開発していただき、マージするときは最新バージョンのモジュールを手元で適用し、動作確認をしてから自分の意思でPushしてください。
Q. developAブランチからdevelopBブランチへの資源のマージは大変じゃないか。
A. 基本的に業務機能単位で納品してもらうので、競合は少ない想定です。ブランチを切らずに作業すると、納品対象がどれなのかわからなくなってしまうので、切り分けする方が大変だと思います。
などです。。。
ただ、これって、わざわざ最初にwikiに書いておく必要あったのかは、謎、というか必要ない気がしてます。。。
聞かれていることは、別に特殊なパターンではないと思うし、どこまで書いてあげれば満足してもらえたのかはわかりません。。。
こまかくフローを決めてますが、やっていることはとてもシンプルで、
- ソースの変更はfeatureブランチで行い、レビュー完了後にマージしてください。
- coreやentityに変更を加えたときはmavenバージョンを上げて提供してください。
- 自分が管理しているモジュールは自分で依存モジュールの管理をしてください。(entityモジュールに変更があったときはcommonモジュールのバージョンアップを各開発者のタイミングで適用。)
- ブランチは絵の通りに(futureはdevelopから。)きってください。
をちゃんと理解していればうまくいったんじゃないかなあと思ってます。
ただ、やっぱり最初にきちんと説明して、ちゃんと各開発者に理解してもらう必要はあったな、という感じです。。。