Pull to refresh

Comments 471

Сколько разных объяснений ООП читал, но про пекаря — никогда.
Мои студенты обожают. :)
Но ведь ужасная аналогия: «Он умеет работать с абстрактной печью...», «я не должен знать чего происходит внутри моей печи». Никто не умеет работать с абстрактной печью. Знание поведения конкретных моделей печей и отличие газовых от электрических и дровяных является одним из ключевых знаний для пекаря, и этот факт ломает всю аналогию к чертям. Почему её обожают?
Позвольте мне ответить:
Пекарь должен знать, что умеет делать печь, как ей управлять, и ее характеристики. Как работает конкретная печь (ее механику и электронику) ему знать не нужно. Этот пример хорош тем, что он моделирует работу пекаря, аппроксимируя ее до управление посредством общего интерфейса…
Это не аналогия а моделирование :)
Не знаю всей специфики приготовления в печи, поэтому буду говорить про плиту

Если пекарь не знает как работает плита:
— он будет «включать» электрическую плиту без электричества
— «включит» газовую плиту и не поднесет спичку
— Нужно учитывать, что плита нагревает блюдо неравномерно и иногда еду придется переворачивать
Всегда есть ограничения и дополнения:
— Для русской печи нужен ухват
— На обычной плите нужно учитывать продолжительное время разогрева
— За газовой плитой нужно следить, чтобы не погас огонь
— На стеклокерамику не рекомендуется проливать воду, категорически запрещено просыпать сахар, нельзя ставить горячее
— На индукционной плиты нельзя готовить в украшениях и нужна специальная посуда
— Есть плиты с механическим или сенсорным управлением, а также изменяой площадью нагревательной поверхности

Можно придумать много другого, но одно из главных ограничений ООП проблема внесения изменений без изменения а) структуры классов б) интерфейсов класса. Условно говоря иногда для обобщения нужно добавить некий базовый класс, который не был предусмотрен заранее или удалить метод, который стал не нужен или изменить логику применения метода. ООП подходит для академического решения задачи (решили и забили/не трогаем), в реальности такого никогда не бывает!
Народ. Ну вы чего? В зависимости от поставленной задачи выбирается уровень абстракции. Если мне надо учитывать больше, то я буду учитывать больше. Вы сейчас просто изменили требования к системе пекарь-печь.

Но! Изменение требований системы везде влечет полный ппц, какую бы методологию вы не использовали. Но ООП отлично приспособлено к внесению изменений при правильной декомпозиции и правильном проектировании, с учетом возможных изменений.
Есть базовый класс — плита, в классах наследниках — газовая плита, электроплита, индукционная плита, создаем дополнительные методы в случае необходимости, или запрещаем вызывать те методы, которые несовместимы с выбранной плитой.
> создаем дополнительные методы в случае необходимости
в базовом классе? оО
Внимательно перечитайте комментарий еще раз, пожалуйста.
«Запрещаем вызывать» — это в каких ЯП доступно?
в любых, где можно кидать exception
Сурово. Хорошо, что вы не хирургом работаете.
Ибо нечего :) Вот в розетку тоже можно палец сунуть, но будет неприятно.
Палец не влазит, там несовместимость на уровне интерфейса.
А вот шпильки влазят…
Если наследник класса «человек» — «ребенок», то пальцы вполне могут влезть.
суровые у вас розетки. Даже у новорожденного пальцы существенно толще
Вариант — игнорировать вызов — переопределить метод пустым.
Напоминает защиту от лишних исключений (С++) : try { /* очень полезная работа */ } catch (...) { /* а это чтоб не ругалось */}
Плохая аналогия. Мы не скрываем что-то, а наоборот демонстрируем готовность выполнить :)
жестко )
ни эксепшины, ни пустой метод — не выход. Это значит, что неверно смоделировали.

на то ООП и нужно, чтобы его не хакать ))
class Oven
{
    public virtual Food Cook(List<FoodProduct> products) ....
}


Нет?

В крайнем случае есть паттерны разные, вроде стратегий. Если не хочется заставлять саму печь готовить, а только пользоваться ею, нажимая на кнопки по разному.
Что значит модификатор virtual?
Это я так написал, как псевдокод. Пишу на шарпе, там уместнее был бы модификатор abstract. Но виртуал более понятный другим (например, С++).

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

Должна ли печь за это отвечать или только методы предоставить — включить, зажечь газ и т.д. — это зависит от задачи. Моделировать же один к одному реальный мир нет смысла.
Если по задаче отдельно методы можно дергать и отвечать за готовку будет не печь, а повар, скажем, то можно применить другие, более сложные способы. Паттерн Стратегия, например. В зависимости от того, какую печь будет использовать повар, у него меняется взаимодействие с печью.
А-а, я привык к модификатору final для методов, которые нельзя переопределять :)

Да, смоделировали неверно в какой-то мере, скажем предусмотрели отдельный метод для активации (включения нагрева) плиты, но не учли того, что могут появиться в продаже плиты с автоактивацией. Но во всём остальном модель подходит — готовит повар, а не печь. Почему бы не хакнуть, до следующего рефакторинга и внедрения той же стратегии.
А если мы находимся в открытом космосе на орбите Плутона, то пекарю нужно будет учитывать экстремальные температуры, отсутствие гравитации и кислорода. А у нас это не предусмотрено. ООП отстой!
Поставил плюс! :) Но надеюсь что это ирония и не более.
Перечитав ветку понял что это ирония. :) Видимо я уже готов ко всему, раз не понял это сразу. :) :)
Вот для вас и написана эта статья :)
Ну зачем предусматривать ВСЕ нюансы поведения модели и пытаться учесть всё-всё? Вы же при проектировании ПО так никогда не делаете, потому что YAGNI. И невозможно это. К ООП это не имеет никакого отношения. А только к выбору правильной абстракции.
Сущности тут разделены немного на другом уровне. Здесь сущность печи/плиты подает газ, зажигает спичку или включается в розетку. Ну или допустим тут адаптер/подмастерье это делает( по одному подмастерью на печь), пекарь лишь дает команду инициализироваться.
И если пекарь передает горячую кастрюлю в команду поставить на плиту, подмастерье проверяет и, узнав, что она хородная, выбрасывает исключение, или код ошибки возвращает.

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

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

Как минимум из недостатков здесь — затраты времени на этот процесс рассуждений (лично у меня эти рассуждения занимают обычно подавляющую часть времени при работе с ООП), никто не замечает, что всё это моделирование достаточно далеко от решение прямой задачи — реализации приложения «печь», к которому можно было бы приступить изначально. За время рассуждения выпустить печь 0.0.1, выдать своим пользователь новый фунционал бета версии.

Кроме этого вынужденного отвлечения, ООП вовлекает автора в формулирование аксиом,
например «печь должна греть».
Все ООП-шные реляции рушатся, когда через некоторое время после реализации структуры классов автор вдруг узнаёт, что на самом деле речь шла не о печи,
а о костре, например. Требования к системе были выражены недостаточно чётко или неочевидно, например в виде «нужно устройство для приготовления пищи в пользование повару».
Автор решил что это, конечно, печь. При чем успел разобраться в типах печей, чтобы сформулировать абстракцию. Поступили новые требование и это оказалась не печь, а костёр. А что же делать с печью теперь? Заархивировать и забыть. Или проще говоря выбросить. И приступить к реализации уточнённой задачи, с наработками, конечно, но множество связей и сущностей придётся придумывать заново. Прямой ущерб первоначальному принципу — упрощения и ускорения реализации.

Вы думаете ситуация, описанная мной нереальна? Я работаю в крупной хостинговой компании уже 5 лет, казалось бы всё просто и понятно на годы вперёд. Но вдруг появляется заказ на новый функционал, по нему делается структура классов, реализуется. В процессе эксплуатации появляются новые требования, но код-то написан под старые.
Доходило до того, что элементарно не удавалось исправить такие вещи как тему емейла, отправляемого клиенту, потому как по изначальным требованиям тема никогда не должна меняться. Более того, тема должна быть только такой, такая у нас должна быть фича.
Для доработки такой мелочи приходилось тратить весьма немелочное время.
Если бы на этапе проектировки не ставилась бы задача выделить сущности и связи исходя из требований, получился бы более размытый код, с меньшим кол-вом классов или ф-ций, но такой проблемы бы не случилось.

Теперь об преимуществах ООП.
Упомянутые преимущества вытекают не столько из ООП, сколько из грамотного деления кода на блоки. При этом блоком кода может быть функция, область видимости, отдельный файл. Эти сущности позволяют избежать повторяемости кода, организовать разделение кода, позволяющее назначить поддержку части кода одним разработчикам, другой — другим. Не обязательно для получения этих выгод использовать какие-то паттерны или вообще классы. Однако, для некоторых задач ООП+паттерны бывают как нельзя кстати, но я не могу рекомендовать применять «правильное» ООП ко всем подряд задачам.

Сам я использую ООП, но без фанатизма. Практически не использую паттерны. Пишу код с учетом того, что завтра у нас печи начнут не греть, а холодить, а еда вообще станет deprecated :) На длительную перспективу, это очень сокращает общее время разработки проекта — делай только то, что от тебя хотят сейчас, никаких додумок и предположений на будущее. Только одно предположение — завтра абсолютно всё может измениться.
Пишу код с учетом того, что завтра у нас печи начнут не греть, а холодить, а еда вообще станет deprecated :)

и

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

разве не противоречат друг другу? Когда я слышу «а вдруг завтра у нас печи начнут не греть, а холодить, надо нам это предусмотреть», то с ужасом ожидаю очередного приступа ООП головного мозга — моей хронической болезни :)
Я думаю, в этом заключается основная суть претензий к ООП — труднодостижимая гибкость относительно требований.
Архитектура классов может быть выверенной и вылизанной. Но это в полной мере возможно лишь в идеальных условиях при стабилизированных требованиях и понятной стратегии развития продукта.

Для меня «дзен» ООП — это умение написать с его помощью такую архитектуру классов, которую не придется рефакторить до основания после очередной смены требований. И тут пригодится не сколько умелое применение паттернов, сколько интуиция по поводу того, что реально в будущем может потребовать изменений. И не впасть при этом в over-engineering и не стать архитектурным астрономом.
Я бы сказал, что это суть претензий к любой парадигме программирования. :(
ответили вместо меня, спасибо :)

Да, претензия к ООП именно в том, оно затрудняет последующие изменения кода,
т.к. система классов заточена под представление системы на момент проектирования.
Если наши ожидания от развития системы и реальное развитие системы отличаются — наша система классов вместо пользы, наоборот начинает нам мешать, т.к. наши старые сущности и связи оказываются инвалидами в новых условиях, их нужно лечить или вовсе убивать, а вместо них заводить новые сущности.

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

Когда нужно просто удалить файл, для этого можно написать функцию, которая делает только удаление файла. При этом не будет потрачено времени на осознание того, какие именно файлы функция должна удалять и зачем, кто её должен вызывать. Не будет потрачено излишнее время, не будут выстроены ненужные абстракции и связи, которые при дальнейшем изменении требований не будут мешать.
Так если нужно лечить или убивать нужно лечить или убивать. Это верно для любой (известной мне) парадигмы. Не предусмотрели возможности изменять тему письма — надо убивать литерал и вставлять вместо него константу, переменную из конфига, а то и процедуру/метод/функцию/кусок кода по получению его от оператора с поддержкой автодополнения. Какое это отношение имеет к ООП?

И не нужно строить красивые системы классов, нужно строить рабочие, и рабочие не во всех ситуациях, которые пришли в голову, а рабочие здесь и сейчас, и ровно в том объёме, что указан в ТЗ (пускай оно и только в голове). Городить абстракции ради абстракций, систему ради системы, возможности замены одного сервиса на лету ради возможности не нужно.
Говорят, что системы нужно проектировать с учетом возможных изменений… Более того, оценка вероятных изменений должны быть этапом проектирования системы.

Иначе было бы проблемно, в проекте на over 1 000 000 строк, все менять с ASCII на UTF8.

Здесь и сейчас — жадный алгоритм, который, как известно, далеко не всегда является оптимальным.
Если никаких объективных данных для оценки нет? Если опыт кричит, что ASCII надолго не хватит, а SQLite два одновременных соединения не выдержит, а уже завтра гендир захочет посмотреть что там техдир в новой системе делает — это одно. Но если никто не может сказать какую фичу запросят пользователи после релиза (знали бы — сразу бы зарелизили) — несколько другое. Ну и, главное, программирование к анализу требований, включая оценку перспектив развития, имхо, мало отношения имеет. Это задачи маркетологов, аналитиков и т. п.

Почти всегда, есть что-то, что вероятно изменится. Для сайтов — новые пункты, языки, СЕО, для ИС — криптография, смена типов базы знаний…

Ну и, главное, программирование к анализу требований, включая оценку перспектив развития, имхо, мало отношения имеет.
Контрпримеры: 1. Программист должен программировать класс String подозреваю, что он может быть не только на char, но и на wchar.
2. Программист должен программировать подсистему отображения набора информации, с учетом того, что информации может быть не 5 единиц, а over 9000.

Другими словами, это не столько оценка требования и перспективы развития, сколько качество системы и уровень адаптации к различным условиям.
а в чем проблема в проекте на 1 000 000 строк заменить ASCII на UTF8? В зависимости от языка конечно. Даже простая автоматическая текстовая подмена типов вполне работает.
Главное — не забывать — юнит-тесты писать, чтобы потом узнать, сломалось ли что-то.
А потому, что в некоторых ЯП, или даже в конкретных реализациях, класс String работает только с символами, которые занимают 1 байт. Замена на 2 байта потребует переписывание множество функций, от getLength до indexOf. И это если есть класс для работы со строками, иначе совсем печаль.

Более того, в проекте на 1 000 000 может быть ряд системные работ со строками, аля memset.

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

В С, например, можно не использовать прямо тип, а макрос препроцессора использовать. Захотели поменять, подменили в макросе. В других языках, если что, создаете свой тип, класс. Если же не предусмотрели (и возможно правильно, не было требований), то можно сейчас создать новый тип и подменить текстовой автоматической подменой.
А юнит-тесты покажут что не так. В общем, я бы из этого проблемы не делал. Потому что это простой автоматический рефакторинг. Да, может оказаться сложным. Но вообще-то, проблема с аски и юникодом довольно известная. И если язык не поддерживает тип юникодов, то можно что-то придумать сразу — написать класс-обертку над стандартным аски-типом. А потом ее подменить.
Автоматические действия с заменой просто сделает все не рабочим. Юнит тесты помогут найти проблемы, но их может и не быть. И даже если есть, решать те проблемы может быть долго и печально.

Я хотел сказать, что дешевле было бы сделать поддержку строк utf8 сразу, чем потом делать такие исправления.
Вы всё правильно написали.
Я прихожу к более четкому выражению своей претензии к ООП — при работе с ним очень легко сделать ошибку, которая выльется затем в трудозатраты на её исправление. Изменять менее структурированный код мне лично проще.
Возможно, это мой личный баг :)
А правильное ООП предполагает довольно четкие структуры классов и связей.
Опять ведь за старое. Это претензия к разработанной вами структуре классов, а не к ООП! И опять же, когда нужно просто удалить файл, для этого можно написать метод, который делает только удаление файла. Зачем, если вы используете ООП, обязательно пытаться всё усложнить и предусматривать ненужные мелочи? А затем всё сваливать на парадигму. Просто решайте поставленную задачу, а правильное применение ООП поможет снизить стоимость переделок.
Вы правы, и мой пример с файлом не самый удачный. Тут сложно нагородить огород, пользуясь приёмами ООП.

Для более реальных ситуаций есть проблема в том, что выбрать упомянутое вами правильное применение ООП — уровень абстракции и всё прочее — не так-то просто. А время на обдумывание при проектировании ООП-сущностей отнимается нещадно. Взять хотя бы рутину по написанию класса и обдумывание его свойств и их модификаторов.

Буквально сегодня минут 30 с коллегами потратил на обсуждение того, как упростить ситуацию с двумя схожими классами, которые отличаются только некоторой реакцией на входные параметры. Коллеги предложили сделать 1 абстрактный класс и 2 наследника, в которых переопределять специфику.
Это потребовало достаточно много времени — написание абстрактного класса с общей логикой (эту логику ещё нужно внимательно вынуть из двух классов),
выноса отличающейся логики в отдельные методы и переопределения в наследниках этого метода. В итоге было сделано именно так.

Казалось бы, ребята сделали всё верно. Но!
1) они потратили уйму времени на обдумывание, обсуждение и реализацию
2) они получили больше классов, чем было — было 2, стало 3 (добавился абстрактный), появилась иерархия и наследники, т.е. система усложнилась

Я предложил совсем не ООПшный подход — сделать 1 класс, отличающуюся логику релизовать простым if-ом. Реализовать это в первом классе.
Убрать второй класс и его использование (трудозатраты на это рефакторинг использования — секундны, решается простой скриптовой заменой использования имени второго класса на имя первого). Это решение было готово через 3 минуты, оно не усложнило систему.

P.S. два упомянутых мной схожих класса в таком виде живут более 2х лет и с тех пор ни разу не менялись и не планируют.
Мне кажется я реально стал понимать точку зрения вашего лагеря :)
На хабре недавно проскакивала статья про фабрики фабрик фабрик для производства молотков. Складывается ощущение, что та статья была не шуточной, а в какой-то степени действительно отражала правду.

По факту, смысл вашего комментария сводится к тому, что следуя ООП ребята впустую потратили 30 минут времени каждого (минимум, 1 человеко-час) и получили такой же выхлоп, как и мгновенное решение с использованием одного if. Здесь даже не поспоришь, это суровая действительность.

Однако, ребята сами виноваты :) Ещё Фаулер в PoEAA чёрным по белому писал: ребята, transaction script — это быстро, эффективно, но не приветствует изменений и не сильно способствует читаемости кода (в экстремальном случае). Domain model — это на старте ощутимо дольше и дороже. Профит в плане снижения сложности внесения изменений появляется только при достижении конкретного объема модели. До него — transaction script эффективней. По-моему, в книге даже был график. Ребята — сами виноваты. Ваше решение лучше по всем критериям! Только if — это не «совсем не ООПшный подход». ООП не запрещает в логике класса использовать условие. Оно просто говорит, что данный подход немного менее очевидный и понятие, лежащее в основе данного условия мы намеренно делаем менее явным и прячем от взора разработчика. Если окажется, что оно было важным — то epic fail. Если более 2х лет нам на него было начихать — okay.

Хочу ещё прокомментировать один момент. Вы чуточку не правы про усложнение или неусложнение системы. Наплодив больше классов, мы увеличиваем количественную сложность системы. Да, классов больше. Качественная сложность может даже наоборот снижаться. У нас же есть мощные инструменты — абстракция и инкапсуляция. Ну и что, что за реализацией данного интерфейса лежат ещё 2 класса и куча условной логики. Мне, как клиенту данного кода — жить прекрасно и шоколадно. А разработчику данного кода — что 1 класс, что 2, что 3 — по сути, равноценно. ООП позволило нам разбить программу на подобласти и под-подобласти, в каждой из которой мир просто, понятен и пушист. А то, что в сумме это на самом деле робот для убийства всех человеков — ну, okay :))
Это не дзен, это колдунство ;)

Дзен — это писать код в здесь и сейчас. Без никаких малейших предположений на счет будущего. И также с безжалостным рефакторингом остатков прошлого.

Дзен, это когда вам говорят:
— Почему ты не предусмотрел возможность того, что печь может быть и открытым костром. Это очевидно и завтра мы это будем внедрять.
— Завтра — будет завтра. Зачем нам думать о завтра? Завтра не существует, вчера не существует. Существует только сегодня.

Будет задача, будем рефакторить. Куда нам спешить? Нас не как пророков нанимали, а как программистов.
К программистам то вопросов и не будет. А вот к проектировщику да.

