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

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

4
Subscribers
Send message

Молоток — это технический долг

Никак не могу оставить в прошлом, одну историю, произошедшую со мной больше 7 лет назад.

На тот момент я, еще студент последнего курса учаги, только получил свою первую шабашку... Осмотревшись по сторонам, понимаю, что кругом меня не то что других молодых нет, но даже разнорабочих. Сплошные дядьки-петровичи с опытом до колена и красными с похмелья лицами... Ну ничего, сейчас я им покажу, что такое «молодая гвардия» 😂.

Получаю спецовку, стакан и струмент. Мне подробнее рассказывают куда что приколачивать. … И на третьем гвозде головка отлетает и отбивает мне большой палец на левой ноге. Я насаживаю головку обратно, и через три гвоздя она опять отлетает и снова отбивает мне большой палец на левой ноге. Больше того, смущает ситуация, что ни у бригадира, ни у кого из мужиков такого не происходит. Молоток стабилен, да и в нем не меняли ничего уже довольно давно. Вывод: проблема на моей стороне и разбираться мне с ней самому.

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

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

Но ведь мы — работяги: мы рождены, чтобы забивать гвозди без боли в большом пальце левой ноги. Почему мы не можем справиться с какими-то гвоздями? Я утверждаю, что проблема в молотках. То как мы вынуждены их заматывать синим скотчем, и следить за полётом головки провоцирует нас делать строгое разделение: вот тут у нас кувалды, где мы стараемся закрепить головку с помощью клина как следует, а вот тут молотки, к которым стандартные приемы не применимы. Тут мы легко сматываем километры синей изоленты, потому что "ну не покупать же новый молоток, он на две бутылки водки потянет, а то и три".

А что, в таком случае, по-вашему объект,

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

Тем более, что в обсуждаемой статье уже есть ответ на поставленный вопрос:

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

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

и какая от него польза?

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

…Но, всё же, если очень коротко: дуализм объекты и сообщения дают (как минимум) всё то же, что дают "инкапсуляция–полиморфизм–наследование–абстракция" (то есть последние просто выводятся из этого дуализма), но на гораздо более простом и (для многих) интуитивно понятном уровне; плюс первые имеют больше вариантов реализации.

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

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

При попытке продолжить сразу вылезет эта самая инкапсуляция

А вот у меня, знаете, ли никакая "инкапсуляции" ни откуда не вылезает.

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

Ну, а дальше

…А дальше, чувствую, дискутировать не будет смысла.

У вас уже выстроена некоторая система — трактовка ООП. Она не соответствует исходному замыслу ООП. В ней виден целый ряд несостыковок. Эти несостыковки постоянно вылезают на практике (в данном случае я про себя) и дают повод для критики такого "ООП"… Но, как показывает опыт, в комментариях объяснять и обсуждать это абсолютно бесполезно — пустая трата времени.

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

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

Остаётся ещё два возможных варианта.

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

Если же вы ещё не разбирались или не разобрались, но всё же захотите это сделать — способы найдёте без труда.

А почему бы не объяснять ООП, начиная с …(сюрприз!) ООП? ;)

Там же нет слова "актор". Как нет слов "инкапсуляция", "наследование", "полиморфизм", "абстракция". А вот слово "объект" есть. Может, есть смысл попробовать с него начать?

А ведь когда-то я, дитя ООП, даже представить себе не мог программирование без while. 

Видимо, дитя ООП внебрачное?

BlockClosure>>#whileTrue: aBlock
self value ifTrue: [ aBlock value. self whileTrue: aBlock ].
^ nil

Конечно, поздновато комментировать, надо было сразу… Но всё же скажу:

Может быть всё же не идеи потеряли смысл/суть, а "мы" (в статистическом смысле) "потеряли" смысл и суть этих идей?

Парадигма - это "очки", через которые мы смотрим на какую-либо систему.

Это метафора. Вы действительно считаете, что доказывать метафору с инструментами через метафору с очками может быть убедительно?

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

Я вам ещё мысль подкину.

Как вы считаете, можно ли одну парадигму полностью отразить в другую? Например, в объектной парадигме смоделировать функциональную? И наоборот?

Если вдруг да, то не сводится ли вопрос выбора парадигмы к вопросу выбора языка?

Но в реальности мы вынуждены идти на компромисс.

Бесспорно, но почему? Нас вынуждает ограниченность парадигмы или ограниченность её реализации — в языке, у нас в голове?

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

А почему они будут невыразительными? Что мешает там, где вам хочется объектно-ориентированного DSL написать его на функциональном языке? Или наоборот?

Я к чему это всё…

Когда IT-индустрия дорастёт до DSL…

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

Выдвину ещё такую гипотезу.

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

А речь вообще не о выборе языка под задачу.

Здесь возникает по крайней мере два вопроса:

1. Откуда вообще следует это аналогия между (мне не очень нравится термин, но назовём это условно) парадигмой и инструментом?

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

А что в этом прекрасного?

Тема хорошая и правильная. Но что интересно: и сама статья, и — особенно! — комментарии к ней являются изумительной иллюстрацией к этой теме.

