1
/
5

Wantedly におけるソフトウェア・アーキテクチャの取り組み

こんにちは、Wantedly でアーキテクトやっている竹野(@Altech)です。この記事では、2020年の暮れから始めた Wantedly 全体のソフトウェア・アーキテクチャに関する取り組みを紹介したいと思います。

なおソフトウェア・アーキテクチャというトピックについては、最近はまとまった本が出版されるなど、以前よりも広く関心が持たれている印象があります。一方で、事業会社においてそれをどのようにアプライするかという段においては、おそらく様々な解があり特に立ち上げのフェーズにおいてそれが難しさにつながるのではないかと思っています。

そこで本記事では、Wantedly においてそれを定義して立ち上げるところから、それが全体のエンジニアリング戦略に埋め込まれるまでを通しで振り返りたいと思います。

経緯

本題に入る前に、アーキテクチャに関する取り組みが始まった組織的な経緯を簡単にお話しします。

Wantedly の開発組織は、2017年ごろから Spotify モデルと呼ばれる組織体制を漸進的に導入していました。知らない方のために簡単に触れておくと、Squad と呼ばれる職能混合型の数人のチームでプロダクト開発を進めながら、Chapter と呼ばれる同一の技術領域を持った横串のチームにも所属するマトリクス組織です。

大まかにこういった体制を敷くことで各技術領域での技術導入・推進は行われていたのですが、その一方で、技術的・アーキテクチャ的な局所最適が後々になって発覚するといったことが目立つようになってきました。

そこで Squad / Chapter という基本構造は維持しつつも、2020年に開発組織全体の会議体を再設計します。そこでは、Cross Chapter Sync Up という月一の会議を用意し、異なる技術領域間での情報共有と意思決定を行うようにしました(図の右上の領域)。

それまで技術領域間の情報共有は組織立った形では行われていなかったため、こういった場を設けることで、最低限、問題の検知はできるだろうと予想していました。

実際にやってみると、個別に話し合うことで結論が出せるトピックもありつつ、少し長期的な目線であったり、大域的な観点で結論を出す必要があるトピックも複数出てきました。

こういった経験から、技術・アーキテクチャの観点でイニシアチブを取る必要性が共有されたため、アーキテクチャについて取り組む分科会を設置しようという流れになりました。Wantedly における全体的なアーキテクチャに関する組織的な取り組みは、ここから始まっていきます。

取り組んだ体制

体制についても少し触れておきます。大きく3つのフェーズがあり、段階的に投下するリソースを増やしていきました。

最初のフェーズは Arch Chapter という分科会的な取り組みです。各技術領域のリードを選出し、週に1-2時間のペースで話し合いました。ここでは、「アーキテクチャ」という一見して曖昧な観点を取り組むべき問題領域として確立することを行っています。

次のフェーズでは「アーキテクト」というポジションの設置が行われました。これは、アーキテクチャに関する取り組みに継続性が必要だと判断されたためです。

最後のフェーズでは Arch Squad という専任チームの設置が行われました。それまで兼任だったアーキテクトを専任化すると同時に、戦略的に重要なソフトウェア基盤の構築や検証を集中的に行うために、アーキテクチャに強みのあるソフトウェアエンジニアを配置しました。

また、これら全てのステップで、関連する技術領域・プロダクト領域とのコラボレーションが必要でした。

取り組みの流れ

実際に取り組んだ流れは大まかに次のようになります。

  1. ミッションとそこに対するアプローチの決定
  2. ドメインについての観察
  3. 技術についての観察
  4. 最初の仮説の策定 ... Wantedly Architecture Overview
  5. インターフェイス定義言語の分断解消の施策 ... Protocol Buffers と GraphQL
  6. アプリのインフラを整える施策 ... デザインシステムライブラリ
  7. 大規模プロジェクトへの投入による有効性の検証
  8. アプリとシステムの分離を決定

図にすると次のようになります。

本記事の構成もこの流れで進めていきます。

特にソフトウェア・アーキテクチャというものは正解があるものではないため、どういった文脈のもとにどのような概念セットを用いて対応したのか、といったことを共有することが必要だと考えています。そこで、本記事でもこれらを明示的に取り扱っていきます。

1. ミッションとそこに対するアプローチ方法を決める

アーキテクトの役割を定義することはできない?

さて、アーキテクチャについて取り組む最初の体制として、Arch Chapter(以下 Arch と呼称)という分科会が設定されたと書きました。とはいえ、これまで社内にアーキテクチャを明示的に扱うポジションやチームは存在しなかったので、どういったことをやるべきなのかを模索・定義するところから始める必要がありました。

なお、一般的に言ってもアーキテクトがやるべきことを定義するというのは難しいようで、例えば最近出た『ソフトウェア・アーキテクチャの基礎』にも「やることはケースバイケースで多岐にわたるのでアーキテクトの役割を定義することは難しい」(意訳)みたいなことが書かれています。

とはいえ、これは何も決められないということではなく、それが組織の文脈やサービスの性質などに依存するということだと思っています。ですから、ある組織においてアーキテクトないしそのチームを設置するということは、常にそれを明らかにすることから始まります(そして多くの場合、その定義を更新し続けることまで責務として含むと思われます)。

期待したいことを集める

