Search
Write a publication
Pull to refresh

Comments 36

С публикацией что-то пошло не так? Проверил через incognito — вроде бы доступна, корректно отображается.

Наверное имелась ввиду низкая содержательность/объем


P.S.


Их не помогли понять ни

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

Да, опыт, конечно :)

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

Для новичков статья в самый раз, пересказывает принципы солид простым языком.

Статья лёгенькая, буквально в двух словах, поэтому позволю себе показать ещё более простой вариант на картинке под спойлером (автор неизвестен):

буквально в двух словах

Как же, теперь, жить? После такого спойлера.

"Делай просто, насколько возможно, но не проще этого."

Может это просто плохая идея если уже в 1000 раз повторяете а они все не могут вашу молитву выучить?

Буква L

Принцип подстановки Барбары Лисков (Liskov Substitution Principle) говорит, что если мы дописываем новых наследников к классу, то нужно это делать таким образом, чтобы не пришлось менять весь старый код, который этих самых наследников будет использовать (старый код-то и не знает ничего про наследников). Опять-таки: легко дописываем, но тяжело ломаем.

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

Ну ковартантность и LSP они обсуждали ещё в том же самом тредике, где Дядя Боб имел неосторожность предложить свои принципы (их там кстати больше) - https://groups.google.com/g/comp.object/c/WICPDcXAMG8?hl=en&pli=1#adee7e5bd99ab111.

Барбара в интервью рассказывала, что формулировала LSP как неформальное правило, больше с целью порассуждать, без претензий на научную строгость. У Дяди же адаптация принципа под OOD (с оглядкой на C++) выглядит вообще как каламбур. Это уже потом Дядю канонизировали, а сказанное превратили в догму.

Ну как без претензий..

Она там вводит определение подтипа, как то, что можно подставить вместо супертипа. А раз можно подставить массив животных в функцию, которая пушит в массив котят, и ничего не сломается, то массив животных, по её определению, получается подтипом массива котят.

Вообще, определение подтипизации, зависящее от того какие функции мы вызываем в программе, - это какое-то вырывание гланд через анус.

Спасибо за ссылку
1987 - это ваша ссылка

