Pull to refresh

Comments 16

Здесь есть единая точка входа и Dependency Injection

Единую точку входа увидел, но что касается DI, то этого я не увидел, как и задела под него.

Если используете рх, то не стоит смешивать подходы и делать так:

button.onClick.AddListener( () => _ctx.buttonClickCounter.Value++);

А еще, по хорошему, ReactiveProperty нужно освобождать.

Непонятно, зачем вам ctx в качестве valueType, если из этого не извлекается какого либо профита.

_ctx.buttonClickCounter.Subscribe(ShowClicks);

Тоже нужно освобождать.

Что мешает какому нить джуну вызвать в `CubeView` метод `Init` несколько раз, и наплодить подписок, которые в результате могут привести к весьма "забавным" багам?

В целом, на уровне дизайна - очень сомнительно.

Во первых, UI построенный на GameObject в Unity3d крайне ущербный из за своего перформенса. Следовательно если вы делаете что то, более менее серьезное, должны быть пулы и ресайклинг элементов UI.

Во вторых, как правило, вьюхи могут реюзаться 100500 раз, с небольшими изменениями в плане отображения и поведения. Другими словами, у объектов из пула должны поддерживаться возможность конфигурирования отображения и подмены поведения. Если вы конечно не хотите плодить в пуле объекты, у которых небольшие различия.

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

В четвертых, если работаем с управляемыми ресурсами, должен быть лайфсайкл менеджмент и защита от дурака. Например, при повторном вызове `Init`, предыдущие подписки должны автоматически подчиститься.

На самом деле это далеко не все, что можно было бы выделить, но коммент и так уже большой получился.

UI построенный на GameObject в Unity3d крайне ущербный из за своего перформенса

А на чем еще UI делать? Не на IMGUI же его писать, это совсем древность неудобная. А новая UI Toolkit еще сырая.

Вообще то, я не предлагал не использовать существующий uGUI, а указал на его проблемы, и что нужно делать, что бы их сгладить. Складывается впечатление, что вы не читали комментарий.

DI - это любое внедрение зависимостей, не обязательно через контейнер и рефлексию.
Если вы создаете все классы от корня через new, передавая запчасти и сервисы через конструктор (да, гиганские конструкторы) - технически это тоже внедрение зависимостей.

Важно тут только то, что объект не занимается поиском зависимостей сам (через синглтон, сервис локатор или хаки) ровно как и не создает объекты сам.

Кстати сериализация в MonoBehaviour в unity, как и ScriptableObject - это тоже внедрение зависимостей.

Абсолютно согласен, DI это внедрение зависимостей, которое здесь реализовано через конструктор, что явно говорит о том, что оно есть

Спасибо за столь объёмное ревью, постараюсь ответить кратко. Я представил базовый-схематичный каркас для архитектуры и специально в конце указал на это. В реальных проектах мы используем и ObjectPoolling и различные решения для UI и защиту "от джунов" или каких либо других ошибок. В этой статье я не преследовал цели рассказать прям обо всём что нужно, что бы проект стал мега надёжным и производительным. К таким решениям команды приходят сами, исходя из опыта специалистов. Для понимания самой сути архитектуры и возможности начать и расширить проект, этого кода вполне достаточно.

Меня смущает то, что это схематичный каркас имеет множество архитектурных мин. Джуны в силу нехватки опыта наступят на них. То что могло быть интересно для опытных программистов тут опущено, а то что продемонстрировано, вряд ли имеет ценность.

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

Банально на проблемах с менеджментом жизненного цикла реактивок можно много где выстрелить себе в ногу.

Наверняка фабрики таки используете. Можно было же было просто фабрику заюзать(или хотя бы ее интерфейс), и комментами накидать ее функционал, но показать правильный пример применения.

И таки "схематичность" не объясняет, зачем тут структуры для контекстных зависимостей. Зачем смешивать подходы, это я про подписку на кнопку классическими методами, в то время когда используется RX, в которых есть для этого API. Что с подменой поведения - не понятно.

Бтв, на счет DI, может стоит использовать термин Context Injection? Мне кажется это более подходящий термин для того, что тут демонстрируется. Т.к. лично я когда вижу DI, ожидаю увидеть DIP, и как минимум задел под IoC-контейнер, иначе в чем смысл вообще упоминать DI?

