YAMADA TAISHI’s diary

ゲームについてとか私の日記とか。このブログのあらゆるコードは好きにどうぞ。利用規約があるものは記事内のGitHubのRepositoryのリンクで貼られていると思うので、そちらを参照ください。

「オブジェクト指向はしっくりこない」とは言わせない

こんにちは、やまだたいし( やまだ たいし (@OrotiYamatano) / Twitter )です。
今回は設計についてちょっと書いておこうと思ったので、記事化することにしました。

目次


今回のお話の結論


オブジェクト指向は悪じゃないし、
オブジェクト指向でつくるなら、開発段階やチームの状況に応じて適した形に変えてきましょうよって話。

オブジェクト指向がふさわしくないという議論


ゲーム業界界隈では度々オブジェクト指向はふさわしくないという議論が持ち上がる。

soysoftware.sakura.ne.jp

オブジェクト指向は昔に作られ古くなってきたプログラミングパラダイムだということは否定しないが、必ずしも悪くないと私は考える。

確かにゲームのプログラムは業務システムと違う部分が多く、
世の中の設計パターンがあわないことが多い。
しかし、考え方は多く適用出来る部分はある。

技術書を通して学ぶべきは方法論ではなく、考え方であると言いたい。

オブジェクト指向についての議論


最近、DDDやオブジェクト指向、クリーンアーキテクチャに違和感を覚えるというのを見かけることが多い。

hachibeechan.hateblo.jp

hadashia.hatenablog.com

nowokay.hatenablog.com

これらのブログについて私が言いたいのは、半分はそうだし、
もう半分はそうじゃないと言いたい。

まずはゲームにおいてDDDを全部採用するのは間違いであると言いたい。
もちろん、ゲーム界隈はこれまで設計の概念が薄く、先に進んでいるWeb業界を真似てみようという動きはすべて間違いとは言わない。

弊ブログでもMVPについて取り上げている。

orotiyamatano.hatenablog.com

しかし、全部を真似するのは間違いであると言いたい。
特にDDDを参考にするのは間違っている。

DDDの認識


DDDを知るのにあたって私はエヴァンス本を読むことをオススメしている。
エヴァンス本翻訳が分かりづらいが、それでもである。
具体的にどのように適用するかはドメイン駆動設計入門などで十分なのだが、
DDDを学ぶ上でエヴァンスさんの思想に当たる部分が抜けているのが気になる。

設計の本を書くミノ駆動さんも誤解されるような書き方をしてしまっている。

↑これに関して言えば、この方↓のツイートが正解といえる。

そもそもエヴァンスさんは業務系アプリケーションをつくるのにあたって、
世界各地でハチャメチャに設計されているのをなんとかしたいという意図で、
DDDというものを編み出し本にしたのだ2004年に。
しかも、結構自信がなさそうに書いているポイントがあったりする。
自信が無いんだなと思って読めば重要ではないと一蹴出来るポイントもあるが、他の解説本はそういった言葉じりは削除されてしまっていることもある。

そもそもドメイン駆動開発はドメインの専門家からの入力に従ってドメインに一致するようにソフトウェアをモデル化することに焦点を当てることだ。

ミノ駆動さんのクラス図はちょっとズレている。
DDDとは業務知識とか実際にある工程などをドメイン化して落とし込むもの。
なのでラーメンの製造工程だったり、ラーメン屋の接客対応などといったものからはドメイン化出来るが、
ラーメンの構成要素をドメインオブジェクト化するのは何か違う気がする。
コンポーネント指向ではありそうだけど。

オブジェクトとしてドメイン化するにしても
例えば一般の会社では
ボールペンは消耗品や備品の一つようにモデリングできるが、
文房具屋ではボールペンは商品の一つのようにモデリングできる。
同じ物体でも、このように扱う専門家によってどのようにモデル化されるかが変わるので、ユビキタス言語策定が必要になったりする。

