ゲーム開発におけるドメイン駆動設計とサーバレスアーキテクチャ

佃松三郎氏(以下、佃):みなさん、こんにちは。最初に「TECH × GAME COLLEGE」についてお話しさせてもらいたいと思います。

私はテクロスCTOの佃と申します。

ゲーム会社が主催する勉強会というのは数多くありますが、ゲームに特化した、もしくは「ゲームっていろんな技術を使ってるよね」という話があるなかで、「本当にゲームにフォーカスするオープンなコミュニティがないな」というところで、去年の8月からこの勉強会がスタートしました。

そこで「DDD」と呼ばれる開発手法について増田さんに登壇いただいたところからスタートしました。今回、ちょうど半年ということで、1つ区切りのイベントとして今回は開かせていただきました。

それでは、今日パネラーとして参加していただく増田さん、まずは簡単に自己紹介と最近取り組まれていることなどをお話しいただければと思います。

増田亨氏(以下、増田):こんばんは。ギルドワークスの増田です、よろしくお願いします。私自身はずっとソフトウェア開発、主に業務系・企業エンタープライズ系のソフトウェア開発をやってきています。

UNITIA』を立ち上げた2年ほど前にテクロスさんの京都オフィスでデザイン設計のレビューやアドバイスを、月に1〜2回ぐらいのペースでやってきたことがご縁で、去年8月の勉強会でドメイン駆動設計のことについてお話しさせてもらいました。

私自身は去年はあまりコードを書けていませんでしたが、今年は念願叶って、だいたい月の半分ぐらいは実際にプロダクションのコードを書いていて、自分なりに少し、ブレイクスルーというと大げさなんですが、今までの考え方より一歩先に進めたような感覚がありました。それをお客さんと一緒にコードを書きながら実験している最中です。

残りの半分は、ドメイン駆動設計というキーワードでご相談を受けることが多いです。とくに去年の後半から、わりと大きな企業や10年もの、20年ものの既存システムを抱えていらっしゃるような会社さんからもご相談を受けることが多くて。

週のうち何回かは、そうしたお客様のところにおうかがいしていろいろ話をしたり、実際のコードを使いながら、ドメイン駆動設計のスキルトランスファーを現場のエンジニアと一緒になってやるといった活動をしています。

:ありがとうございます。それでは丹羽さん、簡単に自己紹介と近況についてお願いします。

丹羽一智氏の経歴

丹羽一智氏(以下、丹羽):丹羽です。よろしくお願いします。私は2006年に、最初は新卒でセガに入社して、そのあと2009年に任天堂に転職をしました。2016年に自分でGame Server Servicesという会社を起ち上げたという流れです。

セガではいわゆるガラケーのゲームを作ったり、サーバの開発をしていました。任天堂では、ニンテンドー3DSのOSやSDKの開発、あとは、サードパーティというゲームを作る人たちに使っていただける汎用的なゲームサーバを開発して、提供するという業務をしていました。

その時に、ゲームを作っている人たちが、サーバの開発や運用の知識がなくても、汎用ゲームサーバを使えばネットワーク対応ゲームが作れる状況がありました。一方で、その頃スマホゲームも立ち上がってきていましたが、そちらでは各社が似たようなサーバシステムを作っていました。

「これって、誰かがまとめて作ったほうが開発効率が上がるし、よりよいゲームにするところにフォーカスできるんじゃないか?」と思って「誰もやらないのかな?」と見ていたんですが、2014年末、AWS Lambdaというサービスが登場しました。

こちらは、プログラムをAWSに預けておくと、そのプログラムのコードの実行時間で費用が発生するという仕組みです。そして翌年の夏ぐらいにAPI Gatewayという仕組みが出てきて、「HTTPリクエストをトリガーとしてLambdaが動いて、Lambdaの実行結果がHTTPのレスポンスで返る」みたいな仕組みが出てきたと。それを見た時に「これでゲームサーバを作れば、すごくスケールするゲームサーバになるんじゃないか?」と思ったんですね。

