18 июля 2012 в 15:22

Зачем нам ООП и что это такое

Всем привет.

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

Начнем.

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

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

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

Как же эти инструменты работают? Да проще пареной репы, потому что это все основано на привычных нам вещах. Люблю простые примеры из жизни:

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

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

Еще стали добавлять абстракцию, как еще один столп ООП. Я думаю, что это скорее верно, но уж очень попахивает КЭПом.

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

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

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

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

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

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

P.S. В комментах к прошлой статье я явно много перегибал палку при обращении к некоторым людям. Приношу свои извинения.
Вадим @veitmen
карма
16,0
рейтинг 0,0
Похожие публикации
Самое читаемое Разработка

Комментарии (469)

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

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

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

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

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


                        Нет?

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

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

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

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

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

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

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

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

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

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

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

                и

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                И так далее.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    Нет.

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

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

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

                            Но когда дело переходит в аналитику, там уже даже сущностями не оперируют, там оперируют массивами.
        • 0
          Цена технологий кстати чаще не берется в расчет. Копейки, чаще всего, по сравнению с остальными пунктами. Но конечно так не всегда, но чаще.
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      :) Чем плох Иван то? :)
      • НЛО прилетело и опубликовало эту надпись здесь
  • +14
    Я яростный приверженец ООП, но ваша статья мне не очень понравилась. И вот почему:

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

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

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

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

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

    • 0
      Спасибо.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    Вы потом внесете изменения требований, о которых я не предполагал
                    да, в реальности всегда так и происходит. хотелось посмотреть, как вы выйдете из положения
                • +1
                  Вот тут отлично передана моя мысль:
                  habrahabr.ru/post/148015/#comment_4995132
                  • 0
                    ну да. но ведь так мы и работаем всё время. сегодня требования одни, а завтра — совершенно другие. как к этому быть готовым?
                    • 0
                      Красиво никак. И дело не в ООП. Дело в опыте.
                      • 0
                        ну вот, вот! скажите, как ваш опыт помогает вам быть готовым к изменениям требований?
                    • +1
                      Ай, случайно послал.

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

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

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

                                как-то так.

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

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

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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      А если серьезно, то фактически разработка объектной модели приложения и есть разработка DSL. Что означают все эти требования к семаническому именованию классов, объектов, методов и т. п., как не разработку новог