具体的に行われた最初のアクションとしては、まずは各所のエンジニアリーダーが集まってブレスト的に Arch に期待したいことを書き出すということがありました。以下は抜粋ですが、CTO、プロダクト開発責任者、インフラ責任者などがコメントしています。

ここから、少なくともやることが色々とありそうだ、ということは透けて見えます。

ところで、エンジニアリングに限らず言えることだと思いますが、実際のところ、こういったものを全て「要求」として捉えて一つ一つ解決していくような方法はあまり得策ではありません。

代わりに、これはそれぞれの立場から見た断片的な期待(困り)として捉えます。例えば、CTOの立場と、プロダクト開発の責任者の立場では、見ているスパンやリスクに対する捉え方も違うでしょう。あるいは技術的なバックグラウンドによっても見えている景色が違います。

そこで、これらの困りをその立場から来る認知とセットで見た上で、本当に欲しいものは何なのか、ということに少しズラして解釈します。

例えば、上に出ている「バックエンドだけじゃなくて、フロントエンドやモバイルも含めたアーキテクチャに責任を持てるグループを作りたい。例えば、GraphQLを全体で採用すべきかの議論に決着を付けられる」は、「技術的に広い範囲に影響する難しい議論のイニシアチブを取ること」が本当に欲しいものかもしれません。「理想的な姿が曖昧なので、そこから議論していくことが大変」は、「共通の言語や枠組み」がないことでそもそも議論ができないという話かもしれません。

このように、具体的な困りを本当に欲しいものに変換しておきます。

問題領域を見出すことの必要性

ところで、チームのミッションに落とし込む上では、まとめて解くことに意味のある領域が必要だと考えています。そういった領域が見出されれば、単に一つ一つ言われたことをこなすよりも良い仕事ができ、ポジションやチームとして存在している意味が生まれるからです。

もう少し具体的に言うと、相互に絡み合っていたりして、一緒に解くことでうまく解けたり、考えることを省略できたり、相乗効果を出せたりする、そういうまとまりを発見することです。

これの必要性は、逆の状態を考えてみると分かりやすいかもしれません。たとえば、相互に絡み合っているにも関わらず、その関心を複数のチームのミッションに分配した状態を考えます。この状態では、各々がチーム外とのコミュニケーションを頻繁に必要としてしまい、そのコストが非常に高くなってしまうかもしれません。そうすると、「議論することが大変」という困りも解消されません。

ソフトウェア設計の言葉を使って表現するならば、凝集性の高い意味的なまとまり=責務を定義・発見するということを、アーキテクチャ・チームの組織設計においても実施する必要があるということです。

この制約を前提にしながら、Arch のミッションとアプローチをそれぞれ考えていきます。

ミッションのために:現状の組織状況から当たりをつける

ミッションを考える上で、ざっくり現状の組織状況を見てできていることとできていないことを確認します。この「できていないこと」を補完することがミッションを考える上で一つの当たりになります。

この意味では分科会が立ち上がった経緯からして、技術領域を横断したところに課題がありそうです。また、領域的な広がりという観点では、技術領域とは別に複数あるプロダクト領域の関係性といったところもソフトウェアにきちんと落とし込む組織構造がありませんでした。これらを総合すると、「技術的・プロダクト的に広い範囲のこと」が現状だとあまり上手くできていないところになりそうです。

次に、領域的な広がりとは別の視点で、時間的な長さについて考えます。広い範囲の課題に手をつけるということは、必然的にそのソフトウェア的な変更などが長期に渡ることは避けられないでしょう。ただ早めにフィードバックを得ることや投資効果を考えると、短期的な成果を出すことも一定考えるべきです。

つまり、技術的・プロダクト的に広い範囲が関わる、短期的な課題と長期的な課題は、一緒に解くことでうまく解けるものです。あくまで目安ですが、だいたいこの辺りに Arch の担う責務がありそうですね。

アプローチのために:二つの軸をきちんと分離する

組織状況からざっくりミッションの当たりを付けたとはいえ、広い範囲のこと(設計や技術選定、場合によってはプロジェクト化まで)を短期的なバランスを取りながら長期的にも発展させていくということは、非常に考えることが多くて難しいことです。

この難しさに立ち向かう上で、ソフトウェア・システムが存在する2つの軸をきちんと区別するということが非常に重要だと思っています。つまり、時間の要素を排除したある時点でのソフトウェア・システムについての思考と、時間軸の中でそれらのソフトウェア・システムがどのように変化するか、という思考です。

ある時点でのソフトウェア・システムについては、全体を考えることができます。これは変化を排除した視点です。それに対して、変化はソフトウェア・システム全体に丸ごと起きるわけではなく、ある部分に起きます。その変化は、相互作用を通じてソフトウェア・システムの他の部分に影響を与えますが、それによる変化もまた一定の部分について起こります。

上の図に準えると、縦の軸と横の軸(平面/範囲)があるということです。

これら2つの軸のどちらの問題を扱っているのか?を明確に区別することが基礎的な視点になると考えているため、今後これを前提にします。

たとえばアーキテクチャ図のようなものを書くときには時間の要素を排除した問題を扱いますし、開発ロードマップやリ・アーキテクチャ戦略のようなものを考えるときには時間軸の中での問題を扱います。

結論:ミッションとアプローチ

最終的に、Arch のミッションとアプローチは、次のように定義しました。

