Здравствуйте, Сергей. По поводу DIP, небольшое уточнение, если у вас высокоуровневый модуль A зависит от низкоуровнего модуля B и вы вынесете в модуле B интерфейс и теперь у вас A зависит от интерфейса модуля B, то это не будет DIP а скорее OCP. У вас как модуль A зависил от модуля B, так и зависит, только теперь от интерфейса. Смысл DIP - это инвертирования зависимостей без инвертирования потока управления. Поэтому интерфейс для B нужно объявлять в модуле A и получаем теперь, что А зависит только от своего интерфейса. а B уже зависит от А (зависимость инвертирована). Этот подход служит часто для изоляции одних слоев приложения от других, например доменного слоя от инфраструктуры.
Тот случай, когда коммент полезнее видео)) Тоже не мог понять как обращение через интерфейсы решает проблему зависимости модулей верхнего уровня. Решил посмотреть это видео для систематизации информации, но еще больше запутался. А Ваш коммент как раз внёс ясность.
Реально красивый и полезный коммент, а видео мне вообще непонятно. Что значит встраивать прямо в сервер? Мы же не в одном классе все пишем. Что значит надо будет разрывать зависимости? Как добавление функционала ведет к тому, что надо удалять старый?
В примере из видео высокоуровневый модуль А - это сервер, а низкоуровневый В - это клиент? И тогда суть в том, чтобы интерфейс, через который мы обращаемся из клиента к северу стал частью клиента, так? То есть, клиент будет вызывать какой-то КлиентСерверИнтерфейс (лежит где-то около клиента). А сервер будет имплементировать КлиентСерверИнтерфейс, который будет брать где-то около клиента? Примерно так?
Ребят, уже прошло три года с момента написания ваших комментов. Надеюсь, вы уже поняли, что ОН ВСЕ правильно говорит? )) Человек, показывая на пальцах, просто вводит в курс дела. А для того, чтобы действительно понять, что же такое DIP, нужно будет написать парочку рабочих приложений и только тогда приходит настоящее понимание того, что это, как это все работает и как использовать Dependency Injection, IRepository, Repository, CQRS, Clean Architecture и как все это и создает Dependency Inversion.
10:06 Есть такая штука - рефакторинг кода. Делай раз: Создай интерфейсы по принципу SOLID/ISP, которые реализует класс. Делай два: Унаследуй жёсткий класс от всех интерфейсов, чтобы он их реализовывал. Делай три: Измени клиентов, чтобы они использовали новые интерфейсы вместо жёсткого класса. Танцы с бубном окончены.
После размышлений на эту тему я возможно понял суть, но мое умозаключение отличается от того что вы написали выше - как я понял dep-inversion - это не БУКВАЛЬНЫЙ разворот зависимости в противоположную сторону, а её трансформация. Классы низкого уровня реализуют единый интерфейс, в свою очередь параметр(который и представляет зависимость) конструктора класса высокого уровня реализует тот же самый единый интерфейс. Таким образом, какой бы аргумент(зависимость) мы бы не кинули в конструктор, пока аргумент отвечает интерфейсу - класс будет работать. В итоге теперь класс высокого уровня ЗАВИСИТ не от класса низкого уровня, а от интерфейса в конструкторе. В свою очередь классы низкого уровня ТОЖЕ ЗАВИСЯТ от интерфейса. Это значит, что изменения в классе низкого уровня не соответствующие интерфейсу, который связывает его с классом высокого уровня, повлекут за собой изменения этого интерфейса, которые в свою очередь повлекут и изменения в коде класса высокого уровня(Ведь его параметр конструктора ТОЖЕ реализует этот интерфейс). Поэтому считаю конкретно это предложение из коммента выше неверным и вредным для новичков которые его читают: "если мы будем что-то менять в UserRepository, или мы можем изменить имя класса, а можем вообще унаследовать другой класс, то это никак не затронет UserClient , нам не нужно вносить изменения в его код". А в сам пример с UserClient и UserRepository я бы для того, чтобы показать именно суть добавил бы класс UserRepository2, который тоже реализует интерфейс IUserRepository, но по-другому(возможно с другой логикой) - и тогда класс UserClient мог бы работать и с UserRepository и с UserRepository2, и как раз при изменении зависимости, то есть самого передаваемого аргумента в конструкторе код в классе UserClient менять бы НЕ ПРИШЛОСЬ, так как для него UserRepository и UserRepository2 это по сути одно и тоже, но под капотом разное. Вот и получается, что теперь UserClient плевать с каким классом работать, вот только полной независимости от классов низкого уровня он все-таки не получил, по причине того, что при любом изменении в IUserRepository придется менять код в классе UserClient. Надеюсь верно и более-менее понятно написал. Если есть реально шарящие люди в этой теме, то надеюсь отпишут хоть что-то в ответ, так как я новичок и с этой темой поломал уже голову некоторое время чисто из-за того что все пишут, что если применить dep-inversion, то можно менять внутренности более низкоуровневых модулей не парясь об высокоуровневых, так вот я реально голову сломал пытаясь понять - как же они не будут влиять, если они от ОДНОГО ИНТЕРФЕЙСА ЗАВИСЯТ.
С возможностями современных(ной) IDE писать на каждый чих интерфейс - тоже такое себе занятие, противоречащее KISS'у. Как и с балансом между хард и софт, нужно соблюдать баланс между "все на интерфейсах"/"ни одного интерфейса в проекте". ИМХО
Бля, просто в душу поразила ваша манера объяснять! Так иногда не хватает грубых слов в общении/объяснении, потому что благодаря им в разы быстрее понимается!) Мое почтение за формат)
а в чём глубинный смысл писать на вот этом непонятном языке? если ты прослушал этот ролик то ты 100% понимаешь русский язык и можешь на нём выразиться или, хотя бы, сообразить, что твои вирши не всем будут понятны и воспользоваться гугло-транслейтом.
@@MikhailKolesnikov На якій мові хочу - на такій і пишу. "не всем будут понятны" - я пишу не для всіх, а конкретно автору цього відео, а він українську шарить. Так що фак оф
увы, вызов всего через интерфейсы тоже бывает организован "через одно место". например, когда интерфейс делается вида: void doJob(JobParameters params, Object yet_another_parameter, Long timeout, String log_prefix, int node_id) ну и так далее.... :)
С интерфейсами бывает еще одна крайность, когда начинают их пилить абсолютно на все в системе. В итоге по мере роста кода и проекта, что бы добраться до того места где выполняется сам код необходимо прокликать кучу методов через ctrl и везде будешь попадаться на интерфейсы, а уже потом заглядывать в класс и идти дальше по цепочке. Должна быть мера все таки
О, холивар ) Это всё понятно, но есть некоторые вопросы, просто на подумать. Как раз связанные с тем, чем хреново ооп в принципе по сравнению с функциональщиной. Вот в этом видео прямо показывается, как один из недостатков ООП доводится до совершенства. 1. Так ли часто нужно вставлять новый функционал, который здесь привели в сравнении с тем, что надо всегда солому подстилать и все время делать больше? Например, там вы решили вставить функционал, может раз в полгода, а классов пишете кучу каждый день. И это а) просто заставляет вас делать больше усилий, б) постоянно больше усилий при дебаге или просто при переходах в среде разработки, в попытке выяснить какая реализация используется. А в то же время современные IDE вполне уже не просто текстовые редакторы, и довольно слабый аргумент, что надо лазить потом будет по всему коду, чтобы разорвать при случае зависимость и выставить интерфейс. Т.е. это не утверждение, что данный подход плохо, просто сами попытайтесь оценить в своей работе, в своей среде разработки, в каком случае производительность программиста хуже. 2. Интерфейс уменьшает зависимость, да. Но ее не всегда надо с коробки уменьшать. Программа - это рельсы для поезда. Поезд должен ездить жестко по ним. В первую очередь программа должна быть жесткой, потому как у нее первая задача - работать правильно, выполняя заложенные требования. А уже 2я, или даже 22я, это антагоническая цель - быть гибкой, потому что что-то может измениться в требованиях. Интерфейс - это набор сигнатур методов. А сигнатура - пример сайдэффекта. Т.е. в ООП вообще нет гарантии что передавая один и те же аргументы, вы будете получать одни и те же результаты, потому что дзёбанные объекты имеют состояние (по сути, поля - это глобальные переменные, за которые ругали еще в процедурном подходе). А интерфейс добавляет хардкора в топку, это прям вот идеальный кот в мешке )) Вы еще и имеете возможность подменять реализацию, одна будет у вас в одном случае, другая в другом, и особенно в юнит тестах. Т.е. получается, что вы сознательно в юнит-тестах окружаете код некими конструкциями, которые ТОЧНО будут работать не так, как это работать будет вживую. По сути, что такое сайдэффект. Работа программы зависит, ну типа как от неких глобальных переменных, и черт знает, какие они будут, когда случится бага, и как себя поведет программа в тех или иных случаях. И вы, когда пишете тест, пытаетесь угадать, какие значения переменных в окружении будут в реале, или выставить так, что на ваш взгляд, оно покроет все разные варианты. Много тестов будет просто ради тестов, потому как в реале эти интерфейсы будут только подмножество вариантов своей работы выдавать. А можно и пропустить реальный кейс. (тут я не рассматриваю, что юнит-тесты должны каждую ветку тестить, но смысл, что у вас оверхед будет по тестам). Это так, на подумать, это не критика ;) Не всё так однозначно. Хотя, если так случилось, что выбрали ООП, то вариантов как лучше, не так и много )
C наступающем Новым Годом, Сергей. В целом с вами согласен, с единственной оговоркой. Использовать класс через интерфейс нужно при внешнем взаимодействии к этому классу, если понимаете о чем я. Если класс реализует обертку настроек или DTO то не вижу смысла этого делать.
3:25 такие задачи как логирование и профайлинг зачастую делаются через аспекты. На первый взгляд это смотрится довольно лаконично, без кучи самодельных интерфейсов и декораторов; вся магия остаётся под капотом АОП-фреймворков. Сергей, сделайте как-нибудь видео про АОП, пожалуйста, мб есть какие-то подводные камни.
@@a.o.yaroslavov А чем он вреден то? Позволяет сначало задать бизнес-логику в виде тестов, а потом уже писать класс, который будет удовлетворять тесты, тем самым, следовать бизнес-логике
Как рассказывать про инверсию зависимостей и не рассказать про инверсию зависимостей. Тот, кто знает, что такое DI, тот знает, что такое DI. А кто нет - нет. Вместо отлития в граните «все классы должны использоваться через интерфейсы», может быть, имело смысл показать пример, как инвертируются зависимости. На схеме, скажем.
К сожалению интерфейсы после релиза системы приходится менять в следствии ее расширения, и иногда весьма интенсивно, и вот тогда начинается просто ад с апдейтом интерфейсов (около сотни). В остальном все достаточно гибко
11 минут каких-то историй хотел понять суть DIP - посмотрел монолог но сути так и не уловил было бы неплохо, если бы все это было лаконичнее и без излишних баек
В идеале не привязываться в подобных видео к языку. Учимся программировать не на языке, а с использованием языка ) имхо (иначе я бы не смотрел эти ролики)
Ну вот не факт. Бывают функциональные единицы с несколькими зависимостями, которые используются приватно только в данном контексте и не имеют смысла вне его, но которые все же инъектируются через DI. Писать каждый раз по этому поводу новый интерфейс -- это по большей части моральная мастурбация. Тут больше применимы принципы yagni и kiss.
Ничерта не понимаю, как добавления новых методов в класс сервера аффектит мой класс клиента. Допустим у меня есть объект класса Сервер в классе Клиент. Через него я вызываю необходимые мне методы. Как добавление новых методов в класс Сервер может сломать работу класса Клиент??? Ну добавились новые методы и что? Хочу вызову, хочу нет... Объясните плиз, я вообще не отдупляю плюсы работы с классами через интерфейс!
Новый метод может, например, принимать новый тип данных. А этот тип данных может быть недоступен для клиентского кода - например пекеджи не обновились. Вот и аффект
Может быть, я не очень умный, но я посмотрел весь плейлист и по-прежнему не понимаю, почему в описанном случае нельзя просто добавить к классу Server метод authorization() или т.п.? Нужна авторизация - дописываем авторизацию, ну в чём проблема-то?
Про стабы интересно. После написания такого кода, есть две реализации для поддержки, и один интерфейс. Слова "интерфейсы должны быть стабильны"... На практике изменения чаще говорят "никто никому ничего не должен", и меняешь по итогу все имплементации. Реализовать такой стаб проще через наследование, чем отдельный интерфейс - изменение будет в двух местах, вместо трёх.
Ребят, возник вопрос, который прям не дает покоя: - Не противоречит ли принципе DIP паттерну Creator. По DIP надо объекты передавать другим объектам через их интерфейсы, а по Creator'у эти объекты следует создавать там, где они используются. Как разрешить это противоречие?
Разрешается противоречие устранением ошибок в понимании принципов) По DIP надо создавать объекты типа интерфейса, который реализует класс объекта, а не передавать что-то. Например, есть класс "МумбаЮмба", который имплементирует интерфейс "МумбаЮмбаИнтерфейс". Теперь в другом классе тебе понадобился объект класса МумбаЮмба. Ты можешь создать его так: МумбаЮмба мумбаЮмба = new МумбаЮмба(); А DIP у тебя просит всего навсего тип переменной указать интерфейсный: МумбаЮмбаИнтерфейс мумбаЮмба = new МумбаЮмба(); Тогда потом в эту переменную ты сможешь отправить объект любого класса, имплементирующего интерфейс МумбаЮмбаИнтерфейс.
@@ergo_____3491 Разве этого достаточно? У меня, конечно, много ошибок в понимании, но я думал так: Один из примером реализации DIP является dependency injection (здесь уже не inversion). Благодаря этому принципу и надо передавать одни классы в другие через интерфейсы, а не создавать одни внутри других
Миллион лайков этому видео! Как открыл для себя удобство прогр-я через интерфейсы, до сих пор кипятком ссусь от счастья) Хотелось бы подобный ролик еще и про DI/IoC.
Ну не особо надо все вызывать через интерфейс. Если надо выделить интерфейс можно за 5 секунд. Зачем его делать заранее? Хотя вот если у нас библиотека, то ее Api лучше через интерфейсы развязать.
Здравствуйте, можете потом снять видео про дизайн паттерны(behavioral, structural), хотя-бы по 2-3 паттерна с каждого. Ещё что такое downcasting и почему его использование это плохо.
А почему нет? Допустим dto который надо записать в базу или сериализовать куда-то или один большой dto конвертировать в несколько маленьких.. И что всю эту функциональность пихать в одну реализацию? А если завтра потребуется поменять серализацию из json в bin, или xml? ИМХО делаем dto с чистыми данными и дальше декоратором наворачиваем всю эту логику.. Проблема в том что как правило программисты сначала пишут реализацию а потом из нее extract interface. Но на практике чаще всего класс реализует несколько интерфейсов, а вся та реализация которая была написана ранее является частным случаем и если из нее выделять интерфейс то он должен быть не один а несколько. Это вечная проблема: вместо того чтобы идти от общего - подумать, абстрагироваться, декомпозировать абстракции, и потом уже приступать к частному - т.е. к реализации конкретных классов, люди сначала хардкодят чтобы работало а потом думают. Поэтому все и пользуются мощными IDE которые по сути ускоряют скорость написания кода а не улучшают качество мысли. Если бы приходилось кодить в блокноте то тут же хочешь не хочешь а быстрее сначала подумать а потом только писать.
@@LinDahai88 >И что всю эту функциональность пихать в одну реализацию? Композицию никто не отменял > если завтра потребуется поменять серализацию из json в bin, или xml? Нужны отдельные интерфейсы для json сериализации, отдельный для xml и т. д. > ИМХО делаем dto с чистыми данными и дальше декоратором наворачиваем всю эту логику.. Почему бы нет, не вижу противоречий. Для ясности, общий интерфейс(ы) над всеми дто или логической группой дто - нормально и правильно. По интерфейсу для каждого класса дто - как-то не очень.
@@lyloo6577 > Нужны отдельные интерфейсы для json сериализации, отдельный для xml и т. д. Не нужны. Иначе это будут интерфейсы отталкивающиеся от реализации а не от клиентского кода. И начнется: если это json то делаем одно иначе если это xml делаем другое иначе если это bin - третье.... Поставьте себя на место разработчика который будет пользоваться Вашим классом: ему нафиг не нужно знать каким способом вы это делаете. Он знает только о массиве байт и о типе из которого этот массив был получен и два метода Serialize/Deserialize. Остальное для него - магия, избавьте его от этого головняка - у него другая задача. Зато если ходите то хоть шифрование прикрутите к своей сериализации - клиент вообще ничего не почувствует. В этом то и смысл интерфейсов сделать так чтобы клиентский код вообще никак не поменялся при изменениях в реализации класса. > Для ясности, общий интерфейс(ы) над всеми дто или логической группой дто - нормально и правильно. Общий интерфейс над группой дто? Т.е. при изменении или добавлении дто-шек будет меняться интерфейс? Или я не так понял или нафига оно надо? Это мы тогда возвращаемся к теме interface segregation. > По интерфейсу для каждого класса дто - как-то не очень Опять таки здесь нет и не должно быть соответствия между дто и интерфейсом. Например класс Pet не реализует интерфейс IPet. Таких интерфейсов быть не должно. Должно быть класс Питомец реализует интерфейсы Гладебильный, Кормибельный и Играбельный. Чувствуете разницу? Один класс но с разными интерфейсами для разных клиентов. Например хозяин может покормить питомца но гости могу только играть и гладить. Так же и с дто-шками - класс один но интерфейсы разные могут быть для разных задач.
@@LinDahai88 вы сами приводите примеры "Кормибельный", "Играбельный" - видно что ваши классы реализуют сложное поведение, то есть уже не dto. > Например класс Pet не реализует интерфейс IPet. Таких интерфейсов быть не должно. Я примерно об этом же пишу. Но мне сложно придумать пример из реальной жизни когда все поля дто можно подвести под интерфейсы в стиле "Кормибельный", "Играбельный" Если не обращаться к ДТО объекту напрямую то это именно и получится IPet Вы давно в программировании? )
@@lyloo6577 > Вы давно в программировании? ) 6 лет, C#, Unity3D > Но мне сложно придумать пример из реальной жизни когда все поля дто можно подвести под интерфейсы в стиле "Кормибельный", "Играбельный" Действительно трудно, но та же сериализация.., или например форматирование.... Сами поля дто-шки трудно назвать полноценными методами т.к. это скорее всего геттеры.., так что думаю это можно не считать. ;) Вообще мы тут спорим про dto. Но если задуматься то это уже не ООП, потому что если это чистые данные без логики которая их обрабатывает то где тогда high cohesion?
так руководству выгодно, что программисты трекают больше времени - больше платит заказчик, сложнее программа - куда ты, заказчик, от нас уйдешь, только мы можем ее саппортить и стоимость смены команды будет для тебя овердорогой
@@maxlich9139 обычно в любой компании есть коммуникация. и обычно трекание времени и отслеживание этого действа - это задача больше PM, чем тимлида или архитектора. и обычно руководство прекрасно в курсе, как ускорить или замедлить проект.
Я всегда на Java стараюсь строить взаимодействие слоев через интерфейсы и люто протестую, когда вижу во время ревью, что кто-то делает инъекцию зависимости в переменную типа класса, а не интерфейса. В нормальном коде должно быть удобно менять имплементации. Да в принципе не нужно вызывающему контекст знать детали реадизации.
Всё от тебя зависит. Программисты по факту учатся сами, университет только даёт какую-то небольшую базу, плюс знакомства с товарищами по интересам. А так да, специальность айтишная, идти можно -- главное не забывай учиться самостоятельно. Главная ошибка многих поступающих: думать, что университет тебя научит программировать. Не научит. Хотя на его лабораторках и курсовых можно практиковаться.
Программная инженерия, так часто называют. Как и написали выше, больше создадут среду, дадут пищу для размышления, какие-то основы основ. А хочешь программировать - всё сам. Хотя в ВШЭ, как понимаю, все условия, чтобы разработка занимала все курсы обучения.
Ага, когда пишешь на Яве, когда производительность - это ниже твоего достоинства, когда это не говно-код, а ты так видишь... тогда таки да - всё виртуальное и везде интерфейсы. Осталось только, чтоб авторы STL одумались и всё переписали на интерфейсах.
@@МаксимАлексеев-ч4й это предохраняет от тех случаев, когда класс используют в рандомных местах проекта, а потом его понадобилось изменить. Некоторые классы (почти) никогда не изменяются и используются в 1 месте. Если 3 мест и больше - точно надо, если проходит ось изменений - точно надо. Если есть бешеные джуно-индусы - точно надо. А ещё это касается только больших проектов, всяким сайтописателям хватает интерфейсов у фасадов модулей.
Добавляйте интерфейс если почувствовали, что он нужен. IDE это умеет делать. Если делаете библиотеку, то все что торчит из нее наружу должно иметь интерфейс. В коде сервиса такой необходимости нет. Это ваш код и не надо городить абстракции раньше времени.
Как показала практика, "все классы через интерфейсы" это тоже бред. Нет смысла загонять все классы в интерфейсы! К примеру не стоит делать интерфейсы для моделей или скажет для тех же DTO. А тот кто это сделает или будет призывать к этому на мой взгляд так же является нехорошим программистом. В интерфейсы стоит загонять сервисы, провайдеры, репозитории, обработчики.... То есть те классы, которые что-то делают с окружением, а все те классы, которые ничего не делают с окружением в интерфейсы нужно загонять крайне взвешенно, что бы не наплодил слишком много ненужных интерфейсов.
на самом деле тут еще надо понимать, зачем ты это делаешь, это объясняется в видео :) если просто услышать эту фразу и начать применять то можно еще большего говна поесть. Так и под дтошки интерфейсы можна начать пилить
Вы хотите общаться с девушкой. Девушка, это интерфейс, а блондинка, брюнетка конкретные реализации. Вот вам старший брат говорит, что вам нужно общаться только с девушками одного цвета волос. Дело к свадьбе и она перекрасилась!
💪Новый поток advanced тренинга Enterprise patterns стартует 2.12 - go.foxminded.ua/3NnrttG
Здравствуйте, Сергей. По поводу DIP, небольшое уточнение, если у вас высокоуровневый модуль A зависит от низкоуровнего модуля B и вы вынесете в модуле B интерфейс и теперь у вас A зависит от интерфейса модуля B, то это не будет DIP а скорее OCP. У вас как модуль A зависил от модуля B, так и зависит, только теперь от интерфейса. Смысл DIP - это инвертирования зависимостей без инвертирования потока управления. Поэтому интерфейс для B нужно объявлять в модуле A и получаем теперь, что А зависит только от своего интерфейса. а B уже зависит от А (зависимость инвертирована). Этот подход служит часто для изоляции одних слоев приложения от других, например доменного слоя от инфраструктуры.
Тот случай, когда коммент полезнее видео)) Тоже не мог понять как обращение через интерфейсы решает проблему зависимости модулей верхнего уровня. Решил посмотреть это видео для систематизации информации, но еще больше запутался. А Ваш коммент как раз внёс ясность.
Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций.
Реально красивый и полезный коммент, а видео мне вообще непонятно. Что значит встраивать прямо в сервер? Мы же не в одном классе все пишем. Что значит надо будет разрывать зависимости? Как добавление функционала ведет к тому, что надо удалять старый?
В примере из видео высокоуровневый модуль А - это сервер, а низкоуровневый В - это клиент?
И тогда суть в том, чтобы интерфейс, через который мы обращаемся из клиента к северу стал частью клиента, так? То есть, клиент будет вызывать какой-то КлиентСерверИнтерфейс (лежит где-то около клиента).
А сервер будет имплементировать КлиентСерверИнтерфейс, который будет брать где-то около клиента? Примерно так?
Ребят, уже прошло три года с момента написания ваших комментов. Надеюсь, вы уже поняли, что ОН ВСЕ правильно говорит? ))
Человек, показывая на пальцах, просто вводит в курс дела. А для того, чтобы действительно понять, что же такое DIP, нужно будет написать парочку рабочих приложений и только тогда приходит настоящее понимание того, что это, как это все работает и как использовать Dependency Injection, IRepository, Repository, CQRS, Clean Architecture и как все это и создает Dependency Inversion.
Спасибо, посмотрев видео наконец-то понял SOLID. В других источниках с которыми сталкивался либо слишком абстрактно пояснено, либо заумно.
Че ты там понял?
Спасибо за видео, все очень понятно!
Пока всего два вопроса!
1) Как вас зовут?
2) Большой ли у вас стаж в программировании?
таймкод 0:00
В голос
Неплохо, рассмеялся, спасибо :)
до сліз
@@ifan146 лол
10:06 Есть такая штука - рефакторинг кода.
Делай раз: Создай интерфейсы по принципу SOLID/ISP, которые реализует класс.
Делай два: Унаследуй жёсткий класс от всех интерфейсов, чтобы он их реализовывал.
Делай три: Измени клиентов, чтобы они использовали новые интерфейсы вместо жёсткого класса.
Танцы с бубном окончены.
за СОЛИД и двор, лайк в упор
поддерживаю. Тема тестирования очень актуальна. Хочется получить информацию в присущей для вас доступной манере подаче информации
Найкраще пояснення SOLID що я чув, набагато краще ніж Шевчук!
Здравия, Сергей, хотелось бы услышать от вас про unit-тестирование, в частности про: Spy, Mock, Stab и еще вроде Fake.
про mock и stub вроде было квкое-то видео, поищи на канале
Да хотелось бы послушать
Поддерживаю
Еще даже не посмотрел видео, а уже поставил лайк. Надо завязывать с такой привычкой
Спасибо большое за видео!
Сергей, все правильно, так и пишем, несогласных стараемся убедить :)
Большое спасибо за ваши видеоролики
Доходчиво и достаточно коротко!
После размышлений на эту тему я возможно понял суть, но мое умозаключение отличается от того что вы написали выше - как я понял dep-inversion - это не БУКВАЛЬНЫЙ разворот зависимости в противоположную сторону, а её трансформация. Классы низкого уровня реализуют единый интерфейс, в свою очередь параметр(который и представляет зависимость) конструктора класса высокого уровня реализует тот же самый единый интерфейс. Таким образом, какой бы аргумент(зависимость) мы бы не кинули в конструктор, пока аргумент отвечает интерфейсу - класс будет работать. В итоге теперь класс высокого уровня ЗАВИСИТ не от класса низкого уровня, а от интерфейса в конструкторе. В свою очередь классы низкого уровня ТОЖЕ ЗАВИСЯТ от интерфейса. Это значит, что изменения в классе низкого уровня не соответствующие интерфейсу, который связывает его с классом высокого уровня, повлекут за собой изменения этого интерфейса, которые в свою очередь повлекут и изменения в коде класса высокого уровня(Ведь его параметр конструктора ТОЖЕ реализует этот интерфейс). Поэтому считаю конкретно это предложение из коммента выше неверным и вредным для новичков которые его читают: "если мы будем что-то менять в UserRepository, или мы можем изменить имя класса, а можем вообще унаследовать другой класс, то это никак не затронет UserClient , нам не нужно вносить изменения в его код". А в сам пример с UserClient и UserRepository я бы для того, чтобы показать именно суть добавил бы класс UserRepository2, который тоже реализует интерфейс IUserRepository, но по-другому(возможно с другой логикой) - и тогда класс UserClient мог бы работать и с UserRepository и с UserRepository2, и как раз при изменении зависимости, то есть самого передаваемого аргумента в конструкторе код в классе UserClient менять бы НЕ ПРИШЛОСЬ, так как для него UserRepository и UserRepository2 это по сути одно и тоже, но под капотом разное. Вот и получается, что теперь UserClient плевать с каким классом работать, вот только полной независимости от классов низкого уровня он все-таки не получил, по причине того, что при любом изменении в IUserRepository придется менять код в классе UserClient. Надеюсь верно и более-менее понятно написал. Если есть реально шарящие люди в этой теме, то надеюсь отпишут хоть что-то в ответ, так как я новичок и с этой темой поломал уже голову некоторое время чисто из-за того что все пишут, что если применить dep-inversion, то можно менять внутренности более низкоуровневых модулей не парясь об высокоуровневых, так вот я реально голову сломал пытаясь понять - как же они не будут влиять, если они от ОДНОГО ИНТЕРФЕЙСА ЗАВИСЯТ.
Спасибо, весь курс хорош)
Thank you SO MUCH!!!
а можно видео потом про DI & IoC?
Вы очень крут!!!
Вот когда появится задача добавить авторизацию, в ИДЕ есть кнопка Extract Interface на классе, и делается дальше всё что вы рассказали.
С возможностями современных(ной) IDE писать на каждый чих интерфейс - тоже такое себе занятие, противоречащее KISS'у. Как и с балансом между хард и софт, нужно соблюдать баланс между "все на интерфейсах"/"ни одного интерфейса в проекте". ИМХО
Наконец послушал про "d". Роберт Мартин в своих лекиях про солид обычно рассказывает только про "sol"
Бля, просто в душу поразила ваша манера объяснять! Так иногда не хватает грубых слов в общении/объяснении, потому что благодаря им в разы быстрее понимается!) Мое почтение за формат)
залпом посмотрел
Зростання вашому каналу! Хорошу справу робите!
а в чём глубинный смысл писать на вот этом непонятном языке? если ты прослушал этот ролик то ты 100% понимаешь русский язык и можешь на нём выразиться или, хотя бы, сообразить, что твои вирши не всем будут понятны и воспользоваться гугло-транслейтом.
@@MikhailKolesnikov На якій мові хочу - на такій і пишу. "не всем будут понятны" - я пишу не для всіх, а конкретно автору цього відео, а він українську шарить. Так що фак оф
@@MikhailKolesnikov Абсолютно понятный язык. Не нравится -- проходи мимо, не задерживайся, сталкер.
@@MikhailKolesnikov я, русский, но его писанина мне понятна и даже прикольно, что он так написал :)
Покажите каждый принцип на практике, на джаве или любо чем)
увы, вызов всего через интерфейсы тоже бывает организован "через одно место".
например, когда интерфейс делается вида:
void doJob(JobParameters params, Object yet_another_parameter, Long timeout, String log_prefix, int node_id)
ну и так далее.... :)
Ну рукожопую жопорукость никогда и никому не победить и не искоренить
С интерфейсами бывает еще одна крайность, когда начинают их пилить абсолютно на все в системе. В итоге по мере роста кода и проекта, что бы добраться до того места где выполняется сам код необходимо прокликать кучу методов через ctrl и везде будешь попадаться на интерфейсы, а уже потом заглядывать в класс и идти дальше по цепочке. Должна быть мера все таки
На эту тему очень понравилось: ua-cam.com/video/knNaUSLhx-U/v-deo.html )
Ctrl+alt переходит сразу на реализацию
Спасибо! Очень крутой цикл роликов. обязательно скину друзьям.
спасибо за видео, поддержите видео комментариями!
ПРОСТО ТОП!! СПАСИБО!!
О, холивар )
Это всё понятно, но есть некоторые вопросы, просто на подумать. Как раз связанные с тем, чем хреново ооп в принципе по сравнению с функциональщиной. Вот в этом видео прямо показывается, как один из недостатков ООП доводится до совершенства.
1. Так ли часто нужно вставлять новый функционал, который здесь привели в сравнении с тем, что надо всегда солому подстилать и все время делать больше? Например, там вы решили вставить функционал, может раз в полгода, а классов пишете кучу каждый день. И это а) просто заставляет вас делать больше усилий, б) постоянно больше усилий при дебаге или просто при переходах в среде разработки, в попытке выяснить какая реализация используется. А в то же время современные IDE вполне уже не просто текстовые редакторы, и довольно слабый аргумент, что надо лазить потом будет по всему коду, чтобы разорвать при случае зависимость и выставить интерфейс.
Т.е. это не утверждение, что данный подход плохо, просто сами попытайтесь оценить в своей работе, в своей среде разработки, в каком случае производительность программиста хуже.
2. Интерфейс уменьшает зависимость, да. Но ее не всегда надо с коробки уменьшать. Программа - это рельсы для поезда. Поезд должен ездить жестко по ним. В первую очередь программа должна быть жесткой, потому как у нее первая задача - работать правильно, выполняя заложенные требования. А уже 2я, или даже 22я, это антагоническая цель - быть гибкой, потому что что-то может измениться в требованиях. Интерфейс - это набор сигнатур методов. А сигнатура - пример сайдэффекта. Т.е. в ООП вообще нет гарантии что передавая один и те же аргументы, вы будете получать одни и те же результаты, потому что дзёбанные объекты имеют состояние (по сути, поля - это глобальные переменные, за которые ругали еще в процедурном подходе). А интерфейс добавляет хардкора в топку, это прям вот идеальный кот в мешке )) Вы еще и имеете возможность подменять реализацию, одна будет у вас в одном случае, другая в другом, и особенно в юнит тестах. Т.е. получается, что вы сознательно в юнит-тестах окружаете код некими конструкциями, которые ТОЧНО будут работать не так, как это работать будет вживую. По сути, что такое сайдэффект. Работа программы зависит, ну типа как от неких глобальных переменных, и черт знает, какие они будут, когда случится бага, и как себя поведет программа в тех или иных случаях. И вы, когда пишете тест, пытаетесь угадать, какие значения переменных в окружении будут в реале, или выставить так, что на ваш взгляд, оно покроет все разные варианты. Много тестов будет просто ради тестов, потому как в реале эти интерфейсы будут только подмножество вариантов своей работы выдавать. А можно и пропустить реальный кейс. (тут я не рассматриваю, что юнит-тесты должны каждую ветку тестить, но смысл, что у вас оверхед будет по тестам).
Это так, на подумать, это не критика ;) Не всё так однозначно. Хотя, если так случилось, что выбрали ООП, то вариантов как лучше, не так и много )
C наступающем Новым Годом, Сергей. В целом с вами согласен, с единственной оговоркой. Использовать класс через интерфейс нужно при внешнем взаимодействии к этому классу, если понимаете о чем я. Если класс реализует обертку настроек или DTO то не вижу смысла этого делать.
Вовремя открыл ютуб (5 сек назад залито). Спасибо за видео.
3:25 такие задачи как логирование и профайлинг зачастую делаются через аспекты. На первый взгляд это смотрится довольно лаконично, без кучи самодельных интерфейсов и декораторов; вся магия остаётся под капотом АОП-фреймворков. Сергей, сделайте как-нибудь видео про АОП, пожалуйста, мб есть какие-то подводные камни.
Подводные камни провляются в тот момент когда система перестала работать на отлично. Сложно сайд-эффекты отслеживать.
Было бы интересно послушать о TDD. Спасибо за вашу работу
@@a.o.yaroslavov А чем он вреден то? Позволяет сначало задать бизнес-логику в виде тестов, а потом уже писать класс, который будет удовлетворять тесты, тем самым, следовать бизнес-логике
Спасибо! Все понятно.
Как рассказывать про инверсию зависимостей и не рассказать про инверсию зависимостей. Тот, кто знает, что такое DI, тот знает, что такое DI. А кто нет - нет. Вместо отлития в граните «все классы должны использоваться через интерфейсы», может быть, имело смысл показать пример, как инвертируются зависимости. На схеме, скажем.
хах, полез в комменты на середине видео и понял, что примеров не будет ))
@Sergey Nemchinskiy Там SRP в назві
Говорит что надо все делать ч/з интерфейс, тогда что же является софткод?
Тоже возник вопрос на этом месте
Да, что-то уже попахивает антипаттерном.
Подожду ответа с вами
Ну, можно ещё вместо каждого метода создавать и передавать при конструировании стратегию, которая этот метод реализует. Тогда код будет ещё мягче.
Огромное спасибо за видео но не хватает примера для полного понимания
Расскажите пожалуйста про самые интересные, на ваш взгляд, принципы, которые описывал Роберт Мартин по мимо принципов SOLID
GRASP
хорошие лекции, спасибо за ваш труд.
На 04:55 он говорит "добавить шаблон прокси из гов". Что за гов? Благодарю за ответ.
Gang of Four (GoF)
К сожалению интерфейсы после релиза системы приходится менять в следствии ее расширения, и иногда весьма интенсивно, и вот тогда начинается просто ад с апдейтом интерфейсов (около сотни). В остальном все достаточно гибко
Спасибо, ничего непонятно
годно
11 минут каких-то историй
хотел понять суть DIP - посмотрел монолог но сути так и не уловил
было бы неплохо, если бы все это было лаконичнее и без излишних баек
Тут такой рассказчик, он по-другому не умеет
Добрый день, очень хотелось бы увидеть все принципы SOLID в виде кода, хорошо бы java.
В идеале не привязываться в подобных видео к языку. Учимся программировать не на языке, а с использованием языка ) имхо (иначе я бы не смотрел эти ролики)
Ну вот не факт. Бывают функциональные единицы с несколькими зависимостями, которые используются приватно только в данном контексте и не имеют смысла вне его, но которые все же инъектируются через DI. Писать каждый раз по этому поводу новый интерфейс -- это по большей части моральная мастурбация. Тут больше применимы принципы yagni и kiss.
Ничерта не понимаю, как добавления новых методов в класс сервера аффектит мой класс клиента. Допустим у меня есть объект класса Сервер в классе Клиент. Через него я вызываю необходимые мне методы. Как добавление новых методов в класс Сервер может сломать работу класса Клиент??? Ну добавились новые методы и что? Хочу вызову, хочу нет... Объясните плиз, я вообще не отдупляю плюсы работы с классами через интерфейс!
Новый метод может, например, принимать новый тип данных. А этот тип данных может быть недоступен для клиентского кода - например пекеджи не обновились. Вот и аффект
Может быть, я не очень умный, но я посмотрел весь плейлист и по-прежнему не понимаю, почему в описанном случае нельзя просто добавить к классу Server метод authorization() или т.п.? Нужна авторизация - дописываем авторизацию, ну в чём проблема-то?
Не хватает наглядной демонстрации через блок схемы. Делали на предыдущих принципах, а тут почему-то не стали :(
фломастеры видать окончательно сдохли, а на новые денег нет.
Про стабы интересно. После написания такого кода, есть две реализации для поддержки, и один интерфейс.
Слова "интерфейсы должны быть стабильны"... На практике изменения чаще говорят "никто никому ничего не должен", и меняешь по итогу все имплементации.
Реализовать такой стаб проще через наследование, чем отдельный интерфейс - изменение будет в двух местах, вместо трёх.
Я тоже не из лагеря «всё через интерфейсы», но аргумент звучит как предложение экономить на семечках.
Наверное самый часто нарушаемый принцип)
Ребят, возник вопрос, который прям не дает покоя:
- Не противоречит ли принципе DIP паттерну Creator. По DIP надо объекты передавать другим объектам через их интерфейсы, а по Creator'у эти объекты следует создавать там, где они используются. Как разрешить это противоречие?
Разрешается противоречие устранением ошибок в понимании принципов)
По DIP надо создавать объекты типа интерфейса, который реализует класс объекта, а не передавать что-то.
Например, есть класс "МумбаЮмба", который имплементирует интерфейс "МумбаЮмбаИнтерфейс".
Теперь в другом классе тебе понадобился объект класса МумбаЮмба.
Ты можешь создать его так:
МумбаЮмба мумбаЮмба = new МумбаЮмба();
А DIP у тебя просит всего навсего тип переменной указать интерфейсный:
МумбаЮмбаИнтерфейс мумбаЮмба = new МумбаЮмба();
Тогда потом в эту переменную ты сможешь отправить объект любого класса, имплементирующего интерфейс МумбаЮмбаИнтерфейс.
@@ergo_____3491 Разве этого достаточно? У меня, конечно, много ошибок в понимании, но я думал так:
Один из примером реализации DIP является dependency injection (здесь уже не inversion). Благодаря этому принципу и надо передавать одни классы в другие через интерфейсы, а не создавать одни внутри других
Миллион лайков этому видео! Как открыл для себя удобство прогр-я через интерфейсы, до сих пор кипятком ссусь от счастья) Хотелось бы подобный ролик еще и про DI/IoC.
8:05
Берете и расширяете функциональность в нужном....шта?
Хотелось бы про TDD
OK!
Ну не особо надо все вызывать через интерфейс. Если надо выделить интерфейс можно за 5 секунд. Зачем его делать заранее? Хотя вот если у нас библиотека, то ее Api лучше через интерфейсы развязать.
Здравствуйте, можете потом снять видео про дизайн паттерны(behavioral, structural), хотя-бы по 2-3 паттерна с каждого.
Ещё что такое downcasting и почему его использование это плохо.
Я только не понял почему в видео про принцип открытости закрытости та же самая инф
Потому что автор сам не разобрался
не знаю оговрка это была или нет но -SRP принцип единственной ответственности.
Каждый класс должен иметь только одну зону ответственности.
А разве интерфейс или декоратор не нарушают принцип единственной ответственности?
Приведите, пожалуйста , примеры DIP, было без DIP так, с DIP стало так...
да, мне тоже кажется, что зря автор в этом ролике сел за стол, а не рисовал, как в предыдущих примеры на доске, хоть и сдохшим фломастером.
про GRASP бы и закон Деметры послушать
что значит вызывать класс через интерфейс?)
Сергей, плиз, го антипаттерны.
а примеров бы
что такое юнит тест ?
Не на каждый класс интерфейс, а на каждый класс, содержащий сложное поведение - интерфейс. Ну не делать же интерфейсы для dto и подобных
А почему нет? Допустим dto который надо записать в базу или сериализовать куда-то или один большой dto конвертировать в несколько маленьких.. И что всю эту функциональность пихать в одну реализацию? А если завтра потребуется поменять серализацию из json в bin, или xml? ИМХО делаем dto с чистыми данными и дальше декоратором наворачиваем всю эту логику.. Проблема в том что как правило программисты сначала пишут реализацию а потом из нее extract interface. Но на практике чаще всего класс реализует несколько интерфейсов, а вся та реализация которая была написана ранее является частным случаем и если из нее выделять интерфейс то он должен быть не один а несколько. Это вечная проблема: вместо того чтобы идти от общего - подумать, абстрагироваться, декомпозировать абстракции, и потом уже приступать к частному - т.е. к реализации конкретных классов, люди сначала хардкодят чтобы работало а потом думают. Поэтому все и пользуются мощными IDE которые по сути ускоряют скорость написания кода а не улучшают качество мысли. Если бы приходилось кодить в блокноте то тут же хочешь не хочешь а быстрее сначала подумать а потом только писать.
@@LinDahai88 >И что всю эту функциональность пихать в одну реализацию?
Композицию никто не отменял
> если завтра потребуется поменять серализацию из json в bin, или xml?
Нужны отдельные интерфейсы для json сериализации, отдельный для xml и т. д.
> ИМХО делаем dto с чистыми данными и дальше декоратором наворачиваем всю эту логику..
Почему бы нет, не вижу противоречий. Для ясности, общий интерфейс(ы) над всеми дто или логической группой дто - нормально и правильно. По интерфейсу для каждого класса дто - как-то не очень.
@@lyloo6577
> Нужны отдельные интерфейсы для json сериализации, отдельный для xml и т. д.
Не нужны. Иначе это будут интерфейсы отталкивающиеся от реализации а не от клиентского кода. И начнется: если это json то делаем одно иначе если это xml делаем другое иначе если это bin - третье.... Поставьте себя на место разработчика который будет пользоваться Вашим классом: ему нафиг не нужно знать каким способом вы это делаете. Он знает только о массиве байт и о типе из которого этот массив был получен и два метода Serialize/Deserialize. Остальное для него - магия, избавьте его от этого головняка - у него другая задача. Зато если ходите то хоть шифрование прикрутите к своей сериализации - клиент вообще ничего не почувствует. В этом то и смысл интерфейсов сделать так чтобы клиентский код вообще никак не поменялся при изменениях в реализации класса.
> Для ясности, общий интерфейс(ы) над всеми дто или логической группой дто - нормально и правильно.
Общий интерфейс над группой дто? Т.е. при изменении или добавлении дто-шек будет меняться интерфейс? Или я не так понял или нафига оно надо? Это мы тогда возвращаемся к теме interface segregation.
> По интерфейсу для каждого класса дто - как-то не очень
Опять таки здесь нет и не должно быть соответствия между дто и интерфейсом. Например класс Pet не реализует интерфейс IPet. Таких интерфейсов быть не должно. Должно быть класс Питомец реализует интерфейсы Гладебильный, Кормибельный и Играбельный. Чувствуете разницу? Один класс но с разными интерфейсами для разных клиентов. Например хозяин может покормить питомца но гости могу только играть и гладить. Так же и с дто-шками - класс один но интерфейсы разные могут быть для разных задач.
@@LinDahai88 вы сами приводите примеры "Кормибельный", "Играбельный" - видно что ваши классы реализуют сложное поведение, то есть уже не dto.
> Например класс Pet не реализует интерфейс IPet. Таких интерфейсов быть не должно.
Я примерно об этом же пишу. Но мне сложно придумать пример из реальной жизни когда все поля дто можно подвести под интерфейсы в стиле "Кормибельный", "Играбельный" Если не обращаться к ДТО объекту напрямую то это именно и получится IPet
Вы давно в программировании? )
@@lyloo6577
> Вы давно в программировании? )
6 лет, C#, Unity3D
> Но мне сложно придумать пример из реальной жизни когда все поля дто можно подвести под интерфейсы в стиле "Кормибельный", "Играбельный"
Действительно трудно, но та же сериализация.., или например форматирование.... Сами поля дто-шки трудно назвать полноценными методами т.к. это скорее всего геттеры.., так что думаю это можно не считать. ;)
Вообще мы тут спорим про dto. Но если задуматься то это уже не ООП, потому что если это чистые данные без логики которая их обрабатывает то где тогда high cohesion?
так руководству выгодно, что программисты трекают больше времени - больше платит заказчик, сложнее программа - куда ты, заказчик, от нас уйдешь, только мы можем ее саппортить и стоимость смены команды будет для тебя овердорогой
да ваще странно, обычно руководство в код не лезет. только тимлиды, сениоры и архитекторы
@@maxlich9139 обычно в любой компании есть коммуникация. и обычно трекание времени и отслеживание этого действа - это задача больше PM, чем тимлида или архитектора. и обычно руководство прекрасно в курсе, как ускорить или замедлить проект.
@@wayfarer2178 ну тонкостей программирования они не обязаны знать
Я всегда на Java стараюсь строить взаимодействие слоев через интерфейсы и люто протестую, когда вижу во время ревью, что кто-то делает инъекцию зависимости в переменную типа класса, а не интерфейса.
В нормальном коде должно быть удобно менять имплементации. Да в принципе не нужно вызывающему контекст знать детали реадизации.
Даеш видео о паттернах
во, какраз думал "когда же будет видео про D"))
И ЭТО ПО ПРЕЖНЕМУ СЕРГЕЙ НЕМЧИНСКИЙ, ИУУУУУУУУУ 😊
Компьютерная инженерия-это IT ? Если пойти в университет на такой факультет,можно ли потом пойти работать программистом ?
Всё от тебя зависит. Программисты по факту учатся сами, университет только даёт какую-то небольшую базу, плюс знакомства с товарищами по интересам.
А так да, специальность айтишная, идти можно -- главное не забывай учиться самостоятельно. Главная ошибка многих поступающих: думать, что университет тебя научит программировать. Не научит. Хотя на его лабораторках и курсовых можно практиковаться.
Программная инженерия, так часто называют. Как и написали выше, больше создадут среду, дадут пищу для размышления, какие-то основы основ. А хочешь программировать - всё сам. Хотя в ВШЭ, как понимаю, все условия, чтобы разработка занимала все курсы обучения.
Где же инверсия? Что инвертируют-то? И при чём тут интерфейсы? :)
Что значит замокать ?)))
Использовать фейковый объект вместо реального. Позволяет изолировать часть логики и/или подменить реализацию метода на более простую.
используется для тестирования или на время, пока сервис с которым ты должен интегрироваться, еще не написан другими разработчиками
Декомпозиция предметной области
плейлист про декомпозицию: ua-cam.com/play/PLmqFxxywkatSezlaoxwFbdBBnAk_JJ__5.html
Теперь у меня есть принципы, знаете-ли, и я себя не на помойке нашел
Ага, когда пишешь на Яве, когда производительность - это ниже твоего достоинства, когда это не говно-код, а ты так видишь... тогда таки да - всё виртуальное и везде интерфейсы.
Осталось только, чтоб авторы STL одумались и всё переписали на интерфейсах.
Можно пожалуйста книги для новичков про java на русском.
видео про книги для программиста: ua-cam.com/video/jOW7_Ie4g-w/v-deo.html
@@SergeyNemchinskiy благодарю.
Не ну прям на каждый класс - это хрень. На важные классы - да, надо.
Как определить, насколько класс важен?
И как определить эту грань, когда он уже недостаточно важен, для описания его интерфейса?
@@МаксимАлексеев-ч4й это предохраняет от тех случаев, когда класс используют в рандомных местах проекта, а потом его понадобилось изменить. Некоторые классы (почти) никогда не изменяются и используются в 1 месте. Если 3 мест и больше - точно надо, если проходит ось изменений - точно надо. Если есть бешеные джуно-индусы - точно надо. А ещё это касается только больших проектов, всяким сайтописателям хватает интерфейсов у фасадов модулей.
Добавляйте интерфейс если почувствовали, что он нужен. IDE это умеет делать. Если делаете библиотеку, то все что торчит из нее наружу должно иметь интерфейс. В коде сервиса такой необходимости нет. Это ваш код и не надо городить абстракции раньше времени.
GoF patterns, растолкуй, плиз
был же целый плейлист
Единственный минус DI - все превращается в магию, и потом хрен разберешься что откуда берется, и что как с чем связано
Как показала практика, "все классы через интерфейсы" это тоже бред. Нет смысла загонять все классы в интерфейсы! К примеру не стоит делать интерфейсы для моделей или скажет для тех же DTO. А тот кто это сделает или будет призывать к этому на мой взгляд так же является нехорошим программистом.
В интерфейсы стоит загонять сервисы, провайдеры, репозитории, обработчики.... То есть те классы, которые что-то делают с окружением, а все те классы, которые ничего не делают с окружением в интерфейсы нужно загонять крайне взвешенно, что бы не наплодил слишком много ненужных интерфейсов.
Название поправьте!
поправили, спасибо!
Что там по мок и стаб
Кратенько )
DRY тоже надо :)
Так есть же
@@SergeyNemchinskiy спасибо, нашёл)
Крч все видео в одном предложение: юзайте классы через интерфейсы.
на самом деле тут еще надо понимать, зачем ты это делаешь, это объясняется в видео :) если просто услышать эту фразу и начать применять то можно еще большего говна поесть. Так и под дтошки интерфейсы можна начать пилить
@@ИльяЛюбашов интерфейсы под дто-шки!? это жестко))) хотя иногда встречается в том или ином виде
Базовые определения не для понимания, а для галочки такое ощущение!
Вот здесь крутое объяснение этого принципа:
ua-cam.com/video/Uq10IqZhf7U/v-deo.htmlsi=yITNxUdvpP1f4fhb
Дуже цікавить просто і доступно про AOP. Для чого воно, які задачі вирішує, основні принципи.
в названии - DIP, в превью - SRP
Это дизайнер опять ошиблась 😉
испорчу картину лайков, поставлю 334-ый :D
Вы хотите общаться с девушкой. Девушка, это интерфейс, а блондинка, брюнетка конкретные реализации. Вот вам старший брат говорит, что вам нужно общаться только с девушками одного цвета волос. Дело к свадьбе и она перекрасилась!
DRY KISS