Pull to refresh

Comments 45

Как и с любым другим "принципом" актуальность зависит от контекста. Все эти принципы не имеют никакого смысла вне контекста

Снова микросервисами пытаются забить шурупы.

Если кто-то не способен написать хороший монолит с качественной архитектурой (а без хорошего понимания SOLID это сложно) то к микросервисам его точно подпускать не стоит.

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

>Лучший способ устроить большой беспорядок - сказать всем: «Просто будьте простыми» и не давайте им никаких дальнейших указаний.

Еще риторические вариации на эту тему, которые часто можно услышать: "Лучше руководствоваться здравым смыслом, чем SOLID, паттернами и проч.", "SOLID - это вкусовщина", "Давайте писать код, а не заниматься ерундой" и т.д. При этом частенько выясняется, что понимания этих принципов у утверждающего и нет вовсе, или оно неверное/сильно искаженное.

UFO just landed and posted this here

А что не так с LSP? Как по мне, в этой статье самое изящное изложение этого принципа из всех, что я слышал.

И во что у вас ООП мутировал, интересно?

UFO just landed and posted this here

Он же сам признается, что то, что под ним подразумевали раньше - и то, что считается сейчас - как бы несколько разные вещи?

Тоже самое, акценты другие. В 90-х часто использовали наследование реализации, сейчас это считается скорее плохой практикой. А суть та же: код не должен видеть разницы между типом и его подтипами.

 enterprise fizz-buzz не смущает?

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

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

Он же сам признается

А мне ваше мнение интересно.

Всякие ФП/ФРП

вообще никак к ООП не относятся.

инкапсуляция-наследование-полиморфизм

строго говоря, к оригинальной идее ООП весьма перпендикулярны. Кроме того, не могли бы вы пояснить, как SOLID завязан на эту триаду?

enterprise fizz-buzz не смущает?

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

А в комментариях затем разбирается ошибка в рассуждениях автора.

Там человек ничего не понял просто, бывает.

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

void SomeFunction(Box<Animal> box)
{
  Animal animal = box.Unbox();
  Dog dog = (Dog)animal; // wtf?
  dog.Aport();
}

Я не делаю никакого анбоксинга. Функция просто засовывает кошку в клетку для животных. А ей передаётся клетка для собак.

То есть вы вот такой пример предполагаете?

class Box<T> where T:Animal
{
  public void Put(T animal)
  {
  	...      
  }
}

void PutAnimal(Box<Animal> box)
{
	box.Put(new Cat());
}

void Test()
{
  PutAnimal(new Box<Dog>());
}

Так в этом случае оно даже не соберется в большинстве ЯП, потому что Box<Animal> не является супертипом для Box<Dog>. Чтобы оно заработало, вам надо явно указать вариантность.

А если "починить" проблему тем, что

class Box
{
  public void Put(Animal animal)
  {
      ...      
  }
}

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

Не утруждайте себя. В статье, на которую я там ссылаюсь, есть примеры кода в том числе и на сишарпе.

Это лишь доказывает, что "клетка для собак" не удовлетворяет контракту "клетки для животных".


Как вы из этого делаете вывод, что виноват LSP?

А удовлетворяет этому контракту любой супер тип, но не подтип.

Супертип чего?


В той "иерархии" типов, которую вы приводили в том посте, у "клетки для животных" на самом деле нет ни супертипов, ни подтипов.

Вы путаете subtyping и assignability.

Посмотрите примеры на языке D - это единственный язык, где компилятор действительно понимает вариантность. К сишарпу и яве её прикручивали сбоку изолентой.

Нет, в данном случае что-то путаете вы.


"Клетка для животных" и "клетка для кошек" — это разные объекты, которые не являются супертипом или субтипом друг для друга независимо от используемого языка программирования.

Тип - это множество возможных значений. Клетка для животных принимает все значения, что и клетка для кошек. Следовательно является её супертипом.

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

Клетка для животных принимает все значения, что и клетка для кошек.

С какого перепугу?

И туда и туда можно положить кошку.

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


Эти два множества не пересекаются, независимо от того сколько раз вы скажите одно и то же в разных формулировках.

Человек немножко не разобрался, чем отличается сабтайпинг от дженериков.

У меня такое ощущение, что он прочитал, что надо подставлять типы а не объекты.

"клетка для животных" - это тип, а не значение. Значением является структура (кортеж) со ссылкой на животное. И эта структура является представителем как типа "клетка для животных" так и "клетка для собак".

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

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

У структурно типизированных языков же с пониманием типов всё традиционно гораздо лучше.

И эта структура является представителем как типа "клетка для животных" так и "клетка для собак".

Нет, не является.

Тип - это множество возможных значений. Клетка для животных принимает все значения, что и клетка для кошек. 

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

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

Клетка для любых животных и клетка для каких-то животных.

Клетка для животных именно что гарантирует, что туда можно поместить любое животное. А при доставании вы не получите ничего кроме животных. При этом гарантия "достать" распространяется на все подтипы. А гарантия "положить" на все супертипы. При этом речь идёт именно про depth subtyping. Width subtyping на эти ограничения никак не влияет.