“仮説からイシューを特定してその結果をもとに仮説を更新し続けることでソフトウェア全体を正しい方向に進化させること”

分解すると、次のようになります。

  • ミッション:ソフトウェア全体を正しい方向に進化させること
  • アプローチ:仮説からイシューを特定してその結果をもとに仮説を更新し続けること

ここで「仮説」と言っているのがある時点での良いと思っている状態であり、「進化させること」が時間軸の観点になります。

説明のために図にしてみると、現実のソフトウェア・システムと並行して、理想的なソフトウェア・システムを仮説として描くことで、相互に進化させていくことを意図しています。

状態遷移として見ると、現実のソフトウェア・システムの方は実装されて動いてるものがそれです。これはコードベースという完全な定義があり、プルリクエストがコードベースにマージされる度に変化していきます。

一方、理想的なソフトウェア・システムの方は常に抽象的な定義になります。これは実際の開発のフィードバックを経てあるべきアーキテクチャの考え(仮説)がアップデートされた際などに、アーキテクチャに責任を持つ人・チームが責任を持って更新します。明らかに、これの初期状態S1が必要になりますね。

ということで、最初の仮説を構築して提示することが次の目標になっていきます。

その下調べとして、サービスが扱う「ドメイン」の観点と、ドメインとは独立に存在する「技術」の観点でそれぞれどういった課題があるのかを調査しました。

この2つの観点で考える理由は、サービス価値に寄与しながらきちんと開発の役に立つアーキテクチャを定義するためです。対象の持っている形を捉えること(ドメイン)と、ソフトウェアとして実現する方法を把握すること(技術)、その上でそれら両方を結合するアーキテクチャに落とすという順番です。次節以降、この3つに分けて見ていきます。

[コラム] 組織のボトルネックになることを避ける

さらっとソフトウェア全体を考えると書きましたが、こういう“全体性”にまつわる仕事を何も考えずにそのまま実行すると、ただのマイクロマネジメントになってしまうし、その前に組織のボトルネックになって機能不全が起きます。これを避けるために、Arch Chapter の仕事の範囲を「仮説の提示・更新とイシューの特定」までとしています。

イシューとは重要な課題という意味で使っていますが、具体的には解決することで仮説の実証に大きく近づく技術的な課題であったり、将来の進化の方向性を決める設計上の選択肢であったりします。Arch Chapter はそれを特定するところまでに留め、そのイシューを解決することは開発組織全体で行う、とすることで組織のボトルネックになることや無駄な統制を行う罠を避ける意図があります。

2. ドメインについての観察

仮説としての全体像を描くために、Wantedly が対象としている事業ドメインやそれに対して既に構築しているサービスのドメインについて、かなりざっくりとした整理と把握を行いました。

振り返ってまとめると、大きくやったことは、次の3つでした。

  1. プロダクトに乗っている機能をリストアップする、
  2. プロダクトの区分を整理する
  3. プロダクトと機能の関係性について考察する

機能のリストアップ

Wantedly というサービスはこれまでいろいろな機能を提供してきましたが、その全てを網羅した機能リストというものが存在しませんでした(個別のプロダクトに限って見れば存在することもありました)。

とにかくサービスの全体感を掴みたかったので、まずは何も考えずにWantedly として提供している全ての機能を各プロダクトマネージャーの協力をもらいながらリストアップしていきます。この際、どういうまとまりを「機能」と捉えるかは人それぞれなので、その部分は自分の方で適宜調整してきます。

少し面白い現象として、例えばモバイルアプリなどはざっくり「Visit アプリ」と書く一方で、Web で提供している機能は比較的細かく羅列されるということがありました。モバイルアプリはプラットフォームの推奨として単一の目的に基づいて提供することが良しとされるので、そういったことも関係しているのかもしれません。それはそれでUXの観点では妥当な見方なのですが、今回はドメインの大きさや分布を正確に掴みたかったため、体験ではなく機能のレベルで整理しました。

このようにしてできたのが「Wantedly プロダクト機能領域」(リンクは内部向け)というスプレッドシートです。

プロダクトの区分整理

次に、プロダクト区分の整理をしました。背景として、何をもって「プロダクト」と捉えて何をもって「機能」と捉えるかといった認識が分科会のメンバーの中でもバラバラだということがありました(これは最初から見えていたものではなく途中いろいろ話している中で見つかった課題なのですが)。

例えば、Wantedly では会社訪問アプリとして「Visitアプリ」を提供しています。このアプリには複数の機能が乗っていて、それと同じ機能はWebアプリ上にも散らばって存在しています。あるメンバーは、「Visitアプリ」に含まれる機能のセットのことを「Visit機能」と呼んでいたり、また別のメンバーはその中に含まれる「ストーリー」(注:ブログ的なものであり採用広報に使われる)のことを「プロダクト」として捉えていたり、といった具合です。

面白いことに、ちょうどその時期、サービスのブランド認知の観点で CDO(Chief Design Officer) が同じような課題感を抱えていてこういったサービスの概念的な整理を「ブランド・ネーム・システム」として行っていました。自分自身もエンジニアの観点で、そちらのディスカッションにときどき参加していたため、そこでの内容を下敷きにしました。

以下は、その整理の結果です。Webアプリは個人向けと企業向けで分かれます。一方、モバイルアプリはストアで提供されているものに直感的に対応しますが、iOSとAndroidのそれぞれのプラットフォームで提供されており、ソフトウェアのアーキテクチャとして見ると2つのコードベースがありコンポーネントが分かれている点に注意が必要です。