どうして私がその事業をやらなかったかというと、汎用ゲームサーバをプラットフォームとして提供しようと思うと、ゲームはアクセス数に振れ幅があり、大ヒットするととてつもないトラフィックになるし、そうでもないときは少ないという状態なので、それを事業としてやろうと思うと、たくさんアクセスが来たときを想定してインフラを用意しておかないと、安心して使っていただけないんですね。

でも、それではインフラ費用がどんどんかかってしまって事業が立ち行く前に資金が尽きてしまうことが想像できたので、なかなか前に進めなかったのですが、このLambdaの実行時間に対して料金がかかるというモデルが出てきたことによって、「これを事業としてできるんじゃないか?」ということで、2016年に創業しました。

今はそうしたサービスの開発をしているのですが、昨年の3月にDeNAやKLabから資金調達をして、今はその資金を溶かしながら開発をしている状態です。

サーバレスでの開発を2年ほど続けていますので、おそらく日本で一番サーバレスに関して詳しい人間なんじゃないかと思っています。以上です。

:ありがとうございます。その資金が溶ける前にぜひ飛躍してもらいたいなと思っております。

丹羽:(笑)。

DDDによって発展しそうな技術

:それでは、今日の流れですが、開発やサーバレスについてあらかじめ質問を広く募集しまして、それに対してライブ的にこの場で両氏にお答えいただければと思い、企画をしてまいりました。

一応、ご質問のほうを色分けしまして、黄色は「まぁ、答えやすいだろう」、オレンジは「ちょっと難しい」、赤は「答えづらいかな?」という感じで分けているので、そのへんも見て質問の難易度も見てもらえればと思います。

それでは、さっそく1つ目にいきたいと思います。難しい話かもしれませんが、「ドメイン駆動設計によって発展しそうなサービスやライブラリがあれば教えてください」と。

質問の意図としては、おそらくテスト駆動開発によってテストライブラリやCIツールが発展したことを考えると、このドメイン駆動設計(DDD)によって、なにか発展しそうなサービスやライブラリがあれば教えていただきたいという質問です。どうでしょう?

増田:そういう意味ではちょっと難しい質問というか、どういうお答えをすればいいですかね……。

:これ、黄色じゃないですね(笑)。

増田:簡単に言うと、ドメイン駆動設計がコアになって作ろうとしているところは、技術的には非常にトラディショナルです。Javaの場合だとPOJO……「Plain Old Java Object」という言い方をしますが、テクニカル要素は一切関係ない、単純にそういう値を計算するだけみたいな、入出力すらいらないような部分をコアのもので作るという作り方です。

そういう意味で言うと、ドメイン駆動設計によって新しい技術が出てくるということは今までもなかったし、これからもないと思います。

ただ、逆に言うと、「ドメイン駆動設計で作ってあるビジネスルールやビジネス知識を持ったオブジェクト群を周りからどう使うか?」という意味において、周りはどんどん変わってきています。

昔だったら……まぁ今でもそうですが、やっぱりトラディショナルなのは、同期でリクエストが飛んできて、レスポンスを返すと。そのリクエストに対してレスポンスを同期で返す、みたいなアーキテクチャのところで使われていることが多いんです。

ですが、おそらくこれからは非同期メッセージング。リクエストを投げたら投げっぱなしで、レスポンスが必要な人間も、同期でレスポンスを待つのではなくて、どこかに答えがあるはずだということを知っていて、自分でまた取りに行くとか。

あるいは、Pub/Subというか、「ビジネス的にはこういう事象が起きたよ」ということをパブリッシングすると、それをリスニングしているサブスクライバーが何種類もいて、そのサブスクライバーがパブリッシュされたものを受け取ったときに、自分の判断でそれに対してビジネス的なアクションを起こす。

要するに、それってビジネスのやり方そのものなんですよね。なにか事象が起きたら、いろんな関係者のところへ連絡が飛んで、関係者が自分のところに関係あると思ったらアクションを起こすということです。

今までは同期という、あまり人間的なやり方じゃない方法がシステム化のスタンダードだったんだけど、非同期メッセージングやPub/Subみたいに、イベントがあって、イベントをリスニングしている人間が担当するものだったら自分でアクションを起こすみたいな、より人間が主体的に活動するようなビジネス活動をシステム上でも実現するような方向の技術は進んでいくのかなと思います。

