Как стать автором
Обновить

Переосмысление SOLID: почему традиционные принципы проектирования не работают при разработке игр

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров9.8K
Всего голосов 27: ↑8 и ↓19-9
Комментарии32

Комментарии 32

SOLID это набор принципов. ECS это паттерн. Принцип это высокоуровневая абстракция, задающая общий ход рассуждениям в процессе дизайна. Паттерн описывает конкретный способ реализации конкретной задачи в конкретном контексте. По смыслу это разные вещи.

Прости, дружище. Нечайно вместо поста тебе минус кинул. :с В качестве компенсации кинул плюс отдельно на профиль.

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

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

Можно-ли обойтись без принципов? Скорее всего нет, если мы хотим дружить с логикой. Ведь логика формально это аксиоматическая система. Т.е. все свои утверждения можно разделить на два класса: аксиомы и теоремы. Теоремы выводятся из аксиом или других теорем. Аксиомы не выводятся ни от куда - это начала. Выделение аксиом даёт понимание структуры логики вашей деятельности, а минимизация их количества - к абстракции и упрощению.

Поэтому задача поиска принципов весьма захватывающая для исследователей в любой научной обрасти, и computer science тут не исключение. Но я согласен с автором в том, что полезность такой деятельности не особо очевидна когда речь идёт о разработке конкретной игры. Здесь нужны в основном конкретные рецепты, такие как паттерны.

Так то паттерн про решение определенной проблемы/задачи при проектировании, а не про конкретную реализацию. Тут скорее проблема в том, что автор считает компонентный подход чем то другим нежели разбиение на небольшие классы "по SRP" (хотя это не так).

Дико извиняюсь, но булшит.

Проблема вообще не в неподходящести SOLID. Проблема в 2 дураках - программистах и менеджерах.

В UE, по крайней мере, несложно и даже отлично придерживаться этого паттерна, но посмотрите на рынок кадров - почти каждый первый это"любящий игры" чел самоучка/скилбоксер который даже имея пару лет опыта просто тупо не знает/понимает даже базовые принципы ООП, что уж там про солид, когда люди не понимают зачем нужны private/protected.

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

Вот потому имхо мы и имеем 40 fps багованое говно на 4090.

Подписываюсь под каждым словом.

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

Подвергать сомнениям дедовские принципы это нормально, иначе они превращаются в догмы.

Изначально SOLID возник в ходе переписки, когда ещё не было комментов на Хабре, и народ трындел в какой-то своей DLке на тему - какие у нас вообще есть принципы хорошего кода?

Сперва насобирали пару десятков. Но потом пришел Дядя Боб и набросил, что этот склад мудрости овер дофига для простого разработчика - надо быть проще и оставил пять с хвостиком.

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

Со временем SOLID мутировал под влиянием разных тенденций и трактовок. Та же Барбара Лисков спустя много лет на конференции как-то отметила в духе, что ее принцип подстановки в оригинале был вообще не о том (да и не она его придумала, а в последствии коллеги наши нестыковки применительно к своей задаче и его переделали), но довольна что кого-то это смогло вдохновить.

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

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

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

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

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

А что плохого в знаниях? Да, многое из накопленного опыта устарело, а некоторое как выяснилось даже вредно. Иногда, на поверку, "я не молюсь на ваши древние скрижали" оказывается просто отсутствием каких-либо знаний вообще. А чё, читаем туториал, берём библу и погнали. Знание, оно конечно для дураков.

А что не так с критикой private/protected? Private не нужен, если в языке есть final и protected. Если программист не хочет, чтобы класс не поломали при наследовании - пусть запрещает наследование целиком.
Эту систему public/private/protected придумали люди сорок лет назад, это не какой-то священный закон природы. Придумывали лучше, придумывали хуже, прижилась эта. Когда-нибудь и "отживется"

Сложно за эти темы спорить, так как у всех разное представление того, как это делать. Но всё же модификаторы доступа довольно нужная вещь. Ты можешь конечно наказать класс final'ом и запретить использовать полиморфизм, но немного заморочившись можно сохранить возможность наследования просто грамотно прописав модификаторы.

Как бы...?

Принцип единой ответственности (SRP)

Почитайте уже оригинальную статью Мартина и все комментарии, данные автором к ней за 20 лет.

Martin defines a responsibility as a reason to change, and concludes that a class or module should have one, and only one, reason to be changed (e.g. rewritten).

Отсюда следует, что если в вашей игре код движения персонажа используется, грубо говоря, еще и для движения облаков, то однажды вы налетите на всратые баги, когда какие-то фиксы для облаков затронут персонажей или наоборот.

При этом принцип не заставляет вас создавать CharacterMovement, CharacterCombat, CharacterInteraction и CharacterAnimation. Это обычно получается само собой из соображений сложности поддержки и восприятия или если, опять же, изменения в движении персонажа начинают засаживать баги в боевую систему. А так весь код персонажа вполне может быть в одном классе.

