Является ли слабое соединение без вариантов использования анти-паттерном?


22

Слабое связывание для некоторых разработчиков является святым Граалем хорошо спроектированного программного обеспечения. Это, конечно, хорошо, когда он делает код более гибким перед лицом изменений, которые могут произойти в обозримом будущем, или избегает дублирования кода.

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

Считаете ли вы, что сосредоточение внимания на слабой связи без каких-либо вариантов использования для слабой связи (например, во избежание дублирования кода или планирования изменений, которые могут произойти в обозримом будущем) является анти-паттерном? Может ли ослабленная муфта попасть под зонтик YAGNI?


1
Большинство преимуществ приходят со стоимостью. Используйте, если выгода превышает стоимость.
LennyProgrammers

4
Вы забыли оборотную сторону монеты со слабой связью, и это high cohesionодно без другого - пустая трата усилий и иллюстрация фундаментального непонимания того или другого.

Ответы:


13

В некотором роде.

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

С другой стороны, переподготовка к нелепым изменениям будет много ненужной сложности и усилий. ЯГНИ, как ты говоришь, бьет его по голове.


22

Практика программирования X хороша или плоха? Ясно, что ответ всегда "это зависит".

Если вы смотрите на свой код, задаваясь вопросом, какие «шаблоны» вы можете внедрить, значит, вы делаете это неправильно.

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

Если вы «проектируете» свое решение так, чтобы оно могло бесконечно расширяться и изменяться, то вы фактически усложняете его.

Я думаю, в конце концов, вы остаетесь с единственной правдой: более или менее сложно разделить объекты? Если их сложнее соединить, то это правильное решение. Если их легче отделить, то это правильное решение.

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


4
Я сделал это только на днях: я подумал, что мне понадобится некоторое перенаправление между двумя классами «на всякий случай». Затем я повредил голову, пытаясь что-то отладить, вырвал косвенность и стал намного счастливее.
Фрэнк Ширар

3

Я думаю, что вы получаете здесь понятие сплоченности . У этого кода хорошая цель? Могу ли я усвоить эту цель и понять «общую картину» того, что происходит?

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

С гибкой точки зрения, я мог бы предположить, что такая слабая связь будет анти-паттерном. Без сплоченности или даже вариантов ее использования вы не сможете написать разумные модульные тесты и не сможете проверить назначение кода. Теперь гибкий код может привести к слабой связи, например, при использовании разработки через тестирование. Но если были созданы правильные тесты в правильном порядке, то, скорее всего, есть и хорошая сплоченность, и слабая связь. И вы говорите только о тех случаях, когда явно нет сплоченности.

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

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


1

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

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

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


1

Простой ответ - слабая связь - это хорошо, если все сделано правильно.

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

Простые правила проектирования: 1. Не объединяйте знания о нескольких предметах в одну точку (как указано везде, зависит), если вы не строите интерфейс фасада. 2. одна функция - одна цель (эта цель может быть многогранной, например, в фасаде) 3. один модуль - один четкий набор взаимосвязанных функций - одна ясная цель 4. если вы не можете просто протестировать его, тогда он не имеет простая цель

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

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


0

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

Теперь моя библиотека изображений полностью независима от математической библиотеки, так что независимо от того, какие изменения я внесу в мою математическую библиотеку, это не повлияет на библиотеку изображений. Это ставит стабильность на первое место. Библиотека изображений теперь более стабильна, так как у нее значительно меньше причин для изменений, поскольку она отделена от любой другой библиотеки, которая может измениться (кроме стандартной библиотеки C, которая, надеюсь, никогда не изменится). В качестве бонуса, его также легко развернуть, когда он представляет собой отдельную библиотеку, которая не требует использования других библиотек для ее создания и использования.

Стабильность очень полезна для меня. Мне нравится создавать коллекцию хорошо протестированного кода, у которого есть все меньше и меньше причин когда-либо меняться в будущем. Это не несбыточная мечта; У меня есть C-код, который я использую и использую снова с конца 80-х, который с тех пор не изменился вообще. По общему признанию это низкоуровневые вещи, такие как пиксельно-ориентированный и связанный с геометрией код, в то время как многие мои высокоуровневые вещи устарели, но это то, что все еще помогает иметь много. Это почти всегда означает, что библиотека опирается на все меньше и меньше вещей, если вообще ничего внешнего. Надежность возрастает, если ваше программное обеспечение все в большей степени зависит от стабильных оснований, которые находят мало или не имеют причин для изменения. Меньше движущихся частей действительно хорошо, даже если на практике количество движущихся частей намного больше, чем у стабильных частей.

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

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

Сцепление и стабильность, пример ECS

Мне также нравятся системы сущностей и компонентов, и они вводят много тесных связей, потому что зависимости системы от компонентов имеют прямой доступ к необработанным данным и манипулируют ими, например:

введите описание изображения здесь

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

Между тем слабосвязанная альтернатива может быть такой:

введите описание изображения здесь

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

Кроме того, если что-то изменилось в дизайне, вы получите больше каскадных поломок, чем в ECS, и, как правило, будет больше причин и соблазнов для изменений в дизайне, поскольку каждая вещь пытается обеспечить хороший объектно-ориентированный интерфейс и абстракцию. Это сразу же приходит с идеей, что каждая мелочь будет пытаться наложить ограничения и ограничения на дизайн, и эти ограничения часто являются тем, что оправдывает изменения дизайна. Функциональность намного более ограничена и должна делать намного больше проектных предположений, чем необработанные данные.

На практике я обнаружил, что вышеупомянутый тип "плоской" системы ECS гораздо проще рассуждать, чем даже самые слабосвязанные системы со сложной паутиной слабых зависимостей, и, что наиболее важно для меня, я нахожу так мало причин для версии ECS когда-либо потребуется изменить какие-либо существующие компоненты, поскольку компоненты, от которых зависит, не несут никакой ответственности, кроме как предоставить соответствующие данные, необходимые для функционирования систем. Сравните сложность проектирования чистого IMotionинтерфейса и конкретного объекта движения, реализующего этот интерфейс, который предоставляет сложные функциональные возможности, пытаясь при этом сохранить инварианты над частными данными и компонент движения, который должен только предоставлять необработанные данные, относящиеся к решению проблемы, и не беспокоиться о функциональность.

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

Самые стабильные функции, которые я когда-либо писал (те, которые я использовал и повторно использовал с конца 80-х годов без необходимости их изменения), были те, которые полагались на необработанные данные, как геометрическая функция, которая только что приняла массив числа с плавающей запятой и целые числа, а не те, которые зависят от сложного Meshобъекта или IMeshинтерфейса, или умножение вектора / матрицы, которое просто зависело от, float[]или double[]не то, от которого зависело FancyMatrixObjectWhichWillRequireDesignChangesNextYearAndDeprecateWhatWeUse.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.