Unity Architect: архитектура unity проектов
4.98K subscribers
17 photos
1 video
79 links
Авторский блог unity lead'a. Пишу про архитектуру проектов и свой путь.

Мой курс по архитектуре: https://vangogih.notion.site/cb0f15e57d5a4f10b2a7df9664b8e5f9

Иногда выкладываю видео и веду стримы: youtube.com/@vangogih

По всем вопросам: @vangogih
Download Telegram
ПЕРЕЕЗД В ИСПАНИЮ 🇪🇸

Я давно мечтал переехать в одну из стран Европы. После долгих изучений и постоянных переездов из страны в страну, стало понятно что нужно где-то обосноваться. Наш с женой выбор пал на Испанию.

1️⃣ Климат
Жене и мне надоела серая московская погода. Либо дикая аномальная жара, либо аномальный холод или отсутствие снега.
Так же, как человек из Сибири, привыкший к холодам и хорошей студеной зиме со снегом, то что происходит в Москве не поворачивается язык назвать это зимой. А я люблю зиму 😞
Осень/весна занимают половину года, а иногда и все 3/4. Слякоть, дожди, серость, все это очень сильно бьет по моральной и продуктивной составляющей.

2️⃣ Менталитет и отношение
Обеденные сиесты в 2 часа, когда можно сгонять домой, покушать, поспать и вернуться домой.
Женщин, детей и даже животных здесь уважают больше чем мужчин. Не поймите не правильно, просто когда в Москве жену страшно посадить одну в такси это не ок.

3️⃣ ВНЖ выдают с российским ИП
Я уже 3 года работаю удаленно как ИП. Испания в начале этого года открыла nomad ВНЖ программу по которой можно получить вид на жительство на 3 года. Процедура пока очень простая с самым низким порогом входа. + принимаю контракты из РФ и ИП в РФ тут котируется.
Дайте знать если интересно, могу сделать отдельный пост, где опишу весь этот длинный путь.

И сейчас как раз занимаюсь подготовкой и подачей документов на nomad ВНЖ.

В данном цикле хотелось бы больше рассказывать о себе, напишите про что интересно почитать:
— С чего все начиналось (школа, универ, самообучение)
— Последний опыт (своя игровая студия, переезды, события последних 2ух лет)

#моя_история@UniArchitect
🔥91
ВЕРСИОНИРОВАНИЕ Ч.1 СЕМАНТИКА

На многих проектах, на которых удалось поработать, я замечал, что версионирование ведется по принципу увеличиваем последнюю цифру. Если последняя цифра больше условных 10, то мы изменяем предпоследнюю цифру на единицу, а последнюю цифру обнуляем. И так далее.
То есть это работает как какой-то счетчик, разделенный тремя точками.
Практического смысла и какой-то идеи я никогда не наблюдал.

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

Мы не можем обновить игру так же, как мы можем обновить Nuget зависимость. Нам не нужно беспокоится об обратной совместимости. Я к тому, что использовать схему major.minor.patch нас никто не заставляет.

Ну как никто, есть один профессиональный объюзер в мире разработки — Apple. Оо, сколько у меня вопросов к этим ребятам. Они заставляют придерживаться схемы major.minor.patch. И остается лишь под это адаптироваться.

В итоге требование к изменению версии всего одно — текущая версия должна быть выше предыдущей. А схема — major.minor.patch.

И с опытом я сформировал такие правила изменения версии:
— major - когда игра не опубликована - 0, после публикации 1. Дальше +1 когда minor достигнет 99 или когда будет очень крупное обновление.
— minor - меняем при каждом релизе
— patch - только для хотфиксов

Пример:
— В develop версия 1.0.0, stable, rc, master версия 0.2.0
— При критической ошибке в 0.2.0 в rc делаем хотфикс и версию меняем на 0.2.1.
— Когда проект будет опубликован в сторах, его версия в master будет 1.0.0, а develop 1.1.0.
— Если в 1.0.0 будет баг, то в stable, rc, master будет вылит фикс, а версия изменится на 1.0.1.

А bundle version code можно формировать по формуле: major * 10000 + minor * 100 + patch. Но с оговоркой что вы готовы менять версию каждый раз при косячной заливке в стор.

Я же отказался от этой формулы и просто перед каждой заливкой в стор ручками увеличиваю bundle version code на 1. И он с версией никак не связан.

