Евгений хорошо подметил, что одна из проблем кода - это "есть еще другие заинтересованные люди". Мне кажется это хорошо описывает ментальное состояние большинства ярых фанатов. Я назвал бы это принцип "инверсия понимания окружающего мира". То есть не мир ставит реальные задачи, а программист их автоматизирует, а программист строит свои замки идеальных абстракций, но иногда приходится загрязнять эти замки плохими хотелками злых дяденек и тетенек, которым что-то там надо. В добавок получается странные парадокс. Чистый код нужен (так же) чтобы можно было быстра вносить изменения, но когда надо быстро вносить изменения то приходится использовать другие подходы так как с чистым кодом быстро вносить изменения не получается. В целом дискуссия получилась интересная и я с удовольствием послушал обоих "спикеров".
мы когда нанимаем я говорю что какая-то архитекрута у нас есть ) про солид не спрашиваем, спрашиваем как отредактировать коммит который запушил и не получить люлей )
Да часто любят эту херню спрашивать, а вот что замечал, когда спрашивает очень опытый специалист, ему вообще плевать, т.к. в коммерческой разработке нет времени, т.к. вот надо срочняк и самая жопа еще в том, что нет четкого понимания, а что будет дальше, поэтому особого смысла нет писать все красиво )
Ребят, всё супер, спасибо за такие разговоры вслух! Маленький нюанс/просьба - тайм-коды... те что есть - немного не айс, не найти потом быстро по теме что надо. Конкретно хочу упасть обратно на барбара-лисков начало обсуждения и попробуй вспомни и найди, к примеру )
34:50 🔥 увы, с точностью до наоборот. И эти люди учат новые кадры в IT 😮 Запоминаем: Инверсия управления - это когда, наоборот, изнутри(снизу) можно решать, что делать снаружи (например, посредством передачи внешнего self-объекта в конструкторы или просто методы суб-объектов, или всякими колбэками "в этих ваших фронтах"). Соответственно обычное (неинвертированное) управление, это верхний (главный) управлят вниз (в суб объекты, функции, под-процедуры, %подставь_свое%), и все вложенные видят картинку вниз, но не видят картинку наверх (благодаря инкапсуляции). Инверсия же управления - шарит (в частном или общем порядке, как, сами решаете), нижним - видеть и/или управлять положением каких то вещей снаружи/сверху, как бы нарушая инкапсуляцию в каких то моментах. Простыми словами это тупо делегирование своих полномочий вниз.
Отличный разбор SOLID принципов, очень сильные программисты! Я когда понял большую часть этих принципов, у меня произошел ДЗЕН в голове :) Теперь я пишу без зазрения совести говнокод, т.к. знаю как писать код хорошо. Нужны ли эти принципы? Если хотите работать не в маленьких командах или над большим продуктом, где пишут на ООП, то да. Тоже самое с алгоритмами и структурами данных. Если хотите работать в корпорациях, то да. То, что говорят не нужно знать алгоритмы и структуры данных, кто в них хорошо разбирается, думаю они лукавят :) Это помогает настроить твой мозг на выполнение задач, которые присущи для БОЛЬШИХ компаний.
Евгений вскользь упомянул Smalltalk. Это ключевой язык для понимания, откуда пришли паттерны и, в общем-то, принципы. И почему они именно так сформулированы. И именно в нём они приобретают полный смысл. В остальных языках они работают гораздо хуже. Как та самая сова на глобусе.
формат топ, продолжайте в том же духе! я бы правда хотел предложить перед тем как что-то обсуждать - проговорить формулировку и вообще обозначить что имеется ввиду. потому что интерпретаций разных букв солида по разному есть, не говоря о том что кто-то уже и забыл сами формулировки.
Про Барбару Лисков мне нравится метафора воронки. Воронка - допустим это класс с одной функцией. Мы хотим поменять одну воронку на другую. Т.е. поменять супертип на подтип. Входное горлышко это что на вход, выходное на выход. В подтипе (другой воронке) можно входное горлышко расширить, но сужать его нельзя иначе то входило в супертип в подтип не пролезет. И наоборот выходное горлышко у новой воронки можно сужать, но нельзя расширять потому что там куда выходное горлышко у прежней воронки раньше входило оно не влезет.
А можете привести пример, когда в коде создают много интерфейсов, а потом их не используют для dip? Интерфейс это же всегда абстракция над конкретной реализацией и если эта абстракция дальше не используется и весь код продолжает ссылаться на конкретные реализации, то какой в этой абстракции смысл? А если используется, то будет dependency injection, который как раз и является реализацией dip.
К 21:10 - на одной из конференций по JS разраб, видимо из Java, начал говорить, что мол, нужно значит контейнер, и зависимости, и абстракции, и типы там вывести для API и вот это все. На что докладчик спокойно предложил ему использовать JS. В том смысле что к любой задаче нужно подойти разумно, выбрать среду (я тут имею ввиду и язык, фреймеврк и архитектуру - вот полный набор), ограничения которой позволяют решить задачу не теряя контроль над реализацией и придерживаться этого выбора. А то будет, как в бородатой шутке, где программист на паскале всегда пишет на паскале на любом языке.
Как по мне абсолютно неверно объяснен принцип DIP. Ключевое слово - это инверсия. Нужно для отделения высокоуровневых слоев от низкоуровневых (onion architerture, DDD и т.д.). Это возможно только через интерфейсы и только с помощью DI (в рантайме магия пропадает конечно). А зависимость от абстракций, а не от реализации - это только частично про DIP. И этот принцип далеко не всегда и везде нужен (в средних или небольших приложениях смысла нет в этом - используем интерфейсы в контексте полиморфизма и всё). А SRP - это вообще сакральная тема. Акторы, про которых упоминает Мартин, можно идендифицировать правильно только с опытом, когда ты видишь не только вертикальное разделение ответственности (домен - приложение - инфраструктура), но и вертикальное, с помощью разных бизнес контекстов. На собесах так вообще бесполезно про это спрашивать :)
С DIP хороший пример недавно видел, в проекте набор процессов, и каждый процесс заводит либо определенное количество потоков либо по требованию. Классы потоков расширяют общий класс с характерными только для них свойствами и методами, из-за ограничения языка в расширении более одного класса, пришлось разбивать и в конструктор каждому классу передавать коннектор, проблема в том, что коннекторы тоже имеют общие свойства и методы, но они не совместимы между собой полностью, тогда сделал для них один абстракный класс и реализовал его во всех, а потом просто инициализировал через конструктор в родительском общем классе. Про SOLID в тот момент не думал, просто прикинул если не кидать коннектор в общий класс через абстракцию, а каждому засунуть свой конкретный экземляр, то потом если что-то надо будет добавить всем сразу, всё же они родня по рантайму, то это будет боль, а так в абстрактном написал и все классы покраснели сколько бы их ни было. ❗Простыми словами . Есть класс User, который расширяет класс Database и User передает в Database экземпляр класса Websocket, чтобы Database сообщал на клиента ход событий. Так вот если зашить Websocket как экземпляр, то например класс Cron уже не сможет расширить Database, так как Websocket у него свой (Коннект с другим сервером), одинаковые лишь некоторые методы и свойства. Ну а то что разное в их вебсокетах - они внутри себя юзают, несмотря на то, что через один и тот же класс. При помощи DIP можно бесконечно много таких по своему уникальных, но имеющих ряд сходств классов вводить в АБСТРАКТНУЮ зависимость от одного общего. ❗❗❗ Вообще элементарный пример, есть функция, которая часто переопределяется, так вот мы пишем параметры для неё в отдельном интерфейсе, вместо того, чтобы просто проставлять типы в сигнатуре и используем везде где нужно повторить. Вот и вся инверсия зависимости, но узнают только те кто дочитал до конца😀
DI делает код "независимым" (и то условно) только относительно конкретной реализации. Это значит, предполагается, что реализаций потенциально может... нет, даже ДОЛЖНО быть несколько. И вот тут начинается "ОДНАКО": * а откуда известно, что реализаций будет несколько * а откуда известно, что реализации будут примерно такими * а кто сказал, что интерфейс останется постоянным Соответственно перед тем, как думать про DI, нужно понимать, что пункты выше хотя бы имеют реальный смысл, иначе программисты платят за ненужные часы разработки ненужной штуки, которая возможно будет выброшена завтра, или навсегда останется неизменной. Тут наверное самым главный вопросом может быть даже не вопрос... а будет ли несколько реализаций. А вопрос: а будет ли вообще интерфейс ВОЗМОЖЕН. Потому что бывают ситуации, когда стабильный интерфейс в принципе неизвестен.
Ну всё же можно в духе Unix-way продумать несложные и, предположительно, стабильные интерфейсы. Если опыт позволяет, то ждёт +/- успех, а остальное - комбинации и/или решается адаптерами.
@@VladimirS-h9o А в этом вся соль. Чтобы создать идеальные интерфейсы, которыми точно можно пользоваться нужно ЗАРАНЕЕ знать какие будут компоненты. Если компонентов заранее нет, то интерфейсов быть не может. Но об этом ни в какой книге ничего не говориться. Иначе говоря, если программист __заранее знает__ с вероятностью 80%, что у него будет вот такая БД и такая БД (или сервис или что там ещё), и при этом у него есть многолетний опыт работы с этими БД, то он может создать интерфейс, который будет обладать минимальной стабильностью. Есть ли такие проекты с такими условиями? Да. Но это проекты, когда ничего нового не создаётся. Шаг влево шаг вправо, и интерфейсы превращаются в 100% антипатерн.
@@EdmondDantesIf Так изначально ты же бьешь во слоям условно, кусок работы с бизнес логикой, кусок работы с базой/внешними сервисами, на каждом лое есть контракт, что он возвращает, условно какую-то доменную модель, которая будет универсальна для всех реализаций. Можно изначально предположить, сколько может быть реализаций, заложив заранее все риски, а так никто точно не скажет, сколько будет реализаций, но дальнейшая поддержка кода однозначно будет легче, хотя бы из-за того, что ты юниты на все это добро сможешь норм написать
@@Dmitry-ug1zq Это возможно только в том случае, если ДО того как код написан, уже известны абстракции и хотя бы на 90% понятно, как они разделены. И известно, какие реализации будут хотя бы с вероятностью 50%. А такое возможно только в небольшом количестве случаев... например когда компания рефакторит уже существующий проект.
Для создания интерфейса совсем не обязательно представлять реализацию. И даже лучше будет, если эта реализация неизвестна. Для создания интерфейса нужно понимать то, как этот интерфейс будет использован. А потом уже под использование надо подгонять реализацию. Иначе смысл интерфейса теряется.
Почему нельзя просто использовать здравый смысл? Тот же SRP - просто базовый инженерный принцып, который говорит о том, что одна "штука" должна отвечать строго за одну единицу работы, тогда и надежность будет, и компоновать "штуки" можна. Или функциональное программирование - основные принцыпы: разделяем данные и сайд-эффекты, а если исполнителей (то есть типов функций) больше одного, просто передаем нужный исполнитель аргументом (то есть получаем тот же DI из функций высшего порядка). А вот с SOLID просто какой-то звиздец. Роберт Мартин где-то украл название, потом лет через 20 написал, что он-де что-то там не так понимал все это время (другими словами - сам не понимает, о чем говорит), а потом вообще спрыгнул с Джавы в Кложу, то есть, с ООП в Лисп, в функциональщину. А все годамы теребят яйки, обсуждая, что же на самом деле такое SOLID, и как и где и его использовать...
В реальном физическом мире это как раз не является жестким требованием. Есть устройства, где тепло, как побочный продукт работы одной подсистемы, используется другой подсистемой, то есть подсистемы получаются неявно связанными. Но там изначально и нет требования модульности.
@@VoroninPavel Согласен, но в инженерии подобная неявная связь считается "паразитной" и нежелательной, поскольку в итоге ведет к недетерменированному поведению в крайевых случаях. Я же, по большей части, говорил о другом - о том, что можно использовать здравый смысл и хорошо обкатанные методики из инженерии (посмотреть тот же курс MIT 6.001 SiCP) для создания сложных и расширяемых систем. А не надрачивать годами на слова одного мужика - т.е. Роба Мартина - создавая SOLID-религию из его интрепретаций чужих слов (учитывая еще и то, что он сам признал, что его интерпретации ошибочны).
@@AlexanderBorshak я думаю, дядя Боб по сути этими буквами обозначил тот же здравый смысл =) А религию... так Губерман хорошо написал: Возглавляя партии и классы, лидеры вовек не брали в толк, что идея, брошенная в массы, - это девка, брошенная в полк.
@@AlexanderBorshak сегодня вот Informit опубликовали наконец-то книгу Влада Хононова: Balancing Coupling in Software Design: Universal Design Principles for Architecting Modular Software Systems Будем посмотреть =)
@@VoroninPavel > я думаю, дядя Боб по сути этими буквами обозначил тот же здравый смысл =) Здравый смысл вроде как достаточно просто объяснить с помощью нескольких примеров, равно как и придти к какому-то общему мнению о нем. Тут же, как мы видим, никакого общего мнения нет годами, если не десятилетиями. Даже в данном видео (за которое авторам, конечно же, спасибо) - говорили 2 часа, но к общему знаменателю так и не пришли. Так что здесь явно что-то не то...
Отличное видео SOLID кажется крайне избитой темой, однако то, что он до сих пор так активно обсуждается как раз говорит об отсутствии консенсуса. Спасибо за новые точки зрения
Спасибо, формат зашел, интересно послушать разные взгляды! Хотел бы закинуть еще одну холиварную тему - автотесты. Там также миллион пирамид разных, разные "школы", виды тестов и тд.
"Не слишком ли мы закопались в детали" имхо наоборот прошлись по верхам. На 43:38 так и не сказали что есть DIP и чем он отличается от DI. СОЕР пытался, но что-то его отвлекло))
Кирилл, привет! 21:41 у меня появился вопрос по данной теме, который уже достаточно давно висит в неопределённости. 21:56 - "У тебя есть прототипы, которые ты можешь пофиксить" В сети среди программистов испокон веков бытует мнение, что язык имеет классы, если он соответствует требованиям закрытости. Например, в Java. А язык, основанный на прототипах, классов не имеет. Это всегда вызывало у меня вопросы, потому как в определении класса из CS "In object-oriented programming, a class is a template definition of the methods and variables in a particular kind of object" класс - это некоторый шаблон, на основе которого строятся объекты с одинаковым поведением. В определении нет никаких упоминаний о том, что класс должен быть статичным (закрытым, неизменяемым). Ещё во времена до ES6 в языке существовала возможность реализовать шаблон-конструктор с помощью function. На выходе получали объект с определенным поведением, принадлежность к конструктору которого можно было определить с помощью оператора instanceof. Собственно, сам вопрос: почему инструменты прототипного языка, попадающие под общее определение класса, классами не являются? Я понимаю разницу между классово-ориентированными и объектно-ориентированными языками. Первые всегда используют классы для создания объектов. Для вторых наличия класса для создания объекта не обязательно. Но ведь "не обязательно" не есть "невозможно". В том же Python, например, объект можно создать без класса на основе встроенных типов данных. Тогда почему про JS говорят, что в нём нет классов, потому что конструктор в нём открытый?
В го неплохо обстоят дела с общими интерфейсам в разных библиотеках. Во многом за счёт того что го в свой стандартный набор библиотек затащили многие нужные для современной разработки вещи. И разработчикам сторонних библиотек для интеграции со стандартными необходимо использовать типовые интерфейсы.
для меня LSP, это про то, что при разработке типов надо больше уделять внимание поведению типа, а не тому, какие данные этот тип предоставляет. а поведение типа, как раз и выражено в предусловиях и постусловиях
В Scala кстати, можно управлять вариантностью тайп параметров, задавать нижние и верхние границы. Это по поводу Лисков. Активно используется как писателями либ, таки и обычными работягами.
Не разбирал все принципы SOLID, но принцип единой ответственности разобрал подробно в 3 частях на своем канале - это если захочется подискутировать (ссылку оставить видимо нельзя, но оставлю название для поиска: "Принцип единой ответственности (SRP) - что с ним не так?" )
S - это база. Если класс называется User то там не должно быть полей accessToken refreshToken, потому что User и Token это разные сущности и когда то может появиться необходимость поддержки нескольких токенов для одного пользователя.
58:55 не, возвращение нулевого элемента там, где супертип вернул бы другое значение - тоже нарушение БЛ. Мне кажется, вы недооценивать то, какие ограничения на самом деле накладывает БЛ. Оно же не про сигнатуры методов и исключений, а про полную подмену подтипа супертипом с полным сохранением поведения. Т.е. переопределение в этом контексте в принципе неуместно ни в какой форме. Как я понимаю, это очень сложный (для исполнения) принцип, который практически всегда нарушается. Например, в терминах канонического определения LSP (того, что в вики): T extends S, q := (x : T) |-> x.foo(55) == 20 forall (x:T)(q(x : T)) => forall (y : S)(q(y)) Или словами, если у любого инстанса суперкласса foo на 55 возвращает 20, то и все инстансы подкласса должны делать ровно так же. Строго по определению LSP.
Принцип LSP вообще фундаментальная вещь. Если у нас в родительком объекте url это url, то расширяющий его объект уж никак не должен держать в url что-то другое.
Полиглотам "сверху" лучше видно, так же и в естественных языках - очередной язык/парадигма помогает лучше понимать предыдущие. Когда человек думает исключительно (иногда принципиально) в ООП - довольно сложно поднять его в абстракциях на уровень выше.
В конце совсем заболтались. Если у тебя все приложение реакт - это один класс, то этот класс не нарушает принцип единственной ответственности, потому что у него одна ответственность - инициализировать и соединить все взаимодействующие классы. Есть только одна причина для его изменения - когда нам ужны другие классы и другая хема их взаимодействия. Если класс создается чтобы склеить во-едино ввод-вывод и вычисления, то естественно он будет выполнять ввод-вывод и вычисления, но это не будет его ответвенностями. Он не меняется если меняется алгоритм вычислений, он только склеивает.
43:40 Я бы наоборот настаивал на том, чтобы вы больше закапывались в детали. Я понимаю, что с одной стороны хочется, чтобы было понятно и новичкам, но я бы на них не фокусировался. Всё таки кажется, что ваша основная аудитория уже опытные программисты
подниму активность к вопросу про "грамар наци" в солид обсуждениях. мне кажется, что выяснять термины - это важно и нужно, это буквально основа любой хорошей дискуссии. когда каждый говорит о своём, всё скатывается в бессмысленный холивар. а аналогия с языком и учебниками кажется не совсем корректной, ведь есть ещё промежуточные варианты между слепым прескриптивизмом, от которого сейчас уходят, и полным отсутствием общепринятых дефиниций у слов по причине того, что все понимают по-разному
DIP - это по факту простой колбэк если воспринимать это с точки зрения ФП. Мы инжектим в свою супер-функцию другую функцию в качестве параметра. И на этапе вызова в рантайме определяем какую реализацию будем передавать
По Iнтерфейсам с Соером не согласен. Недавно сам к этому пришел. В проекте одна главная группа процессов и несколько зависимых групп процессов, в каждой группе один главный и несколько дочерних процессов, каждый из зависимых дочерних процессов работает через вебсокет с конкретными из главных дочерних. Так вот, по идее, протокол один, рантайм родственный, ну и сделал для всех коммуникаций один оберточный интерфейс с общими свойствами и одним свойством универсальным, которое является встроенным интерфейсом, каждая коммуникация отдельное свойство интерфейса, всё четко, работает через утиные генерики по одному из общих полей - другого не засунешь. Так вот проблема сейчас, что универсальный встроенный интерфейс юзают не связанные логически части программы. Нужно было использовать для каждой пары контактирующих процессов отдельный интерфейс или встроенному интерфейсу добавить ещё один уровень который тоже будет генерить по назначениям. Потому что, хотя коннекты используют только свои свойства, однако то, что все эти наборы в одном и том же интерфейсе это наводит путаницу, когда нужно быстро нарисовать в голове картину что и куда идет. ❗Сложно получается, вот простой пример. Если у тебя есть фабрика, которая производит широкий спектр товаров, с уникальными свойствами каждый, то пусть эти товары будут разбиты по категориям и каждый магазин ничего не знает о товарах из тех категорий с которыми он не работает.
1:06:45 Я везде задаю этот вопрос: нахрена 95% разрабов знать алгоритмы, если всё уже написано? При таком подходе, всем надо уметь в ассемблер. А чё, везде же используется. А вот про то что прежде чем отвергать SOLID, надо плотно его год попрактиковать, согласен полностью. SOLID (большая его часть) выстреливает на длинной дистанции, и главный его плюс - легкость изменений. Конечно, все вмеру, но штука очень мощная, хоть и ни разу не новая концептуально.
Принципы SOLID , это не законы которые нельзя нарушать, это принципы позволяют принять решение в спорной ситуации когда стоит вопрос так или вот так, тогда тихий голос SOLID шепчет: «вот так будет лучше!»
SRP - это когда взяли программный модуль с состоянием и на его основе создали ООП и куча паттернов. И он ответственнен за кучу лишней архитектуры и тонны макулатуры на эту тему.
O - принцип легко понять. Есть метод, расширяя его функционал для других использований нельзя менять поведение, которое существовала изначально. Дополнительное поведение не должно ломать предыдущее.
По-моему наоборот. Класс должен быть спроектирован так, чтобы его не нужно было менять а достаточно было бы расширять. Это не требование как пользоваться существующим кодом (расширять/менять), это требование как проектировать этот код - так чтобы мотиваций менять было мало а мотиваций расширять было много.
А если функционал метода расширяется не для «других использований», а для всех? Смысл паттерна в том, чтобы добавлять что-то в архитектуру, не меняя уже построенной части. Но эти изменения могут вносить (и вносят) изменения в поведение системы.
**SOLID** - это набор принципов объектно-ориентированного программирования, направленных на улучшение качества кода. Принципы SOLID помогают делать код более гибким, понятным и поддерживаемым. Однако они также могут подвергаться критике при чрезмерном применении или в случаях, когда они не соответствуют задачам проекта. ### 1. **Single Responsibility Principle (SRP)** - Принцип единственной ответственности **Описание:** Каждый класс должен отвечать только за одну задачу или функцию в системе. Если класс выполняет несколько обязанностей, то изменения в одной обязанности могут повлиять на другую. **Плюсы:** Упрощает код, делает его более понятным, снижает взаимозависимость. **Критика:** При излишне строгом применении можно раздробить логику на слишком мелкие классы, что приведет к усложнению структуры и увеличению числа объектов. ### 2. **Open/Closed Principle (OCP)** - Принцип открытости/закрытости **Описание:** Программные сущности должны быть открыты для расширения, но закрыты для модификации. Это означает, что поведение системы можно изменять, не меняя исходный код. **Плюсы:** Уменьшает необходимость в изменении уже написанного кода, снижает вероятность появления багов при добавлении новых функций. **Критика:** Реализация этого принципа часто приводит к усложнению абстракций и созданию чрезмерного количества классов и интерфейсов. ### 3. **Liskov Substitution Principle (LSP)** - Принцип подстановки Барбары Лисков **Описание:** Объекты наследующих классов должны корректно заменять объекты базовых классов без нарушения работы программы. Другими словами, наследуемый класс не должен нарушать логику базового. **Плюсы:** Повышает предсказуемость поведения программы, снижает вероятность возникновения ошибок при использовании полиморфизма. **Критика:** В реальных проектах могут возникнуть ситуации, когда для соответствия этому принципу приходится искусственно ограничивать наследование, что снижает гибкость. ### 4. **Interface Segregation Principle (ISP)** - Принцип разделения интерфейсов **Описание:** Клиенты не должны быть вынуждены зависеть от интерфейсов, которые они не используют. То есть, лучше создавать несколько специализированных интерфейсов, чем один универсальный. **Плюсы:** Улучшает декомпозицию системы, делает код более читаемым и гибким. **Критика:** Излишнее следование принципу может привести к созданию множества мелких интерфейсов, что затруднит восприятие и усложнит работу с кодом. ### 5. **Dependency Inversion Principle (DIP)** - Принцип инверсии зависимостей **Описание:** Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций (интерфейсов), а абстракции не должны зависеть от конкретных реализаций. **Плюсы:** Позволяет легко заменять и масштабировать модули, что повышает гибкость и расширяемость системы. **Критика:** Реализация DIP требует написания большого числа интерфейсов и абстракций, что может усложнить код и сделать его трудным для понимания. --- ### Общая критика SOLID: - **Усложнение кода:** Излишнее следование SOLID может привести к фрагментации кода, увеличению числа классов, интерфейсов и абстракций. Это делает систему сложной для понимания и сопровождения, особенно для небольших проектов. - **Затруднённость рефакторинга:** В реальных проектах иногда проще модифицировать существующий код, чем расширять его через создание новых классов и интерфейсов. - **Избыточная гибкость:** В некоторых случаях требуется предсказуемая и прямая реализация функционала, а SOLID может слишком усложнить простые задачи. Тем не менее, **SOLID** остается важным инструментом для улучшения качества кода, особенно в больших проектах с множеством взаимозависимостей, при этом его применение должно быть оправдано контекстом проекта.
Joel Spolsky в середине нулевых выкатил статью о видах ПО. Если Ваш код меньше 1000 строк, код одноразовый или embedded без возможности обновления, то SOLID не нужен. Буква O как мне кажется применимо только к такому виду софта как публичные библиотеки. Если Вы пишите enterprise и по сути прикладной софт, то скорее всего Вам все равно на модификации, поэтому и столько непонимания. Когда же Вам нужно backward compatibility, правила deprecation между версиями, то важно конечно создавать интерфейс нужной расширяемости и не требующий изменений.
@@VladimirS-h9o Боюсь спикеры тоже не особо врубаються о чем рассказывают. Меня когда первый раз спросили на собесе про Солид, это был 2019 год, у меня тогда было 15 лет коммерческого опыта и 21 год опыт общего программирования и сотни тысяч строк кода написанного и десятки проектов. За следующие 5 лет я пытался найти ответы, смирился с тем что этот вопрос задают, заметил что мнения у людей по этим принципам всегда разные, кроме может буквы I. Доказательство кто прав обычно производиться оскорблениями или повышением голоса. Для себя я нашел способ рассказывать эту сказку, но не уверен что она нравиться всем.
Чтобы быть "адвокатом" нужно приобрести компетенции, а не опыт на основе проектов из лапши и кома грязи. Лучше бы просто задали вопросы гостю чем прерывайющий, загрязняющий шум, который и порождает непонимание. Книжки читать надо а не смотреть на опыт, основанный на вредных привычках аля "видел так делают, удобно"
@@danilakhtarov SOLID появился в ООП, но многие его идеи перекликаются с базовыми принципами функционального программирования. Чистые функции, иммутабельность, функции высшего порядка и полиморфизм через алгебраические типы позволяют в ФП добиватся тех же целей - модульности, гибкости, переиспользуемости и независемости компонентов, как и SOLID в ООП.
Классные принципы, один не имеет отношения к архитектуре, другой нафиг не нужен, третий слишком простой и банальный, а сам автор принципов внятно не может их сформуливовать и объяснить что он имел в виду и каждый год меняет свои трактовки.... Очень инженерный подход....
солид - не особо конкретная штука, все пункты в нём об одном и том же - используйте ооп правильно, не используйте неправильно. почитать про него никому не помешает, но молиться на него не стоит совершенно точно
58:15 Если на интерфейсе родительского класса был указано, что из метода может вылететь исключение, то выкидывание его из подкласса не ломает принцип Лисков. Клиентский код должен быть готов к получению результата работы метода в виде исключения и должен его корректно обработать.
Сам Мартин что создал кроме книг? Какое образование у него, какой опыт программирования? Судя по его биографии он программистом ни дня не работал. Какой то журналист придумал вам принципы, а вы их всерьёз обсуждаете.
Два часа обсуждали, в итоге выяснили что никто толком не понимает принципы, что сами принципы плохо сформулированны, а автор принципов вообще не программист. ЛОЛ
Зайдите в ближайший бар, купите 2 литра разливного, вернись обратно, поставьте эту СОЛИДную философию на скорость x0.5 и можете понять как со стороны нас видят девушки, когда мы берем их с собой в заведение и компанией мужиков обсуждаем айтишечку.
Знаете, по-моему нифига понятней не стало, нагнали очередного тумана, налили воды, и у людей с критическим мышлением 😎 только укрепляются сомнения - а заслуживает ли тема такого внимания? Из пяти принципов два "по большому счету бесполезны", два "все понимают неправильно", а один "создает ложное чувство понимания".
Насколько по вашему SOLID влияет на то как вы пишите код?
Прекрасные принципы если их не трактовать буквально.
ща посмотрим что это такое (помню только single responsibility) и скажу)
ни насколько, реквест кинул, данные по пропсам распихал, зарплату получил, пошел пиво пить.
@@mastnova2676 а че так можно было?
Srp, dip, open-closed прям топ, но команде объяснить зачем, конечно бывает сложно
Как выше в комменте написали - пиво,зарплата - что пристал 😅
Дед с батей сцепились по пьяни и испортили всем восприятие SOLID каждый раз одно и то же
Кстати это доказывает то, что нет прям общей и строгой концепции, есть только принципы и понятия.
Евгений хорошо подметил, что одна из проблем кода - это "есть еще другие заинтересованные люди". Мне кажется это хорошо описывает ментальное состояние большинства ярых фанатов. Я назвал бы это принцип "инверсия понимания окружающего мира". То есть не мир ставит реальные задачи, а программист их автоматизирует, а программист строит свои замки идеальных абстракций, но иногда приходится загрязнять эти замки плохими хотелками злых дяденек и тетенек, которым что-то там надо.
В добавок получается странные парадокс. Чистый код нужен (так же) чтобы можно было быстра вносить изменения, но когда надо быстро вносить изменения то приходится использовать другие подходы так как с чистым кодом быстро вносить изменения не получается.
В целом дискуссия получилась интересная и я с удовольствием послушал обоих "спикеров".
Классно. Такие беседы заставляют мозг взглянуть на то, что он уже освоил с другого ракурса и немного переосмыслить сложившеся понимание этих принципов
Спрашивают на каждом собесе.
Выходишь на работу, в коде Х ночевал.
Я думаю каждый несёт ответственность чтобы самостоятельно использовать, как религиозные правила
Так тебя наверно и нанимают, чтобы Х не было. Не?
мы когда нанимаем я говорю что какая-то архитекрута у нас есть ) про солид не спрашиваем, спрашиваем как отредактировать коммит который запушил и не получить люлей )
Да часто любят эту херню спрашивать, а вот что замечал, когда спрашивает очень опытый специалист, ему вообще плевать, т.к. в коммерческой разработке нет времени, т.к. вот надо срочняк и самая жопа еще в том, что нет четкого понимания, а что будет дальше, поэтому особого смысла нет писать все красиво )
Это систематическая ошибка выжившего. Раньше удивлялся, сейчас привык. Спрашивают там где есть проблема как раз таки с кодом.
Соер один из немногих кто дело говорит. Легендарный человек.
SOLIDный разговор SOLIDных мужчин
Ребят, всё супер, спасибо за такие разговоры вслух! Маленький нюанс/просьба - тайм-коды... те что есть - немного не айс, не найти потом быстро по теме что надо. Конкретно хочу упасть обратно на барбара-лисков начало обсуждения и попробуй вспомни и найди, к примеру )
Соер: "зачем писать таймкоды? МОЖНО ЖЕ ПОПРОСТИЬ У AI!"
34:50 🔥 увы, с точностью до наоборот. И эти люди учат новые кадры в IT 😮 Запоминаем: Инверсия управления - это когда, наоборот, изнутри(снизу) можно решать, что делать снаружи (например, посредством передачи внешнего self-объекта в конструкторы или просто методы суб-объектов, или всякими колбэками "в этих ваших фронтах").
Соответственно обычное (неинвертированное) управление, это верхний (главный) управлят вниз (в суб объекты, функции, под-процедуры, %подставь_свое%), и все вложенные видят картинку вниз, но не видят картинку наверх (благодаря инкапсуляции).
Инверсия же управления - шарит (в частном или общем порядке, как, сами решаете), нижним - видеть и/или управлять положением каких то вещей снаружи/сверху, как бы нарушая инкапсуляцию в каких то моментах.
Простыми словами это тупо делегирование своих полномочий вниз.
Ждем подкаста про GRASP
Отличный разбор SOLID принципов, очень сильные программисты! Я когда понял большую часть этих принципов, у меня произошел ДЗЕН в голове :) Теперь я пишу без зазрения совести говнокод, т.к. знаю как писать код хорошо.
Нужны ли эти принципы? Если хотите работать не в маленьких командах или над большим продуктом, где пишут на ООП, то да.
Тоже самое с алгоритмами и структурами данных. Если хотите работать в корпорациях, то да.
То, что говорят не нужно знать алгоритмы и структуры данных, кто в них хорошо разбирается, думаю они лукавят :)
Это помогает настроить твой мозг на выполнение задач, которые присущи для БОЛЬШИХ компаний.
Евгений вскользь упомянул Smalltalk. Это ключевой язык для понимания, откуда пришли паттерны и, в общем-то, принципы. И почему они именно так сформулированы. И именно в нём они приобретают полный смысл. В остальных языках они работают гораздо хуже. Как та самая сова на глобусе.
формат топ, продолжайте в том же духе!
я бы правда хотел предложить перед тем как что-то обсуждать - проговорить формулировку и вообще обозначить что имеется ввиду. потому что интерпретаций разных букв солида по разному есть, не говоря о том что кто-то уже и забыл сами формулировки.
Про Барбару Лисков мне нравится метафора воронки.
Воронка - допустим это класс с одной функцией.
Мы хотим поменять одну воронку на другую. Т.е. поменять супертип на подтип.
Входное горлышко это что на вход, выходное на выход.
В подтипе (другой воронке) можно входное горлышко расширить, но сужать его нельзя иначе то входило в супертип в подтип не пролезет.
И наоборот выходное горлышко у новой воронки можно сужать, но нельзя расширять потому что там куда выходное горлышко у прежней воронки раньше входило оно не влезет.
очень интересно, спасибо! ждём продолжения
А можете привести пример, когда в коде создают много интерфейсов, а потом их не используют для dip? Интерфейс это же всегда абстракция над конкретной реализацией и если эта абстракция дальше не используется и весь код продолжает ссылаться на конкретные реализации, то какой в этой абстракции смысл? А если используется, то будет dependency injection, который как раз и является реализацией dip.
К 21:10 - на одной из конференций по JS разраб, видимо из Java, начал говорить, что мол, нужно значит контейнер, и зависимости, и абстракции, и типы там вывести для API и вот это все. На что докладчик спокойно предложил ему использовать JS. В том смысле что к любой задаче нужно подойти разумно, выбрать среду (я тут имею ввиду и язык, фреймеврк и архитектуру - вот полный набор), ограничения которой позволяют решить задачу не теряя контроль над реализацией и придерживаться этого выбора. А то будет, как в бородатой шутке, где программист на паскале всегда пишет на паскале на любом языке.
Как по мне абсолютно неверно объяснен принцип DIP. Ключевое слово - это инверсия. Нужно для отделения высокоуровневых слоев от низкоуровневых (onion architerture, DDD и т.д.). Это возможно только через интерфейсы и только с помощью DI (в рантайме магия пропадает конечно). А зависимость от абстракций, а не от реализации - это только частично про DIP. И этот принцип далеко не всегда и везде нужен (в средних или небольших приложениях смысла нет в этом - используем интерфейсы в контексте полиморфизма и всё). А SRP - это вообще сакральная тема. Акторы, про которых упоминает Мартин, можно идендифицировать правильно только с опытом, когда ты видишь не только вертикальное разделение ответственности (домен - приложение - инфраструктура), но и вертикальное, с помощью разных бизнес контекстов. На собесах так вообще бесполезно про это спрашивать :)
>> используем интерфейсы в контексте полиморфизма и всё
Так это и есть буквально инверсия зависимостей
С DIP хороший пример недавно видел, в проекте набор процессов, и каждый процесс заводит либо определенное количество потоков либо по требованию. Классы потоков расширяют общий класс с характерными только для них свойствами и методами, из-за ограничения языка в расширении более одного класса, пришлось разбивать и в конструктор каждому классу передавать коннектор, проблема в том, что коннекторы тоже имеют общие свойства и методы, но они не совместимы между собой полностью, тогда сделал для них один абстракный класс и реализовал его во всех, а потом просто инициализировал через конструктор в родительском общем классе. Про SOLID в тот момент не думал, просто прикинул если не кидать коннектор в общий класс через абстракцию, а каждому засунуть свой конкретный экземляр, то потом если что-то надо будет добавить всем сразу, всё же они родня по рантайму, то это будет боль, а так в абстрактном написал и все классы покраснели сколько бы их ни было.
❗Простыми словами . Есть класс User, который расширяет класс Database и User передает в Database экземпляр класса Websocket, чтобы Database сообщал на клиента ход событий. Так вот если зашить Websocket как экземпляр, то например класс Cron уже не сможет расширить Database, так как Websocket у него свой (Коннект с другим сервером), одинаковые лишь некоторые методы и свойства. Ну а то что разное в их вебсокетах - они внутри себя юзают, несмотря на то, что через один и тот же класс. При помощи DIP можно бесконечно много таких по своему уникальных, но имеющих ряд сходств классов вводить в АБСТРАКТНУЮ зависимость от одного общего.
❗❗❗ Вообще элементарный пример, есть функция, которая часто переопределяется, так вот мы пишем параметры для неё в отдельном интерфейсе, вместо того, чтобы просто проставлять типы в сигнатуре и используем везде где нужно повторить. Вот и вся инверсия зависимости, но узнают только те кто дочитал до конца😀
DI делает код "независимым" (и то условно) только относительно конкретной реализации. Это значит, предполагается, что реализаций потенциально может... нет, даже ДОЛЖНО быть несколько. И вот тут начинается "ОДНАКО":
* а откуда известно, что реализаций будет несколько
* а откуда известно, что реализации будут примерно такими
* а кто сказал, что интерфейс останется постоянным
Соответственно перед тем, как думать про DI, нужно понимать, что пункты выше хотя бы имеют реальный смысл, иначе программисты платят за ненужные часы разработки ненужной штуки, которая возможно будет выброшена завтра, или навсегда останется неизменной.
Тут наверное самым главный вопросом может быть даже не вопрос... а будет ли несколько реализаций. А вопрос: а будет ли вообще интерфейс ВОЗМОЖЕН. Потому что бывают ситуации, когда стабильный интерфейс в принципе неизвестен.
Ну всё же можно в духе Unix-way продумать несложные и, предположительно, стабильные интерфейсы. Если опыт позволяет, то ждёт +/- успех, а остальное - комбинации и/или решается адаптерами.
@@VladimirS-h9o А в этом вся соль. Чтобы создать идеальные интерфейсы, которыми точно можно пользоваться нужно ЗАРАНЕЕ знать какие будут компоненты. Если компонентов заранее нет, то интерфейсов быть не может. Но об этом ни в какой книге ничего не говориться.
Иначе говоря, если программист __заранее знает__ с вероятностью 80%, что у него будет вот такая БД и такая БД (или сервис или что там ещё), и при этом у него есть многолетний опыт работы с этими БД, то он может создать интерфейс, который будет обладать минимальной стабильностью. Есть ли такие проекты с такими условиями? Да. Но это проекты, когда ничего нового не создаётся. Шаг влево шаг вправо, и интерфейсы превращаются в 100% антипатерн.
@@EdmondDantesIf Так изначально ты же бьешь во слоям условно, кусок работы с бизнес логикой, кусок работы с базой/внешними сервисами, на каждом лое есть контракт, что он возвращает, условно какую-то доменную модель, которая будет универсальна для всех реализаций. Можно изначально предположить, сколько может быть реализаций, заложив заранее все риски, а так никто точно не скажет, сколько будет реализаций, но дальнейшая поддержка кода однозначно будет легче, хотя бы из-за того, что ты юниты на все это добро сможешь норм написать
@@Dmitry-ug1zq Это возможно только в том случае, если ДО того как код написан, уже известны абстракции и хотя бы на 90% понятно, как они разделены. И известно, какие реализации будут хотя бы с вероятностью 50%. А такое возможно только в небольшом количестве случаев... например когда компания рефакторит уже существующий проект.
Для создания интерфейса совсем не обязательно представлять реализацию. И даже лучше будет, если эта реализация неизвестна. Для создания интерфейса нужно понимать то, как этот интерфейс будет использован. А потом уже под использование надо подгонять реализацию. Иначе смысл интерфейса теряется.
Очень интересный выпуск, вы в процессе дискуссии обмениваетесь опытом из которого можно для себя многое вынести!
Выпуск зашел! Давайте еще
Ждем Егора Бугаенко с тру ООП
Почему нельзя просто использовать здравый смысл? Тот же SRP - просто базовый инженерный принцып, который говорит о том, что одна "штука" должна отвечать строго за одну единицу работы, тогда и надежность будет, и компоновать "штуки" можна. Или функциональное программирование - основные принцыпы: разделяем данные и сайд-эффекты, а если исполнителей (то есть типов функций) больше одного, просто передаем нужный исполнитель аргументом (то есть получаем тот же DI из функций высшего порядка). А вот с SOLID просто какой-то звиздец. Роберт Мартин где-то украл название, потом лет через 20 написал, что он-де что-то там не так понимал все это время (другими словами - сам не понимает, о чем говорит), а потом вообще спрыгнул с Джавы в Кложу, то есть, с ООП в Лисп, в функциональщину. А все годамы теребят яйки, обсуждая, что же на самом деле такое SOLID, и как и где и его использовать...
В реальном физическом мире это как раз не является жестким требованием. Есть устройства, где тепло, как побочный продукт работы одной подсистемы, используется другой подсистемой, то есть подсистемы получаются неявно связанными. Но там изначально и нет требования модульности.
@@VoroninPavel Согласен, но в инженерии подобная неявная связь считается "паразитной" и нежелательной, поскольку в итоге ведет к недетерменированному поведению в крайевых случаях. Я же, по большей части, говорил о другом - о том, что можно использовать здравый смысл и хорошо обкатанные методики из инженерии (посмотреть тот же курс MIT 6.001 SiCP) для создания сложных и расширяемых систем. А не надрачивать годами на слова одного мужика - т.е. Роба Мартина - создавая SOLID-религию из его интрепретаций чужих слов (учитывая еще и то, что он сам признал, что его интерпретации ошибочны).
@@AlexanderBorshak я думаю, дядя Боб по сути этими буквами обозначил тот же здравый смысл =) А религию... так Губерман хорошо написал:
Возглавляя партии и классы, лидеры вовек не брали в толк, что идея, брошенная в массы, - это девка, брошенная в полк.
@@AlexanderBorshak сегодня вот Informit опубликовали наконец-то книгу Влада Хононова: Balancing Coupling in Software Design: Universal Design Principles for Architecting Modular Software Systems
Будем посмотреть =)
@@VoroninPavel > я думаю, дядя Боб по сути этими буквами обозначил тот же здравый смысл =)
Здравый смысл вроде как достаточно просто объяснить с помощью нескольких примеров, равно как и придти к какому-то общему мнению о нем. Тут же, как мы видим, никакого общего мнения нет годами, если не десятилетиями. Даже в данном видео (за которое авторам, конечно же, спасибо) - говорили 2 часа, но к общему знаменателю так и не пришли. Так что здесь явно что-то не то...
Высший пилотаж - не долбить головой стены, а знать когда или зачем принципы нужно нарушить на пользу делу.
Мне нравится такой формат, спасибо! :)
Отличное видео
SOLID кажется крайне избитой темой, однако то, что он до сих пор так активно обсуждается как раз говорит об отсутствии консенсуса.
Спасибо за новые точки зрения
Спасибо большое за обсуждение :-)
Спасибо, формат зашел, интересно послушать разные взгляды!
Хотел бы закинуть еще одну холиварную тему - автотесты. Там также миллион пирамид разных, разные "школы", виды тестов и тд.
Очень классный выпуск. Формат шикарный
"Не слишком ли мы закопались в детали" имхо наоборот прошлись по верхам. На 43:38 так и не сказали что есть DIP и чем он отличается от DI. СОЕР пытался, но что-то его отвлекло))
Кирилл, привет!
21:41 у меня появился вопрос по данной теме, который уже достаточно давно висит в неопределённости.
21:56 - "У тебя есть прототипы, которые ты можешь пофиксить"
В сети среди программистов испокон веков бытует мнение, что язык имеет классы, если он соответствует требованиям закрытости. Например, в Java. А язык, основанный на прототипах, классов не имеет. Это всегда вызывало у меня вопросы, потому как в определении класса из CS "In object-oriented programming, a class is a template definition of the methods and variables in a particular kind of object" класс - это некоторый шаблон, на основе которого строятся объекты с одинаковым поведением. В определении нет никаких упоминаний о том, что класс должен быть статичным (закрытым, неизменяемым).
Ещё во времена до ES6 в языке существовала возможность реализовать шаблон-конструктор с помощью function. На выходе получали объект с определенным поведением, принадлежность к конструктору которого можно было определить с помощью оператора instanceof.
Собственно, сам вопрос: почему инструменты прототипного языка, попадающие под общее определение класса, классами не являются?
Я понимаю разницу между классово-ориентированными и объектно-ориентированными языками. Первые всегда используют классы для создания объектов. Для вторых наличия класса для создания объекта не обязательно. Но ведь "не обязательно" не есть "невозможно". В том же Python, например, объект можно создать без класса на основе встроенных типов данных. Тогда почему про JS говорят, что в нём нет классов, потому что конструктор в нём открытый?
Очень интересны подобные осуждения! Хотим продолжения!
Отличный выпуск про дебри программирования. Давайте еще! Гость очень понравился. Здравые получились дебаты
В го неплохо обстоят дела с общими интерфейсам в разных библиотеках. Во многом за счёт того что го в свой стандартный набор библиотек затащили многие нужные для современной разработки вещи. И разработчикам сторонних библиотек для интеграции со стандартными необходимо использовать типовые интерфейсы.
Ура! Отличный звук
для меня LSP, это про то, что при разработке типов надо больше уделять внимание поведению типа, а не тому, какие данные этот тип предоставляет. а поведение типа, как раз и выражено в предусловиях и постусловиях
В Scala кстати, можно управлять вариантностью тайп параметров, задавать нижние и верхние границы. Это по поводу Лисков. Активно используется как писателями либ, таки и обычными работягами.
Плюсую за аналогии 1:55
Все должно быть на интуитивном уровне, как грамматика
Не разбирал все принципы SOLID, но принцип единой ответственности разобрал подробно в 3 частях на своем канале - это если захочется подискутировать (ссылку оставить видимо нельзя, но оставлю название для поиска: "Принцип единой ответственности (SRP) - что с ним не так?" )
Эти принципы обязательно нужно преподавать джунам.
Что применять или нет, профи решит сам интуитивно.
S - это база. Если класс называется User то там не должно быть полей accessToken refreshToken, потому что User и Token это разные сущности и когда то может появиться необходимость поддержки нескольких токенов для одного пользователя.
58:55 не, возвращение нулевого элемента там, где супертип вернул бы другое значение - тоже нарушение БЛ.
Мне кажется, вы недооценивать то, какие ограничения на самом деле накладывает БЛ.
Оно же не про сигнатуры методов и исключений, а про полную подмену подтипа супертипом с полным сохранением поведения.
Т.е. переопределение в этом контексте в принципе неуместно ни в какой форме.
Как я понимаю, это очень сложный (для исполнения) принцип, который практически всегда нарушается.
Например, в терминах канонического определения LSP (того, что в вики):
T extends S,
q := (x : T) |-> x.foo(55) == 20
forall (x:T)(q(x : T)) => forall (y : S)(q(y))
Или словами, если у любого инстанса суперкласса foo на 55 возвращает 20, то и все инстансы подкласса должны делать ровно так же. Строго по определению LSP.
И никаких новых исключений тоже быть не может. LSP действительно стоит особняком в этом списке, КМК.
Спасибо за дискуссию! Отлично закрепляется материал из курса JS: полиморфизм ;)
Классно, но нехватает визуального отображения. сложно понимать
неплохо ) хорошо когда люди делятся практическим опыт а не просто обсуждают коров в вакууме
Принцип LSP вообще фундаментальная вещь. Если у нас в родительком объекте url это url, то расширяющий его объект уж никак не должен держать в url что-то другое.
49:00 принцип Барбары Лисков можно выразить как нельзя кристаллизировать предусловие и разряжать(диффузировать) постусловие
льзя
1:27:20 final пишут что бы не наследовался, расширение должно быть устроено не через наследование ;)
Агрегация это всего лишь одна из разновидностей расширения кода, также как и наследование. И там и там есть свои плюсы и минусы.
класс. очень понравилось. обсудите TDD, там тоже много спорных моментов
Полиглотам "сверху" лучше видно, так же и в естественных языках - очередной язык/парадигма помогает лучше понимать предыдущие.
Когда человек думает исключительно (иногда принципиально) в ООП - довольно сложно поднять его в абстракциях на уровень выше.
В конце совсем заболтались. Если у тебя все приложение реакт - это один класс, то этот класс не нарушает принцип единственной ответственности, потому что у него одна ответственность - инициализировать и соединить все взаимодействующие классы. Есть только одна причина для его изменения - когда нам ужны другие классы и другая хема их взаимодействия. Если класс создается чтобы склеить во-едино ввод-вывод и вычисления, то естественно он будет выполнять ввод-вывод и вычисления, но это не будет его ответвенностями. Он не меняется если меняется алгоритм вычислений, он только склеивает.
подскажите что за наушники у вас с микрофоном
shokz
43:40 Я бы наоборот настаивал на том, чтобы вы больше закапывались в детали. Я понимаю, что с одной стороны хочется, чтобы было понятно и новичкам, но я бы на них не фокусировался. Всё таки кажется, что ваша основная аудитория уже опытные программисты
Ну нормальный диалог, иногда в сторону (дебри) конечно уходили, но в целом зашло. Наткнулся на ссылку на LinkedIn , подписался.
подниму активность
к вопросу про "грамар наци" в солид обсуждениях. мне кажется, что выяснять термины - это важно и нужно, это буквально основа любой хорошей дискуссии. когда каждый говорит о своём, всё скатывается в бессмысленный холивар.
а аналогия с языком и учебниками кажется не совсем корректной, ведь есть ещё промежуточные варианты между слепым прескриптивизмом, от которого сейчас уходят, и полным отсутствием общепринятых дефиниций у слов по причине того, что все понимают по-разному
Успешно освоить JS и положить паттерны. Из - за динамической природы языка можно все перепробовать и переболеть краснухой.
DIP - это по факту простой колбэк если воспринимать это с точки зрения ФП. Мы инжектим в свою супер-функцию другую функцию в качестве параметра. И на этапе вызова в рантайме определяем какую реализацию будем передавать
Только это DI, а не DIP
@@qqq2084ee похоже, потому что и то, и другое, и третье можно решить через коллбеки.
У меня возникло ощущение, что я понимаю о чём говорит каждый, но ребята друг друга не понимают.
Надо шарить экран с кодом, чтобы не об облаках в небе говорить, а так классно
Не не, эти подкасты можно слушать на прогулке, а когда с кодом, то надо у компа сидеть.
По Iнтерфейсам с Соером не согласен. Недавно сам к этому пришел. В проекте одна главная группа процессов и несколько зависимых групп процессов, в каждой группе один главный и несколько дочерних процессов, каждый из зависимых дочерних процессов работает через вебсокет с конкретными из главных дочерних. Так вот, по идее, протокол один, рантайм родственный, ну и сделал для всех коммуникаций один оберточный интерфейс с общими свойствами и одним свойством универсальным, которое является встроенным интерфейсом, каждая коммуникация отдельное свойство интерфейса, всё четко, работает через утиные генерики по одному из общих полей - другого не засунешь. Так вот проблема сейчас, что универсальный встроенный интерфейс юзают не связанные логически части программы. Нужно было использовать для каждой пары контактирующих процессов отдельный интерфейс или встроенному интерфейсу добавить ещё один уровень который тоже будет генерить по назначениям. Потому что, хотя коннекты используют только свои свойства, однако то, что все эти наборы в одном и том же интерфейсе это наводит путаницу, когда нужно быстро нарисовать в голове картину что и куда идет.
❗Сложно получается, вот простой пример. Если у тебя есть фабрика, которая производит широкий спектр товаров, с уникальными свойствами каждый, то пусть эти товары будут разбиты по категориям и каждый магазин ничего не знает о товарах из тех категорий с которыми он не работает.
1:06:45 Я везде задаю этот вопрос: нахрена 95% разрабов знать алгоритмы, если всё уже написано? При таком подходе, всем надо уметь в ассемблер. А чё, везде же используется.
А вот про то что прежде чем отвергать SOLID, надо плотно его год попрактиковать, согласен полностью. SOLID (большая его часть) выстреливает на длинной дистанции, и главный его плюс - легкость изменений. Конечно, все вмеру, но штука очень мощная, хоть и ни разу не новая концептуально.
S0ER - легенда! 😎
Принципы SOLID , это не законы которые нельзя нарушать, это принципы позволяют принять решение в спорной ситуации когда стоит вопрос так или вот так, тогда тихий голос SOLID шепчет: «вот так будет лучше!»
SRP - это когда взяли программный модуль с состоянием и на его основе создали ООП и куча паттернов.
И он ответственнен за кучу лишней архитектуры и тонны макулатуры на эту тему.
Принцип Единственной Ответственности нарушает принципы ООП.
Оч круто
O - принцип легко понять. Есть метод, расширяя его функционал для других использований нельзя менять поведение, которое существовала изначально. Дополнительное поведение не должно ломать предыдущее.
По-моему наоборот. Класс должен быть спроектирован так, чтобы его не нужно было менять а достаточно было бы расширять. Это не требование как пользоваться существующим кодом (расширять/менять), это требование как проектировать этот код - так чтобы мотиваций менять было мало а мотиваций расширять было много.
А если функционал метода расширяется не для «других использований», а для всех?
Смысл паттерна в том, чтобы добавлять что-то в архитектуру, не меняя уже построенной части. Но эти изменения могут вносить (и вносят) изменения в поведение системы.
Ты архитектор. Нет ты архитектор.
Хорошо, я архитектор, но ты архитектуристый архитектор.
Нет ты архитектуристый архитектор…
**SOLID** - это набор принципов объектно-ориентированного программирования, направленных на улучшение качества кода. Принципы SOLID помогают делать код более гибким, понятным и поддерживаемым. Однако они также могут подвергаться критике при чрезмерном применении или в случаях, когда они не соответствуют задачам проекта.
### 1. **Single Responsibility Principle (SRP)** - Принцип единственной ответственности
**Описание:** Каждый класс должен отвечать только за одну задачу или функцию в системе. Если класс выполняет несколько обязанностей, то изменения в одной обязанности могут повлиять на другую.
**Плюсы:** Упрощает код, делает его более понятным, снижает взаимозависимость.
**Критика:** При излишне строгом применении можно раздробить логику на слишком мелкие классы, что приведет к усложнению структуры и увеличению числа объектов.
### 2. **Open/Closed Principle (OCP)** - Принцип открытости/закрытости
**Описание:** Программные сущности должны быть открыты для расширения, но закрыты для модификации. Это означает, что поведение системы можно изменять, не меняя исходный код.
**Плюсы:** Уменьшает необходимость в изменении уже написанного кода, снижает вероятность появления багов при добавлении новых функций.
**Критика:** Реализация этого принципа часто приводит к усложнению абстракций и созданию чрезмерного количества классов и интерфейсов.
### 3. **Liskov Substitution Principle (LSP)** - Принцип подстановки Барбары Лисков
**Описание:** Объекты наследующих классов должны корректно заменять объекты базовых классов без нарушения работы программы. Другими словами, наследуемый класс не должен нарушать логику базового.
**Плюсы:** Повышает предсказуемость поведения программы, снижает вероятность возникновения ошибок при использовании полиморфизма.
**Критика:** В реальных проектах могут возникнуть ситуации, когда для соответствия этому принципу приходится искусственно ограничивать наследование, что снижает гибкость.
### 4. **Interface Segregation Principle (ISP)** - Принцип разделения интерфейсов
**Описание:** Клиенты не должны быть вынуждены зависеть от интерфейсов, которые они не используют. То есть, лучше создавать несколько специализированных интерфейсов, чем один универсальный.
**Плюсы:** Улучшает декомпозицию системы, делает код более читаемым и гибким.
**Критика:** Излишнее следование принципу может привести к созданию множества мелких интерфейсов, что затруднит восприятие и усложнит работу с кодом.
### 5. **Dependency Inversion Principle (DIP)** - Принцип инверсии зависимостей
**Описание:** Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций (интерфейсов), а абстракции не должны зависеть от конкретных реализаций.
**Плюсы:** Позволяет легко заменять и масштабировать модули, что повышает гибкость и расширяемость системы.
**Критика:** Реализация DIP требует написания большого числа интерфейсов и абстракций, что может усложнить код и сделать его трудным для понимания.
---
### Общая критика SOLID:
- **Усложнение кода:** Излишнее следование SOLID может привести к фрагментации кода, увеличению числа классов, интерфейсов и абстракций. Это делает систему сложной для понимания и сопровождения, особенно для небольших проектов.
- **Затруднённость рефакторинга:** В реальных проектах иногда проще модифицировать существующий код, чем расширять его через создание новых классов и интерфейсов.
- **Избыточная гибкость:** В некоторых случаях требуется предсказуемая и прямая реализация функционала, а SOLID может слишком усложнить простые задачи.
Тем не менее, **SOLID** остается важным инструментом для улучшения качества кода, особенно в больших проектах с множеством взаимозависимостей, при этом его применение должно быть оправдано контекстом проекта.
40:00 - не подходит как аргумент на примере базы данных. Это дерево. Частный случай леса.
Joel Spolsky в середине нулевых выкатил статью о видах ПО. Если Ваш код меньше 1000 строк, код одноразовый или embedded без возможности обновления, то SOLID не нужен. Буква O как мне кажется применимо только к такому виду софта как публичные библиотеки. Если Вы пишите enterprise и по сути прикладной софт, то скорее всего Вам все равно на модификации, поэтому и столько непонимания. Когда же Вам нужно backward compatibility, правила deprecation между версиями, то важно конечно создавать интерфейс нужной расширяемости и не требующий изменений.
Мне всегда эти рассказы о SOLID напоминают:
- Сколько стоят помидоры?
- ... Идет часовой текст из видео...
- Так сколько стоят помидоры?
Мне когда разговор неинтересен, я тоже не врубаюсь что происходит
@@VladimirS-h9o Боюсь спикеры тоже не особо врубаються о чем рассказывают. Меня когда первый раз спросили на собесе про Солид, это был 2019 год, у меня тогда было 15 лет коммерческого опыта и 21 год опыт общего программирования и сотни тысяч строк кода написанного и десятки проектов. За следующие 5 лет я пытался найти ответы, смирился с тем что этот вопрос задают, заметил что мнения у людей по этим принципам всегда разные, кроме может буквы I. Доказательство кто прав обычно производиться оскорблениями или повышением голоса. Для себя я нашел способ рассказывать эту сказку, но не уверен что она нравиться всем.
Чтобы быть "адвокатом" нужно приобрести компетенции, а не опыт на основе проектов из лапши и кома грязи. Лучше бы просто задали вопросы гостю чем прерывайющий, загрязняющий шум, который и порождает непонимание. Книжки читать надо а не смотреть на опыт, основанный на вредных привычках аля "видел так делают, удобно"
Уж если это видео, то можно было бы и кода показать и графики немного хотя бы )
А насколько SOLID применим к функциональному программированию по вашему мнению?
В фп всё есть функция.
S - функция
O - функция
L - функция
…
@@danilakhtarov
SOLID появился в ООП, но многие его идеи перекликаются с базовыми принципами функционального программирования. Чистые функции, иммутабельность, функции высшего порядка и полиморфизм через алгебраические типы позволяют в ФП добиватся тех же целей - модульности, гибкости, переиспользуемости и независемости компонентов, как и SOLID в ООП.
О, господин Промис, собственной персоной!Кирилл, пригласите Мурыча, пожалуйста!
Напоминает меня бухого с коллегой по работе на вечеринке, попытка разъяснить ситуацию кто же «батя» 😊😊😊
Классные принципы, один не имеет отношения к архитектуре, другой нафиг не нужен, третий слишком простой и банальный, а сам автор принципов внятно не может их сформуливовать и объяснить что он имел в виду и каждый год меняет свои трактовки....
Очень инженерный подход....
Я понял инверсию зависимостей👍
Позовите Мурыча 😂 он вас спецификацией на место поставить
2:50 мартин в блоге сказал что лисков это не про на следование как он раньше писал
Мартин сам свои принципы не понимает.
И вообще он не программист.
Кто знает, что за гарнитура у Кирилла?
@@3ggr shokz
Этот этот, как его, он ещё этот да как его вообщем он там ещё с этим ну как его. Вообщем хз
после этого видео стало еще больше не ясно)
солид - не особо конкретная штука, все пункты в нём об одном и том же - используйте ооп правильно, не используйте неправильно.
почитать про него никому не помешает, но молиться на него не стоит совершенно точно
48:20 Два здоровых мужика начали обсуждать женщину за ее спиной 😂
58:15 Если на интерфейсе родительского класса был указано, что из метода может вылететь исключение, то выкидывание его из подкласса не ломает принцип Лисков.
Клиентский код должен быть готов к получению результата работы метода в виде исключения и должен его корректно обработать.
Solid топ монолит бататный Картоп
Сам Мартин что создал кроме книг?
Какое образование у него, какой опыт программирования?
Судя по его биографии он программистом ни дня не работал.
Какой то журналист придумал вам принципы, а вы их всерьёз обсуждаете.
Два часа обсуждали, в итоге выяснили что никто толком не понимает принципы, что сами принципы плохо сформулированны, а автор принципов вообще не программист. ЛОЛ
Зайдите в ближайший бар, купите 2 литра разливного, вернись обратно, поставьте эту СОЛИДную философию на скорость x0.5 и можете понять как со стороны нас видят девушки, когда мы берем их с собой в заведение и компанией мужиков обсуждаем айтишечку.
Каки
диалог двух странных))))))))))))
Вода вода вода. Вам на пенсию пора
SOLID бесмыссленная трата времени. Всё.
Такой противный Соер
Знаете, по-моему нифига понятней не стало, нагнали очередного тумана, налили воды, и у людей с критическим мышлением 😎 только укрепляются сомнения - а заслуживает ли тема такого внимания? Из пяти принципов два "по большому счету бесполезны", два "все понимают неправильно", а один "создает ложное чувство понимания".
Чисто фронтендер пытается в тему, в которой он не силен)
Ох повезло тебе что тут кловунов нет, тебе бы напихали