Но все забывают про стоимость рисков. Если вероятность какого то изменения требования (добавления, изменения, удаления не важно) = 0.00001%, и если оно изменится в будущем, я буду вынужден потратить 100500 долларов на его внесение. Но если я сейчас заложу, что называется на берегу, гибкость в данном направлении, то оно мне будет стоить 100$, то я скорее сразу реализую гибкий механизм.
К сожалению, так бывает редко. Существенно чаще бывает так: вероятность изменения — 0,0001, косты изменения «по факту» — $1000, косты «разработки заранее» — $100, падение производительности разработки из-за заложенной универсальности — 10%.
Да, если 10% времени будут стоить больше 1000 долларов, то лучше не реализовывать.
10% времени стоят больше $1000 в любом сколько-нибудь крупном проекте.
Ну я не спорю. :) Но вы ранее это не уточнили. Поэтому я не понимаю чего вы хотите сказать. Вообще не надо думать о изменениях? Или что? Ток не говорите что все зависит от множества факторов и т.д., т.к. это мои слова выше.
Я хочу сказать, что по моему опыту, об изменениях надо думать, но чаще всего бесполезно под них что-то планировать и реализовывать заранее.
Ну спорно, очень спорно. Все зависит от конкретной ситуации.
гибкость в каком-либо направлении означает негибкость в других направлениях. Поддержка преждевременной гибкости несет больше расходов.

1. Код сейчас принято покрывать юнит-тестами. Это один из самых серьезных методов сокращения багов и какой-то гарантии, что код делает то что надо. Лишняя гибкость — лишний функционал. Лишний функционал тоже покрывается юнит-тестами. При изменении чего-то (часто бывает), тесты являются определенным иногда тормозом. Потому что их тоже нужно менять. Но при этом, тесты дают саму возможность изменений, потому что без них вообще страшно что-то менять в уже работающем коде. Никакой без них гарантии, что всё идет как надо. В итоге изменения с тестами экономят время и деньги из этапа сопровождения.
т.е. издержки на поддержание лишних тестов. Могут быть довольно серьезными.
2. Если код простой и соответствует требованиям только на «здесь и сейчас», а также покрыт юнит-тестами, то любые изменения в коде делаются значительно легче делаются изменения. Т.е. это не 100500 долларов на его изменения.
3. Если вы не угадали направление, кроме всего прочего, далее возможно придется удалять код. Потери.
4. Если вы угадали направление, то времени и денег вы не так и много сэкономили, если сэкономили вообще. То, что делалось наперед, съело время раньше. А так съест время сегодня. Раньше могли бы заниматься более важными задачами. Обычно их хватает всегда.

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

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

Так, во-первых, далеко не всегда бывает. А во-вторых методология написания ПО с помощью угадывания и такая как я описал отличается. Отличается в ту сторону, что ПО, которое пишут для здесь и сейчас — гораздо легче поддается изменениям. И затраты на изменения небольшие. Не грозят катасрофой. Потому в ТДД рефакторят всё время. И никто рефакторинга не боится.

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

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

Вот за это просто сразу плюс в карму. Не то, чтобы проблема специфична только для ООП — в проектировании она в принципе довольно часто возникает — но в ООП она особенно заметна.
Если не сложно, поясните, пожалуйста, почему означенная проблема особенно заметна в ООП. Именно этот тезис я извлёк из вашей статьи и именно он у меня вызывал абсолютное непонимание.
Ну, как-то обоснованно и опираясь на твёрдые факты тут не объяснишь — всегда можно будет найти какие-нибудь «но». Тут скорее чувствовать нужно. Тем не менее, попробую объяснить на примере, как раз том, которую использует автор этой статьи:

Есть пекарь. Есть печь электрическая и газовая. Ваша задача смоделировать процесс приготовления пищи пекарем в каждой из печи

Первое, на что стоит обратить внимание, это то, что мы видим не задачу. Задача может звучать, например, как «создать систему поддержки пекарни», а в подзадачи входить отслеживание прихода и ухода продуктов, расхода топлива, контроль условий эксплуатации и т.д. ООП нас учит как раз тому, что предложил автор — смоделировать процесс приготовления пищи. Чтобы сделать это, мы начинаем думать:

1. Какие у нас есть объекты в предметной области?
2. Как они взаимодействуют?

Как только базовое понимание модели есть, мы переходим на технический уровень:

3. Как уменьшить дублирование кода?
4. Как это можно реализовать средствами языка?

Когда первая аппроксимация системы готова, мы начинаем причёсывать её, а для этого продумываем:

5. Как сделать систему расширяемой (добавление новых печей и т.д.)?
6. Как могут измениться требования, и что нужно предусмотреть, чтобы всё не сломалось.

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

Это в ООП. В не ООП мы не ограничиваем решение задачи только моделированием предметной области. У нас есть задача и подзадачи, так почему бы не приступить сразу к решению этих задач? Чтобы подсчитать расход топлива, нам не нужна модель печи — достаточно простых уравнений. Мы можем сразу написать функции для этих уравнений, не тратя время на overhead в виде моделей печи, пекаря, топлива и булочки с маком. Просто решить поставленную задачу. Всё.

Плюсы и минусы есть у обоих подходов. ООП создаёт накладные расходы, но может помочь лучше структурировать код, сгруппировав по смыслу. Не ООП (а, скажем, процедурное программирование) позволяет сразу сконцентрироваться на задачах, но может быть более слабым в борьбе со сложностью. Многое зависит в т.ч. от самодисциплины и умения подходить к проблеме с разных сторон (в ООП ведь тоже не обязательно пытаться смоделировать предметную область).
Мысль уловил, осознал и даже выглядит разумно.

Но есть вопрос:

Первое, на что стоит обратить внимание, это то, что мы видим не задачу. Задача может звучать, например, как «создать систему поддержки пекарни», а в подзадачи входить отслеживание прихода и ухода продуктов, расхода топлива, контроль условий эксплуатации и т.д. ООП нас учит как раз тому, что предложил автор — смоделировать процесс приготовления пищи


Если задача стоит «создать систему поддержки пекарни, подзадачи которой 1), 2) и 3)», то зачем моделировать процесс приготовления пищи? И почему именно этому учит ООП? Что-то подобное идёт из DDD, да. Опишем модель процесса приготовления пищи и затем поверх забабахаем то, что нам на самом деле нужно. Но разве ООП нас заставляет так делать? Если я включаю мозг на 1 шаг раньше и не бросаюсь описывать модель, а бью систему на актёров и юзкейсы и уже в рамках каждого смотрю, что мне с ним делать дальше — это что? (Исходя из вашей логики, складывается ощущение что вы бы это назвали чем-то другим, нежели ООП-подходом)
Одна из «больших идей» ООП — это как раз моделирование предметной области. Считается, что это позволяет облегчить создание архитектуры, т.к. связи между объектами берутся напрямую из жизни. Подход не всегда верный, но, как подтвердил своим постом автор данного топика, достаточно распространённый. DDD действительно имеют схожую концепцию (по крайней мере, насколько я понимаю этот термин) и часто использует в качестве инструмента ОО языки. Нет, ООП не заставляет вас сразу бросаться в моделирование, но поскольку ООП вроде как предоставляет удобный инструмент для отражения реального мира в программе, соблазн велик. Если вы включите мозги на 1 шаг раньше, то ваше решение всё равно может быть реализовано в рамках ООП, но решение будет другим, непохожим на решение, предложенное, например, автором статьи.
Не буду отрицать, что соблазн кинуться в моделирование очень велик и по факту затраты на подобное моделирование могут оказаться выше, нежели решить задачу «в лоб». Точно такая же проблема наблюдается с GoF (имхо) — велик соблазн абстрагировать в каком-нибудь паттерне каждый технический чих в программе. Но ведь всё это справедливо для неокрепших, начинающих умов! ООП даёт нам слишком много свободы и поэтому ею тяжелее распорядиться правильно. Поэтому нужно сильнее себя контролировать и чаще оглядываться назад, нежели смотреть в светлое будущее, когда наш калькулятор наверное будет забирать с биржи текущие котировки валют и уметь переводить из одной в другую. Нам в этом помогают всевозможные DDD (в книжке Эванса, по-моему, чуть ли не каждый спорный нюанс из комментариев к обеим статьям рассмотрен). Как награда за наши старания — в грамотно спроектированном ПО по ООП подходу действительно будет проще вносить изменения и действительно будет проще разобраться стороннему программисту.

У меня вот авто — Subaru. Считается, что она позволяет ездить быстрее 80% остальных авто. У меня нет к ней претензий, потому что хотя велик соблазн почудить, особенно зимой, я включаю мозг и так не делаю! Несколько раз (месяцев) потренировался на закрытой площадке и действительно, когда необходимо — я могу на ней ездить быстрее остальных.
Про авто — отличный пример, надо запомнить :)
Минусы как-то описывались в «как программисты строят дома».
Примерно — один начал строить этажи, второй шахту лифта. Но тут оказалось что высота и к-во дверей лифта не совпадает с высотой этажей. А про лестницу и дверь вообще забыли. И надо переделывать.

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

Т.е это «подумать и спроектировать заранее, вместо сразу реализовывать подзадачи» напрямую не относится к ООП.
Естественно, проблема релевантна для любой парадигмы (я двумя комментариями выше как раз об этом говорил). Тут ещё интересно сравнить восходящее и нисходящее проектирование. Термины не очень распространённые, поэтому поясню: при нисходящем проектировании мы сначала начинаем думать про самые общие цели и задачи, а потом уже декомпозируем каждую из них, пока не доберёмся до самых мелких. Другими словами, проектируем сверху вниз. При восходящем, соответственно, мы делаем строго наоборот: сначала продумываем реализацию отдельных частей, а потом всё это связываем в единую систему, т.е. идём снизу вверх. Так вот, ООП по определению нацелен на нисходящее проектирование, т.к. старается смоделировать всю задачу в терминах объектов и их взаимодействия. На противоположной стороне, вероятно, находится ФП, которое очень хорошо поддерживает проектирование сверху вниз: вначале продумали отдельные модули с очевидным функционалом, а потом уже на основе имеющихся модулей начали думать про более высокие уровни архитектуры.
Как по мне, то ни ООП, ни ФП, ни ПП не накладывают ограничений на направление проектирования/моделирования. Все три можно успешно применять и когда задача разобрана постановщиком до последнего нюанса, равно как когда вообще задача не ясна. Выбирать надо по задаче и по доступным ресурсам.
Не совсем.
Для задачи — «реализуйте 5 разных печей и параллельно обучите 5 Иванов, при этом каждую печь проектируют отдельные люди» — нет.
И для задачи «ты пока реализуй 2 печи, а потом ты уволишься, а придет кто-то новый и ему нужно будет еще 3 сделать» — тоже.

Тут ограничение только на интерфейс взаимодействия модулей печей и Иванов, а это гораздо более мелкая задача, чем проектирование полной ОО архитектуры. Если подразумевается общая функциональность (которую в ООП вынесли бы в абстрактные печи и абстрактных Иванов), то её вполне можно поместить в отдельный модуль, при этом не закрепляя жёстко объекты в иерархии наследования.
Спасибо! Отвечу вам взаимностью, когда сам наберу достаточно кармы для оценок.
Также поддерживаю ваше более подробное разъяснение этого моего тезиса habrahabr.ru/post/148015/?reply_to=4996307#comment_4998355

Должен заметить, что в этом топике нахожу беспрецендентное взаимопонимание с отдельными коллегами :)
Блин. Ну вы забываете абсолютно про абстракции. Если не будет абстракции, то я буду вынужден программировать поведение атомов в системе пекарь-печь.
Да ну вы что. Это же студенты, они только пельмени и роллтон готовить умеют, и разница между газом/электричеством/дровами им еще даже и не встречалась в жизни ;)
Я слышал о студентах, которые даже пельмени приготовить не умеют.
Потому, что готовить не умеют (ну или не настолько умеют или просто красивая) и разницу не ощущают.
Ну да, не очень удачный пример. Лучше возьмём принтер. операционная система не заточена под какие-то конкретные принтеры. У она предоставляет программе интерфейс абстрактного принтера который имеют драйверы всех принтеров, и ОС вообще никак не волнует, как там принтер печатает и печатает ли он вообще. Вот это програмный интерфейс — это полиморфизм. Драйвер — инкапсуляция. (Блин, для наследования как-то нету места)
Внимание вопрос! А причем в Вашем примере с принтером ООП?
Базовый класс — драйвер транспорта? Не очень конечно, корректно.
Для наследования нет места потому что это не ООП
Если в контексте вашей задачи знание пекаря о печи являются существенной информацией, значит данный пример в вашем случае будет неверно выбранным уровнем абстракции… Вам значит надо сделать отдельно объекты «электрическая печь» и «газовая печь», определить, что важного о них знает пекарь и работать с ними соответственно вашей задаче.

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

Для эффективной реализации приложения иерархия классов должна отражать взаимосвязи существенные для вашей задачи. Умение отбросить лишние, несущественные взаимосвязи, выделить/усилить принципиальные является ключевым в ОО-проектировании.

Еще раз: Универсальной (на все случаи жизни) иерархии классов не существует. Эффективная иерархия классов может быть построена только в контексте конкретной задачи.

В связи с этим, абстрактные рассуждения про наследование, инкапсуляцию и полиморфизм не имеют никакого смысла вне контекста задачи, и являются обычным псевдоинтеллектуальным бредом. Чем та статья, о которой упоминает автор данной статьи, и является.
А виртуальные классы на примере пекаря?)
Хотя аналогия хорошая)
Есть продукты и есть функции: поджарить, протушить и нарезать, например. Хотим пожрать. В роли «повара» выступает функция или, если угодно, процесс, который решает, какие продукты использовать и какие действия над ними производить в зависимости от входных параметров (название блюда). В результате получаем готовый ужин.

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

А ещё теоретически при таком раскладе один и тот же повар сможет приготовить пять блюд одновременно без необходимости ручной синхронизации, потому что процессы приготовления ни от чего лишнего не зависят. А Ваш пекарь в процессе приготовления блюд сломает стол — и капец! :) Или ингридиенты перепуает :)
Как по мне на редкость неудачный пример. Пекарь Должен знать о том что у него за печь, какое горючее потребляет, как ее включать, как использовать именно эту печь, а не абстрактную печь в вакууме. Иначе это очень плохой пекарь, если он не знает своих инструментов. Пекарь Должен хотя-бы ознакомится с особенностями конкретной печи, прежде чем начнет ее использовать. Есть промышленные, есть бытовые печи, духовки и т.д. И технология готовки там отличаются не хило.
Это всего лишь пример.
Вот оконный менеджер не знает что у вас за приложение — броузер, архиватор или 3D игра, но при этом он знает как свернуть окно, как закрыть приложение, как показать его название и иконку в списке задач. Но ведь приложения разные!

А почему так? Да потому что приложения пишутся под менеджер окон, а не наоборот!

Так и с печами — если печи разные, то их специально будут делать одинаковыми в управлении, потому что мы такое ТЗ делаем.
Или управление под один стандарт адаптировать, типа приделаем к газовой печи автоподжиг или к электрической пустое действие «зажги конфорку».
Я всем преподавателям говорю, и вам тоже скажу — перестаньте уже плодить в индустрию ООП-фанатиков.

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

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

А они не умеют сортировку пузырьком. Зато наизусть вот знают ваши инкапсуляции-наследования-полиморфизмы.
Вы не в кулинарном техникуме преподаёте? :)
Точнее обожали, сейчас не преподаю, т.к. переехал…
Читал замечательную книжку First Head: Design Patterns.

Там готовили абстрактную пиццу на абстракной пиццерии-фабрике. :)
Да, я тоже долго не мог собраться написать… Но прям чуял что напишу. :)
Еще говорят что некоторые вещи нельзя представить в виде объектов и их взаимодействия.

Несомненно, все можно так представить. Но дело в том, что некоторые вещи существенно проще представить в другой модели.
Не спорю. Но что касается разработки ПО, то скорее всего более понятного, именно понятного для других программистов, я не встречал. И давайте пример. :)
А давайте, прежде чем мы перейдем к примерам, я спрошу, что вы подразумеваете под разработкой ПО.

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

Но для меня разработка ПО это тоже самое, но плюс минимальные затраты на само написание кода, расширение и сопровождение.
плюс минимальные затраты на само написание кода, расширение и сопровождение.

Это уже количественные характеристики, определяющие эффективность процесса.

Так вот, возьмем сначала самый простой пример: менеджер хочет видеть еженедельный отчет по эффективности продаж. В пяти разрезах и с drill-down. Продажи лежат в БД (уже много лет как лежат).

«Очевидно», что самый эффективный способ это сделать — это построить кубик поверх БД, а потом выложить этот кубик в Sharepoint BI или просто в Excel, в зависимости от того, что у нас развернуто и используется (ну или в любую другую BI-систему, просто эти первыми на ум пришли).

Требование реализовано, ни одного объекта не пострадало ни только при разработке, но даже при проектировании системы.
Блин. Честно не знаю что ответить. Явно вижу что вы абсолютно правы, но явно чувствую что вы меня накололи в определении «разработка ПО». :)

Я все таки понимал нечто большое, чем конфигурирование MOSS и построение кубика… Ну тут то да, вам не нужно использовать ООП. Блин, моя «разработка ПО» гораздо более чем ваша. :)
Понимаете, на нынешнем уровне сложности бизнес-процессов максимум задач надо сводить именно к таким решениям. Просто потому, что вы иначе не успеете.

Вы думаете, DSL, SOA и прочие умные слова вырастают на пустом месте?

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

И так далее.

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

«ООП — это технология уровня реализации» заметьте, я и не говорил иначе, более того, я это подчеркнул.

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

А слова вырастают, но продолжают убивать когда требуется сильно кастомное решение.
«ООП — это технология уровня реализации» заметьте, я и не говорил иначе, более того, я это подчеркнул.

Есть уровень реализации бизнес-задач, а есть уровень реализации платформы, например. И это разные уровни.

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

BTW, все большее развитие мультипарадигменности в языках это подчеркивает.
Это типа вы сейчас сказали, что DSL, SOA и прочее — это какая-то новая парадигма? И сервисы не имеют поведения, не имеют внутреннего состояния, а DSL не оперируют предметной областью и мы на них не описываем поведение объектов этой самой области? И кубик — это не объект с кучей данных, да? И даже когда задача сводится к установке готового продукта, его настройке и интеграции с кучей других — там внутри нет ООП? По-моему, это оно самое — проектирование, объектно-ориентированное. Код тут лишь вершина айсберга, а в его низах кое-что другое, о чём писал автор в статье.
Это типа вы сейчас сказали, что DSL, SOA и прочее — это какая-то новая парадигма?

Нет, я этого не говорил.

И сервисы не имеют поведения, не имеют внутреннего состояния

Сервисы в contemporary SOA не имеют внутреннего состояния.

DSL не оперируют предметной областью и мы на них не описываем поведение объектов этой самой области

DSL оперирует предметной областью. Он не обязан быть объектным, так регулярно делают (примеры есть у Айенде).

И кубик — это не объект с кучей данных, да?

Кубик, несомненно, объект. Но его абстракция в голове проектировщика — это многомерные данные, а не «объект».

И даже когда задача сводится к установке готового продукта, его настройке и интеграции с кучей других — там внутри нет ООП?

Никто не знает, и слава б-гу. Это как раз уменьшение сложности.
Там тоже ООП не имеет смысла, там сообщения и агенты.

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

Тут есть две точки зрения. С одной из них (современное SOA), в подобной архитектуре нет ничего, кроме объектов и сообщений, и с этой точки зрения оно похоже на ООП (с других все равно не похоже, потому что coarse-grained interfaces и stateless agents). А с другой (enterprise integration patterns), помимо агентов и сообщений есть еще посредники (которые, собственно, и управляют сообщениями), и вот они в ООП ложатся хуже. Хотя, несомненно, они тоже объекты, но вот стройность картины уже теряется.
Приходится вводить пркси, адаптеры и фасады? Вы про это?
Нет — меняется место принятия решения.
Если объект А посылал сообщение объекту Б — то не важно через адаптер он это делает или нет — он знает про Б.