При том в вопросе версионирования остается еще один нераскрытый момент — миграция данных между релизами. Об этом мы поговорим в следующем посте данного цикла 😊

#проект_релиз@UniArchitect
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥3
Retention (R)
Первая и базовая метрика, которой измеряется успешность проекта.

Всего 2 типа:
Classic retention — % пользователей, которые открыли игру на следующий день*
Rolling retention — % пользователей, которые открыли игру на следующий день* или позже

Минусы второго — может измениться в любой момент. Даже если пользователь зайдет в игру в следующий раз на 90 день, он попадет в Rolling R1.

Следующий день* — есть 2 типа интервала от которого можно замерять R:
1. 24h — пользователь будет учтен, если откроет приложение в период 24-48 часов после установки.
2. Calendar — пользователь будет учтен, если откроет приложение на следующий календарный день.

Минус второго — пользователь, который скачал игру в 11:50 вечера и открывший ее в 12:05 следующего дня будет учтен.

Из интересного:
▫️ Изменение R1 — динамика развития проекта
▫️ Rolling R на практике используется редко, чаще упоминается на публике или на слайдах в отчетах
▫️ 24h R можно использовать для быстрого определения эффективности компании. Это работает т.к. мы можем в данном случае измерить возврат 0-го дня.
▫️ Calendar Classic R чаще всего просили показать инвесторы. Многие кто слышал цифры ниже бэнчмарков сразу разворачивались
▫️ Если на старте R1 ниже 20%, а FTUE уже отлажен, то потребуются координальные изменения в core части игры, чтобы проект выжил
▫️ Если на старте R1 около 15 и ниже, то проект дешевле убить чем вытягивать
▫️ Если R1 > 35% это успех

#проект_liveOps@UniArchitect
#метрики@UniArchitect
👍6🔥3
СЦЕНЫ

Первая проблема, которую я сразу решаю на новом проекте — 4 сцены для управления состоянием проекта.

0.Bootstrap — точка входа и контекст проекта (аналитика, SDK сторов, платежка, конфиги, связь с сервером).

1.Loading — загрузка, авторизация, GDPR, проверка обновлений и прочее что нужно для старта игры.

2.Meta — в основном UI в котором вы тратите накопленные ресурсы на прогресс по игре

3.Core — основная реиграбельная часть

4.Empty — костыль сцена для 100% выгрузки всех ресурсов предыдущей сцены.

Из любой сцены мы можем перейти в любую. Исключение Bootstrap. В нее входим только при запуске игры. И из нее загружаем только Loading.

#проект_с_нуля@UniArchitect
👍11
(А|а)рхитектура

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

Архитектурные подходы (паттерны) в разработке ПО универсальны. Их можно применить к любому языку и проекту. Код, следующий этим принципам, будет одинаков с точки зрения масштабируемости и сложности.

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

И при проектировании нужно вырабатывать эти решения (правила, подходы, гайдлайны) не только для кода, но и для всего с чем проект связан:
— Именование файлов и папок, структура хранения ассетов, структура сборок
— Утилиты для разработки, тестирование, работа с системой контроля версии
— Билд проекта и его деплой, работа со сторами и выливка хотфиксов
— Мониторинг метрик, ошибок и реагирование на них

#аббревиатуры@UniArchitect
🔥21
С ПОЛЕЙ РАЗРАБОТКИ:
ОПТИМИЗАЦИИ ЗАГРУЗКИ

В этой рубрике я пишу про то, с чем столкнулся вот только что и сразу решил об этом написать пост.

Вводные:
1️⃣ Карта с 5 уровнями. Группа из 5 уровней называется остров.
1ый остров - тутор
ГК - глобальная карта на которой находятся все острова
2️⃣ Игрок прошел последнюю карту 1го острова (т.е. тутор), нажимает кнопку открытия ГК (это scrollRect горизонтальный с 10+ элементами) и получает ANR.
3️⃣ В логах перекати поле. Нет ничего. Ни одной ошибки ни одного warning'a.

ANR коротко — главный поток висит >5 секунд?
— Android ядро грохает приложение.

Причина:
Instantiate большого кол-ва объектов в одном кадре
Canvas.ForceUpdateCanvases(); занимает >1000ms на компе. На девайсе замерить не удалось, угадайте почему 🤷‍♂️

Решение:
— Если в одном кадре много Instantiate - делаем из метода корутину и проставляем delay (или return null) после каждого выполнения тяжелой логики
— Перед добавлением элементов включаем сам объект в иерархии, на котором будут создаваться объекты

