この記事は MoneyForward Advent Calendar 2018 の 11 日目の記事です。
昨日は iOS デベロッパーの tamadon さんの 育児とやっていきの両立について という記事でした。
育児とやっていきの両立が偉大すぎて、僕には一生到達できぬ高みなんじゃないかとビビっています。
自己紹介
改めて、2018 年 4 月入社の新卒でマネーフォワードクラウドの横断チームにて Rails のエンジニアをやっています、古濱 (@furuhama) といいます。
僕が最近メインでやっていた Rails のバージョンアップとその他の改善のお話に関して書いてみたいと思います。
この記事で扱うこと
この記事で書くこと
- バージョンアップ作業をやるときに考え・取り組み
- 継続的にサービスをメンテナンスしていくための取り組み
この記事で書かないこと
- バージョンアップ作業の具体的で詳細な手順
- バージョンアップ作業時にハマった問題の解決方法
背景
マネーフォワードではサービス開発においてスモールチーム&マイクロサービス的なアプローチを採用していて、一般に公開していないものも含めてたくさんの Rails アプリケーションが日々色々な場所で動いています。
そうしたサービスの中には安定的に稼働しているものも多く、特に社内向けのサービスなどは、盛んに開発されている外部向けサービスと比較するとメンテナンスにあまり工数をかけられていない実情がありました。
メンテナンスがおろそかになっているサービスがどういうことになるのか。僕の理解だと以下が挙げられると思います。
- 利用しているライブラリのバージョンが古くなり、セキュリティパッチなどが当たらなくなっていきヤバい
- 利用しているライブラリが新しく提供するようになった便利な/役立つ API が利用できず悔しい
- そのサービスに依存しているサービスがあると、新しいことをやる際のコストが上がりつらい
- サービスに関する知見がまとまっていないと、社内ドキュメントや過去のコミットに断片的に存在する知見を漁る楽しい時間がやってくる
- 手をかけてもらってないサービスは拗ねるので、コードを読んでも何をやっているのかさっぱり理解できないことがある
- そんなこんなで上記の理由から、サービスに対して要望をいただいてもすぐに対応できないことが出てくる
こうなってしまうと大変ですよね。
そこで立ち上がったのが僕の所属している横断チームです。クラウド側を中心に会社全体を見たときに、比較的メンテナンスが行われていないサービスに対して貢献することで会社全体として提供する価値の底上げができるといいよね、と画策しています。
(もちろんサービスのメンテナンスだけでなく、他にも複数サービスをまたいだ改善のお仕事も色々とやっております。)
お仕事をもらった
という壮大な前振りから入りましたが、要は古くなったアプリケーションで Rails を中心とする利用ライブラリのバージョンアップのお仕事を仰せつかりました。
さてみなさんは、エンジニアの同期が頑張ってサービスの新機能を作ったり、サービス全体のデプロイ基盤を構築したり、あるいはビジネス側の同期が数値目標を持って営業を行ったりしている中、彼らから「はまふぃー(注: 筆者のあだ名)は最近なにやってるの?」と聞かれ、 「Rails のバージョンアップをやろうとしているよ、公式でバージョンアップのためのガイドまで用意してくれているからそれを見ながら手順に沿って進めていくんだ!」と答える時の気持ちは想像したことがありますでしょうか?
もちろん重要な仕事であることは理解しつつも、そんな会話の中で新卒の僕がふと(こんなんでサンタさんは来てくれるんだろうか...?サンタさんはちゃんとお仕事をしている大人の元にしか来ないから、もしかして今年はプレゼントをもらえないかも...)などと想像してしまうのも無理からぬことでありましょう。
さらに、いろんなサービスでバージョンをあげる作業はどこか似通ってくるでしょうから 飽きてくる -> モチベ下がる -> パフォーマンス低下 -> サンタさん来ない
なんて最悪の流れも考えられなくはありません。
(このタスクをやりきって絶対サンタさんに来てもらうんだ...!!!)、そう決意し圧倒的な説得力でサンタさんを呼び寄せるべく Rails バージョンアップタスクを開始したのでした。
どうやってサンタさんを呼び寄せるか
そもそもサンタさんはどんな大人の元に来てくれるのでしょうか。
僕の想像では「与えられた業務の達成という短期的な目的にとらわれ過ぎず、長期的な価値の創出を考えて業務を進めていく大人」の元には来てくれそうな気がしています。いかにも正しそうですね。そうに違いない。
ただ単に公式ドキュメントを読んでふんふんと鼻歌を歌いつつバージョンを上げていても多分来てくれません。これは大変です。
僕がちゃんとした大人としてサンタさんに認めてもらうためには、各サービスが長期的に価値を生み出すような状態を目指さねばならぬのです。
とは言ってもサービスが長期的に価値を生み出せる状態とはなんでしょう?少し考えてみた上で、僕は以下の点が重要なんじゃないかと思いました。
- 現在提供している価値を、将来も少ないメンテナンスコストで安定的に提供できるサービスである
- 要求されている価値が変化した場合に変更を加えやすいサービスである
これだとちょっとふわっとしているので、もうちょっと具体的な作業を考えてみました。
サンタを呼び寄せるバージョンアップ作業
バージョンアップすることはもちろんですが、それと共にメンテナンスしやすい環境を作ることを意識して取り組むと良さそうです。
- 不要な機能や gem があれば消す
- Rails も含めて、残った必要な gem のバージョンを上げる
- Rails way に乗っていない書き方をしている部分があったらリファクタリングする
- テストが書かれていない/足らない場所を見つけたらテストを追加する
将来的なメンテナンスを考えると不要なものがたくさんあるという状況は望ましくないですね。
ゴミの多い部屋に住まなくてはならないことを考えてみてください。どの家具を使うにもゴミをどけなくてはならないなんて嫌ですよね。サンタさんも逃げてしまいます。
また、将来的にもメンテナを多く割けない状況を想定すると、 Rails のように巨大で実績があり信頼できるライブラリへの依存を大きくし、なるべく素直に Rails way に乗る形でアプリケーションを記述していくべきだ、という判断をチームで行いました。
そこで Rails の標準 API で用意されている方法を使って書き換えられる場所を見つけた場合には、リファクタリングを行っていました。
テストがほとんど書かれていなかったり、テストケースの考慮が甘い部分も見つかったので、そういった部分は都度テストを追加していました。
成仏パート
実際の作業について具体的に触れることはしないですが、サクサク進んだ感を出しているバージョンアップ作業も以下のようなつらみがありました。彼らもこのままでは浮かばれないので成仏のために書かせてください。
- production mode で起動時に読み込んでくれる eager_load_path の変更で、今まであった定数(クラス/モジュール)が読み込めなくなって落ちる
- 例外発生時に、エラー通知のために入れていた gem の処理の中で例外が発生してしまったせいで、エラー箇所がわからなくてハマる
- パラメータの扱いの変更で挙動が変わってうまく欲しいデータにアクセスできずハマる
- アセットが読み込めなくてページが落ちるようになる(本当は今までもブラウザのコンソールに warning が出ていたけど落ちるようになっていた)
- ローカルで検証していた際に CSP(Content-Security-Policy) に関するヘッダ情報がブラウザにキャッシュされていて、設定が反映されてないと思ってハマる
などなど、言える範囲でも大なり小なりたくさんあって、「は〜〜〜〜〜〜〜」と寿命を 30 分くらい縮めそうなため息を何度かつきました。
どれくらい減ったか
さて、成仏を終えて本題に戻ります。
不要なものを消すと言いましたが、実際にどれくらいのコードや gem を減らせたんでしょうか。
簡単に比較できる数値ではないですが、僕とチームのみんなのやった感を出すためにすごくざっくりと調べてみました。
サービス | 加えた行数(+) | 消した行数(-) | 消した gem 数 |
---|---|---|---|
A | 3269 | 14440 | 12 |
B | 5531 | 6613 | 16 |
C | 3734 | 2681 | 2 |
D | 1915 | 1608 | 12 |
うんうん、サービスごとに個性が分かれますね。
サービス A や B は社内ユーザーメインで色々な機能を持っていたので、実は使っていない機能がたくさんありました。
外部向けにも利用されていてもともと責務がはっきりしていたサービス C や D ではそんなに消せるコードはなくて、全体としてはむしろ増えているようですね。どちらも依存 gem は減らせたのですっきり最高です。
これでサンタさんが来てくれるんじゃないかって?いえいえ、まだ半分しかできていません。
サンタを呼び寄せる継続的な取り組み
メンテナンスしやすい環境を作るというところまではできました。
しかしサンタさんは一瞬だけ頑張った人のところには来てくれず、継続的に頑張った人のところに来ると相場が決まっていたはずです。
せっかく頑張ったのに結局サンタさんが来てくれなかったらすごく悲しいので、継続的にメンテナンスしていける環境を作っていきましょう。
ここで一つの疑問が僕の頭に浮かびます。これから先のメンテナンスを全て人間がやらないといけないんでしょうか。そんな根気のいる作業、僕はゆとり世代なのですぐに音を上げてしまいます。
ご安心ください、もちろんマネーフォワードでは継続的なメンテナンスの部分的な自動化にも取り組んでいます。
そこで今回の作業で対象サービスに導入した、 gem のアップデートと脆弱性の検出における取り組みを紹介したいと思います。
gem の自動アップデート
gem の自動アップデートでは dependabot というサービスを最近利用し始めました。 dependabot くんが定期的にアップデート可能な gem を見つけて PR を出してくれます。細かい設定もできてなんだか可愛いですね。たまにどかっと PR 送ってくるので「うるせー!!!」って思います。
脆弱性の検出
利用しているライブラリやアプリケーションコードに脆弱性が紛れ込んでないかのチェックには snyk と brakeman を利用しています。snyk は Gemfile(Gemfile.lock) をみて問題のあるライブラリがないか 24 時間 365 日チェックしてくれていますし、brakeman は PR 作成時に CircleCI によるテストと並行して実行されるのでうっかり脆弱コードを書いてしまってもすぐに気づけます。
snyk
snyk はリポジトリごとに脆弱性を管理することができます。 一口に脆弱性と言っても、サービスの性質によって対応すべきもの/しなくてよいものが存在するため、プロダクトセキュリティ担当のエンジニアと話し合ってトリアージした上で対応するようにしています。
brakeman
brakeman は rubocop のような lint ツールと一緒に、 Sider というサービスを利用して実行しています。 GitHub 上で PR を作成したタイミングでテストと同様に自動的に各種ツールが実行される仕組みになっています。
こうした取り組みによって僕たちエンジニアは四六時中メンテナンスのことを考えることなく、他の有益なことに取り組めるというわけです。ありがたいことですね。
まとめ
いかがでしたでしょうか、みなさん。いかがでしたでしょうか、サンタさん。
今回の Rails バージョンアップ作業をきっかけとしたメンテナンスしやすいサービス環境作りで、それなりに
「与えられた業務の達成という短期的な目的にとらわれ過ぎず、長期的な価値の創出を考えて業務を進めていく大人」
に近づけたんじゃないかと思っています。
努力の甲斐あって今年はサンタさんが来てくれそうな気配をびしびし感じてます。
でもここで油断してはいけません。クリスマスまで 2 週間もあるので明日からも気を抜かずに頑張ろうと思います。
しょうもない長文にお付き合いいただきありがとうございました。
よいクリスマスを!(まだ少し先だけど)
明日は MoneyForward Advent Calendar 2018 の 12 日目 garko さんの記事です。お楽しみに。
そして最後に一言...
「マネーフォワードでは、複数サービスを横断する改善の取り組みに興味のあるエンジニアを募集しています!!!!!」
ご応募お待ちしています。
【採用サイト】 ■マネーフォワード採用サイト ■Wantedly | マネーフォワード
【マネーフォワードのプロダクト】 ■自動家計簿・資産管理サービス『マネーフォワード ME』 iPhone,iPad Android
■「しら」ずにお金が「たま」る 人生を楽しむ貯金アプリ『しらたま』 iPhone,iPad
■おトクが飛び出すクーポンアプリ『tock pop トックポップ』
■金融商品の比較・申し込みサイト『Money Forward Mall』
■ビジネス向けクラウドサービス『マネーフォワードクラウドシリーズ』 ・バックオフィス業務を効率化『マネーフォワードクラウド』 ・会計ソフト『マネーフォワードクラウド会計』 ・確定申告ソフト『マネーフォワードクラウド確定申告』 ・請求書管理ソフト『マネーフォワードクラウド請求書』 ・給与計算ソフト『マネーフォワードクラウド給与』 ・経費精算ソフト『マネーフォワードクラウド経費』 ・マイナンバー管理ソフト『マネーフォワードクラウドマイナンバー』 ・資金調達サービス『マネーフォワードクラウド資金調達』