合同会社EXNOAとは

岡崎翔悟氏:今回「Goとクリーンアーキテクチャ」と題しまして、EXNOAの岡崎が発表いたします。

「EXNOAって何だ?」と思われた方が多数いらっしゃると思うので、まずはそちらの説明から。DMM GAMESは2020年4月10日付でEXNOAに社名を変更しました。ただし、一般作品のブランド名として「DMM GAMES」は残っています。一般作品の「DMM GAMES」とR18作品の「FANZA GAMES」。それらを運営するEXNOAをどうぞよろしくお願いします。

会社の説明を先にしたので、次は自己紹介をします。岡崎翔悟です。合同会社EXNOAのプラットフォーム開発本部、PFシステム部のWebグループで、「Shark」という名前のバックエンドに所属しています。役職とかはありませんが、テックリードっぽい立ち回りのポジションです。

17新卒として、まだDMM.comラボだったときに入社しました。それから分社化したり、社名が変わったりしています。愛称は「邪神」です。

今日のアジェンダなんですが、Goでクリーンアーキテクチャの思想を活用して開発している話をしようと思います。内容は「技術選定」と「クリーンアーキテクチャとは」「Goとクリーンアーキテクチャ」。あとGoでの実際の開発について話していこうかなと思っています。

Goでクリーンアーキテクチャを実践するまで

まず技術選定から。Goでクリーンアーキテクチャを実践してみようと決めるまでの要因を話していきます。

今回の対象は、弊社のゲームプラットフォームのWebシステム。これを簡単に説明すると、一般的なWebサービスとゲームデベロッパー向けのAPIを提供しているサービスだと思ってください。ゲームデベロッパー向けのAPIとしては、課金や会員とかを提供するゲームプラットフォームがもっているような機能です。

特徴は、ゲームプラットフォームあるあるだと思うんですが、イベントやヒットしたゲームが登場すると高負荷になったりします。最大で4,000req/sぐらい出たこともありました。

あとは、PFシステムから見た際に、にお客さんとなるようなアクターが多い。これはシンプルにゲームで遊んでくれるユーザーさんだけではなく、ゲームデベロッパーさんもPFシステム部から見たらお客さんに含まれます。あと自分の会社にいるPFシステムを運営する側の人たちも、PFシステムのエンジニアから見たらお客さんの位置づけです。

現在抱えている問題もあります。それは、DMM GAMES、FANZA GAMESは長くサービスを続けられているので、全体的にシステムの老朽化が進んでいる問題です。

他にも、画面主導にリポジトリを構成しているので、ドメイン駆動設計ができていない部分があります。

モノリシックな開発で今までは済んでいました。しかし限界が近づいてきていて、ドメイン駆動設計をやってマイクロサービス化しないと成長できない段階に来たと考えています。

あと、フロントエンドとバックエンドが密結合状態です。そこの解決には、フロントの開発にバックエンドのエンジニアを巻き込む必要があると思っています。

今は基本的に運用はオンプレです。今後はクラウドサービスとかも利用したいので、クラウド移行も進めていく必要があります。

そこで技術的な解決手法として、クラウドネイティブにやっていくためにコンテナ化する。Dockerに準ずる技術を使ったり、コンテナオーケストレーションツールを使ってマイクロサービスを実現していく。今はデファクトスタンダードになっているのはKubernetesですかね。

ドメイン駆動設計という思想を取り入れて、うまくマイクロサービス化していこうと考えています。

クリーンアーキテクチャは何を示すのか

次はクリーンアーキテクチャの話です。Goの話はちょっと待ってください。まずクリーンアーキテクチャは何を示しているのかを説明から。

この図をみなさん1回は見たことあるんじゃないかなと思います。この図はあくまで具体例の1つであって、この図を守ることがクリーンアーキテクチャの本質ではありません。

緑の部分のControllersやUse Cases、Entitiesだったりを分離しなさいとか、レイヤーを図のように4分割しましょうといったものではありません。そこが本質ではないという話です。

重要なのは関心の分離。この関心の分離を実現するために何が必要なのかというと、各レイヤーの依存ルールです。

図で重要なのは矢印のベクトル。始点と終点とその向きがどう向いているのかが重要で、始点が外側の円で、終点が内側の円で、外から中に線が向いています。これはクリーンアーキテクチャの本から引用すると、依存性は内側、上位レベルの方針だけに向かっていかなければいけません、ということです。

クリーンアーキテクチャの具体的なアーキテクチャ。例えばレイヤードだったりヘキサゴナルだったりオニオン。そのほかにもあると思いますが。関係性と言ったら、これらのアーキテクチャはどれも詳細の細部は異なりますが、よく似ています。