Если есть посредник, то объект А посылает сообщение в пустоту — а кто словит, тому и будет. Посредник ловит и отсылает его в Б, а может и в В или куда-то еще в зависимости от изменившихся требований.

Так вроде?
Прокси, адаптеры и фасады — в ООП — это шаблоны, состоящие из тех же объектов. А в messaging аналогичные им элементы — это first-class citizens.
Не важно как это реализуется. Смысловая разница в чем?
В уровне абстракции. Там, где ООП оперирует двумя понятиями (объекты и сообщения), messaging оперирует существенно большим их количеством.
Ну мне кажется что если вы покажете эти понятия, то на это будут те же объекты.
Deep down, несомненно. Во-первых, потому, что слово «объект» настолько всеобъемлюще, что им можно назвать все, что угодно, во-вторых, потому что если у вас есть молоток, все вокруг выглядит как гвозди.

Дело не в том, что это можно рассматривать как объекты. Дело в том, что это эффективнее рассматривать иначе. Объекты — это слишком общая абстракция, она слишком далека от происходящего, и на то, чтобы пересечь этот промежуток, требуется слишком много усилий.
А причем тут ООП? ООП это такой же инструмент как и все остальные методологии. Он вовсе не универсален и имеет свои области применения.

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

При том, что автор статьи попросил показать ему примеры ситуаций, где иное, не-ООП представление практичнее.

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

Вы, видимо, не очень понимаете, что такое разрез (dimension) в аналитических данных, иначе бы вы не говорили, что это паттерн presenter.

Ну и да, если вы обратите внимание, данные и представление в моей реализации полностью разделены, данными занимается OLAP, а представлением — соответствующий клиент, имя которым миллион.
Чем тут вам не объектный подход? Вы просто использовали другую терминологию.

С названием паттерна промахнулся. Пардон… Что такое разрез данных я знаю. Вы по сути получаете историю состояний сущности (объекта), которой в базе данных не существует. Одни и те же данные в базе одновременно могут являться данными о состоянии разных объектов.
Чем тут вам не объектный подход? Вы просто использовали другую терминологию.

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

Вы по сути получаете историю состояний сущности (объекта), которой в базе данных не существует.

Нет.

Одни и те же данные в базе одновременно могут являться данными о состоянии разных объектов.

Тоже нет.
Разрез в аналитических данных — это не история состояний, которой в базе не существует. Это просто измерение аналитического многомерного куба.
Я говорил про то, что сущности в базе не существует. Но это не значит. что данных о ней не существует… Впрочем, я думаю мы друг друга поняли, просто вы решили принять определенную позу… Красиво…
Я говорил про то, что сущности в базе не существует.

Как это — не существует? Она там вполне есть. ER-диаграммы про нее нарисованы даже. Просто это не объект в терминах ООП. А сущность как раз есть.

Но когда дело переходит в аналитику, там уже даже сущностями не оперируют, там оперируют массивами.
Цена технологий кстати чаще не берется в расчет. Копейки, чаще всего, по сравнению с остальными пунктами. Но конечно так не всегда, но чаще.
UFO just landed and posted this here
UFO just landed and posted this here
Я яростный приверженец ООП, но ваша статья мне не очень понравилась. И вот почему:

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

2.
Используя объектное мышление вы легко можете решить любую задачу (очень важно что любую, абсолютно любую)
Даже NP-полную? Это как-то на рекламу смахивает, нежели на что-то разумное :(

3. Очень красиво начали рассказывать про инкапсуляцию, а потом свели все к геттерам и сеттерам. Ну зачем?

4.
И даже есть стандарты, которые могут понять хорошо ли вы выбрали абстракции и верна ли ваша декомпозиция (SOLID).
SOLID уже стандарт? SOLID не имеет прямого отношения к декомпозиции. SOLID скорее для первого приближения грамотности проектирования, нежели для верификации грамотности выбора абстракций и декомпозиций.

Но есть в статье и то, что мне очень понравилось:
1. Акцент на объектном мышлении.
2. Описание полиморфизма и наследования.
3. Качество изложения.

Спасибо.

1. Отправлю в личку.
2. Ну… Я могу конечно включить в текст статьи исключения задач которые я не могу решить, но я думаю не стоит. Тем более про NP-полную…
3. Да, это связанно с прошлой статьей. Просто сильно меня зацепило. Я вам дам ссылку и потом напишите мнение свое. Мне интересно
4. Да, наверное перегнул. Но SOLID явно может помочь понять в каком направлении идти.
2. Вы сделали акцент на том, что можно решить абсолютно любую задачу, чего делать не следовало. Я пытаюсь сказать, что если программист не мог решить задачу без ООП, то он не сможет решить задачу и с ООП, за редким исключением. ООП лишь ускоряет разработку и уменьшает сложность программного продукта.

4. Согласен, может. Но я строго рекомендую читать умные книги, а не расшифровку различных аббревиатур.
Еще раз спасибо.

2. Да, я сейчас подумаю как лучше написать эту часть
4. Это я оставлю, но сделаю формулировку мягче
>ООП лишь ускоряет разработку и уменьшает сложность программного продукта.

Ну еще оно все-таки упрощает разработку. Разве не может так оказаться, что без использования ООП сложность задачи превосходит возможности данного конкретного программиста, а с использованием ООП — оказывается в пределах возможного?

Лично я для себя понимаю, что многие из разрабатываемых мной в профессиональной деятельности продуктов я бы просто не решился бы даже начать делать без хороших инструментов — и для меня ООП один из таких хороших инструментов.
Полностью согласен, моя ошибка.
При чем здесь NP-полнота? Как вообще связаны ООП и алгоритмическая сложность?

Фраза «решить задачу» далеко не всегда трактуется как «придумать алгоритм полиномиальной сложности».
Мимо проходил.

1. Ну, я думаю имелась в виду статья Я не знаю ООП (действительно очень спорная статья)
2. А что NP-полные задачи уже нерешаемы? Многие из этих задач действительно можно легко представить в ООП стиле. Другое дело, что они решение будет находиться за продолжительное (в т.ч. нереально продолжительное) время.
3. Это скорее отсылка к той же статье, где getters&setters названы нарушением (!) инкапсуляции.
Упс. Уже ответили, пока мимо ходил.
Спасибо.

1 и 3. Именно. Но я посчитал не нужным давать ссылку в статье.

Про второй пункт спорить не буду. У всех есть своя правда. И решаемы и нет. :)
По поводу ссылки. Извините, если сделал то, что Вы не считали правильным. Просто не казалось, что привести ссылку было бы нетактично.
Ну сделанного не воротишь. :) Ничего страшного, это просто мой бзик.
1. Да, она (уже увидел в личке).
2. Я несколько в другом контексте критиковал это утверждение.
3. Это было сложно понять, учитывая, что я не помню уже всей сути той статьи.
Упс. Не успел увидеть, что мой коммент уже написали вместо меня :)
2. Думаю, это как-то слишком критично. Мне казалось очевидным, что если человек не представляет метода решения задачи, то ООП тут не помощник. Однако многие (не все, конечно) не столько даже алгоритмически, сколько технически сложные задачи легче решаются при декомпозиции. А объектная декомпозиция, имхо (в среднем по палате), одна из самых удачных.
Имею право. Автор — аспирант, преподаватель — человек науки, следовательно, не имеет права допускать ошибки уровня формализации, терминологии и прочего. Диссертацию же скоро нужно будет писать, а там за такое голову рубят (мне рассказывали).

Я был бы просто счастлив, получать жёсткие, конструктивные критики к своим статьям.
Да безусловно, критика отличная, я не спорю. :) Что то уже поменял, над чем то еще думаю. :)
Придумал вроде про пункт 2. :)
«Используя объектное мышление вы легко можете решить любую задачу (очень важно что любую, абсолютно любую)»
И может, даже важно еще и то, что далеко не любую задачу нужно решать с ООП. Где-то оно бывает лишним ведь.
Конечно, в совсем небольших программках оно точно лишнее, может где-то еще.
Главное — чтобы Ивана не унаследовали от печи, а то терминатор отдыхает.
Ага, Ивана унаследовать от печени, лёгких, челюсти (которая наследуется от зуба), сердца и почек (от каждой по отдельности). И его кота — так же от всего этого унаследовать. И объявить это полиморфизмом.
Это юмор был =)
И пример плохо продуманной объектной модели.
Элегантнее Вашего способа стрельбы себе в ногу еще не видал. Унаследовать Ивана от его ливера, причем по частям. =)
Увы, способ не мой, взято из реального проекта =)
(все имена и органы изменены)
Боги, что это за проект? =)
Очень интересно (если, конечно, это не секретная отечественная разработка).

К сожалению, не могу раскрыть данную информацию =)
В любом случае, там уже всё переделано. Так выглядел проект до рефакторинга.
Астрологи объявляют неделю ООП на Хабре. Количество холиваров увеличивается вдвое.
Страуструп жалел, что не придумал properties вместо геттеров и сеттеров ;-)
это можно поправить в С++ используя мета-абстракцию. Например qmake в Qt решает эту проблему.
С другой стороны в базовой поддержке это было бы удобнее, с этим тяжело не согласиться.
Если использовать «мета-абстракцию» такого рода, то можно даже в Лиспах все скобочки нафиг поудалять прекомпилятором :-D
Честно говоря не пойму про что статья. Автор нашумевшего топика крайне интересно рассуждал, вырывая отдельные куски из общего контекста и уверяя читателя в том, что никакой серебряной пули нет ни в этом куске ни в том что осталось. Т.е. он словно применил первый столп ООП (абстракцию) к самому ООП. Это больше необычно чем интересно.

Тут же я снова вижу примеры про печи/автомобили/самолеты/человеки/собаки и т.д.
Я думаю что ООП — прекрасная идеология, т.к. она понятна массам.

Потребовалось в начале века много программистов. Потребовалось методика их обучение. Методикой, основанной на математике, кучу народа не обучить — математику мало кто понимает на хорошем уровне.

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

Это была отличная, прагматичная мысль.
Очень интересная мысль.

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

Ну это мое дурацкое мнение.
А мне кажется что все верно. Именно так и появился ООП. Точнее он иначе то и не мог появится. В общем вы правы.
Что-то мне кажется он появился с появлением оконных интерфейсов.
Все эти толпы окошек, кнопочек, контролов (слегка разные, но с одними интерфейсами).

А документооборот тогда был в виде отдельных файликов и никакой особой сложности не представлял.
:)
Появились аппаратные возможности сделать проще жизнь как пользователей, так и разработчиков. Может не проще, но красивее точно :) Вот разработчики и стали рисовать окошки для пользователей, а для себя ООП языки :)
Именно потому, что программисты считают что бухгалтерия не имеет ничего общего с математикой, у 1С-бухгалтеров регулярно что-то там не сходится :)
Возможно вы имели в виду арифметику? :)
А в арифметике округление(a+b) == округление(a) + округление(b)?
А в элементарной арифметики нет операции округления. Даже в «общеинженерной» высшей математике этот вопрос задевали мельком, был специальный, емнип, курс или довольно большая часть какого-то курса.
А бухгалтерии — есть элементарная операция округления.
Она там далеко не элементарная вроде :)
Да. Потому что бухгалтерия — не элементарная арифметика.
Тут такое мнение у всех, кто никуда кроме мейнстрим-ООП-языков толком не лазил. Если знаешь только что-то одно — естественно оно кажется очевидным.
Ну, не знаю, я лазил (включая такую «эзотерику» как язык без ключевых слов :) ) и всё равно довольно близок к этому мнению: большинство множество задач реального «бытового» мира хорошо описываются средствами ООП. Задачи мира «абстрактного» в них не входят, наверное.
Так а я о чем? Нужны были не мега-мозги решать диффуры. Нужно было простых людей научить решать простые задачи. Придумали ООП, чтобы даже такие люди умели делать декомпозицию задач. Работает? Работает. Молодцы кто придумал? Молодцы.
Немного не так. Сначала придумали, а популярность получило оно значительно (по ИТ-меркам) позже.
Придумали ООП намного раньше, чем оно получило распространение. Распиарили — да, позже.
Вопрос в том, что именно распиарили или просто возможности и потребности дошли до того, чтобы массово использовать? Как не знаю, с автомобилем, например — сначала был игрушкой, потом элитным средством передвижения, а потом стал обыденностью, товаром массового спроса — чего тут больше пиара или технологической готовности и необходимости быстро перемещаться на значительные расстояния?
Идея «о гуманитарной основе» весьма оригинальна, но позвольте с Вами не согласиться.
Возниковение ООП было закономерным процессом в эволюции программирования: в процедурном программировании (которое находилось в непосредственной близости к просто исполнению набора машинных инструкций в ЦП) по мере усложнения обрабатываемых данных стало очевидно удобство вынесения данных и методов по работе с ними в отдельные независимые модули, и рассмотрение их как неких цельных сущностей, от деталей реализации которых мы абстрагируемся. Это легло в основу объектного подхода.
Опять же зайчики и рыбки. Посмотри вокруг. Кто и почему придумал пришить vtable к объекту? Что бы было если бы это не сделали? Как еще можно было бы решить вопрос с инкапсуляцией? Почему и зачем приняли все эти решения?
Мне кажется, что решение довольно очевидное при решении некоторого класса задач. Причина как у многих хороших решений проста — лень. :) Вопрос следует ставить почему это решение стало доминирующим в современном программировании.
Мне вот ни разу не очевидно зачем к каждой сишной записи было лепить по одному или нескольким vptr. При том, что простейшие задачи, вроде написания полиморфной операции сложения, через это не решаются.
Чтобы единообразно обрабатывать группу объектов со схожим поведением. Например, чтобы написать один цикл для отрисовки всех игровых объектов на экране, а не делать три. Это зачем я придумал :)
Ну и да, мой посыл был про то, что вместо посильнее подумать, взяли идею «все есть объект». И как-бы оно работает — с таким посылом даже школьники не валят все в кучу, а стремятся как-то разложить по полочкам. И это круто.
Так думали же. Парадигм разных много было и есть. Но «рынок» выбрал эту.
vtable придумал вроде Страуструп, для того, чтобы было не так тормозно, как в Симуле. Инкапсуляция была еще в С и к ООП отношения имеет ровно столько же, сколько оператор if, авторы статей типа этой подменяют понятия.
Vtable — полиморфизм (который тоже с ООП связан так же, как оператор if). Другие варианты реализации полиморфизма — статический (компилятор подсовывает нужную реализацию во время компиляции), при утиной типизации поиск идет не по смещению в vtable, а по словарю, медленно, но очень гибко. ООП можно сделать на vtable или duck typing. Равно как с vtable и duck typing можно ООП не использовать, делая все на интерфейсах без наследования. Зачем именно vtable — быстро и в рантайме. Разрулить во время компиляции еще быстрее, но не всегда возможно
Проблема в том, что люди пытаются рассуждать об ООП, как о какой-то абстрактной концепции. ООП — это новый этап в развитии методик промышленного программирования.
  • Инкапсуляция позволяет распараллелить процессы, тем самым ускорив разработку ПО.
  • Наследование снижает время на разработку, а значит и затраты, за счёт повторного использования кода.
  • Полиморфизм позволяет быстро подстраиваться под требования заказчика.

И, естественно, что ООП не противоречит существовавшим ранее парадигмам, а вбирает в себя всё лучше, что было.
Прикольно. :) Таких характеристик еще не слышал. :)
Сильно, тоже не видел в таком контексте ООП.
Ну, собственно говоря, эта идея уже достаточно давно будоражит умы, а ООП просто как один из инструментов. Эксперименты идут, например, Одерски в Scale пытается реализовать что-то похожее – проводятся аналогии с радиоэлектроникой, где есть некий обширный, но все же стандартизованный набор элементов и их характеристик, а уже из таких блоков строятся более объемные конструкции. Никто (99,9%) ведь не делает сам для себя резисторы, например.
Это называется компонентный подход и ему скоро 20 лет. Delphi же с его в том числе «невизуальными компонентами».
Достали вы со своим ООП. Всегда можно подобрать пример, красиво иллюстрирующий любую хрень. Даже для HQ9+ можно подобрать 4 примера «про пекаря». Почему все не бросаются писать на HQ9+…
Эмпирически говоря, ООП имеет более мощное множество красивых примеров, нежели любая другая хрень.
Ну это шедеврально! :) :)
если позволите, я попробую столкнуть ваш красивый пример с суровой реальностью. не холивара ради, а потому, что мне самому это слабо понятно.
газовую печть нужно зажигать спичкой, предварительно повернув ручку, и следить за давлением газа в баллоне (ну пускай у нас газовая печь от баллона работает). если газа осталось мало, нужно менять баллон.
электрическая печь включается поворотом ручки, следить не за чем не нужно.
как пекарь, умеющий работать с абстрактной печью, поступит в этом случае?
Уважаемый, уровень абстракции… Если вам надо это учитывать, берете и учитываете. Возможно у меня даже объектная модель поменяется, на таком уровне абстракции. Не исключено что я добавлю виды ручек для печей и т.д. Все зависит от задачи. ИСпользуя объектное мышление вы и должны найти оптимальный уровень абстракции для решения задачи.
ну а как бы вы спроектировали объектную модель в моём случае?
Ммм… накидал кое чего ниже. Если надо подробнее напишите.
да, пожалуйста подробнее. я пытался сейчас прикинуть объектную модель, но как-то громоздка получается. хочется ваш вариант услышать. потом, если хотите, свой опишу
Подождите, а вы что хотите увидеть? Что я как Девид Блейн скукожу реализацию до двух строчек?
я хочу увидеть, как мыслят другие люди. чтобы самому научиться объектному мышлению
А что мы тогда сейчас делаем? Какую задачу решаем? Что нужно в итоге?

Понимаете, когда разрабатываешь систему, в зависимости от ее типа и опыта проектировщика сразу проектируется система с учетом возможных изменений. Вы ведь согласитесь что тогда вносить изменения проще, не учитывая даже что используем ООП? :) Поэтому опыт так важен. И не важно какой подход вы используете. Если вы не думаете о том, что будут меняться требования, то это всегда сложности.

В нашем вопросе проблема того чего вы хотите. Вы потом внесете изменения требований, о которых я не предполагал и начнете говорить что ООП отстой. :) Мне не хватит опыта разработки приложений типа пекарь-печь, для того, что бы показать вам максимально компактное и гибкое решение. :)
вы знаете, в изменении требование и есть проблема. я спроектировал несколько систем с нуля, и мне всегда казалось, что абстракции выделены правильно, и к изменениям я готов. но потом открывались новые, абсолютно фантастические требования, и мне приходилось либо много переделывать, либо городить какие-то. поэтому мне хотелось (да и всё ещё хочется) посмотреть, как с такой задачей справляются другие специалисты. тем более что пример-то несложный.

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

Вы потом внесете изменения требований, о которых я не предполагал
да, в реальности всегда так и происходит. хотелось посмотреть, как вы выйдете из положения
ну да. но ведь так мы и работаем всё время. сегодня требования одни, а завтра — совершенно другие. как к этому быть готовым?
Красиво никак. И дело не в ООП. Дело в опыте.
ну вот, вот! скажите, как ваш опыт помогает вам быть готовым к изменениям требований?
Ай, случайно послал.

Да как вы можете предугадать все изменения? ДА никак. И при проектировании надо просто понимать где узкие места и там делать абстракции более гибкие. Это только опыт. Поэтому опыт так важен в программировании. Зная основные узкие места и возможные проблемы вы будете проектировать свою систему так, что любые изменения будут восприняты как должное. :)
нет, абсолютно серьёзно. задавая свой первый вопрос, я в глубине души надеялся, что у вас есть какая-то серебряная пуля, с помощью которой можно быть готовым к изменениям. у меня такой пули, кроме интуиции, нет. и вы тоже сказали, что только интуиция и опыт, и при серьёзных изменениях требований вы переделываете абстракции. так что спасибо за честность и за советы
НУ я бы сказал что если приходится сильно переделывать абстракции, то это ошибка проектировщика, который не предусмотрел возможность таких серьезных изменений. Не учел всех рисков. Желаю вам никогда с таким не сталкиваться. :) Честно. Очень обидно становится что вот о таких вещах не подумал. Сейчас бы сидел и улыбался, а приходится херачить всю ночь. :)
>это ошибка проектировщика, который не предусмотрел возможность таких серьезных изменений.

