Эта цитата действительно заставила меня посмеяться. Тем не менее, я считаю минимизацию побочных эффектов действительно переводить в код, который гораздо проще рассуждать и поддерживать. Тем не менее, я не могу позволить себе роскошь исследовать функциональное программирование так, как хотелось бы.
То, как я смотрю на это при работе на объектно-ориентированных и процедурных языках, которые вращаются вокруг побочных эффектов, состоит в том, чтобы содержать и изолировать побочные эффекты.
В качестве основного примера, у видеоигры есть необходимый побочный эффект отрисовки графики на экране. Тем не менее, здесь есть два различных типа путей проектирования в отношении побочных эффектов.
Кто-то стремится минимизировать и ослабить связь, делая рендерер очень абстрактным и в основном говорит, что нужно визуализировать. Затем другие части системы сообщают визуализатору, что рисовать, и это может быть группа примитивов, таких как треугольники и точки с матрицами проекции и просмотра моделей, или, возможно, что-то более высокого уровня, например абстрактные модели, камеры, источники света и частицы. В любом случае, такой дизайн вращается вокруг многих вещей, вызывающих внешние побочные эффекты, поскольку потенциально многие части кодовой базы будут подталкивать изменения к средству визуализации (независимо от того, насколько он абстрактен или косвенен, чистый эффект в такой система запускает внешние эффекты рендеринга).
Другой способ - содержать / изолировать эти побочные эффекты. Вместо того, чтобы визуализатору отображалось, что отображать, он вместо этого становится связанным с игровым миром (хотя это могут быть лишь некоторые основные абстракции и, возможно, доступ к графу сцены). Теперь он получает доступ к сцене самостоятельно (доступ только для чтения), просматривает сцену и выясняет, что нужно визуализировать, используя больше дизайна в стиле pull. Это приводит к большей связи рендерера с игровым миром, но это также означает, что побочные эффекты, связанные с выводом на экран, теперь полностью содержатся внутри рендерера.
Этот последний дизайн содержит или изолирует побочных эффектов, и я считаю, что этот тип дизайна гораздо проще поддерживать и поддерживать правильно. Это по-прежнему вызывает побочные эффекты, но все побочные эффекты, связанные с выводом графики на экран, теперь полностью содержатся в рендерере. Если есть проблема, вы знаете, что ошибка будет в коде рендерера, а не в результате чего-то внешнего, неправильно использовавшего ее и сообщившего о неправильных действиях.
Из-за этого, когда дело доходит до связи, я всегда считал более желательным максимизировать эфферентные (исходящие) связи в вещах, которые вызывают внешние побочные эффекты и минимизировать афферентные (входящие) связи. Это относится независимо от абстракций. В контексте побочных эффектов зависимость от IRenderer
все еще является зависимостью от конкретного Renderer
в том, что касается коммуникации относительно того, какие побочные эффекты могут произойти. Абстракция не имеет значения, насколько побочные эффекты будут происходить.
Рендерер должен зависеть от остального мира, чтобы он мог полностью изолировать эти побочные эффекты на экране; остальной мир не должен зависеть от визуализатора. Такая же аналогия для файловой заставки. Хранителю файла не следует указывать, что сохранять во внешнем мире. Следует взглянуть на окружающий мир и выяснить, что экономить самостоятельно. Таков будет путь проектирования, который стремится изолировать и сдержать побочные эффекты; это имеет тенденцию быть более основанным на напряжении чем основанное на толчке. Результат имеет тенденцию вводить немного больше связи (хотя она может быть слабой), если вы строите графики зависимостей, поскольку может потребоваться связать заставку с вещами, которые он даже не заинтересован в сохранении, или для средства визуализации может потребоваться доступ только для чтения к вещам он даже не заинтересован в рендеринге, чтобы обнаружить то, что его интересует в рендеринге.
Тем не менее, конечный результат заключается в том, что зависимости от переходят от *1031* к побочным эффектам. Когда у нас есть система с множеством зависимостей, направленная на подталкивание внешних побочных эффектов, я всегда находил, что о них сложнее всего рассуждать, так как многие части системы могут потенциально изменять внешние состояния до такой степени, что не просто сложно понять, что произойдет, но также , когда и , где . Поэтому наиболее простой способ исправить / предотвратить эту проблему - попытаться заставить зависимости перетекать от побочных эффектов, а не к ним.
Во всяком случае, я обнаружил, что в пользу этих типов конструкций есть практический способ помочь избежать ошибок, а также помочь обнаружить и изолировать их, когда они существуют, чтобы их было легче воспроизводить и исправлять.
Другая полезная стратегия, которую я нахожу, состоит в том, чтобы сделать побочные эффекты более однородными для любой данной петли / фазы системы. Например, вместо выполнения цикла, который удаляет связанные данные из чего-то, разделяет их, а затем удаляет, я обнаружил, что гораздо проще, если в таких случаях вы делаете три однородных цикла. Первый однородный цикл может удалить связанные данные. Второй однородный цикл может отделить узел. Третий однородный цикл может удалить его из остальной системы. Это на более низком уровне, связанном больше с реализацией, чем с дизайном, но я часто обнаруживал, что результат легче рассуждать, поддерживать и даже оптимизировать (проще распараллелить, например, и с улучшенной локализацией ссылок) - вы принимаете эти неоднородные циклы запускают несколько различных типов побочных эффектов и разбивают их на несколько однородных циклов, каждый из которых вызывает только один однородный вид побочного эффекта.