Очевидно тогда клетка для собак это не клетка для любого типа животных.

В нее нельзя положить слона,

А гарантия "положить" на все супертипы. 

Это как - в клетку для животных можно положить что угодно?

Клетка_для_любого<T> инвариантна относительно T.

Как и требует LSP - мы не можем подменить клетку в которое гарантированно помещается любое животное на клетку которая гарантирует что там только собаки и принимает только собак как и наоборот.

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

Это как - в клетку для животных можно положить что угодно?

В клетку для животных можно положить и собаку.

Клетка_для_любого<T> инвариантна относительно T.

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

Дженерики

Обратите внимание, что в своих статьях я намеренно ничего не говорю про дженерики, ограничиваясь исключительно полиморфизмом подтипов.

В клетку для животных можно положить и собаку.

Собака подтип, а не супертип

Вариантность - это свойство кода, который с этой клеткой работает.

А свойства должны быть таковы, чтобы соблюдать контракт клетки.

Клетка, которая принимает и выдает только собак не является клеткой которая принимает любое животное. Поэтому подстановка для них не работает.

не говорю про дженерики

Дженерик это функция которая делает из одного типа другой тип. То, что эта функция работает в голове а не выражена в ЯП на ход рассуждений не влияет.

Вы просто повторяете одно и то же. Я устал.

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

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

Variance refers to how subtyping between more complex types relates to subtyping between their components.


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

Знать что такие принципы есть и в чём они упрощают жизнь - важно.
А вот применять или нет - уже зависит от проекта и команды. В проектах с большим легаси и feature driven development - наверное далеко до solid.

Программное обеспечение по-прежнему представляет собой операторы if, циклы while и операторы присваивания — последовательность, выбор и итерацию.

Да неужели. А я вот вижу, что всё больше задач решается «одним запросом на LINQ».
Каждое новое поколение любит думать, что их мир сильно отличается от мира предыдущего поколения. Каждое новое поколение ошибается в этом.

То есть, прогресса в программировании нет. В принципе, после этого понятно всё.

Как я понимаю автора, революции в программировании не случилось, есть эволюционное развитие.

И "один запрос на LINQ" внутри себя как раз и разворачивается в "if, циклы while и операторы присваивания".

В принципе, вам ничто не мешает взять какой-нибудь достаточно древний ЯП и забабахать LINQ на нем. В зависимости от древности и дубовости языка вам, конечно, придется пободаться с лямбдами и переизобретением expression trees - но на что-то принципиально нереализуемое вы вряд ли наткнетесь.

Как я понимаю автора, революции в программировании не случилось, есть эволюционное развитие.

LINQ — это сильное изменение, за время жизни поколения глубоко укоренившееся в обиходе. Про него уже даже комиксы рисуют (с Джоном Скитом в главной роли). Но автор утверждает, что это заблуждение: таких изменений не бывает.

И «один запрос на LINQ» внутри себя как раз и разворачивается в «if, циклы while и операторы присваивания».

Во-первых, можно точно так же сказать, что не существует ни if'а, ни while, ни операторов присваивания, потому, что на более нижнем этаже есть только два состояния и три оператора.

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

Часто из программистов в менеджеры идут люди, у которых не сложилось с программированием. Не все конечно, но часто :) Почему, по тому же принципу, они не идут в стоматологи или не выбирают другую специальность? Очевидно, им будут необходимы соответствующие знания и опыт, но похоже у менеджеров такой проблемы нет :) Ничего не имею против менеджеров, но полностью доверять их мнению в разработке ПО не стоит. Выбор архитектуры монолитов, микросервисов и т.п. ни чего не говорит о том нужен ли там ООП и SOLID. И еще один момент - каждый раз, когда кто-то рассказывает как он понимает принципы SOLID они играют для меня новыми красками. Для себя я сделал несколько субъективных выводов:

- SOLID это не правила, а рекомендации о том, как делать программы в ООП

- они появились в результате многолетнего опыта использования ООП на практике и показывают путь «между граблями»

- они кончено как-то работают и по отдельности, но очень хорошо работают вместе, взаимно дополняя и усиливая друг друга

- основные цели: обуздать сложность, минимизировать ресурсы на разработку и поддержку

- очевидные преимущества: уменьшение связанности и дублирования, упрощение кода

UFO just landed and posted this here

Достаточно было сказать, что концепция микросервисов сама по себе базируется на SOLID

P.S. а SOLID в свою очередь это разжёванные киты ООП.

Подскажите, пожалуйста, куда копать.

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

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

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

Память об этом событии находится у двух конкретных объектов. Нет централизованной базы данных, в которой ведётся запись о событиях со стороны "наблюдателя". Память о событии находится только в распоряжении объектов, которые непосредственно принимали участие в каких-либо действиях.

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

Где такой подход, если он существует и имеет смысл, мог бы применятся?

Sign up to leave a comment.

Articles