もちろんTDDやテストライブラリ、CIツールというのはいいものがどんどん出てくるので、それは使うべきなんですが、それをドメイン駆動設計が引っ張るわけでもないし、それがないとドメイン駆動設計ができないというものではないのかなとは思いますけどね。

ドメイン駆動設計と「型」

:それで言うと、キューとかそういったものになってくるというか、ビジネスの実態に近づくようなものがあれば、そういったサービスが発展するという話ですかね。

増田:そうですね。やっぱり非同期だったりPub/Subみたいな、活動と活動主体が連携し合うというやり方をビジネスに合わせていくためには、もっと非同期であったり疎結合になっていくんだろうなと思います。

:なるほど。ありがとうございます。

丹羽:あっ、いいですか? 私、ドメイン駆動設計について増田さんにいろいろ教えていただいたんですが、その時にこの考え方ってすごくマイクロサービスだなと思ったんですね。システムをいろいろな役割に分割して、それぞれが自分の責務で動くと。自分に関係ないものは別のドメインオブジェクトにお願いをすると。これって、要はマイクロサービスだなと思ったんです。

このマイクロサービスはこういう役割があって、それを責任を持ってやります。その中の「どういうデータベースを持っているか?」といったことは外からはまったく関係なくて、外向きのインターフェースがあるので、それに対してリクエストをするというのが、マイクロサービスかなと思います。

先ほどPub/Subみたいな仕組みが出てくるんじゃないかというのも、まさにマイクロサービスです。対象のマイクロサービスが動いているか動いていないかというのは不確かなので、もっとリアクティブな設計になっていって、ジョブを依頼して、とりあえずその結果はすぐには返ってこないかもしれないけど、別のマイクロサービスがそれに合わせて動くみたいな流れになっていくのは、今話を聞いていて、すごく納得感がありました。

そういう意味では、最近ではServiceMeshなんかが出てきているので、そういう方面があるのかなと思いました。

増田:そうそう、1つ忘れていました。技術トレンドで言うと、実は非常に大きなトレンドがドメイン駆動設計にとっては重要で、私自身はそう思ってやっているんですけれども、型ですね。

静的な強い型付けで扱う値……ビジネスで扱う値というのは、intとかlongみたいなふわっとした値ではないので、もっと範囲が限定されていたりとか。例えば「金額×金額」なんていう計算はやってはいけません。緩い型だと「int × int」は当たり前のようにできてしまいます。だから、きつい型付け、意味のある用途別の型をいかにうまく使うかが、ドメイン駆動設計のコアな設計スタイルというか。

なので、これはみなさんがどう捉えているかはわかりませんが、私から見ると、ここ5年くらいでLLや動的型付けと言われた言語の勢いは止まってしまって、むしろ今「型をどうやって扱うか」という方向に来ているのは、ドメイン駆動設計にとっては「まあ、それは当たり前だよね」という感じはしてますね。

:ということは、質問の回答としてまとめると、マイクロサービスとか、そういったものが将来的に発展するんじゃないかと。すでに発展はしてますけど、そういったものと、あとは非常に強い型付けを持つ言語が、今後出てくる可能性があるということですかね?

増田:いや、言語としてはそんなに強くならないんじゃないですかね。むしろ、今あるくらいの型付き言語でいいから、そこをもっとうまく使う。自分たちで用途に合わせた型を作ることが、もっと一般的になっていく。そんな流れになってくるんじゃないかと思います。

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

FaaSの進化について

:では、次に行きます。これは丹羽さん向けですね。「サーバレスはFaaSからまだ進化すると思いますか?」ということです。これ以上どう進化するのかわかりませんが、もし進化するならどのように進化すると思いますか?

今はおそらく、最小単位のファンクション自体がサービスとして1つ動いているなかで、「そこからさらに進化するのか?」という質問だと思います。そのあたりはどのようにお考えですか?

丹羽:今の「Function as a Service」って、関数を定義しておくと引数を受け取って返り値を返すみたいに非常にシンプルなファンクションなんですね。ゆえに、その実行環境もどこで実行されるかわかりません。