これらはいずれも同じ目的をもっていて、それは何かというと関心の分離です。これらはどれもソフトウェアをレイヤーに分けて、関心の分離という目的を達成しようとしている。その具体的なアーキテクチャをいっている思想です。

アーキテクチャのルールはどれも同じ。これはアーキテクチャの本の引用で、日本語版だと日本語で表紙にデカデカと書かれています。

関心の分離で得られるもの

先ほど関心の分離が一番重要だと話しました。しかし「それによって何が得られるの?」というと、5つ得られるものがあります。

1つ目はフレームワーク独立です。フルスタックなフレームワークを必要としないし、依存もしない。

2つ目がテスト可能。テストが重要なことは、みなさん重々承知かと思いますが。これは単に可能というわけではなくて、外部の要素に囚われずにテストできるということです。ユニットテストで、たいていその中で閉じられる。E2Eテストとかは全部やらなくてもテストができることになります。

3つ目はUI独立。ビジネスルールの変更なしにUIを置き換えられます。これはUIと聞くとデザインだけみたいなイメージをもたれるかもしれません。例えばリクエストのレスポンスをHTMLでレンダリングしたものを返していたが、やはりJSONで返したい。JSONの送る先は「フロントエンドチームが結成されたのでそっちにデータを送ってください」みたいな場合でも、ビジネスルールは変更しなくても変えられます。

4つ目のデータベースの独立は、データベースを容易に交換することが可能。これもビジネスルールと分離されているので、容易に交換できる話です。

5つ目は外部機能独立。これはビジネスルールは外側についてなにも知らなくていい。先ほどのクリーンアーキテクチャの説明の円や矢印の説明を文字にしたような形です。

これは、まさに邪神が求めていた力なんですね。

Goはクリーンアーキテクチャの思想を活かせるか

やっとGoとクリーンアーキテクチャの話に突入します。内容は、Goはクリーンアーキテクチャの思想を活かせるかどうか。

はじめに言っておくと、クリーンアーキテクチャは、特定の技術や言語などには依存しません。他にも特定のプログラミング言語やフレームワークに依存することもないです。

ただし、フレームワークの選び方については、気をつける必要があります。なぜかというと、関心と分離の利点でお話しした、フレームワーク独立という思想に反してしまうからです。なので、フルスタックのフレームワークを選定すると、そこのルールに引きずられてしまうのでフレームワークとは馴染まないかもしれません。

あと、Goは基本的に標準パッケージで事足りるようにする思想です。この点がクリーンアーキテクチャと親和性が高いところかなと思っています。フレームワークといっても薄いものが多くて、特定の機能だけがほしい場合。そのフレームワークを選べばその機能だけが提供されて、組みやすいです。

ちなみにGoを選択した理由はこれだけありません。でも、今回の題材で、これ以上Goでどうという話をすると、収拾が付かなくなりそうなので割愛させてください。

これは実際にクリーンアーキテクチャで組んでみたようなディレクトリの構成例です。Goはパッケージ内でプライベートになります。4つの階層(entities、usecases、interfaces、infrastructure)があり、この中ではプライベートで、その中では自由に呼べます。ただし、層を跨ぐときは呼べません。

1リポジトリの中に複数サブドメインがあるような場合も、今はapplicationの下に4階層が普通に並べられています。「いや、なんかこのアプリケーションは、AドメインとBドメインを組み合わせてなんかやらないような、大きなドメインなんですよね」みたいな場合。applicationの下にもう1つ階層を作って4階層を置いていくか、ドメインが区切れているんだったらリポジトリを最初から分ける。この2択になるのかなと思います。

関心を守るための依存ルールを守った境界のまたぎ方についてです。例としてよく言われる「依存関係逆転の原則」を使ってGoで書く際は、インターフェースを利用します。

普通に呼ぶと、リポジトリから普通にSQLHandlerを呼んでしまう。こうすると依存性の向きが逆転してしまうので、インターフェースを噛ませて依存性の向きを逆転させてから、正しい向きに直す感じです。

Goを使った開発のメリット

次はGoを使った開発について。僕らがチームで開発していての感想などを話していこうと思います。

Goを使った開発で、一番僕がいいと思ったのは言語として提供されるフォーマットがあること。複数人で開発していても、ちゃんとLinterかけてもらえれば書き方の差分が出ない点は素晴らしいです。

あと、言語として提供されるパッケージ管理。Go Modulesが出てきてから管理については、一切考えなくて済むので便利です。

あとは後方互換性の高さ。今日も更新があったのかな? ちゃんと互換性をもったマイナーバージョンアップをするので、特に書き直しが必要なアップデートは今まで経験したことがありません。

