こんにちは!フロントエンドエンジニアの小澤です。画像のにっこり笑ってる人です。
この記事は「エディトルブログキャンペーン」1日目の記事です。本記事ではエディトル開発チームのフロントエンド技術について取り組んできたことを紹介します。
エディトルブログキャンペーン
エディトルブログキャンペーンは、ウィルゲートで開発中のサービス「エディトル」について各チームメンバーからの視点で取り組みを紹介していくキャンペーンです。
本日2020年2月10日(月)から2月14日にかけて1日1記事を投稿していきます。
投稿する内容としては、
1日目:フロントエンド
2日目:バックエンド
3日目:フロントエンド、バックエンド、事業部との調整
4日目:マネージャーからの視点
5日目:インターン生からの視点
上記の日程で記事を投稿していきます。 開発に着手してから1年弱経ちましたが、それまでやってきたことや学びなどを紹介していきます。
エディトルとは
私が開発に携わっているエディトルはコンテンツ制作に特化したオンラインの編集チームを構築するサービスです。 2018年から開発が始まった新しいサービスです。
エディトルのシステムは大きく分けると編集者などの情報や支払情報を持つバックエンドと、バックエンドからデータを取得し表示するフロントエンドの2つに分けられます。 この記事では主にフロントエンド技術について説明していきます。
エディトルのフロントエンド事情
エディトルはSPAのアプリケーションです。React×TypeScriptで構築されており、ウィルゲートのプロダクトでは比較的新しい技術を導入しています。 コンポーネントベースで開発することができますし、StorybookやJestを使えばデザインや挙動、テストの確認なども簡単にできます。
主要ライブラリ
エディトルで使用している主要ライブラリを紹介します。
- React
- Redux
- TypeScript
- styled-components
- Storybook
- TSLint
- Jest
- Prettier
- webpack
Reactを始めとした主要ライブラリは、基本的にはLatest releaseまで対応しており、常に最新の環境を適用するようにしています。
破壊的な変更を伴うメジャーバージョンアップデートはまだしも、後方互換が保証されているマイナー、パッチアップデートなら積極的にアップデートするべきだと思います。
また、最新のアップデートを取り込むことでいつでも新しい技術を導入、検証できるような環境を整えています。
このあたりの話はこちらで詳しくしていますので、ぜひご覧ください。
TSLintは非推奨になりましたね。エディトルでは2020年4月からESLintに以降する予定です。
技術選定の背景
なぜ上記のような技術を選定したのかについて説明します。
SPA
SPAとはSingle Page Applicationの略で、単一のwebページでコンテンツ切り替えを行うことでページ遷移の必要がなく、ブラウザの挙動に縛られないUIの実現やパフォーマンスの向上が可能になります。 有名なサービスだとFacebookなどが例として挙げられます。
当初の機能要件としてプロジェクトの状態を見やすく、操作しやすいものにするためにカンバンボードのような機能や、ユーザ間でやり取りをするチャット機能を実装する必要があったのでSPAの導入に至りました。
ちなみにカンバンボードとはプロジェクトなどの進捗を見える化するツールの総称です。有名なサービスだとJIRAなどが挙げられます。
React
SPAを実現するためのフレームワーク、ライブラリとして代表的なものがいくつかあると思います。例えばGoogle社がOSSとして公開しているAngular、Evan You氏が作者であるVue、そしてエディトルに採用されたFacebook社がOSSとして公開しているReactなどが例として挙げられます。
React – ユーザインターフェース構築のための JavaScript ライブラリ
この中でなぜReactなのかというと
- コミュニティが活発である
- TypeScriptで書くことを公式が推奨している
- 小さく始められる
が主に理由として挙げられます。 AngularはReact、Vueと比較すると小さく始めることが難しいです。Vueは選定当時はTypeScriptとの相性が良いとは言えず、VueプロジェクトでTypeScriptを使うにはひと工夫が必要でした。 また、新規技術を取り入れることで組織としても技術に秀でた会社にしていきたい、といった狙いもありました。
以上のことから、Reactを導入することになりました。
コンポーネント粒度
エディトルでは以下のようなディレクトリ構成で開発しています。
. ├── app.tsx ├── components │ ├── App.tsx │ ├── atoms │ │ ├── ... │ ├── layout │ │ ├── ... │ ├── molecules │ │ ├── ... │ ├── organisms │ │ ├── ... │ ├── pages │ │ ├── ...
基本的にはAtomic Designをベースにコンポーネントの粒度を分けていますが、独自に拡張している部分もあります。 Atomic DesigntとはUIパーツ・コンポーネント単位で定義していくUIデザイン手法です。Reactはコンポーネントベースで開発できるので、Atomic Designと相性がいいです。
Atoms
最小限単位のコンポーネントで、IconやButtonなどが該当します。 「ボタン」「テキストの表示」などの単一の機能を提供します。
基本的にstateは持たず、親コンポーネントから渡されたpropsを元にHTMLを返却します。ドメインは持ちません。
Layout (独自定義)
レイアウトを組むためのコンポーネントです。 Atomic DesignでいうAtomsくらいの粒度です。 各ページをラップするコンポーネントで未ログイン時、ログイン時などにそれぞれのレイアウトを適用しています。ドメインは持ちません。
Molecules
複数のAtomsから構成され、複数の機能を提供します。
再利用前提のコンポーネントで、List, Modal, User thumbnailなどが該当します。 複数の機能を持つコンポーネントで複数のAtomsを組み合わせて作られます。
UNIX哲学の「do one thing and do it well(小さな一つのことをうまくやる)」に基づいています。 Moleculesはユーザへ何かのタスクを完了させることができます。
基本的にstateは持たず、親コンポーネントから渡されたpropsを元にHTMLを返却します。ドメインは持ちません。
Organisms
この階層のコンポーネントでは、データ取得処理を記述したり、Redux Stateとconnectし、状態を保持することができます。 ここで取得した状態はpropsとして、Molecules,Atoms のコンポーネントにも引き継がれます。
複数ページに渡って共通化したいコンポーネントを配置します。 例えばButtonやCheckboxなどの一般的な汎用コンポーネントはこちらには配置しません。 Pages寄りの、共通化したいコンポーネントを配置します。ドメインを持ちます。
Templates
2ペイン構造などページの根幹となるレイアウトを提供します。 ヘッダーやフッター、サイドバーなどはレイアウトともにTemplatesで配置します。ドメインを持つ場合があります。
Pages
ページのコンポーネントです。 ページ独自のコンポーネントはこの中に子コンポーネントに切りつつ配置します。
基本的には渡されたthis.props.childrenをそのまま表示します。 各ルーティング毎に1つずつ存在します。Redux Stateとconnectし、状態を保持することができます。
このように、コンポーネントを決められた粒度ごとに分けることでそれぞれのコンポーネントの役割が定まり、見通しが良くなります。
テスト事情
エディトルではJestを使ってコンポーネントのテストを行っています。
このあたりの話はこちらで詳しくしていますので、ぜひご覧ください。
今後はStoryShotsを使ってStorybookと連携してコストを最小限に抑えつつ品質を向上させていけたらなと思います。
今後の展望
エディトルは今後、さらにリアルタイム性が求められるようなSPAアプリケーションになっていきます。そのため、WebSocketやService Workerなどの導入を検討している段階です。
フロントエンド技術の流れはとても早いので常に最新の技術を取り入れ、プロダクトを技術的なアプローチでも成長させていけたらなと思います。 こういった取り組みがナレッジとして自社に還元され「フロントエンド技術が優れている会社」になっていくと思います。
最後に
明日はエディトルのバックエンドを担当しているバックエンドエンジニア三島さんの記事で「LaravelでレイヤードアーキテクチャとCQRSの導入事例」です。
乞うご期待です!