Ну вот же я и говорю, опытный проектировщик скорее всего не захочет вообще накладывать никаких ограничений на домен сразу, то есть сделает из объектов стуктуры данных. Лучше постепенно накладыват ad-hoc, чем вставлять костыли в систему, где уже существующий код завязан на более строгий контракт моделей.
А надо ли? Не проще ли ничего заранее не предусматривать, абстракции и наследование вводить только чтобы избегать дублирования кода, а не призрачной возможности изменения. Как минимум их не так жалко будет ломать, когда требования изменятся, но на существующие абстракции без костылей не ложатся — не будет мысли «в этот раз моя крутая абстракция от хранилища, позволяющая прозрачно менять SQL СУБД на SOAP-сервис не пригодилась, но обязательно пригодится, а пока впихнём костыль чтобы использование индексов можно было задать».
Так тоже можно. Но надо же понимать что есть понятия рисков. Просто лучше иногда «перебздеть» чем «недобздеть». :) Верно ведь?
В том-то и дело, что только иногда :) В системах с коротким жизненным циклом скорее всего абстракцией не успеешь воспользоваться. С длинным — то, на что ориентировался, устареет и в новых требованиях по адаптации будет то, что не вписывается в старую абстракцию. Скажем ваш Иван долго изучал как работать и с электро-, и с газовыми печами, вы ему сказали, что спички нужны будут, он каждый раз подходя к плите проверял не газовая ли она, чтобы не забыть зажечь спичку, но с облегчением вздыхал, видя что электрическая. И вот привезли газовую, вы достаёте учебник по спичкам, чтобы научить Ивана их зажигать, но видите в спецификации, что у неё электроподжиг и по интерфейсу она не отличается от хорошо знакомой Ивану электрической, только тайминги немного другие.
Да, возможно что то в этом есть. Но я бы сказал что тут скорее дело случая. Повезет или нет. Закономерностей нет. :)
Тогда задачка по простейшей теории игр: ставка на исход какого-то события с неизвестной вероятностью N человеко-часов, можно сделать её до исхода, можно после, если сделал до исхода, то ставка теряется, если после — нет. Какая оптимальная стратегия, если известно что вероятность меньше единицы? :)
Стратегия — прилагать все усилия для того чтобы оно не устарело :)
Т.е всеми силами вставлять палки в колеса прогресса.

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

как-то так.

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

Что вы делаете? А придумываете интерфейс. И одновременно даете команды:
— учить Иванов
— делать печи

И никаких спичек не будет! Будет автоподжиг — вы ведь так задачу поставили разработчикам печей. :)
А если к вам приходит разработчик угольной печи и говорит «не — не получится, кто-то ж должен уголь насыпать в печь — это ж не газ и не электричество». Вы ему сможете смело ответить — А это все потому что вы не правильно абстракции выбрали! :)
Это называется leaky abstraction. Т.е. когда знаний о свойствах абстрактной сущности не хватает и приходится лезть в реализацию.

Характернейшая проблема наследования, не так ли?
Точнее объектная модель железно поменяется. У меня будут пекари которые умеют работать с печами электрическими и печами газовыми. Но они все будут пекарями. Они один хрен будут готовить и все пекари будут уметь готовить. И я это сделаю с минимальным дублированием кода.
Здесь, мне кажется, вы ошибаетесь.
Если поменяли печь — нового пекаря создавать как-то неправильно.
нам не придется переписывать нашего Ивана для каждой из печей


будут пекари которые умеют работать с печами электрическими и печами газовыми


оО
Это и есть — полиморфизм.
Но его еще нужно понять.
Все Пекари продолжат работать с АбстрактнойПлитой, но конкретный ПекарьДляГазПлиты будет работать с газом, а ПекарьДляЭлектроПлиты с с эл-ом. Также придется добавить управленца (Фабрика), который будет следить, чтобы к ГазовойПлите подходил только ПекарьДляГазПлиты, а к ЭлектроПлите — только ПекарьДляЭлектроПлиты.
При этом основные задачи пекаря останутся в классе Пекарь, и не будут захламлены особенностями конкретной плиты.

Также можно вместо наследования от Пекаря применить агрегирование, и выделить специфику работу с плитой в свойство Пекаря НавыкРаботыСПлитой. А Фабрика по-прежнему будет следить, чтобы к ГазовойПлите подходил Пекарь с навыком НавыкРаботыСГазовойПлитой, а к электро — с НавыкРаботыСЭлектроПлитой.

Если в Фабрике накопится много условий if(газ){...}else{...}, то имеет смысл выделить АбстрактнуюФабрику, которая создаёт абстрактного Пекаря и абстрактную Плиту, а ФабрикаДляГаза и ФабрикаДляЭлэктричества будут создавать соответственно конкретных пекарей и плиты. А ГенеральныйДиректор будет выбирать, на какую пекарню поставить ФабрикуДляГаза, а на какую — ФабрикуДляЭлектричества.
Какой у вас опыт разработки реальных проектов в реальных командах?
Ммм… Реальных проектов, в реальных командах от трех человек и более с третьего курса. Лет семь получается. В качестве тимлида и ведущего года три-четыре.
Но какое это имеет значение?
Наверное значение в том, что ООП позволяет частично вместо документации использовать сам язык для того чтобы усилить соблюдение договоренностей об интерфейсах между людьми из разных под-проектов.
И чем больше людей в командах, тем важнее что сам язык запрещает доступ к каким-то данным, вместо того чтобы это делал человек словами «но ведь мы же договорились!».
Понятно что от всего не спасет, но облегчит.
Одно дело слова теоретика, совсем другое личный практический опыт.
Хорошая статья, можно кому-то подкинуть для понимания. Хотя я обычно на транспортных средствах ООП показываю.
Вы уж извините, но примеры вы приводите просто ужасные. Попытка проанализировать ООП на таких примерах не более чем умозрение. ООП широко используется в библиотеках и инфраструктурных задачах, задачах где требуется написание обобщенного кода, тут возможности ООП раскрываются на полную катушку. Но 90% прикладного кода — это не обобщенный код, это очень частные сценарии, здесь нечего абстрагировать, наследовать, да и инкапсулировать тоже, задачами поддержания данных в непротиворечивом состоянии занимается СУБД, а не прикладной код, прикладной код лишь парсит ошибки в бесконечных сценариях. Практически все бизнес-приложения, которые я видел использовали функциональную декомпозицию.
«прикладной код лишь парсит ошибки в бесконечных сценариях» — эмм… Это как так?

«Практически все бизнес-приложения, которые я видел использовали функциональную декомпозицию.» — это вы что под этим подразумеваете? Это вообще как? Я тоже много видел бизнес приложений. И все использовали при проектировании ООП.
Рассмотрим типичное приложение: ИС объемом порядка 50к строк. Сущностей, представляющих доменные объекты около 20. Получаем несколько тысяч строк на каждую сущность. И бОльшая часть этого представляет собой application logic, а не domain logic. Ну там знаете, сходить в БД, отправить сообщение через шину, сделать удаленный http-запрос. Все классы, которые это делают не моделируют ничего из домена. Это сервисы. Они statless, то есть это по сути дела процедуры. Вам привели уже выше хороший пример. Типичный прогер не изобретает крутые абстракции. Он пишет дергалки каких-то готовых подситем гоняя данные туда-сюда, пишет сценарии, если хотите обвязку вокруг абстракций, абстракций от источников данных.

> использовали функциональную декомпозицию.» — это вы что под этим подразумеваете?

То, что приложения реализуются обычно по user-stories. Заказчик описывает сценарий. Программист с использованием уже готовых сценариев или с нуля кодирует этот сценарий в виже нового сервиса. Сервис прокидывается на UI, пишутся соовтествующие тесты на этот сценарий. Что касается ООП моделирования, то это все сводится обычно или к мизерному применению ООП, либо вообще к реляционному проектированию, проектированию от базы. Эта та самая кучка доменных сущностей. В которых зачастую умышленно ограничивают ООП, что бы не накладывать заранее ограничений: нам ведь еще предстоит реализовать еще сотни или даже тысячи сценариев, и мы не знаем точно эти ограничения. Лучше ограничения реализовывать ad-hoc, в сервисах. Это дико не технологично, но без гибкости проект долго не протянет.
Вообще application logic и domain logic это лишь разные уровни приложения, и чаще application logic не будет простыми stateless классами и может быть даже сложнее, чем domain logic (например, тот же ORM).

Про user-stories тоже не ясно. Это лишь один из методов проектирования и может быть применен к функциональной и объектной парадигме.
А точнее user-stories это правильно, язык для общения заказчика с программистами. И декомпозиции здесь никакой нет — дай двум независимым программистам один и тот же набор сценариев, и они сделают два разных приложений (от «всё в одном классе», до тысячи классов).
Да, насчет объектной декомпозиции. Тот же Эванс имхо лучше всех на данный момент описал то, как это нужно делать. Объектная декомпозиций делается итеративно, с активным участием заказчика и с обучением его моделированию. Если заказчик не готов выдавать требования в виде требований по модификации модели, а только в виде частных случаев (user-stories), то выделить самому базис довольно проблематично.
>и чаще application logic не будет простыми stateless классами и может быть даже сложнее, чем domain logic (например, тот же ORM).

А я разве написал, что applogic stateless классы простые? Как раз это самая сложная часть приложения. ORM кстати говоря, это infrastructure, а не application logic. Инфрастуктура, кака я писал, по определению является обобщенным кодом, для которого ООП то, что доктор прописал.

По поводу stateful applogic — за это по-хорошему нужно бить по рукам, так как это: потенциальные threading issues, проблемы кластеризации, сложности отладки, тестирования. Поверьте, я знаю о чем говорю, сейчас как раз такое приложение поддерживаю :)
>Про user-stories тоже не ясно. Это лишь один из методов проектирования и может быть применен к функциональной и объектной парадигме.

Очень странно использовать для проектирования один подход, а для реализации другой. Кстати, я не отрицаю объектной декомпозиции, оно имеет право на жизнь, но довольно ограничено. Такие проекты хорошо описаны у Эрика Эванса в его книге DDD.
А, раз речь про DDD, то ок со слоями. А то на слои тоже делят по-разному, у Крэг Лармана вообще application logic layer это те же business объекты, только которые уникальны для конкретного приложения.

А про ограниченность объектной декомпозиции вопрос открыт. Responsibility Driven Design (который и основывается на объектной декомпозиции) до сих пор считается самым эффективным методом для построения ОО-приложений, на основе его придуманы другие техники: DDD (акцент на Ubiquitous Language), TDD (на тестах), BDD (на user-stories).
>до сих пор считается самым эффективным методом для построения ОО-приложений,

Тут все очень зависит. Во-первых глупо городить ООП там, где его реально мало, когда домен по природе худой. Но даже с толстыми доменами проблема. Был в Москве один проповедник DDD, на многих конференциях про это рассказывал. На последней конференции он вдруг говорит, «ребята, даже не думайте использовать это DDD — распрощаетесь с модульностью». То есть он взвесив инкапсуляцию и модульность выбрал модульность. С модульностью нужно пояснить: ООП дает отличную модульность на уровне одного объекта и никудышнюю на уровне группы объектов — все знают почти про всех. Да, там есть CDI и так далее и так далее, но задумываешься: оно того стоит, городить эти воздушные замки? Может по-бырому заговнокодить, баги зафиксить и баста? Мы же знаем, что решение последних 20% задачи занимает 80% времени. Может нам проработать дизайн на 80% затратив только 20% времени? Проблемы явно есть, вопрос очень сложный, вердикты выносить рано.
А это смотря как объекты между собой общаются.
Грубо лезут в кишки — т.е вызывают чужие методы.
Или без жестких связей посылают сообщения «а у меня тут такое случилось… кнопку нажали» — и все кто хотел — добавился Listener-ами к этому.

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

Т.е логика запрятана в самом факте вызова И поменять ее нельзя снаружи. В сообщениях запрятанную логику можно снаружи переопределить в некоторых рамках.
Прокси/заместитель, внедряющийся посредством IoC-контейнера в цепочку вызовов независимо и от клиента, и от сервера? Интерфейс, да, должен тот же реализовывать (но не исключительно его), но по времени связывания варианты есть вплоть до каждого вызова.

А вот проксировать сообщения независимо от отправителя и получателя не получится в схеме все-всем (а-ля общая шина), ведь получатель подписывается на сообщения этого вида и максимум что может сделать файервол это ответить быстрее сервера, но это не предотвратит выполнение им нежелательной, а то и вредной работы.
Видел я такой код на листенерах. Лично мне не понравилось. Уж лучше в сервисе из одной точки скоординировать всю работу. А с листенерами одна путаница, то и дело, что клацаешь в IDE кто кого вызывает и на листике рисуешь.
Статья не очень понравилась тем, что рассматривает статический случай.
А вместо этого людей реально интересует динамика (что всплыло при обсуждении).
Не так важно как мы красиво построили систему. Более важно что произойдет в случае необходимости ее поменять.

ООП слегка развязывает руки — при внесении модификаций в систему, разбитую на части общающиеся через четко прописанный интерфейс мы получаем возможность менять систему по очереди независимо.
Т.е сначала одну часть (не ломая работоспособности), затем другую.

Точно так же мы это можем делать при использовании библиотек (не важно ООП или библиотек функций).
Изменили, версия другая, но старый код работает (почти всегда ;)

Если ООП не использовать — то нет повода думать о разбиения системы на части, с четко прописанными интерфейсами (слабо изменяющимися во времени). Т.е никто не запрещает про это думать :) Но сам язык не намекает на это. ;)

Т.е плюс в том что не приходится затрагивать всю систему при внесении изменений.
Минус в том, что изменения очень часто не помещаются в придуманные нами интерфейсы и появляются извращения :)

Ну как с файлами — сначала были на локальном винте.
Потом появились права доступа — оп… вдруг оказалось что файл может существовать, а прочитать его низя (а старый софт то не знает! хотя интерфейс доступа к файлам остался тот же).
Потом появились сетевые хранилища — оп… вдруг оказалось что файл начал читаться и с какого-то момента перестал или чтение вдруг занимает минуты, а не секунды (чтение с сервера в другой стране). А старый софт то по прежнему не знает… интерфейс то тот же… Ни тебе прогрессбаров «скачивания» файла, ни оптимальной работы с данными (как начнет открывать для определения типа по содержимому — тут мы на минут 30 и зависнем).

Абстракция «файл» — хорошая как бы. И интерфейс доступа вроде как не менялся — открыл, прочитал, записал, закрыл. Но… протекающие абстрации никто не отменял. Если мы не меняем интерфейсы — все больше в этих абстракциях появляется дырок.

Зато экономим время программистов — им не приходится думать о «открыть локальный файл, открыть сетевой файл, открыть файл с DropBox»…

ps. да это все не относится именно к ООП, но и к нему тоже, только примеры будут другими.
Как-то очень тонко ОО-языки намекают на разделение на части и фиксацию интерфейсов — god-object порождение ООП :) Соглашения и (само)дисциплина тут значат больше чем языковые возможности и, тем более, намёки.

Но в целом согласен, преимущества ООП перед процедурным подходом больше заметны в динамике. Но скорее в намёках на необходимость разделения на части, а необходимость фиксировать хоть как-то интерфейсы между ними лишь следствие.
>Если ООП не использовать — то нет повода думать о разбиения системы на части, с четко прописанными интерфейсами

О, а не расскажите как вы это готовите. У меня вот сложилось впечатление, что самый лучший способ делить систему на части, это вводить процедурные интерфейсы — фасады. Или что бы совсем надежно, сервисы сделать ремотными, то есть SOA. Что бы не было соблазна как-то обойти интерфейс :)
TDD? Чтобы тест оставался простым и быстрым тестируемые подсистемы (юниты) должны быть максимально друг от друга изолированы, но чтобы общаться им нужны интерфейсы — система «сама», без лишних усилий бьётся на части и обрастает интерфейсами (особенно в сильно статически типизированых языках).
Ну так вот я про то, что интерфейсы прямого отношения к ООП не имеют. Я их могу ввести и без ООП (SOA)
Конечно, не имеют. Но если бы в ООП их (в широком смысле) не было бы, то во многом это и не ООП был бы.
Кстати вот это с интерфесам чистой воды байка. Это упрощает мокирование кода, модульности это практически не дает. Что бы добиться модульности нужно здорово код встряхнуть, просто интерфейсами тут не отделаешься.
Вот вы говорите «совсем надежно». Это значит кто-то нарушает договоренности зафиксированные, скажем, в документации? В рамках команды им можно просто по голове за такое дать :))
Другое дело если у вас нет влияния на разработчиков использующих вашу часть системы…

ps. и это нам показывает что ООП не достаточно. Т.е уровня protected свойств не хватает уже. Нужны proctected объекты в рамках… модулей?!

pps. а исходники у вас открыты для всех? Если нет — в конструкторе принимайте параметр — пароль. И без пароля чужих не допускать! :-D
… а если открыты — часто менять и смотреть что ломается ;)
> В рамках команды им можно просто по голове за такое дать :))

Не хочется проблему эскалировать с технического уровня на организационный. Потому как, увы, я могу менять код, но не могу менять людей, который этот код пишут. Многие любят по-бырому накатать код кое-как, а когда начинаешь говорить типа это не правильно — мега аргумент: оно уже работает. Угадайте на чью сторону становится руководство в таких случаях?
Руководству нужны «фичи» и оно не думает о будущем. Проблемы решаются по мере поступления :)

Это не техническая проблема. Это проблема взаимодействия разработчиков.

Называйте классы в виде Class324324 и меняйте 324324 на другой автозаменой каждый день. Это техническое «решение», которое же не решит реальную проблему :))
Не, ну SOA имеет другие плюшки кроме «модульности через нихачу» :)
Не советую без особой необходимости лезть в SOA — часто это ведёт к большому количеству дублирующего кода и практически всегда к усложнению поддержки системы. SOA хорош, когда у вас есть с десяток независимых проектов, выполняющих строго разделённые функции. Например, есть email сервер, поисковая система, сервис хранения фотографий и т.д. Тогда да, SOA идеально подходит: разделяй и властвуй. А когда service1 оперирует теми же объектами предметной области и использует ту же базу данных, что и service2 — это очень, очень плохо.
Ну я как бы в курсе, уже года 4 разрабатываю SOA-приложения :) Все это вопросы модульности. В SOA модульность — вопрос выживаемости. Не видел вообще модульных не SOA приложений. Везде гребаный слоеный пирог.
А, ну тогда извините :)
А что тогда?
«интеллектуальные агенты»?
Это когда кусок кода решает «мне нужны сейчас фото» и копируется на сервер где они хранятся и там исполняется. А потом с этими результатами копируется на сервер где хранится почта и продолжает обработку.
Ну я грубо :)

При таких задачах речь идет уже о распределенной среде и тут как бы ООП уже непричем…
Почему ООП не может быть методом реализации распределенной среды? ООП разве предписывает, что сообщения (вызов методов) должны передаваться (вызываться) в рамках одного процесса, хоста и т. п.?
А вы на реализации посмотрите — типа RPC, Corba…
Главное — что вызывающий О1.м1 ждет завершения выполнения О2.м2.
Это уже несколько другое. Вы передаете колбек для обработки принятого результата. А это уже способ выкрутится :)
Очереди заданий, форки/нити и т. п. — тоже способ выкрутиться из ограничений ООП парадигмы?
Мне кажется, прозвучавший на этой неделе протест (возражение) против ООП — по сути из ничего. Автор просто попёр против «общности», заведомо не став рассматривать конкретные частности. И спор был не против ООП, а против трёх-четырёх принципов. Вроде — этого я не увидел, это не важно, это не ясно… Ну и где ООП?
По-моему ООП всё же шире. его можно сузить до трёх-четырёх пунктов — но только в педагогических целях. А на практике — по сути всё сводится к связи неких данных и набора функций, что их обрабатывает. Т.е. по сути к инкапсуляции. А есть ли там наследование и полиморфизм — это уже вопрос второстепенный.
То ли дело обмен сообщениями!