プロダクトと機能の関係性について

この整理をもとに、「ある機能があるプロダクトに乗るかどうか」を表にしたのが以下です。

これを見て直ちにわかることは、ある機能がいろいろなプロダクトに乗る可能性がある、ということです。

そのようなサービス設計に至っている背景について少し個別に見ていきましょう。

「募集」や「ストーリー」といった機能が、個人向けと企業向けの両方のWebアプリで提供されているのは、採用に関わる事業ドメインの two-sided market place としての性質から来ています。個人と企業という二種類の主体が大きく分けて存在し、この間でマッチングが起こるという性質です。

また、その際にはコンテンツが重要になることから、ほとんどの場合、一方がコンテンツの作成者となり、もう一方がコンテンツの読み取り者となります(コンテンツが重要なのは、Webサービスの検索性という観点や、マッチングのためにお互いにサービス上から一定の事前判断が必要ということから来ます)。

また、「プロフィール」が Wantedly Visit と Wantdly People にまたがって提供されているのは、Wantedly 全体としてのプラットフォーム化を重視しているという戦略から来るものです。

これらは排除すべき無駄な複雑性とは真逆の、サービスの価値の源泉であることから、ドメインの基本的な性質だと断定できます。これによって、アーキテクチャとして考慮すべき特性が一つ明らかにできました。

コラム:「どうやって」よりも「なぜ」の方がずっと重要だ

先ほど「ある機能がいろいろなプロダクトに乗る可能性がある」と書きました。これは、現状のプロダクトを解析して得られた、客観的な「事実」に近いものです。

この事実をどう扱うか。この事実だけ見ると、プロダクトマネジメントが散らかっているという問題だとも捉えることができるのではないかと思います。であればそれはアーキテクチャとして考慮すべき特性ではなく、プロダクトとして解消すべき複雑性でしかなくなります。その場合、そのような機能展開を積極的に支えるアーキテクチャを作ってしまうと、最悪の場合、プロダクトが複雑になってユーザー体験を損ねてしまうことすら考えられます。

このように、ソフトウェアのアーキテクチャは、「なぜそうなっているか」を問うことなしには適切な判断ができないケースがそこら中にあります。『ソフトウェアアーキテクチャの基礎』では、このことが次のような言葉で強調されています。

ソフトウェアアーキテクチャの第二法則: 「どうやって」よりも「なぜ」の方がずっと重要だ

ここで行った「ドメイン」についての観察は、非常にハイレベルなレイヤーのもので、データのモデリングなどにブレークダウンして考える余地はいくらでもあります。しかしここでは全体としての仮説を提示するという一旦のゴールがあるため、先に進みます。

3. 技術についての観察

次に技術の観点を見ていきます。改めて、なぜ技術について見るのかと言うと、ドメインの観点だけだと机上の空論というか、あくまで分析上の概念にとどまってしまうためです。最終的に、ドメインの洞察を、その実現手段たる技術と紐づけることで、実際の開発に直接役に立つものを作ることが目的です(アーキテクチャは開発の役に立つべきです)。

技術についてのざっくりとした想定として、これまでの開発経験から、それまで導入してきたものが全くの的外れなものであるということはないだろう、という想定がありました。例えば以下の資料で、各時点の技術判断の経緯が語られています。

Wantedly における Go 導入にまつわる技術背景 | Wantedly Engineer Blog
(本記事は Go Conference 2019 Autumn にて無料配布した冊子『WANTEDLY TECHBOOK GoCon Edition vol.2』からの掲載です) 配布した冊子の前半では Go の導入にあたってどのような工夫をしてきたのかを紹介しました。そこに書かれていたように、新しいプログラミング言語を導入するにはそれなりの整備コストがかかります。それではなぜそこまでして Go を導入したのでしょうか。本記事では Go を導入した背景について説明していきたいと思います。 どのプログラミン
https://www.wantedly.com/companies/wantedly/post_articles/193633

そこで、要素技術はすでにあるものをベースとしつつ、現在発生している課題感を解消するような「調整」ができないか?という方向で考えます。こうすることで、リ・アーキテクチャのエンジニアリングコストや、組織の学習コストに一定の範囲に抑えることができます(もちろんこれは少し保守的なやり方なのですが、それは効果とコストとのトレードオフです)。

問いを設計する

課題感を把握するにあたっては、分科会のメンバー(それぞれある技術領域に詳しい)に協力してもらいました。具体的には、次のような問いを投げかけています。

技術的な分岐点・選択肢の洗い出しと依存関係・衝突関係の整理をしたい。そのために・・

現時点で「これとこれは両立しにくい」「これを解決する設計が見出せない」「あり得るかもしれないけど難易度が高い」「悩ましくてどうあるべきかパッと答えが出ない」と思っていることを書いてみる

この問いの投げかけ方は、アーキテクチャに特有の課題感が集まるように少し設計されています。技術的な課題感はいくらでもあるはずなので、トレードオフがあって判断しづらかったり、時間軸として長い目で考えなければいけないので決定できない、など特にアーキテクチャとして解決するべきカテゴリーの課題感が集中的に集まるように問いかけを工夫しました。

結果

このようにして実際に出てきたのが以下です。