だからこそスケールするということではあるんですけど、状態がサーバ側で持てない、引数で状態を渡してあげるとか、データベースみたいな領域でやらなければいけないという制約があります。これがFunction as a Serviceの宿命でありつつ、開発を難しくしているところだと思います。

今後進化していくとすると、いわゆるpersistの領域のI/Oが速くなれば……要はグローバル変数やスコープに応じた変数を外部に持てるようになれば、ファンクション自体はすごく並列度を上げられます。

そのpersist領域がどれぐらいI/Oに耐えられるかというところではありますが、そういう外部の記憶領域のI/Oが速くなれば、もしかするとFunction as a Serviceを組み合わせて……今までプログラムの中で「functionがfunctionを呼ぶ」みたいなのって、ごく当たり前に作っていると思いますが、クラスを定義してそのメンバーであるfunctionを定義すると、そのインスタンスのメモリ空間を外部でマッピングして、あたかも1つのプログラムのようにFunction as a Serviceが動き始める、ということが将来あるかもしれないなと思っています。

I/Oがなくなるとどうなるか

:増田さん、いかがですか?

増田:そういう意味で言うと、I/Oがなくなるんじゃないですかね。メモリや主記憶があたかも不揮発であるかのように。アプリケーションを作る人間が主記憶から外部記憶に出したり取り込むというアクションではなくなるのではないかと思います。

これは、別に夢物語みたいなことを言っているわけじゃなくて、このアイデアのもとになっている2つのことをお伝えしておきます。Smalltalkって名前ぐらいはご存じですよね。Smalltalkはそういう環境なんです。ファイルI/Oできないんですよ。メモリをダンプできるだけであって。

だから、Smalltalkはメモリ上のダンプがバージョンアップしていくだけの環境なんですね。メモリしかないんです。だから、Smalltalkの世界で生まれたMVCに「なんでI/Oがないんや?」というのは当たり前の話で、「オンメモリのモデル=それがすべて」なんですね。

ただ実際問題として、コンピュータって電源を切ったら主記憶は消えてしまいます。ですが、今ではIntelが不揮発性のメインメモリを持ったアーキテクチャを商用で出してはいるので、ああいったことが当たり前になってきたり。

もしかしたら今のSSDの技術に対して、OSレベルで仮想メモリのようなかたちで全部扱えてしまうような、アプリケーションプログラマから見たら、主記憶か外部記憶か意識せずにシームレスに使えるみたいなものが出てきたときに、スケールや性能面ですごい世界が来るというか、来たらおもしろいなと思っています。

:そうですね。メモリそのものがそもそも不揮発かどうかという概念がなくなると。

増田:そうそう。

:取り出したいときに取り出せる。そのコストも極限まで下がるというイメージですかね。

増田:今のネットワークがそれに近くなってきてますよね。昔はネットワークにつながってる・つながってないってすごく気にしていたけど、今のスマホではあまり関係なく動いてますよね。

:確かにそうですね。

増田:だんだん、そういう外部記憶の実行環境というものが、なんというか、分離というアーキテクチャが……少なくとも論理的なアプリケーションレベルから言うと、だんだん薄れてくるんじゃないですかね。

:ありがとうございます。この質問に対しての回答をまとめるとすれば、ファンクションという括りよりも、ファンクションそのものが1つのプログラム、一塊のプログラムになるようなかたちで進化すると。

丹羽:いや、もっと高レベルになると……。今作っているようなモノリスなプログラムをデプロイすると、それがFunction as a Serviceとして動くみたいなイメージですかね。要は関数から関数を、普通にプログラム書いているんだけど、実行時に分解されて……。

:ああ、あるほど。

丹羽:はい。ファンクションを呼び出すということは、別のコンテナが起動してそこで実行される、みたいなことになるかもしれません。

:なるほど。

増田:オブジェクトが勝手にあちこちにデプロイされちゃって、通信し合う感じですよね。

:それは本当に次の世代ですね。

増田:Kubernetesなんか、ちょっとそれに近いかな。

足を引っ張っているメンバーがいたらどうするか?