(Не буду говорить про Scrum ` не очень интересно, но, чувствую, с ним та же история.) А с нормальным ООП ни автор, ни комментаторы так и не захотели ведь разобраться! Гораздо проще ведь в очередной раз перемалывать банальную истину про то, что "у каждой технологии есть своя область", не уточняя, где же она находится.

А автор ещё и пропаганду ФП умудрился ввернуть Не совсем беспочвенно, но и не очень-то способствует лучшем пониманию.

Если в голове у ФП последователей такое, я прохожу мимо 😆

Неожиданно, да? Но нет, уважаемый, путаете вы. Точнее, скорее всего, запутали вас.

В нормальном, чистом ООП достаточно двух базовых видов сущностей: объекты и сообщения. Ни конструкторов, ни типов, ни run-/designtime, ни даже классов и, тем более, типов не нужно — всё это, если и будет, то будет в виде "деталей реализации".

Понимаю, что вам — не лично вам; выросло уже не одно, не два, и даже не три поколения программистов, для которых ООП это три (может быть, четыре) "кита" — недосуг и (морально?) тяжело заставить себя более глубоко изучить вопрос "что такое ООП". Но если вы таки заставите себя почитать, например, The Early History of Smallltalk, или — ещё лучше — на практике попробовать Smalltalk (например, в виде Pharo) или Self, то, возможно, увидите что-то интересное для себя. А "ущербная" парадигма может вдруг заиграть неожиданными красками. И, кстати, вы можете найти интересные связи с так любимым вам ФП.

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

В ФП ответственность создания не на отдельном объекте, а на контексте / вызывающем сервисе. А в ООП жёстко: либо ответственность на самом объекте (в конструкторе) либо на другом объекте (чистая выдумка), который пытается вобрать в себя контекст, вариации логики создания.

В ООП ответственность за создание объекта ВСЕГДА лежит вне этого объекта. Уже просто потому, что если объект нужно создать, значит этого объекта ещё нет — и как то, чего нет, может отвечать за что либо?

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

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

С "философской" точки зрения всё логично и самоподобно, а потому требует меньшее количество сущностей, и, следовательно, проще.

Получается такая двойственная/сопряжённая задача для задачи разработки "в общем смысле" — войственный/сопряжённый подход. Вопросов и сомнений сразу же возникает очень много. Но раз, как я понимаю, работает, то есть что поизучать и о чём поразмышлять. Спасибо!

Спасибо переводчику за адекватный перевод и — особенно — за выбор статьи. Тема TDD (Test-Driven Development) vs. TDD (Type-Driven Development) весьма интересна — даже несмотря на то, что напоминает вечную проблему курицы и яйца :)

Итак, концепция TDD (Test Driven Development) – достаточно проста: Разработка ведется короткими циклами, каждый из которых состоит из 3‑х стадий:

1)Написание тестов, покрывающий желаемое изменение

В TDD на каждой итерации пишется ровно один(!) тест. И да, это принципиально.

Всё это очень странно.

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

Во-вторых, замечу, что "минимизация" вероятности дублирования не тождественна гарантии отсутствия. Это тоже не принципиально.

Но как может инициализация (а так же очистка после) быть не общей? SetUp/TearDown и их наследники же не просто так в xUnit-е поддерживаются, нет? Даже в этой наитривиальнейшей задачке присутствует дублирование в инициализации тестов. И предложенные вами в комментарии тесты будут это дублирование иметь — если его в какой-то момент не устранить.

Вообще, причин для изменения тестов в процессе разработки просто немерено.

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

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

А как быть с квинтэссенцией всего это бардака и тем, ради чего всё это (якобы) вообще затевалось — с изменениями требований к системе в целом…

А ещё вы очень лихо спихнули (только не понятно на кого) проблему оптимизации, которая непосредственно затрагивает TDD: количество тестов будет расти, а значит будет увеличиваться время их работы, а значит время отклика (обратной связи) будет расти — рано или поздно захочется их оптимизировать… Как это делать, не изменяя тестов? Или кто-то будет это делать за нас? Напомню: мы всё ещё про разработку, а не про тестирование и покрытие.

Ах, да — чуть не забыл, возможно, самую главную причину для изменения тестов — разработчика. Он меняется! Меняется его понимание того, что он разрабатывает. Соответственно, меняется язык, которым он своё понимание записывает. Тест в TDD — это спецификация требования на примере. И очень важно, не просто знать, проходит тест или ломается, а понимать его суть. А задача сформулировать тест/спецификацию так, так чтобы и самом разработчик в будущем, и друге люди смогли понять смысла теста — далеко не тривиально. Решить её с первого захода "может не только лишь каждый". У вас это стабильно получается?

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

Если честно, я вообще не могу представить, как вам удаётся не менять тесты?… Без обид (я спрашиваю для понимания, не с целью победить в полемике, честно!), но вы действительно практикуете TDD в "промышленной" (или как то назвать лучше) разработке? Давно?

Information

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