内容は多岐に渡りますが、一つ一つ見ていくと、それぞれのトピックは相互に絡み合っていて、独立に考えて結論を出すことが難しいものが一定あることが分かります(ある程度想定していた結果です)。

例えば、パッと見ても次の4つはそれぞれが取りうる選択肢を制約する関係になっています。

  • バックエンド・BFF のAPIがドメインオブジェクトに近いものをしゃべるべきか、UI に基づく何かをしゃべるか
  • モバイルの API とウェブの API はどこまで共通にするべきか
  • バックエンドとフロントエンドを分離する方向性の良し悪し
  • GraphQL の採用有無

このような関係を随所に見出すことができるため、全体としては解けないパズルのようになっています。

これらを論理的に解きほぐすことは、材料としては意味がありますが、それ自体はあるべきアーキテクチャを直接導くものではありません。これはあくまで技術的な観点に限定した問題構造でしかないためです。

アーキテクチャは、ここまで観察してきた技術・ドメイン・組織(ここでは触れていません)などを総合して、それらを全体的に解決するような構造(解決構造)を持ってくることに相当します。従ってアーキテクチャはその論理的な導出の正しさではなく、提示されたものが 全体的にどの程度適合するか ということを以って validate されるものだと考える方が良いでしょう。

次に紹介する、Wantedly Architecture Overview はこの解決構造にあたるものであり、前述の「理想的なソフトウェア・システム」における初期状態になります。

4. 最初の仮説の策定 ...Wantedly Architecture Overview

Wanteldy Architechture Overview は1枚のドキュメントとしてまとめています(初版は Dropbox Paper として公開しています)。

フォーマット

このドキュメントでは、重要な問題を主題ごとに列挙することで全体を構成しています。

そして、それぞれについて「問題の本質は何か」「問題について論じた上での解決の提示」「関連する他の問題へのリンク」を述べたものになっています(「パタン・ランゲージ」という都市計画の設計指針のフォーマットを参考にしています)。

実際に含まれる主題としては、次のようになっています。

  • 全体
  • アプリ層のコンポーネント分割
  • システム層のコンポーネント分割
  • システム層のコンポーネント間の協調戦略
  • アプリ層とシステム層の協調戦略
  • データ層(ウェアハウス)への集約戦略
  • システム層とデータ層の協調戦略
  • データ層の抽象化戦略
  • コンポーネントに横断的な関心の存在と共有戦略

これらの主題について、2つピックアップして内容を見ていきましょう。

例1:全体

最初の主題は「全体」です。全体についての「本質的な問題」は、そのままの状態では自由度が高く複雑すぎて手に負えない、というものです。

アプリケーションを提供するために必要なコンポーネントは膨大で、種類も異なる。そういうものが全ての組み合わせで相互作用し得るとしたら、設計上の意思決定も影響範囲の把握も難しくなる。

そこで、レイヤード・アーキテクチャというよく使われるアーキテクチャ・スタイルを導入し、相互作用を限定すると同時に名前をつけて認識できるようにします(「問題に対して解決となる設計」の部分)。

アプリケーションの動作に関わるレイヤーが3つ存在する。

アプリケーション(Applications):
  モバイル・ウェブ含めてそれぞれ複数存在
  複数コンポーネント(~10)
システム(The System):
  マイクロサービスアーキテクチャで構成されバックエンドで稼働する
  複数コンポーネント(~100)
  実行基盤:Kubernetes
データウェアハウス(Data):
  単一コンポーネント
  実行基盤:BigQuery
  クライアント:Looker, Salesforce

ざっくりいうと、アプリケーションにはプロダクトx提供プラットフォームの数だけコンポーネントが存在し、システムには多数のコンポーネントがマイクロサービスないしモノリスとして存在する。・・・

技術用語とアーキテクチャ

この枠組みがなぜ必要なのかというと、共通の言語で議論をするためです。

と言うのも、世の中の技術的な用語というのは色々な括りが(各プラットフォーマーの影響を多分に受けながら)多種多様に存在していて、全体を認識する際になんとなくそれぞれの概念を使って話します。しかし、出自が違えば言葉と概念が違うので、コミュニケーションがずれます。

「フロントエンドとバックエンド」などは特に分かりやすい例で、一般的にこの言葉が使われるときは Web のことしか想定されておらず、「モバイルアプリ」は別の何かだと捉えられています。「フロントエンドとバックエンド」という括りは、クラシックなWebアプリケーションにはよく当てはまります。しかし、我々の事業やサービスとしての価値、そして技術の実態を含めて考えたとき、その捉え方が本当に有用かどうか、ということは問う必要があります。

アプリとシステム

toC 向けのプロダクトとして考えると、iOS アプリや Android アプリを作っている理由は、何よりも“そこにユーザーがいるから”です。Web アプリを作っている理由も、本来は同様のはずです。なので、ユーザー接点として、ユーザーがいるプラットフォームにアプリを提供している、と考えられます。

一方で、Wantedly の場合、プロダクトの価値はユーザー・インターフェイスのみから生まれているわけではなく、「募集」や「プロフィール」といったデータがあってそれが使えるからこそです。

そう考えると、それらのデータを貯めていける「バックエンド」とは、ユーザー接点を持つこととは別の、複数のアプリケーション・プラットフォームに API を通じて長期の価値を提供するシステムであるはずで、そう捉えて作ることで実際にそのような価値を持続的に生み出すことができます。

