自己紹介と会社紹介

中山太雅氏(以下、中山):「フロントエンドをゼロから作り上げしくじってきた青春の思い出」ということで、話します。ファンファーレの中山と言います。よろしくお願いします。

時間がないので早口になってしまうと思いますが、ちょっとお許しください。発表内容ですが、大小いろいろ織り込もうと思いましたが時間の関係上、大にフォーカスしてお送りしようと思ってます。すみませんがご了承ください。

こんな感じで話そうと思っています。自己紹介と会社紹介をした上で、何をしくじったのかを最初に伝えて、そのバックグランドというか、どんな感じでしくじっていったのかを共有して、結果的にはどう対応しているかみたいなところを話そうと思ってます。

自己紹介および会社紹介です。中山と言います。ソフトウェアエンジニアで、ファンファーレではフロントエンドを担当してます。これまではサーバーサイドやフロントエンド、フロントエンドと言ってもUnityとかそういう感じですが、いろいろ経験してきました。

会社紹介です。弊社ファンファーレは、労働人口不足の産廃業界の省力化に取り組んでます。具体的には、最適な配車計画を短時間で自動生成するサービス「配車頭」を提供してます。

サービスを一言でいうと、最高の数理最適化を最高のUI/UXで届けることを目標にしていて。ITリテラシーがあまり高くないような方でも、ストレスなく最高の数理最適化を享受できる感じで、細やかなUX設計を行なっています。

しくじり発生の流れとその内容

かなり早く進んでいますが、何をしくじったのか。一言でいうと、アーキテクチャの設計をしくじって、データの更新がしづらくなったことです。こうやって言ってますがメチャクチャ大きい失敗で、今メチャクチャ心が痛いですというのを始めに言っておきます(笑)。

スライドに書きましたが、問い合わせが増えてきた時期に、開発が2ヶ月止めちゃってごめんね、みたいな感じの内容になってます。

しくじりの流れで、会社のフェーズのどのあたりで発生したのかという図です。弊社CEOの近藤が立ち上げ、技術面を見るためにCTOの矢部がジョインし、PoCを作っていこうとなった時に、「あんまりリッチなものでなくてもいいからとりあえず動くものを作ろう」ということでRailsで画面作ってた時期がありました。その時にバックエンドで副業の方が入って作っていた感じになっていて。

PoCができて「だいたいワークするね」という感じになったので、商用化をする時にフロントエンドをしっかりリッチに作っていきたいということになり、私がジョインしたのがだいたい1年ぐらい前の話です。

かなり簡略化していますが、ざっくりしたシステム構成図です。フロントエンドからバックエンドへ情報を送って、さらにその奥で最適化エンジンが走って、いつどこに車を向かわせるみたいな配車表を最適化して、その情報を返すみたいな図になってます。

フロントエンドと最適化エンジンは本業のエンジニアが担当していますが、バックエンドは副業の方がメインで、リソースがあまり潤沢ではなかったという背景がありました。

私がジョインした時に、立ち上げに当たってはそのアーキテクチャを設計する必要があって、過去事例などをいろいろリサーチしました。スライドにいくつか例を出していますが、もうちょっといろいろリサーチしました。

当時、DDDの文脈をフロントエンドにうまく組み込もうとしている人たちがそれなりにいる印象を持っていて。いろいろなやり方があると思いますが、今でも私は有効、正しいと思っていて。

ただ、当時の自分の認識が「バックエンドに何かしらエンティティがあると、多少加工してフロントエンドに返したとしても、トラックすべき対象であることは変わらないはずだ」と。

つまり何が言いたいかというと、フロントエンドから見てもエンティティはエンティティである。そのエンティティが何かみたいなその下の説明は、ドメイン駆動設計などを見てもらえたらと思いますが、エンティティは一意性を持っていて、状態の連続的な変化をトラックするべき対象であると。

