Почему «защита от изменений» подразумевает направление зависимости? - PullRequest
0 голосов
/ 26 декабря 2018

Немного предыстории: я программист-самоучка, который начал работать на Python и изучал Java, когда я присоединился к MegaCorp (TM) 6 лет назад.Имея степень по математике, я довольно солиден (без каламбура) по алгоритмам и критическому мышлению, но я часто нахожусь с пробелом в знаниях, связанных со структурами данных, дизайном или другими основами CompSci, которые мои коллеги изучили в своей информатикекурсы.

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

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

Если компонент A должен быть защищен от изменений в компоненте B, тогда компонент B должен зависеть от компонента A.

(Я должен отметить, что в отсутствие какого-либо фактического определения, которое я вижу, я думаю о «компоненте» как о эквивалентном Java-пакету, хотя я думаю, что могут быть применены те же мыслительные процессыесли «компонент» представляет собой отдельную услугу - оба должны предоставлять пользователям стабильные используемые интерфейсы, вызываемые локально или по сети)

В этом утверждении не представлено никаких доказательств, и оно не самоочевидно длямне.Рассмотрим случай класса ClassA в компоненте (пакете) ComponentA, который вызывает DoStuffReturn doStuff(DoStuffInput input, String someOtherArg) в ClassB в компоненте ComponentB - и в котором вызов происходит либо через прямую зависимость, либо через зависимость от интерфейса в ComponentB ( не в ComponentA, как советует Чистая архитектура)

  • Если изменение в B является функциональным изменением, а не подписьюизменить (т. е. - для одного и того же входа DoStuffInput и String, возвращается другое DoStuffReturn), тогда не нужно никаких изменений в вызове A:
    • ClassA к ClassB.doStuffостается действительным (те же аргументы и тип возвращаемого значения)
    • ClassA модульные тесты (которые должны использовать фиктивные ClassB с) все равно должны проходить
    • Любые функциональные / интеграционные тесты, которые проверяют, какДля ClassA и ClassB совместной работы потребуется обновить их ожидания, но это не изменится на ComponentA (если только эти тесты не равны в ComponentA - я, как правило, видел их вComponentAIntegrationTests пакет, но я думаю, что они также могут быть совмещены. Это не кажетсябыть тем, о чем говорится в книге - похоже, речь идет об изменениях в коде, а не в тестах)
  • Если изменение в B является изменением сигнатуры метода, отличного отdoStuff, тогда A не потребует никаких изменений
  • Если изменение в B является изменением подписи на doStuff, то A потребует изменения - но это будет иметь местоесли интерфейс был и в A тоже.

(Обратите внимание, что в соответствии с настройкой Чистая архитектура выступает за, где интерфейс для предоставляющего класса находится в потребляющем Компоненте (A), только в первом случаебудет представлять собой изменение в B - так что это единственное, что нам действительно нужно беспокоиться)

Чего мне не хватает?Если ComponentA зависит от ComponentB, при каких обстоятельствах изменение класса в ComponentB потребует изменения в ComponentA?

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

Ответы [ 2 ]

0 голосов
/ 19 января 2019

Чтобы объяснить, как мы защищаем один компонент от изменений в другом путем инвертирования направления зависимости, давайте сначала определим компонент и зависимость .В контексте чистой архитектуры компоненты - это файлы JAR, а зависимости - это ссылки между классами.

Компоненты - это единицы развертывания.Это самые маленькие объекты, которые могут быть развернуты как часть системы.В Java это файлы jar.- стр. 96

Первое, на что нужно обратить внимание, это то, что все зависимости исходный код зависимости,Стрелка, указывающая из класса A в класс B, означает, что в исходном коде класса A упоминается имя класса B, а в классе B ничего не упоминается о классе A. - стр. 72

Тогда возникает вопрос: Какие изменения мы хотим защитить компоненты (банки) от ?И ответ таков: перекомпиляция, повторное развертывание и транзитивные зависимости.

Если компонент A зависит от компонента B, то любое изменение в B (даже если это изменение не влияет на API, который A потребляет) требует A для перекомпиляции.Кроме того, если изменение в B добавляет, удаляет или изменяет зависимость B, тогда A должно согласовать новую транзитивную зависимость, и поэтому изменение распространяется.

Эта зависимостьозначает, что изменение исходного кода [B] приведет к перекомпиляции и повторному развертыванию [A], даже если на самом деле ничего, о чем оно заботилось, не изменилось.- стр. 84

Транзитивные зависимости являются нарушением общего принципа, согласно которому программные объекты не должны зависеть от того, что они надеваютне использовать напрямую.- стр. 75

Здесь я объединяю элементы нескольких принципов SOLID;но они имеют общие черты, когда дело доходит до обработки изменений.

0 голосов
/ 27 декабря 2018

Что касается моего прошлого, у меня есть степень по компьютерным наукам и более 20 лет профессионального опыта.

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

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

Мне кажется, что дядя Боб - далеко не идеальный источник информации об объектной ориентации. Здесь - подробная критика «Чистой архитектуры» (не книга, идея), которую я написал некоторое время назад, если вам интересно.

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...