:赤にしたんですけど、これはあるかもしれないし、ないかもしれませんが「開発チーム内に、明らかに足を引っ張っている人がいて困っています。どうすればいいですか?」というお悩みです。どう足を引っ張っているかは質問の中から想像するしかありませんが、これについて両氏はどうお答えになられますか?

(丹羽氏が増田氏にマイクを差し出す)

増田:いいの? 俺から言っちゃったら、次に話せなくなるかもしれないよ。大丈夫?

丹羽:大丈夫です。なんとかします(笑)。

増田:足を引っ張っているかどうかというのは事実じゃなくて主観なので、「主観の問題だよね」というのがまず1点。その主観を受け入れたとしたら、僕は選択肢は2択だと思っていて、その人を辞めさせるか、自分が辞めるかしかないと思う。

:なるほど。

増田:要するに、チームでなんとかしようというのであれば、「足を引っ張ってる」という主観をなくすところから始めないと、おそらくなにも解決しないような気がします。「足を引っ張ってる」という主観を持ってしまった瞬間に、選択肢は相当狭まるんじゃないかな。

:つまり、この質問者の方のものの見方をどちらかに寄せるしかないと。

増田:いや、どちらかというか、「そうは言ったって私から見たらどうしても足を引っ張っているようにしか見えません」と言うんだったら、それは切るか、自分がいなくなるかという選択肢しか残らないんじゃないかな。

:なるほど。

増田:足を引っ張ってるんじゃなくて「彼はあることをしてくれている」と見れば、じゃあもっとそこでパフォーマンスを出してもらおうとか、あるいは「彼はいいことをやってくれてるんだけど、ある部分は僕にとって邪魔になってる」みたいなことがあるのであれば、そこで「邪魔をしないでほしい」というところを交渉するか。だから、やっぱり主観だと思うんですよね。チームの評価というか。

丹羽:私、わりとスタンドプレーでいろいろやってきて、チームで開発をする経験ってあまり多くないんですが、当然人によってパフォーマンスが違う部分があるのは確かなんですね。ただ、それが速いからいいという話ではぜんぜんなくて。速くても品質がよくなければダメだし、ゆっくりでも品質がすごくいいものを出してくる人もいるわけですから、「引っ張ってる」というのが、どういうベクトルかによると思っています。

実際、私はわりと手が速いほうではあるんですけど、アウトプットにわりと穴があるタイプなんですね。私が最初に採用したメンバーは、ゆっくりなんだけど穴はしっかり塞ぐタイプ。「私が穴を開けたところを塞いでもらおう」みたいな(笑)、そういう考え方でやっているので、そもそもチームを作るときに「どういうメンバーなのか?」という特性を考えるのが大事だと思います。

これは現場レベルではどうしようもないので、マネージャーレベルがちゃんとしたチームを作れていないのであれば、先ほど増田さんがおっしゃったように、自分がマネージャーでないのであれば自分が去るしかないのかなと思います。

:なるほど。お互いを補い合う環境やチーム構成であれば幸せだし、そうじゃなかったとしたら、「そもそもこの考え方そのものが主観だよね」というところで、その主観を正すのか、もしくはそのまま自分が去るのか、どっちかにしましょうと。

増田:先ほどは突き放したような言い方をしてしまったかもしれませんが、私はチームを任されて、お客さんと約束して、ビジネスとして開発したことは何度もあって、そのときはもう待ったなしに切ります。結果が出せないのであれば。

:なるほど。

増田:私にとってチームがいいチームになるかどうかは、少なくともお客さんとの契約においてはぜんぜん重要ではありません。ただし、それがギスギスしたり非人間的な活動をしたかというとそうは思っていなくて。ものを作るのは楽しかったし、自分たちでいろいろな意見をぶつけ合うこと自体は、ストレスでも心理的に不安な状態でもなかったですし。

ただし、チームとして成果を出すことに関して言えば、同好会やお友達ではないので、なにかと制約や判断基準がある。チームを預かる立場だったら、「結果を出すにはどうすればいいか?」というところから考えていく、判断していくということは実際に何度もやってきていますよね。でも、ブラックだとか、よくないと思ったことはありません。

