エンジニアの渋谷です。
マネーフォワードは3月30日に【給与計算ソフト - MFクラウド給与】という新サービスをローンチさせていただきました。
マネーフォワード、クラウド型給与計算ソフト『MFクラウド給与』(β版)を無料提供開始~法改正や税制改正にも自動対応。企業の給与計算・労務をもっとスマートに~
クラウド上で完結する本格的な給与計算サービスとして、リアルタイム給与計算機能や料率自動反映などを備えております。
本サービスの企画自体は、昨年年末に3人でスタートし、年明けから様々な方にお手伝いいただきながら、約3ヶ月の開発期間でローンチしました。
今回は、新サービスをゼロから作り上げるにあたり、エンジニアとしてやって良かった、と思えた事を9つばかり紹介させていただきます。
1:リリース前確認シート
企画がスタートした時に、【ビジョン】【ミッション】といった事をチーム内で議論しましたが、それと同時に【リリース前確認シート】という物も作成しました。
これはリリース直前に見直すべきチェックシートのようなもので、一部抜粋すると以下のような物です。
(※公開にあたり、一部書き換えています)
リリース直前は多くのバグ修正やテストに終われ、慌ただしい事が多いです。
直前になって慌てぬよう、時間に余裕があり、かつ冷静でいられる企画スタート段階でチェックリストを作っておく事で、リリース前の時間を有効活用することができました。
2:用語集と和英辞書
用語集
用語集は、チーム内での共通認識を得るのに役立ちます。
特に給与サービスは専門用語が多く、同じ単語について話しているのに、お互いに別の話をしていた、なんて事になりかねません。
また、チームメンバーのあだ名や趣味の紹介の記事もあり、コミュニケーションの手助けにもなります。
和英辞書
和英辞書はエンジニアのコードの可読性や品質担保に役立ちました。
例えば、【手当】の事を、paymentと書くエンジニアと、allowanceと書くエンジニアがいると、コード内に一貫性がなくなってしまいます。
一貫性の無いコードは可読性が下がるだけでなく、バグの温床ともなります。
- workとjob
- genderとsex
- last_nameとfamily_name
どちらが英語として正しいかという意味合いよりも、プロジェクト内で記述が統一されることのメリットが大きいと感じました。
特に給与サービスは複雑な日本語が多く、【社会保険料調整額】や【現物通勤手当(非課税)】など、共通化された英語をチーム内で定義しないと、読んでも何を表すのか分からない状態となってしまいます。
今回はスタート段階から和英辞典ページを作成し、新たにテーブルを追加したり、ページを作るたびに、和英辞典を更新する運用を行いました。
3:新しくジョインされる方へ
企画スタート段階で、プロダクトマネージャー1名、エンジニア2名の体制でした。
そして、企画スタートのタイミングで、【新しく給与チームへ入られる方へ】というページを作成しました。
※目次だけ抜粋
これには二つの目的があり、
1つは、チーム内での暗黙知を減らし、個々の開発時のtipを、チームの資産として蓄積して行くため。 また、環境や構成のメモは、将来的な自動構築などの足がかりとする為です。 (企画スタート段階では構成の変更が頻発しそうで、自動化は見送りました)
2つ目は、新しい人の受け入れ準備はできてるから早く採用しよう、という採用チームや自分たちへの無言のプレッシャーw
そして、意図した通り(?)、年明けから1名のRailsエンジニアの方に加わっていただき、その方にはジョイン初日にこのページを読んでいただきました。
4:コード規約
マネーフォワード全体のコード規約(moneyforward/ruby-style-guide)もありますが、チーム内でも独自のコード規約を作成しました。
一気に作り上げたというよりは、チーム内で議論した内容を、つどつど文字に起こしていくという運用でした。
※目次だけ抜粋
コード規約は、コードの品質を一定以上に保つのに役立つのはもちろんですが、最も大きな恩恵は、review時における無駄な感情対立が起き難くなる点だと思います。
例えば、
- boolean columnは、 is_ とする
- 種類を表すcolumnは、_kind とする
- model内での、クラスメソッド,scope,validate,定数などの並び順
など、ルールが無い世界で指摘されると、個人の好みの問題と捉えられて、感情論になりやすく、かといって放置すると、プロジェクト内のコードに一貫性がなくなってしまうような事象であっても、【コード規約】という軸があれば、【コード規約に合わせましょう!】というだけでreviewをスムーズに行う事が出来ます。
もちろん、コード規約自体に納得感が必要なので、一人で作り上げたり、他チームから流用したりせずに、チーム内の議論をまとめるノート、のような意味合いで全員で作り上げるのが良いかと思います。
5:pre-commit
規約ができれば、そもそも規約違反はコミットできなくしたい、と思うものです。
今回は、pre-commit を利用しました。
- jish/pre-commit
- git用のpre-commit gemが便利すぎる - TakiTakeの日記
- rubocopやjshintなどをgit-hookにまとめて設定できるpre-commit gemが便利そう(メモ) - Qiita
pre-commitは、様々なコード規約をチェックし、git-hookにまとめて設定する事が出来ます。
マネーフォワードは、Railsにて開発を行っていますが、今回は、ruby/javascript/coffee script/yaml/json など、関連するコードをほとんどチェック対象としました。
これにより、規約違反や推奨されない記述は、commit前に弾かれるようになりました。 今回はチーム内の全員がこれを入れる事で、reviewは本当のロジックのreviewだけに集中する事ができました。
6:独自builder
開発初期は速度を優先するため、bootstrapベースのデザインで開発を行いました。 そして、デザインを整える際に、classとstyleを置き換えて行ったのですが、全てのページのclassを置き換える作業は、かなりの作業量となってしまいます。
そこで今回は、独自のbuilderを最初に定義しました。
class MfFormBuilder < ActionView::Helpers::FormBuilder def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block) additional_html_options = { class: " #{CSS_CLASSES[:radio_button]}" } html_options.merge!(additional_html_options) { |_k, option, additional_option| option + additional_option } super end def select(method, choices = nil, options = {}, html_options = {}, &block) additional_html_options = { class: " #{CSS_CLASSES[:form_element]}" } html_options.merge!(additional_html_options) { |_k, option, additional_option| option + additional_option } super end ... ... ... end
これにより、CSS_CLASSES
の定数を書き換えるだけで、form関連のデザインを一括で変更する事ができます。
また、viewの記述量が減るので、class: 'btn btn-xxsmall'
といった記述をview内に書きまくる、といった作業がなくなり、templateの見通しが良くなります。
builderを利用する場合は、本来
form_for xxxxxxxx , builder: MfFormBuilder
といった記述を都度行いますが、今回は、application_helper.rbにて、form_forも拡張し、何も記述せずとも、独自builderが利用されるようにしました。
こうしておくと、新しくプロジェクトに加わった方や、デザインを担当される方が、フォームにつけるべきCSSを探しまわるとか、そういう意識をする必要がなく、本来の開発に集中する事が出来ます。
7:resourceとresourcesしか使わないルーティング設定
今回のプロジェクトには、 config/routes.rb
にcollection/member
やget/post
と言った記述は一切出てきません。
全てのroutingを、resource
とresources
で定義しています。
これにより全てのactionは、index/show/new/create/edit/update/destroy
の7つのいずれかになるため、routingの見通しがよく、controllerが非常に簡易に保たれています。
また、複数のモデルを触りたいケースが出てきた場合はService層に隠蔽するなど、controllerにロジックを一切記述しないことを目標にしたので、controllerの行数が非常に少ないです。 (ほぼ全てのcontrollerが、60行以下)
resource
とresources
だけを利用すると、複数recordの同時update(部門や職種をまとめて、追加・削除・編集するような場面)が行い難いですが、今回は複数同時更新のcontrollerを、multiple_hoges_controller.rb
として定義してみました。
そして、
- accepts_nested_attributes_for
- nathanvda/cocoon
の二つを使う事により、薄いcontrollerで、かつ、RESTfullなURLを実現してみています。
例えば、user has_many books
という関係で、booksをまとめて更新するような処理を書く場合
resource :multiple_books, only: %i( edit update )
class MultipleBooksController < ApplicationsController def edit render partial: 'modals/multiple_books/form' end def update respond_to do |format| if current_user.update(books_params) format.html { redirect_to users_path, notice: "#{Book.model_name.human}を更新しました。" } else format.html { redirect_to users_path, alert: current_user.errors.full_messages } end end end private def books_params column_names = [ books_attributes: [ :id, :name, :_destroy ] ] params.fetch(:office, {}).permit(column_names) end end
- form_option = { url: multiple_books_path, as: :user } = form_for current_user, form_option do |f| table thead tr th 名前 th 削除 tbody#js-books-tbody = f.fields_for :books do |book_form| = render 'book_fields', f: book_form
tr td = f.text_field :name td # link_to_remote_destroy_association は今回独自に定義したhelper methodですが、_destroyのチェックボックスを表示していただければ動きます。 = link_to_remote_destroy_association f do = image_icon_delete_tag
has_many :books accepts_nested_attributes_for :books, allow_destroy: true
belongs_to :user
このような記述をする事で、controllerは簡易に保ちつつ、has_manyな関係のrecordをまとめて更新する処理を行う事ができました。
今回使用したcocoonは、has_manyな関係性のデータを扱うformを作成する場合に便利なgemで、下記のサイトが参考になります
8:もくもく会
プロジェクト開始時は、基盤という物が存在しません。 誰かが書いてきたコードを参考に開発する、という事も出来ず、同時並行で開発すると、設計も方針もばらばらのコードが生まれかねません。
今回はそれを防ぐ為に、もくもく会をたくさん開催しました。 例えば、ある日の3時〜5時など、数時間ぶっ通しで一つの会議室で、みんなでもくもく開発します。
そして、気になる設計があれば、ディスプレイに映してみんなで議論します。
例えば、
- concernsへロジックを切り出す基準
- concerns fileの命名規則
- app/services 層の設計方針
- rspecの粒度
- javascriptの全体設計
- gemの導入相談と共有
などなどです。 会議室なので他チームへの迷惑を気にせず話せますし、一人で設計にモヤモヤするのではなく、全員が納得する指針を最初に作ってしまいました。
チーム開発初期は、個人の力でガーーと作りきっちゃうのが最速、という考え方はもちろんありますが、今回はプロジェクト全体のコードを、誰が見ても読みやすくメンテしやすいコードにする事を目標に、このような方針としました。
ここで決まった内容は、【チームのコード規約】にも追記します。
9:チャット通知
今回は、複数の通知の仕組みを入れてみました。
- エラー通知
- pull request通知
- FeedBack通知
- rspec通知
- 網羅テスト通知
- KPI通知
それぞれ細かい説明は省略しますが、【エンジニアが画面を見て集中している状態】を保つため、極力情報を集約しています。
最後に
マネーフォワードでは、Railsエンジニアを募集しています。 採用情報|マネーフォワード
お互いに改善案を出し合いながら、サービスと共に一緒に成長出来る仲間をお待ちしています!