Это позволит не в один кадр обновить все добавленные на канвас элементы (а это куча примерно в 1000 объектов), а в несколько.

p.s. обожаю фиксы в одну строку (см. последний скрин, это весь фикс)

Насколько вообще заходит такой формат, черканите коммент 😊

#будни@UniArchitect
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🆒8
ПЕРЕКЛЮЧЕНИЕ СЦЕН — Additive.

СЦЕНЫ

Нюансы:
— Загрузка и выгрузка асинхронная, требует написания доп. кода
— Нужно ручками в новой сцене дергать SceneManager.SetActiveScene
Только после этого делать Instantiate объектов.
— Сторонние плагины все равно создают DontDestroyOnLoad объекты

Преимущества:
— Можно отказаться от DontDestroyOnLoad объектов и использовать Bootstrap сцену для хранения глобального контекста.
— Захотели перезапустить игру полностью? Загрузили заново Bootstrap и весь контекст дропнулся без лишних телодвижений
— Очистка памяти и уменьшение используемой RAM без Empty сцен

+ Tutorial можно сделать отдельной сценой, которая при загрузке будет определять какая сцена загружена, какой последний шаг и вести пользователя

#проект_с_нуля@UniArchitect
👍6🔥1
СТРУКТУРА ВЕТОК ПРОЕКТА

У структуры веток всего 1 требование — деление процесса разработки на понятные стадии.

Из опыта создания нескольких проектов с нуля я выделил такую структуру веток:

🔹 develop — разработка.
- В этой ветке происходит контролируемый разработчиками хаос
- Код в ветке может работать, а может и нет
- Окружения разворачивается локально
- Настройки проекта могут быть какие угодно в зависимости от потребностей разработчиков

🔹 art — стабильная версия develop.
- Нужна геймдизайнерам, QA, аналитикам и т.п. для проверки, тестирования текущего состояния приложения
- Cвое серверное окружение

🔹 stable — feature freeze. Выделяет конкретный список, набор фичей, которые получат пользователи в этом обновлении.
- Сюда мержится develop когда все фичи версии сделаны
- Включена вся отладка
- Включены читы
- Фейковый магазин
- Cвое серверное окружение

🔹 rc — Release Candidate. Это пред-релизная версия.
- В данную ветку мержится stable
- Сюда могут быть залиты только hotfix’ы
- Версия максимально приближена к проду
- Отключена вся отладка
- Конфигурация на максимальную производительность
- Реальный магазин
- База данных синхронизирована с продом

🔹 main/master — тот самый prod, который принято ронять 😬
- Сюда мержится rc
- Состояние из этой ветки всегда соответствует состоянию приложения у пользователей на девайсах.
- В нее может напрямую пушить только лид, либо ответственный за релиз.

Кол-во веток и окружение нужно варьировать в зависимости от потребностей проекта.

#проект_в_разработке@UniArchitect
👍7
ВЕРСИОНИРОВАНИЕ Ч.2. МИГРАЦИЯ

Ч.1. СЕМАНТИКА

В первой части я говорил что поддерживать обратную совместимость для игр нет смысла, потому что API нет.
Исключение — профиль игрока. Его обратную совместимость мы должны обеспечивать всегда.

Страшный сон для игрока — потеря прогресса.
Страшный сон любого проекта — ошибки с локальным профилем игрока.
Если профиль не синхронизирован с сервером, а игрок потратил деньги, то можно ловить кучу 1 ⭐️ в сторах, возвращать всем деньги и смело ставить свечку за упокой проекта 🕯

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

Пример:
- Профиль игрока версии 1.0.0 — { “coins”: 100 }
- Переименовали coins в soft, версия 1.1.0 — { "soft":100 }
- Объединили поля с валютами в объект, версия 1.2.0 —
{ "bank": { "soft":100, "hard":10 } }

Если не будет миграции игрок получит ошибку десериализации при запуске игры после обновления. Потому что json schema между версиями разная.

Решение:
Json файл нужно версионировать. При изменении схемы (поломке обратной совместимости), писать миграции.

Задача сводится к тому чтобы написать свой JsonConverter, который будет брать все объекты миграции с версии k до n и вызывать их методы.
Где k - версия json у пользователя, n - версия json в проекте

Типичная ошибка:
Десериализовать файл в старый формат, мигрировать, сохранять и снова десериализовать в новый формат.
Как ни странно, встречал такое решение в нескольких проектах. Это костыль, не делайте так.

