Pull to refresh
15
0.1
Денис Щетинин @chaetal

Пользователь

Send message

Правильно. Теперь откройте текст статьи и прочитайте, что там написано по поводу DRY.

Теперь откройте мой комментарий и прочитайте, что там написано. Соотнесите. Подумайте. Попробуйте понять. Я ещё долго могу продолжать, но, может, всё-таки откажемся от императивного стиля? ;)

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

Неправильно. Теперь откройте текст статьи и комментариев и прочитайте, что там написано.

Именно об этом сказали автор статьи, автор начального комментария, и я. Поэтому я не понимаю, с чем вы спорите.

У вас наблюдается удивительная "сверх"-способность видеть и понимать то, что не было написано, и не понимать то, что написано :)

Без особой надежды на понимание постараюсь еще раз — максимально просто и кратко…

========================= Начало пояснения

В статье предлагается следующая логика (это не цитата, просто других способов выделить текст не нахожу):

У меня не получается применять принцип DRY, следовательно он плохой. Его использовать не надо, это даже почти грехом объявляется :) И предлагается заменить на PRY.

Это на столько дико, что спорить с этим я вообще не вижу смысла. От короткого комментария по этому поводу не удержался, но на этом всё.

А вот с комментарием, на который я ответил, я вообще не спорил. Где вы это вообще обнаружили? …А, ну да — сверх-способности же ;) Простите.

Я всего лишь попросил пример, когда появившиеся в результате адекватного применения DRY …

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

В ответ на это вы привели абсолютно неадекватные примеры, на что я вам и указал. И тут понеслось… :D

Адекватным примером был бы:

  • Кусок функциональности, к которому имеет смысл применить DRY

  • Результат этого рефакторинга — "невинная абстракция"

  • Какой из этого в итоге получился монстр, и его связь с предыдущим рефакторингом

========================= Конец пояснения

А с чем я действительно готов спорить по поводу DRY, я подробно объяснил ранее. Но вы это проигнорировали, как это модно было говорить, "чуть более, чем полностью".

Вот в том и смысл этого примера, что можно. В них содержится столько информации, сколько есть на старте проекта.

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

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

Да, согласен. Занесло :) Но если вы так и не поняли, то этот момент у меня возражений как раз не вызывал.

Что еще раз говорит о том, что вы не следите за дискуссией и спорите о чем-то своем.

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

Нет, не должен.

Если вы не отвечаете нет, то это говорит о том, что ваши "примеры" неадекватны. Что я с самого начала до вас и пытался донести — об этом выше.

Остаётся только понять, вы эти привели по недоразумению или намеренно, для троллинга? Ну, чтобы завязать спор на пустом месте и всеми неправдами пытаться в нём победить. Ок, вы победили. На этом завершим? Я ниже только ещё отвечу на некоторые интересные моменты. Но можем считать, что на результат это не влияет — вы блистательно победили!

Это тоже говорит о том, что вы спорите о чем-то своем.

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

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

В моей системе на Smalltalk-е DTO скорее всего не было бы в принципе. Но если вам так хочется кода, пожалуйста:

EntityService >> createFrom: aDto
model = mapper createModelFrom: aDto.
entityManager save: model.
^ model

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

Вы предлагаете не добавлять новую функциональность, а не устранять дублирование — это рефакторинг, так как на существующую функциональность это действие как раз влиять не должно.

А делать это, точнее не делать, вы предлагаете из каких-то смутных фантазий о том, что когда-то в будущем это может привести к проблемам. Вот здесь и возникает You Are Not Gonna Need It — решать какие-то смутные будущие проблемы.

И ещё раз (вдруг всё-таки поймёте) обращу ваше внимание, что мой исходный вопрос как раз был про эти будущие проблемы.

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

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

Видимо кода будет еще больше. Это хорошо показывает цену вашего подхода и правильность утверждения про монстра.

И у вас опять наблюдаются проблемы с логикой Ну, с трактовкой-анализом имеющихся фактов и выводами из них.

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

Трудности перевода, понимаю. Но "архитектура" — один из худших вариантов, правда.

Хорошо, уговорили, потрачу ещё какую-то часть своего бесценного времени в надежде, что это кому-нибудь чем-нибудь поможет.

Это написано прямым текстом в первом комментария этой ветки

Читаем внимательно и не выдёргиваем из контекста. Комментарий начинается словами:

По поводу DRY.

Про что разговор? Про DRY!

Так что

Это еще одно подтверждение, что вы потеряли нить обсуждения.

— верно, но только относительно вас. Ну, почти верно — так как вы нить обсуждения, похоже, и не находили. Без обид, по факту.

Именно поэтому я привел примеры, где избавляться от "дублирования" кусков кода не надо.

(…)

Покажите вашу версию этого кода с избавлением от дублирования,

Относительно первого куска — в целом согласен, избавлять от дублирования там не нужно. Просто потому, что там там нет того дублирования, которое вызывает проблемы и к которому следует применять принцип DRY.

То есть, не потому, что вы нашли хороший пример, представляющий код, к которому не нужно применять принцип DRY. А потому что пример неудачный — он иллюстарирует ситуацию, не попадающую под этот принцип. Повторяющаяся последовательность символов в вашем коде — это ещё не дублирование (не то дублирование, про которое идёт речь в DRY.

Точнее, дублирование в вашем примере скорее всего его нет. Просто по приведённому фрагменту об этом невозможно судить. Это ещё раз показывает, что данный пример неудачен.

Чтобы точно судить, есть ли дублирование в той системе, надо смотреть контекст: как используются, как работают и на сколько связаны между собой Категория и Продукт. И, если дублирование всё же обнаружится, то способ избавления от него всё равно должен будет подбираться по тому же контексту… 

…Но если я начну углубляться в эту тему, придётся говорить о плохих формулировках принципа DRY (например, о каких "повторениях информации различного рода" идёт речь и до каких приделов предлагается это повторение "снижать" в статье на Wikipeda?), проводить исследования о реальных истоках и основаниях этого принципа, о диффузии и инверсии смысла… — это очень долго и в данном контексте не имеет большого смысла.

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

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

Если у вас таких объектов не много (например, как в вашем примере, ровно два), то я бы так делать не стал, а записал бы в "тех.долг".

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

Для этого я бы создал объект, который знает, как создать и сохранить правильный объект из DTО. И, кстати, это была бы единственная функциональность этого объекта — гарантия, что он не разрастётся до пресловутого "монстра".

Разумеется, я бы не стал создавать базовый класс для упомянутых в вашем сервисов и выносить эту функциональность туда. Как именно такой объект был бы реализовано зависит от используемого языка и его объектной модели. В Java с её якобы "строгой типизацией" пришлось бы подумать и поизвращаться (и это ещё один аргумент отложить избавление от такого дублирования до того момента, когда связанные с ним неудобства начнут перевешивать расходы на избавление от него …но, обращу внимение, отложить, а не вообще забить на это дублирование, или, тем более, утверждать, что это нормально и даже хорошо). А, например, в Smalltalk-е и Ruby (по второму не уверен, это, скорее, гипотеза) всё было просто и органично. Как это сделать в PHP (вы же на нём свои примеры привели?) — без понятия, никогда не имел с ним дела.

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

Я не знаю, зачем вы начали спорить.

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

DRY предлагает некоторый критерий для обнаружение "плохого" кода. Но вообще, формулировки этого принципе мне не нравятся — они переусложнены, запутывают и скрывают настоящий смысл. Но, как я уже сказал, это отдельная большая тема. Избавлять от разного рода "плохого" дублирования (в идеале — от любого) необходимо. Объяснить, как именно, находить дублирование и оценивать его — сложно. Но это не значит, что не нужно вообще. Просто понимание придёт с практикой.

(Раз уж упомянул и его тоже затронули.) YAGNI представляет собой гипотезу, что не надо пытаться предугадывать (фантазировать про) возможные будущие проблемы, а делать только то, что нужно здесь и сейчас.

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

Но понять и освоить нужно правильно. И исходное высказывание про DRY, и приведённые вами "примеры" является как раз иллюстрацией неправильного понимания идеи и, соответственно, неадекватной её критики.

Например, ваши примеры и высказывания говорят о том, что вы не очень хорошо понимаете, о каком дублировании идёт речь. Я вбросил словосочетание "кусок кода". Вы незамедлительно за него ухватились, ведь ваши примеры — это тоже куски кода. Но тогда тогда и любая буква где-то в коде — это тоже "кусок кода", не так ли? И, следуя DRY, нужно избавляться от всех повторов этой буквы? Судя по вашим примерам и высказываниям , вы должны ответить положительно. А по-моему — нет.

Основываясь на такой доведенной до абсурда трактовке DRY, можно сделать вывод, что это принцип вообще плохой. Где-то в комментариях уже предлагали заменить его на PRY. Но это лишь логическая ошибка. Либо намеренно используемый полимеческий манипулятивный приём.

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

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

DRY предлагает некую эвристику, помогающую определить, что, возможно, следует почистить зубы. А YAGNI говорит, что не стоит переживать, что из-за чистки зубов вы попадёте под автомобиль.

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

Разве это не очевидно? ;)

