業務システムのモダナイズを始めました〜RoRからFastAPI × next.jsへ
はじめに
この記事では、詳細な技術の話は割愛しています。
「なぜモダナイズをやろうと思ったのか?」
「どんな課題意識があったのか?」
「具体的にどうプロジェクトを進めてきたのか?」
といった、課題設定・意思決定のプロセスに重点を置くことで、同じような境遇にあるチームの意思決定の材料になればと思っております。
RoRの限界...?
ダイレクト出版の業務システムはRoR(v6.1)で動いてきました。リリースから6年ほど経っているでしょうか。このシステムは何をするものかというと、例えば、
- 商品を管理する
- 顧客を管理する
- 注文内容を設定する
- 一斉配信メールを送信する
- マーケティングオートメーションを設定する
- 各種分析を行う
など、業務に関わるありとあらゆることを行っています。ソースコードは10万行程度で、中堅システムといった具合でしょうか。
実はこのシステム、そこまでレガシーというわけではなく、テストコードやCI/CDといった基本的なポイントは押さえられています。なので、機能の新規開発でデグレはほぼ発生していませんし、既存機能のfixも概ねスピーディーに行えています。
しかし...一つ、致命的といっていいほどのマイナスポイントがありました...。それは、
フロントエンドの開発者体験が悪い
というものです。
生のhtml/css/jsの苦しさ
RoRのバージョン6系列ということもあり、viewの基本となるerb(htmlとrubyをいい感じに扱えるもの)、sass、js.erb、partial(要素の一部を別ファイルに切り出して各所で呼び出せる機能)を駆使して画面を作っていましたが、画面単位で開発が進んでいくために、徐々に
- 同じ見た目なのにそれぞれ違う方法で実装されている
- 逆に、同じコンポーネントなのに微妙に見た目や挙動が違っている
- sassが画面単位で切られているので全く同じcssのコピペが発生している
といった問題が顕在化し、「ほとんど同じ見た目のページを作るのになんで丸一日かかるんだ...」という苛立ちが募るようになってきていました。
また、業務用システムであってもSaaSのようなリッチでわかりやすいUIを目指しているということもあり、特にバニラjsの実装は複雑になりやすく、辛いものがあります。複雑な手続きが各所に散っているわけなので、そもそも画面上の動きがどこでどう実装されているのか追うのも一苦労な箇所もあります。
フロントエンドの開発者体験が悪いことの深刻さ
開発者体験が悪いと、
- 今働いているエンジニアが「フロントエンドを頑張りたい」と思えなくなるため、フロントエンドを担当できる人材が育たなくなる
- フロントエンドの開発者体験が悪いため、新規でフロントエンドエンジニアを採用するのが困難になる
- 結果、いつまでたっても会社のフロントエンドまわりの技術が進歩しない
こういった悪循環が発生します。これは、単に開発効率が悪いことの何倍も厄介です。
ITエンジニアのような、個人個人の技術力が全体に大きな影響を与える職種において、優秀な人材が育たない・採用できないというのは開発組織として致命的な問題です。
マネジメントを考えると、これは単に「開発効率が悪い」というだけで片付けることができない課題でした。
問題の本質
ただ、これはRoRの限界というよりも、お恥ずかしながらただ我々が再利用性のあるコンポーネント設計をできていないことによる問題だと捉えました。
RoRは、超高速でプロダクトを立ち上げられるだけのお手軽さがある反面、書き手に委ねられるところも多いです。最初期は画面ごとにview/sass/jsを作っていても特に問題なかったのが、プロダクトが成長したり、運用するようになるにつれ、再利用できないことのコストがボディーブローのように効いてくるようになってしまっていました。RoRの良さである「素早さ」が損なわれている状態は、せっかくの良いツールを使いこなせていない歯がゆさがあります。
そして、私たちのモダナイズプロジェクトは、このフロントエンドの課題意識、苛立ちから始まりました。
RoR × Reactを試す2週間
当時フロントエンド開発への苛立ちがピークに達していた私のチーム(5人)は、四半期目標として「業務システムにReactを導入する」というものを掲げ、2週間開発をストップしてReactを導入するためにガチャガチャいじくり回すという実験を行いました。
上述の通り、問題はRoRというフレームワークにあるのではなく、「再利用できない作りにしてしまっている」ということです。そのため、設計に強制力をもたせることを目的として、RoRにReactを載せることを検討しました。
2つのgem(Rubyライブラリ)を検討
とりあえず使用感を掴みたかったので、RoRで簡便にReactを導入するために
- react-rails
- react_on_rails
という2つのgemをそれぞれテストブランチで試験導入してみました。
react-rails:現行のビルド環境のまま簡単に導入できる
react_on_rails:ビルド環境に手を加える必要があるが、よりできる幅が広がる
ざっくり、こんな感じです。
2週間の検証の結果、react_on_railsであれば「Reactっぽく書ける」「外部ライブラリを使える」といった基本的な要件は満たせましたが、私たちの現在の環境では、本番で長く使うことを考えると
- アセットパイプライン(フロントエンドのビルド・コンパイル環境)を抜本的に変更する必要がある
- バックエンド側もガラッと変える必要がある箇所がある
という課題が新たに生まれます。そして、やはり普通のReactではないので標準的な設計にはなりえません。ここで、2つの選択肢が生まれます。
RoR × Reactを採用し、両者の結合を許容しながら頑張って上記の課題を解決するか、RoRをやめるかです。私たちは、後者を選びました。
なぜRoRをやめたのか
一番の決め手は、当初の課題意識である「フロントエンドの開発者体験」でした。gemの実験の最中、メンバーが、
「react_on_railsはreact_on_railsであって、Reactじゃないですね。」
という感想をポロッと口にしたのを今でも覚えています。そのメンバーは、もともと他社でReactを触っていたり、フリーランスでもReactの案件を動かしていたりと実務経験の豊富な学生インターンの方だったのですが、彼の口から出たこの言葉や実際に触ってみた感覚として「コレジャナイ」感が強くありました。
もちろん、react_on_railsでしっかりと書けば顕在的な問題であるフロントエンドの開発効率は改善するでしょうが、開発者体験全体を考えたときにベストな選択肢ではないと思いました。
世の中はフロントとバックを分離していく方向に向かっていて(主観ですが)、その中で、react_on_railsという特殊な環境で、RoRと結合した(≒歪んだ)設計でプログラムを書くというのは、フロントエンドのキャリアとしてあえてやりたいものではない...。
「単純な開発効率よりも、開発者体験が悪い事のほうが深刻だ」と上述しましたが、RoRとReactを結合させた状態を採用するということは表面的な(開発効率という)問題しか解決しないおそれがあります。
そして、仮にRoR × Reactを採用したとしても、バックエンドの大幅な改修が発生することが予想されるため、新たに作り直しても工数的にあまり変わらないという感覚値がありました。
であれば、中長期を見据えて純粋なReactで構成したほうがハッピーです。これが、RoRとの決別の第一歩となります(next.jsは色々簡単なので導入しました。)
rubyからも離れたワケ
上述の通り、フロントエンドはバックエンドに依存しない形にすることになったので、バックエンドはなんでもよくなりました。
順当に考えれば、今のRoRプロジェクトのバックエンド側を調整して再利用しますが、こちらも思い切って変えることにしました。
rubyは世界的に見ても(残念ながら)ダウントレンドです。
(Stack Overflowより)
社内でも時折、「rubyいつやめるよ?」みたいな雑談が出たりしていたのですが、やはり開発者コミュニティの大きさ、アクセスできるリソースの多さ、ライブラリの豊富さは武器になります。
トレンドに乗った言語環境は、採用の武器にもなります。
これが、rubyからpythonへ切り替えた決め手です。
バックエンドのミッション
ここまでバックエンドの課題については触れてきませんでしたが、バックエンドはバックエンドで、色々課題を抱えていました。
- 特に最初期に書かれた古いコードが負債化している
- 統一的な設計方針がない
- ActiveRecordとデータベースモデリングの噛み合わせが悪い
- RoRの破壊的なメジャーバージョンアップデートが辛い
特に、設計方針のなさは今後のことを考えても改善していかなければならないポイントです。弊社では現状リポジトリ全体の管理者がおらず、複数のチームがそれぞれバラバラにコードをコミットする体制を取っている背景もあって、悪く言えば好き放題書けるような環境でした。
しかし、これからさらに機能開発を行ったり、組織を拡大していくなかで、設計方針がない状態は負債の温床となりかねません。したがって、組織全体が従うことのできる設計方針を作るということをミッションに定め、リプレイスしていくことに決定しました。
(このミッションにおいてはフレームワークはなんでもよく、上記の技術的な問題を解消・緩和できそうなFastAPIを使う運びとなります。)
PJキックオフへ
モダナイズに向け、ざっくり半年〜1年弱くらいの予想のもと、私のチームから2名このプロジェクト専属で配置しました。
また、技術顧問として以前からお世話になっていたバックエンドエンジニア1名、その方のお知り合いのフロントエンドエンジニア1名にも参画していただき、実働2名 × 技術顧問2名の体制でモダナイズプロジェクトが始まります(ちなみに2名ともアメリカの会社にお勤めで、ハワイからリモートです。)
モダナイズにおいては内部品質がすべてと言っても過言ではないので、経営層に企画を持っていき万全のサポート体制でプロジェクトをスタートをできたのは僥倖です(このような御縁や経営層の理解に本当に助けられています。)
プロジェクト開始から3ヶ月経ちましたが、既存システムとの併存環境構築、機能の雛形が完成目前という進捗です。メンバーの感触は上々で、一番大事にしていた内部品質はかなり自信を持てていますし、開発それ自体や技術顧問の方からのご指導で得られたナレッジをもとにした社内勉強会、Qiita記事なども盛り上がっています。
次の目標
現在は実働の2名のみが知識・経験を蓄えていますが、これを組織全体に伝播させていき、全体の技術レベルを一段階飛躍させることを目標としています(私含め...笑)。
今後このプロジェクトがどう転ぶかはやってみないとわかりませんが、うまくいっても失敗しても、いいケーススタディにはなることでしょう。
以上、弊社で実施しているモダナイズPJの経緯でした。また、まとまった進捗ができてた頃に記事を書こうと思います。
長文にお付き合いいただきありがとうございました。
Discussion