このような背景から、Wantedly においてはソフトウェアを「アプリ(Applications)」「システム(The System)」「データウェアハウス(Data)」の3層で分割しています。

そして、こういう視点に立つと、「フロントエンドとバックエンドを分離するべきか」「モバイルアプリと API を共通化するべきか」といった技術的な議論にも決着がついたり指針を与えることになります(これが解決構造であることの意味です)。

例2:データウェアハウスへの集約戦略

もうちょっとシンプルな主題も少し紹介しておきます。データに関する本質的な問題として、次のようなものがあります。

データはあらゆるところから収集して相互に組み合わせて使えるようにすることに価値がある。

これに対して、次のような解決を提示しています。

相互に組み合わせて使えるようにするため、すべてのデータをデータウェアハウスに集約している。
データは大きくプライマリーデータとログデータの二種類があり、集約方法が異なる。

データの種類として、トランザクションデータと時系列データ(ログ)がある。
トランザクションデータはシステムで発生し、データウェアハウスには自前モジュールで毎日同期される。
ログデータはアプリケーションとシステムの両方で発生し、データウェアハウスには fluentd によるストリーミングで送られる。

最後に、関連する主題として何があるかが提示される、という形です。

そうやって集約したデータをどのように処理するかがある(→ システム層とデータ層の協調戦略)。

このようなアーキテクチャ上の意思決定を1枚の図にまとめたのが、採用デックや Wantedly Engineering Handbook で公開している図です。

・・・長くなりましたが、以上がアーキテクチャの領域を立ち上げる際に行った取り組みです。

ここまでやったことで、当初のミッションとアプローチで述べた「仮説からイシューを特定してその結果をもとに仮説を更新し続けることでソフトウェア全体を正しい方向に進化させること」をやっていくための準備ができたという状態です。組織としてはこの後、アーキテクトの任命、専任のアーキテクチャ・チーム(Arch Squad; 以下 Arch と略)の組成といった形で段階的にリソースを投下していきます。

新たに Squad として編成された Arch では、ソフトウェア全体を進化させることの推進を行いました。取り組むことの大まかな基準としては、特にボトルネックになっているイシューであること、ソフトウェア基盤の検証・構築など難易度が高くかつ片手間でできないもの、などです。

ここでは、そのうち特に全体の設計に影響する施策を2つだけ紹介します。

5. 施策:インターフェイス定義言語の分断解消 ... Protocol Buffers と GraphQL

アーキテクチャ全体の図を見れば明らかなように、ソフトウェアはユーザーのデバイスからクラウドのサーバーまで様々なところで動いており、これらの間で通信が行われることでサービスが動いています。この通信がAPI呼び出しであり、これらはインターフェイス定義言語を用いてスキーマが記述されます。

よって、インターフェイス定義というのは重要なのですが、そこには技術的な分断がありました。

分断とあるべき状態

この時点で、Protocol Buffers と GraphQL という二つのインターフェイス定義を行う技術は既に別個に導入されていました。個別に見るとそれぞれの技術が解決したい課題というのは確かに存在していて、かつその技術を適切に使えば実際に解決できるであろう、ということもまた確かだったのですが、アーキテクチャ全体として見るとあまり良い状態とは言えませんでした。

これら2つの技術は「API のスキーマを記述することで、API に型をもたらす」という点では、同じ課題を解決します。「型がある」というのはプログラマーにとって(事前の記述コストが許容できるのであれば)ほとんど自明に開発生産性の向上をもたらすので、これは良いことのように思えます。

一方で、スキーマというのはマイクロサービス・アーキテクチャのように API ファーストなソフトウェア開発スタイルにおいては、ドメインの知識を凝縮したものである必要があります。そうすると、「ドメインの知識の集約」という点で、Web フロントエンドのインターフェイスとなる GraphQL に知識を集約するのか、それとも個々のマイクロサービスのインターフェイスとなる Protocol Buffers に知識を集約するのか、という二つの選択肢が生まれ、これがバックエンドと Web フロントエンドの「分断」を発生させます。

これの本来あるべき状態は、「API のスキーマを記述する」というコストを支払うことで、それが「型がある」というような単純なレベルから「ドメインの知識がコードとして現れる」というような高いレベルまで、そして「Web フロントエンドが嬉しい」ではなく「バックエンドも Web フロントエンドもモバイルも嬉しい」といったようにあらゆる点と面でプラスに働き、それによってスキーマを書くということ自体が加速し、ソフトウェアが成熟していくというものです。

参考までに、この辺りの個人的な見方については以下のところでもお話ししています。

技術的な解決策

それを行うにあたって、単純にどちらか片方に寄せるという選択肢もあったのですが、私見では両者の敷いている問題設定は異なるものであり、アプリとシステムの通信には GraphQL、システム間の通信には Protocol Buffers / gRPC が適合していると考えてました。Wantedly Architecture Overview でもそういった仮説を提示しています。

そこで、Protocol Buffers のメッセージ定義から GraphQL のオブジェクト定義を生成するソフトウェア基盤を作成し、サーバーの検証と導入を進めました。詳しいことは、資料とコードが公開されているのでここでは割愛します。