Перевод:

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

Оригинал:

The first misunderstanding is that folks seem to lump all design together.

Design — это не архитектура! Design — это дизайн! Можно перевести как "замысел", "конструкция". Даже "проект" уже не надо — будет путать читателя. Но переводя как "архитектура", вы радикально меняете смысл, так как термин "архитектура" всегда нес иную смысловую нагрузку, а сейчас, когда под "архитектурой" стало модно понимать вообще нечто чуть ли не ортогональное основной функциональности программной системы, и подавно.

Да, под дизайном в России чаще понимают всякие там "украшательства". Но даже "заимствовать" (хотя это никакое не заимствование) слово из совершенно другой области человеческой деятельности будет гораздо лучше, чем нагрузить другим смыслом уже занятый термин из той же области. То, что под словом "дизайн" в этой статье понимается совсем не цвет кнопочек и размер шрифта, будет очевидно из контекста. А вот то, что речь идёт про дизайн (конструкцию) программной системы, а не про её архитектуру — поди ещё догагдайся.

Не знаю, откуда пошла традиция переводить "design" как "архитектура" — от DDD Evans-а в редакции Бродового, или ещё раньше, но с этим надо как-то заканчивать.

Переводчики несут львиную долю ответственности за непонимание и неверную трактовку русскоязычным IT-сообществом многих понятий. Взять то же TDD — это не "Разработка через тестирование"! Тестирование — абсолютно отдельный вид деятельности, принципиально отличающий от разработки. Там просто напросто цели другие. Написание автоматического теста — ещё не тестирование. Зато у нас с момент выхода перевода TDD by Example эта методология трактуется как способ покрыть код тестами. И уже скоро 20 лет как это перебороть никто не может.

Нет. Вы потеряли нить обсуждения.

(…)

Неважно, насколько он тривиальный,

Нет, видимо это вы не поняли, о каких примерах шла речь. Или сделали вид — не знаю.

Вы спросили про примеры, когда не надо делать абстракцию, я привел примеры.

Можно было еще привести пример метода тепа Calculator >> twoPlusTwo return 2 + 2. — тоже пример кода, в котором "не надо делать абстракцию" (на самом деле, даже в нём надо).

Я делаю вывод, что в этих примерах абстракцию делать не надо.

Абстракцию делать надо. Просто абстракция — это не вынос родительского класса.

обе функции могут (и скорее всего будут) меняться независимо друг от друга

Любые две функции, пока они две разные "функции", будут меняться независимо. И именно поэтому, надо выявлять куски кода (не обязательно "функции"), которые связаны между собой и искать способ избавляться от этого дублирования.

Сегодня он тривиальный, завтра (…)

YAGNI.

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

А, ну я увидел статью про анемичную модель. Дальнейшее обсуждение сведётся к холивару про смысл ООП. Можно не продолжать.

Нужно ли выносить int $id в абстракцию BaseEntity? Нет.

Здесь нет дублирования функциональности. Её (функциональности) здесь в принципе нет.

Нужно ли делать BaseCrudService, который будет вызывать new и save, с абстрактным методом loadDataToEntity($entity, $dto), который переопределяется в наследниках? Нет.

Вы серьёзно?! У вас два раза написан тривиальный код, который практически ничего не делает, и вы всерьёз рассматриваете вариант по созданию базового класса, в котором будет вызываться конструктор? И из-за того, что этот …мммм, как бы помягче… не самый удачный вариант действительно оказывается …не самым удачным, делаете вывод, что DRY это плохо, а дублирование это хорошо? Я вас правильно понял?

нужны детально прописаные требования, причем финализированные - иначе адище вам гарантирован

А если TDD не использовать, то без ясных требований прямая дорога в рай? ;D