:ありがとうございます。これは、このへんにしておきましょう。

増田:(笑)。

開発における方向性を定める方法

:次は増田さんの件ですね。「ドメイン駆動設計を取り入れているのですが、各自の知識や方向性がバラバラです。どこまでやればいいでしょうか?」。これは「どこまで揃えればいいのか?」という質問だと思います。

おそらく、設計レベルで留める人や行動レベルまでやってしまうというところ、もしくはDDDの本をバイブルにして実践を忠実にやろうとか、1つのことをやるとしても、どうしても方向性がバラバラになってしまうという質問だと思います。この質問に対しては、どうお答えになられますか?

増田:方向性がバラバラというのは実際にそうで、私も相談を受けたり、実際に自分でチームを率いて作らなければいけないときに必ず起きる問題です。

いくつか話をしておくと、まず「動けばいい」という価値観と「動いているだけじゃなくて、もっといい設計しなきゃダメじゃん」という価値観のぶつかり合いは、早めに解消する必要があります。価値観がぜんぜん違うんです。

エンジニアには「動けばいい」とか「動いているものをなんで変えなきゃいけないんだ?」という価値観を持っていらっしゃる方も相当数いるので、その中でドメイン駆動設計をやろうとすると、それはもう絶対成立しません。

ドメイン駆動設計は「将来なにか拡張が入ったときに、楽に安全に実装するまえに、どんな工夫をしておけばいいんだろう?」とか、そういうところにエネルギーをかける。それと「動けばいい」という価値観とでは、どうしても一致しません。ですので、まずはその部分の意識合わせはすごく大切です。

これは公式にやる必要はないです。僕はソフトウェアを作っているんだったら、動けばいいと思っていますが、「動いていいとはいえ、もうちょっといいやり方があるよね?」みたいに思うかどうかがバラバラでは、チームの支えにならないんじゃないかという気はします。

あとは、「よくしようよ」といったときに、「いや、俺はこっちのほうがいいと思う」とか「こういうやり方がいいと思う」というところで、方向性は一致しているけれど、Howとか、どのレベルまでやるか、どこをやるかがバラバラということもあると思います。

それに関しては、ある意味では非常に難しいですが、濃淡をつけたりメリハリをつけるということを議論するべきですね。よくないのは、とにかくなんでもフラットに、同じようにしようとか、思考を停止して「こういうパターンだから、あっちもこういうパターンにしよう」みたいな考えで、それとは絶対に戦うべきです。「やるべきところや、やったら価値がありそうなところって、ここだよね」ということを合意して進めることが大切です。

タイムボックスを有効活用する

増田:私は、ワークショップをやっているときに意識的にしていることがあります。3人1チームで、だいたい45分ぐらいで1レッスンなんですが、事前に「3人の結果を45分後に出してね」と。「それぞれの意見で、個人としてはもっとこっちのほうがいいと思うのがあるだろうけど、3人として結果を出すことにフォーカスしてやってくださいね」ということをきちんと強調してやってもらう。みんなそれなりに意見交換した上で「じゃあ、いったんこういうかたちにしようか」って、わりと決まるんですね。

だから、タイムボックスを切って、「タイムボックスが出たときに成果物を出す」「意見がバラバラのままでタイムボックス切れというのはありえないよね」というところだけ合意できれば、あとはどうやって合意するかは、あまり大した問題ではない気がします。

:なるほど。なにかしらの成果や方向性は合意によって定まるのではないかというお話ですね。それでは、丹羽さんお願いします。

丹羽:すごく話しにくいお題なんですけど、私もサーバレスでアプリケーションを作っていると、サーバレスに対する知識の差は人によってあるので、じゃあそこをどうやって穴埋めしようとしているかというと、基本的にコードの自動生成を進めています。

そうすることで、テンプレートから出てくるわけなので、「テンプレートが正しく設計されていれば、アウトプットの品質がある程度一定になる」ということを心がけてサービスの開発環境を作っています。

:なるほど。じゃあ丹羽さんのお答えとすれば、「ある程度、環境で縛る」という話ですね。ありがとうございます。