(これだけがDDDではないが)このような話がDDDである。

それをゲームに適用しようとする方々がいたりする。
私は疑念を抱かざるを得ない。

もしDDDをやりたいと言う人がいるならば「ほう……聞かせてみてくれ」っていうと思う。

そもそもゲームの内容をDDDとして設計するのは文脈として変だからだ。
設計する上でゲームは業務システムでもないし元となる業務フローなんかもないのでモデリング出来ない。
無理にDDDに当てはめようとすると破綻すると思われる。
ゲームでDDDをするとなれば、なにかその人が思うドメイン概念の抽象化作業、モデリング方法が存在することになるはず、
一体全体どう落とし込むつもりなのか聞いてみたくなると思う。
私には正しく落とし込む方法は思い浮かばない。

しかし、DDDはゲームに相応しくないと考える反面、
ドメインを定義するという考え方自体は非常に参考になるとは思う。
ドメインとは違うがゲームにおいて責務の単位はどれに該当するかと試行錯誤することは必ずしも間違いとは言えない。

他設計手法についても……


他設計手法についても同様のことがいえる。
WebのようなViewからのレスポンスがキメられた値だったら話は別だが、
ゲームの場合は見えているもの自体がオブジェクト本体であるので、ViewとModelは切り離すことが出来ない。
また静的な挙動ではなく、ゲームは常にシステム内の時間が遷移し、ほとんどが静的なオブジェクトで構成されているWebやシステム系アプリケーションとは話が違う。

クリーンアーキテクチャ本の話の厄介さはソコが起因してくる。
クリーンアーキテクチャ本は後半はゲームに適用できない設計や手法の話になるが、
前半においてはかなり適用できる部分が多い。

業務開発手法をゲームに適用しようとするのは簡単に言うと、デザインパターンがなぜそのようなデザインパターンになったのか知らずに闇雲にパターンを適用しようとするのと同じだ。

オブジェクト指向がふさわしくないという議論


オブジェクト指向がふさわしくないという議論、これに反対していこうと思う。

soysoftware.sakura.ne.jp

nowokay.hatenablog.com

何度もいうが、オブジェクト指向自体が古くなってきたプログラミングパラダイムだということは否定しないし、新たなプログラミングパラダイムが出てきて相応しいのがあるのかも知れない。
だが、少なくとも現状オブジェクト指向が駄目だから手続き型に戻ろうというのは可笑しな話であると言いたい。

そもそも上2つの記事であげられている部分で議論の論点になる部分は抽象化、レイアリングされすぎたクラス設計が嫌だということなんだと思う。

正直私は言いたい。

クラス統合しろ!!!!
レイアリングが間違っているんだ。

そんなことをしても良いのか?と思う人がいるかもしれない。
だが、槍玉に上げられるクリーンアーキテクチャ本にはしっかり丁寧にどうすべきか書いてある。

ちゃんと読め!!!

クリーンアーキテクチャではなんと言われているのか


そのクリーンアーキテクチャ本ではどのように触れられているのかというと
凝集性というワードが重要になってくる。
簡単に言うといろんな実装がクラスにまたがってしまい、読みづらいコードは凝集性が低いといえるし、クラス内に手続き的にギュッと集まったコードは凝集性が高いと言える。

皆、何故か図が好きなようなので本から抜粋して下に貼っておく。
(クリーンアーキテクチャが槍玉に上がるとき円の図がよく貼られるよねw)

これらを一言で説明すると、こうだ。