Тут только объект вызывает второй объект. И второй даже не догадывается кто его вызвал.

А с сообщениями — не факт что на твое сообщение кто-то ответит вообще. А если ответит — то он значит должен знать кому отвечает.
this.send_message(reciever, this, 'message');?
Вот вот — самому вручную передавать свой this. Язык в этом никак не помогает.

Причем контекст исполнения (стек исполнения) остается какой? Мы из О1.м1 вызываем О2.м2 из которого снова О1.м3 при этом все еще остаемся внутри не завершенного первого метода О1.м1.

Сравните с сообщением — отправили и вышли из метода не дожидаясь результата.
А должен помогать? Зачем? И кто сказал, что вызов синхронный?
Тоже считаю, что в ООП на практике основное это инкапсуляция в одной сущности данных и процедур (в мэйнстриме) их обрабатывающих. Но полиморфизм с наследованием тоже часто используются, всё-таки возможность работать с сущностями разных типов единообразно, без многочисленных instanceof, дорогого стоит, а наследование основной механизм обеспечения этого., даже в языках с утиной типизацией.
Верно. Наследование и полиморфизм — это лишь инструмент для уменьшения количества кода.

Инкапсуляция — это, я бы сказал, основное требование к проектируемому вами объекту. Если вы соблюдаете принцип инкапсуляции, то жить будет проще тем, кто это объект использует.
Интерфейсы, примеси, лямбда выражения, делегатопредикатоколбеки – это все появляется в ООЯП не просто так. Эти красивые штуки привносят скорее процесс/функциональность, чем данные. Они, наверное, поэтому и появляются, что ООП не все задачи решает эффективно.

Собственно говоря, данные — это ширпотреб, о которых не всегда стоит так сильно заботиться, как делает это ООП. Зачастую более важны процессы и результаты, чем данные, которыми они оперируют. Например, инженер программирует на ЯП. Неважно какой программист (Вася, Петя или Джон Ресиг) и какой ЯП он использует. Важно (для заказчика прежде всего) лишь то, как (время, качество, кривая входа, стоимость поддержки и тд.) он это делает и что в итоге получается. Понятно, что скорее всего Джон сделает это лучше Васи, но это совсем не факт.

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

И в конце, хотел бы задать вопрос автору, как бы он решал подобную задачу:
хочу чтобы «нарисовать карандашем на бумаге».
И в конце, хотел бы задать вопрос автору, как бы он решал подобную задачу:
хочу чтобы «нарисовать карандашем на бумаге».

Про какую задачу вы говорите? Как проектировать/реализовывать процесс? Процесс, это есть изменение состояний объекта во времени по некоторым правилам и взаимодействие объектов. Описанием процесса не занимается ООП. НО используя ООП этот самый процесс можно реализовать и спроектировать объекты участвующие в этом процессе.
По результатам дискуссии можно сказать что ООП устарел! :)

DSL рулит.
msdn.microsoft.com/ru-ru/library/aa302173.aspx
(понравилось в начале описание процесса упрощения разработки с помощью введения абстракций).

ООП позволяет свои личные абстракции делать частью языка (и соответственно проверять на уровне компилятора), а DSL позволяет оставить в языке только свои личные абстракции, убрав базовые (которые из ООП не выбросишь).
Думаю DSL не взлетит, как очередная серебряная пуля. Краеугольный камень разработки: основная стоимость разработки — это стоимость поддержки. Вносить изменения сильно дороже, чем разрабатывать с нуля. DSL тут никак не помогает, а даже усугубляет. Вот через 2 года мы понимаем, что фундамент, заложенный в дизайн DSL — уже не актуален, новые требования уже не реализовать без костылей. Что делать? Универсальный ЯП, на то он и универсальный, что можно любой изврат ляпать.
Вносить изменения сильно дороже, чем разрабатывать с нуля. DSL тут никак не помогает, а даже усугубляет

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

Вот через 2 года мы понимаем, что фундамент, заложенный в дизайн DSL — уже не актуален, новые требования уже не реализовать без костылей. Что делать?

Править DSL, благо это несложно. Но это ошибка класса «неправильно спроектирована БД, новые требования уже не реализовать».
Ну наверное да, ошибка эта того же класса. Но все равно моя идея в том, что краеуголную проблему это не решает. Когда нас не устраивает фундамент — это большая беда. Что структура БД менять гемор, что DSL
… но поскольку к изменениям структуры БД современные проекты относятся весьма пофигистично (в том смысле, что это рутинный challenge), то и изменение DSL их особо не запарит.

Собственно, изменение DSL ничем не отличается от изменения объектной модели сервисного слоя приложения.
Разница есть.
Мы взбираемся по пирамиде абстракций.
Чем выше — тем меньше шансов что фундамент (модель) окажется не правильной.
Потому надо не про DSL говорить, а сравнивать DSL и ООП. И тут шансы у DSL выше.
Хоть это все еще и не идеал :)

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

ps. а когда не устраивает фундамент — мы строим новый дом и переезжаем :)
Т.е не решена пока (вроде?) проблема миграции данных из модели в модель.
>Чем выше — тем меньше шансов что фундамент (модель) окажется не правильной

Ну хз конечно, но мне почему-то кажеться, что как раз наоборот, чем более абстрактуню опердень мы пишем, тем шансы ошибиться больше. Как там все эти проповедники TDD советуют: только после реализации кейса мы ищем дублирования, и выделяем абстракции. То есть признаем полное фиаско в проектировании top-down и юзаем плебейское bottom-up.
как раз наоборот, чем более абстрактуню опердень мы пишем, тем шансы ошибиться больше

Вы, кажется, не совсем понимаете смысл DSL. DSL как раз максимально конкретен (в отличие от абстрактного языка программирования общего назначения), и оперирует он ровно теми же терминами, что и бизнес. Поэтому при правильно проведенном анализе бизнеса (а без него вообще ничего нельзя написать) DSL получается практически без затрат.
Это вечная путаница слов «абстрактно» и «конкретно». Разные люди их понимают с точностью да наоборот. :)
Статью прочтите (хоть бегло).
Там как раз и расхваливают DSL за то что изменения в модели можно вносить часто и безболезненно.
Т.е оно само меняет все взаимосвязанные части.
Вот только остается вопрос что делать с существующими реальными данными… но там это тоже упоминается.
Ок, прочту :) Тока уже скептически думаю о том, что, как всегда DSL позволит нам безболезненно менять части если… мы правильно этот DSL спроектируем. А если неправильно, увольте, думать лучше было нужно… I want to believe… что же, посмотрим, посмотрим :)
Что-то мне кажется что это "… если… мы правильно.." отмазка фанатов парадигмы :)

Надо думать о другом — какой из доступных на сегодня вариантов что дает.
А точнее — какой из вариантов построения систем больше всего облегчит изменения ее.
Даже если нас попросят из носорога сделать бабочку :)
1С впереди планеты всей? :)

А если серьезно, то фактически разработка объектной модели приложения и есть разработка DSL. Что означают все эти требования к семаническому именованию классов, объектов, методов и т. п., как не разработку нового языка со старым синтаксисом, но новой семантикой?
DSL еще и убирает не нужные базовые — Строка, Число, Дата…
А ООП этого не может сделать.

Т.е получаем новый язык, но чистый — только то что нам нужно. Собственно потому этот L и DS :)
Это уже от реализации зависит.
Печь — интерфейс. Зачем тут здесь наследование не понятно. А без наследования ООП вовсе не ООП, о чем и говорилось в той самой статье.

На самом деле не очень и понятно зачем им иметь общий интерфейс (скрипты работы с печкой обобщить не получится, поэтому пользователь всегда должен знать тип печи, и скорее тут нужно два модуля пекаря без состояния с общим интерфейсом типа трансформировать тесто в хлеб, опять нет ООП). Хотя понятно, что тот, кто изучает яву после С уверен, что все достижения человечества и есть ООП.
Эх, не хватает кармы плюсануть. Все правильно пишете! Абсолютно здравый, прагматичный подход.
У всех печей, как и у всех пекарей, есть что-то общее в рамках этой предметной области, нет? Если да, то можно (а следуя DRY нужно) выделить это общее. А ООП лишь средство выделения, может не оптимальное, но рабочее и, имхо, интуитивно понятное.
«А без наследования ООП вовсе не ООП» — это заблуждение. Это лишь один из инструментов.
Остальные инструменты вовсе не oop-specific. То, что пытался донести оппонент своей статьей. Проблема ооп-фанов, на мой взгляд, в том, что ооп — единственное, о существовании чего им сказали сразу же после объяснения того, что такое цикл. Типа, есть не-ООП — мрачная сишка без h файлов и php с глобальными переменными и светлый мир ООП с инкапсуляцией и абстракцией. А упоминание того, что инкапсуляция и с помощью линкера и h файлов доступна, объявляется предтечей ООП.
Вообще, спор на тему «защиты ООП», объектного мышления, инкапсуляции и прочего SOLID не может считаться состоявшимся до тех пор, пока в нём не обсудили, должен ли быть класс Square потомком класса Rectangle, или ровно наоборот.
Вроде уже обсуждали на днях, правда с окружностью и эллипсом.
А господи, я то думал, обсуждение закончилось, а не тут то было.

Во-первых, не путайте реальность и ваше восприятие. Какие-то отрицательные эмоции, желание выставить ООП злом… Не путайте эмоции с художественными приёмами и не пытайтесь, пожалуйста судить, о моих намерениях — у вас это плохо получается.

Во-вторых, во всём тексте достаточно заменить «ООП» на «ФП», «объект» на «функцию», «наследование», «полиморфизм» и «инкапсуляцию» соответственно на «композицию», «сопастовление с образцом» и «отсутствие состояния», и получится вполне справедливый текст про функциональное программирование. Не верите? Ну смотрите:

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


Могу то же самое написать для модульного программирования. Т.е. то, что вы описываете как «путь ООП», «принципиально новый подход к проектированию» ничем не отличается от подходов в других языках. Различаются только какие-то инструменты. Все эти декомпозиции, абстракции и т.д. есть везде, но вы почему-то считаете, что только в ООП их можно реализовать «как надо».

Названия инструментов языка, кстати, не просто так подобраны. В примере с пекарем наследование действительно можно заменить на композицию функций, а объект «печь» заменив на замыкание «испечь». При этом гибкость получившегося кода будет гораздо выше, плюс вы избавитесь от связки классов по наследованию.

С полиморфизмом, правда не совсем совпало: для замыкания «испечь» не понадобится сопастовление с образцом. Вообще ничего не понадобится — на место шагов приготовления можно будет поставить любые функции, подходящие по сигнатуре. Идеальная расширяемость без необходимости наследования.

Пример инкапсуляции отвратительный — вместо метода `setOn()` (или как он у вас там) должен быть метод `cook()`. Соответственно, дальше всё описание сыплется.

В-третьих, про типизацию я вроде привёл пример, перечитайте. Не доходит? Перечитайте ещё раз.
И да, не забудьте про null — это одна из самых распространённых ошибок из-за недостатка типизации таких языков как Java (в C# вроде чуть полегче). Кроме того, в статье я забыл упомянуть про ADT — исправился в комментариях.

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

Вот очень люблю такие высказывания. «Я сказал и всё! Не смейте со мной спорить!»

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

И снова: расширьте понятие объекта до просто некой законченной сущности в программе (а не конкретно инстанса класса) и получится описание любой парадигмы.

В итоге что такое ООП из текста так и непонятно.
Черт, я вам ниже ответил.
«Во-вторых, во всём тексте достаточно заменить «ООП» на «ФП», «объект» на «функцию», «наследование», «полиморфизм» и «инкапсуляцию» соответственно на «композицию», «сопастовление с образцом» и «отсутствие состояния», и получится вполне справедливый текст про функциональное программирование.» — ну да, прикольно, но какое это отношение имеет к ООП? Вы про то, что одни понятие ООП подменило другими? Даже если так, то новые понятия гораздо проще воспринимать. Разве нет?

«Пример инкапсуляции отвратительный — вместо метода `setOn()` (или как он у вас там) должен быть метод `cook()`.» Хм… Мне кажется вы так и не поняли что такое инкапсуляция.

«И да, не забудьте про null — это одна из самых распространённых ошибок из-за недостатка типизации таких языков как Java (в C# вроде чуть полегче).» — если честно, не понял глубинный смысл вашего высказывания.

«И снова: расширьте понятие объекта до просто некой законченной сущности в программе (а не конкретно инстанса класса) и получится описание любой парадигмы. » — да нет, уважаемый, как раз это вы хотите сузить. Понятие объекта именно ООП вынесло на тот уровень, когда GoF могут с удовольствием создавать всякие мосты, фабрики. И нами это воспринимается нормально.
Вот вы мне щас вообще мозг вынесли.

Я прекрасно понимаю, что такое инкапсуляция. Опять же, в SICP (почитайте таки для саморазвития — книга стоит на самом высоком месте в матрице компетентности программиста от Google) во 2-3 главах приводятся отличные примеры абстракции и инкапсуляции (см. реализацию работы с декартовыми и полярными координатами). А ваш пример отвратителен, поскольку вы подменяете одно понятие другим — логическое действие объекта «прикотовить» вы заменяете на установку его состояния на «включена». С точки зрения модели функция «включить плиту» бессмысленна, поскольку не приводит ни к каким значимым результатам. Именно по этой причине названия «начать работу» или «разогреть» являются гораздо более правильными в данном случае, но к установке свойств они не имеют никакого отношения. И да, эта функция может выполнять те же функции, что и «включить» — начать уменьшать переменную с топливом, увеличивать темпетаруту и т.д., и будет являться прекрасным примером инкапсуляции. Только вот к свойствам объекта и геттерам с сеттерами, о которых я говорил в своей статье, это уже не будет иметь никакого отношения. А для DTO объектов вы не придумаете примера, в котором установка свойства приведёт к каким-то действиям — просто по определению, потому что DTO-объекты на то и data transfer objects, что просто переносят данные и не выполняют никакой логики. Иначе это уже не DTO.

ну да, прикольно, но какое это отношение имеет к ООП? Вы про то, что одни понятие ООП подменило другими? Даже если так, то новые понятия гораздо проще воспринимать. Разве нет?

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

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

«И да, не забудьте про null — это одна из самых распространённых ошибок из-за недостатка типизации таких языков как Java (в C# вроде чуть полегче).» — если честно, не понял глубинный смысл вашего высказывания.

Вы не понимаете, но при этом обвиняете меня в глупости? Вот это круто. Я надеялся, что вы хотя бы сможете постоять за своё мнение.
Строгая типизация означает строгое соблюдение теории множеств — переменные одного типа (множества) не могут стать переменными другого типа, кроме случая, когда одно множество является надмножеством другого. Отсюда лезут косяки современных ОО языков. Значение null принадлежит сразу всем множествам, при этом не выполняя действия других объектов из этих множест. Если ваша функция принимает объект типа SomeObject, то она с удовольствием примет и значение null, но вызвать его методы или получить свойства уже не сможет — null чужой для множества SomeObject объект. Изобретение Тони Хоаром ссылки null было ошибкой на миллиард долларов, ведущая к многочисленным багам и крахам программ.
Есть и куча других примеров косяков ООП в плане типизации. Сама иерархия объектов противоположна теории множест — наследники имеют больший функционал, а значит с точки зрения множест являеются надмножествами, а не подмножествами. Конечно, необязательно опираться на математику при разработке, но тогда вы теряете очень сильный формальный язык, читайте — сильный инструмент верификации программ.
Ещё один пример — сужение типа за счёт явного приведения. Например, приведения Object к String. Современные языки активно используют этот инструмент, но не заставляют программиста проверять результат — в ООП неправильное приведение это «исключительная ситуация», хотя в других языках использовалась бы штатная проверка (дело не в механизме эксепшенов, конечно, дело в самом подходе ОО языков: эксепшены используются не в каких-то крайних случаях, а в самых обычных штатных ситуациях).
Про типизацию можно долго говорить, показывая в ОО языках элементы как статической, так и динамической типизаций. Но вы этого тупо не понимаете, потому что не знаете, что может быть по другому.

да нет, уважаемый, как раз это вы хотите сузить. Понятие объекта именно ООП вынесло на тот уровень, когда GoF могут с удовольствием создавать всякие мосты, фабрики. И нами это воспринимается нормально.

Во-первых, вы GoF ещё раз перечитайте. Там несколько раз говорится, что паттерны решают проблемы, с которыми ООП не может эффективно справиться. Так что чем больше паттернов, тем больше задач, с которыми голове ООП не может нормально справиться. Во-вторых, о да, понятие «что угодно» гораздо уже чем понятие «инстанс класса». Вы хотя читайте, что вам пишут. В ООП объектом называется только единый законченный элемент, хранящийся в одной области памяти. List в Java/C# — это именно один элемент, который уже хранит в себе коллекцию нужного типа. В Clojure и других ФЯ список может быть представлен цепочкой объектов, когда один указывает на другой (переменная списка хранит указатель на начало списка), но такой список всё равно будет считаться объектом. В Java/C# — нет, это уже что-то не цельное, не инкапсулирующее и т.д. А связные списки, хранящиеся как цепочки, открывают целый мир очень мощных алгоритмов.
Так что нет, уважаемый, инстанс класса — это гораздо меньше, чем просто объект.
Уважаемый, мне просто уже лень разбивать ваши недальновидные доводы… :(

А ваш пример отвратителен, поскольку вы подменяете одно понятие другим — логическое действие объекта «прикотовить» вы заменяете на установку его состояния на «включена».

Вы не понимаете что на определенном уровне абстракции, мне хочется менять состояние объекта, что бы при это менялось его поведение? Нет? Далее, печь не может готовить, готовить может пекарь. Печь, в рамках моей абстракции имеет состояние ВКЛ и ВЫКЛ. При изменении состояния, печь начинает потреблять газ или электричество. Сеттеры и геттеры инструмент, который позволяет отследить момент изменения состояния. Инкапсуляция соблюдена, т.к. я не знаю как работает моя печь. Если бы я после изменения состояния ВЫКЛ на ВКЛ, говорил печи начинай потреблять энергию/газ, то это говорит о том, что я знаю устройство печи, и знаю как она работает.

А для DTO объектов вы не придумаете примера, в котором установка свойства приведёт к каким-то действиям — просто по определению, потому что DTO-объекты на то и data transfer objects, что просто переносят данные и не выполняют никакой логики.
В рамках моей абстракции есть экземпляр класса письмо. Он не обладает никаким поведение, т.к. мне это не нужно. Он обладает только свойством текст. Которое можно менять как угодно. Письмо используется в качестве DTO для передачи данных между моими слоями. Оно является объектом в рамках моей доменной (даже доменной!) модели. Где противоречие инкапсуляции? Письмо просто не обладает поведением в рамках моей абстракции. И мне даже инкапсулировать нечего! Мне и не нужен пример в котором я для DTO объекта буду придумывать поведение! При этом мое письмо это реализация паттерна DTO.

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

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

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

А в чем собсно проблема то? И почему вы думаете что наследники должны иметь меньший функционал? Вы не верно применяете теорию множеств. Наследники не должны являться подмножеством. Они включают часть функционала родителя + часть функционала нового. Или вы заведомо решили что потомок является подмножеством родителя, и теперь вы используете сформированное вами неверное утверждение как истину?

Во-первых, вы GoF ещё раз перечитайте. Там несколько раз говорится, что паттерны решают проблемы, с которыми ООП не может эффективно справиться.
Эм… Т.е. по вашему паттерны это набор костылей, которые помогают привести ООП к более нормальному виду? Но это не набор решений часто встречаемых задач, с которыми программистам часто приходится сталкиваться? А то, что паттерны некоторые идеально ложатся на ООП, и собсно без ООП я даже не знаю можно ли некоторые реализовать (я не говорю что нельзя, но если вы дадите мне пример реализация абстрактной фабрики без ООП, я честно буду рад, но не более того). И то что паттерны, это отличные абстракции объектов реального мира тоже в расчет не берем?

Так что нет, уважаемый, инстанс класса — это гораздо меньше, чем просто объект.
Мне кажется что вы там какие то проблемы у себя в голове придумываете, потом думаете что эти проблемы возникли благодаря, в данном случае, мне, и пытаетесь меня убедить в обратном. :) Я вам где то сказал что инстанс класса — это гораздо больше чем просто объект? Вы думаете что я не знаю что понятие объекта нигде не использовалось? Вы хотите сузить понятие объекта в рамках ООП, до понятия объекта в языках, в которых ОО подход не использовался. Я же вам говорю, что объект в рамках ООП, это гораздо больше чем понятие объекта, которое существовало ранее, до появления ООП.
(я не говорю что нельзя, но если вы дадите мне пример реализация абстрактной фабрики без ООП, я честно буду рад, но не более того)

А зачем нужна абстрактная фабрика вне ООП?
А удобный и гибкий механизм не нужен?
Не нужен. Это если вкратце.

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

Так вот, не нужен какой-то механизм. Нужно решение задачи. Какую именно (конкретную прикладную или инфраструктурную) задачу вы пытаетесь решить?
Вас аналитик просит реализовать абстрактную фабрику? :) Суровые у вас аналитики. :) :)

