Существуют ли существенные недостатки в зависимости от абстракций?

9

Я читал эту вики о Принципе стабильных абстракций (SAP) .

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

SteveCallender
источник
Попробуйте использовать компонент, который вам удобен, не используйте предоставляемые им абстракции, но делайте все в деталях на уровне ниже, чем вы привыкли. Это даст вам довольно хорошее представление о преимуществах и недостатках абстракции.
Килиан Фот
2
Вы читали связанную статью и / или книгу, на которой основана статья?
Йорг Миттаг
1
+1 Хороший вопрос, тем более что я не думаю, что связь между стабильностью и абстракцией сразу интуитивна. Страница 11 этой статьи помогает, ее пример абстрактного случая имеет смысл, но, возможно, кто-то может написать более ясный пример конкретного случая. Просьба снять с удержания.
Майк
С какой проблемной областью вы имеете дело с этими абстракциями? Как отмечалось на С2: «При моделировании реальных доменов - мира клиентов, сотрудников, счетов-фактур, счетов-фактур, продуктов, SKU, зарплат и т. Д. - найти стабильные абстракции может быть сложно. Вычислительные домены - Мир стеков, очередей, функций, деревьев, процессов, потоков, графических виджетов, отчетов, форм и т. д. - с гораздо большей вероятностью будет стабильным ». и «В некоторых областях трудно получить стабильные абстракции». Не зная, какую проблему вы пытаетесь решить с помощью SAP, трудно дать вам хороший ответ.
@ JörgWMittag и Mike - Да, я прочитал статью. Я просто чувствую, что нет объяснения, почему «нестабильные пакеты должны быть конкретными». На странице 13 этой статьи он показывает график, но на самом деле не объясняет слишком подробно, почему следует избегать (1,1) на графике? Является ли идея, что в основном нестабильная, означает меньше афферентных зависимостей и нет необходимости использовать абстракцию? Если это так ... разве не рекомендуется использовать абстракцию в любом случае, просто на случай, если стабильность изменится с изменением требований ..
SteveCallender

Ответы:

7

Думайте о ваших пакетах как об API, чтобы взять пример из бумаги, взять определения для Readerс string Reader.Read()и Writerс void Writer.Write(string)как ваш абстрактный API.

Затем вы можете создать класс Copyс методом Copier.Copy(Reader, Writer)и реализацией Writer.Write(Reader.Read())и, возможно, с некоторыми проверками работоспособности.

Теперь, вы делаете конкретные реализации, например FileReader, FileWriter, KeyboardReaderи DownloadThingsFromTheInternetReader.

Что если вы хотите изменить свою реализацию FileReader? Нет проблем, просто измените класс и перекомпилируйте.

Что если вы хотите изменить определение своей абстракции Reader? К сожалению, вы не можете просто изменить, но вы также должны изменить Copier, FileReader, KeyboardReaderи DownloadThingsFromTheInternetReader.

Это обоснование принципа стабильной абстракции: сделайте ваши конкретизации менее стабильными, чем абстракции.

отстой
источник
1
Я согласен со всем, что вы говорите, но я считаю, что авторское определение стабильности и ваше разнятся. Вы относитесь к стабильности как к необходимости изменения, автор говорит, что «стабильность - это не мера вероятности того, что модуль изменится; скорее, это мера сложности смены модуля». Поэтому мой вопрос заключается в том, почему выгодно, чтобы пакеты, которые легко изменить, были более конкретными, а не абстрактными?
SteveCallender
1
@SteveCallender Это тонкое различие: авторское определение «стабильности» - это то, что большинство людей называют «потребностью в стабильности». Т.е. чем больше модулей зависит от модуля, тем более «стабильным» должен быть модуль.
Residuum
6

Из-за ЯГНИ .

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

Я также думаю, что реальный вопрос, который нужно задать себе, это не «Нужно ли мне зависеть от абстракций?» а скорее «Нужна ли модульность?». И модульность не всегда нужна, см. Ниже.

В компании, в которой я работаю, некоторые программы, которые я разрабатываю, тесно связаны с каким-либо аппаратным устройством, с которым оно должно взаимодействовать. Эти устройства разрабатываются для достижения очень конкретных целей и являются не только модульными. :-) После того , как первый произведенный устройство выходит из завода и устанавливается где - то, как его встроенное программное обеспечение и аппаратные средства никогда не может изменить, когда - либо .

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

пятнистый
источник
1
Я склонен согласиться с YAGNI, но я удивляюсь твоему примеру. Вы никогда и не повторять любой код в разных устройствах? Мне трудно поверить, что на устройствах одной и той же компании нет общего кода. Кроме того, как клиенты любят, когда вы не исправляете ошибки в их прошивке? Вы говорите , что никогда не являются ошибками, никогда ? Если у вас есть один и тот же код, который глючит в 4 разных реализациях, вы должны исправить ошибку 4 раза, если она не в общем модуле.
Фурманатор
1
Общий код @Fuhrmanator отличается от абстракций. Общий код может просто означать вспомогательный метод или библиотеку - никаких абстракций не требуется.
Эйлон
@Fuhrmanator Конечно, у нас есть общий код в библиотеках, но, как сказал Эйлон, не все зависит от абстракций (однако некоторые части делают это). Я никогда не говорил, что ошибок нет, я сказал, что их нельзя исправить (по причинам, которые выходят за рамки вопроса ОП).
Пятно
@ Eilon мой комментарий о модульности не всегда нужен (не абстракции).
Фурманатор
@Spotted Нет проблем с тем, что я не смог заплатить. Это довольно специфический пример, не типичный для большинства программ.
Фурманатор
6

