プロダクトエンジニアリング部の海老澤です。 普段は LIFULL HOME'S の賃貸部門のフロントエンド開発をしています。
近年、LIFULL の開発部門では「開発生産性」という言葉が取り沙汰されるようになりました。
LIFULL HOME'Sの主要リポジトリは10年以上運用され続け、今も多くの開発者によって日々改修され続けています。 長い年月の中で小さな設計ミスも積み重なって大きくなり、ちょっとした実装でも入念な調査が必要となり開発生産低下の要因となっていました。 また10年以上前に採用したフレームワークで稼働しているため、今ではドキュメントを探すのも一苦労という具合です。
そこで主要開発部門では「自部門の機能はマイクロサービスへと切り離し、各々で面倒を見る」という方針になりました。 賃貸部門も同様に機能の切り離しを始め、先日「物件詳細ページ」のマイクロサービス化を行いました。 今回はマイクロサービス化にあたり新基盤の技術選定をしたので、実際触ってみた感想などを交えながら紹介していければと思います。
画面のビフォーアフター
マイクロサービス化と同時にUIのリニューアルも検討、開発中です。
※キャプチャは開発中の画面です。
旧基盤ではダイナミックサービングでPC/Tab用・SP用のレイアウトを切り替えていましたが、新基盤ではレスポンシブデザインへと変更しました。 デバイス間のデザインルール・トンマナの差分をなくすこと、開発生産性を上げ改善スピードを上げるのが狙いです。
新基盤の全体構成
今回は Web アプリケーション部分のみ刷新を行いました。API は全社で使っている既存のものを使っています。
ここからは技術選定についての詳細を書いていきます。
バックエンド
バックエンド 技術選定のモチベーション
社内で標準採用されている言語・技術であること
これは組織の課題でもあるのですが、LIFULL はエンジニアの部署異動がそこそこあります。 社内では技術集約の観点で標準技術が定められてるのでそれに従いました。
技術選定で「挑戦」しないこと
LIFULL HOME'S の賃貸部門は LIFULL の中でも中核を担う組織で、ほかの開発チームに比べて規模が大きいです。 それゆえに人員の入れ替えも顕著で、さまざまな技術スタックを持った人がいます。
そういった中で目新しいフレームワークを用いるとドキュメントや知見不足に悩むことがあります。 有識者がチームに必ずいるのであれば良いのですが、チーム編成の都合上難しい場合もあります。 そうなってしまった場合、開発はつまずきがちになりますしコードの品質も落ちることが過去の経験則から容易に想像できました。
このような事態を避けるために我々は技術選定で「挑戦」するのをやめ、学習コストの低いフレームワークを採用することを選びました。
採用技術
上記のモチベーションを踏まえ、バックエンドは以下を採用しています。
- アーキテクチャ: Clean Architecture
- フレームワーク: Express x TypeScript
- アプリケーション実行基盤: 内製ライブラリ「KEEL」
アーキテクチャ: Clean Architecture
LIFULL のバックエンド刷新プロジェクトで採用されたアーキテクチャです。 それが社内に広まっていて知見も溜まっているため、今回 Clean Architecture を採用しました。 www.lifull.blog
情報を表示するだけの Web アプリケーションで Clean Architecture は冗長ではないかという意見もありましたが、レイヤごとの責務・規約がはっきりしており制約が厳しいことから開発者によるブレが少なくなることが見込めます。
実際業務で触ってみたときも「どこに何を書けばいいのか」というのが分かりやすく、設計しやすいのは魅力だと感じました。(実装の「詳細」「抽象化」まわりの理解はちょっと大変でしたが……😇)
フレームワーク: Express x TypeScript
言わずと知れたバックエンドフレームワークです。 日本語ドキュメントや記事、ライブラリも充実しているため学習コストを低く抑えることができます。
型の恩恵は受けたかったため TypeScript も導入しています。 TypeScript は社内でも導入事例が多くすんなり決まりました。 今の所は複雑な型推論は必要としておらず、素直にコードを追えば型がわかるため安心感があります。 バックエンドとフロントエンドで言語を共通にできるのも良い点だと感じました。
アプリケーション実行基盤: 内製ライブラリ「KEEL」
実行基盤は全社で利用している内製ライブラリ「KEEL」を活用しています。 デプロイやログ吐き出しなど日々の運用タスクを吸収してくれるすばらしい基盤で、 KEEL のおかげでアプリケーション開発に集中できています。 当ブログでもよく記事があがっていますので詳細は割愛しますが、ぜひご覧ください。 www.lifull.blog
フロントエンド
フロントエンド 技術選定のモチベーション
メンテナンスコストが軽いこと
まず第一に、LIFULL HOME'S は複雑な操作やインタラクションを必要としないポータルサイトです。 クライアントが入稿した情報の表示がメインで、ユーザーの操作によって画面が大きく変わるということがほとんどありません。
そういったサイトを開発していくうえで React や Vue を用いるのは冗長だと考えました。 実際アップデートの頻度も高くメンテナンスコストが嵩みますし、ビルドプロセスも必須です。 今後さらにイケているフロントエンド技術が出てきた際に引き剥がしにくいという欠点もあります。
前身のメインリポジトリは10年以上稼働していますが、 ソースコードの規模が膨大すぎること、依存関係が大きいことからアップデートが非常に困難になっています。 今回の新基盤は何年稼働するか分かりませんが、少なくとも5年以上は開発されるでしょう。 そうなった時にメンテナンスコストが軽いというのは大きなメリットとなります。
開発者のスキルに左右されないこと
バックエンドの技術選定でも触れましたが、賃貸開発部門は規模が大きく人員の入れ替えも顕著です。 常に複数のチームが稼働しており、同じページを並行開発していることもあります。 HTML/CSS/JavaScript に明るくないコーダーやバックエンドエンジニアがフロントを触ることも多々あります。 そういった際に学習コストの高い React や Vue だと逆に開発の遅れを招いたりレビューコストが高まるという懸念もありました。
そのため、なるべく平易で学習コストの低い技術を採用しています。 後述する Tailwind CSS や Stimulus は比較的最近のフレームワークですが、ドキュメントが簡潔かつできることも限られているため1日あれば手に馴染む技術です。
フロントエンド 採用技術
これらのモチベーションを踏まえ、フロントエンドは以下を採用しました。
- HTML: Preact x TypeScript で HTML を生成し Express でサーバサイドレンダリング
- CSS: Tailwind CSS
- JavaScript: Stimulus
HTML: Preact x TypeScript
Preact x TypeScript で Express から素の HTML を返却しています。
Preact の選定理由としては軽量であること、型が使えることです。 我々は HTML をレンダリングしたいだけなので React のような重いライブラリは冗長でした。 とはいえ型情報は付与したかったので、 tsx 形式が使える Preact を採用しています。
クライアントサイドの振る舞いは前述の Stimulus を利用するので Preact はテンプレートエンジンとしてのみ利用しています。 これは別のテンプレートエンジンに差し替えたくなったときに載せ替えを容易にするためでもあります。
CSS: Tailwind CSS
Tailwind CSS はユーティリティファーストな CSS フレームワークで、非常に小さい単位の CSS クラスを HTML に直接書いて組み合わせることでスタイリングをします。
従来の課題として、HTML と CSS の概念的距離が遠いという問題がありました。 普通にコーディングを行おうとすると HTML に適当なクラス名を振って別途 CSS でそのクラスに応じたスタイルを書き、HTML 側でその CSS を読み込むという手間が発生します。 Sass の登場で CSS を書くのはいくらか楽になりましたが、概念的距離の圧縮まではいきませんでした。 Vue のように SFC でやるという手もありますが、それでもクラスの命名という一番面倒で退屈な作業は残ってしまいます。
Tailwind CSS はすでに用意されているクラスを組み合わせて使うので命名という概念がなく、 HTML にガンガン書いていけるので概念的距離をゼロにできます。 また、クラスの単位が非常に小さいのでカスタマイズ性も高く、デザインの再現も容易です。 HTML を見るだけである程度見た目が想起できるというのも魅力的ですね。
頻出スタイル(ex: ボタンデザイン)は @layer component
へ切り出して使っていますが、ごく少数ですし1ファイルにまとめているので何個も CSS ファイルを開くこともありません。
体感ですが CSS を書いていたころよりも倍以上のスピードでコーディングできるようになったと感じています。
素 CSS/Sass を書くときは少し憂鬱になります。
JavaScript: Stimulus
前述したように、LIFULL HOME'S は物件情報を載せるポータルサイトでありユーザーの複雑な操作を必要としません。 そのため js で与えるべき振る舞いも少なく、再利用できる動きがとても多いです。
そういった振る舞いを共通化する際、React や Vue でコンポーネント化して再利用するというのが考えられます。 しかし表示箇所によって少しデザインが変わるだけで HTML や CSS クラスの分岐が発生してコンポーネントが肥大化していくという問題があります。 Slot や Mixin を使いこなせばそんなことにはならないかもしれませんが、大規模な開発組織でそれらの統率をとっていくのは非常に困難です。
そこで我々は 37signals 謹製の JavaScript ライブラリ Stimulus を採用しました。
ドキュメントにもあるように、Stimulus はちょっとした振る舞いを HTML に与えるライブラリです。
HTML に data-controller
とそれに付随するデータ、アクションを書くことでイベントを貼り付けることができます。
Stimulus の旨味は Controller を複数アタッチできること、DOM 構造に縛られないこと、イベントアタッチの処理が不要なこと です。 再利用性の高い小さな Controller を作っておけば HTML がどんな構造・デザインであろうとアタッチすれば動きますし、複数組み合わせると複雑な動きも作れます。
また、HTML と js の結合で一番面倒なのが addEventListener
の処理かと思いますが、
Stimulus は MutationObserver
で DOM を監視しており HTML が画面に出現するだけで 自動で該当の Controller のイベントがアタッチされます。
これは非常に強力で、サーバサイドから Stimulus Controller が設定された HTML を返却すれば Ajax で画面を一部更新しようと勝手にイベントがアタッチされるため js の読み込み忘れで画面が壊れた〜という心配もありません。
同様に DOM が消えれば removeEventListener
されるのも安心ポイントです。
今回の新基盤ではオートローダーの仕組みも導入しているためページごとに読み込む js を bundle する必要もありません。たいへん快適です。
弊社エンジニアの Qiita 記事でも紹介しております。 qiita.com
再利用性の高い Stimulus Controller が充実してくると HTML に既存 Controller を書いていくだけで振る舞いの実装が終了するため、js を書くことがほぼなくなります。 実際、新基盤が稼働してから数ヵ月機能追加・画面改修をしていましたが、ほとんど js は書いていません。 コードは書くほど負債になると言いますが、きちんと設計すればするほど資産になっていくのも Stimulus の魅力だと感じます。
過去の記事でも話題にしていますので、ぜひこちらもご覧ください。 www.lifull.blog
テスティング
テスティング 技術選定のモチベーション
テスティングに関してはそこまで大きい課題感はなかったのですが、 UnitTest を速く実行できること、E2E テストを書きやすくするのは意識しました。
テスティング 採用技術
- UnitTest: Vitest
- E2E: Playwright
UnitTest: Vitest
Vitest は Vite の設定をそのまま使えるテスティングライブラリです。 今まで弊社の TypeScript 環境では Jest を採用していて最初はそれに倣っていましたが、 開発中に Vitest がよいぞとなり乗り換えをしました。
書き味は Jest とほぼ同様ですが実行速度が桁違いで、爆速で UnitTest を回せます。また、config も非常にシンプルで設定がとても楽ちんです。
Vite を使っているわけではないので全恩恵を授かっているわけではないのですが、実行速度が速いというだけで爆アドだと思います。 乗り換え自体もとても簡単にできたので、Jest を使っている方はぜひ Vitest もご検討ください。
E2E: Playwright
Playwright は Microsoft 謹製の E2E ライブラリです。
TypeScript に標準対応しているのが魅力的で、難しいセットアップをせずとも導入が可能です。
公式ドキュメントも充実しており、「こういうことがやりたいな〜」というのはたいてい Guide にそろっているので安心感があります。
主に旧基盤と新基盤の情報の表示差分確認や package bump 時のビジュアルリグレッションで活用していて、テスト工数の削減に役立っています。
まとめ
まだ新基盤が稼働して数ヵ月しか経っておりませんが、旧基盤と比べて圧倒的に開発しやすく生産性が高まっているのを感じています。 実際稼働から何名か新規メンバーが入りましたが、そこまで苦労せず開発できているようです。
LIFULL HOME'S はまだまだ成長していくプロダクトです。 今回の基盤刷新をきっかけにより良い価値をユーザーに届けてまいります💪
最後に、LIFULL ではともに成長していける仲間を募集しています。よろしければこちらのページもご覧ください。