У себя на проектах я использую этот плагин. Он достаточно интерпрайзный и местами решения оч странные, но он работает.

Смотрю на плагин и слышу как это интерпрайзное говно кричит о том чтобы его переписали и упростили.

Давайте 15 👍 этому посту и я за пару недель
👨‍💻 свою версию, которую вы сможете использовать в своем проекте.

Обещание выполнено!
https://github.com/vangogih/FastMigrations.Json.Net

#проект_релиз@UniArchitect
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31
НАВИГАЦИЯ

Об авторе блога

Open source:
Unity Empty Project Template 80+⭐️
Fast Migrations Json .NET 40+⭐️

#проект_с_нуля@UniArchitect — все что нужно знать, когда создаете новый проект

#проект_в_разработке@UniArchitect — все с чем приходится сталкиваться во время разработки

#проект_релиз@UniArchitect — нюансы, процессы, проблемы публикации мобильных проектов

#проект_liveOps@UniArchitect — поддержка, оперирование приложениями, которые уже опубликованы

#аббревиатуры@UniArchitect — высказываюсь на тему популярных аббревиатур

#моя_история@UniArchitect — истории моего карьерного и не только пути

#метрики@UniArchitect — аналитические метрики проекта, которые полезно знать

#будни@UniArchitect — реальные проблемы, с которыми я сталкиваюсь и сразу пишу об этом

#software_engineering@UniArchitect — цикл статей на тему инженерной разработки ПО.
Основа для понимания архитектуры ПО

#курс@UniArchitect — статьи, где я делюсь прогрессом по курсу, который я проработал и создал

Мероприятия:
#DevGAMM_Lisbon_23@UniArchitect

@UniArchitect
👍6
FTUE

Для программиста — жизнь это while(true)
Для CG художника — жизнь это lerp(a,b,t)
Для аналитика — жизнь это funnel

В прошлый раз я писал про Retention (R).
Но от чего зависит R и можно ли его как-то предсказать?
— Можно если знать конверсию FTUE воронки.

Воронка (funnel) — последовательность шагов, по которым проходит группа пользователей.
Пример:
— Установка
— Согласие с GDPR (General Data Protection Regulation)
— Загрузка ассетов из CDN (Content Devilery Network)
— Шаги тутора
— Сыгранные N игр в core части

Из прохождения всех шагов складывается первое впечатление пользователя от игры — FTUE.
FTUE (First time user experience) — воронка, которую проходит пользователь до возврата на 1 день.

Замерами мы понимаем эффективность шагов. И если она не достаточная, то мы улучшаем его, делая первый опыт игрока более приятным, тем самым влияя на R1.

Из интересного:
▫️ Для R1 ~30-35% конверсия FTUE должна быть ~60-70%
▫️ Аномальное изменение % отвала между версиями == техническая проблема (софт/хард лок, ANR)
▫️ Эффективность изменений в обновлении == дельта отвала между текущей и прошлой версией
▫️ 500 пользователей — минимально достаточное кол-во, чтобы считать данные репрезентативными

⚠️ Эксклюзив: фрагмент документа с одного из проектов, над которым я работал.

#проект_liveOps@UniArchitect
#метрики@UniArchitect
👍3🔥2
DI

DI (Dependency Injection) — подход, который абстрагирует создание объекта, выделяя его на отдельный слой и отделяя от основного приложения.
Добавляет концепцию управления зоной использования (scope) и временем жизни объекта.

При том важно разделять:
🔹Composition Root (CR) — паттерн, подход при котором создание объектов системы происходит в одном месте.
Выделяет 3 (RRR) фазы управления жизненным циклом объектов:
- Register — создание зависимостей
- Resolve — решение графа зависимостей
- Release — удаление, освобождение объекта

🔹DI container (DIc 🍆) — как правило плагин, реализация-автоматизация CR.
Т.е. вместо ручного создания и решения графа зависимостей, он через рефлексию или кодогеном сам прокидывает зависимости в конструктор или поля.

🔹Service Locator (SL) — создает, хранит и отдает по требованию любое множество зависимостей
Может быть частью реализации CR, но тогда решать граф нужно самому.
В этом месте, при не понимании RRR, возникает куча проблем (кольцевые зависимости, классы боги) из-за чего SL называют антипаттерном.