それを更新するにはどうするかを考えた時に、バックエンドのリソースよりもフロントエンドのリソースのほうが潤沢にあって。「多少フロントエンドにロジックを持っちゃってもいいのでは?」ということで、エンティティを書き換え、それをサーバーに書き戻すというアーキテクチャにしました。このあたりから「ちょっと雲行きが怪しいぞ?」とにっこりしてる方もいると思いますが(笑)。

要はこんな感じになってたと。リポジトリはエンティティを保持しているもので、そこに今エンティティがあり、それを書き換えた挙句、サーバーサイドに同期するかたちになっていましたが、問題があって。

何が問題かというと、当たり前の話ですが、サーバー側でしかわからない制約をすごく扱いにくくて。その制約に引っかかった場合に状態を書き戻せないし、Webを分散システムとして見た時に、次の状態を決めやすいのはバックエンドなので、フロントエンドで過剰にコントロールするのはやはりやるべきではないと。

例えば数千のエンティティがあり、名前の重複を許さないようなケースがあった場合に、バックエンドであれば普通に対処できると思いますが、フロントエンドでそれをやろうとなった時に、「どうするんですか」という問いにはかなり答えづらいと思っていて。「じゃあフロントエンドにじゃあ全部置くんですか」「そんなわけないだろ」みたいな。あとatomicityがなくなるとか、そのあたりもけっこう微妙で、間違ってますと。

リファクタリングの時間を確保して対応

どう対応したのかです。リファクタリングをするための時間を取り、アーキテクチャを再設計して、外部のアドバイザ含めて議論、レビューなどをしながらリファクタリングしています。今まさにリファクタリング中ですが、詳細を語るには時間もないので、別の機会にしたいと思っています。

これが改善版というか。けっこう一般的な構造だとは思いますが、例えばVuexであれば、アクションみたいなものがいて、それが外部と通信して最終的に状態が定まり、Storeに書き戻されるみたいな。

内部的に微妙に違ったりしますが、ざっくり言うとこんな感じになっています。フロントエンドで状態を過剰にコントロールするのはやめましょう、という感じです。

負債を負債としと認めて返済する

今回のしくじりでいろいろ学んだなと思っていて。フロントエンドのアーキテクチャを設計するタスクにチャレンジ精神を持って挑戦して、「こういう場合にこういう問題が起きるな」みたいなものは、「いやあ、自分が間違ってたな」と負債を負債として認め、その負債から理想的なアーキテクチャ像をもう1回組み立てて、負債を返済する文化を作ったのが、ある意味よかったというか。

ちょっと言葉は難しいですが、ただでは立ち上がらないみたいな。そういう文化を作れたのがよかったと思っています。

以上ですが、参考文献としていろいろ書いてあるので、あとで見てもらえたらと思います、という感じで以上です。ありがとうございました。

質疑応答

田仲紘典氏(以下、田仲):ありがとうございました。負債に向き合える早さがすごいなと思っていて。いち早く察知して解消していくことは、やはり大事かなと思っています。負債と向き合うってあとあとたぶんすごくジャブのように効いてくると思うので、大事ですよね。

中山:負債の種類にもたぶんいろいろあると思いますが、簡単に変わらない構造がアーキテクチャであるはずなので。だから、そこでしくじると影響がメチャクチャ大きいというのは当たり前の話で。

こういうレベルの失敗ってそうそうないような気もしていますが、だからこそ今の時期にやらないとまずいっていうのがあって。CTO、CEOと相談して、「これちょっとやらせてください」「今やらないとまずいのでやっときましょう」みたいな話をしてやっています。

田仲:なるほど。「他のメンバーから、負債を負債として理解してもらえたのでしょうか」というコメントがきていて。基本的にそのCTOやその他のメンバー、たぶん業務委託などで入っている方とかも、認識合わせしながら今やった感じですか。