Также см. принцип "low coupling high cohesion", который идет рука об руку с SRP.

Мне тоже показалось, что автор предложил "альтернативы", а по сути, сделал все тоже самое, только в профиль. Просто "единственная ответственность" у него стала "перемещение персонажа", например. То есть, SRP в чистом виде, просто распределение ответственности другое.

строгой иерархии классов, предложенной SOLID

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

НЛО прилетело и опубликовало эту надпись здесь

SRP это как бог - его нет, многие в него верят, объяснить не могут

OCP не нарушается если принято решение полностью переделать класс. А вот добавлять пистолет с прицелом как отдельную от пистолета сущность не стоит (но возможно степень сродства не 100% и надо будет вводить класс стреляло)

LSP это основа Entity framework ов, то, что ваш босс как то по другому беснуется не должно менять интерфейс каким именно образом мы ему передаём урон (а вот получит он урон или нет уже вопрос реализации)

ISP если у вас каждый куст помимо коллизии еще и магазин реализует то вы что-то перемудрили

DIP не требует абстракций и вообще не влияет на производительность, зависимость может быть final friend и ковыряйся в её нутре сколько надо без накладных расходов. DIP говорит только что зависимости должны приходить извне, а не порождаться внутри/быть глобальными

Не Лискова, а Лисков. Барбара Лисков. А принципы проектирования от того, игра это или нет, не изменяются. Иначе можно только игру "ЩИ!!! Симулятор жестокости" написать.

Вам уже на dtf накидали минусов с указанием ошибок в рассуждениях, и общего качества материала, как будто написанного ЧатГпт. Пишите лучше код и игры, познавайте разные методы на практике, тогда на такое не останется времени ;)

Почему по твоему мнению, добавление лазерного прицела в пистолет должен менять кодовую базу, что противоречит OCP? Если код написан так, что стрельба меняется из-за модификации функционала, не относящегося к стрельбе, это значит что стрельба написана изначально некорректно. А OCP как раз и гласит, что мы открыты для расширения, а добавление лазерного прицела - отличная демонстрация расширения, которая не должна влиять на существующую механику стрельбу и прицеливания через мушку.

Приведенные вами примеры наоборот работают за SOLID, эти примеры в голос орут: "подумай, правильно ли спроектированы классы и их иерархия?" Именно для рефлексии с такой постановкой вопроса предназначен SOLID, чтобы разработчик задумался перед принятием решения. Поэтому маркеры в виде принципов я бы не назвал бесполезными. Разумеется конечное решение (и ответственность) за разработчиком.

Ох, Я прямо пригорел немножко, простите.

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

SRP - он диктует не то, что класс должен делать одно, он диктует что класс должен изменяться в интересах одного актора. В контексте игр это значит, что хорошей будет декомпозиция в интересах игр. Например декомпозиция игрового персонажа на модель, контроллер игрового объекта и вью - хорошая с точки зрения SRP игровая декомпозиция. Модель отвечает за поведение и, возможно сохранение данных (или сериализацию и передачу по сети), контроллер - за взаимодействие с прочими сервисами, например вводом, визуалом и эффектами. А вью - за детали отрисовки, анимацию и т.д. Это соблюдение SRP для игр.

OCP - тут его как только не трактуют, но, очевидно, не существует проектов, когда можно было бы только дописывать новый код, но не менять старый.
Вопрос скорее в том, какой дизайн объектов мы используем и насколько он расширяем. Применительно к пистолету OCP может означать что стоит проектировать пистолет как раздельно эммитер пулек, пистолет и визуалы дополнительного обвеса. Тогда для добавления лазерного прицела менять пистолет не нужно вообще, просто дописать прицел и скомбинировать их.
Конечно это высший пилотаж, придумать такое заранее может быть оверинжинерингом и вообще правильная декомпозиция - вопрос на милион в разработке ПО.
Поэтому если OCP не помогает - действительно не нужно об этом думать.

LSP - тут в целом обычная проблема. Не только в играх, но вообще везде любят использовать наследование как инструмент переиспользования кода, а не как объекты с общим интерфейсом.
В этом смысле, кстати, нарушения LSP нет, хотя ИМХО, код получается так себе, не стоит использовать глубокие иерархии.
Но что тут важно - LSP будет нарушено, если в списке "бегающие юниты" окажется турель, то она не сможет выполнять все функции бегающих юнитов, и может сломать какую нибудь систему, которой это правдо важно.
В принципе, это тоже не страшно.
Самым важным следствием LSP Я бы назвал такое - если вы наследуете объект, например юнит, который умеет бегать, стрелять и терять здоровье, а потом заглушаете часть функций (не умеет бегать) - то вы можете получить хрупкий код. Вместо этого лучше разделить функции по аспектам или компонентам и использовать не один интерфейс для всех юнитов, а для юнитов, которые стреляют или бегают.