Какую именно (конкретную прикладную или инфраструктурную) задачу вы пытаетесь решить?

Сейчас никакую.

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

Меня аналитик регулярно просит написать хранимку. За что и получает.

Вы хотите сказать что все зависит от задачи и требований?

Я хочу сказать, что в среднем в парадигмах, отличных от ООП, не нужен «паттерн абстрактная фабрика», а там, где он нужен, он легко реализуется.

Я, кстати, отдельно хочу заметить, что есть паттерны, которые порождаются исключительно ООП и в других парадигмах не очень нужны. Типовые примеры: стратегия и визитор.
Я, кстати, отдельно хочу заметить, что есть паттерны, которые порождаются исключительно ООП и в других парадигмах не очень нужны.

А что, паттернов которые порождаются другими парадигмами нет?

Меня аналитик регулярно просит написать хранимку. За что и получает.

Аплодирую сразу по двум пунктам. :) За то что не пускаете аналитика не в свое дело и за то что не любите хранимки. :)
А что, паттернов которые порождаются другими парадигмами нет?

Есть. И это как раз иллюстрация того, что паттерн — это типовое решение какой-то внешней задачи в рамках возможностей парадигмы (и, уровнем ниже, языка). Так что ffriend здесь прав, они возникают именно потому, что сама парадигма не решает эту задачу достаточно прозрачно, чтобы не надо было порождать паттерн.
Ну вот тоже как то от противного. Т.е. не задача породила паттерн, а узость текущей парадигмы?
Задача вместе с узостью парадигмы породили паттерн. Убери любое из двух, паттерн пропадет.
Я полностью понял что вы хотите сказать.

Моя точка зрения немного отличается от Вашей. Задача + инструменты парадигмы породили паттерн.

Но, давайте возьмем вашу точку зрения за истину. Что мы имеем? Чем меньше паттернов для парадигмы необходимо, тем она лучше. Но, т.к. паттерн решает какую то задачу, а количество задач стремится к бесконечности, то парадигма в которой не будут нужны паттерны — утопия. Получается что все парадигмы будут порождать паттерны. Но паттерны порождаемые ООП, наиболее просты для понимания человека, т.к. представляют собой абстракции объектов реального мира. Далее, т.к. используя объектный подход можно решить ЛЮБУЮ решаемую задачу на уровне ЯП, а качество решения чаще всего зависит лишь от опыта решающего, то получается что используя инструменты парадигмы можно решить заведомо любую задачу.
Но паттерны порождаемые ООП, наиболее просты для понимания человека

До этого момента все было хорошо. А теперь вы внезапно выдали ничем не подкрепленное утверждение.

представляют собой абстракции объектов реального мира

Например, паттерн «стратегия» или «команда», да-да-да.

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

Как уже говорилось, это с равным успехом верно и для процедурного подхода. No point there.
Например, паттерн «стратегия» или «команда»
А что тут не так? :) Паттерны «Стратегия» и «команда» есть абстракции объектов стратегия и команда. Или вы не видите что стратегию можно рассматривать как объект?

До этого момента все было хорошо. А теперь вы внезапно выдали ничем не подкрепленное утверждение.
Ну почему же? Тут логическая цепочка работает. Вы согласны что для понимания человека наиболее понятно взаимодействие объектов, которые он может увидеть в реальном мире? Следовательно, если мы пробуем перенести решение задачи в объектное представление, то это проще чем что то другое?

Как уже говорилось, это с равным успехом верно и для процедурного подхода.
Ну конечно, я не спорю. :) Но благодаря инструментам ООП сделать это гораздо проще и удобнее чем в процедурном подходе. НЕТ?
Но благодаря инструментам ООП сделать это гораздо проще и удобнее чем в процедурном подходе.
В общем, с учетом того, что количество задач бесконечно. А то вы мне тут щас какой нить элементарный пример приведете…
Дело, понимаете ли, в том, что никого не интересует «в общем» и «бесконечное количество задач». Программирование — это прикладная дисциплина, призванная решать конкретные задачи.
Паттерны «Стратегия» и «команда» есть абстракции объектов стратегия и команда.

Стратегия — в реальном мире — (а) не объект (б) имеет больше одного значения. И да, ее реализация в соответствующем паттерне не имеет ничего общего с тем, как нормальные люди понимают стратегию.

То же относится и к «команде». В жизни кто-то дает команду кому-то, сама команда — это только сообщение в терминах ООП, не объект. А в паттерне команда исполняет сама себя (не важно, что при этом она обычно делегирует управление дальше, важно, что она сама — первичный исполнитель).

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

Да.

Следовательно, если мы пробуем перенести решение задачи в объектное представление, то это проще чем что то другое?

Не следует из первого никак. Потому что «объектное представление» — это не «взаимодействие объектов, которое можно увидеть в реальном мире».

Но благодаря инструментам ООП сделать это гораздо проще и удобнее чем в процедурном подходе. НЕТ?

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

Ну почему же стратегия не объект то? :) Вы думаете что все объекты материальны? Если говорить про реальный мир, то я отлично вижу стратегию, как объект, который можно применить/использовать в военных действиях. И паттерн команда есть отличная абстракция. Про команду тоже самое.

Потому что «объектное представление» — это не «взаимодействие объектов, которое можно увидеть в реальном мире».
Может быть вы просто этого не видите? Объектное мышление сложная штука и его надо развивать. Я не говорю что ООП просто и легко решает все задачи, я говорю что оно решает любую задачу. И если вы умеете использовать ООП, то решение будет практически идеальным с точки зрения понимания, гибкости и масштабирования. И безусловно некоторые вещи проще решить без ООП, но, чаще всего, это простые задачи.
И паттерн команда есть отличная абстракция. Про команду тоже самое.


И паттерн СТРАТЕГИЯ есть отличная абстракция. Про команду тоже самое.

Спешил…
Вы думаете что все объекты материальны?

Я имею право так думать.

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

Может быть вы просто этого не видите?

Да, я этого не вижу, в этом и пойнт.

Когда вы говорите «проще», вы подразумеваете «проще, если вы сначала потратите 100500 часов на обучение и проектирование».

Объектное мышление сложная штука

Вот видите? «Сложная». Об этом и речь. После этого смешно говорите о том, что задачи решаются проще.

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

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

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

Но в реальности это не так. В реальности для каждой конкретной задачи решение может быть совсем другим.

И безусловно некоторые вещи проще решить без ООП, но, чаще всего, это простые задачи.

Мир состоит из простых задач. Их компоновка — вот что делает их сложными.

Нет, правда. У меня сейчас в разработке так называемая «Информационная Система масштаба Предприятия». Там, чтобы не соврать, сотни, если не тысячи, поддерживаемых процессов и участвующих в них сущностей. Так вот, более 90% — это простые задачи, каждая из которых решается безо всякого ООП, просто и наглядно. Вот их общая компоновка и унификация — это да, это задачка. И, надо сказать, что ее адекватное решение — это DSL. А интеграционные задачи там решаются (окей, будем честными, должны решаться) в терминах сообщений.
Я скажу даже больше, ООП не так хорош для решения больших задач, как это принято считать. На последнем проекте, над которым я работал, была довольно большая развитая система обработки текста. Было большое количество сущностей, связанных по принципу многие-ко-многим. Например, были источники текста, были языки, были наборы процедур предварительной обработки и наборы ключевых алгоритмов, а также способы формирования ответа и т.д. Первая реализация была на Java и следовала всем правилам ООП: для каждой группы, конечно же, были сделаны либо интерфейсы, либо абстрактные классы, конкретные реализации наследовались, всё было оформлено в каркас и т.д. По ходу дела возникали вспомогательные паттерны типа фабрик для порождения анализаторов языка, адаптеры, чтобы совместить элементы, которые изначально не собирались совмещать, строители, которые собирали нужный pipeline и т.д. Времени на проектирование и реализацию ушло уйма, и всё равно постоянно появлялись детали конкретных анализаторв, алгоритмов, источников данных и т.д., которое заставляли дополнять и доробатывать архитектуру. Всё получалось настолько громоздко и негибко, что ради интереса я решил попробовать во внерабочее время написать что-то подобное на Clojure. Основную часть я реализивал за 2 часа. За неделю я переписал весь функционал, не использовав ни одной строчки написанного на Java кода. Весь конвеер обработки превратился в небольшое замыкание, компонующее обработчики. Обычная композиция функций напрочь порвало всё ООП, практически остановив рост сложности системы.
Ради справедливости надо сказать, что то же самое можно было написать и на Java, однако этот код был бы очень далёк от ООП.
Ну да, это тоже характерная группа примеров: алгоритмы обработки данных, где собственно данные и их обработка жестко разделены (как мы помним, это анти-ООП, поскольку в ООП данные и методы объединяются).
Ну да, это тоже характерная группа примеров: алгоритмы обработки данных, где собственно данные и их обработка жестко разделены (как мы помним, это анти-ООП, поскольку в ООП данные и методы объединяются).
А вы что, при реализации логики по доменной модели, поведение и действия над доменными объектами запихиваете в доменные объекты? Какое такое анти-ООП? И почему мы должны это помнить?
А вы что, при реализации логики по доменной модели, поведение и действия над доменными объектами запихиваете в доменные объекты?

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

Какое такое анти-ООП?

Такое. Потому что типичный объект в ООП — это данные и методы. А тут данные отдельно, методы отдельно.
Ну, неплохо бы, потому что поведение доменных объектов и действия одних доменных объектов над другими.
Ну т.е. если я этого не делаю то я не использую объектный подход вы считаете?

Такое. Потому что типичный объект в ООП — это данные и методы. А тут данные отдельно, методы отдельно.
Еще раз говорю, что типичный (любой) объект реального мира обладает состоянием и поведением. А у нас типичный объект это абстракция. Я теперь начинаю думать что добавление еще одного столпа, абстракции, не такая уж плохая идея. :)
Ну, неплохо бы, потому что поведение доменных объектов и действия одних доменных объектов над другими.
Вообще хотелось бы что бы вы раскрыли больше это высказывание. Потому что чем больше вчитываюсь, тем больше не понимаю что вы имели ввиду… :(
Ну т.е. если я этого не делаю то я не использую объектный подход вы считаете?

Ну вообще, да.

Еще раз говорю, что типичный (любой) объект реального мира обладает состоянием и поведением. А у нас типичный объект это абстракция.

И что вы хотели этим сказать, простите?
И что вы хотели этим сказать, простите?
То что объект, в рамках абстракции, может обладать состоянием и/или поведением.
Но вот когда у вас в рамках задачи одни объекты обладают только состоянием, а другие — только поведением, у вас уже не ООП, а его иллюзия.
Но вот когда у вас в рамках задачи одни объекты обладают только состоянием, а другие — только поведением, у вас уже не ООП, а его иллюзия.
:) :) Почему же? Вы тоже считаете что DTO не может быть объектов в рамках моей объектной модели?
Потому что когда данные — отдельно, а операции — отдельно, это обычное модульное программирование.

DTO, все-таки, составляет несущественную часть объектов в нормальной ОО-системе, а уж тем более — в доменной модели. Почитайте у того же Фаулера про anemic domain model.
DTO, все-таки, составляет несущественную часть объектов в нормальной ОО-системе, а уж тем более — в доменной модели. Почитайте у того же Фаулера про anemic domain model.
Ну т.е. вы признали что объекты могут обладать ток состоянием.

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

Нет, не учитываем. Поскольку это утверждение ничем не подкреплено.
К счастью или к сожалению, но как и ваше…

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

Итого: меняется и состояние, и поведение. Если быть более точным, то меняется состояние и выполняется действие. Действие выполняется. Делается что-то кроме изменения данных. Видите это слово — действие? Оно и отличает полноценный объект от тупо контейнера данных. И если какой-то метод выполняет какое-то действие, кроме предоставления доступа к данным, то это уже нифига не метод доступа к данным, а полноценный логический метод. А методы доступа к данным (aka properties, accessors, getters/setters) делают именно то, что подразумевает их название — предоставляют доступ к данным.
(Конечно, можно сказать, что некоторый метод совмещает в себе признаки метода доступа к данным и дополнительные действия, но тогда вся терминология течёт.)

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

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

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

Какое отношение ваша печь имеет к проблемам типизации в ООП?

А в чем собсно проблема то? И почему вы думаете что наследники должны иметь меньший функционал?

Прочитайте ещё раз. Следующее же предложение, идущее после цитируемой вами части.

Эм… Т.е. по вашему паттерны это набор костылей, которые помогают привести ООП к более нормальному виду?

Частично. Паттерн Стратегия заменяет процедурные переменные (aka указатели на функцию, first-class citizen functions), паттерн Фабрика (ака Виртуальный Конструктор) закрывает дыру с ключевым словом new, делегируя создание объектов (возможно переопределямым) функциям, приведённая вами Абстрактная Фабрика используется для разных целей, в частности для (довольно кривой) эмуляции алгебраических типов данных, которые являются родными во многих языках программирования.
С другой стороны, многие паттерны являются общеязыковыми, как например Фасад или Наблюдатель.

Я же вам говорю, что объект в рамках ООП, это гораздо больше чем понятие объекта, которое существовало ранее, до появления ООП.

Объект в ООП:
Сущность в адресном пространстве вычислительной системы, появляющаяся при создании экземпляра класса или копирования прототипа (например, после запуска результатов компиляции и связывания исходного кода на выполнение).

Объект вообще:
Объе́кт (лат. objectum — предмет) — философская категория, если определять её в пределах эпистемологии, выражающая нечто, существующее в реальной действительности (то есть независимо от сознания) — предмет, явление или процесс, на которые направлена предметно-практическая и познавательная деятельность субъекта (наблюдателя). При этом в качестве объекта может выступать и сам субъект. В качестве субъекта выступает личность, социальная группа или всё общество.

Мне кажется, или второе понятие шире?
> Мне кажется, или второе понятие шире?
Не стоит забывать что главное во втором определении «внимание наблюдателя».
А оно очень быстро меняется в run-time ;)
Например, берем объект Арбуз — вроде как объект? Берем нож и режем им арбуз. Теперь у нас сколько объектов? :) И процесс нарезания это метод какого объекта, а главное с какими параметрами? :)

И все это вообще никак не ложится в программирование. Потому что там нет «существующих в реальной действительности» объектов. Мы можем все скопировать 10 раз. Это другой мир. Яблоко не скопируешь. Документ скопируешь, но для реального мира — это будут 2 разных объекта на разных листах бумаги.

ps. А еще ООП есть прототипное и динамическое (JS), в котором нет понятия «класс» и типы могут меняться в реально времени (например, в зависимости от ввода пользователя). И менять интерфейсы и объекты в нем можно вообще на лету без перезапуска системы!

Речь шла о двух смыслах слова «объект» вообще. Предыдущий оратор заявил о том, что понятие объекта, как оно воспринималось до появления ООП, является более узким, чем понятие объекта в ООП. Учитывая, что до появления ООП объектом можно было назвать что угодно, как в рамках программы, так и за её пределами, понятие, очевидно, шире. Запихивать любые объекты вселенной в программу я, естественно, не собирался.

P.S. В своей статье я как раз описал несколько примеров «неклассического» ООП. Советую взглянуть, особенно на мультиметоды в Clojure и систему S3 в R — довольно нестандартные подходы к объектно-ориентированному проектированию.
Более того, я продолжаю это утверждать. Что до ООП понятия объекта, как такового и не существовало.

Дело в том, что до момента первой реализации ООП(1967 г.), остальные парадигмы, ФП например + Lisp, понятие объекта как такового не вводили.

Далее про DTO. Объекты реального мира обладают как состоянием так и поведением. Но в рамках требуемой мне абстракции у моих объектов может не существовать состояния или поведения.
А то что вы сейчас видите объекты во всем, это и есть заслуга ООП.
«Что до ООП понятия объекта, как такового и не существовало.» — безусловно в рамках разработки ПО! А то сейчас начнете придираться к словам и видеть призраков.
Вот в том то и дело, что в рамках разработки ПО кроме специальных терминов использовалась общеупотребительная лексика, в том числе понятие объекта, которым я мог назвать что угодно — хоть переменную, хоть функцию, хоть сложную структуру данных. Теперь же, благодаря ООП, мне приходится говорить «вот эта штуковина», «эта структура… эээ… элементов» и т.д.
:) Вы сейчас говорите так, как будто жили в 1967 году. А тот факт, что современники того времени не могли воспринять симулу с ее объектами, вы в расчет не берете? :) :)
Необязательно жить в 1967 году, чтобы не быть испорченным терминологией ООП — достаточно начать изучение программирования с любой парадигмы.
Т.е. вы считаете, что современники не могли воспринять симулу тупо из-за того, что не использовали слово «объект»?
Т.е. вы считаете, что современники не могли воспринять симулу тупо из-за того, что не использовали слово «объект»?
Не могли воспринять такой подход. Он слишком не походил на те подходы, которые были до этого.
Я про ООП подход ничего не говорил, я говорил про сам термин «объект». До и после популяризации ООП.
Я про ООП подход ничего не говорил, я говорил про сам термин «объект». До и после популяризации ООП.
К сожалению я теряю нить ваших рассуждений и доводов.

Ток не надо мне говорить про понятие «объект» не в рамках разработки ООП. Ок?
Ток не надо мне говорить про понятие «объект» не в рамках разработки ООП = не в рамках разработки ПО! :) :)

