Его беспокоило то, что большое количество занятий перерастет в кошмар обслуживания. На мой взгляд, это будет иметь совершенно противоположный эффект.
Я абсолютно на стороне вашего друга, но это может зависеть от наших доменов, типов проблем и конструкций, которые мы решаем, и особенно от того, какие типы вещей могут потребовать изменений в будущем. Разные проблемы, разные решения. Я не верю в правильное или неправильное, просто программисты пытаются найти лучший способ, которым они могут лучше всего решить свои конкретные проблемы дизайна. Я работаю в VFX, который не слишком отличается от игровых движков.
Но проблема для меня, с которой я боролся в том, что, по крайней мере, можно было бы назвать несколько более похожей на SOLID-совместимую архитектуру (она была на основе COM), может грубо сводиться к «слишком большому количеству классов» или «слишком большому количеству функций», так как твой друг мог бы описать. Я бы конкретно сказал: «слишком много взаимодействий, слишком много мест, которые могли бы плохо себя вести, слишком много мест, которые могли бы вызвать побочные эффекты, слишком много мест, которые, возможно, нужно изменить, и слишком много мест, которые могли бы не делать то, что мы думаем, что они делают». «.
У нас было несколько абстрактных (и чистых) интерфейсов, реализованных множеством подтипов, вроде этого (сделал эту диаграмму в контексте обсуждения преимуществ ECS, не обращая внимания на нижний левый комментарий):
Где интерфейс движения или интерфейс узла сцены могут быть реализованы с помощью сотен подтипов: источников света, камер, сеток, решателей физики, шейдеров, текстур, костей, примитивных форм, кривых и т. Д. И т. Д. (И часто бывают разные типы каждого ). И главная проблема заключалась в том, что эти проекты были не такими стабильными. У нас были изменяющиеся требования, и иногда сами интерфейсы приходилось менять, и когда вы хотите изменить абстрактный интерфейс, реализованный на 200 подтипах, это чрезвычайно дорогое изменение. Мы начали смягчать это, используя абстрактные базовые классы, между которыми снижались затраты на такие изменения дизайна, но они все еще были дорогими.
Итак, в качестве альтернативы я начал исследовать архитектуру системы сущностей и компонентов, довольно часто используемую в игровой индустрии. Это изменило все, чтобы быть таким:
И вау! Это была такая разница с точки зрения ремонтопригодности. Зависимости перешли не к абстракциям , а к данным (компонентам). И, по крайней мере, в моем случае, данные были гораздо более стабильными и их было проще понять с точки зрения проектирования, несмотря на изменяющиеся требования (хотя то, что мы можем делать с одними и теми же данными, постоянно меняется с изменением требований).
Кроме того, поскольку объекты в ECS используют композицию вместо наследования, им фактически не нужно содержать функциональность. Они просто аналогичный «контейнер компонентов». Это сделало так, что аналогичные 200 подтипов, которые реализовали интерфейс движения, превращаются в 200 экземпляров сущности (не отдельные типы с отдельным кодом), которые просто хранят компонент движения (который является ничем иным, как данными, связанными с движением). A PointLight
больше не является отдельным классом / подтипом. Это не класс вообще. Это экземпляр объекта, который просто комбинирует некоторые компоненты (данные), связанные с тем, где он находится в пространстве (движение), и конкретными свойствами точечных источников света. Единственная функциональность, связанная с ними, находится внутри систем, таких какRenderSystem
, который ищет компоненты света в сцене, чтобы определить, как визуализировать сцену.
С изменением требований в соответствии с подходом ECS часто возникала необходимость изменить только одну или две системы, работающие с этими данными, или просто ввести новую систему на стороне, или ввести новый компонент, если потребовались новые данные.
Так что, по крайней мере, для моего домена, и я почти уверен, что это не для всех, это сильно упростило ситуацию, потому что зависимости стремились к стабильности (вещи, которые не нужно часто менять вообще). Это не имело место в архитектуре COM, когда зависимости равномерно стекались к абстракциям. В моем случае гораздо проще выяснить, какие данные требуются для первоначального движения, а не все возможные вещи, которые вы могли бы с ним сделать, что часто меняется с течением месяцев или лет, когда появляются новые требования.
Есть ли в ООП случаи, когда некоторые или все принципы SOLID не пригодны для очистки кода?
Ну, чистый код я не могу сказать, так как некоторые люди приравнивают чистый код к SOLID, но определенно есть некоторые случаи, когда отделение данных от функциональности, как это делает ECS, и перенаправление зависимостей от абстракций к данным, безусловно, может сделать вещи намного проще. измените, по очевидным причинам связи, если данные будут намного более стабильными, чем абстракции. Конечно, зависимости от данных могут затруднить поддержание инвариантов, но ECS стремится свести это к минимуму с помощью системной организации, которая минимизирует количество систем, которые получают доступ к компоненту любого типа.
Это не обязательно, что зависимости должны течь к абстракциям, как предполагает DIP; зависимости должны стремиться к вещам, которые вряд ли нуждаются в будущих изменениях. Это может или не может быть абстракциями во всех случаях (это, конечно, не в моем).
- Да, существуют принципы проектирования ООП, которые частично противоречат SOLID
- Да, существуют принципы проектирования ООП, которые полностью противоречат SOLID.
Я не уверен, является ли ECS действительно ароматом ООП. Некоторые люди определяют это таким образом, но я вижу, что это очень сильно отличается от характеристик связи и отделения данных (компонентов) от функциональности (систем) и отсутствия инкапсуляции данных. Если бы это считалось формой ООП, я бы подумал, что он очень сильно конфликтует с SOLID (по крайней мере, самые строгие идеи SRP, open / closed, подстановка liskov и DIP). Но я надеюсь, что это разумный пример одного случая и области, где самые фундаментальные аспекты SOLID, по крайней мере, так как люди обычно интерпретируют их в более узнаваемом контексте ООП, могут быть не применимы.
Крошечные классы
Я объяснял архитектуру одной из моих игр, которая, к удивлению моего друга, содержала много небольших классов и несколько уровней абстракции. Я утверждал, что это было результатом того, что я сосредоточился на том, чтобы дать всем Единую Ответственность, а также ослабить связь между компонентами.
ECS бросил вызов и сильно изменил мои взгляды. Как и вы, я привык думать, что сама идея ремонтопригодности состоит в том, чтобы иметь простейшую реализацию для возможных вещей, что подразумевает много вещей и, кроме того, много взаимозависимых вещей (даже если взаимозависимости находятся между абстракциями). Это имеет смысл, если вы увеличиваете только один класс или функцию, чтобы увидеть наиболее простую и простую реализацию, а если мы ее не видим, реорганизуйте ее и, возможно, даже разложите дальше. Но в результате может быть легко пропустить то, что происходит с внешним миром, потому что всякий раз, когда вы делите что-либо относительно сложное на две или более вещи, эти две или более вещи неизбежно должны взаимодействовать * (см. Ниже) друг с другом в некоторых Кстати, или что-то снаружи должно взаимодействовать со всеми ними.
В эти дни я обнаружил, что существует баланс между простотой чего-либо и количеством вещей, и сколько требуется взаимодействия. Системы в ECS имеют тенденцию быть довольно здоровенными с нетривиальными реализациями для работы с данными, такими как PhysicsSystem
или RenderSystem
или GuiLayoutSystem
. Однако тот факт, что сложному продукту так мало нужно, имеет тенденцию облегчать отступление и рассуждать об общем поведении всей кодовой базы. Там есть что-то, что может указывать на то, что неплохо было бы полагаться на меньшее количество более объемных классов (по-прежнему выполняющих, возможно, единственную ответственность), если это означает, что нужно поддерживать меньше классов, о которых нужно думать, и меньше взаимодействий на протяжении всего процесса. система.
взаимодействия
Я говорю «взаимодействия», а не «связывание» (хотя сокращение взаимодействий подразумевает уменьшение обоих), поскольку вы можете использовать абстракции для разделения двух конкретных объектов, но они по-прежнему взаимодействуют друг с другом. Они все еще могут вызывать побочные эффекты в процессе этого косвенного общения. И часто я нахожу, что моя способность рассуждать о правильности системы связана с этими «взаимодействиями» больше, чем с «связью». Минимизация взаимодействий, как правило, облегчает мне понимание всего с высоты птичьего полета. Это означает, что вещи вообще не разговаривают друг с другом, и в этом смысле ECS также имеет тенденцию действительно минимизировать «взаимодействия», а не просто связь с минимумом минимумов (по крайней мере, я не имею
Тем не менее, это может быть, по крайней мере, частично я и мои личные слабости. Я обнаружил, что самым большим препятствием для меня является создание систем огромного масштаба, и я до сих пор уверенно рассуждаю о них, перемещаюсь по ним и чувствую, что могу вносить любые потенциальные желаемые изменения в любом месте предсказуемым образом, это управление состоянием и ресурсами наряду с побочные эффекты. Это самое большое препятствие, которое начинает возникать при переходе от десятков тысяч LOC к сотням тысяч LOC к миллионам LOC, даже для кода, который я полностью создал самостоятельно. Если что-то замедлит меня до уровня выше всего, это чувство, что я больше не могу понять, что происходит с точки зрения состояния приложения, данных, побочных эффектов. Это' Это не роботизированное время, которое требуется для внесения изменений, которое замедляет меня настолько сильно, как неспособность понять все последствия изменений, если система выходит за пределы способности моего разума рассуждать об этом. И сокращение количества взаимодействий стало для меня наиболее эффективным способом, позволяющим значительно увеличить объем продукта и значительно расширить его возможности, при этом я лично не перегружен этими вещами, поскольку сокращение количества взаимодействий до минимума также уменьшает количество мест, которые могут даже возможно изменить состояние приложения и вызвать побочные эффекты существенно.
Это может обернуться чем-то вроде этого (где все на диаграмме имеет функциональность, и, очевидно, сценарий реального мира будет иметь много-много раз количество объектов, и это диаграмма взаимодействия, а не связь, как связь между ними будут абстракции):
... для этого, где только системы имеют функциональность (синие компоненты теперь являются просто данными, а теперь это диаграмма связи):
И по этому поводу возникают мысли, и, возможно, есть способ создать некоторые из этих преимуществ в более подходящем контексте ООП, более совместимом с SOLID, но я пока не совсем нашел конструкции и слова, и я нахожу это Трудно, так как терминология я привык разбрасывать все, что непосредственно связано с ООП. Я продолжаю пытаться выяснить это, читая ответы людей здесь, а также стараюсь изо всех сил сформулировать свои собственные, но есть некоторые вещи, очень интересные в природе ECS, которые я не смог точно указать на это. может быть более широко применимым даже к архитектурам, которые его не используют. Я также надеюсь, что этот ответ не сработает как акция ECS! Я просто нахожу это очень интересным, так как проектирование ECS действительно сильно изменило мои мысли,