Я думаю, что вы, возможно, смущены словом « стабильный», которое выбрал Роберт Мартин. Вот где я думаю, что путаница начинается:

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

Если вы прочитаете оригинальную статью , вы увидите (выделение мое):

Классическое определение слова «стабильность» звучит так: «Нелегко перенести». Это определение, которое мы будем использовать в этой статье. То есть стабильность не является мерой вероятности того, что модуль изменится; скорее это мера сложности смены модуля .

Очевидно, что модули, которые сложнее изменить, будут менее изменчивыми. Чем сложнее заменить модуль, т. Е. Чем он более стабилен, тем менее изменчивым он будет.

Я всегда боролся с авторским выбором слова « стабильный» , поскольку я (как и вы) склонен думать о «вероятностном» аспекте стабильности, т. Е. Вряд ли изменится . Сложность подразумевает, что изменение этого модуля сломает множество других модулей, и для исправления кода потребуется много работы.

Мартин также использует слова « независимый и ответственный» , которые для меня гораздо более значимы. На своем обучающем семинаре он использовал метафору о родителях детей, которые растут, и о том, как они должны быть «ответственными», потому что их дети зависят от них. Развод, безработица, тюремное заключение и т. Д. Являются отличными примерами того, как изменения в родителях будут влиять на детей. Поэтому родители должны быть «стабильными» на благо своих детей. Кстати, эта метафора детей / родителей не обязательно связана с наследованием в ООП!

Итак, следуя духу «ответственности», я придумал альтернативные значения, которые трудно изменить (или не следует менять ):

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

Итак, вставив эти определения в утверждение

чем стабильнее пакет, тем более абстрактным он должен быть

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

Давайте процитируем принцип стабильной абстракции (SAP), подчеркнув запутанные слова стабильный / нестабильный:

Пакеты, которые являются максимально стабильными, должны быть максимально абстрактными. Нестабильные пакеты должны быть бетонными. Абстракция пакета должна быть пропорциональна его стабильности .

Разъяснение без этих смущающих слов:

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

TL; DR

Название вашего вопроса спрашивает:

Существуют ли существенные недостатки в зависимости от абстракций?

Я думаю, что если вы правильно создаете абстракции (например, они существуют, потому что от них зависит большой объем кода), то никаких существенных недостатков нет.

Fuhrmanator
источник
0

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

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

Таким образом, если ваш пакет будет часто меняться, он должен лучше предоставлять конкретные, а не абстракции. Иначе ... кто, черт возьми, будет его использовать? ;)

Владислав Раструсный
источник
0

Имейте в виду показатель стабильности Мартина и то, что он подразумевает под «стабильностью»:

Instability = Ce / (Ca+Ce)

Или:

Instability = Outgoing / (Incoming+Outgoing)

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

Между тем, когда у вас есть противоположный сценарий полной «стабильности» с пакетом, используемым одной или несколькими вещами, но он ничего не использует сам по себе, например, центральный пакет, используемый программным обеспечением, тогда Мартин говорит, что эта вещь должна быть Аннотация. Это также подкрепляется частью DIP SOLI (D), принципом инверсии зависимостей, который в основном утверждает, что зависимости должны равномерно перетекать в абстракции как для кода низкого, так и высокого уровня.

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

Существуют ли существенные недостатки в зависимости от абстракций?

Ну, я на самом деле не согласен с Мартином здесь, по крайней мере, в отношении моего домена, и здесь мне нужно ввести новое определение «стабильности», как «отсутствие причин для изменений». В этом случае я бы сказал, что зависимости должны стремиться к стабильности, но абстрактные интерфейсы не помогают, если абстрактные интерфейсы нестабильны (по моему определению «неустойчивые», как в случае склонности к многократным изменениям, а не Мартина). Если разработчики не могут получить правильные абстракции и клиенты неоднократно меняют свое мнение таким образом, что абстрактные попытки моделировать программное обеспечение становятся неполными или неэффективными, мы больше не выигрываем от расширенной гибкости абстрактных интерфейсов для защиты системы от каскадных изменений, нарушающих зависимость , В моем личном случае я нашел двигатели ECS, такие как те, что найдены в играх ААА,наиболее конкретный : к необработанным данным, но такие данные очень стабильны (например, «вряд ли когда-либо нужно будет менять»). Я часто находил вероятность того, что что-то, требующее будущих изменений, было бы более полезным показателем, чем отношение эфферентных к общему количеству связей при принятии решений SE.

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

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


источник