Из этого следует:
▫️Реализовать DI можно без использования DIc
▫️DIc (Zenject, Vcontainer и др.) сильно расширяют жизненный цикл любого класса
▫️С DIс мы делегируем обязанность по созданию и управлению жизненным циклом объекта!
▫️Легковестной реализацией DI может быть SL (статический класс со словарем)

При использовании DIc или SL важно навсегда запомнить:
1. Никакой логики в конструкторе. Только агрегация и композиция
2. Вся логика инициализации, как отдельная стадия создания объекта, выделяется в отдельный метод

В случае несоблюдения мы рискуем обратиться к зависимости раньше, чем был решен граф, что сразу == куча головняка с порядком регистрации зависимостей.

Картинка из книги Dependency Injection Principles, Practices, and Patterns by Steven van Deursen and Mark Seemann

#проект_в_разработке@UniArchitect
#аббревиатуры@UniArchitect
👍28🤔1
СТРУКТУРА СБОРОК

Сборки (Assembly definition, asmdef) — unity обертка над сборками в .NET.
По факту это json в котором прописана конфигурация .NET Assembly.

Это делает сборки неотъемлемой частью архитектуры, потому что каждую сборку можно версионировать, проставлять в нее зависимости, определять отдельные define’ы.
Так же по умолчанию она поддерживает проверку на циклические зависимости.

У себя на проектах я выделяю такие сборки:
🔹 Runtime — клиентский код
🔹 Editor — утилиты редактора
🔹 Tests.PlayMode — интеграционные тесты.
Т.е. тесты, для которых требуется unity scripts lifecycle
🔹 Tests.EditorMode — unit тесты

Для онлайн приложений так же выделяю:
🔹 Transport — cпецифичная для клиента связь с сервером. Реализация подключения, обмена данными, переключение состояний
🔹 Shared — общие с бэком модели данных, константы, конфиги и прочее.

Т.е. эти сборки является моделью домена и явно отделяют отображение unity (слой Presentation) от источника данных (слой Data Source)
Что-то на архитектурном, будет отдельный пост про это
Выделение этих частей позволяет mock'ать клиентскую часть и запускать клиент без unity т.е. должны стоять галки No Engine References

Из интересного:
▫️ В define constrains поддерживает отрицание. Т.е. можно выключить всю сборку для PROD define’ов
▫️MonoBehavior нельзя добавить как компонент на объект если в Platforms отмечен только Editor
Чтобы это обойти, поставьте галку на любую платформу, под которую 100% проект никогда не будет собран (Stadia например)
▫️ Для удобства редактирования и отслеживания изменений в git, уберите галку Use GUIDs
▫️ csc.rsp можно положить рядом с asmdef и прописать туда дополнительные параметры компиляции
Удобно когда нужно подключить большой список define’ов или отключить надоедливые warning’и
▫️Можно делать точеные оптимизации или патчи IL кода через Mono.Cecil или Harmony. Так раньше был сделан inject в VContainer
▫️Если сборка не изменилась, то перекомпилироваться она не будет. Таким образом, разбивая крупные сборки на более мелкие, можно значительно снизить время компиляции проекта. Из комментов, спасибо @Bogotoff.

А какие сборки вы выделяете в своих проектах?
👨‍💻 в комменты, я создал

#проект_с_нуля@UniArchitect
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🍌1
SILVERFOX GAMES НАЧАЛО

Краткий карьерный путь

Осенью 22 мне на Linkedin постучался партнер и предложил сделать свою игру.
Кстати, добавляйтесь в друзья 👋

Он подготовил идею, описал ГД документ. После вычитки мы созвонились на 2 часа, обсудили все нюансы и убедились что понимаем друг друга.

Я составил список команды и расходы на нее, партнер подготовил P&L. Решили сделать прототип под который будем поднимать намеченную сумму в 400.000$ на 1 год разработки.

Через пару месяцев был готов прототип. Под него партнер сделал питч. Начали рассылать по инвесторам.

Не хочу чтобы кто-то питал иллюзий насчет подъема pre-seed раунда под идею.
Такое в реальности делается только если есть огромный послужной список. 10+ лет над AAA в Ubisoft например.
В остальных случаях это FFF (Family, Friends, Fools). Наша история не исключение.

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

Соглашусь с мыслью из книги “Гении и аутсайдеры”, о том что большую часть успеха определяет контекст времени.
У нас это был Март 2022. Мягко говоря не самое простое время для фаундеров из России.

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

