PONOS Advent Calendar 2024の5日目の記事です。
はじめに
システム開発を俯瞰してみた時に様々なソフトウェア設計原則が存在しています。
コードや設計レビューで「SOLID原則に反してます」といった話が上がることはよくあることかと思います。
では、そのさらに一段上がったところで、もっと根本的な設計ではどんな話をされていますか?
ものすごく今更な話ですが、ゲーム開発においても「ゲームのサービス化」とも言える、長期的なコンテンツ提供の場へと変化してきています。
であれば、(言うまでもないですが)他の同じような長期運用型のシステム開発におけるノウハウを取り入れることも重要だと思います。
ソフトウェア設計における一般的な原則
まず、代表的な設計原則をすごく雑な説明で並べてみます。
(詳細な説明は目的ではないため省きます)
SOLID原則
拡張性、保守性の向上など。主にクラスやクラス間の設計について視点が置かれている。
原則 | 名称 | 概要 |
---|---|---|
SRP | 単一責任の原則 | 一つのクラスは一つの責任だけを持つべき |
OCP | オープン・クローズドの原則 | 拡張には開いていて、修正には閉じているべき |
LSP | リスコフの置換原則 | サブタイプはそのスーパータイプと置換可能でなければならない |
ISP | インターフェース分離の原則 | クラスは必要のないインターフェースに依存すべきではない |
DIP | 依存関係逆転の原則 | 高水準のモジュールは低水準のモジュールに依存すべきではなく、かつどちらも抽象に依存すべき |
パッケージ設計の原則
コンポーネント(モジュールのようなデプロイ単位)の設計について視点が置かれている。パッケージとしてみても粒度の差はあれどそれほど違和感ない。
凝集性
原則 | 名称 | 概要 |
---|---|---|
REP | 再利用・リリース等価の原則 | 再利用レベルはリリースレベルと一致すべき > いつも一緒に使うなら一緒にまとめて |
CRP | 全再利用の原則 | パッケージ内のクラスは、それら全てが再利用される場合にのみ一緒にグループ化されるべき > 関係ないものを入れるな |
CCP | 閉鎖性共通の原則 | 同じ理由で変更されるクラス群は一緒にパッケージされるべき > 同じ理由で変更が必要になるものはまとめて |
結合性
原則 | 名称 | 概要 |
---|---|---|
ADP | 非循環依存関係の原則 | パッケージ構造は循環的な依存関係を持つべきではない > パッケージが循環参照してたら独立したリリースが困難やん |
SDP | 安定依存性の原則 | 安定度の高い(抽象度の高い)方向に向かって依存しろ > 変更が多いものにあまり変更すべきでないものが依存してたら変更しにくい |
SAP | 安定度・抽象度等価の原則 | パッケージの安定性はその抽象度に比例するべき > 抽象的なものは安定しており、具体的なものは不安定だ |
ともかくここで言いたいのは、これらの設計原則がソフトウェアの構造に対してある種の普遍的なガイドラインとして機能していると言うことです。
一方、現実のプロダクトというのは どのような構造が望ましいか という事だけでなく、現実的にどのように運用されるか という事は重要です。
ライフサイクルという視点
例えばペースレイヤリングというものがあります。
ペースレイヤリングとは建築における構成要素について、変化のしやすさを6層に分けて、生活の変化などの要素によってどのように影響され、変化していくかを分析をして提唱されたものです。
建築におけるペースレイヤリング
レイヤー | 建造物 | ライフサイクル |
---|---|---|
Stuff | 日用品などのオブジェクト | 数日、数週間 |
Space Plan | 部屋のレイアウト | 数ヶ月 |
Services | 機能/設備 | 数年 |
Skin | 外装 | 10年 |
Structure | 構造 | 数十年~ |
Site | 土地 | 数百年~ |
当たり前のことですが、日用品よりも家の構造を変える事は難しく、家の構造を変えるとそれより上位のレイヤーは全て影響を受けてしまいます。逆にいえば上位のレイヤーは下位のレイヤーに依存しています。
私がこれを重要だと思うのは、これが 現実的なライフサイクルを想定した 「変化のしやすさ」によって、示唆を与えてくれている点です。
"安定性/変動性" は "抽象性/具体性" と並べて語られることが多い ですが(なぜなら抽象的なものほど安定しているから)、今回の文脈においては抽象性との関連性とは別に、時間軸による変動性のみに着目している事も大事だと思います。
企業アプリケーションのペースレイヤーモデル
例えば企業のためのアプリケーションではこのようなレイヤリングがあります。
レイヤー | ライフサイクル | 内容 |
---|---|---|
革新システム | ~1年 | 新たな要件や機会に対処するたの特別なアプリケーション。カスタム開発する価値があるかも。 |
差別化システム | ~5年 | 他社との差別化を実現する、企業固有のプロセスを実現するもの。ベスト・オブ・ブリードなシステム構築が良い。 |
記録システム | ~20年 | 企業の重要なマスターデータで、ほぼ共通化しており変化はしない。逆に成熟性、堅牢性が求められる。 |
ここでは変更の頻度やそのシステムの特性に応じて、適切な開発・運用手法を示唆しています。
ゲーム開発のライフサイクル
本題です。これをゲーム開発に置き換えてみたいと思います。
先に書いておくと、正解がこれだというようなことを言いたいのではありません。
そもそも切り口は色々ありますし、個々の戦略にもよります。
例えば、20年続くようなゲームシステムを想定してみます。
ライフサイクル | システム |
---|---|
1週間 | アセット、マスター |
数週間 | UI |
数ヶ月 | 機能 |
3年 | 課金システム |
5年 | 対応プラットフォーム |
10年 | ゲームエンジン/フレームワーク |
20年 | コアロジック |
このように ゲームエンジンよりもコアロジックのほうがライフサイクルが長い という考え方になります。もしそうなのであれば、"コアロジックがゲームエンジンに依存するべきではない" という考え方が合理的ということになります。
であれば 「クリーンアーキテクチャはどうでしょうか?」 というような議論になると思います。
まとめ
結局、クリーンアーキテクチャ言いたいだけやんと思われたかもしれませんが、「専門的な手段の紹介」から入るとあまり上手くいかない実感がありますし、それ自体が重要なわけではないと思います。
ですので、今回は 変化に耐えうる設計のためにライフサイクルの視点を持つ という切り口で書いてみました。
それでは次回は@blockさんです。