チームで開発していてけっこう簡単に覚えられるので、学習コストも低いかなというイメージをもちました。やはり難しいのは設計やアーキテクチャを考えたりドメイン分析するところですかね。そういうところに時間を使えるので、学習コストの低さはチームとか組織で開発する時にはメリットになりうるかなと思っています。

今はけっこう激動な時代かなと僕は思っていて。多種多様なアーキテクチャとか言語とかありますが、そこから選定しないといけない場合が増えたと思っています。今は、多種多様なアーキテクチャが存在している時代です。メリットが享受できないのに、何でもできるようなフルスタックなフレームワークを使うと困るようになったのではないでしょうか。

あとRDB以外にもいろいろなデータベースが使える時代になりました。AmazonのDynamoDBを使ったり、Cloud Spannerを使えたり。そういう高機能なデータベースがクラウドサービスの登場によって簡単に高パフォーマンスで利用可能です。昔は難しくて、自分のオンプレでは運用できなかったようなデータベースを簡単に運用できるような時代になりました。

グローバルにビジネスを展開する上で分散システムとかを使うときがあると思います。現状ちょっとつらいところもありますが、これもクラウドサービスによって手軽に利用できる時代になってきました。AmazonのKinesisやApacheのKafka。このApacheのKafkaもフルマネージドのサービスで使えたりもします。

ほかにも、フロントエンドとバックエンドの分離。いろいろやってみたという事例をたくさん聞くようになってきました。バックエンドは単に永続層からデータを取って、フロントエンドにデータを渡すだけ。フロントはよりリッチなUIを提供するためにがんばって分離するという例も、比較的増えてきたのかなと思っていますね。

弊社のビジネスの特性上、こういったものを利用していく場合が増えてきたのかなと実感しています。

Goとクリーンアーキテクチャの相性は、個人的にはけっこういいのかなと思っていて。なぜなら、薄いフレームワークを組み合わせるときにGoの思想がマッチしているからです。仮に失敗してもクリーンアーキテクチャで組んでいれば差し替えが可能なので、メリットはあると思っています。

あと、僕の個人的な感想なんですが、DIPについてよくわかっていなかったということがちょっと露呈してしまいました。「インターフェースって実際どう使うんだ?」と最初はなっていましたし。

Goの基調講演の話で、Goの目的について話をしていて。GoogleがGoを作った目的は、プログラミング言語の設計に関する研究を行うのではなくて、設計者とその同僚の作業環境を改善することですという内容。

こういう視点は組織で開発する上で重要になっていて。4年目の僕がテックリード的に何かプロジェクトを遂行するときは、こういう思想をもった言語を使えることは大きなメリットであると思っています。

Goとクリーンアーキテクチャの使い方

クリーンアーキテクチャは関心の分離を求める思想です。具体的なアーキテクチャではなく、共通ルールとしての知恵を授けてくれます。人類は万能な答えを欲しがりますが、そこに価値はないのかもしれません。

「クリーンアーキテクチャをやったほうがいい?」という疑問があるのかと思います。この質問はおかしくて、「一切関心を分離しなくていいシステムって存在するのかな?」について考えると、この質問は出てこないかなと思っています。

あと「フルスタックなフレームワークはダメなの?」の疑問については、そんなことはありません。MVCのリッチなフルスタックなフレームワークで価値を出せるときもあると考えています。揃っているから便利だし、それでビジネスを遂行できれば価値を生み出すことはできるのではないでしょうか。

あと、激動の時代に生まれたGoという言語は、クリーンアーキテクチャと親和性が抜群で、クラウドネイティブな開発への親和性が高いです。

あと、クリーンアーキテクチャとか設計原則だとかデザインパターンは人類の英知だと思っていて。「こうやるとヤバかったからこうした」とか「こうするとうまくいったよ」などが、うまくまとめられたものだと思います。

ただ、結果だけを追い求めず、生まれた背景も考えるようにしてください。それを把握をしておかないと、逆に操られてよくわからないことになってしまうかなと思っています。

書籍の『Clean Architecture』にはエンジニアの歴史の話が出てきて、「穴あけパンチでプログラムのコードを書いていたよ」という背景も登場します。

そういった背景は、本当に今のモダンなWebサービスから見ると「そんなのどうでもいいんじゃない?」みたいな意見も当然あると思いますが。しかし、書籍からでないと、そういった背景を知ることができません。こんな思想で「プログラミングのパラダイムが変わってきたんだな」みたいなことが知れるのもいいかなと思っています。

これは、クリーンアーキテクチャの中の1個の思想です。具体例とかをこの本に求めるのは、間違いかもしれません。あと、DDDやオブジェクト指向は、こういう知識の上に成り立っているので、歴史的な部分も勉強していくことも大切かなと思っています。

発表は以上です。ありがとうございました。