Какие выводы:
▫️ Поднять pre-seed можно только если у вас друг ангел-ивестор, родители при ресурсах, либо у вас огромное комьюнити, которое вы успешно монетизируете.
Либо вы успешный выходец популярной студии.
▫️ Если вам посчастливится поднять pre-seed. Не спешите тратить деньги, нанимать огромный штат и стартовать разработку.
Лучше маленькая мобильная, гибкая команда и четко выверенные шаги, которые при минимальных затратах дадут понять жизнеспособность идеи.
Чем со старта структура из 15-20 человек, которая менее мобильна, потребляет больше денег.
▫️Игры ОЧЕНЬ дорого, ОЧЕНЬ долго и ОЧЕНЬ сложно.
Success rate игровых проектов ~8%.
Как по мне, если вы хотите создать компанию, то начинать с игровой студии супер рисково.
Начните с чего попроще и подешевле: SaaS или точеное B2B решение.
▫️А еще, скорее всего вы не станете более желанным на рынке кадров только за счет того что у вас за спиной опыт создания своей компании.

#моя_история@UniArchitect
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥4🤯3
С ПОЛЕЙ РАЗРАБОТКИ: РАБОТА С VPS

Вводные:
Часто при разработке нужно подключиться к удаленному серверу (VPS), чтобы поднять упавший прод, VPN'чик свой развернуть или боевую базу удалить 😵‍💫

Но сегодня я подключался к тачке, к которой доступ был только через QEMU в браузере.

Задача:
Подключиться через ssh к машине

Нюанс:
▫️Буффер-обмена между моей локальной машиной и VPS не работает.
Т.е. вы не можете через ctrl+c ctrl+v передать любые данные.
▫️Для удобной работы нужно прописать в authorized_keys свой публичный ключ
Но вот беда, RSA 2048/4086 ключ, очень длинный. ~400 и ~700 символов, на секундочку 🤯

Возможные варианты решения:
1️⃣ Вбить ручками
2️⃣ Положить ключ в файл с публичным доступом и через curl скачать его.
Например: github gist или на свой веб-сервер.
Проблема очевидна, шарим ключ в паблик и может быть засвечен какими-нибудь nmap ботами.
3️⃣ Настроить синхронизацию буффера-обмена
Проблема: нужно ребутить тачку и не факт что это вообще заработает.

Мое решение:
Использовал не RSA, а ed25519 ключ (он короче RSA в ~8 раз) и вбил его ручками 🤷‍♂️
Проблема: если у вас только RSA, то лучше воспользоваться 2ым решением. Так же не всеми программами он поддерживается (привет postgres)

Дополнение ко 2️⃣ решению:
Можно сделать secret github gist, сгенерировать временный access token и одним curl запросом выкачать его. Подробнее тут
Минусы: весь запрос придется вбивать ручками, но это все равно быстрее и эффективнее чем идти по 2 или 3 пути.

Есть другие варианты? 👨‍💻 в комменты

#будни@UniArchitect
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4😁1
ТОЧКА ВХОДА

Точка входа — LUCA проекта, место откуда все начинается.

А ее первостепенная и единственная задача — прозрачная инициализация проекта/сцены

Критерии прозрачности:
🔹Можно легко найти в проекте/сцене
Объект всегда находится вверху иерархии сцены
На сцене объект всегда называется "EntryPoint"
🔹Сквозное единое именование
Постфикс Scope — для RRR фазы
Постфикс Flow — для фазы инициализации
Пример: BattleScope, BattleFlow, MetaScope, MetaFlow
🔹Единый дизайн классов
Каждый Scope наследуется от класса, предоставляющий функционал IoC контейнера LifetimeScope, MonoInstaller
Каждый Flow начинается с метода Start, в котором происходит вся инициализация

Т.е. мы сначала создаем объекты, inject'им их в Flow, ждем вызова Start и согласно нашему порядку инициализируем.

Из интересного:
🔸Поскольку решение графа и инициализация разделены, то начало работы класса может быть отложено на сколько угодно по времени.
🔸Инициализация в Start освобождает от необходимости помнить что такое ExecutionOrder
Так же защищает от рисков обратиться к внешней зависимости (плагину), которая еще не проинициализирована.
🔸Можно легко включать, отключать части игры, занося блоки инициализации под define
🔸Правило "1 точка входа = 1 сцена" избавляет от racing condition при инициализации
🔸Для инициализации монобехов пишется отдельный метод Init
Start и Awake не реализуются из-за racing condition
Иногда удобно прописать вызов Init в Start, чтобы запустить объект на другой сцене, вне основной системы
🔸Легко сделать примитивный перезапуск игры. Достаточно ещё раз вызвать метод Start