Не понятно, как масштабировать эту архитектуру. Хотелось бы увидеть код более сложного проекта, чем подсчет кликов на кнопочке. С несколькими сценами, физикой и 5+ экранами.

По началу масштабирование может показаться сложным, но по факту это простой, немного монотонный процесс (куда без них). Вся суть в правильной декомпозиции сущностей, а от них уже идём дальше. В статье и так получилось не мало кода, дописывать ещё не вижу смысла. Могу добавить, что сейчас работаю над проектом с такой архитектурой в котором уже более 50 сущностей.

Вот это и отталкивает, что даже такой маленький проект требует большой кодовой базы. Поэтому такой подход и лучше показывать на большом проекте, чтоб продемонстрировать всю мощь (если она действительно есть). Например, хотим сделать это и это, а потом добавить вот такое. При обычном подходе у нас так, а при этом - вот так.

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

В общем, не хватает чего-то из продакшена.

Очень интересное решение хотя и имеет подводные камне. Можно попробовать на похожих принципах встроить работу с ECS(не имеющие интеграцию с Unity/ну или имеющие). Entry Point порождает ECSWorld как Root и на него уже крепятся остальные сущности и через View создаются нужные GameObject для вывода результатов, так мы получим почти пустые GameObject'ы со скрытой логикой где-то в сущностях.

Добрый день.
Любопытная статья, но вы можете сказать, а зачем такая организация?
Какие плюсы и минусы?

Пока все что мне видно - это фанатичное стремление всем управлять из кода, не использовать синглтоны, потому что харам (ну то есть непонятно почему) и куча boilerplate кода.

Из минусов могу назвать постоянное заполнение значений переменных контекстов и невозможность поиска этих значение в редакторе через "Find usage", тк контексты всегда создаются заново. Но во второй части статьи я расскажу о том как прошёл мой опыт по переходу на контексты с ссылочным типом.

Из плюсов:

  • Наглядная организация кода, всегда понятно что за что отвечает и какие связи нужны, незнакомый с кодом человек быстро разберётся (если конечно всё не испортить в ходе реализации)

  • Лёгкость масштабирования - добавляем новые сущности, объединяем со старыми при помощи контекстов

  • Лёгкость рефакторинга - всегда можно разделить функционал на несколько PM, передать другой сущности (если это необходимо)

  • Гибкая организация контекста. Например, если нужно наладить взаимодействие между классами в разных ветвях проекта, то можно включить в контекст реактивную переменную с интерфейсом класса

Привет, Костя).
Я рад, что ты придерживаешься, разработанного мной подхода к проектированию архитектуры и, что все больше разработчиков к нему приобщаются.
Так как передача подхода местами искажена, внесу комменарии со своей стороны, чтобы у твоего читателя не было путаницы:

  • View - это не GameObject, а MonoBehaviour

  • Presenter Model - не Presenter, а Presentation Model

  • DisposableObject, зачем в твоем коде _unityObjects? В оигинале был AttachComponent, который отвечал за добавление Unity обьекта и не вошел в статью:

protected Object AttachComponent(Object obj)
{
	if (_isDisposed)
	{
		Debug.Log("disposed");
		return default;
	}
	if (!obj)
	{
		Debug.Log("can't add null object");
		return default;
	}
	if (_unityObjects == null)
	{
		_unityObjects = new List<Object>(1);
	}
	_unityObjects.Add(obj);
	return obj;
}

В моём профиле есть ссылка на TG канал, где я разбираю данный подход для разработки игр.

Привет)) да, я внёс некоторые изменения, мне кажется так проще понять тем, кто в первые знакомится с архитектурой.

Надеюсь ты не против того, что я таким образом решил рассказать про Composition Root. Ну и на авторство проектирования, я, конечно, не претендую. Моя цель рассказать и пообщаться со всем заинтересованными.

Спасибо за правки по статье, архитектура реально хорошая, если интересно, то можешь глянуть на рефакторинг и дать свою оценку https://habr.com/ru/articles/711140/

Sign up to leave a comment.

Articles