С этими спорами я уже не могу нормально сокращения писать. :)
Понятие «объект» прекрасно существует в рамках разработки ПО, но за рамками ООП, и имеет то же значение, что и в общеупотребительной лексике. Но если вы не хотите об этом говорить — ради б-га.
Понятие «объект» прекрасно существует в рамках разработки ПО, но за рамками ООП, и имеет то же значение, что и в общеупотребительной лексике. Но если вы не хотите об этом говорить — ради б-га.
Эм… Ну мы же про разработку ПО говорим. Нет? То что понятие объекта существовало очень давно, до появления ООП я прекрасно понимаю. Но при чем тут это?? Или вы хотите сказать что до появления ООП его именно так и использовали как после? Где логика ваших высказываний? Вы кидаете бессмысленные выражения, которые невозможно притянуть к объекту спора.
Объясняю последний раз, если не дойдёт — пеняйте на себя. ООП из общеупотребительного слова, которое было очень удобно использовать для обозначения чего угодно в программе, сделало конкретный термин парадигмы, чем вызвало массу неудобства. Всё. Точка. Мысль на этом заканчивается, больше добавить нечего.
Вот вы всё время повторяете фразу «в рамках требуемой мне абстракции». А что такое абстракция? Абстракция — это выделение существенных признаков и игнорирование несущественных. В рамках ООП для объекта существенным является и поведение, и состояние. Конечно, вы можете сделать свою абстракцию более высокого уровня для своей предметной области, но это уже будет над-ООП. А на уровне абстракции ООП, которое мы тут и обсуждаем, объект поведением обладать обязан (а вот состоянием, кстати, нет).
Даже простая структура как бы обладает поведением: устанавливает (изменяет) своё состояние, хранит его, возвращает.Константы, переменные процедурных языков, регистры ассемблера — всё это объекты по большому счёту с точки зрения ООП. Просто число их методов (обрабатываемых сообщений) весьма ограничено и активно используется синтаксический сахар для их вызова :) Языки типа Ruby это хорошо показывают — вы вроде пишите программу на процедурном языке, пользуясь привычными переменными, константами, литералами и операцими с ними, но при её исполнении с точки зрения семантики языка происходит только создание объектов и вызов их методов.
Какой вы интересный пример с Ruby привели: программист пишет в процедурном стиле, но при этом under the hoods использются объетно-ориентированные конструкции языка. Этот пример хорошо показывает разницу между стилем/парадигмой разработки и используемыми для этого средствами языка.

ОО парадигма, если верить Алану Кэю, предполагает наличие объектов, каждый из которых выполняет какую-то роль. Это как разделение обязанностей в реальном мире: сапожник делает сапоги, сантехник чинит краны, дворник подметает улицы. Соответственно, недостаточно, чтобы объект просто «имел поведение», нужно, чтобы он был полезен для сообщества, а именно выполнял какую-то работу. Структуры/DTO не выполняют никаких действий. Это просто сообщения, которыми обмениваются объекты, чтобы дать друг другу знать о том, что нужно выполнить какое-то действие. По сути, эти сообщения между объектами можно было бы передавать не через структуры/DTO, а, например, через пайпы или потоки ввода-вывода между объектами. И парадигма от этого ни разу бы не пострадала. В то же время, смысловые объекты (дворника, сантехника, сапожника) уже нельзя передать по пайпам — это принципиально другие звери, от которых требуется выполнение работы.
Так data-only объекты (не считаю что DTO обязаны являться таковыми) выполняют свою роль — хранят своё состояние, предоставляют доступ к нему и зачастую позволяют его менять. С одной стороны они, да, часть (в мэйнстрим-языках именно часть, причём необязательная) сообщений, но с другой стороны выполняют свою часть общей работы — передают данные между объектами. У них есть поведение «установить значение свойства» и есть поведение «получить значение свойства». Так же как другие объекты они выполняют свой контракт. Они как курьер, который несёт сапоги от сапожника к дворнику :) Их роль менее заметна и, зачастую, они являются дорогим излишеством, но, тем не менее, роль у них есть.
Спасибо. :) А то я уже очень устал об этом писать. :) Искренне спасибо!
Нет, в том то и дело, что «курьеров» в ООП нет — сообщения доставляются мгновенно и без лишних затрат (если, конечно, не считать курьерами объекты сетевого соединения или DAO-объекты, но это уже совсем не DTO). Ещё одним хорошим отличительным признаком DTO является то, что его можно разбить на несколько частей и передать один за другим — данные от этого не изменяться. А вот бизнес объект на части не разберёшь — он просто перестанет быть собой. Пекарь может прислать сапожнику вместо одного 4 сообщения — «сделай», «мне», «новые», «сапоги» — с указанием последовательности прочтения, смысл сообщения от этого не поменяется. А вот сапожника разбить уже не получится: его правая рука не может подбивать сапоги без зада, сидящего на стуле, и головы контролирующей этот процесс. Именно поэтому бизнес объекты неделимы и требуют инкапсуляции, а DTO — нет.
Как без лишних, когда нужно создать DTO и проиницииализировать его нужными данными?
Это затраты на упаковку сообщения, но не на их передачу.
Это просто не прямые затраты на передачу, а косвенные, накладные.
Ещё раз: любую структуру данных при вызове метода можно разложить на части:

class SomeRecord {
   String x; 
   int y;

   /* getters and setters */
}
...
void printRecord(SomeRecord r) {
   System.out.println("[" + r.getX() + " " + r.getY() + "]");
}

Можно всегда переписать как:
void printRecord(String x, int y) {
   System.out.println("[" + x + " " + y + "]");
}

Смысл от этого не изменится. В отличие от объектов доменной области.
А кто говорит об объектах только доменной области? И, у DTO, имхо в сеттерах и геттерах может быть логика более сложная, чем чтение/запись полей. Скажем, если в вашем примере y должно быть строго положительным и соответствующий сеттер такую проверку проводит (пускай ассертом), то это ещё будет, имхо, DTO, но ваши примеры уже будут неэквивалентны.
Из Википедии:
The difference between data transfer objects and business objects or data access objects is that a DTO does not have any behavior except for storage and retrieval of its own data (accessors and mutators).

Так что нет, это уже будет не DTO.
И обратите внимание что это объект который не обладает поведением кроме как хранение и передача данных. Т.е. методы типа setVаlue, getValue имеют место быть и это не перестает быть DTO. :)
А я когда-то говорил, что геттеры и сеттеры противоречат идее DTO? При условии, что это действительно просто геттеры и сеттеры, а не методы, нагруженные дополнительно какой-то логикой.
Согласен с определением, но не согласен, что проверка входных данных не может входить в storage behavior. Скажем, в некоторых языках можно задать тип «интервал целых от 1 до 100», а в других нельзя. В одном объект с таким типом, проверяемым автоматически и неявно при компиляции или рантайме будет DTO, а в другом, проверяемом в рантайме, но не автоматически, а явно общими средствами языка не будет? Или вообще проверка типа при сохранении исключает DTO? Типа «мы с приёмником разберёмся, а не твое дело хранится в id целое или строка.»
Вы говорите про конкретные реализации, я — про общие концепции. И концептуально ООП не затрагивает типизацию вообще — вспомните, что сам Smalltalk был динамически типизированным и никаких проверок, соответственно, не вводил.
Вот и я про них. И получается одно из двух: или проверки в сеттерах допустимы, или реализации DTO в некоторых языках противоречат ООП, поскольку в них проверки типа при присваивании избежать невозможно, например в Java.
Да не то, чтобы нарушает. Тут важно намерение. Как говорил Сассман, программы пишутся людьми для людей, и только потом для компьютеров. С точки зрения дизайна здесь важно, что проектировщик не вкладывал дополнительного смысла, кроме как хранение и извлечение информации. А реализация — это уже запись дизайна на конкретном языке.
Вот собственно у меня и нет намерений нарушать, когда в DTO вкладываю проверку предусловий приёмника :) Считаю, что проверка данных перед сохранением неотъемлемая часть процесса сохранения. Причём, следуя логике и принципам DRY и KISS, DTO для неё самое подходящее место.
Если проверка — это неотъемлемая часть, то ваш объект — уже не DTO. Логика DTO в хранении и отдаче данных, ни больше, ни меньше. Если вы добавляете ещё что-то, то это уже подмена понятий.
Ну извините, но и че вы тут написали??

Printer printer = new Printer();
SomeRecord someRecord = new SomeRecord();
printer.printRecord(someRecord.x, someRecord.y);
//или
printer.printRecord(someRecord);

Ну поменяли мы объектную декомпозицию, ну и что? SomeRecord отличный доменный объект, который может выполнять функции DTO.
Вы сейчас различия между DTO и доменными объектам рассказываете? Или что? Ну да, отлично рассказали. Все правильно, епт. :) :)

Вы так и не поняли что DTO — это паттерн. Который рассказывает лишь о том, как можно передавать данные между чем угодно. Будь то даже разнородные платформы. Так вот, если я реализую DTO, то я могу реализовать его как угодно. И то, что объект, который реализует DTO, может являться в рамках моего приложения чем угодно, не противоречит ни понятию DTO, ни тому, что DTO — это объект в рамках моей объектной декомпозиции. Роль DTO в моем приложении может выполнять как доменный объект, который может не требовать инкапсуляции, т.к. не обладает поведением (пример с письмом), так и любой другой объект, который будет являться частью моей объектной декомпозиции.
Я то вашу позицию понял, но поймите и вы: если мы называем DTO полноценными объектами, то ломается вся концепция. Как вы сами говорили, ООП призвано проводить аналогии с реальным миром. Объекты в ООП — это агенты (люди, службы, машины, etc.), выполняющие некоторые полезные для сообщества функции. Письмо никаких функций не выполняет, это другие объекты могут с ним что-то сделать.

Конечно, если вам очень хочется, вы можете создать свою абстракцию, в которой объектами смогут быть также и DTO, но тогда это сломает всю аналогию с реальным миром, где сообщения, которыми обмениваются агенты, не имеет абсолютно никакого поведения. Если хотите нарушить аналогию — ради б-га, попробуйте ввести такую терминологию. Только не забудьте ещё вопрос про логическую инкапсуляцию, которая для DTO в таком случае нарушается. И да, не надо говорить, что не нарушается, потому что мы не знаем как там работают геттеры и сеттеры и бла бла бла — я сверху привёл определение DTO, где чётко сказано, что никаких действий кроме хранения и извлечения своих собственных данных DTO не производит. Иначе это уже не DTO.
Можно поподробнее про DTO, а точнее про логическую инкапсуляцию, нарушаемую для DTO. Вы имеете ввиду, что DTO — не объекты, поэтому для них не выполняются (не нужны) абстракции, полиморфизм, инкапсуляция и т.д. Если мы пример расширитель сознания и посмотрим на мир так, будто DTO стало объектом, то возможность получить доступ к его данным — нарушит инкапсуляцию, которой он на самом деле должен обладать, т.к. является объектом?
Да, именно так. Почему-то многие приписывают понятие инкапсуляции именно реализации, т.е. конкретным методам типа getValue() и setValue(). В то же время ООП описывает идеи, концепции. Идея инкапсуляции заключается в том, чтобы скрыть от пользователя внутренности, которые тот не должен видеть. Возвращаясь к примеру с сапожником, пользователь должен знать, что сапожник умеет делать сапоги, подбивать подошву и т.д., но не должен знать, какие сапожник использует материалы, сколько у него в этот момент заказов и т.п. В случае DTO пользователь знает об объекте всё. И тут уже не важно, обернули вы поля в аксесоры или нет — все внутренности класса для пользователя прозрачны. Если, например, у нас есть DTO Person с полями firstName и lastName, и где-то в коде у нас есть что-то вроде `print(p.getFirstName() + " " + p.getLastName())`, то мы привязываемся к данным объекта, и по коду, и логически, что может негативно сказаться при внесении в логику изменений. Конечно, в коде мы можем изменить соответствующие методы, но это будет хак, нарушающий (новую) логику. Геттеры и сеттеры позволят нам быстро пофиксить возникшие проблемы, но не сохранит красоту архитектуры, как это было бы при полноценной инкапсуляции, как в случае с сапожником.
Почему-то многие приписывают понятие инкапсуляции именно реализации, т.е. конкретным методам типа getValue() и setValue().
Я сколько раз говорил что это только инструмент языка, который помогает реализовать инкапсуляцию? У меня сложилось мнение, не отвергаю то, что ошибочно, что вы даже против методов setValue() & getValue() в DTO объектах.
Методы — это инструмент, помогающий инкапсуляции, я бы так сказал. Не сужая до геттеров и сеттеров.
Окей, у нас есть DTO Person и мы переживаем, что пользователь о нём знает всё. Знает что там есть firstName, lastName и оперирует ими для своий целей. Что делать то тогда, чтобы избежать описанной вами проблемы?
Ничего. DTO на то и DTO, чтобы пользователь знал о нём всё. В нём по определению нет инкапсуляции, а значит нет и этого слоя защиты, присущего полноценным объектам.

С другой стороны, учитывая, что DTO — это не полноценный объект, а просто набор данных, понятия инварианта для него также неприменимо. А значит неполное заполнение DTO (когда некоторые поля тупо пустые, например) — это не такая уж и проблема для архитектуры.
Конечно, если вам очень хочется, вы можете создать свою абстракцию, в которой объектами смогут быть также и DTO, но тогда это сломает всю аналогию с реальным миром, где сообщения, которыми обмениваются агенты, не имеет абсолютно никакого поведения.
Эм… А я разве сказал что DTO будут обладать поведением? Я сказал что доменный объект, который не обладает поведением может выполнять функции DTO.

что никаких действий кроме хранения и извлечения своих собственных данных DTO не производит
С этим согласен. Но заметьте, существование объекта не обладающим поведением — нормальная абстракция. С письмом пример отлично подходит. И таких очень много.
Эм… А я разве сказал что DTO будут обладать поведением? Я сказал что доменный объект, который не обладает поведением может выполнять функции DTO.

На практике — да, так чаще всего и делают. Но инкапсуляция при этом всё равно нарушается. Например, есть у нас доменный объект Point с полями x и y. Объект обладает некоторым поведением — как минимум для него перегружены операторы + и -, а также определён метод draw() для отрисовки на конве. Однако, как бы мы не старались, мы не сможем предусмотреть все возможные функции для точки, а значит нам придётся дать доступ к полям x и y через геттеры и сеттеры. Это вполне здоровое и адекватное решение. Однако инкапсуляция при этом нарушается, поскольку пользователь получает прямой (логический) доступ к полям объекта и может нарушить его непротиворечивость, установив, например, одну из координат в null. Можно, конечно, сделать всё жёстче — поля сделать неизменяемыми и инициализировать в конструкторе, проверяя на правильность коордтинат, а на интерфейс выводить только getter'ы. Однако какова будет логика проверки на правильность координат? Ок, предположим, что null для координаты — это не логично, ну а отрицательные координаты — нормально? Сейчас нет, а чуть позже может быть и да, предсказать опять таки сложно. Вводя дополнительные ограничения мы делаем лишние движения, которые затем могут привести к ещё большему количеству лишних движений. В итоге на практике мы, скорее всего, забьём и предоставим полный доступ к полям наших точек, надеясь, что пользователь не совсем идиот.

Но заметьте, существование объекта не обладающим поведением — нормальная абстракция. С письмом пример отлично подходит. И таких очень много.

Так тогда ломается другая аналогия с реальным миром, та, которую заложил Алан Кэй и которую я всё время описываю с помощью агентов. Письмо ничего не делает, значит оно бесполезно в качестве агента для сообщества. Ну и, опять же, как я уже говорил, письмо — это просто связка данных, которые при желании можно «развязать» и передать по частям, что идёт вразрез с идеей объекта-агента.
Но инкапсуляция при этом всё равно нарушается. Например, есть у нас доменный объект Point с полями x и y. Объект обладает некоторым поведением — как минимум для него перегружены операторы + и -, а также определён метод draw() для отрисовки на конве. Однако, как бы мы не старались, мы не сможем предусмотреть все возможные функции для точки, а значит нам придётся дать доступ к полям x и y через геттеры и сеттеры.
Ну что за бред то? Инкапсуляция не есть скрытия состояния! Есть скрытие реализации! Я же уже не один раз пример приводил!
Уважаемый, если вы ещё не заметили, мы с вами расходимся во мнении по некоторым ключевым пунктам, так что я тоже приводил море примеров, но пока мы не найдём общую «систему координат», примеры будут бесполезны. А поскольку вы начинаете выходить из себя, предлагаю эту дискуссию закончить.
Паттерн Стратегия заменяет процедурные переменные (aka указатели на функцию, first-class citizen functions), паттерн Фабрика (ака Виртуальный Конструктор) закрывает дыру с ключевым словом new
То что вы пишите, чаще всего есть проблема языка, а не ООП. Но, вы хотите сказать что я не могу реализовать паттерн стратегия через указатель на функцию??? Паттерн — это шаблон реализации. Т.е. общий принцип, но не конкретная реализация.
вы хотите сказать что я не могу реализовать паттерн стратегия через указатель на функцию?

Можете. И в том же C# это уже некоторое время так и делается.

Вот только в ФП это никогда не называлось «паттерном стратегия», потому что это один из основных приемов самой парадигмы, нет никакого смысла выделять его в отдельный паттерн.
Вот только в ФП это никогда не называлось «паттерном стратегия», потому что это один из основных приемов самой парадигмы, нет никакого смысла выделять его в отдельный паттерн.

Ну вы забываете основные цели паттернов видимо? Это же еще и передача информации о реализации. Поэтому паттерн то все равно нужен, даже в ФП.

НУ я если честно не понимаю каким образом паттерны являются минусом ООП. И не вижу смысла в подходе что чем больше паттернов, тем хуже.
Поэтому паттерн то все равно нужен, даже в ФП.

Кому нужен-то?

НУ я если честно не понимаю каким образом паттерны являются минусом ООП. И не вижу смысла в подходе что чем больше паттернов, тем хуже.

Паттерны не являются минусом ООП. Но не являются и его плюсом. Это просто некая данность, типовые решения задач.
Кому нужен-то?
Программистам. Что бы инфу передавать друг другу было проще.

Паттерны не являются минусом ООП. Но не являются и его плюсом. Это просто некая данность, типовые решения задач.
А вы не знаете почему тогда уважаемый ffriend использует паттерны, как что то, что является минусом ООП? :) :)
Программистам. Что бы инфу передавать друг другу было проще.

Программистам в рамках ФП это лишняя информация. То, что они видят — это банальная, типовая функция высшего порядка.

А вы не знаете почему тогда уважаемый ffriend использует паттерны, как что то, что является минусом ООП?

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


Да, я думаю что в этом проблема. Философски мы смотрим на мир по разному. :) Для меня мир это объекты и то, как они взаимодействуют. Будь то материально или нет.

Я никогда не говорил что ООП надо использовать всегда. Я уверен что есть, а может будут, такие подходы, которые это сделают в конкретном случае лучше. Но ООП можно рассматривать как универсальный механизм, которым сложно пользоваться. Но если вы видите результаты трудов человека, который умеет хорошо пользоваться ООП, то вам достаточно легко будет разобраться, что тут происходит. Даже если сами проектировать вы умеете с трудом.
ОЙ. :) ЭТо к сообщению выше.

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

Вот только людей, которые действительно хорошо умеют пользоваться ООП, исчезающе мало.
Да, и может быть, в какой то мере, благодаря некоторым статьям, написанным ранее на этой неделе. :) :)
А свою точку зрения я уже озвучивал: если парадигма порождает много паттернов, значит в ней есть много задач, которые не решаются «в лоб».
Еще раз хочу попросить вас задуматься. Вы уверены что парадигма порождает паттерны? Ее узость? Почему вы не рассматриваете паттерн, как решение задачи инструментами парадигмы? И вы думаете что, если бы во всех ООП языках сразу были бы указатели на функции, то паттерн стратегия не появился бы? Почему вы говорите что функции высшего порядка это гораздо лучшее описание для программиста функционального языка, чем сказать что эти функции реализуют такую то стратегию? Задумайтесь.
Вы уверены что парадигма порождает паттерны?

Несомненно, парадигма порождает паттерны. Потому что паттерны выражены в ее терминах. Просто парадигма — не единственное, что их порождает.

И вы думаете что, если бы во всех ООП языках сразу были бы указатели на функции, то паттерн стратегия не появился бы?

Понимаете ли, в чем дело, «указатель на функцию» — это термин, невозможный в ООП. В ООП мы можем иметь дело только с объектами.

Почему вы говорите что функции высшего порядка это гораздо лучшее описание для программиста функционального языка, чем сказать что эти функции реализуют такую то стратегию?

