こんにちは、 @mugi_uno です。
Misocaがサービスローンチされたのは 2011年です。実は2021年は10年目ということで何気に節目の年だったりします。
10年もあれば世の中的にもさまざまな技術変遷があり、Misocaもその波に乗っていけるよう、日々改善を繰り返してきました。
というわけで今回は、私自身がフロントエンド側の作業を多くやってきたこともあり「この10年間でMisocaのアーキテクチャがどのように変わってきたのか?」をフロントエンド側に焦点を絞って振り返ってみたいと思います。
※ 意思決定に関する資料が無いものも存在するため、一部は情報に基づく推察になる点をご承知おきください。
年表
いきなりですが、ざっくり年表を書いてみました。
上部の黄色いラインは、フロントエンドに大きい影響を与えたMisocaの機能です。
これをもとに、サービスローンチから順を追って見てみます。
創成期 / 2011 サービスローンチ〜2015
いきなり4年経過していますが、この頃はある程度固定化されたアーキテクチャで開発が進められていました。
ベースとなる技術要素は
- jQuery
- CoffeeScript
- Bootstrap
- Sprockets (Asset Pipeline)
と、当時Railsでアプリケーションを組む際に主流だったものが利用されています。
当時はまだ npm によるパッケージ管理なども導入されておらず、jQuery UI のような依存ライブラリは、直接リポジトリ内にダウンロードしたファイルが配備されていました。
また、recalc
という魔法の金額計算関数が爆誕し、長きに渡って良い意味でも悪い意味でも大活躍します。
フロントエンド改善のはじまりと案件機能 / 2015-2016
ローンチからしばらくはMisocaフロントエンドの技術スタックに大きい変化はありませんでしたが、この頃から徐々に新しいライブラリが導入されるなど、いくつかの改善が施されるようになっていきます。
Vue.js 導入
機能が増えていくと同時に、フロントエンド側のコードも徐々に増えていき、jQuery だけですべてを制御することの課題感が出てきたころです。
そこで、検討の結果 Vue.js (当時のバージョンは 0.12) が導入されました。 他にも Angular や Backbone なども候補に挙がっていたようですが、重厚ではなく薄いものがいい、ということで Vue.js が選ばれました。
現在の視点で見ると「Vue.js が薄い?」と思いますが、当時の Vue.js は Single File Component も存在しないため webpack などのビルドも必要なく、かつ Rails が出力するテンプレートをそのまま利用できるなど、コストを低く導入できる点なども採用理由でした。
一気にすべてを書き換えることは厳しいため、このあたりから時間がある時に徐々に Vue.js へ書き換えるようになりました。
パッケージ管理とBrowserifyによるビルド
依存ライブラリはファイルを直接リポジトリに配備して管理していましたが、Vue.js の導入とほぼ同時期に、npm によるパッケージ管理と Browserify によるビルドが組み込まれました。依存が増えて手動による管理に限界が出てきたと思われます。
今でこそ webpack が大活躍していますが、当時は Browserifyや Bower が広く使われていたころです。
Misocaでは browserfy-rails という Gem を介して Browserify ビルドを実行していました。
RubyMineでデバッグしたときのブログが残っていますね。
案件機能と React & Redux
とある実現しなかった機能開発で React & Redux が試験導入され、そのノウハウをもとに 「案件」という機能が React & Redux を利用した SPA で構築されました。
それまではフロントエンド部分の開発はあっても、基本的には Rails Way に乗った開発スタイルでしたので、技術的には挑戦的なテーマで、 社内的にもモダンフロントエンドのノウハウを蓄積できるいい機会だったのではないかと思われます。
フロントエンド開発生産性の改善 / 2017-2018
世の中的にもフロントエンドに求められる範囲がどんどん拡大していたころですが、Misocaではアーキテクチャ的に大きい更新が無く、客観的に見るとレガシー化が進んでました。一部のコア機能は Vue.js 化されていましたが、積極的に活用されているとはいえず、新しくコードを書くときは jQuery & CoffeeScript が現役でした。
開発生産性への影響に限らず、採用面などでもデメリットが大きいため、このころから脱レガシー作業に多く取り組むようになります。
Webpacker 導入
ビルドに利用していた browserify-rails ですが、日常的にフルビルドに数分かかる状態になっており、開発時の大きなフラストレーションになっていました。
そこで、ちょうど同時期に Rails 5.1 で導入された Webpacker を試したところ、15秒-20秒ほどでビルドが終わることがわかりました。
トレンド的にも webpack が完全に主流になっており、流れに乗る意味でも Webpacker が正式導入されました。 JSのビルドは browserify-rails と Sprockets の両方を使っていた状態でしたが、これによって Sprockets はCSSと画像のビルドのみを行う存在になりました。
Vue.js の最新化
当時の Vue.js の最新バージョンは 2.4 で、いまでこそ当然の Single File Component をはじめとする、多くの魅力的な機能が利用可能でしたが、Misocaでは2015年に Vue.js を導入してから更新されておらず 0.12 のまま止まっていました。
jQuery を使ってコードを書き続けるのは将来を見据えた場合に望ましくなく、かといって Vue 0.12 で新しいコードを書くのももはや負債を増やす事になりかねません。
Webpacker の導入で Vue 2.x 系のビルドを組み込むことが可能になったため、それを利用して Vue.js の最新化が行われました。 これ以降は、 Dependabot などで継続的な更新を続けるようになり、2.x 系の最新版が維持されています。(3.x系への更新は IEの絡みにより未着手です。)
CoffeeScript → ESNext へ
Vue.js の最新化をする際に、多くのコードの書き換えが必要となりました。
その際に、CoffeeScriptで新しく書くのは気が引けたため、併せてESNextへの書き換えが実施されました。 これ以降はすべてのコードが ESNext で書かれるようになります。
いま思えば、このタイミングで ESNext 化をしていなかったら、後々の TypeScript 導入時に地獄を見ていたのかもしれないな..と思います。
CI周りの整備 (ESLint、テストコード)
CoffeeScript から ESNext に移行したことで、ESLintによるコード分析が可能になりました。 各エンジニアのセンスと好みによっていい感じにレビューで指摘していたものが、ESLintによって検査される秩序ある世界に変わりました。
また、Vue.js 最新化や ESNext への置き換え時は Feature Spec と人力テストにすべてを委ねるドキドキの作業で、精神衛生上とてもよろしくないものでした。
フロントエンドのテストコードが一切存在しないことが改善時の大きな負担になるのを痛感し、フロントエンド単体で Mocha を利用した テストコードを書けるように整備されました。
さらなる改善 / 2019-2020
ある程度全体的な土台が整備されてきたため、+αの挑戦的な取り組みを始めたり、長らく手がつけられなかった秘伝のタレ的なコードにもメスを入れはじめた頃です。
金額計算処理のリファクタリング
サービスローンチ時からずっと支えてきた「recalc
」という魔法のグローバル関数がありましたが、魔法すぎて全体像を誰も把握できておらず、改善しようにも手がつけられない状態が長く続いていました。
そんな中、国で軽減税率制度の導入が決定したことで、魔法とかそんなことは言ってられない状態になりました。
そこで、魔法の関数 recalc は廃止され、計算ロジックだけが npm パッケージとして外部に切り出されました。
それまでの改善の積み重ねによって、テストコードをはじめとするリファクタリングを支える土台は整っていたので、なんとか実現できました。
Webpacker → webpack
導入コストの低さから browserify-rails に取って代わる形で導入された Webpacker ですが、フロントエンドで必要とする依存の増加に伴い、Webpacker のまま開発を続けるのに支障が出てくるようになりました。
Webpacker の恩恵を受けるフェーズは終了したと判断し、純粋な webpack ビルドへ置き換えられました。
Mocha→Jest
世の中の潮流に併せて、テストコードが Mocha から Jest に移行されました。
それまでは mocha-webpack を利用しており、実行も重たい状態でしたが、Jest によって大きく改善されました。
また、Jest によって提供されるスナップショットテストなども一部で利用されるようになりました。
TypeScript の導入
2021年現在では完全にメインストリームと化した TypeScript ですが、 Misocaでは同年に実施された金額計算処理のリファクタリングのような作業のリスクを軽減する目的で導入されました。 さすがに学習コストも高かったので、社内ハンズオンなども実施されています。
当初は strict: false
の緩い状態での導入で、自動推論で恩恵を受けられる部分だけ受けておこう、というスタイルでした。
デザイン周りの大幅な改善
この頃は、デザインに関する大きな改善進捗もありました。
まず、デザイナーの皆さんにより「ユーザー体験統一」というプロジェクトが旗揚げされました。
これにより、Misoca全体でデザインに関する統一した指針 (Misoca Design System) が定まり、プロダクトに適用されました。
さらに、それまで大活躍していた Bootstrap もすべて引き剥がされ FLOCSS に書き直されました。 CSSの詳細度バトルから解放され、秩序が訪れます。
また、CSSビルドが Asset Pipeline から webpack に乗る形に置き換えられました。 CSS周りでの依存関係もきちんと管理されるようになり、日常的な更新も可能になりました。 同時にSprocketsの役割はさらに小さくなり、現在はごく一部の画像のビルドのためだけに利用しています。
SPAによる機能実装
いくつかの機能がSPAで機能実装され、あわせていくつかの新しい技術要素にトライしました。代表的なものは Vue Composition API と GraphQL の2つです。
それまでは Vue 2.x の Option API で開発をしていましたが、TypeScriptとの相性で厳しさを強く感じていました。 Vue Composition APIは、Vue 3.x 系以降で追加される Vue.js における新しいAPI で、従来とは大きく記法が異なりますが、TypeScript との親和性が高いです。
これ以降は、Misocaでは積極的に Vue Composition API が利用されるようになります。
また、フロントエンド⇔バックエンド間通信に GraphQL が導入されました。実験的な側面も大きかったように思いますが、型定義面などで感じられる恩恵も大きく、現在も新規API作成時は GraphQL を利用しています。
現在と未来 / 2021-
現在は次のようなことに取り組んでいます。
Vue Composition API への書き換え
すべてのコードが Vue Composition API であるのを理想として徐々に書き換えています。
Vue 3.x でも Option API は引き続き利用可能ですが、2つの記法が混在していると混乱を招くのと、TypeScriptとの相性を考えて 基本的に Composition API に統一しようとしています。
TypeScriptの型定義の強化
導入時は strict: false
でゆるゆるの状態のTypeScriptでしたが、現在は strict: true
に切り替わり、将来に委ねて FIXME_any
という定義で逃げていた any
利用箇所もすべて厳密な型定義に置き換えました。
他にも型検査的に怪しい箇所が多数残っている状態ですので、日々コツコツと手を加えている状況です。
React & Redux 機能の廃止
2016年に案件機能と同時に導入された React & Redux は、機能自体が提供終了の運びとなり、同時にコード上からも姿を消す予定です。 今後しばらくは Vue.js に一本化して開発していくことになると思います。
【予告】案件機能を終了します | 請求書作成サービス「Misoca(ミソカ)」
今後の課題
少しずつ改善されてはいるMisocaフロントエンドですが、課題は多く残されています。
代表的なものはjQueryで、サービスの中でもコアな部分でjQueryコードがまだまだ現役で動いています。 jQueryであるがゆえに影響範囲が読みづらく、それによる変更時の不具合もちらほら発生しているため、なんとかする必要があります。
また、GraphQL化も道半ばで、新規作成したAPIと既存APIの一部はGraphQLに移行しましたが、完遂しておらず RESTと混在している状態です。 それによってTypeScript型定義がごちゃごちゃしている部分もありますし、今後も継続して対処していく必要があります。
他にも Vue3.x導入を目指した対応・テストコードの拡充など、やれることはたくさんあります。
おわりに & 未来の話
歴史を振り返ってみると、改善の土台の上に新しい改善が乗っており、そこから新しい技術挑戦へと繋がっているように感じます。
フロントエンドは技術変遷が早いと言われ、日々新しい技術要素が登場しています。 それは同時にフロントエンド側に求められる機能要件の範囲が広がっていることを意味し、Misocaの機能開発も例外ではありません。
サービスとして何か新しいことをやりたい・実現したいときに、「レガシーなのでできません」と言うことができるだけないよう、 コツコツした積み重ねで準備しておくのが大事なのかもしれません。
日々精進ですね。自分も頑張りたいと思います👍