Ясные требования нужны в любом случае. И TDD заставит их прояснить. Без TDD — да, можно какое-то время изображать деятельность.

К тому же, TDD даст возможность прояснять требования постепенно, двигаясь маленькими быстрыми шагами — это позволяет часто выдавать новые версии, использовать их на практике и получать быструю обратную связь: правильно поняли очередной "кусок" или нет. На вопрос, как без TDD кто-то умудряется организовать "agile-" разработку, я ни разу не получил вменяемого ответа. Впрочем, я и вменяемого agile-процесса на практкие, к сожалению, до сих пор не видел, одни scrum-ные потёмкинские деревни.

А про бесплатную(!) страховочную сеть в виде тестов, которая позволяет спокойно вносить любые изменения в существующую систему, пишут даже те, кто TDD не понимает.

+100500

@kmoseenk , в чём была сложность с переводом слова "каноничный"? ;)

Да, пожалуйста — придумывайте любые методики, какие захотите. Просто не называйте их так же, как уже существующие. Путаницы и так хватает с огромным избытком.

А те, кто не пропагандирует TDD, верят, что можно сделать что-то, не понимая, что нужно сделать? ;D

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

Они понимали, что программная система — сложная. И что требования к программной системе — тоже сложная штука. И они знали, что человечество придумало хороший способ "борьбы" со сложностью — делить сложные вещи на более простые. Как сейчас модно говорить "есть слона по кусочкам". И предложили делать именно так, и с реализацией в целом, и (sic!) с требованиями. Потому как они-то понимали, что без понимания требований не будет и реализации. Точнее, может и будет. Но не та, которая нужна.

Именно поэтому итерация в TDD начинается с того, что придумывается сценарий, который описывает, как соответствующая предъявляемым требованиям система должна повести себя в этой конкретной ситуации. Понимаете "фишку"? Из огро-о-омной такой непонятной кучи чаще всего произвольным образом обобщённых "требований" выводим (дедукцией) один ма-а-аленький такой, очень конкретный, а потом гораздо более простой и понятный кусочек — пример. Это и есть способ уточнить — т.е. специфицировать — требования. Спецификация на примере.

Такой конкретный и ограниченный пример гораздо проще понять. Его не так сложно оценить на предмет соответствия требованиям. Его и реализовать проще. Проще — значит и быстрее. А понимаете, зачем нужно быстрее? Чтобы можно было быстрее показать эту самую систему и получить обратную связь: а правильно ли мы поняли требования? В нужном направлении мы двигаемся? Требования ведь не только сложны, они ещё и меняться любят.

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

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

рассмотреть методологию или даже способ организации разработки в более широком смысле

А TDD — это про разработку в узком смысле как раз: про "программирование", "кодирование", про реализацию требований. Не про весь цикл разработки.

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

Не хочу отвечать за автора того сообщения, но правильно понимание TDD отталкивается от того, что требования должны быть специфицированы — т.е. корректно описаны — до начала кодирования. Кто это сделает — аналитик, разработчик, тестировщик или (в идеале) все вместе — вопрос вне рамок TDD.

Вроде как требования это тоже результат разработки в какой-то степени, по крайней мере мне так кажется. Я собственно пытался развивать мысль в этом направлении, но это направление похоже никому не интересно.

Очень даже интересно. Только это уже не про TDD. "Вокруг и около" TDD — да.
И, прежде чем развивать что-то, желательно сначала узнать и понять это что-то. Тогда и лишней работы меньше будет, и вас поймут быстрее, и ваши мысли оценят по достоинству.

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

Именно! +100500
Именно поэтому я там даже уточнил, какую именно стоит взять ;)

"Кто-то с кем-то сделал что-то — ой-ой-ой-ой!
Неизвестно, где-когда…" — так что всё это мура!

Абстракция "с таким ветвлением" — уже не абстракция. А вот дублирование кода головную боль приносит гарантировано. Естественно, если там есть чему болеть :)

Так что давайте примеры в студию, а то какие-то страшилки для самых маленьких получаются.

Не осилил DRY — "придумал" PRY!

Вы серьёзно?

Скудненько. Даже какой-то необразованный О. Бендер знал четыреста сравнительно честных способов отъема денег у населения ;)

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

1
23 ...

Information

Rating
2,587-th
Location
Тверь, Тверская обл., Россия
Date of birth
Registered
Activity