GitHub - proto-graphql/proto-nexus: Protobuf-First GraphQL Schemas with GraphQL Nexus
Protobuf-First GraphQL Schemas with GraphQL Nexus yarn add nexus graphql # required as a peer dependency yarn add --dev protoc-gen-nexus # if you generate code with `protoc --js_out` yarn add @proto-nexus/google-protobuf \ google-protobuf @types/google-pr
https://github.com/proto-graphql/proto-nexus

なお、この部分は、システムとアプリを一般性のある形で API で分離する要であり、ここの部分で技術的な解決策がなければ GraphQL は廃止して Protocol Buffers に寄せるという意思決定もあり得ました。そうなると、Wantedly Architecture Overview の全体を見なす必要があります。そのため、このイシューの検証は Arch でイニシアチブを取って進めました。

6. 施策:アプリのインフラを整える ... デザインシステムライブラリ

すでに述べたように、Wantedly は複数のアプリケーション・プラットフォームにアプリを展開しています。これがドメインの特性から来ていることはすでに述べました。

これらのアプリそれぞれに対してUIデザインが行われるわけですが、同じ機能を何回もデザインすることはデザイン工数上望ましくなく、またユーザー体験の一貫性にも欠けます。これを解決するために、デザインシステムというものが導入されていました。

これは元々プロダクトデザイン上の判断でしたが、目的に立ち戻るとこれをソフトウェアのライブラリとして実装することで、エンジニアリングとして同じ効果が得られることが見込めました。

そこで、デザインシステムをアプリ全体のインフラとして定義しています。GraphQL API を通じて自由に宣言的にデータを操作し、デザインシステムライブラリを使って基礎的な UI を構築できれば、Webアプリやモバイルアプリの開発のアジリティを全体としてかなり上げることができるのではないか、という見立てです。

ただそうは言っても、デザインシステムを適切にソフトウェアのライブラリに落とし込むという作業は、プロダクトデザインに対する理解と、エンジニアリングに対する理解のどちらも深く求められるため、なかなか使えるものができなかったという経緯がありました。つまりこれも Product Design Chpapter とアプリケーション技術系の Chapter という、職能領域間の間に落ちる問題だったわけです。

そこで、Webアプリにおいてデザインシステムライブラリを開発しつつ、デザインシステムの定義をより精緻にしていくということを Arch で行いました。後者のアウトプットとして、以下のブログが公開されています。

ノンデザイナーズ・Wantedly デザインシステム完全理解ペーパー | Wantedly Engineer Blog
Wantedly では新卒含む新入社員向けに研修を毎年実施しています。これは「新入社員向け」といいつつ既存の社員も自由に参加できるものです。今年はこの研修のフォーマットを借りて、Wantedly のプロダクト開発を支える重要な概念のひとつである「Wantedly の UI デザインシステム」についての研修を、ソフトウェアエンジニアの @izumin5210 (筆者) とプロダクトデザイナーの @NishaMe で実施しました。 デザインの構造を正しく捉えることは、UI の実装を専門にしているかどうかを問わ
https://www.wantedly.com/companies/wantedly/post_articles/395772

コラム:Webページか?Webアプリか?

ここまで、Webフロントエンドに意図的に「Webアプリ」と呼んできました。これはページ遷移以外の画面書き換えを行うもので、インタラクティブ性の高いものです。

一方で、このようなインタラクションがあまりないページも存在します。そのようなものは「Webページ」ないし「Webメディア」と呼ぶ方が良いかもしれません。

なぜこの2つを区別しているかというと、両者でソフトウェアの複雑性が全く異なるからです。

そして、モバイルとWebの2つのプラットフォームで、近い UI/UX を提供しようと志向すると、必然的にある程度「アプリ」化しますし、プラットフォームであるところのWebブラウザーもそれに対応する進化をしています(参考:V8 とレンダリングエンジン Blink のアーキテクチャ)。

Wantedlyは現在、Webアプリを作っています。作ろうとしているものがWebページなのか、Webアプリなのかによってアーキテクチャの議論は変わってくるでしょう。

7. 有効性の検証

GraphQL を使ってアプリとシステムを分離しつつ、デザインシステムライブラリでアプリのUIを効率良く実装できる準備が整った段階で、それらの有効性を比較的大型のプロジェクト(数ヶ月程度)で検証しています。

検証としては、以下の2つのシナリオでうまくいことを確認しています。

シナリオ1) プラットフォームAに向けて先行実装された機能を、プラットフォームBに向けて展開する
シナリオ2) 同一プラットフォームにおいてアプリaに先行実装された機能を、アプリbに向けて展開する

この2つのシナリオで上手くいくと、採用ドメインの4つのアプリ(個人向けWebアプリ、企業向けWebアプリ、iOSアプリ、Androidアプリ)に対して1つのシステム API を提供することになり、開発のアジリティやロジックの凝集性が大きく上がります。それによって、考えているアーキテクチャ及び構築したソフトウェア基盤の有効性が判断できます。

