はじめまして、リンクバルエンジニアの北村尚之です。
弊社が運営するマッチングアプリ「CoupLink」ですが、今年の夏にソースコードの全面的なリプレイスを行いました。
具体的には、Vue.jsというライブラリを用いてフロントエンドをSingle Page Application(以下SPA)化しました。
また、HTMLを提供していたバックエンドも、DB設計からやり直し、APIサーバーとして一新しました。
この記事では、主にフロントエンド部分について、下記の話をしたいと思います。
- リプレイスの目的
- SPA化にあたり考えたこと
- 設計について
- Vue.jsの学習コストについて
目次
リプレイスの目的
SPA化による高速化
今回の改修以前のCoupLinkは、Ruby on Railsで組まれた通常のHTMLを返すWebページをベースに、ハイブリッドアプリとして提供されていました。
この構成だと、画面遷移にページの再読込みが発生するため、パフォーマンスには限界がありました。
これをSPA化によって改善したかったのが主な目的です。
設計・コーディングの改善
既存のソースについて、フロント・バックエンドともに設計がベストなものではありませんでした。
それに加え、数年間の運用でコードも複雑化し、開発パフォーマンスに悪影響がありました。
これを設計から一新したかったのも目的の一つです。
SPA化にあたり考えたこと
ネイティブアプリとの比較
CoupLinkはネイティブでの実装が検討されたり、実際に部分的にネイティブ化されたことがありました。
ですが今回、しばらくはWebでやっていこう、という結論になりました。
主な理由は以下3点です。
- チームのエンジニアの多くがWebメインである
- 毎週挑戦的に多くのリリースを行っていきたいと考えたときに、Webのほうがスピードを出せる
- SPA化によって、ネイティブにそれほど劣らないUIを実現できる
3つ目についてですが、SPA化で遷移が高速になることと、APIも速さに気を使っているため、単純なロードの速さならネイティブに劣っていないと思います。
スワイプのスムーズさや、細かい部分のインタラクションをこだわろうとしたときなどに、ネイティブに敵わないところがあると思います。
代わりに、Webでも努力できる部分は可能な限り調整しました。
例えば、無限スクロールするタイプの一覧系画面で、APIから30件ずつアイテムを取得してくる場合に、
画面へ30件表示しきってから次の30件を取得しに行くのではなく、20件ほど表示した時点で、次の30件を取得しはじめる、といったことをしました。
ライブラリの選定・Vue.jsを選んだ理由
フロントエンドのトレンドである
これは非常に重要な要素だと考えています。
コミュニティが活発で、情報が得られやすい。経験者を探すのも、新しく始めたい人を探すのも困難でない。
といったさまざまなメリットがあると思います。
公式でサポートされている拡張機能が多い
ルーティングを管理するVue-routerや、状態管理のためのVuexなど、Webアプリを開発していくうえで必要になってくる仕組みが、公式の拡張機能として提供されていることは非常に心強いです。
単一ファイルコンポーネント
Vue.jsの単一ファイルコンポーネントは、その部品を構成するのに必要な処理、テンプレート、CSSが一つのファイルに定義されます。
コンポーネント指向に基づいてWebアプリを組み立てていく際、これは非常に扱いやすいです。
いずれもクローズドな定義となり、例えばここに書かれたCSSは他のコンポーネントに影響を与えません。
HTML/CSSの既存資材をどうしたか
今回のリプレイスは、HTMLやCSSも例外ではなく、全て書き直しています。
HTMLやCSSは軽視されてしまうことがありますが、しっかり設計しないと、あっという間に破綻してしまいますし、一度破綻するとプログラミングより挽回するのが難しい気がします。
CoupLinkのリプレイス前のHTMLやCSSは、これといって命名規則も定められておらず、設計レベルで改善が必要でした。
これを解決しながらVueコンポーネントへ移植するよりも、新しく書き直すほうが断然低コストだったため、既存の資材は捨てました。
SEOに関して
SPA化にあたりよく心配されるのが、SEOに不利になってしまう点です。
なぜなら、SPAは最初にレスポンスされるHTMLにコンテンツが含まれないため、検索エンジンのクローラーがjsを解釈しない限りページを評価できないためです。
Googleのクローラーに関してはjsを解釈すると言われているものの、私見においては、これによる評価が、コンテンツをレンダリングした状態で返す場合と比べて同等である確証が持てておりません。
この対策として、SPA化の際にはSever Side Rendering(以下SSR)という手法が用いられる場合があります。
詳しくは割愛しますが、これによって初回HTMLでコンテンツが返ってきますので、SEOに関する問題の大部分を解決することができます。
ただ、CoupLinkはほとんどの画面へのアクセスにログインを要するため、そもそもSEOを考慮する必要がなく、SSRを含めて特に対策は行っていません。
設計について
Vue.jsのプロジェクトをセットアップする際、Vue-cliまたはNuxt.jsといったツールを用いて、一通りの設定を行うことができます。
もちろん自分でライブラリ選定から全て行うという道もありますが、おすすめではありません。
Vue-cliは公式で用意されたツールで、Vue.jsプロジェクトに必要な一通りのものが揃います。
Nuxt.jsは、さらに細かな規約も定義され、Vue-cliに比べて自由度は落ちますが、より強いフレームが用意されます。
CoupLinkではVue-cliをベースに設計を進めました。
開発開始後しばらくは、大まかな部分を一人で実装しつつ、設計的な部分も調整していきました。
実装の方向性がメンバーごとにブレてしまわないよう、ある程度の見本が整って、設計的な部分も調整しきった段階でアサインしてもらいたいと考えていました。
チームみんなで書き始めてからは比較的スムーズでしたが、もちろん実装のブレが全くなかったわけではありません。
僕は最初、GlobalMixinという全コンポーネントで読み込まれるMixinを用意していました。
ここには、あらゆるコンポーネントで使うような本当に汎用的な処理だけを書くつもりでいました。
なぜなら、このGlobalMixinの多用は、名前の衝突を招いたり、定義元を追うのを困難にするためです。
しかし、この基準を明確にルール化できなかったため、開発が進むにつれ、2,3個のコンポーネントで使うだけのちょっとした処理まで定義されるようになってしまいました。
(これについては、別ファイルに切り出して、使う場所で明確にimportしてもらうようにしました)
このような「最初に設計した人の頭の中にだけあるルール」は暗黙的に認知されることもありますが、されない場合もあります。
とはいえ、ルールをたくさん用意することで解決したくはありませんので、見ただけでどこにどんな処理を定義するべきか分かるよう、ディレクトリの切り分けに至るまで慎重に考える必要があると思いました。
Vue-cliやNuxt.jsなどによるセットアップは、それを実現するうえでかなりの近道になると思います。
Vue.jsの学習コストについて
今回、ライブラリにVue.jsを採用しましたが、社内にVue.jsの実績があったわけではなく、メンバーには開発しながら習得してもらう前提でした。
Vue.jsは、単に実装するだけであれば学習コストは高くないと感じていますが、プログラマー出身なのか、HTMLコーダー出身なのかでそれぞれ少し難しく感じる部分があるかもしれません。
うちのチームはサーバーサイド寄りの開発者が多いのですが、JaveScriptやViewテンプレートの実装に関しては問題なく実装できていました。
宣言的にテンプレートを作っていく思想は、RailsのERBなどともよく似ているので、親しみやすいのかもしれません。
どちらかというと、Vue.jsの学習とは関係ありませんが、CSSまわりの実装に苦労しているように見えました。
CSSは仕組みこそ簡単ですが、プログラミングとは違ったコツや知識が必要となるため、慣れていない人には少し厄介かもしれません。
このプロジェクトとは別の話ですが、jQuery経験の長いコーダーにVue.jsを使ってもらった際は、HTMLの動きを宣言的に書くというのが慣れないようで、どうしても自分でDOMを変更する処理を書いてしまいがちでした。
いずれにしても、Vue.jsを習得してもらうのは困難なことではありませんでした。
公式ドキュメントが充実していることも、その助けになっていると思います。
おわりに
今回のリプレイスで、アプリのパフォーマンスを改善できたことももちろんですが、
ソースが一新されて開発効率が大幅に上がったことが何よりよかったです。
この新しいソースをベースにCoupLinkをより便利で使いやすくしていきますので、ぜひ使っていただけたらと思います。
リンクバルでは一緒に働く仲間を募集中です。
少しでも興味のある方はこちらまで連絡をお願いいたします。
今回のリプレイスのような技術的な改善に理解が得られるのも、弊社技術部のよいところだと思います。