レガシーなシステムとの向き合い方 ~ リニューアル案件を通して

f:id:makizawa:20210217111217j:plain

本記事はぐるなびで、飲食店掲載ページ(以下、店舗ページ)の開発を担当している店舗チームがお送りします。



はじめに

ぐるなびはWebメディア業界の中では老舗で、技術的負債やレガシーな運用・開発フローが多数残っています。
今回はそんな中、ぐるなびのエンジニアがそういった技術的負債にどう立ち向かっているのかを紹介します。

納品スタイルな開発体制

ぐるなびの開発体制は工程ごとに分業されています。
企画が要件を決めて、その要件をもとにデザインチームがデザインをします。
そのデザインをもとにフロントチームがHTMLやCSS、JSなどの静的資源を作成し、作成された静的資源をもとにバックエンドチームが動きを付けていきます。(これを以降では「納品スタイル」と呼びます。)

そんな納品スタイルがゆえにチーム間で実装に関する余計なコミュニケーションが発生したり、無駄なHTML取り込みなどが発生していました。
ぐるなび開発体制
ぐるなび開発体制

店舗ページのリニューアル案件

こうした開発スタイル(フロー)に課題を感じながらも何もできずにいたのですが、2020年9月にリリースした店舗ページのデザインリニューアルをきっかけに、これまでできていなかったいくつかの課題に取り組んでみました。
デザインチーム、フロントチーム、バックエンドチームの視点でそれぞれを紹介したいと思います。

目次

デザイン

デザインにおける今までの課題

ユーザーから頂戴していたご意見や、リニューアル前のデザインでユーザーテストを実施した結果、下記の課題が上がっていました。
  • 写真が小さい
  • 文字が小さい
  • 情報量が多い
  • 1ページに使用している色数が多く、ゴチャゴチャした印象
  • 表示項目が多く仕様も複雑で、改修する都度時間を要している
    • これらの原因は以下と分析しています。
    1. 2000年代初頭のスマートフォン版立ち上げ後、デザインベースを変えていない
      • 当時の小さめの端末サイズをベースに文字・写真サイズを策定していた。
    2. ユーザーテストを実施していなかった
      • ユーザの声を反映しないまま、項目追加を繰り返していた。
    3. デザインのガイドラインは存在していたが、各パーツの利用ルールが明確に決まっていなかった
長い間、弊社内でも課題は認識しておりましたが、大規模な改修となるためなかなか動き出せない状態でした。 続きは以下のぐるなびnote公式アカウントに掲載しているためぜひご覧ください!

スマートフォン版ページ、リニューアルしました

フロントエンド

リニューアルを前に

フロントエンドの開発環境としてはレガシーな環境下での運用を行なっていました。 タスクランナー(grunt) + テンプレートエンジン(handlebars)で静的htmlや各種アセットを生成して開発へ納品。
フロントエンドの環境図
フロントエンドの環境図
SPAやSSRが主流となって久しいweb業界において「フロントエンドから納品される静的htmlをphpに組み込む」 というのはあまりにも前時代的であると同時に、開発コスト面においてもとてつもないロスを生み出していました。

また、LAMP環境下で動的なコンテンツの実装を行うため、テスト工程や確認作業などにも同様のコストがかかっており 会社やユーザーが考える新サービスの提供や進化に開発が追いにつくには、マンパワーによる人海戦術しかありませんでした。

フロントエンドとしてリニューアルの話が持ち上がった時点でコンテンツの作業者は全員同じ思いでした・・・。
「これで納品スタイルを辞められる」
そしてvue.jsなどのフレームワークやライブラリであるReactを利用し、効率的な機能開発と運用を目指していく事を目的としてリニューアルに向けて動き出したのです。

モダン化への大きな障壁

・引き継がれてきた環境!
こうして伝統的に納品スタイルで開発を行ってきた弊社がリニューアルに向けて動き出すわけですが、その前にどういった開発環境だったのかも説明しておきたいと思います。
静的HTMLとアセットを作るという工程の特性から我らがフロントエンドでは一時期テンプレートエンジンが大流行しました。


handlebars + metalsmithから始まり、タスクランナーであるgruntの導入。 その後、gulpへと移行してejsの利用。 最終的にはwebpack + pugloader + pugが弊社のスタンダードとなりました。


弊社の開発スタイル(静的ファイル納品)を考えると、テンプレートエンジンを活用していくのは自然の流れだったと思います。

生のHTMLやCSS、バニラで開発していた頃に比べると格段に効率は上がりました。
しかし開発運用を進めている内にとある問題が顕在化していくことになります。
そしてそれに気づいた時には既に地獄に片足を突っ込んでいました。
「アーキテクチャ設計をしていない。」
プロジェクト毎には決まっていてもフロントエンドとしてのレギュレーションの統一は一部に過ぎず、開発工数が満足に取れない中でそれらの大部分は実装者に委ねられていました。
もちろんsass等のプリプロセッサは使っていたのでCSSアーキテクチャの導入はしていましたが

「この案件はBEM」

「こっちの案件はSMACSS」

「そっちはFLOCSS」

という有様でした。 もちろんそのような状況では環境の把握に時間がかかるので、レビューもリファクタも遅々として進まず・・・。
数年後には完全に属人化してしまい、退職引継ぎなど管理者の変更の流れの中で誰も仕様やコードについて把握している人がいなくなるということになってしまいました。