具体的なケースとして、個人向け Web アプリに先行リリースされた新しいプロフィール機能(https://www.wantedly.com/id/Altech のこと)を、Android アプリと企業向け Web アプリに展開するプロジェクトがあったので、そこで2つのシナリオを検証しました。

Android アプリに展開するプロジェクトでは、モバイルチームを中心に iOS / Android における GraphQL エコシステムの事前検証をするところから始まり、実際のプロジェクトで API を使ってもらいました。この際は、システム側の GraphQL API は僅かな改修のみで利用できることを確認しました。

企業向け Web アプリに展開するプロジェクトでは、Arch のエンジニア2人(著者含む)はバックエンドとフロントエンドで分業してみることで、GraphQL API によるソフトウェア開発の分業の実際を把握します。この場合、表示するデータはほとんど一緒ですが、企業の採用担当者という新しい種類のユーザーに対して表示するため、バックエンド側はそこの認可ロジックを追加するということを行いました。

学び

GraphQL API を使うことでバックエンドのシステム側の開発とアプリ側の開発を分離できたということに加えて、次のような利点が改めて確認できました。

  • アプリ側:2つ目以降のアプリでは、直ちに実装が開始できるためリードタイムが大幅に短縮される
  • システム側:認可ロジックなどを一般的に実装することになるため、長期的な API 資産になりやすい

また、デザインシステムライブラリについてはその有効性が確認できましたが、全体設計にさらに改善できる点が見つかり、この後新しいバージョンを再設計しました。

8. 今後の方針

アプリとシステムの分離を決定

前述の検証を踏まえて、アプリとシステムを分離したアーキテクチャにすることは本格的に重要だろうという考えから、今後の方向性として「アプリとシステムの分離」を決定しました。

いわゆるクラシックな Web アプリケーション的な「バックエンドとそれに対応するフロントエンド」という考え方から、たくさんのアプリと裏側にある一つのシステム、という捉え方に変化します。

こういう構図を、開発プロジェクトのタイムラインに変換した時、最初のシステム実装に大きめのコストがかかるといった構図になります(この部分を投資として説明するために経営メンバー向けに資料を作成しました)。

例えば、ユーザーの「転職意欲」を入れられるようにする機能を追加するとき、最初は個人ユーザー向け Web アプリに対して入力用の機能追加を行うとします。その時、フロントエンドだけでなくバックエンドの開発が必要になります。ただし、それを iOS アプリ、Android アプリに展開するときは、モバイルエンジニアだけでそれが可能になります。それを企業ユーザー向けの Web アプリに展開するときも、企業特有の仕様がなければフロントエンドエンジニアのみで可能になります。

単なる人日工数ではなく、少ない人数と職種でリリースが可能になるということがとても重要です。Amazon のジェフ・ベゾスは「ピザ2枚ルール」を作るくらいチームを小さく保つことに固執しました。

一つ気をつけなければいけないのは、バックエンドの人は「目の前の Web アプリに必要な API を実装している」と考えるのではなく「あらゆるアプリから使われる、転職意欲というWantedlyプラットフォームの価値をシステムに実装している」と考える視点です。これは、プロジェクト・マネージャーも同じような認識が必要ですし、ステークホルダーもある程度は共通の認識が必要になってきます。そのため、開発以外の人がいる場でもお話をしました。

もちろん、全てがすべて、こういったシステムの先行投資をしなければならないわけではなく、あるアプリケーション・プラットフォームで検証をしてが決まってから、汎用的な API を実装する、といった順序で進めることもできます(ただしその場合は、負債を借りているという認識とその返済計画が必要です)。

実際のところ、今この時点でのシステムとアプリケーションの分離が投資対効果としてどうか、というのは非常に複雑です。このくらい大きな決定は、数年後にならないと誰にでもわかる形でトータルの良し悪しがわかる状態までは行きませんし、当然ながらその間組織も事業環境も変化します。理想を言えば、この判断をもっと早くできたら、とも思います。

その上で、直接的なリターンに加えて、「あるべき状態が分からなくて迷い続ける」よりは「今からでも目指すべき状態がある方が良いだろう」という見切りの元にこの判断をしています。

振り返りと今後

最後に、全体のアーキテクチャの観点から見た振り返りと今後の課題について記載します。

まず、アーキテクチャ・チーム及び各技術領域での取り組みの甲斐もあって、ソフトウェア・アーキテクチャの取り組みを始める以前とは随分全体的な課題分布が変わったなと思っています。その上で、今後の大きな課題ポイントとしては次のようなところがあると考えています。

一つは、アプリとシステムの分離を実際に進めることです。これを行うために、バックエンドとしてはプロフィール以外のドメイン上のデータを GraphQL オブジェクトとして API で戦略的に提供していくことになると思います。主要なドメインのオブジェクトが揃っていけば、アプリの開発やリアーキテクチャも加速度的に容易になっていくはずです。

こうしてアプリとシステム分離が進んでいくと、システムをある程度アプリから独立に改善していくことができるようになります。こうして、システム内部のアーキテクチャを育てていくことの重要性が徐々に上がっていきます。この段においては、ドメイン設計が鍵になるでしょう。

また、この記事では Arch が直接に推進した施策を紹介しましたが、データウェアハウスをインフラとするデータ領域もさまざまな課題があり、漸進的なツールの導入が進んでいます。ここはプロダクトの成長に合わせて継続して基盤も改善していくことになると思います。

今後は、これらの課題に組織として継続的に取り組みながら、そのフィードバックを元にソフトウェア全体の仮説を更新していくことで現実のソフトウェアを正しい方向に進化させていければ良いと思っています。

11 いいね!
11 いいね!
同じタグの記事
今週のランキング
Wantedly, Inc.からお誘い
この話題に共感したら、メンバーと話してみませんか?