Потому что ФВП — это термин самой парадигмы, а не добавочный термин шаблона. Бритва Оккама.
Потому что ФВП — это термин самой парадигмы, а не добавочный термин шаблона.
Ну вы понимаете что ФВП и понятия стратегии несут абсолютно разный смысл. И когда мы говорим про стратегию, даже в рамках ФП, то это гораздо более конкретное использование ФВП? Или в ФП понятие стратегии вообще не применимо?:)

Ну вы понимаете что ФВП и понятия стратегии несут абсолютно разный смысл.

Угу. Диаметрально.

И когда мы говорим про стратегию, даже в рамках ФП, то это гораздо более конкретное использование ФВП?

Нет. Это единственное возможное использование ФВП.

Или в ФП понятие стратегии вообще не применимо?

Если кратко, то да, потому что любая функция, переданная в ФВП, является стратегией. Поэтому это бессмысленный термин.

В отличие от ООП, где стратегией является не каждый объект, передаваемый в метод другого объекта.
Понимаете ли, в чем дело, «указатель на функцию» — это термин, невозможный в ООП. В ООП мы можем иметь дело только с объектами.
Так я же и говорю что паттерн это решение проблемы средствами парадигмы. В ООП задачу с изменением поведнеия решают так, в ФП это решается вообще другими средствами в процедурном третьими.
Так я же и говорю что паттерн это решение проблемы средствами парадигмы.

… только если парадигма не предоставляет средств решения, не требующих абстракции до паттерна.
только если парадигма не предоставляет средств решения, не требующих абстракции до паттерна.


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

Некоторых задач. Или вам опять привести примеров?
Я уверен что есть исключения. :) С удовольствием бы посмотрел на примеры. Честно.
Весь ETL — одно большое исключение.
Эмм… Какая часть из ETL не ложится на объектную модель? Точнее какую часть из этого процесса невозможно реализовать используя ООП? Или у нас в ООП запреты на работу с параллельными вычислениями? Или я не понял что вы имели ввиду?
Кажется, я уже не первый раз вам повторяю одно и то же: все можно реализовать с помощью ООП. Но не всякое такое решение будет более понятно, чем решение на специализированном механизме.

Потому что, уж извините, но типичный для ETL pipeline «загрузить данные из источника — отфильтровать те, где — (маппинг: в колонке A значение умножить на 3, в колонке B значение обрезать до 50 символов, в колонке Ц дату преобразовать из UTC в часовой пояс из колонки D) — загрузить в приемник» на ООП будет выглядеть банально громоздко.

Банальный SQL — и тот в ООП выглядит громоздко.

(ну и да, параллельные вычисления здесь вообще не при чем)
Кажется, я уже не первый раз вам повторяю одно и то же: все можно реализовать с помощью ООП. Но не всякое такое решение будет более понятно, чем решение на специализированном механизме.
Эм, а что за механизм то? НЕ методология уже? А механизм инструмент? А если инструмент реализован с использованием ООП, то тогда считается?
Это уже демагогия пошла.

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

И да, ETL — не самый лучший пример.
Я кстати нашел отличную аналогию для ваших доводов по поводу Sharepoint, которые вы приводили выше. С ETL я уверен что вы пошли бы в туже сторону.

Аналогия такая, что вы для решения задачи перемещения из точки А в точку Б, выбираете между двигателем внутреннего сгорания и автомобилем.
«Банальный SQL — и тот в ООП выглядит громоздко.» — извините, а вы не могли бы рассказать где работа с SQL выглядит лучше?
ffriend не использует паттерны, как что-то, что является минусом ООП, он вообще ничего плохого про сами паттерны не говорил. Не читайте больше, чем написано.
ffriend не использует паттерны, как что-то, что является минусом ООП, он вообще ничего плохого про сами паттерны не говорил.
Так а чего вы тогда их вообще притянули?
Так что чем больше паттернов, тем больше задач, с которыми голове ООП не может нормально справиться.
Не знаю, где вы здесь усмотрели камень в огород паттернов. Как уже сказали (и долго объясняли) сверху, паттерны являются следствием отсутствия родных средств решения некоторой задачи в конкретном языке или парадигме. GoF проводят хорошую аналогию с архитектурой (зданий), откуда и пошёл термин. Проектируя здание, вы рассчитываете на определённые строительные блоки, доступные вам. Если некоторое архитектурное решение нельзя просто реализовать с помощью доступных строительных блоков, это решение с помощью тех же блоков реализуется сложно. Если задача повторяется, решение записывается и обзывается паттерном. Это, в принципе, хорошо — универсальных строительных блоков всё равно не бывает, а паттерны предоставляют готовое решение без необходимости смены поставщика блоков. Однако, большое количество паттернов, связанных с данным набором блоков, по определению означает большое количество задач, которые с этими блоками просто реализовать нельзя.
Вот вы еще раз четко даете понять, что мысли в вашей голове возникают сами собой. :)

Не знаю, где вы здесь усмотрели камень в огород паттернов.
И я не знаю где вы увидели подобное в моих словах. :) :) Понимаете, ваше высказывание:
ffriend не использует паттерны, как что-то, что является минусом ООП, он вообще ничего плохого про сами паттерны не говорил.
состоит из двух частей. В первой части, вы утверждаете что «ffriend не использует паттерны, как что-то, что является минусом ООП», где я вам четко привожу ваши же слова:
Так что чем больше паттернов, тем больше задач, с которыми голове ООП не может нормально справиться.
Вторую же часть «он вообще ничего плохого про сами паттерны не говорил», вы придумали сами. Т.к. я нигде не говорил что вы говорите про паттерны плохо. Отсюда я делаю четкие выводы что вы не видите того, что против вас, а видите лишь то, что вам хочется видеть. Я бы могу сказать что это просто розовые очки, но в свете ваших статей я бы сказал что это скорее дилетантство.
И я не знаю где вы увидели подобное в моих словах. :) :)

Здесь:
А вы не знаете почему тогда уважаемый ffriend использует паттерны, как что то, что является минусом ООП? :) :)

Паттерны не являются минусом, паттерны являются индикатором, что в парадигме есть минусы.Так же, как большое количество больниц в городе не является минусом для города, но указывает на то, что в городе часто болеют.
Ай, ну бред же. Ну индикатором является минуса, или минусом, факт то, что вы используете паттерны как аргумент против ООП. А мы выяснили что глупо это рассматривать как минус какого либо подхода.
А мы выяснили что глупо это рассматривать как минус какого либо подхода. Или как аргумент против какого либо подхода.
Факт в том, что вы читаете больше, чем написано. Я нигде не использовал паттерны как минус ООП, равно как и минус какой-либо другой парадигмы. Если я не ошибаюсь, разговор про паттерны начал не я, а я лишь присоединился для пояснения идеи корреляции между количеством паттернов и количеством нерешаемых просто в рамках парадигмы задач.
НУ я если честно не понимаю каким образом паттерны являются минусом ООП.

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

И не вижу смысла в подходе что чем больше паттернов, тем хуже.

Двояко. С одной стороны, чем больше паттернов, тем меньше, значит, очевидных решений. С другой стороны, тем больше готовых кирпичиков, из которых собирается решение, а не они создаются с нуля. С одной стороны, недостаточно гибкий синтаксис для решения типовой задачи одной конструкцией языка, с другой — уже есть типовое решение этой типовой задачи, объяснять его детали не нужно.
Абсолютно согласен. Поэтому не понимаю как наличие паттернов может быть индикатором отрицательных черт парадигмы. :) Спасибо.
Да всё же просто! Есть случаи, где ООП не хватает инструментов и выразительности для лёгкого решения задачи. Поэтому есть задокументированные костыли — паттерны. Чем больше костылей, значит тем больше дыр в изначальной парадигме, которые необходимо заткнуть. В ФП например «стратегия» не нужна, потому что подобный подход является частью самой парадигмы и является естественным для неё.

Я думаю, именно это вам пытаются сказать.
Прикольно. Хабр показал мне тот комментарий как новый. А там уже целая дискуссия :( Можете игнорировать!
Понимаете ли в чем дело. Я так не считаю. Я считаю что паттерн — это есть решение задачи в рамках парадигмы. Изменение поведения в ФП решается терминами парадигмы, и, вы будете смеяться, но и в ООП задача решается в рамках парадигмы. ООП не создает искусственных понятий, костылей. Все решается в рамках заложенных концепций, так же, как и в ФП. Для ООП стратегия тоже является естественной. Почему? Потому что ООП как раз и создано для решения задач через абстракции.
Любой язык создан для решения задач через абстракции.
Любой язык создан для решения задач через абстракции
Браво. Ток в случае с ООп это решается через абстракции объектов.
Стратегия не является естественной для объектов. Стратегия является естественной для функций, а в ООП эти функции приходится дополнительно оборачивать объектом. Это вам и пытаются сказать.
Понимаю. Я знаю что вы так не считаете. Я тоже :)
Добрался до компьютера, теперь могу написать много.

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

Вот есть язык С, на котором описано WinAPI. В WinAPI много функций с большим количеством параметров, первым из которых является хэндл. И для каждого хэндла существуют как минимум 2 функции. Например, CreateFile и CloseFile.
Это объектный паттерн, который активно используется в С и в ООП-библиотеках, имеющих сишный фасад, а также биндингах к этим библиотекам. Паттерн это, потому что от программиста требуется выполнения серии правил (описать структуру, конструктор, деструктор, не показывать структуру, а только указатель на нее). Программист что-то может легко нарушить, но тогда это не будет этим паттерном.
C появлением языков, поддерживающих классы (я не говорю ООП-языков, потому что классы не обязательно означают ООП), этот паттерн перестал быть нужен. Никто сейчас не говорит об объектном паттерне.
У класса всегда будет конструктор и объявив сущность языка все требования будут выполнены компилятором. Аналогично, в грязных ФП-языках существует возможность создавать объекты с помощью изменяемых замыканий. Это тоже не объекты ООП (нет наследования и сабтайпинга) и тоже паттерн.
В С++ интерфейс является паттерном, который при желании можно нарушить, добавив в абстрактный класс поле и похерив ABI, а в Java нет. В асме есть паттерн функции в виде push ebp ...ret и куча других паттернов, вызванных предельной невыразительностью языка.

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

Во-первых, куча паттернов является созданием классов с одним методом (возможно, с кучей полей, но с одним методом). Это описано в презентации the lack of design patterns in python (замечу, что python не ФП-язык). Это все от недостатка функций высшего порядка. Команда, стратегия, фабричный метод, абстрактная фабрика, цепочка обязанностей, интерпретатор, сколько их там… Есть паттерны, стоящие особняком от большого списка «отсутствие ФВП», например визитор — отсутствие в реализации полиморфизма времени выполнения, основанного на vtable, диспетчеризации по нескольким аргументам; если в языке есть мультиметоды, он не нужен.

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

По поводу объектной декомпозиции. Объект, по SICP, — это такая штука, которая имеет и скрывает свой стейт, что иногда бывает удобно, а иногда — глупо. Такие объекты существовали и до ООП. Противоположность объектной декомпозиции являются штуки, которые не имеют стейта (все поля — const) и имеют несколько входов и выходов, преобразующих данные. ООП поддерживает оба вида декомпозиции и в споре по поводу того, хороша ли объектная декомпозиция в рамках обсуждения ООП я не вижу смысла. ООП не означает объектную декомпозицию, «объекты» в ООП могут быть как и объектами, так и преобразователями без стейта, DTO и вообще чем угодно (о чем и говорит оппонент), и «ООП — это объектная декомпозиция» это подмена понятий, которой пудрят мозги. Декомпозиция может и на объекты, но объекты эти могут быть чем угодно, и «ООП — это декомпозиция на что угодно». Через пару лет, когда невинная печка-объект превращается в документацию на AbstractSingletonProxyFactoryBean про это уже и не вспоминают, но при объяснении ООП почему-то все равно говорят о том, что ООП — это об объектной декомпозиции. В функциональном языке можно сделать объектную декомпозицию, но это не будет иметь отношения к ООП.

Так что же такое ООП? Если выкинуть из (объекты с состоянием; наследование; полиморфизм [времени выполнения]) что-то одно, то это будет не ООП.
1. Вычеркнем наследование. Для объектов с состоянием и без наследования полиморфизм можно разрулить статически. Это штуки типа STL.
2. Вычеркнем состояние. Наследование и полиморфизм со структурами без состояния — SOA, для которого пример с печкой лучше всего подходит. Обычно пользователю нужна не печка и пекарь, а ресторан с конкретным меню, и в любом случае нужно предусмотреть абстрагирование от процесса включения печки. Это идеал для любой библиотеки, протокола, инструмента командной строки и всего такого. Иногда он недостижим (например, включение печки — тяжелый процесс, просвечивающий через дыру в абстракции).
3. Вычеркнем полиморфизм. Объекты с состоянием и наследование без полиморфизма — наследование тут полностью эквивалентно агрегированию. Я могу согласиться в том, что это тоже sort of ООП, т.е. основные признаки ООП — это состояние и наследование.

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

Тройка (объекты с состоянием; наследование; полиморфизм [времени выполнения]) порождает абстрактные печки. Первое, что охота из нее выкинуть — это наследование. Наследование хорошо себя показало в задаче однопоточного GUI. У GUI-компонентов совпадает очень много кода и полей. В каких еще задачах помогает именно ООП? Я не знаю. В ООП связи очень жесткие и выделить наследника на этапе проектрования не имея под боком такую же систему невозможно. Эволюционный развитие системы затруднен. Хорошим и опытным проектировщиком считается тот, кто набил руку в построении почти эквивалентных иерархий под разных заказчиков. Знания проектировщика, работающего несколько лет с GUI будут бесполезны при разработке софта, работающего с деньгами. Первый совет, который дают «практики» — не обощать слишком сильно, потому что жесткость иерархии не дает реально повторно использовать код и лучше писать конкретный код под заказчика.
Спасибо.

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

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

Вычеркнем состояние. Наследование и полиморфизм со структурами без состояния — SOA, для которого пример с печкой лучше всего подходит.
Ну я, если честно не до конца понял, как мы выпрыгнули так высоко. Но, более того, почему вы думаете, что в реализации SOA, на стороне одного из сервисов я не использую ОО подход? А также объекты с состояниями и без оных?

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

Знания проектировщика, работающего несколько лет с GUI будут бесполезны при разработке софта, работающего с деньгами.
Абсолютно согласен. Только проблема в незнании предметной области.

Декомпозиция может и на объекты, но объекты эти могут быть чем угодно, и «ООП — это декомпозиция на что угодно».
Да, это и есть универсальность ООП и основная проблема. Научиться этим пользоваться можно только обладая очень хорошим объектным мышлением. Но «прочитать» такие решения, чаще всего гораздо проще.
Объект, по SICP, — это такая штука, которая имеет и скрывает свой стейт, что иногда бывает удобно, а иногда — глупо. Такие объекты существовали и до ООП.
Я очень рад, что какие то подходы впитывают лучшее от других. И ничего против этого не имею. Я уверен что только используя лучшее, и внося что то еще хорошее можно развиваться.

Но зачем же сейчас говорить, что объекты существовали ранее и кто то думал о том, что может проектировать и разрабатывать ПО используя объекты, абстракции объектов реального мира? Сейчас вы безусловно будете говорить что они существуют, благодаря ООП. И следует просто посмотреть на хронологию и понять с какого момента понятие объекта (со стейтом или без, с поведением или без) стало фигурировать в разработке ПО.
Сейчас вы безусловно будете говорить что они существуют, благодаря ООП.
Скомкано как то. Хотел сказать что сейчас начинает казаться что так было всегда. А начинает казаться так лишь благодаря ООП.
Один-единственный вопрос к автору.
Вы пробовали работать над большим проектом не в рамках ООП? Ну там, программа или библиотека на чистом С; какой-нибудь сервер на Эрланге; да хотя бы дополнение к Emacs на Лиспе?
На C приходилось, но я бы не сказал что это было что то большое. Команда два человека. Кода не много.

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

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

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

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

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


Я тоже в этом уверен. Как и уверен в том, что если ошибки нет, то скорость разработки а также простота сопровождения системы будет значительно выше при разработке через ООП, с учетом верно выбранных абстракций. Я так же уверен что внесение прогнозируемых изменений в ООП гораздо проще. Я думаю спорить не будем?
А что мне с вами спорить? Вы нормально работали только с ООП. Я просто не вижу смысла в споре.
ХМ… Ну если я не использовал, скажем, процедурный подход в полной мере, это же не значит что я ничего о нем не знаю? И какие то вещи я могу узнать у других людей, которые эти самые подходы использовали. Нет?
Вы знаете теорию. А мне интересна практика, интересен опыт.
Вы думаете что без практики я не имею права говорить что сопровождение программ написанных через ООП гораздо проще, чем сопровождение программ написанных через процедурный подход? Для этих вещей нужна тонна опыта? Вы глубоко заблуждаетесь.
Ну почему же, вы имеете право это говорить.
Только я имею право вас не слушать, потому что ваши слова не имеют никакого веса.
Фаулеру поверите?

Реализация бизнес логики через сценарий транзакций. Стандартный процедурный подход. Сравнения с другими подходами помните?

Не понимаю, почему если не работал, то ко мне даже прислушиваться не надо. Хамство. Ей богу.
Хамство — это хаять то, чего даже не знаешь.

Фаулера, GoF, да и много чего еще я читал. Потому то я вас и слушать не буду — вы же только повторяете за ними. Что нового я от вас услышу?
Мне кажется что вы неадекватны.
Вам много чего кажется, но мало что из этого является правдой.
Да тут то все железно.

Спорить с вами вообще бессмысленно. Если я не создал ни одной лампочки, то о том как она работает мне говорить нельзя… :(
А вы читали у того же Фаулера отдельную книжку про DSL?
И как этот подход реализации бизнес-логики сравнивается со всеми остальными, описанными в PoEAA?
Если честно, не помню что бы там что то противоречило моим словам.
И те вещи, о которых я сказал выше есть, обычные пункты при сравнении процедурного подхода и объектного.
>Как и уверен в том, что если ошибки нет

К сожалению мы слишком поздно узнаем о таких ошибках.
Я не хочу ничего решать — я хочу ПЕЧЬ! :)
Кстати, в универе меня удивляет следующий факт: книжки и статьи в интернете говорят, что основные принципы ООП — это инкапсуляция, наследование и полиморфизм, в то время, как наши преподаватели — абстрагирование, инкапсуляция, иерархия и модульность + (необязательные) типизация, сохраняемость и параллелизм
После прочтения последних двух статей про ООП, этот факт имхо уже не имеет значения :))
Абстрагирование — принцип любого П(программирования), иерархия — суть наследование, дерево/лес, связный ациклический граф. О соотношении модульности и полиморфизма можно поговорить :)
Еще говорят что некоторые вещи нельзя представить в виде объектов и их взаимодействия. Я уверен что это не так.

Это действительно нет так, так как противоречит всему что известно на данный момент науке. С научной точки зрения всё в мире — объекты и взаимодействия между ними, причём это можно увидеть на любом уровне: от субатомных частиц до скоплений галактик. Социальная сфера — не исключение.
Кстати, интересный вопрос: а кто-нибудь когда-нибудь пытался построить модель элементарных частей в терминах ООП, с наследованием, инкапсуляцией и т.п…
*элементарных частиц, эх, невнимательность.
В науке очень не любят объекты с состоянием, оно мешает думать.
Обычно в истории любой науки объектный подход с шариками развивается до такого, где время всего лишь параметр в некоем неизменяемом мире. Уж в плане квантовой механики объектный подход терпит полное фиаско.
Ваша научная точка зрения на самом деле философская — это человеческое мышление объектно на бытовом уровне, на деле для природы никаких галактик не существует
Да, что уж и говорить — функционалисты оборзели :))
Вот мне вот интересно, кто (как много) из тех кто написал за эту неделю статьи по ООП, и те кто так яростно комментировал — прочитал НЕ по диагонали книгу Г. Буча?
Software Engineering with Ada? :)
Ого, эту статью еще кто то читает. :)

Articles