3.3. Type Hierarchy A type hierarchy is composed of subtypes and supertypes. The intuitive idea of a eubtype is one whose objects provide all the behavior of objects of another type (th e supertype) plus something extra. What is wanted here is something like the following substitution property [S]: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for oz, then S is a subtype of T. (See also [2, 171 for other work in this area.)

Т.е. для всех программ, не для одной функции.

А вот википедия - 1994
 Barbara Liskov and Jeannette Wing described the principle succinctly in a 1994 paper as follows:[1]

Subtype Requirement: Let {\displaystyle \phi (x)}

 be a property provable about objects {\displaystyle x} of type T. Then {\displaystyle \phi (y)} should be true for objects {\displaystyle y} of type S where S is a subtype of T.

Вообще, определение подтипизации, зависящее от того какие функции мы вызываем в программе, - это какое-то вырывание гланд через анус.

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

Если программа делает то, что нужно, но принцип не соблюдается, возможно вам нужны другие отношения между типами.

Для "всех возможных программ" по такому определению мутабельные типы вообще не образуют иерархии ибо являются инвариантными.

Что такое инвариантные типы?

Подставляются не типы а объекты типа. Конвариантны/контравариантны не типы а преобразования типов. Т.е. функция над типами. Ко-вариантны

Within the type system of a programming language, a typing rule or a type constructor is:

  • covariant if it preserves the ordering of types (≤), which orders types from more specific to more generic: If A ≤ B, then I<A> ≤ I<B>;

  • contravariant if it reverses this ordering: If A ≤ B, then I<B> ≤ I<A>;

  • bivariant if both of these apply (i.e., if A ≤ B, then I<A> ≡ I<B>);[1]

  • variant if covariant, contravariant or bivariant;

  • invariant or nonvariant if not variant.

т.е. у вас есть спрособ описать функцию на пространстве типов f(x) -> y
если из x1 is x2 следует f(x1) is f(x2) то преобразование ковариантно. (Аргумент со-варьируется с результатом)

Например в C# вот это не скомпилируется, так как List<> сам по себе не тип а фактически конструктор типов.

 public static void Main()
  {
    object x = null;
    if (x is List<object> || x is List<>)
    {


    }
  }

Впрочем, мы это уже обсуждали

Тут мне непонятно. Если есть коллекция ICollection с методами Add(Object x) и Object GetFirst() почему мутабельный List с такими же методами не является его подтипом?

Это исследовательская работа, скорее уровня реферата. Она там собирает примеры абстракции данных в паре языков и в одном из разделов рассуждает про разницу между наследованием реализации и иерархией типов (а сейчас будет лучше сказать - спецификаций - потому, что ее трактовка типа там отличается от привычной из type theory). А сам "принцип" это цитата из другого автора, который она привела просто в качестве примера:

The intuitive idea of a subtype is one whose objects provide all the behavior of objects of another type (the supertype) plus something extra. What is wanted here is something like the following substitution property [6]: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T. (See also [2, 17] for other work in this area.)

Я так понимаю LSP для ООП это стало с подачи дяди, сама Барбара ни чего такого не предполагала. Даже наоборот:

We are using the words “subtype” and “supertype” here to emphasize that now we are talking about a semantic distinction. By contrast, “subclass” and “superclass” are simply linguistic concepts in programming languages that allow programs to be built in a particular way. They can be used to implement subtypes, but also, as mentioned above, in other ways.

SRP трактуют по разному. "Одна причина" - это про Big Bang или теологию?

Почему-то в статье (да и в самой методологии) ничего не говорится о том, что нужны различные уровни описания. Дело в том, что, обычно, берётся иерерхия классов, инкапсулирующих важнейшие библиотеки, и создаётся новая иерархия классов. Точнее, создаются наследники существующих классов и соответствующие им иерархии. Классов (например, в Java) и так очень много, а тут ещё добавляется новая иерархия для описания предметной области. Тут зарыта довольно серьёзная собака. Системный подход не допускает смешение уровней описания, а это значит, что иерархия системных объектов и иерархия прикладных объектов — это две незавиисмые друг от друга иерархии. Вы берёте иерархию системных объектов и создаёте, по сути, новый язык описания, в терминах которого описываете уже объекты предметной области.

в Java вот есть интерфейс Collection с методами в духе add(), remove() и так далее. И в неизменяемых реализациях коллекций эти методы, ясное дело, не нужны. Поэтому, согласно принципу I, интерфейс стоит разделить на Collection и его наследника, MutableCollection (как сделано в Kotlin, например).

А не будет более естественным иметь единый класс Collection, но иметь параметр в конструкторе, который описывает поведение коллекции? (В некоторых ситуациях, можно было бы, даже, ожидать создания шаблона Collection.) По своей сути, коллекция — это абстрактный тип данных, который в самом общем виде описывает некоторый контейнер однородных (в определённом отношении) объектов. Но этот абстрактный тип инкапсулирует два следующих объекта: способ доступа и внутреннее представление.

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

неизменяемые реализации коллекций

Подозреваю, топик стартер имел в виду, что в java.util.Collections есть методы .unmodifiableList, .unmodifiableSet, возвращающие экземпляры неизменяемых коллекций.

Совершенно выпустил из виду, что интересное начинается уж здесь:

в Java вот есть интерфейс Collection

То есть: колекция сама является интерфейсом (задумчиво уходит в совершенном замешательстве).

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

А вот в английской wiki про SOLID

design principles intended to make software designs more understandable, flexible, and maintainable

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

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

Код живёт в разработке ну может пару дней

В этом же и суть: запилили фичу и забыли. Написанный код больше стараемся не трогать.

Статья простая и понятная. Много натыкался на статьи, которые можно объединить одной фразой "Не понимаю зачем в современном мире SOLID, никогда его не понимал, его написали старые бородатые дядьки под старое, никому не нужное ООП, юзать его не буду и вам не советую, на дворе 2020 + год", но человек не спасовал, разобрался, и написал свое понимание, и это хорошо, ибо новичкам будут попадаться выше упомянутые статейки, если не будет новой информации про опыт применения принципов SOLID.

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

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

Это неверное допущение. Принципы SOLID в первую очередь о том, как сделать так чтобы изменение существующей функциональности — равно как и добавление новой — не было сильно трудозатратым и не часто приводило к багам.

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

Приз за самую короткую и бессодержательную статью о принципах SOLID сфоткаете?

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

с этой фразой согласен

Учитывая интуитивное соотношение новых/существующих систем, как правило, приходится дополнять уже неотъемлемую старую функциональность. Слово "новое" в этом ключе не совсем верное. Больше похоже на приобревшее дальнейшее развитие старое. И поскольку мы, как правило, докладываем небольшие кирпичики к уже существующей большой куче, основной акцент должен быть на том, как эту кучу не разрушить.

Принцип D было бы неплохо уточнить или объяснить по-другому - что такое зависимость и где она инвертируется? А то во многих кодобазах генерируются тысячи абстракций, а Принцип D нарушается. Иначе это ещё больше запутывает.

Sign up to leave a comment.

Articles