こんにちは、ウォンテッドリーの Visit Growth Squad というプロダクトグロースチームでソフトウェアエンジニアをしている川辺 (@sh1ntaro_dev) です。
この記事は Wantedly Advent Calendar 2023 の15日目の投稿です。前日は Visit Growth Squad 原さんによる「失敗から学んで大きくなる」という記事でした。
長年にわたり、ウォンテッドリーではWebフロントエンドの開発と運用が続けられてきました。技術の進化と共にこの長い道のりを歩んできて、振り返れば様々な形で技術的負債が積み重なっていたり、設計や実装がさまざまな複雑性を持つようになりました。
この記事ではフロントエンド開発で感じた開発の難しさ等について言及していますが、過去にこのプロジェクトに関わってきたエンジニアに対し責任を問う意図は全くありません。むしろプロダクトの成長と共に彼らはその時点で最善と考えられる選択をし続け、多大な貢献をしてきました。それだけでなく、このような複雑なアーキテクチャの開発環境でも私のような新入社員がすぐに開発を始められたは彼らの行いによるものだと認識しています。
しかし、時代とともに変わる技術の潮流により、一度は最適だった方法が次第に劣化し、新たな課題や難しさを生んだり、エンジニア自身の新たな学びやアイデアの挑戦により生まれる複雑性など、開発において避けては通れないいくつかの壁が存在します。
(個人的にいつも参考にしている 良いコードとは何か というスライドには技術的負債の種類について記載があります。このうち「変化による負債」と「学びによる負債」が上記で説明した物にあたると感じています。)
この記事では、ウォンテッドリーのフロントエンド開発において内在しているいくつかの主要な課題や複雑性の高いポイントについて、入社半年を超えたいちフロントエンドエンジニアの視点から、なるべく完結に透明性高く棚卸ししつつ、それについて取り組むべき行動や理想像についても交えながらご紹介したいと思います。
※ 文中、用語を以下のように使い分けています。
ウォンテッドリー: 会社や組織としてのウォンテッドリーを表します。
Wantedly: プロダクトとしての Wantedly を表します。
フロントエンドの実装パターンが多い
初っ端から多少バックエンドにも関わる話をしますが、これはウォンテッドリーにWebフロントエンドを実装するエンジニアとしてJOINして、最初の段階で必ずキャッチアップしなくてはならないものだと思います。
非常に大事な話なので、外部公開もしているハンドブックの目立つところに書かれていたり
https://docs.wantedly.dev/fields/apps/frontend-architecture
> これまでの技術スタックは大きく4世代存在し、v1〜v4 と呼ばれています。
何度か外部への登壇の際に説明があったりしました。
https://speakerdeck.com/chloe463/wantedlynohurontoendoling-yu-noqu-rizu-mitoke-ti?slide=11
> Wantedly のフロントエンドには4つの地層がある
またウォンテッドリーにおける、フロントエンドや技術の話に閉じないチームとアーキテクチャの変遷の話についてはこちらのスライドも参考になると思います。
現状と課題感
- これまでのチームとアーキテクチャの進化と同時に、古い実装が取り残されている部分がある
- このフロントエンドアーキテクチャには4種類の層が存在する
- v1: Haml / SCSS / AngularJS & jQuery & Backbone.js
- v2: TypeScript + React + Redux + redux-thunk / styled-components / webpack
- v3: TypeScript + React + Redux + redux-thunk / styled-components / webpack / SSR
- v4: TypeScript + React(Next.js) + GraphQL / styled-components
- 開発を行う対象のページ、機能がどのバージョンで作られているか把握しそれぞれのアプローチ別の技術スタックを習得する必要がある
いいと思っている点
- 一つのアーキテクチャから新しいアーキテクチャに移行し切る前に、さらに新たなアーキテクチャへ挑戦をするという意思決定
- ドキュメントにそれぞれの歴史について詳しい意思決定の記録が残されていて、先人のメンバーもそれをしっかり理解していること
どうしたらより良いか
- 徐々に古いものから新しいアーキテクチャに移行していくこと
- この際はリグレッションにとても慎重になること(UIの変化、ロギング、パフォーマンス ...etc)
- 今後バージョンごとの当時の意思決定や技術選定の理由、ADR等を明確に記録しておくこと
スキーマ駆動開発の実態
(一つ前のトピック同様バックエンド側の話も含みます。)
Wantedly の開発にはスキーマ駆動での開発スタイルを採用しています。
一般的に想起される「スキーマ駆動開発」とは OpenAPI や GraphQL などを用いてそれぞれフロントエンドサーバーとバックエンドサーバー間における、データモデルやAPIの型の互換性を担保するような開発体験を指すことが多いと思います。
Wantedly におけるスキーマ駆動においては、一つのスキーマが関連するものとして多くのバックエンドマイクロサービスや、Webアプリケーションフロントエンド、モバイル実装など一つのスキーマから関連する領域がとても多いです。
現状と課題感
- 全体で見て Single Source of Truth となる protobuf スキーマを修正してから、フロントエンド実装が開始できるまでの手順が多い
- 覚えるべきアーキテクチャとコード自動生成の手順が多い
いいと思っている点
- 多くのマイクロサービスや、フロントエンドリポジトリがある中でも、結果的にスキーマを Single Source にできている点
- HTTP / JSON, gRPC, GraphQL と様々な通信方法が混在するアーキテクチャではあるが、それらの適用箇所を適切に設計されている点
- これらの設計と実装についてわかりやすいドキュメントが用意されていた
どうしたらより良いか
- Node.js でできた API Gateway 層を一本化する (後述するGraphQLの通信パターンの話に紐づきます。)
- スキーマ設計からコード実装の一連の流れをドキュメント化し図を用意しつつ開発メンバーにオンボーディングする
フロントエンドのテストアプローチの多さ
Wantedly 全体のフロントエンドのテストを俯瞰した時、多くのテストアプローチが存在しているなと感じました。 ただしこれは実装パターンを改善したことにより採用する技術が増え、当然それに推奨されるテストライブラリも増えるなど仕方のない部分もあったり、冒頭で触れた技術的負債の「学びによる負債」に当たるものであったりと、アプローチが多いことそれ自体は大きな課題ではありません。
ただし新規参入者にとっての認知負荷となり、多少なりとも日々の開発の足枷になることは一定あると感じています。
現状と課題感
大きく分けて以下のようなテストアプローチが存在しています。
( Ruby on Rails となっている部分はアーキテクチャ上フロントエンドを Rails から切り離せていない部分なので、アーキテクチャ刷新に伴い自然となくなる部分ではあるかと思います)
- E2E Test
- Capybara (Ruby on Rails)
- Cypress
- Playwright
- Visual Regression Test
- Percy (Ruby on Rails)
- Chromatic
- Integration Test
- Jest & React Testing Library
- Storybook & React Testing Library (composeStories)
- Storybook Interaction test (play function)
- play function ごと composeStories する方法
- play function の中に @storybook/jest を使って test を書く方法
- Unit Test
- Jestによる custome hooks や純粋関数のテスト
- その他
- react-test-renderer を用いた snapshot テスト
また、mock data を都度用意したり、msw で graphql 通信を mock したりと言った違いがあったり、Redux に依存しているモジュールのテストが難しいなど、細かい部分の懸念点も存在しています。
いいと思っている点
- リグレッションに気付きやすい設計になっている、特にChromaticのVRTがあるおかげで積極的にライブラリアップデートやリファクタリングを行える。
- 頻繁に壊れるE2Eも、ビジネスインパクトの大きい機能の大事な部分だけに書くよう留められている
- Testing Trophy の比率にほぼ似たような配分でテストが書けている
どうしたらより良いか
- まずは後述する複数のフロントエンドアーキテクチャを徐々に統合していくこと
- 上にあげたフロントエンドのテスト手法について体系的にドキュメント化する
- テスト自体の設計や配分はかなり理想に近いと個人的には感じました、ただそれぞれの層における表現方法に複雑さがあるためこれを層ごとに統一していけると開発者体験も上がるのではないかなと感じます。
デザインシステムのバージョンが多い
ウォンテッドリーでは誰でも効率よく、ユーザーに一貫したUI/UXを提供できるようにするため、2021年から「Wantedly Design System」を公開しています。
デザインシステムの中身については以下の記事を参照ください。
Wantedly Design System : プロダクト開発を加速させるための一貫性と効率性
ノンデザイナーズ・Wantedly デザインシステム完全理解ペーパー
ここにもWebフロントエンドで実現する際に複雑性が介在しています。
Webフロントエンドのアーキテクチャと同様に、デザインシステムのWeb実装にも現時点で3種類のバージョンが存在しています。
この課題に対してより近い話が、最近の JSConf JPにて弊社メンバーが発表を行ったのでそちらも参考にしてみてください。
現状と課題感
- 簡単に要約すると以下の三つのバージョンが存在する(バージョンと言ってもパッケージとしては別々の実装)
- v1: 2018年に始めた一番最初のバージョンで、見た目はデザインと一致しているものの、デザイナーとの細かい概念の認識齟齬が生じていた。
- v2: v1の失敗をもとにデザイナーと概念の認識を整理し React に特化した実装を実現。
- v3: 現在推奨しているバージョン。v2で生じていた外部ライブラリへの強い依存や開発体験の悪さを改善している。内部で Tailwind を使うようになった。
良いと思っている点
- デザインシステムを実現し、実際にプロダクトのUI/UXの品質だったり開発者体験に大きく影響を与えていること
- 「Wantedly って UI 綺麗ですよね!」と言われることもあるが、その要因はこのデザインシステムも大きく関連していると感じる
- 実装したデザインシステムを開発に投入し、そこで感じた課題を議論し素早いサイクルで次のアプローチへと繋げているところ
どうしたらより良いか
- 古いバージョンのデザインシステムで実装されている箇所を徐々に新しくリファクタリングしていく
- フロントエンド横断チームのメンバーがメインの開発業務の合間に徐々に移行を進めています。
- 新規参入者には、この複数バージョンがある事実と歴史を詳細にオンボーディングすること
- v3の実装についても、まだたくさんの改善点が内在している状況なのでデザイナーやモバイルエンジニアとも連携を取りつつ成長を続けていきたい
GraphQL の通信パターンが2種類ある
ウォンテッドリーではアプリケーションレイヤーとシステムレイヤーの間の通信にGraphQLを積極的に採用しています。GraphQLの話も含む基本的なアーキテクチャの話はWantedly Engineering Handbookの以下の章にまとめられています。
つまりウォンテッドリーにおけるGraphQLはドメイン知識を有するバックエンドサーバーとしてではなく、後ろ側にあるマイクロサービスとの仲介役としての Gateway サーバーとして機能しています。
この Gateway サーバーが2種類存在しており、これもフロントエンド開発における大きなポイントとなりました。なぜ2種類存在しているのかといった GraphQL Server アーキテクチャの歴史や背景については以下のスライドで詳しく説明されています。
技術を的に当てる技術について - GraphQL を入れ直した話
現状と課題感
- 2種類の Gateway 的役割を担う GraphQL Server が存在している
- Webフロントエンドからの疎通はページやコンポーネントによってその二つの両方に向いている
- 2番目に開発した Server の方に徐々に実装を移していきたい
良いと思っている点
- アーキテクチャやデザインシステムの話と同じですが、やはり一度開発したものを運用して感じた懸念について議論を行い、その懸念を解消する新たなアプローチをスピード感もって導入する意思決定が良いなと感じた。
どうしたらより良いか
- 現在この GraphQL Server の開発の責務はバックエンドエンジニアにあるが、フロントエンドエンジニアもその役割を超えて、この GraphQL Server の移行について関わっていくべきだと感じた。
- 二つの実装のそれぞれの背景や役割、既存実装の向き先についてチーム全体が理解すること
秩序のないディレクトリ構成
ここでようやく説明するのですが、ウォンテッドリーのフロントエンドには React と Next.js をメインに採用しています。 React におけるディレクトリ構成の話は界隈全体でも度々頻繁にあちこちで議論されるトピックだと思います。
Wantedlyを開発する上でのフロントエンド実装はざっくりと以下のように分けられます。
1. Ruby on Rails 上で view にあたる部分を haml で実装
2. Ruby on Rails 上で view に当たる部分を React で実装
3. Rails から切り離された Next.js 上での React 実装
ここでは3の話をメインに取り扱います。
現状と課題感
- Next.js 実装のリポジトリは2つ(ユーザー画面と管理画面)存在するが、それぞれでディレクトリ構成に秩序がない状態
- それぞれの内部でも、ディレクトリ構成の古い思想と新しい思想が混在している
- 新しい思想として、React実装のベストプラクティスを集めた bulletproof-react などでも採用されている features ベースでのディレクトリ構成を進めている
- しかし、この features/foo の中の構造に秩序が保たれていなかったりもしており、featuresごとに概念を分けられてはいるものの、その中身は無法地帯、なんてこともある
良いと思っている点
- ガチガチにルールを定めることは、フロントエンド専門ではない複数のエンジニアが開発を行うウォンテッドリーにおいてあえて採用しなかったとも思える
どうしたらより良いか
- こういった課題は新規参入者ほど、声を上げた方が良いと思っているので大きな構造を変えるのではなく、小さなところから改善を提案していくマインドが必要。
- また、割れ窓を放置しないこと、少しでも適当になっている部分があると感じたら声を上げたりPull Requestを投げてみる。
さいごに
いかがでしたでしょうか、10年以上続くプロダクトには、たとえ適切に正しいメンテナンスを行なってきたとしてもこのような複雑性は至る所に存在しています。
これらのトピックは、確かに個人的にも開発を行う上で障壁となり得るものでしたが、その歴史や背景を理解した上で改めて俯瞰すると、どれもチームとプロダクトが成長していく過程で避けては通れない成長痛であることがわかります。
進化の過程で生じた負債や複雑性の高いポイントについては、新入社員などチーム外の視点も持っている人こそ、積極的に開発環境や文化に対してフィードバックを行うべきであると考えています。
ウォンテッドリーでは Developer Experience の向上を目的とした専門チームがいたり、社内ドキュメンテーションが充実していたり、有識者から適切に知見を伝播させ新規参入者の悩みを解消し全員が効率よく開発に臨めるような仕組みが十分整っているなと感じます。
日々のプロダクトグロース業務を行う上で感じたフロントエンド横軸のこれらのトピックについて、私も徐々に課題解決に向けて積極的に Issue に手を挙げたりアイデアを提出して Wantedly のWebフロントエンドをより良いものにしていけるといいなと日々意識しています。
最後に、これらのトピックに興味がある方、我々と一緒にWantedlyのプロダクトとフロントエンド基盤を成長させていきたい方をいつでも募集していますので、気になる方はぜひ一度お話ししましょう!
カジュアル面談のご希望お待ちしています。