約2ヶ月半のグループ開発をして学んだこと
はじめに
この記事は, 講義として約2ヶ月半のグループ開発を経て, その過程で学んだことを記録する目的で書きました。グループ開発の内容よりも良かった部分および悪かった部分とその改善策を書いた方が自分のためにも見る方のためにもなると考え, 開発の中身はあまり深く書きませんでした*1。ご承知おきください。
もくじ
開発していた環境
開発日数は全体で2ヶ月半で, 環境構築に2週間ほど, 残りの1ヶ月程度でコーディング及びテストを行いました。メンバーは6人で以下の通りでした。
人 | 立ち位置 | 補足 |
---|---|---|
もっちー | リーダー兼デザイナー | 事務作業およびデザイン系のプロ。「コードが書けないので」と言いつつ実績コード数はある。 |
松君 | フロント側の開発リーダー | 休息を犠牲にして指数関数的に強くなったプロ。彼のおかげでVueXを導入できた。 |
K君 | フロントエンドエンジニア | 初心者なりにも理解しようと努力していたひと。分からない部分はしっかり質問してた。 |
O君 | バック側の開発リーダー | インフラ面やコードレビューの絶対的プロ。何故かアイコンがいちごオレ。 |
鴨君 | バックエンドエンジニア | Javaのプロ(らしい)。Golang初めてとか言いつつしっかり実装してた。 |
私 | バックエンドエンジニア | Vue.jsとGolangを少し書ける。最終的にフルスタックになってた気がする。 |
開発したもの
概要
開発したアプリケーションは, モノを管理するアプリケーションで「mono-management」と言います。提供する機能は, モノの登録と編集, 親子関係を持つタグによるモノのカテゴリ分けなどです。
アプリケーションの構成は以下の通りで, フロントエンドをVue.js, バックエンドをGolangおよびMySQLサーバで実装しており, アクセスはNginxを介して行う設計としました。なお, これらのサーバは全てDockerコンテナ上で動作させました。
サーバの環境構築
サーバの環境構築には, docker-composeを選定しました。選定した理由は, 複数のサーバを立てて相互で通信するため, 1発でまとめて環境構築できるのが魅力的だったためです。とはいえ, バックエンドで使用したDockerのMySQL8.0公式スクリプトにバグが潜んでいたため, それの特定と対応に時間がかかりました*2。これにより, 環境構築のためのdocker-compose.ymlやsqlfiles, nginx.conf等の作成が約2週間程かかってしまいました。しかし, ここでしっかりと環境構築したおかげで, 開発時の結合テストが本当に楽になったので悪くなかったと考えています。
フロントエンド
フロントエンドのページ作成には, JavaScriptのVue.jsフレームワークを選定しました。選定理由は2つありました。1つ目の理由は, 納期があるため学習コストの低いフレームワークを選定する必要があったためです。フロントエンドのフレームワークを触れたことがないメンバーが複数いる状態だったため, 私たちに選択の余地は無かったように思います。2つ目の理由は, サーバとの通信を最低限にするSPAを導入したかったためです。今回開発したWebアプリケーションはモノの登録や編集などでページ遷移をすることが多くなることが想定されました。そのため, 必要な部分のみをバックエンドのAPIサーバとやりとりすることで通信時間の短縮が期待できました。結果として, Vue.jsを利用したことで開発初期はあまり進んでいませんでしたが, 途中からコンポーネントの再利用やVueXの導入によって開発が加速し, 結果として何とか納品することができたので正しい選択だったと考えています。
バックエンド
DBサーバ
バックエンドのDBサーバには, MySQLを選定しました。選定理由は, フリーで使用できるDBの中で最もポピュラーなDBだったためです。今回はdocker-composeでサーバを管理していたため, 初期起動時にテーブルを自動生成するためのsqlファイルを書きました。sqlfilesを置いておくだけで, コンテナ内にテーブルを生成してくれるのでかなり楽でした。
JSON APIサーバ
バックエンドのJSON APIサーバには, Golangのginフレームワークを選定しました。選定理由は, Golangのフレームワークの中で最もGitHubのドキュメント等がしっかりしていると感じたためです。 以前の記事であるmixiさんのGit Challengeでしゅもんさんという方に相談した際には「APIサーバ程度なら軽量でswaggerでAPIが吐くJSONも簡単に確認できる出来るgoaがオススメ」と言われました。しかし, メンバーのO君と話し合った結果, swaggerを利用した開発は魅力的ですが, 今回の開発規模なら手書きで対応できるため学習コストを低くするという意味でもginの方が良いという結論に至りました。結果として, ドキュメントを見るかググることで対応できたので, ginで問題ありませんでした。しかし, 他の言語・フレームワークと比較した時にGolangのginフレームワークである必要があったかと聞かれると, はっきりと答えることができません。強いて言えば, 「私がGolangの言語仕様が好きなので」ということくらいでしょうか?
また, Golang以外の言語でもあるとは思いますが, documentを自動生成してくれる機能も魅力的でした。実際にGitHub Pagesで公開しているので, もし良ければ参照してみてください。
ORMライブラリ
APIサーバがDBサーバとやりとりするために, GolangのORMライブラリとしてgormを選定しました。このライブラリの選定理由は, 使用するginフレームワークとの相性が良さそうで, 何よりGolangのORMライブラリの中で最も多機能だったためです。基本的な文法に加え, トランザクション管理などもしっかりと対応していたため, 開発時に欲しい機能は大抵あり非常に助かりました*3。
開発に伴い作成した書類
開発を始める前に, 要求仕様書・外部設計書・内部設計書・総合テスト仕様書という書類を作成しました。各仕様書の内容については, ググれば幾らでも出てくるので割愛します。
良かった部分
設計書を書いてからコーディングを始めたこと
(講義の構成上ですが)設計書を作成してからコーディングを行なったため, 全体像を見据えながら次に何を書くべきなのかを明確にしてコーディングを行うことができました。更に, フロントとバックを結合する際に想定されるリクエストとレスポンスが定義されていたので, 割と問題なく結合できたのも良かったです。*4
Pull Requestに対するレビューの義務化
私たちはGithub-Flowに沿った開発を行っていました。そこで, developが汚染されるようなコードをマージされるのを危惧して, developへのマージに関して1人以上のレビュアーによるApproveを義務化しました。*5これにより, 他人に読まれることを意識して, 関係ない差分を入れないようになりました。また, 私だけかもしれませんが, 自分のコードを読んでもらえると嬉しいので, モチベにつながったという副作用もありました。
docker-composeによる一括管理
これはサーバの環境構築でも書きましたが, フロントエンドとバックエンドの結合テストが, $ docker-compose up
と1度叩くだけでできてしまうので非常に楽でした。そして, コンテナはVMと比較して軽いので複数コンテナを立ててもメモリが圧迫されなかったのもポイントです。また, Dockerは環境依存しないので, 本番環境のUbuntuでもO君のArchLinuxでも私や鴨君のMacOSXでもテストをすることができ, Pull Requestに対するレビューに対応できたのも良かった点です*6。
slackによる情報共有
現在はslackを使用している人が多いと思うので主要機能は割愛します。私たちのslackで特徴的だったのは, #懺悔室チャンネルの存在です。#懺悔室チャンネルはミスした時に懺悔(報告)をするチャンネルです。ここに吐き出すことで, ミスをしても後腐れなく開発ができたので良かったと考えています。*7
悪かった部分とその改善策
関係ない差分を含んだPull Requestを飛ばしてしまったこと
悪かった点
例えば, 以下のようなPull Requestが挙げられます。
色々とツッコミどころがあると思いますが, 何より「Fix get tag list」というPull Requestにも関わらず, modifiedに関係ないファイルが多すぎることが一番の問題だと思います*8。実はこのPull Requestでは関係ない差分で必要な行を削除してしまっていたのです。この時はレビュアーがミスに気づき指摘してくれたので助かりましたが, このように関係ない差分を含んだPull Requestを飛ばしてしまったのは悪かった点だと考えています。
改善策
シンプルで効果的な改善策は, Pull Request名を厳格に書くということです。厳格に書くことで, 関係ない差分を含んでいる場合は気づけますし, Pull Request名に「&」が入る場合はPull Requestを分割して行えば良いので, 差分の簡略化かつ明確化に繋がると考えています。しかし, 今回の開発でもそうでしたが, 厳格な命名をつけるのは面倒なものです。そのため, 普段から厳格な命名をつける心がけをして, 厳格な命名を習慣化することが重要だと考えます。
環境構築が遅かったこと
悪かった点
サーバの環境構築でも書きましたが, docker-compose関連の環境構築で約2週間を費やしてしまいました。先日以下のようなツイートを見かけて, 他講義により開発時間を確保できなかったり公式MySQLスクリプトの不備などの問題があったりしたものの, やはり2週間は長すぎたなと思いました。
えっ!?
— と (@t0riumi) 2019年7月29日
開発環境の構築に二日以上かかるエンジニアがいるんですか!?
しっかりとした環境構築のおかげで, 後々の開発が加速したのでその点は良かったのかもしれませんが, この期間が短ければ開発日数を増やせたのかなとも思います。
改善策
これに対する改善策をずっと考えていたのですが, 思いつきませんでした。強いていうなら経験を積んで, 起きそうな問題を把握しておくことくらいでしょうか?環境構築が大変なことはよく理解しているつもりなので, これに対して効果的な改善策はないと考えています(あれば教えて欲しいです)。
レビューの仕方が曖昧だったこと
悪かった点
先述した通り, 今回はPull Requestをマージする際にレビューを義務化しました。しかし, レビューをする機会がほとんど無かったため, レビューの仕方が人によって異なっていたのも問題だった気がします。私は, コードの変更差分の確認と, 動かした際にPull Requestの内容で正しく修正されていることが確認できたらApproveしていましたが, このレビュー方法も正しかったのかどうかわかりません......
改善策
レビューに関して詳しいことはわからないので, 本なり記事なりを見て学ぶのが一番だと思います。ただし, Pull Requestする側は, レビュアーがレビューしやすいように変更差分を簡潔にしたり, commitを多く挟んだり, Pull Requestの目的などを明確にしておくべきだと感じました。結局のところ, Pull Requestが曖昧だとレビュアーも困りますしね。
今回の開発で学んだこと
今回の開発で学んだことを技術面/非技術面に分けて要点のみを絞って書いておきます。
技術的な話
docker-composeによる環境構築は時間をかけてもやっておくべき
今まで散々書いてきましたが, 結合テストが楽というメリットが最も強いです。今回のようにフロントエンドとバックエンドが異なる場合は, 結合テストを行う際にそれぞれのサーバの環境を合わせて別々に立てるのは大変です。また, 仮に立ててもCORS関連で通信ができないトラブルが起きようものなら辛い気持ちになることでしょう。そのため, $ docker-compose up
で本番環境が立つdocker-composeは有用でした。
公式のスクリプトにも誤りはあるのでコードを読んでみるのもアリ
今回悩まされた公式MySQL8.0のスクリプトの件です。今までは, 5,6時間バグと格闘して対処法が見つからない場合, 時間がかかりそうなので別の手法に変えるようにしていました。しかし, 今回のようにGitHubでコードが見れる場合は実際のコードを確認して「なぜそのエラーが出ているのか」を確認することで, 自らパッチスクリプトを書いて対処可能なことを学びました。時間はかかるかもしれませんが, どうしてもその技術を使用する必要のある時に有用なので, 頭に留めておくつもりです。
不明瞭で必要のない差分を含むPull Requestは悲劇を生むことがある
今回の記事では触れませんでしたが, 実は問題のあるPull Requestがマージされてdevelopブランチが汚染されたことがありました。$ docker-compose up
が正しく動作しなかったので気づけましたが, これが気づきにくい部分だったらと思うと恐ろしいです。この件に関しては, レビューの時点で気づけなかったのも問題ですが, 何よりそのようなPull Requestを飛ばさないのが一番だと思います。
非技術的な話
時間は有限
今回開発を行った際に強く感じたのは, 時間が足りないということでした。コーディングを始めてから締め切りまでは1ヶ月強ほどあったはずですが, 他講義との兼ね合いで実際にコーディングできたのは50時間も無かったように思います。これは開発以外にも言えることかもしれませんが, 締め切りが先でも使える時間は有限なので, 必要最低限のコードを実装できるような規模にすることが重要だと感じました。
「グループワークに不満があるなら全部お前がやればいい」は大嘘
これはとある講義のグループワークをしていた時に, とある教師から言われたのですが, 長期間の作業に関してこの考えは通用しないなと感じました。結局, ひと1人ができることなど高が知れていますし, 何よりこのやり方は自分の首を締めるだけでなくメンバからの不信感を増大させるので, 長期間の作業には向いていないと感じました。大抵の場合, 「これやって」とお願いすれば何らかの反応があるので, まずそれをするのが良いと思います。
おわりに
ここまでお読みいただきありがとうございました。読み返してみて「まぁそれはそうだよな」と思えるレベルのことが多い気がしましたが, 少しでも参考になれば幸いです。良かった部分は「当然だろ?」と思えるように, 悪かった部分は繰り返さないようにしようと思います。
また, 今回の開発は長かったようで短く, 前期日程の空き時間をほとんど全て注ぎ, 他のことが出来ないほどでした*9。正直こんな厳しい開発はしたくないなと思うので, 次に開発をするときはマトモなボリュームの設計にして開発しようと思います。
*1:現時点でその部分を知って得する人が思いあたらないので書くつもりはないです
*2:既にIssueが立っていました。O君がこのバグに対応するパッチスクリプトを書いてくれました。
*3:開発時に「有能じゃん」と頻繁に言っていたのをよく覚えています。
*4:一応JSONの変数で大文字小文字関係のトラブルはあったものの, それ以外に大きな問題は起きませんでした。
*5:企業でのグループ開発をしたことがないのでわかりませんが, やはりこれが一般的なのでしょうか?
*6:Windows10 Home EditionだとHyper-Vが使用できなかったので, フロントの2人は使えませんでした。早くWSL2出てくれ......
*7:これは余談ですが懺悔したメンバーがすぐに退出するので, 常駐していた1人のメンバーがシスターと呼ばれるようになっていました。
*8:「CreateMonoとEditMonoは副作用なのであまり見なくておkです。」も問題ですが。