● 再利用・リリース等価の原則(REP)
再利用性を高めるためにクラスまとめろ
● 閉鎖性共通の原則(CCP)
保守性を高めるためにクラスまとめろ
● 全再利用の原則(CRP
関係ないクラスと繋がり持つな。分割して再利用性高めろ(インターフェース切るのもここ)

上のブログでは↓のように述べられているが、それはCRP寄り/REP寄りになってしまっているということだ。

オブジェクト同士の連携でプログラムを組むと、コードが飛びまくって追いにくくなります。そして単一責務の原則により、小さいクラスが大量に生成されて、追いにくさがさらにあがっていきます。

超簡単に言うとクラス分けし過ぎ。

ホンマにそれ責務単位なの?
私は責務というのは、DDDが言うようなドメインとかじゃなく、
個人的にはクラスの変更の単位に依存すると考えていて、
一つの機能変更で多くのクラスを見る必要や変更の必要があるならまとめてしまったほうが良いと考える。

凝集性が低いと開発中、さまざまなコードを見に行く必要があり開発し辛い。

クリーンアーキテクチャ本では更に
抽象度が高くなる方向に依存すべき だが、コンポーネントの安定度や抽象度はきちんと区別できるものではない(p.167 要約)」というような感じで書かれているが太字部分が読まれすぎていて「コンポーネントの安定度や抽象度はきちんと区別できるものではない」 という部分がしっかり読まれていないような気がする。

しかも、クリーンアーキテクチャではこれの解決策が回答されている。
抽象度と安定度を数値化し、それを元に直せという。

私はゲームプログラマーなのでUnityに例えさせてもらう。

例えば
Unityのワンクラスで完結させるような実装は
ゲームオブジェクトなど他を参照しまくるが外部への依存は0なのでI = 0 / (20 + 0) のような式になってInstabilityが0
UnityのコンポーネントクラスはInterfaceで実装は基本無い?はずなのでA = 0 / 20 みたいな式になってabstraction(?)が0
結果

0 抽象度(abstraction?):,0安定度(Instability)

で苦痛ゾーンになる。
まぁ再利用性に欠けるって言うこと。

こんなアドバイスをくれつつも、こう↓とも記している。

この三角形のなかで開発チームの現在の懸念事項に見合った落としどころ を 見つける。 それだけではなく、時がたてばチームの懸念事項が変わるということも心得ている。 たとえば、 開発の初期段階なら再利用・リリース 等価 の 原則(REP)よりも閉鎖性共通の原則(CCP) のほうがずっと重要になる。 再利用性よりも、 開発しやすさのほうが重要だからだ。

極端に言えば、Unity1Weekなど作ることだけに重みを置くプロダクトはクラス数少なくてもあんま問題ないってわけですね。

コンシューマーのような作りきり案件ではCCP重視でいいけど、スマホのような運用案件ではREPは重視した方がいい。
(とはいえ、コンシューマーであっても機能を次のゲームに活かすことはあるとは思うで、CCPだけ重視は辛いと思う)

私はオブジェクト指向のSOLID原則や抽象化が神格化され過ぎた結果、凝集性の低いコードがはびこり、オブジェクト指向はしっくりこないと言われるのが増えているのではないかと推測する。

つまり何が言いたいのか


現状オブジェクト指向でつくるなら、開発段階やチームの状況に応じて適した形に変えていけば問題ないと思います。

開発段階であれば、CCPもとい保守性を高めるためにクラスまとめることは悪じゃありません。
とはいえ、開発中も保守が発生します。
プロダクトが完成に近づくにつれ徐々に凝集性→保守性にシフトした作りに柔軟に変えていけることこそが重要です。

つまり、「オブジェクト指向が悪」って言うのはちょっと違って、
「クラスを変更し実装変更することが出来ないプロジェクトが悪」です。

かくいう私も理想からは遠く悩んでばかりですが、余裕ある実装が出来るように皆さん頑張って共々一緒に理想の設計を追い求めて行ければなと思います。

まとめ


・業務アプリケーションとゲームは違う
・設計パターン本や設計本は手法じゃなく思想を学んで欲しい
オブジェクト指向の抽象化に囚われすぎないで欲しい
オブジェクト指向でつくるなら、開発段階やチームの状況に応じて適した形に変えてきましょう

以上、やまだたいしでした。