ISP - опять же, тут люди городят такое, что можно согласиться - если вам кажется, что интерфейсов дофига - не используйте столько.
Я бы сказал проблема не в ISP, но в том, что их пихают туда, куда надо и куда не нужно, буквально следуя умным книжкам.
Тут рекомендация - класс сам по себе содержит интерфейс (свои публичные поля), это достаточный уровень абстракции, больше делать не нужно без веской причины.
Веских причин примерно 3 - полиморфизм, тестирование, инверсия зависимостей.

DIP - вот тут соглашусь.
Архитектура должна помогать, а не мешать, если при попытке делать чистую архитектуру получается херня, рулите в сторону практичного кода, а не чистой архитектуры. Либо подумайте еще.
И да, в любой момент может потребоваться хак, обращающийся к чему то напрямую, имеющий не ООП организацию и т.д.
Но вообще принцип неплох. Вообще Я рекомендую Чистую архитектуру того же Мартина, там неплохо написано, зачем.

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

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

Data Driven Design - тоже никак не противоречит классическим рекомендациям разработки ПО.
Собственно все крутые ребята топят за позднее связывание данных и конфигурацию.
Вообще это полезная штука.

В общем это выглядит немного как перпендикулярно тому, про что классические рекомендации разработки ПО.


Очень похоже на сгенерированную статью. Не "в стиле gpt", а от "неё" полностью от начала и до конца.
В этой статье, комментах на dtf и во второй статье на dtf очень похоже на то, что это какая-то нейросеть, которая обучается на примерах, задаёт вопросы, очень часто "признаёт ошибки", чтобы не выглядеть подозрительно (но при этом выглядит ещё подозрительнее, т.к. обычно новички, которые ринулись доказывать, что современные постулаты индустрии неверные, их неправильно понимают и что они только вредят и нужно меняться (предлагая взамен почти то же самое), имеют такое завышенное ЧСВ, что вряд ли знают и понимаю суть фразы "признавать ошибки"), не отвечает прямо на вопросы (в ответ выдаёт ещё более странные общие рассуждения, а не конкретику).
А главное, что натолкнуло на такую мысль: в текстах в вышеуказанных источниках заметно нарушение причинно-следственных связей, слабая аргументация, отсутствие прямой логики. И самое главное: совершенно непонятна цель. Как будто промт был "критика SOLID", без указания какой должна быть цель поста.

Очень спутанное повествование, хаотическое содержание, противоречие текста самому себе в разных местах, лишние повторы, слишком общие рассуждения после слова "например" - это всё признаки слабой экспертизы в вопросе, которая достигается жесткой нетерпимостью к ошибкам и большим количеством циклов обучения с обратной связью. Тут этого не наблюдается. То есть та "нейросеть" (настоящая или искусственная, не важно), которая это генерировала, развита слабовато. При этом орфография, пунктуация, связь слов между собой, корректность употребления слов, глубина понимания терминологии свидетельствуют о высокой грамотности. Противоречие. Если это генерировал один эксперт (низкого уровня), а редактировал другой эксперт высокого уровня, то большинства глупых ошибок не было бы и был бы указан редактор, т.к. среди экспертов высокого уровня есть уважение к чужому труду и часто выражается благодарность. Тут этого не наблюдается. Одна самосогласованная естественная нейросеть такое выдать не могла бы, т.к. принципы в основе сути статьи расходятся с принципами в основе словесного описания идей: движок преобразования идей в словесную форму развит гораздо сильнее, заметен очень сильный контраст, не свойственный людям (обычно если в голове бардак, то он заметен во всех видах деятельности). Да и человеческие принципы обычно распространяются на всю деятельность мозга, а не разделены по прикладным задачам, т.к. эти принципы реализованы в архитектуре естественных нейросетей, а не в фильтрах или генераторах мыслей.

Похоже проводится какой-то эксперимент. Хотелось бы почитать о результатах.

эмоции от статьи

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

Вы сейчас описали 90% комментариев на Хабре.

Решил, что публика на хабре менее токсичная чем на DTF?)
Я уверен, что почти все тут точно также скажут что это статься с искусственными примерами говнокода лишь бы оправдать плохое понимание SOLID'а

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

Такое ощущение, что есть непонимание SOLID, отсюда и "аргументы"

Нужно размуно подходить к разработке и адекватно оценивать время и затраты на будущую поддержку.

Примпняю DDD в unity мидкорных проектах, ещё ни разу не пожалел.

По началу, когда идёт фитчеринг немного дольше получается. Но количество костылей, полученных багов - минимально.

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

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

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

Блин, нейронку вам в бухту. (((

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации