Я уже как лет 6 регулярно отвечаю на вопросы в архитектурном чатике.
И уже 6 лет туда регулярно залетают вопросы в духе:
— А архитектура на Scriptable Object (SO) норм?
— Посмотрел видеоролик Х и Y, думаю сделать проект на SO, что думаете?
— Хочу систему конфигов сделать через SO, что скажете?
У меня есть
Отсюда, 6 причин почему SO, скорее всего, станут занозой на большом проекте.
1️⃣ Изменения в SO отображаются в git только после сохранения проекта.
Оо, сколько раз это ломало проект или делало вас "некомпетентным" в глазах других после заливки новой фичи.
Кейс простой:
— У вас есть 50 SO-объектов.
— В 5 из них вы поменяли значение/ссылку.
— Открыли git, сделали commit.
— У вас всё работает, у других — нет. 😱
У меня, честно, глаз дергается каждый раз, когда я меняю что-то в SO.
Жму по 10 раз Ctrl+S и визуально перепроверяю каждый asset-файл на корректность изменений.
2️⃣ SO-объект сохраняет изменения между запусками.
Легко можно получить ситуацию, когда вы указали ссылку на SO-объект в вашем префабе, изменили значение в runtime' e, и это значение осталось в SO-объекте.
И самое страшное в этом — ссылочные типы:
— Вы передали List<T> из вашего SO как аргумент в метод, в котором добавили/изменили/удалили значение
— Та-дам! После того, как вы выйдете из PlayMode, изменения останутся внутри SO
Вот и получается что вроде все настроил, запустил один раз, все работает.
Запускаешь 2 раз и все... А ведь день так хорошо начался 😬
3️⃣ Из пункта 2 → Вы вынуждены копировать данные из SO, чтобы использовать их в runtime.
Вместо тысячи слов — реальный класс в котором все данные копируются в новый SO объект, чтобы изменять их в runtime'е.
И так почти в каждом SO-объекте:
1000 бесполезных строк кода и 10ки MB бесполезных аллокаций. 😭
4️⃣ SO при создании грузит в память все asset'ы на которые ссылается.
Допустим, вы делаете rogue-like игру:
— В игре 100 уровней == 100 префабов
— Вы создаете SO-объект и добавляете туда все ссылки на префабы
— Прокидываете ссылку с SO в объект на сцене
— Запускаете игру и все префабы, на которые указывает ваш SO, успешно загружаются в RAM устройства 😱
Вам нужен один уровень, а в памяти все 100.
5️⃣ Вместе с SO вы тянете нативную часть.
Внутри SO будут вызваны методы, которые являются частью unity.
И этот объект будет дороже в создании как по памяти, так и по производительности.
А также он будет иметь хроническую проблему сравнения с null.
6️⃣ Удаление SO-объекта не показывает файлы, которые ссылались на него.
Как результат, ищи-свищи, в каком из SO-объектов потеряна ссылка. 🫠
А по факту, никто просто не удаляет SO-объекты из проекта, так как это очень багоопасно.
Просто делают новую конфигурацию, что захламляет проект.
Единственное решение:
Через глобальный поиск искать guid файла, который был удалён, во всех *.asset'ах проекта. 😵
🔻Отсюда правила, которые я ввожу на своих проектах, чтобы избежать проблем выше:
🔸Прямые ссылки на SO запрещены.
Только путь до asset'а , либо
AssetReference (если есть Addressables).🔸Любая вложенность SO→SO, Prefab→SO запрещена (если нужна, см. пункт выше).
🔸В SO никакой логики: максимум Pure-методы и get only-свойства.
🔸Ссылки на любые коллекции должны возвращать только
IReadOnly*<T> интерфейс.Итого:
Easy to learn, hard to master.
Для маленьких проектов/прототипов еще может быть.
Для работы в большой команде, кмк, слишком много нюансов, чтобы использовать это как архитектурную основу проекта 🫠
Сохраняй этот пост себе и пересылай коллегам, чтобы держать эти нюансы всегда под рукой. 😎
Ну и делись своим опытом в комментах💪
Ставь 👍, если тебе по кайфу такая движуха!
#проект_в_разработке@UniArchitect
