はじめに
この記事では、私がソーシャルゲーム開発にエンジニアとして、またプランナーとして、個人としても企業としても長年携わってきて、ベストプラクティスと思われるマスターデータ運用について前置きとして紹介させていただきます。また、最後にそのベストプラクティスを個人から企業まで幅広く汎用的に使用できるものとしてツール化したものをご紹介させていただきます。
前置きが長いので、ツール紹介のみを閲覧希望の方はこちらからジャンプしてください。
Unityでのマスターデータ運用に使われるツールについて
Unityを使用したマスターデータ運用において、一次ソースデータとしておそらく下記のようなものがあげられると思います。
- ScriptableObject
- Excel
- Google SpreadSheet
このうちScriptableObject
をマスターデータの手動入稿先として運用している企業はほとんどありませんが、ここ数年でGoogle SpreadSheet
を採用し始めた企業も多いのではないでしょうか?
私自身も色々な会社を転々としておりますが、その中でもここ2、3年でGoogle SpreadSheet
を使用しているプロダクトに配属されるケースが多くなってきました。
Google SpreadSheetをマスターデータ運用に使用するケース
これはあくまで一例ですが、Google SpreadSheet
を使用する場合、下記のようなワークフローになる場合が多いです。
ここでは、動的に変化するシート内のデータをスタティックなものとして扱うため、また差分情報をGit
で確認できるように中間的なデータとしてS3
にCSV
をGAS
でアップロードして、それをCI
が専用リポジトリにコミットする流れを取っております。
実際に運用してみての感想
Excel
のようにgit
で差分を簡単に確認はできませんが、Google SpreadSheet
を使用することで同じシートを複数人で同時に入稿作業してもコンフリクトは発生しませんので、当時私もExcel
を使用する以上にGoogle SpreadSheet
を推奨していた時がありました。また、Google SpreadSheet
で入稿したデータはGoogle App Script(GAS)
を使用することでCI
による様々な自動化が可能であると考えておりました。(というより)Excel
なんてレガシー、モダンなGoogle SpreadSheet
使うでしょ?みたいな感覚でした
ですが、Google SpreadSheet
を使用したプロダクトを数ヶ月、数年と運用していくうちに上記のメリットを大きく上回るデメリットがあることに気づきました。個人や極小規模のプロダクトならこれらのデメリットを感じないケースもあるかもしれませんが、実際にある程度の規模のプロダクトで運用されてきた方なら以下のようなデメリットを感じた方も多いのではないでしょうか?
- 誰がどのような変更をしたのかが、過去を遡って特定できない
- フィルタリングが共有されてしまう(個人用フィルタリングも使いづらい)
- ブランチ運用に超絶向いていない(
GAS
で無理やりやってもちゃんとしたマージなんてまーじ無理) - ちょっとした更新をするにしても時間がかかる(エディターで直ダウンロードしようとしてもパブリッシングデータがいつ更新されているのかがポーリングできない)
- アカウント管理をちゃんとしてない場合、個人アカウントで作られたシートがその人が退職してアカウントが破棄されると、シートも破棄されて絶望する
などなど、他にもあげるとキリがありませんが、この中でも「ちょっとした更新をするにしても時間がかかる」というデメリットはなんども調整に調整を重ねるようなマスターデータ運用には、非常に不向きであると感じました。そして、これらのデメリットがあまりにも大きいため、この時点でだんだんと
「あれ、Excel
くんって割と優秀な子だった?」
という思いが強くなってきました。
Excelをマスターデータ運用に使用するケース
では反対にExcel
をマスターデータ運用の一次ソースデータとして使用した場合について、今まで私が経験した中でベストプラクティスと感じたワークフローは以下のようなものでした。
S3
やマスターデータ専用リポジトリという中間の存在がなくなったため、先ほどのワークフローより幾分かシンプルに見えると思います。実際、Excel
はユーザーが直接リポジトリにコミットすることが可能なため、CI
側としてはポーリングを容易に実装することができ、ユーザーがわざわざジョブキッカーになる必要は無くなります。
実際に運用してみての感想
ご存知の通り、大きなデメリットとして同じファイルを追加、編集する際に確実に作業者どちらかの方でコンフリクトが発生してしまい、そのコンフリクトの解決が非常に面倒であるというものがあります。また、Google SpreadSheet
とは違い、ライセンスを購入する必要もあり、そのままではGit
での差分もバイナリファイル扱いされるため、差分を確認することもできません。
これらのような非常に大きいデメリットを抱えているExcel
ですが、私はこのデメリットすらも大きく上回るメリットがExcel
にはあると感じております。具体的には以下のようなものです。
- 調整がローカルで全て完結する
-
xlsx
ファイルであれば、内部がxml
ファイルなので、解析ツールが容易に作成できる。また、差分確認などであれば、世の中にたくさんのツールが出回っている - 昔からよく使われているツールなので、比較的ほとんどのプランナーが使用できる
- それぞれのユーザーが
Git
に直接コミットするので、誰がいつ何をしたのかがすぐにわかる -
python
などでマージツールを作成することができるため、ブランチ運用と相性が良い - ローカルにあるファイルなので、好き勝手にフィルタリングできる(コミットしないでねw)
などがあげられます。もちろん技術的コストがかかりますが、マージツールを作成することでブランチ運用できることや、比較的ほとんどのプランナーが使用できるという点から、チーム開発する場合でもGoogle SpreadSheet
より優れているのではないか、というのが個人的な意見です。
それぞれのデメリットの解決方法
Excel
を使用するにあたって、大きなデメリットがあるという点について前述いたしましたが、今までの私のプロダクトではこれらを克服するために下記のような対策を行うことで、デメリットを比較的抑えることができました。
作業者間で発生するコンフリクトの対策
Git
はSVN
とは違い、ファイル単位でのロックは不可能なため、これらの対策をするには第3者からの干渉が必須と考えました。
その最も良かった対策の一つとして、管理ツールで編集者登録をし、JenkinsからPullRequestのマージをユーザーごとにバリデーションするというものがあげられます。図にすると下記のようなものになります。
Slack
に関して、強制力はありませんが各ユーザーに通知を行うことで、よりコンフリクトを避けられるように設計します。とはいえ、ソースコードと同じで基本的には同じものを追加、編集するという場合には基本的に当事者間での情報の共有は必須と考えます。
デフォルト設定で差分を確認できない
前述している通り、こちらはパブリックに公開されているツールが複数あります。
仕組みとしては単純で、xlsx
という形式のExcel
であれば基本的にxml
ファイルをzip
でアーカイブしているものになり、これら公開されている差分確認ツールは一般にそれらExcel
ファイルの中身を解析して、tsv
ファイルとして出力するためのツールとなっております。
これらxlsx
ファイルをtsv
ファイルとして出力するツールを.gitconfig
や.gitattributes
に設定することで、コンソールではもちろん、SourceTree
のようなGUIツールでもバイナリファイルとしてではなく、tsv
ファイルとして認識され、差分を出力することが可能です。
結論、どちらを使えば良いのか
長々とExcel
を使用した場合と、Google SpreadSheet
を使用した場合とで、実際に運用した感想について話させていただきましたが、結論としてどちらを使用するべきかは正直プロダクトや企業、開発するものによって、どちらが良いかは分かれると思います。
例えば、これまでGoogle SpreadSheet
を運用してきた経験やツールがすでにあり、GAS
で作成したツールもたくさんある場合は無理にExcel
を使用するべきではないかもしれませんし、アクションゲームのようにキャラクターのパラメータを頻繁に変更しながらバランスを調整するような開発スタイルをとる場合、反映速度が遅いGoogle SpreadSheet
を無理に使用するべきではないと考えます。
ですが、私個人的な意見を申すと、もしあなたがまだマスターデータの運用をどうするか迷っている、もしくはまだ何も手をつけていない状態であるのであれば、Excel
をマスターデータ運用で使用することをお勧めします。
マスターデータ運用ツールの紹介
前置きがかなり長くなりましたが、ここからは私が前述した内容をより汎用的に使用できるようツール化したものの紹介になります。また、ここから紹介する内容はREADME
で公開している内容を詳しく日本語で解説したものになります。英語でのドキュメントになりますが、より簡易的な使用方法については以下のリポジトリを直接参照ください。
特徴
このツールを使用する上で、大きな特徴は以下の通りです。
-
Excel
をマスターデータ一次ソースファイルとして使用する -
DTO
/DAO
/VO
の設計思想を導入している -
ScriptableObject
をマスターデータアセットとして使用する(AssetBundle
との親和性を高めるため) - マスターデータ操作用のスクリプトは全てジェネレーターによって生成される(
CI
との親和性を高めるため) -
Excel
ファイル内でEnum
タイプ定義をすることができる(タイプ定義がコメントの役割をもつ上、コメントとは違い確実にスクリプトでの定義と同一になる) - マスターデータアセットのロード処理のプロセスのみをユーザーが定義できる(デモでは
Addressables
の使用を推奨しております)
導入方法
このツールを使用する前に、以下の手順を行い導入してください。
1. NuGetForUnityのパッケージをプロジェクトに取り込む
こちらから最新のパッケージをダウンロードして、Editorからインポートしてください。
https://github.com/GlitchEnzo/NuGetForUnity/releases
2. ExcelDataReaderのパッケージをインストールする
NuGet
を使用して、ExcelDataReader
の以下のパッケージをインストールしてください。
- ExcelDataReader
- ExcelDataReader.DataSet
NuGet
を使用してパッケージをダウンロードする方法については、こちらで詳しく解説しております。
3. Addressable Assets Systemのパッケージをインストールする
UnityMasterData
のサンプルスクリプトでAddressables
を使用しております。
メニューからWindow/Package Manager
でPackageManager
を開いて、Addressables
をインストールしてください。
4. UnityMasterDataのパッケージをプロジェクトに取り込む
こちらから最新のパッケージをダウンロードして、Editorからインポートしてください。
https://github.com/tani-shi/unity-master-data/releases
UnityMasterData
の導入は以上になります。
ワークフロー
このツールを使用する上で、以下のようなワークフローを想定しております。
1. マスターデータをエクセルに入稿する
ここで入稿する場合以下のようなフォーマットである必要があります。
A | B... | ||
---|---|---|---|
1 | プライマリーキー名 *1 | フィールド名 | <= 必ず入力してください |
2 | コメント | コメント | <= 空でも可 |
3 | Enum定義 *2 | <= 空でも可 | |
4 | プライマリーキータイプ *1 | フィールドタイプ *2 | <= 必ず入力してください |
5〜 | プライマリーキー値 | パラメータ値 | <= タイプがstringであれば空でも可。それ以外は必ず入力してください |
- *1 プライマリーキー名は
id
となり、プライマリーキータイプはint
もしくはuint
になるのが一般です。 - *2 Enum定義が空でない場合は、そのカラムのフィールドタイプがそのEnumのタイプ名となり、自動的に
MasterDataType.cs
に定義されます。
サンプルファイルを用意しております。参照ください。
2. マスターデータ操作用のスクリプトを生成・更新する
MasterDataClassGenerator.GenerateAllDataScripts
をあなたのプロジェクトのスクリプトから呼び出してください。この時、以下のようなスクリプトが生成されます。
- {0}/MasterData/DAO/Generated/{1}/{2}DAO.cs
- {0}/MasterData/DTO/Generated/{1}/{2}DTO.cs
- {0}/MasterData/VO/Generated/{1}/{2}VO.cs
- {0}/MasterData/Type/Generated/MasterDataType.cs
- {0}/MasterData/Collection/Generated/MasterDataAccessorObjectCollection.cs
- {0}/MasterData/Editor/Exporter/Generated/{1}Exporter.cs
{0} = 設定したスクリプト生成ルートパス
{1} = エクセルファイル名
{2} = シート名
3. マスターデータをScriptableObjectとして書き出す
MasterDataExporter.Export
をあなたのプロジェクトのスクリプトから呼び出してください。この時、以下のようなアセットが生成されます。
- {0}/MasterData/{1}/{2}.asset
{0} = 設定したアセット書き出しルートパス
{1} = エクセルファイル名
{2} = シート名
基本的なワークフローとしては、ここまでの1.〜3.を繰り返してマスターデータの調整を行っていくような想定をしております。
4. MasterDataManagerBaseを継承して、プロジェクト固有のアセットロード処理を実装したクラスを作成する
ワークフローとして紹介しておりますが、このステップは一度実装すれば基本的に更新する必要はありません。
こちらはサンプルとして、Addressables
を使用してロード処理を実装したサンプルスクリプトです。
5. 4.で作成したマネージャークラスを使いマスターデータを操作する
上で紹介したサンプルマネージャークラスを実装したサンプルスクリプトです。
注意することとして、マスターデータを取得する処理を実装する箇所よりも先に、マスターデータアセットをロードする処理を実装した箇所が先に実行されなければなりません。
最後に
今回紹介させていただいたツールは私が完全に個人的な見解で、今まで経験したマスターデータの運用の中で最も効率的にゲーム開発ができる設計と感じたものをツール化したものになります。もちろんこれが最適解かどうかというとケースバイケースですが、個人で開発をしていてチーム開発のワークフローを経験したことがない方や、これからソーシャルゲーム開発を行っていく上で技術を模索しているような企業の方の何か参考になるようなものになれば幸いです。
また、今回はGoogle SpreadSheet
について運用する上でデメリットばかり触れてしまいましたが、実はこういう使い方するとこっちの方が使いやすいよ!といったような意見があれば、ご指摘いただきたいです。
それでは最後まで閲覧いただき、ありがとうございました。