TGViewer
SpellSinger - разработчик игр на Unity SpellSinger - разработчик игр на Unity @spellsingergames · 548 subscribers
Post #136 860
Я выстрелил себе в ногу

Распространенное выражение среди программистов, но мне всегда было только примерно понятно, что оно означает. А вчера я смог это прочувствовать на себе.

TL;DR Я обосрался с циклическими зависимостями

Не так давно у нас в игре появилась система заданий. С помощью этой системы мы реализовали обучение. По мере обучения в игре разблокируются новые механики и элементы интерфейса. Соответственно, в игре есть класс QuestService, который отвечает за все задания, и от него зависят все остальные сервисы, в которых что-то разблокируется по мере прохождения обучения.

Так как обучение появилось в игре не сразу, есть ряд игроков, которые уже прокачались, и им не нужно показывать всё обучение или его часть. Для этого предусмотрена возможность пропустить квест по какому-то условию. Естественно, эти условия вычисляются при инициализации QuestService.

Добавляя последний квест, я сделал условие, которое зависело от сервиса Foo, при этом сам этот сервис Foo зависел от QuestService. В итоге, при вычислении условия, код получал не проинициализированную до конца зависимость, и падал с NRE (NPE, прим. для моих коллег джавистов). Обиднее всего то, что баг был плавающий, и не воспроизвелся, когда я тестировал, поэтому он попал на все площадки, где есть наша игра, и нам срочно пришлось выпускать хотфикс.

Чтобы не допустить такого в будущем, я буду потихоньку рефакторить весь код, и переходить от field injection к constructor injection. Ибо
Constructor injection guarantees no circular dependencies between classes, which is generally a bad thing to do. Zenject does allow circular dependencies when using other injections types however such as method/field/property injection

Изначально я поленился использовать constructor injection, потому что приходилось писать больше кода, и потому что я делал сервисами монобехи (а для монобехов не поддерживается constructor injection), чтобы хранить в них ссылки на объекты сцены или какие-то serialized параметры. Видимо, очень зря. Надо будет поискать какой-нибудь lombok для C# или плагинчик для Rider, который будет генерировать конструкторы, и делать монобехи со ссылками и параметрами отдельными зависимостями для сервисов, чтобы сервисы были обычным объектами.

#программирование
  • 👍 16
More from @spellsingergames
  1. Oct 1, 2026Автор
  2. Aug 31, 2026Post #235
  3. Aug 25, 2026Прошли модерацию на Crazy Games. Basic Launch продлится до 15 сентября или пока не наберет…
  4. Aug 24, 2026А мы, тем временем, идём покорять #crazy_games Вчера ночью отправили билд на модерацию. Мо…
  5. Aug 24, 20262 недели нужно рекоммендеру Яндекс игр, чтобы как-то отреагировать на изменения метрик. AR…
  6. Aug 14, 2026Шестой эпизод подкаста ГЕЙМДЕВ ПОД ПИВОМ уже во вторник, в 22:30МСК! Хорошенечко отоспитес…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →