💪Новый поток advanced тренинга Enterprise patterns стартует 2.12. Получите скидку -15% для ранних пташек только до 15.11 - go.foxminded.ua/4eXh83k
@-ebaka4 жыл бұрын
Роберт что-то непонятное сказал, то ли дело Барбара
@65983354 жыл бұрын
XDXDXD
@СергО-л6ф3 жыл бұрын
Математически чёткое описание всегда более точное, чем словесное описание. Например, Правила Ассоциативноти и Дистрибутивности и звучат лучше...
@alokym86 Жыл бұрын
Я знаю чому для Вас формулювання Барбари Лісков складне і заплутане! Все тому, що для Вас і квадрат - це не прямокутник!) Дякую за відео. Приклад з квадратом підірвав мій мозок.
@vadimsokhatsky2748 Жыл бұрын
Сергей, спасибо! С вашими видео обучение программированию становится сплошным кайфом!
@romansharpe11314 жыл бұрын
Есть 2 класса Pistol и Rifle. Оба должны стрелять и перезаряжаться, значит выносим эту логику в класс Weapon и наследуемся от него. Появлятся новое оружие Knife, которое тоже атакует (стреляет) и также наследуется от Weapon. Теперь нож и стреляет, и перезаряжается. Реализуем LSP: между классами Weapon -> Pistol/Rifle делаем прослойку Gun и выносим туда логику перезарядки, а в Weapon оставляем только атаку/стрельбу. В итоге получаем: Weapon -> Gun -> Pistol/Rifle и Weapon -> Knife
@JackFastGame4 жыл бұрын
Что делать, если к такому пришли только после написания кода? Например, нужно было сделать пистолет и ружьё, написали классы: Weapon -> Pistol, Weapon -> Rifle, а потом заказчик добавил в ТЗ нож. Что теперь делать?
@romansharpe11314 жыл бұрын
@@JackFastGame по нормальному неплохо было бы продумать все это заранее. Здесь же я привел свой пример, как выглядит LSP на практике.
@0imax4 жыл бұрын
@@JackFastGame Если код был написан правильно, то другие классы обращались к оружию через интерфейс Weapon и знать не знали, что там внутри. Тогда, если расширить структуру наследования от Weapon, как в комментарии выше, для внешнего кода работа этого класса не изменится.
@stakhovskiy4 жыл бұрын
Август месяц на дворе, а его все еще зовут Сергей Немчинский. Хосспаде! Спасибо за видео 😄Лайк.
@z1zzz4 жыл бұрын
А в чём прикол?
@igorost7953 жыл бұрын
Попрошу! Сергей "тутромбик" Немчинский!
@BukasovMaxim4 жыл бұрын
Я бы еще добавил, что при оверрайде неабстрактных методов, новый метод должен уметь принимать параметры в таком же диапазоне или шире (но ни в коем случае не уже), а при возвращении значений - в таком же диапазоне или уже (но ни в коем случае не шире). Например в каком-то классе есть метод, который умеет принимать число от 1 до 100 и возвращать от 1 до 10. Если его заоверрайдить так, что новый будет уметь принимать 0..200, а возвращать 3..5 - существующий клиентский код будет доволен. А вот если переписать так, что новый метод умеет принимать только 1..50 или вдруг возвращает 0..20 - то существующий клиентский код может быть неприятно удивлён. Также можно было бы еще сказать, что список выбрасываемых исключений можно сокращать, а исключения - конкретизировать, а вот наоборот - добавлять новые или расширять существующие - нельзя. Но с контролируемыми исключениями компилятор Джавы в этом плане сам подскажет, что можно, а что нет, а неконтролируемые... на то они и неконтролируемые :)
@vladzaiko50123 жыл бұрын
что то я не уверен что вы правильно написалали, если базовый класс возвращал от 1 до 10, а наследник будет возвращать от 3 до 5 а это ведь нарушение принципов о которых говорит Сергей - наследник не может возвращать меньше чем базовый класс. Базовый класс будет ожидать что при определенных параметрах вернется 10, а наследник вернет максимум 5 и все сломается.
@BukasovMaxim3 жыл бұрын
@@vladzaiko5012 Представьте, что есть клиентский код, который умеет разговаривать на английском, французском и немецком. Есть базовый компонент, который иногда выдаёт клиенту что-то на английском, а иногда - на немецком. Клиент понимает эти сообщения от компонента. Если заменим этот компонент на новый, который будет выдавать сообщения только на английском (т.е. сузим диапазон возвращаемых значений), то клиентский код всё еще будет понимать эти сообщения. А вот если новый компонент вдруг заговорит на японском (т.е. расширим диапазон возвращаемых значений), то клиентский код сломается - потому что клиентский код не знает, что делать с сообщениями на японском.
@vladzaiko50123 жыл бұрын
@@BukasovMaxim так в том то и дело что клиентский код, который работает с базовым классом он не знает о функционале на японском языке, который уже появился в наследниках, он не может его вызвать и сломаться.
@BukasovMaxim3 жыл бұрын
@@vladzaiko5012 Речь не о новых методах. Речь о старых методах, которые в новых компонентах вдруг начали выдавать на выход то, что старые компоненты не выдавали. Пример: батарейка (как компонент). Допустим у нас есть электрическая схема (клиент), которой нужно питание +5В +/-10% (т.е. от 4.5 до 5.5 - будет работать). Если у нас есть батарейка, которая выдаёт +5В +/- 5% (т.е. от 4.75 до 5.25), то все ОК, схема будет работать и не сгорит (потому что при замене компонентов выходные диапазоны можно сужать без проблем). Но если мы вставим батарейку +5В +/-20%, то она может дать или слишком мало (и схема не заработает) или слишком много (и схема сгорит). Поэтому, при подмене компонентов, расширять возвращаемый диапазон - нельзя (можно только сужать). Входной диапазон - наоборот: сужать нельзя (чтобы клиент не послал в компонент что-то такое, что он не поймёт), а расширять - можно (чтобы компонент был не глупее, чем его предок).
@catmother83683 жыл бұрын
@@BukasovMaxim спасибо за отличное объяснение! А что, если у нас есть класс User и класс Admin, который является наследником от User? Допустим, в User есть метод, вохвращающий все права пользователей. User будет возвращать стандартные разрешения типа редактировать аккаунт и проч. Но у Admin нужно будет расширять этот список. Верно ли я понимаю, что в данном случае произойдёт нарушение принципа LSP? Как этого избежать? Не лучше ли выделить отдельный класс с правами, чтобы не нарушать SRP?
@LeoMrakobes4 жыл бұрын
@Sergey Nemchinskiy уже раньше обещал про "почему нельзя возвращать null"
@БендерЗадунайский-щ9ы4 жыл бұрын
надо! про тест фёст надо про нуль из методов и ДОСКУ МАРКЕРНУЮ! НАДО!
@Asmaers4 жыл бұрын
и про красную футболку!
@VitaliyZlobin4 жыл бұрын
доску особенно, уши режет
@kspshnik3 жыл бұрын
дададад! и про TDD и про null надонадонадо!
@КазимБерловский3 жыл бұрын
Доска как раз под бумагой. Приглядись)
@whoiam63953 жыл бұрын
Спасибо огромное!!! В 3х словах рассказал то что я не смог понять ни в одном видео до этого.
@whoiam63953 жыл бұрын
А я их пересмотрел штук 10
@TheHosuwisp4 жыл бұрын
Математический вариант Барбары все разложил по полочкам, а то так много воды и ничего не понятно.
@SergeyNemchinskiy4 жыл бұрын
ахаха. Ну, рад за вас :)
@ffconsole34674 жыл бұрын
Попався, математiк
@fakerliar65994 жыл бұрын
Тоже объяснение Барбары показалось более простым и понятным, хотя не математик. Может это потому что я женщина?:D
@murationametisation43473 жыл бұрын
Чувак, и мне показалось вариант Барбары намного ясный и простой. Но задело то, что автор видео так обобщает, "всем непонятно". Бро, как раз таки и понятно. Это может для гуманитариев проблема понять из-за боязни математики.
@lindx25333 жыл бұрын
странно что ты за этим вариантом полез на ютьюб к немчинскому
@masterbedroom5943 жыл бұрын
Сергей, выражаю вам искреннюю благодарность
@АлексейПоляков-ш1э4 жыл бұрын
TDD - ДА! Про return null - ДА! Спасибо за видео!
@protchenko.oleksandr2 жыл бұрын
Або це просто вже 100те відео про Лісков і я нарешті зрозумів, або це найкраще з тих відео що я бачив і я зрозумів =))
@SergeyNemchinskiy2 жыл бұрын
я просто умею объяснять :)
@bumer77214 жыл бұрын
Об ACID интересно послушать. А за SOLID благодарю)
@maxlich91394 жыл бұрын
было, Владимир Кузнецов рассказывал.
@bumer77214 жыл бұрын
@@maxlich9139 Дякую! Шукатиму.
@UnrealSPh4 жыл бұрын
Возможно, описание самой Барбары станет более понятным, если понимать когда она его предложила и как выглядели ассоциации типов в ЯП в то время, так как *спойлер* наследование не единственный способ ассоциации классов, а скорее частный случай. Насчёт использования наследования вы скорее всего заблуждаетесь, но причина заблуждения это легаси информация, которую из года в год перевыпускают в требованиях к коду. Если вы боретесь с копипастингом кода в проекте, то для этого больше подходит композиция кода. А если и методология разработки у вас не waterfall, то n-ступенчатая иерархия наследования превратит процесс изменения кода в ад (не забываем, что классы содержат ещё и стейты). Наследование сильный инструмент, но его главное назначение в продуктах, которые должны иметь жёсткую структуру иерархии, а так же максимально долгое время жизни самой иерархии. Напрмер фреймворки. Там наследование чувствует себя хорошо.
@samuro2ua4 жыл бұрын
Сергей, тема разработки через тестирование очень интересна! Как и SOLID. Спасибо.
@Snake19S4 жыл бұрын
Сергей, вы такой живчик в этом видео. Отлично получилось!
@YuretsUA3 жыл бұрын
Очень доступное объяснение, особенно в разрезе примеров. Сразу вспомнил где я уже наговнокодил...
@РостикНазаренко-п8с2 жыл бұрын
Дуже вам дякую за пояснення. Все просто і зрозуміло )
@НиколайЮрченко-о2й4 жыл бұрын
Классное видео, спасибо за детальное и простое объяснение, хотелось бы еще послушать про паттерн pipeline.
@xdef424 жыл бұрын
Я не использую наследование, я имплементирую интерфейсы, и занимаюсь агрегацией и композицией
@nanvlad4 жыл бұрын
Ты сраный рукожоп по версии Немчинского)) Я тоже агрегирую и композирую с интерфейсами + ещё дженерики
@alexeydeyev49704 жыл бұрын
Имплементирование можно с натяжкой отнести к наследованию.
@grommaks4 жыл бұрын
аналогично
@makaroningable4 жыл бұрын
Я наследую только абстрактные классы где имплементирую основное поведение, частично переопределяемое в классах наследниках. Но вот так чтоб в чистом виде унаследоваться от другого конкретного класса - такого тоже нет.
@woodzimierz96214 жыл бұрын
@@makaroningable есть товарищи, которые отрицают любую форму наследования
@Chat-Mayevskogo3 жыл бұрын
Я себе тоже такую футболочку взял, тока черную, чтоб прям в тему последних времен было) Это когда джаву в js тоже будут компилить, наверное)
@NikolayMishin3 жыл бұрын
Самый сложный принцип, я вечно сыплюсь на нем))) но объяснение с прямоугольником и квадратом просто огонь! Спасибо 🙏
@yuriytheone Жыл бұрын
Ты сыпишься, потому что Solid ложны. Каждый принцип ложен! Давай про Srp. Когда ты создаёшь дочерний класс, ты его создаёшь именно таким, какой нужен именно в твоём коде. И именно с таким интерфейсом, который нужен твоему софту. Далее Ocp - ты не только можешь менять код метода, но и должен если это нужно для оптимизации. Да, представь себе Ocp тоже ложен. Далее Lsp - зачем тебе порождать наследников и закидывать в какой либо метод работающий с классом родителем. Ну, вот ты и не можешь объяснить... У немчи6ского яйц нет признать, Solid - фуфло.
@andrew_golubev4 жыл бұрын
Качество стало на порядок лучше, так держать!
@Madeniath4 жыл бұрын
Про TDD интересно было бы посмотреть.
@Oleksii_Leshchenko4 жыл бұрын
про то, как оно в жизни
@Zlobusz4 жыл бұрын
Программирую на php в Symfony. На самом деле крайне редко приходится использовать наследование. Чаще фреймворк предоставляют интерфейсы, чем абстрактные классы. А наследоваться от какой-то конкретной реализации - тоже не совсем приятно. Поэтому случаев наследования можно по пальцам одной руки пересчить. Но принцип постановки Лисковой зашёл. Спасибо! Теперь бы про инверсию зависимости послушать)
@alexeyb58302 жыл бұрын
потому, что ооп это не про наследование. В чистой архитектуре про это написано. Ооп это про полиморфизм. Старину Боба видимо не всего Немчинский читал, либо читал и не понял.
@nataliia93464 жыл бұрын
Хотелось бы с таким классным объяснением и примерами послушать о Паттернах Программирования :)
@SergeyNemchinskiy4 жыл бұрын
эм.... Ну вот же оно: foxminded.com.ua/grasp-gof-design-patterns-advanced-on-line-course/
@kyryloshamraiev62892 жыл бұрын
Очень наглядное объяснение. Проще говоря, нужно наследовать большее от меньшего, а не наоборот. Все станет на свои места, если считать, что квадрат - это частный случай прямоугольника, а не его наследник. Именно такой подход применят учёные. Потому обьяснение Барбары и не понятно программистам с ООП профдеформацией. :)
@RomanL32111 ай бұрын
ООП профдеформация это интересно))) всё под неё пытаются подтянуть, иногда усложняя код до нельзя...
@vladyarets35962 жыл бұрын
1:16 ну нафиг)) Как это прочитать получилось?!) 1:50 а не. вот тут нафиг, дяде Бобу спасибо огромнейшее!
@ntvisigoth4 жыл бұрын
@Sergey Nemchinskiy: Мужик, здоровья тебе! Отличное пояснение! ;)
@eligolin9947 Жыл бұрын
По моей оценке вся суть проблемы была не раскрыта. Наследование как "анти паттерн", основана на сложности соблюдение LSP принципа. Пройдёмся по примерам в этом ролике: 1. Здесь Сергей рассказывает как плохо нарушать LSP принцип и к чему это может привести. Но дело не в том что его нельзя явно нарушать (это и так понятно), а в том что его очень сложно соблюдать. 2. Сергей здесь спасибо вам за альтернативное определение LSP (оно добавляет глубины понимания!) хотя по моей оценке примеры всё равно слабы. 3. По моей оценке этот пример вообще не об этом. Здесь проблема не в соблюдении или несоблюдении LSP, а в отсутствии инкапсуляции. Это был хороший пример того что лучше писать иммутабильные классы а setters/getters могут раскрыть зачастую внутреннюю структуру класса. С точки зрения наследования - это как раз один из немногих примеров где наследование является корректным. Наследования квадрата от прямоугольника является математически правильным и хорошо обоснованным с точки зрения качеств квадрата по отношению к качествам прямоугольника.Если бы состояние этих классов задавалось только при помощи конструктора, то никакой проблемы не было бы.
@andrey78299 ай бұрын
Очень понятно объясняете - супер, спасибо
@newprim13 жыл бұрын
Это самое лучшее объяснение принципа Лисков, что я встречал! Подписка однозначно
@AnnaIsHere4 жыл бұрын
Хотелось бы больший упор на "как надо" вместо "как не надо"
@Gusto200003 жыл бұрын
Просто берете как не надо и делаете не так и будет как надо
@fractalzombie3 жыл бұрын
С опытом придёт.
@АнтонДудкевич3 жыл бұрын
@@Gusto20000 и если это приходится объяснять, то, наверное, лучше никак не надо ;)
@screamer89322 жыл бұрын
@@Gusto20000 Часто бывает 101 способ как не надо и только парочку как надо. Кск би так убегая от плохого 98 способа не попасть в 86))
@НиколайКоваленко-г2к5 ай бұрын
что касаемо lsp то что бы его не нарушать нужно просто придерживаться ооп. Надо постараться что бы его нарушить.
@ПашаХЗ-м8й4 жыл бұрын
Давно ждал!
@sergekim4 жыл бұрын
Спасибо большое, Сергей!)
@topalidinka3 жыл бұрын
Я вас обожаю. Вы один из самых интересных и умных людей, которых я знаю) спасибо за знания и ваш юмор ☺️
@VoroninPavel4 жыл бұрын
Хе-хе, люблю этот пример с квадратом и прямоугольником. Только он еще веселее. Если ввести иммутабельность с втиле старого доброго ФП и после вызова любого "мутирующего" метода возвращать экземпляро нового объекта, то квадрат-таки можно сделать проямоугольником, не нарушая принципы ООП ;-)
@kosatchev4 жыл бұрын
Принцип на примере семьи Хилтон: class Hilton { Money manageHotel(Hotel h) { Money m = makeCustomersHappy(c); return m; } } class Paris extends Hilton { @Override Money manageHotel(Hotel h){ Money m = sellHotel(h); return m; } }
@torrvic11562 жыл бұрын
Отличная шутка про ведение бизнеса 😂
@TheDaslord4 жыл бұрын
Сергей, спасибо за видео! Пожалуйста, снимите видео про возврат null, очень интересно, сам постоянно так делаю.
@torrvic11562 жыл бұрын
Я просто офигеваю от того, какой Сергей потрясающий интеллектуал. Мне страшно смотреть его видео. Страшно от того, что голова может лопнуть от обилия деталей, но потом трясущейся рукой тянусь и нажимаю кнопку начала просмотра, а потом инфа кое-как укладывается под отличную и ровную мелодию под методичный голос Сергея… P.S. короче, как тупой я понял принцип LSP главным образом в том, что не должен наследуемый класс делать больше, чем его основной класс.
@homo-ergaster4 жыл бұрын
Вот что интересно, базовые классы Java нарушают LSP совершенно без стеснения. Попробуйте, например, сделать так: Map map = Map.of("a", 10, "b", 20); map.put("c", 30); и охренейте от того, что вам прилетит Exception в Runtime. При том что вся эта лабуда прекрасно скомпилируется. Когда-то налип с этим делом по незнанию, пришлось в довольно большом пакете искать где я делал Map.of и переделывать на new HashMap.
@kotanhp31152 жыл бұрын
Хорошее видео, жду такое же про Оксимирона
@ВадимКорженко-э8б4 жыл бұрын
TDD интересно. С удовольствием послушаю.
@ArtemGaleev-w4t4 жыл бұрын
Раз уж вы сказали про наследование и попросили предложить что после СОЛИД рассказать, то предлагаю достаточно холиварную тему: наследование vs композиция. Заранее прошу прощения если вы эту тему уже поднимали
@SergeyNemchinskiy4 жыл бұрын
расскажу. Регулярно поднимаю эту тему на тренингах, надо и в отдельном видео рассказать
@victortamanov4 жыл бұрын
Про TDD интересно будет посмотреть.
@sick_bear2 жыл бұрын
Наконец-то я понял этот принцип)
@igor_knv4 жыл бұрын
Понравился пример про квадрат и прямоугольник. Кто-кого расширяет.
@alexeydeyev49704 жыл бұрын
Очень интересно про Test First!!! В топ!!
@samirsalimkhanov35544 жыл бұрын
Надо убрать бумагу между маркером и доской, потом писать. Я так думаю))) спаисбо за видос
@YuretsUA3 жыл бұрын
Это нарушает 1-й принцип SLP, каждому объекту своя зона ответственности, доска для того, чтобы бумагу удерживать, и бумага не рвалась под фломастером. А бумага уже для отображения текстовой информации, так что тут все грамотно...
@yuriyfedoryshyn52064 жыл бұрын
looking forward to a TDD video))
@maxlich91394 жыл бұрын
Клевое видео. Единственное что Сергей не рассказал: что тогда делать-то, если твоя реализация не поддерживает данный метод базового класса? Я такое видел и не только в тестах и моках (и там да, бросались эксепшены; и вроде бы это даже было в каких-то известных либах)
@alexanderlex-s9334 жыл бұрын
Изучаю Java с нуля. Даром прошли 5 лет в 1С, ООП - это взрыв мозга )))) 11:20 - я не могу использовать ООП в 1С, там только процедурный код - и да, я чувствую себя рукожопом, но за хорошую зарплату.
@Ardolynk Жыл бұрын
Разве mock не должен лежать в модуле test, недосягаемом для основного кода?
@woodzimierz96214 жыл бұрын
Про TDD очень интересно.
@wandos7772 жыл бұрын
Супер, Сергей) Спасибо большое за видео, однозначно лайк!)
@dmitrinikolaev69864 жыл бұрын
Про TDD было бы очень интересно послушать!
@Дмитрий-х2й5р4 жыл бұрын
Спасибо. Только с квадратом как быть? Разве при наследовании у него не разумно переопределить метод подсчета площади?
@danilakapitanov70443 жыл бұрын
Проблема не столько с определением площади, сколько с установкой сторон в клиентском коде. Правильным решением является создание абстрактного класса Figure с методом вычисления площади, от которого наследуется отдельно Rect и отдельно Square и реализуют метод вычисления площади. При этом для клиентского кода логика работы по установке сторон Rect и Square становится разная. Т.е. прямоугольник и квадрат по сути это разные сущности, как ,например, прямоугольник и круг.
@alexanderbelov68923 жыл бұрын
@@danilakapitanov7044 Раз уж речь про клиентский код работы с фигурами, то характеристики фигур должны прописываться при создании, и отсутствовать методы их изменения, которые будут разными для разных фигур. К примеру для фигур могут быть методы get_square() для площади, и scale() для изменения размера. Но никак не изменения характеристик описывающих фигуру по отдельности. Для изменения фигуры с другими сторонами нужно создать новую фигуру, а предыдущую удалить.
@dmitriimolchanov49713 жыл бұрын
На примере mock, можно ведь для неиспользуемых методов оставить имплементацию парент класса, если это, конечно, не абстрактый класс или мы не имплеменим интерфейс. Хотя тут уже тогда нарушение как раз второго принципа-необходимо использовать интерфейс, или я что-то упустил?)
@zapplay4 жыл бұрын
Хотелось бы увидеть видео о том почему нельзя возвращать null
@alexeiceglei98414 жыл бұрын
Юнит тесты интересны очень, особенно какие то хитрости, типо того же test first
@vanilla10064 жыл бұрын
TDD, буду рад выслушать
@СергейКарпиченко-с6б4 жыл бұрын
Спасибо большое за видео!
@demidovmaxim10084 жыл бұрын
Большое спасибо за выпуск!!!
@АнтонДудкевич3 жыл бұрын
Я вот чет не понял, что плохого в примере с квадратом ) Ну, перезаписал он сторону с 10 на 5, ну, посчитал он площадь 25. Так она такая и есть в его случае ) Одинаковый интерфейс родителя и наследника никак не означает одинакового результата. Если он одинаковый всегда, - нахрена наследовали-то? )
@Hellsome_Rider4 жыл бұрын
Это вообще из другой оперы, но я бы послушал про DDD domain driven design, что такое bounded context и как его правильно определять
@eligolin9947 Жыл бұрын
Я постараюсь привести пример проблематики соблюдения LSP принципа. Допустим у вас есть класс Human. У этого класса есть такие поля как; пол, возраст, рост, вес и тд.. Теперь представим что у нас есть класс Student. В этом классе добавляется название колледжа, номер курса, и специальность. Согласитесь что наследование студента от человека выглядит довольно безобидным и естественным. Ещё представим что в текущей версии кода есть метода которая вычисляет налог "социального страхования" для любого человека, и основана она только на возрасте человека. Понятно что в текущей версии кода, LSP принцип соблюдается для этой методы. А теперь представим что в будущем закон изменился и теперь студенты освобождены от оплаты налогов. С этого момента LSP принцип нарушен. проблема здесь на самом деле глубокая и заключается она в том что если B наследует от A, то требуется доказать математически что B является A. Дело в том что наследование Student от Human основывается на нашем естественном восприятии но в то же время плохо определено в математическом смысле. Вся сложность LSP является в том что наследование должно быть корректно не только в текущей версии кода, но и во всех (неизвестно на сегодня) будущих его версиях. Когда домейн классов находится в математической плоскости нам легче создать корректное наследование, но к сожалению это лишь малая часть всех проблем которыми мы занимаемся. Отсюда вытекает общий антипаттерн наследования.
@ОлегПаламарчук-р5к Жыл бұрын
Цілком погоджуюсь.
@tislambek4 жыл бұрын
Можете расказать в следующем видео о проекты спринга
@antonkuranov4 жыл бұрын
Принцип подстановки безусловно правильный, но реально работает лишь в отдельных ограниченных случаях. Начиная с определенного момента ваши абстракции начинают течь, и решить эту проблему становится гораздо сложнее, нежели если бы LSP вообще не использовался бы с самого начала: приходится расширять интерфейс и патчить все зависимости. Пример протекающей абстракции -- это любой интерфейс драйвера, который возвращает "driver capabilities".
@eb60064 жыл бұрын
Про TDD интересно, запишите пож-ста
@haqoncsgo53804 жыл бұрын
В целом, неплохо рассказано, конечно. Я бы добавил в формат реальный кейс с кодом, примеров нарушений принципа в системных библиотеках (в той же Java нарушения лисков достаточно). Ещё не затронута тема ковариантности и контравариантности. Иии что значит нельзя возвращать null из методов? Это абсолютно нормально и даже нужно. Естественно, с документацией. Или когда ваш язык поддерживает нормальные nullable типы - null как отдельный тип данных.
@SergeyNemchinskiy4 жыл бұрын
нельзя возвращать null, это очевидно
@haqoncsgo53804 жыл бұрын
@@SergeyNemchinskiy Если вы имеете ввиду принцип Лисков, то и тут не соглашусь, всё зависит от контракта, предоставляемым базовым типом, если там подразумевается null, то можно. А если вы имеете ввиду вообще, в целом, то и тут неясна ваша идея. В некоторых случаях, действительно, есть лучше способ показать отсутствие данных. Например, в .NET - try pattern, когда возвращаемое значение - bool, показывающее результат операции, а данные возвращаются через ссылку одним из аргументов. Также в .net ввели nullable reference types, с помощью которого явно видно, где тип может быть null, а где нет.
@0imax4 жыл бұрын
Я бы предпочёл получить из метода пустой список вместо null, прописанного где-нибудь в дебрях в документации.
@haqoncsgo53804 жыл бұрын
0imax Касаемо чего то перечисляемого, да, тут лучшим способом будет вернуть что то пустое, но существующее. И то стоит понимать, что могут быть моменты, когда нужно уметь различать отсутсвие самого списка и отсутствие в списке вообще кого то. Но обычные объекты, возвращаемые аля GetUserById, GetActualPlayerConnection и прочее - здесь лучшим способом заявить об отсутствии чего то только null, никаких throw
@0imax4 жыл бұрын
@@haqoncsgo5380 а по мне так лучше кинуть нормальный exception и обработать его, чем возвращать null: Во-первых, правильно названный exception сразу даёт информацию о причине "поломки". А во-вторых, таким образом можно обработать ситуацию, когда причин отсутствия объекта может быть несколько, как с тем же connection.
@dmitriykozyrev88354 жыл бұрын
Сразу лайк, спасибо тебе большое!
@РинатРаот4 жыл бұрын
Ах**нно) наконец то понял в чём фишка этого принципа
@artemboiarshinov4 жыл бұрын
Немного про моки, раз уж Сергей про них заговорил. Чтобы замокать только строго определенные методы стороннего компонента, вызывающегося в тестируемом коде, можно использовать библиотеки типа Mockito или PowerMock, вместо того чтобы самостоятельно писать mock-реализацию этого компонента. Это стандартное решение, все так делают. Есть еще идея Егора Бугаенко: для каждого компонента в его интерфейсе писать fake-реализацию этого интерфейса, которая будет использоваться в тестах всех зависимых компонентов. Это похоже на то, о чем говорит Сергей Немчинский, но ответственность за написания мока берет на себя не разработчик клиентского кода, а разработчик компонента. Соответственно разработчик компонента обязан реализовать все методы этой fake-реализации. Немного утопическая идея, но она решает проблему хрупкости, присущей тестам, написанным с помощью Mockito.
@SergeyNemchinskiy4 жыл бұрын
то, что Бугаенко не знает слова Stub и вместо этого придумывает свои термины - не удивлен
@artemboiarshinov4 жыл бұрын
@@SergeyNemchinskiy Его основная идея заключается в том, что эти заглушки должны быть написаны в java-файле предоставляемого интерфейса. Мол это позволит пользователям вашей библиотеки не писать заглушки самостоятельно, что уменьшит дублирование кода на планете)) А так мне и самому Егор Бугаенко не нравится, слишком уж он хайпожористый
@СанжарСовет-ъ5ц3 жыл бұрын
ну круто я понял как делать не надо ,а как делать надо сам разберусь спасибо лайк щищ
@denisbielishev4 жыл бұрын
Будет интересно услышать про GRASP и GoF
@1kit3 жыл бұрын
Подкупает именно искренность и человечность. "Я могу ошибаться и делаю это постоянно, и умею признавать". Я бы уже десять раз заново видео перезаписал и смонтировал так будто я ни разу не оговорился. У Сергея без монтажа одним куском всё идёт с первого дубля, прям как в жизни. Upd.: :-D интересно, а код он так же пишет? Тут херня получилась, ну не важно, оставляем так дальше поехали.
@edmond-dantes-17964 жыл бұрын
Всё видео ждал, когда покажете пример с прямоугольником и квадратом, уже думал, что не будет) В чем проблема не использовать наследование? Я, конечно, не эксперт, но знаю, что с ним регулярно возникают проблемы +оно статично и в многих случаях выгоднее использовать композицию и агрегацию. Можете рассказать в видео подробно об этом)
@SergeyNemchinskiy4 жыл бұрын
почему нельзя не использовать наследование? Запишу
@kirilleremeev97074 жыл бұрын
Ну так, а какое все таки решение в вопросе прямоугольник-квадрат? Все его приводят в пример, а решения ни кто не приводит! Получается два выбора: либо отказаться от наследования и следовать LSP... Но тогда будет нарушен другой же принцип - не дублируй код. Т.е. если у вас в базовом классе (например в прямоугольнике) двести методов и один из них не LSP, то что тогда?
@SergeyNemchinskiy4 жыл бұрын
наследовать прямоугольник от квадрата
@vanweyden4 жыл бұрын
Вообще квадрат не нужен)
@kirilleremeev97074 жыл бұрын
@@SergeyNemchinskiy Квадрат это частный случай от прямоугольника (по крайней мере я лучше выкину принципы solid чем так поступлю). И функции setWidth и setHight нужно будет переписывать для прямоугольника, что опять же нарушает - дочерний класс переопределяет функциональность базового. Теперь новый side эффект - я ожидаю что стороны равны для квадарта (базового класса), а для прямоугольника - не равны. Проблема с функцией площади теперь выливается аналогичную проблему с функцией с периметром...
@chocolazerboom73894 жыл бұрын
Чёт прямо больно, что такие листы бумаги тратятся на то, что можно нарисовать на доске и стереть
@ESTechnonet Жыл бұрын
А еще больно - звук маркера скрипучий.
@cicik57 Жыл бұрын
если вам не понятно то это не значит что "всем" не будет понятно. В формулировке Липскоу это свойство звучит абсолютно точно и должно быть понятно любому програмисту, в отличии от огульной словестной интерпретации мартина
@OlezhikChanal4 жыл бұрын
Раз пошла такая пьянка. Серию про паттерны жду. Буду смотреть и советовать всем.
@SergeyNemchinskiy4 жыл бұрын
Ну про паттерны я уже снял. Вот она foxminded.com.ua/grasp-gof-design-patterns-advanced-on-line-course/
@jossefal19574 жыл бұрын
Хорошее объяснение, как обычно лайк
@dmytromarchuk30234 жыл бұрын
Ставлю лайк відразу! "Виріс" на відосах Сергія про Design Patterns, Clean Code, etc
@undefined-n5v4 жыл бұрын
Сложно представить сценарий, когда при наследовании захочется переопределить какой-то метод базового класса чтобы он кидал NotIImplementedException, у кого был грешок, расскажите, что вас к этому привело?
@screamer89322 жыл бұрын
Насколько я понял из поиска по гуглу. Тут весь пример завязан на Mock об'екте который по определению является пустышкой с методами заглушками. И если оставлять родительськую реализацию то нарушается смысл. Это как я понял. Если кто поправит буду рад
@AndriySydorka4 жыл бұрын
Дядя Сережа, росскажи про Test first!
@halgerdka92874 жыл бұрын
про пример с квадратом. что мешает переопределить только метод getSquare() return a*a ? и вообще не трогать b
@makskors50023 жыл бұрын
TDD очень интересно!
@user-hv8rh8nk9d4 жыл бұрын
Отлично. Про тесты видео нужно
@Telemahk3 жыл бұрын
По итогу - надо квадрат наследовать от прямоугольника или правильнее новый класс делать?
@sfoxer3 жыл бұрын
Лучший препод =) Что бы мы без вас делали)
@wcode4044 жыл бұрын
Квадрат выглядит как частный случай прямоугольника, так же как квадрат частный случай ромба или прямоугольник частный случай параллелограмма. На самом деле это всё фигуры и на одна из них не является дочерней по отношению к другой. Я писал об этом здесь: github.com/peter-gribanov/clean-code-php
@FrolovDaniil4 жыл бұрын
Можно ещё про DRY, KISS, YAGNI
@SergeyNemchinskiy4 жыл бұрын
уже в планах
@FrolovDaniil4 жыл бұрын
@@SergeyNemchinskiy Смотрю Вас из интереса уже наверное больше года, когда ещё начинал знакомиться с Java, сейчас вообще Python разработчик. Так вот качество видосов стало на порядок выше, видно, что развиваетесь. Так держать! Пожалуйста, подумайте по поводу маркерной доски, а то эти шуршания маркера по бумаге некоторых приводят в ужас (меня например).
@AAAnatoly4 жыл бұрын
Юнит-тесты очень интересны. По сути, я самоучка, и до юнит-тестов не дошёл, а начинать страшно
@YoungT184 жыл бұрын
Такая же ситуация, но успокаиваю себя тем что джуну вроде как не обязательно наличие в стеке этой технологии и в будущем я смогу уже на реальном проекте это изучить
@kisurov4 жыл бұрын
Ничего там нет страшного
@pgriggs12994 жыл бұрын
@@YoungT18 Mockito и JUnit обязательно нужно знать джуну, также будет в разы круче, если код, например, в пет-проектах будет протестирован, потому что не протестированный код = нерабочий код
@r2d29254 жыл бұрын
Что сложного, вызвал метод, передал тестов данные, и сравнял с заранее верным ответом. Это примитив, но смысл таков. Модульные тесты сложнее, но тоже эмалируешь роботу кода и сравниваешь с подготовленным ответом.
@John_602nd4 жыл бұрын
Ничего страшного совершенно, с ними другая проблема, что их ленятся писать. В Java все юнит тесты: @Before, @Test, assert(Equals/That/...) Если прочитать как это работает, то... Это в целом всё. А прочитать можно в первой же статье в гугле по запросу "Java UnitTest"
@Mr430467214 жыл бұрын
Про ТДД можно видео)) и про другие драйвен девелопмент
@МаринаГаркуша-у2р4 жыл бұрын
Можно видео про TDD, и про кидание нулей в методах, плис))
@dmitry_shelemekh4 жыл бұрын
Крутотенюшка!
@ivanoviv18449 ай бұрын
Ну как тут не подписаться ну никак и лайк поствлю и все что угодно
@НикитаГлухов-п5ю4 жыл бұрын
Про наследование в конце дичь. Это прямой способ насрать себе в руки, создав сильнейшую связь между 2 классами. Проблему хрупкого базового класса никто не отменял. Composition over inheritance годами проверенный принцип, приведший к тому, что в языках последнего десятилетия (Golang) наследование выкидывают нафиг как концепцию. Как бы для эффективного переиспользования кода и достижения гибкости, достаточно интерфейсов (декларирующих контракт) и делегирования. Об этом в Effective Java Джошуа Блох пишет почти в самом начале.