・静的ファイルの納品がやめられない!
そのような状態の中でリニューアルに突入していくことになりましたが、早くも最初の壁にぶつかることになります。
一番の課題である納品をやめることができない事がわかります。
  • 全体リニューアルではなく一部改修だったため、システムが絡み合う部分を完全に切り離すことが出来なかった
  • 管理者も存在せず、影響範囲も不明なファイル郡があまりにも多すぎた
とりわけ難しかったのが二番目でした。
リニューアルは部分的であったため、スコープ外のページに対して及ぼす影響が調べきれませんでした。

・行き着いたのはJSX
結果的に多くの制約を抱えた中でリニューアルを迎えました。
全ての刷新が難しい事が分かったので、将来を見据えた実装を行う事で一致しました。
そして採用に至ったのがJSXです。
まずhandlebarsでの運用・開発でのボトルネックの解消を目指しました。


  • include partialが辛い問題
<div class="hoge">
    #{{ parcial名 }}
</div>


handlebarsでpartialを使う際に上記のように#{{ parcial名 }}としますが、どこにこのpartialがあるのか一見してわからないため、長年の運用開発の中で複雑に膨れ上がった環境内からpartialを探すのに時間がかかっていました。
これはJSXの導入によって「関数ジャンプを使ってコードを追える」ようになりました。

  • テンプレートエンジン特有の記法を覚える必要がない
JSXはjavascriptの拡張構文となるので、javascriptとhtmlの知識があればすんなりと入れます。
それに比べてテンプレートエンジンは特有の記法を覚える必要があるので、初めて観た人はぎょっとする事もあります。
特にpugなどはインデントでネスト表現をするため慣れない人は苦労するパターンもあったりします。
そもそも納品スタイル自体が特殊なので、採用してる開発現場は少ないでしょうね・・・。
  • 将来的にはReactに移行したい
JSXであればReactへの移行がとてもスムーズにできます。
今回は移行が叶わなかったため初回導入(htmlの生成部分にのみReactを使用)とまでは行きませんでしたが、そう遠くない未来に移行を考えています。

バックエンド

過去に積み上げられて手を付けられずにいた課題の山

バックエンドでは、これまで何度も改修に改修を重ねてきた結果
ソースコードの整備ができていない状況が続いていました。
そこで今回はテンプレートファイルを中心に、課題解決に取り組みを行うことになりました。
既存のテンプレートファイルには、以下のような問題がありました。
  • ソースコードをぱっと見て、どのような機能があるかイメージがつかめない
  • 1ファイル3000行以上ある長いコードを読んで改修箇所を探すのが大変
  • 似たような処理が各所で実装されており、共通化されていない
  • テンプレートにロジックが書かれていて可読性が低い
これらを解決するために、ディレクトリ構成の見直しを行うことになりました。

テンプレートのディレクトリ構成見直し

テンプレートファイルについて、ディレクトリ構成のルールは特に決まっておらず、
実装者の好きなように構成されていました。 チーム内で話し合った結果、以下のような構成を基本とすることが決まりました。
スマートフォン版ページ/
 L pege名/
  L index.tpl
  L meta.tpl
  L script.tpl
  L components/
   L parts/
components配下の例
  L components/
   L navigation.tpl
   L section.tpl
   L pager.tpl
   L parts/
    L tag.tpl

テンプレートやディレクトリの役割

index.tpl
対象ページのindexとなるページ。目次的な役割として使用するため、
基本はincludeでcomponentsを読み込むようにする。
meta.tpl
対象ページのメタ情報を記載する。
script.tpl
ページを大枠で区切っている情報をテンプレートにまとめて格納する。
components
ページを大枠で区切っている情報をテンプレートにまとめて格納する。
parts
コンポーネントさらにを細かく分割している情報を配置する。

ディレクトリ構成の見直しによる効果

挙げていた課題に対して、結果として以下のような効果がありました。

ソースコードをぱっと見て、どのような機能があるかイメージがつかめない

index.tplが目次の役割を果たすため、そのページ内に何があるか把握しやすくなり保守性が高くなりました。

1ファイル3000行以上ある長いコードを読んで改修箇所を探すのが大変

index.tplにincludeされているテンプレートを追って行くだけで、改修箇所にたどり着けるようになりました。 componentsやpartsのファイル名もわかりやすく命名したことで、すぐに該当箇所が判断できます。

似たような処理が各所で実装されており、共通化されていない

partsとして細かい範囲を切り出すことで機能が独立し、共通機能として複数ページで共有できるようになりました。

テンプレートにロジックが書かれていて可読性が低い

テンプレートにどうしても必要なロジックについても、1ファイルあたりの行数が減ったおかげで読みやすくなりました。 ルールを決めたことで、新たにチームに加わった人でも実装に取り掛かりやすい構成にできたのではないかと思っています。

さいごに

もともとはリニューアル案件を記事にするつもりでしたが、路線変更して改善系を中心に紹介しました。
いきなり大きな改善をすることは難しいため、こうした小さな改善を繰り返すことで、どんどんモダンな技術を取り入れていけたらなと思ってます!またこのブログで進捗状況を紹介していく予定ですのでお楽しみを!
今回記事を公開するにあたり以下の方々にご協力をいただきました。大変感謝です。
  • UXデザイナー
    • しばた
  • フロントチーム
    • まっきー
    • 池田マン
  • バックエンドチーム
    • しおりん
    • たっきー
まっきー
店舗フロントエンド開発TechLead。ぐるなび8年目。
映画っ子。飲みながら映画の話できる人を求めて社内を徘徊中。
家に小型シアター作りたいなぁ