Пост по миграциями собрал больше 15 👍 и я уже начал пилить свою легковесную версию. Следите за обновлениями 😊

Так же думаю сделать базовый шаблон проекта в unity в котором реализую все описанные в #проект_с_нуля рекомендации.
Давайте 30 👍 под этим постом, я за пару недель 👨‍💻 свою версию, которую вы сможете первой импортировать в пустой проект 😎

#проект_с_нуля@UniArchitect
Please open Telegram to view this post
VIEW IN TELEGRAM
👍68
КОГНИТИВНАЯ СЛОЖНОСТЬ

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

Для понимания выводов нужно пояснить:
🔸 Символьная сложность (symbolic complexity, definition. 7, стр. 7) — кол-во строк кода
🔸 Операционная сложность (operational complexity) — сумма весов сложности базовых операций (if, switch, for, while, do-while, function call и т.д. Table. 3, стр. 14)
🔸 Архитектурная сложность (architectural complexity, definition 22, стр. 16) — сумма весов всех аргументов, возвращаемых значений и локальных переменных
🔸 Когнитивная сложность одного объекта (unit of cognitive complexity, definition 24, стр. 17) — произведение операционной и архитектурной сложности объекта
Если совсем просто: все операции объекта, помноженные на все его переменные
🔸 Когнитивная сложность ПО (cognitive complexity) — сумма когнитивных сложностей всех объектов системы
🔸 Сложность связей проекта (relational complexity, definition 25, стр. 20) — произведение кол-ва объектов проекта и кол-ва связей объекта с самым большим кол-вом связей
Т.е. как будто все объекты системы одинаково сложны

Вот несколько сухих выводов оттуда:
1️⃣ Минимальная когнитивная сложность — символьная сложность. Когда архитектурная и операционная сложность = 1.
Т.е. проект без циклов, ветвлений, объектов, вызовов методов и т.д.
2️⃣ Максимальная когнитивная сложность — все объекты одинаково сложны
3️⃣ Когнитивная сложность находится между минимальным и максимальным значениями (corollary 4, стр. 21)
4️⃣ Зависимость между минимальной и максимальной сложностью — квадратичная
Т.е. условные 10 строк кода могут создать максимальную сложность в 100. Если каждая из строк будет вынесена в отдельный класс, в отдельный метод с одним аргументом и одним возвращаемым значением

Душно, да? Давайте своими словами:
🔹 Выделение логики в отдельный метод не всегда равно упрощение
Т.е. если метод с 2мя for'ами разбить на 2 метода по 1 for в каждом, то сложность объекта увеличится в 2 раза 🤷‍♂️
🔹 Сделать объект проще = уменьшить его архитектурную и операционную сложность
Т.е. выделить аргументы в 1 объект, избавиться от возвращаемого значения, уменьшить кол-во локальных переменных и уменьшить кол-во операций
🔹 Уменьшение архитектурной сложности ведет к увеличению сложности связей
Т.е. суммарная когнитивная сложность проекта остается такой же
🔹 Когнитивная сложность проекта всегда растет

#software_engineering@UniArchitect
👍191
Unity Empty Project Template (UEPT)

Под постом про точку входа собралось больше 50 👍, это просто ошеломительный результат 🤯

После пары выходных плотной работы я подготовил шаблон, с которого вы можете начать создание своего нового проекта 😎

В разделе Installation вы сможете найти инструкции по настройке.
Пока там 10 пунктов, все из которых нужно делать ручками.
Использовать unitypackage не получилось т.к. он игнорирует пустые папки при импорте 😵‍💫

Я хочу написать автоматизацию пунктов 4-9. Окно-помощник, в котором можно будет:
— Переименовать все папки
— Удалить лишние папки
— Переименовать все asmdef и asmref файлы
— Удалить все примеры
— Сгенерировать Scope, Flow файлы для Zenject
Благодаря ему можно будет за пару кликов настроить проект!

Давайте наберем 25 ⭐️ GitHub и тогда еще за пару недель я 👨‍💻 окно-помощник

Как вам шаблон? 👨‍💻 в комменты

@UniArchitect
Please open Telegram to view this post
VIEW IN TELEGRAM
👍44🤯2