中山:そうですね。そんなに頻繁に開催しているわけではありませんが、ライブでAllhandsみたいなものをやり、「こういうアーキテクチャになっていて、こういうやり方をするとこのあたりが問題なので、こういうふうに改善しようと思っています」みたいな話をしてますね。

田仲:ちなみに、社長からの賛同は得られたんですか。

中山:許してもらってます(笑)。今もしかしたらZoomでいるかもしれませんが、さっきも話しましたが、「ちょっとこれは今やっておかないとまずいです」という話をして、「申し訳ないですけど時間取ってもらえますか」ということで、取ってもらってます。

田仲:たぶんDDDや概念があったと思いますが、フロントに組み込む前に検討した方法や、「こういうアーキテクチャでやるべきだった」という、やるべきというか考えていた方法は何かありますか。

DDD以外でもいいです。DDDの方法っぽい中でも組み合わせのアーキテクチャはいくらでもあると思いますが、「こんなようなかたちのほうがよかったな」みたいに、検討した内容ってありますか。

中山:要はその1年前ということですよね。エンティティをそのまま返さなかったとしても、結局Viewモデルみたいなかたちで返すとは思っていて。そこに関して、そんなにいろいろなパターンがある気はしていません。

大事な分岐点というのは、要はフロントエンドに本質的な情報のかたちで持っていいのか悪いのかみたいなところがけっこうあると思っていて。私は今でもけっこう持っていいんじゃないかとちょっと思っている。

それはどういうことというと、要は「エンティティ持っててもいいんじゃない?」という話です。DDDの文脈でいうと、利口なUIは否定されるような流れがあるような気がしていて。言ってることはわからなくもないですが、それだとけっこう扱いづらいし、真にリアクティブで動かないみたいなものがあったりして。

例えばslackで名前を変えても、別にページ再読み込みしなくても、自分の名前が全部変わるじゃないですか。あれがどうして起きてるかというと、エンティティをエンティティとしてトラックしてるから可能なのであって。

つまり、どういうかたちで情報を返そうが、エンティティはエンティティとして認識してるからああいう格好いいかたちにできるんです。だから、Viewモデルといっても、エンティティはエンティティだという感覚を私はちょっと持っていて。

例えばzozoの人とかも、「情報はリソースベースで持ってたほうがやりやすいんじゃないか」みたいなことを確かチラッと書いていて。それはどういうことかというと、たぶんその人が“リソース”と言っているのは、たぶんエンティティのことだと思っています。

要は、エンティティはエンティティとして持ってたほうがやりやすい感覚を、現場の人は持ってるのではないかと私はちょっと思っています。個人的な意見で違うって言われるかもしれないんですけど(笑)。

田仲:違うって言えたら言います。気持ちはすごいわかる。

小佐野洋(以下、小佐野):気持ちはすごくわかるから、サーバーサイドのエンティティと、フロントエンドのエンティティは必ずしも一緒である必要があるのかというと、そこは微妙な気がする。

中山:それはそうだし、多少付加して返す時もあるとは思っているものの、逆というか、「そんなに違うことある?」ともちょっと思います。確かに違うこともありますが、ネストして上側でラップして付加するようなことはある気はしていますが、そのネストした中でエンティティを入れてもそんなに害はないというか。

情報量なんて大したことないし、集約していて何メガバイトみたいなメチャクチャなものを返すのはちょっとナンセンスだと思いますが、そんなことにはそうそうならない気がしていて。

小佐野:「確かにそうかな」とも思うけど、時々変わる場合もなきにしもあらずだったりするので。「サーバーサイドでは公開するけれど、画面上こう表示したいからこう集約します」みたいな。

集約のかたちが違う場合もあるかなと。サーバーからは全部のデータが返ってくるけれど、そのうち一部だけ必要だっていうパターンだと、IDでトラックしてはいけないものがあったりすると思うので、それはあるような気がします。

田仲:なるほどね。ちょうど15分経ってしまったので、ここでいったん終わりにします。中山さん、ありがとうございました。

中山:ありがとうございます。