Я в течение десятилетий программировал на объектно-ориентированных языках. Первым из них стал С++, затем был Smalltalk, и наконец .NET и Java. Я фанатично использовал преимущества наследования, инкапсуляции и полиморфизма, этих трёх столпов парадигмы объектно-ориентированного программирования. Мне очень хотелось воспользоваться обещанным повторным использованием и прикоснуться к мудрости, накопленной моими предшественниками в этой новой и захватывающей сфере. Меня волновала сама мысль о том, что я могу мапить объекты реального мира в классы и думал, что весь мир можно аккуратно разложить по местам.

Я не мог ошибаться сильнее.

Наследование — первый павший Столп




На первый взгляд, наследование — главное преимущество парадигмы ООП. Все приводимые нам упрощённые примеры иерархий, казалось, имели смысл.



А «повторное использование» — вообще термин дня. Нет, пожалуй, даже года, а то и больше. Я всё это проглатывал и бежал реализовывать в реальных проектах моё новообретённое видение.

Проблема бананов, обезьян и джунглей


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

Появился новый проект, я не забывал о своей идее с классом и испытывал большой энтузиазм. Без проблем. Повторное использование спешит на помощь. Нужно просто взять класс из другого проекта и применить его. Ну… вообще-то… не просто класс. Понадобится родительский класс. Но… Но это всё. Гхм… погодите… кажется, нужен будет ещё родитель родителя… А потом… в общем, нужны ВСЕ родители. Хорошо… хорошо… Я с этим разберусь. Без проблем.

Ну замечательно. Теперь не компилируется. Почему??? А, понятно… Этот объект содержит этот другой объект. Так что он мне тоже нужен. Без проблем. Погодите… Мне не нужен всего лишь тот объект. Мне нужен его родитель, и родитель родителя, и т.д. Для каждого вложенного объекта мне нужны родители, а также их родители, и их родители, родители… Мда. Джо Армстронг, создатель Erlang, когда-то сказал прекрасные слова:

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

Решение проблемы банана, обезьян и джунглей


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

Проблема ромба


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



Большинство ОО-языков это не поддерживают, хотя оно и выглядит вполне здраво. Так в чём дело? Посмотрим на этот псевдокод:

Class PoweredDevice {
}

Class Scanner inherits from PoweredDevice {
    function start() {
    }
}

Class Printer inherits from PoweredDevice {
    function start() {
    }
}

Class Copier inherits from Scanner, Printer {
}

Обратите внимание, что классы Scanner и Printer оба реализуют функцию start. Тогда какую функцию start унаследует класс Copier? Та, что реализована классом Scanner? Или классом Printer? Не могут же они обе унаследоваться.

Решение проблемы ромба


Решение очень простое: не делайте так. Вот именно. Большинство ОО-языков не позволят так сделать. Но… что если мне нужно смоделировать такую ситуацию? Мне нужно моё повторное использование! Тогда вы должны агрегировать и делегировать.

Class PoweredDevice {
}

Class Scanner inherits from PoweredDevice {
    function start() {
    }
}

Class Printer inherits from PoweredDevice {
    function start() {
    }
}

Class Copier {
    Scanner scanner
    Printer printer
    function start() {
        printer.start()
    }
}

Класс Copier теперь содержит экземпляры Printer и Scanner. Он делегирует реализацию функции start классу Printer. А может так же легко делегировать Scanner’у. Эта проблема — ещё одна трещина в Столпе Наследования.

Проблема хрупкого базового класса


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

import java.util.ArrayList;

public class Array
{
    private ArrayList<Object> a = new ArrayList<Object>();

    public void add(Object element)
    {
        a.add(element);
    }
 
    public void addAll(Object elements[])
    {
        for (int i = 0; i < elements.length; ++i)
            a.add(elements[i]); // this line is going to be changed
    }
}

ВАЖНО: Обратите внимание на выделенную строку. Позднее она изменится и всё сломает. У этого класса две функции интерфейса: add() и addAll(). Функция add() добавляет одиночный элемент, а addAll()несколько элементов посредством вызова функции add(). А вот производный класс:

public class ArrayCount extends Array
{
    private int count = 0;
 
    @Override
    public void add(Object element)
    {
        super.add(element);
        ++count;
    }
 
    @Override
    public void addAll(Object elements[])
    {
        super.addAll(elements);
        count += elements.length;
    }
}

Класс ArrayCount — специализация общего класса Array. Единственная разница в их поведении заключается в том, что ArrayCount содержит счётчик количества элементов. Давайте подробнее разберём оба класса.

  • Array add() добавляет элемент в локальный ArrayList.
  • Array addAll() вызывает локальный ArrayList для добавления каждого элемента.
  • ArrayCount add() вызывает свой родительский add(), а затем инкрементирует счётчик.
  • ArrayCount addAll() вызывает свой родительский addAll(), а затем инкрементирует счётчик по количеству элементов.

И всё работает замечательно. А теперь критическое изменение выделенной строки:

public void addAll(Object elements[])
{
    for (int i = 0; i < elements.length; ++i)
        add(elements[i]); // эта строка была изменена
}

Что касается владельца базового класса, то он работает так, как заявлено. И проходит все автотесты. Но владелец не обращает внимание на производный класс. И владелец производного класса сильно разочарован. Теперь ArrayCount addAll() вызывает родительский addAll(), который внутри себя вызывает add(), управление которым уже было ПЕРЕХВАЧЕНО производным классом. В результате счётчик инкрементируется при каждом вызове add() производного класса, а затем СНОВА инкрементируется по количеству элементов, добавляемых addAll() производного класса. ТО ЕСТЬ, ЭЛЕМЕНТЫ ПОДСЧИТЫВАЮТСЯ ДВАЖДЫ.

Раз такое может произойти, автор производного класса должен ЗНАТЬ, как был реализован базовый класс. И он должен быть информирован о каждом изменении в базовом классе, поскольку это может иметь непредсказуемое влияние на производный класс. Гхм! Эта огромная трещина будет всегда угрожать стабильности драгоценного Столпа Наследования.

Решение проблемы хрупкого базового класса


И снова на помощь спешат агрегирование и делегирование. Благодаря им мы переходим в программировании от стратегии «белого ящика» к стратегии «чёрного ящика». В первом случае мы должны следить за реализацией базового класса. А во втором случае мы можем полностью игнорировать эту реализацию, потому что не можем внедрить код в базовый класс, перехватив управление одной из его функций. Мы должны работать только с интерфейсом.

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

Проблема иерархии


Каждый раз, создавая новую компанию, мне приходится решать проблему, связанную с выбором места для документации компании. Нужно ли мне сделать папку Документы, а внутри неё создать папку Компания? Или мне нужно сделать папку Компания, а внутри неё — Документы? Оба варианта рабочие, но какой из них правильный? Какой лучше?

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

Решение проблемы иерархии


А не так с ней то… что иерархия “общее/частное” не работает. Так для чего тогда хороши иерархии?

Для включения (Containment).

Если посмотреть на реальный мир, то вы везде будете натыкаться на иерархии включения. А чего вы не найдёте, так это иерархии “общее/частное”. Не будем пока на этом останавливаться. Объектно-ориентированная парадигма изначально была взята из реального мира, наполненного объектами. Но потом она начала использовать порочные модели, вроде иерархии “общее/частное”, аналогов которым в жизни не существует. Зато мир наполнен иерархиями включения. Хороший пример — ваши носки. Они лежат ящике, который находится внутри шкафа, который находится внутри вашей комнаты, которая находится внутри вашего дома и т.д.

Другой пример иерархий включения — папки в компьютере. Они содержат файлы. Как мы их категорируем? Если вспомнить о документах компании, то не особо-то и важно, куда их класть, в папку Документы или в папку Барахло. Важно то, что я категорирую их с помощью тэгов. Я помечаю файл такими тэгами:

  • Document
  • Company
  • Handbook

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

Инкапсуляция, второй обрушившийся столп




На первый взгляд, инкапсуляция — второе важнейшее преимущество объектно-ориентированного программирования. Переменные объекта защищены от доступа снаружи, то есть они инкапсулированы в объект. Больше не нужно беспокоиться о глобальных переменных, к которым обращается кто ни попадя. Инкапсуляция — это сейф для ваших переменных. Инкапсуляция просто НЕВЕРОЯТНАЯ!!! Долгой жизни инкапсуляции… До тех пор, пока не возникнет…

Проблема ссылки (The Reference Problem)


Ради повышения производительности, функциям передаются не значения объектов, а ссылки на них. Это означает, что и сами функции передают не объекты, а ссылки. Если ссылка на объект передаётся конструктору объектов, то он кладёт её в приватную переменную, защищённую инкапсулированием. Но переданный объект небезопасен! Почему? Потому в какой-то части нашего кода содержится указатель на объект, то есть код, вызывающий конструктор. Но он ДОЛЖЕН иметь ссылку на объект, в противном случае он не сможет передать её конструктору.

Решение проблемы ссылки


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

Полиморфизм, третий обрушившийся Столп




Полиморфизм — это рыжеволосый пасынок Объектно-Ориентированной Троицы. Вроде Ларри Файна в этой компании. Куда бы они не отправились, он был с ними, но всегда на вспомогательных ролях. Это не значит, что полиморфизм плох, просто для его использования вам не нужен ОО-язык. Его могут предоставить интерфейсы. Причём безо всякой дополнительной объектно-ориентированной нагрузки. Кроме того, в случае с интерфейсами вы не ограничены количеством возможных поведений, которые можно сочетать. Так что без лишних разговоров прощаемся с ОО-полиморфизмом, и приветствуем полиморфизм на основе интерфейсов.

Нарушенные обещания




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

И что теперь?


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

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


  1. DexterHD
    05.08.2016 13:36
    +111

    Как обычно, куча помоев вылитая на одну парадигму и уже заезженное "Пикачу ФП я выбираю тебя". Без агруменов, примеров, и какого либо описания того, как же это круто и почему это круто.


    1. napa3um
      05.08.2016 13:58
      +32

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


    1. pda0
      05.08.2016 16:44
      +61

      Ну, это мне сейчас веганов напомнило.

      Я — функциональщик. Прекрасно себя чувствую. Это вы от объектов такой раздражительный.


      1. taulatin_one
        05.08.2016 17:47
        +4

        А что функциональщики у нас не используют объекты и прочие чуждые для них элементы?


        1. Idot
          05.08.2016 18:05
          +3

          «Новообращённые святее Папы Римского» ©
          Помнится недавно в обсуждении ФП, один из его адептов отказывался признавать LISP в качестве ФП (язык с которого ФП и началось), за то что в новых его версиях была добавлена поддержка ООП.


          1. sumanai
            05.08.2016 20:55
            +4

            за то что в новых его версиях была добавлена поддержка ООП.

            Интересно, насколько новых? Даже при чтении «Структура и интерпретация компьютерных программ» начиная с главы 3 идёт ООП. А книжка то старая.


            1. Idot
              06.08.2016 05:12
              +2

              LISP появился раньше, чем C++ и последующая мода на ООП. LISP появился в 1954 году, C++ в 1983 году, а первая версия Object LISP в 1985 году. Однако, мода на ООП всех захлестнула после Windows 3.0, так как под DOS и UNIX без проблем обходились и без ООП, от чего был былинный срач о ненужности/нужности ООП, а вот Windows уже требовал именно ООП чтобы писать что-то неконсольное.

              PS поскольку речь зашла о связи Windows и ООП, то интересно как работают без ООП интерфейсы у ФП программ написанных без ООП?


              1. Idot
                06.08.2016 05:26

                поскольку речь зашла о связи Windows и ООП, то интересно как работают без ООП интерфейсы у ФП программ написанных без ООП?
                Я про пользовательский интерфейс программы.


                1. 0xd34df00d
                  08.08.2016 04:54
                  +1

                  1. Idot
                    08.08.2016 10:16

                    Спасибо!


              1. IIvana
                07.08.2016 07:30

                а вот Windows уже требовал именно ООП чтобы писать что-то неконсольное

                Чего? Я ни разу не умею это ваше (С) ООП, пишу гуевые программки и игрушки под Винду на чистых сях/хаскеле/чем угодно — что я делаю не так? ВинАПИ сишное на все сто, куда и зачем мне объекты пихать?


                1. Antervis
                  07.08.2016 08:17
                  +2

                  COM-объекты ж еще есть


          1. Per_Ardua
            06.08.2016 06:16

            В таком случае он, наверное, и JS не признает в качестве ФП. По мне так, если функциональный подход реализуем средствами языка, то такой язык можно считать ФП (даже, если он позиционируется как ОО-язык)


            1. vintage
              06.08.2016 10:13

              В JS невозможно реализовать сколь-нибудь полезную чистую функцию. О каком ФП тут можно говорить?


              1. ivan386
                06.08.2016 13:59

                Поясните подробней пожалуйста с чем это связано?


                1. vintage
                  06.08.2016 14:57

                  Как чистые функции связаны с фп?


                  1. ivan386
                    06.08.2016 15:14
                    +3

                    Невозможность реализации полезной чистой функции.


                    1. MaximChistov
                      09.08.2016 16:03

                      подозреваю что он о том, что сторонний код может что-то используемое в функции ВНЕЗАПНО подменить(например undefined)


          1. igrishaev
            06.08.2016 10:00
            +1

            Хех, так Лисп — это не функциональный язык. Лисп поддерживает ФП-парадигму, но не заставляет ей следовать. Вы можете писать на Лиспе в стиле раннего Си с глобальными переменными.


        1. 0xd34df00d
          06.08.2016 04:26
          +1

          Что за объекты в хаскеле?


    1. lookid
      05.08.2016 22:49
      -13

      Это статья детектор. Для выявления тех, кто не знает ООП или очень мало (лабки в вузе) писал на нем. Я полностью согласен с автором. Поддерживать ООП-код, когда у тебя 100500 классов и чтобы добавить хоть какую-то доп-фичу нужно перелопачивать 100500 классов и интерфейсов, это ад. Вы видели Java Framework'и? Как вам? Ужас? А что творится с кешем, а виртуальное наследование? Это сущий кошмар.

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


      1. lair
        05.08.2016 22:50
        +16

        Поддерживать ООП-код, когда у тебя 100500 классов и чтобы добавить хоть какую-то доп-фичу нужно перелопачивать 100500 классов и интерфейсов, это ад.

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


        1. lookid
          05.08.2016 22:58
          -21

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


          1. lair
            05.08.2016 23:00
            +12

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

            Например?


            И когда архитектура разрастается, то поддерживать и расширять её становится настолько сложно, что она превращается в «плохую архитектуру».

            Так, а альтернативные предложения?


            Давайте вы сами (да и отписавшиеся здесь) не будете себя обманывать. Вы никогда не писали архитектуру.

            Оу да, конечно, вам виднее, что я (и остальные отписавшиеся) писал.


            1. lookid
              05.08.2016 23:07
              -11

              Если вы писали полиморфизм и парочку extends-implements, то вы не писали архитектуру. Давайте не будем забывать, что 99% здесь отписавшихся никогда не испытывали проблем с кешем и производительностью из-за использования ООП. И 99% здесь пишут ООП ради ООП.


              1. lair
                05.08.2016 23:08
                +5

                Я же говорю, вам явно виднее, кто что писал. Зато как конкретные вопросы — так никаких ответов. Мимими.


                1. lookid
                  05.08.2016 23:15
                  -8

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


              1. lair
                05.08.2016 23:11
                +5

                Ну и да, признаюсь, я правда никогда не испытывал проблем с кэшом и прозводительностью из-за использования ООП. Разное было, и хреновый I/O (пятикратная просадка), и идиотская ошибка в распаковке base64 (шестидесятикратная просадка), и всякие другие вещи — а вот ООП как-то не мешало пока еще.


              1. areht
                05.08.2016 23:20
                +4

                > никогда не испытывали проблем с кешем и производительностью из-за использования ООП

                мм… А вы вообще в курсе, что ООП-программы компилируются в тот же ассемблер, что и всё остальное?


                1. Toshiro
                  06.08.2016 15:15
                  -1

                  У него свой ассемблер с блекджеком и ш@#$%^и)) И в его ассемблере ООП при компиляции вызывает проблемы с кешем и производительностью)) Ну чего вы набросились на человека?)))


                  1. Mendel
                    07.08.2016 12:59
                    +1

                    Ну справедливости ради — проблемы с производительностью у ООП вполне себе реальная тема. типичный сценарий — быстро прототипируешь логику на простых SOLIDных классах.
                    Десяток уровней абстракции, сотня классов в предметной области где высокая связность всего и вся. И получаем дикую потерю в скорости. Но!
                    1 — без ООП мы бы еще схемы на доске рисовали, а не проблемы щупали.
                    2 — Задача обычно решается так или иначе кешированием, или некоторым нарушением изящной структуры.
                    3 — даже если задача действительно плохо пригодна для эффективной работы в ООП-парадигме (например в конечном итоге у нас оказывается 80% пятиэтажных join «в узких местах», которые занимают 80%, то всё равно гораздо проще и эффективнее писать это всё поверх уже работающей пусть и неэффективной структуры, чем «в вакууме».
                    4 — реально задач таких почти и нет. В голову сейчас приходит только один пример, да и то не у меня был — там предметная область была — научные исследования в области генетики. «Божественный код» это классическая лапша, поскольку о структуре там никто не думал, так что слабо детерминируется, и анализ его аналогично вызывает вопросы. Тут нельзя отрефакторить предметную область :)

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


                    1. Toshiro
                      07.08.2016 13:07
                      -6

                      Десятки сотен уровней абстракции… Сотни тысяч классов… Пятиэтажные json… Вы упретесь в невозможность поддержки такой системы намного раньше проблем с производительностью, независимо от того что у вас под капотом — ФП, ООП или гибрид!!!

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


                      1. lair
                        07.08.2016 13:55
                        +2

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


                        1. Toshiro
                          07.08.2016 15:17
                          -5

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

                          И мы опять возвращаемся к тому же самому. Что ООП != архитектура. Вы повторяете ту же ошибку, что и lookid и JustMoose выше. Делаете однозначные заявление о технологии в принципе, не учитывая детали ее применения.

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


                          1. Mendel
                            07.08.2016 15:26
                            +3

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


                            1. Toshiro
                              07.08.2016 15:30

                              А что тогда является показанием для архитектурных решений Карл?! о_О


                              1. Toshiro
                                07.08.2016 16:33

                                Да, поскольку часто выделение микросервов сокращаит оверхед. Например если части запроса асинхронные, не?

                                И вообще, мы как то ушли от основной темы. В общем я к чему — в целом вообще неважно ООП у тебя или ФП. Накосячить можно и так, и так.


                                1. lair
                                  07.08.2016 16:48
                                  +1

                                  Да, поскольку часто выделение микросервов сокращаит оверхед.

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


                                  в целом вообще неважно ООП у тебя или ФП. Накосячить можно и так, и так.

                                  Можно подумать, с этим кто-то спорил.


                          1. lair
                            07.08.2016 16:22

                            Голословное утверждение

                            Что именно голословное утверждение? Что распределенная система добавляет оверхед?


                            повышение или снижение производительности напрямую зависит от задачи

                            Не от задачи, а от архитектуры и контекста.


                      1. Mendel
                        07.08.2016 14:34

                        Нее. Там бы всё и утонуло под весом «микро»сервисов)
                        Вы тут совсем не в тему сказали.


                1. Piter_Y
                  08.08.2016 12:04

                  Если точнее, то в команды процессора или байт-код, для java например.


          1. struvv
            08.08.2016 12:01
            +3

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

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

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

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


            1. vlad72
              08.08.2016 17:04

              Не хотите написать статью про дырки в ФП?


              1. symbix
                08.08.2016 17:20

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

                Но я не считаю, что это проблема — просто надо понимать, что пишешь.


                1. 0xd34df00d
                  08.08.2016 20:14
                  +1

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


      1. C4ET4uK
        06.08.2016 09:19
        +2

        >Это статья детектор. Для выявления тех, кто не знает ООП или очень мало (лабки в вузе) писал на нем.
        Тут согласен. А дальше ересь пошла.


      1. fedor1113
        07.08.2016 01:47

        Кхм… Этот комментарий детектор. Для выявления тех, кто не знает ООП или очень мало (лабки в вузе) писал на нем (или тех, кого на нём писать [толком] не научили). Простите, но не смог удержаться… (ибо чистая правда)


      1. KroTozeR
        08.08.2016 12:02
        -1

        Наш проект собирается пол часа. Он достался нам по наследству от коллег, которые раньше писали с применением ФП, потом сели на C++ Builder и поехали всякие TХреньКотораяДелает() --> TХреньКотораяДелаетБольше() --> TХреньКотораяДелаетМного(). Так же пошли структуры с указателями на классы для передачи данных между ними… и т.д. и т.п.

        Пытаемся по немногу рефакторить сего монстра. Встаивание функционала по ТЗ (т.н. «улучшения») в код, построенный на ФП происходит раза в четыре быстрее, чем в унаследованный код. Львиную долю времени приходится отслеживать связи, чтобы понять причину падения при успешной сборке.

        Да-да, архитектура, конечно, но она – наипрямейшее следствие злоупотребления ООП! И адепты ООП могут сколь угодно с пеной у рта рассказывать про «руки из жопы», но мы на этом теряем время, а потому активно выпиливаем из проекта этот зООПарк, ибо он вредит процессу.


        1. lair
          08.08.2016 12:08
          +2

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


        1. wholeman
          08.08.2016 12:24

          Люди сменили парадигму программирования. Естественно, что проект, на котором они осваивали новую, имеет, мягко говоря, некоторые недостатки. Чувство любого инструмента приходит после периода проб и ошибок.


    1. neit_kas
      07.08.2016 01:13
      +4

      Просто проблема автора в том, что он не использует парадигму, а поклоняется ей. Когда-то поклонялся ООП, потом нашёл в нём проблемы, и его мир был буквально разрушен. Теперь (с горя наверно) также стал поклоняться ФП. Ждём статью годика через два с заголовком: «Прощай, функциональное программирование».


      1. unixwz
        08.08.2016 11:56

        «Здравствуй процедурное».


        1. taujavarob
          08.08.2016 15:26

          «Здравствуй процедурное».


          Хм. Нужен ли goto?


          1. Idot
            08.08.2016 20:15

            Кнут в «Искусстве программирования» не стремался его активно использовать.


  1. symbix
    05.08.2016 13:38
    +44

    Эту ересь уже несколько раз обсуждали в комментариях. :)

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

    Посмотрим, как через пару лет он напишет то же самое про ФП :)


    1. shamanis
      05.08.2016 14:02
      +21

      Что вы еще ожидали в блоге майл.ру :)
      Плохая архитектура это их конек.


      1. herr_kaizer
        06.08.2016 09:21

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


        1. msnake
          08.08.2016 12:03
          +1

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


      1. Toshiro
        06.08.2016 15:22

        Мне тоже интересно, на основании чего) Хотя это мне многое объясняет)


    1. G-M-A-X
      05.08.2016 14:22
      +2

      Тогда зачем было лепить из ООП дуру, если три кита, на которых он стоит — фигня? :)

      П.С.
      ООП использую в меру, без фанатизма.


      1. symbix
        05.08.2016 15:13
        +4

        Это смотря что считать китами.

        «Actually I made up the term „object-oriented“, and I can tell you I did not have C++ in mind.» — Alan Kay


      1. areht
        05.08.2016 18:59
        +3

        Кто вам сказал, что именно это киты ООП?

        GoF 20 лет назад разжевали, что наследование использовать не надо, и как именно не надо.


        1. BlackRaven86
          05.08.2016 22:59

          Добавлю статью на тему от Герба Саттера — "Uses and Abuses of Inheritance": часть 1, часть 2


    1. poxu
      06.08.2016 14:25
      +1

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


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


      1. IIvana
        07.08.2016 07:40

        Догадаться несложно — поверить тяжело )

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


        1. poxu
          08.08.2016 15:49

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


      1. Source
        07.08.2016 14:46

        Добавлю ссылку на первоисточник цитаты из сообщения IIvana: http://lists.squeakfoundation.org/pipermail/squeak-dev/1998-October/017019.html
        Полный текст интереснее.


  1. kohus
    05.08.2016 13:40
    +14

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


    1. arvitaly
      05.08.2016 14:10
      -6

      Проблема повторного использования — единственная проблема в программировании (речь не только о чужом коде, но и о своем). И да, в ФП тоже меняются интерфейсы, но происходит это значительно реже, так как меняется лишь одна функция. Если же в ООП меняется один метод или публичное свойство, то все остальные тоже идут на свалку, так как меняется интерфейс всего объекта. Мало того, если меняется интерфейс любого из родителей, то на свалку идет вся эта гора. Грубо говоря, ФП позволяет делать детали максимально мелкими. Это добавляет сложности композиции, но это уже к вопросу об умственных способностях программистов. Собственно, нет вопроса, что эффективнее, есть вопрос — где взять столько умов. Поэтому, простые языки, типа Go, в промышленности эффективнее, гораздо проще менять разработчиков.


      1. lair
        05.08.2016 14:13
        +8

        Проблема повторного использования — единственная проблема в программировании

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


        1. arvitaly
          05.08.2016 14:22
          -8

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


          1. XPC_Ro_D12
            06.12.2016 18:27

            Автору на будущее. Пишется не P.S.S, а P.P.S.


            1. arvitaly
              05.08.2016 14:41
              -14

              > Во-первых, это само по себе не правда. Во-вторых, только очень маленькое количество программ линейно.
              Все программы линейны.
              > Это тоже не правда. Во-первых, она сама должна быть поименована, во-вторых, используемые ей операции должны быть поименованы. Это необходимый минимум.
              Не должна. Не должны.
              >Почему это?
              Потому что, тезисы должен доказывать тот, кто их выдвигает.


              1. lair
                05.08.2016 14:44
                +10

                Все программы линейны.

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


                Не должна. Не должны.

                То есть используемая вами программа не имеет никакого имени, и используемые в ней операции — тоже не имеют никаких имен?


                Потому что, тезисы должен доказывать тот, кто их выдвигает.

                Ну вот и доказывайте тезис о том, что "инвалидация кэша не относится к задачам программирования" — вы же его выдвинули?


                1. arvitaly
                  05.08.2016 14:49
                  -15

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


                  1. lair
                    05.08.2016 14:53
                    +4

                    Только в вашей вселенной. Это ваш тезис.

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


                    Именно так.

                    Приведите пример. Я не знаю ни одной программы, не имеющей названия.


                    Нет, вы выдвинули тезис, что это задача программирования.

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


                    1. arvitaly
                      05.08.2016 15:04
                      -11

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


                      1. lair
                        05.08.2016 15:10
                        +6

                        Именно это я и утверждаю.

                        В таком случае вся индустрия внезапно занимается не тем. Угу.


                        Естественно, если вы, опять же, не забыли про декларированную мною «единственную сложность»

                        Рекурсивные определения не ко мне.


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

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


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

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


                        1. arvitaly
                          05.08.2016 15:18
                          -8

                          > В таком случае вся индустрия внезапно занимается не тем. Угу.
                          Не знаю чем занимается ваша выдуманная индустрия, моя занимается проблемой повторного использования.
                          > Рекурсивные определения не ко мне.
                          Я заметил, что у вас сложности с ведением диалога.
                          > Содержащая десяток именованных объектов. Поэтому, внезапно, задача именования все еще актуальна.
                          Именование этих объектов не относится к программированию никаким боком, если вы не заметили для написания этой безымянной программы (кстати, поздравляю, вы ее увидели первый раз в жизни), мне не пришлось выдумывать ни одного нового наименования.
                          > Никто не ставил мне эту задачи, они возникли как частная проблема внутри конкретной бизнес-задачи
                          Ура, теперь и вы поняли, что задача инвалидации кэша является задачей бизнеса, а не программирования, и ключевое решение «какой вариант выбрать» принимается на уровне бизнес-планирования. А вот уже обычную задачу «инвалидация кэша при вот таком-то выбранном бизнес-решении» можно решить и программированием.


                          1. lair
                            05.08.2016 15:20
                            +5

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

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


                            PS


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

                            А вот и нет. Бизнесу на это положить, у бизнеса есть ровно одно требование: 30+ транзакций такого типа в секунду (при такой-то загрузке).


                            Впрочем, повторюсь, представления вашей индустрии о программировании меня не интересуют.


                            1. arvitaly
                              05.08.2016 15:23
                              -10

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


                            1. VolCh
                              05.08.2016 21:26
                              +2

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


                              1. lair
                                05.08.2016 21:48

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


                              1. arvitaly
                                06.08.2016 04:24
                                -4

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


                                1. michael_vostrikov
                                  06.08.2016 06:55
                                  +1

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


                                  1. arvitaly
                                    06.08.2016 07:00
                                    -5

                                    Я предлагаю называть вещи своими именами и не преувеличивать. И нет, не все задачи в IT-отрасли относятся к программированию! Но и к UX-дизайнерству или управлению тоже не относятся. Если вы не знаете как называется конкретная отрасль — не повод называть ее программированием, правда? И так странно слышать «тыжпрограммист» на ресурсе для программистов, похоже давно нужно было поднять эту тему, вон как все запустилось.


                                    1. areht
                                      06.08.2016 12:05
                                      +1

                                      Так и как же называется человек, который формулирует когда кеш инвалидировать?


                                      1. arvitaly
                                        06.08.2016 12:21
                                        -3

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


                                        1. areht
                                          06.08.2016 12:55
                                          +2

                                          > менеджер проекта

                                          Этот человек должен диаграммы Ганта инвалидировать, когда уволит программистов, не инвалидировавших кэш.

                                          > IT-директор

                                          А этот, на втором собеседовании, спрашивать «к кому вы пойдёте, если надо инвалидировать кэш?».

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


                                1. doniys_a
                                  06.08.2016 14:59

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

                                  А то, что некоторые люди (ох, как оказалось их много), занимаясь не только программированием, решили, что теперь все есть оно, наверное, это ЧСВ, ну, или банально ошибка

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


                    1. VolCh
                      05.08.2016 21:21
                      +2

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


              1. Idot
                06.08.2016 15:27
                +3

                Все программы линейны.

                Извините за личный вопрос, Вы случайно не закончили краткие курсы, вместо учёбы в ВУЗе?
                Уж очень в Вашем сообщении сквозит невежество и отсутствие какого-либо знакомства с теорией.


          1. encyclopedist
            05.08.2016 20:12
            +3

            А нет никакой сложности в написании линейной программы

            Про "проблему остановки" вы похоже не слышали.


            1. hlogeon
              05.08.2016 21:26
              +4

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


              1. arvitaly
                06.08.2016 02:12
                -3

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


                1. 0xd34df00d
                  06.08.2016 04:38
                  +1

                  Я с теорией категорий немножко знаком, и мне непонятно, как она помогает писать более короткий код.

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


                  1. arvitaly
                    06.08.2016 05:24
                    -1

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


                1. hlogeon
                  06.08.2016 05:18
                  +6

                  И тогда выходит, что те 6 статей, что вы тут писали — пустой звук. Все и так уже поняли, что вы зеленый и собеседников слушать не хотите, в двух соседних комментариях противоречите сами себе. Так активно рассуждаете про теории, а которых, судя по набору технологий о которых вы пишите(а значит в которых разбираетесь), вы понятия не имеете.
                  Даже спорить не хочется с очередным JavaScript- & PHP-функциональным программистом, с одной стороны находящим проблемы даже в шаблонизации HTML и тут же говорящим об отсутсвии оных в программировании вообще.

                  В проектах, где количество разработчиков больше одного, задача разделения кода и отображения — одна из первоочередных


                  Почему нельзя написать идеальную программу

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

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

                  Поэтому наша программа из одной строчки гарантированно будет работать с ошибками.


                  По долгу службы приходится иметь очень много дел с JSON, и здесь система типов TypeScript не помогает ничем, даже мешает, ведь компилятор сообщает об отсутствии ошибок, JSON.parse возвращает тип Any. Кроме того, TypeScript не поддерживает рефлексию, ввиду специфики работы, а значит, нет возможности проверить тип, основываясь на уже существующем коде. Также, до последнего времени, средств для мета-программирования не было вовсе.


                  1. vintage
                    06.08.2016 10:24

                    На самом деле TypeScript уже поддерживает рефлексию. Правда пока в весьма куцем виде.


                    А результат работы JSON.parse вы всегда можете скастовать к более конкретному типу после (или во время, благодаря type guards) валидации.


                    1. hlogeon
                      06.08.2016 10:26

                      И что? Это решает все проблемы программирования и в нем их больше нет?) Цитаты из постов arvitaly которы утверждает, что программирование лишено проблем в принципе.


                      1. vintage
                        06.08.2016 10:50
                        +1

                        Просто делюсь информацией на тему. Вы чего такой агрессивный? :-)


                        1. hlogeon
                          06.08.2016 10:56
                          +1

                          Утро добрым не бывает :D


          1. samaranin
            07.12.2016 14:10

            Большое спасибо!


            1. arvitaly
              07.08.2016 07:49
              -1

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


              1. Ckpyt
                07.08.2016 07:56

                А не надо путать программиста — человека, дающего код в ответ на требование «дай мне кнопку сделать все» и кодера — человека, реализующего написанный алгоритм :-)


                1. arvitaly
                  07.08.2016 08:53
                  -3

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

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

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

                  Согласен, все это путать не надо, да и в википедии (по вашей же ссылке) примерно это и описано https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%81%D1%82#.D0.A1.D0.BB.D0.BE.D0.B2.D0.BE.D1.83.D0.BF.D0.BE.D1.82.D1.80.D0.B5.D0.B1.D0.BB.D0.B5.D0.BD.D0.B8.D0.B5. А на требование «дай мне кнопку сделать все» дают код в ответ не программисты, а несуществующие персонажи из сказки «Программист — бог».


        1. 4eyes
          05.08.2016 15:05
          +10

          либо проблем две, и это именование и инвалидация кэша.
          две: именование, инвалидация кеша и ошибки на единицу.


          1. lair
            05.08.2016 15:07

            (и я даже знаю источник)


          1. arvitaly
            05.08.2016 16:56
            -7

            Ошибка на единицу тоже возникает из-за желания уменьшить повторный код путем введения цикла.


        1. zunkree
          05.08.2016 20:54

          Справедливости ради стоит заметить, что не в программировании, а в computer science.


          1. lair
            05.08.2016 21:47

            Если о втором варианте, то да, формально да. Прямо скажем, в первом варианте это тоже не "сложность", это "основной императив".


      1. den_golub
        06.12.2016 18:28

        Да, точно. Благодарствую, поправил.


      1. symbix
        05.08.2016 15:18

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

        В Go, кстати, очень элегантная реализация ООП.


        1. arvitaly
          05.08.2016 15:33

          >Если изменился контракт — очевидно, что требует изменений и код, полагающийся на него. Это справедливо для любой парадигмы.
          Речь о величине куска с контрактом. Чем он меньше, тем меньше изменений в использующем его коде.


          1. areht
            05.08.2016 19:10
            +2

            > Речь о величине куска с контрактом. Чем он меньше, тем меньше изменений в использующем его коде.

            И при чём тут ООП?


          1. svekl
            05.08.2016 21:59
            +1

            Величина контракта не зависит от парадигмы, большие контракты — это проблема исключительно архитектуры


          1. symbix
            06.08.2016 01:09

            Поэтому лучше, когда контракты явно объявлены и придерживаются SRP.

            Ровно то же справедливо для любой парадигмы, опять же. Названия меняются, суть остается.


            1. arvitaly
              06.08.2016 03:20
              -4

              Нет никаких проблем в написание однократно используемого кода. Проблемы начинаются, когда для разных модулей/проектов/систем разные представления о SRP для данного объекта и конкретного метода.
              В ООП жестко задан тип связи между методами (поведение объекта), в ФП — и эта связь является описываемой функцией. Так вот в одном модуле этот класс объекта полностью поддерживает SRP, а в другом нужна только его половина.
              Мало того, каждый модуль можно рассматривать во временном промежутке. Сегодня SRP для него таков, а завтра может быть что-то изменится (тут можно спорить о качестве композиции).
              И вновь напомню, что люди не одинаковые. Для одних будет SRP заключаться в этом, для других в другом.
              Так вот, ФП позволяет сделать систему гибче, за счет настраиваемости связей, жестко зашитых в ООП (да, да, именно публичные, приватные, защищенные свойства, принципы наследования и т.д.). Но за эту гибкость приходится платить сложностью — мы знаем гораздо меньше заранее об одном и том же объеме кода (чем в ООП). Немногие способны компилировать в голове такой код, в отличии от, например, линейного скрипта. Поэтому детям в школе дают QBasic. Не потому, что на нем нельзя чего-то написать, а потому что на единицу объема доступный для разбора мозгом код. А кто-то способен ночью, проснувшись, прочитать чужой haskell и мгновенно понять.
              Так что, выбор парадигмы напрямую зависит от ваших возможностей и потребностей, но именно в связи с совокупными возможностями ваших программистов.
              Кстати, советую всем в возрасте от 35 лет (усредненно) принять свой уровень, как данность и не мучаться угрызениями совести от незнания сложных языков.


              1. symbix
                06.08.2016 07:03
                +2

                1) в ООП, как и в ФП, и даже как и в процедурке, связей ровно столько, сколько вы напрограммируете.
                2) либо вы не понимаете, что такое SRP, либо я не распарсил
                3) если у вас с возрастом проблемы, я сочувствую, но не стоит говорить за всех. Робу Пайку скоро 60, а Кену Томпсону вообще уже 73, однако модный у молодежи Go они как-то сделали и продолжают над ним работать.


                1. arvitaly
                  06.08.2016 08:01
                  -4

                  > 1) в ООП, как и в ФП, и даже как и в процедурке, связей ровно столько, сколько вы напрограммируете.
                  В ООП уже зашиты некоторые из них (я описал выше какие), поэтому нет, там их меньше, в ФП приходится писать их вручную.
                  > 2) либо вы не понимаете, что такое SRP, либо я не распарсил
                  А фишка как раз в том и заключается, что нет формулы определения SRP, понятие завязано на семантике, которая не определена формально даже в естественных языках (а именно с помощью слов из естественных языков и даются названия обобщениям). Например, пресловутый стул, как оказалось может быть и сидением и предметов торговли, иметь и три ножки и вообще не иметь ножек и т.д. Создайте класс стул с его SRP и получите непонимание уже даже вашего соседа) Что уж говорить про интернациональные пакеты.
                  > 3) если у вас с возрастом проблемы, я сочувствую, но не стоит говорить за всех. Робу Пайку скоро 60, а Кену Томпсону вообще уже 73, однако модный у молодежи Go они как-то сделали и продолжают над ним работать.
                  Не понял, где тут логическая связь вообще. Я говорю всего лишь о том, что после определенного возраста обучение сложным вещам дается намного тяжелее. А то, что Пайк обладает уровнем для создания простого языка, не говорит о его возможности к созданию (или даже изучению) гораздо сложного, правда? В любом случае, ремарку про усреднение я оставил неспроста. Для кого-то это может быть и 60, но Пайк не тот пример.


                  1. grossws
                    06.08.2016 17:34
                    +1

                    семантике, которая не определена формально даже в естественных языках

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


                  1. symbix
                    06.08.2016 23:13
                    +1

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

                    Вообще, сделать простой язык — намного сложнее, чем сложный.

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


              1. wholeman
                08.08.2016 12:55

                Кстати, советую всем в возрасте от 35 лет (усредненно) принять свой уровень, как данность и не мучаться угрызениями совести от незнания сложных языков.
                Утверждение, типичное для возраста до 25 лет или ранее.
                Проблема не столько в возрасте, сколько в опыте. Освоив, например, ООП и простой язык C++, для смены их на что-то другое уже нужны достаточно веские причины, поскольку новый язык придётся осваивать заново. Даже если он отличается несильно, тонкие ощущения будут другими, т.к. некоторые конструкции, которыми привык оперировать, могут отсутствовать, а для их замены есть что-то другое.
                Также приходит понимание, что языков много, и изучить каждый вновь придуманный, потому что кто-то считает, что он — лучше всех, просто не хватит времени.


                1. 0xd34df00d
                  08.08.2016 20:16

                  Так не в этом ли и дело, что в более юном возрасте всякие разные новые языки учатся с большим удовольствием и большим стремлением, что ли?


                  1. taujavarob
                    08.08.2016 20:36

                    Так не в этом ли и дело, что в более юном возрасте всякие разные новые языки учатся с большим удовольствием и большим стремлением, что ли?

                    Полно людей, севших 30 лет назад на C и так и не слезших с него.


                    1. vlad72
                      08.08.2016 20:58

                      В молодости интересно все новое, но потом становится достаточно эффективности.


                      1. 0xd34df00d
                        08.08.2016 21:05

                        Ну вот грустно, когда интерес пропадает, и становится достаточно чего-то там.


                        1. wholeman
                          08.08.2016 22:46

                          Интерес не пропадает — он меняет направление и становится более осмысленным. В юности это (было) больше похоже на метания.


                          1. taujavarob
                            09.08.2016 17:32

                            Интерес не пропадает — он меняет направление и становится более осмысленным.


                            Он просто меняет направление. — Знаю программиста на SQL — с возрастом он стал начальником отдела и начал… писать стихи. — При встрече просил никогда не говорить с ним о базах данных и SQL.


                        1. vlad72
                          08.08.2016 23:34

                          Саморазвитие возвращает юношеские дерзания ))


                    1. Idot
                      09.08.2016 03:47

                      А есть ещё давно севшие на COBOL, и недавно была про это статья. Если за язык хорошо платят, а работа нравится и приносит удовольствие, то нет нужды слезать с языка.


                      1. taujavarob
                        09.08.2016 17:32

                        Если за язык хорошо платят, а работа нравится и приносит удовольствие, то нет нужды слезать с языка.


                        Тут много если. Имхо


                  1. Idot
                    09.08.2016 10:58

                    Ну, в юном возрасте, я изучал на бумаге и CLU и Modula, и кучу других экзотических языков, и даже пытался учить PL/1, но отсутствие доступных компиляторов остановило меня.


                    1. taujavarob
                      09.08.2016 17:34

                      Ну, в юном возрасте, я изучал на бумаге и CLU и Modula, и кучу других экзотических языков, и даже пытался учить PL/1, но отсутствие доступных компиляторов остановило меня.


                      Потом вы выучили Adabas, Foxpro, Clipper и Дельфи, завершив всё SQL и Java. Наверное.


        1. VolCh
          05.08.2016 21:27

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


      1. MisterN
        05.08.2016 20:54

        Господи, вы хоть поняли, что поставили выбор парадигмы программирования в зависимость от «умственных способностей программиста»? Если в ооп меняется один метод или публичное свойство, то все зависит от того, насколько меняется и как оно влияет на другие. Так же, как и в функциональном проганьи. Зачем нужно делать функцию? Чтобы её потом везде использовать. А если мы много используем функцию и вдруг её радикально изменили, обновив в том числе и параметры? Ну а чем в этом смысле отличаются методы объекта?


    1. pda0
      05.08.2016 17:00
      +3

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

      Но раз автор этого не знает, то он далёк от понимания программирования вообще, так что всерьёз воспринимать его критику…


    1. 0xd34df00d
      06.08.2016 04:31

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


  1. ilyaplot
    05.08.2016 13:43
    +9

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


  1. ik62
    05.08.2016 13:44
    +17

    прощай Charles Scalfani, Software Engineer and Architect, Teacher, Writer, Filmmaker, Photographer, Artist… — объектно-ориентированному программированию будет тебя очень не хватать.


    1. overmind0
      06.08.2016 12:54

      Тоже обратил внимание что он и на дуде игрец


  1. napa3um
    05.08.2016 13:48
    +5

    Объявлен год ФРП. Количество статей с хвалами ФП и ненавистью к ООП увеличилось вчетверо.


    1. vadim_shb
      06.08.2016 00:57
      +1

      Вроде прошлый таким был… Или позапрошлый…


  1. elmm
    05.08.2016 13:51
    +1

    Интересно, кто раньше умрёт ООП или я? Хоронят, хоронят его, а оно всё ни как не умирает.
    И в каждой такой статье по сути одно и тоже уже. Скучно.


    1. TyVik
      05.08.2016 14:02
      +1

      Да не умрёт оно никогда, в крайнем случае поменяет название. Идея хорошая и применима во многих случаях.


  1. Misiam
    05.08.2016 13:55
    +12

    Каждый раз вспоминается шутка с одного it форума (ссылка на оригинал затерялась):

    «Почему они выбирают между ООП и процедурами? Надо выбирать между ООП и HTTP.» © Popoff


  1. forketyfork
    05.08.2016 13:59
    +22

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


    1. areht
      05.08.2016 19:25
      +1

      Ну, это не проблема с состоянием, или ООП. Это проблема языка.
      Если в C# ты пометил add() в базовам классе как virtual, но начинаешь его вызывать(т.е. меняется семантика) — это неявный breaking change, и свинство.
      Если virtual add(int n){internalAdd(n);} — и проблемы нет.

      в Java как-то не очевиднее.


      1. 0xd34df00d
        06.08.2016 04:45
        +1

        Потому что там на самом деле три метода: публичные add и addMuti и приватный/протектед addImpl, при этом первые два никогда не вызывают друг друга, а делегируют непосредственную вставку третьему.

        Хочешь перехватывать общение с пользователем класса — переопределяешь первые два. Хочешь перехватывать реализацию — переопределяешь третий.

        Non-virtual interface из плюсов тут, кстати, тоже где-то рядом.


  1. TyVik
    05.08.2016 14:00
    +14

    Как же надоели такие статьи! Человек работал 10 лет с ООП, но так и не научился его готовить? И вместо того чтобы понять когда что использовать он предлагает всё переписать на ФП. Набьёт шишек там и напишет точно такую же обличительную статью про ФП. Прям круговорот какой-то…


    1. UA3MQJ
      05.08.2016 14:29
      +9

      1. VolCh
        05.08.2016 21:32
        +1

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


        1. UA3MQJ
          05.08.2016 22:29

          «мопед не мой» (с)


  1. Landgraph
    05.08.2016 14:00
    +3

    Только недавно перечитывал Страуструпа и там один из вариантов решения «проблемы ромба» на С++:

    class Copier: public Scanner, public Printer {
    public:
    using Printer::start;
    }
    


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


    1. develop7
      05.08.2016 14:22

      решать проблему ромба множественным наследованием — это, пожалуй, качественно новый уровень зла


      1. Landgraph
        05.08.2016 14:37
        +3

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


      1. dolk13
        05.08.2016 20:55
        +3

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


        1. BlessMaster
          06.08.2016 00:01
          +2

          В данном случае пример — это сама задача. Копир должен наследовать и принтер, и сканер. А это чуточку разные вещи, выполняющие разные задачи. «Старт» принтера и «старт» сканера — это не одно и то же, нельзя выбрать что-то одно из этого, нельзя «стартануть» их просто «по-очереди». Нужно, чтобы отработал сканер, забрать его результат и отдать обработать принтеру. Что в принципе независимый третий метод «старт».

          То есть архитектура уже должна приводить к компоновке, а не наследованию и разведению «состояний» «в разные углы». Копир состоит из принтера и сканера, связывая их дополнительными функциями, но не наследует их свойства, как может показаться на первый взгляд.

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


          1. vintage
            06.08.2016 00:19
            +1

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


            class Copier : Printer , Scanner {
            
                /// запускает основную функцию девайса (большая зелёная кнопка)
                start(){
                    return super->Printer::start( super->Scanner::start() )
                }
            
                /// конкретно у копира есть дополнительная кнопка запуска отдельно принтера
                print() {
                    return super->Printer::start()
                }
            
                /// конкретно у копира есть дополнительная кнопка запуска отдельно сканнера
                scan() {
                    return super->Scanner::start()
                }
            
            }


            1. symbix
              06.08.2016 00:28
              +2

              Для начала нужны PrinterInterface и ScannerInterface.
              Тогда все становится понятно: Copier implements PrinterInterface, ScannerInterface.
              Если в обоих интерфейсах методы называются start, а не scan и print, то будет плохо, но это надо было сразу думать над неймингом.
              Если же методы называются print() и scan(), как у нормальных людей, то и проблем нет.

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


              1. vintage
                06.08.2016 00:49
                +1

                Для начала нужны PrinterInterface и ScannerInterface.

                Не нужны. Нужна возможность наследовать интерфейсы без реализации:


                class Printer { ... }
                class Scanner { ... }
                class Copier implements Printer, Scanner { ... }

                Если же методы называются print() и scan(), как у нормальных людей, то и проблем нет.

                Если знать, где упадёшь, то можно и соломки подстелить: scanWithLaser(), printToBottomTray().


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

                И копипастить проксирование каждого из 100500 методов? А толку? Указывая "extends" вы фактически явно указываете проксировать всё, что не перегружено, до предка.


                1. symbix
                  06.08.2016 01:20

                  Интерфейсы нужны, потому что ISP.

                  scanWithLaser — как раз-таки нет, это уже детали реализации. Если кто-то наплодил интерфейсов с методами performAction или go, это уж ССЗБ. Имя метода должен отражать суть действия.

                  По поводу наследования все написано классиками в GoF — Favor 'object composition' over 'class inheritance'. Не вижу смысла пересказывать своими словами, все равно лучше не получится. Что касается «100500» — а зачем, а откуда? Всего два метода, это не больно. А если и правда 100500 — так боль уже в том, что их 100500, где-то забыли про SRP, типичный God Object. (И, кстати, копипастить надо не во всех языках).


                  1. vintage
                    06.08.2016 01:32

                    Интерфейсы нужны, потому что ISP.

                    Объявление класса уже является объявлением интерфейса. В большинстве случаев нет логической необходимости его дублировать отдельно.


                    scanWithLaser — как раз-таки нет, это уже детали реализации.

                    Это конкретизация интерфейса. Такая же, как и print|scan или startPrinting|startScanning вместо start.


                    По поводу наследования все написано классиками в GoF — Favor 'object composition' over 'class inheritance'.

                    Ни чем не обоснованный догматизм.


                    Всего два метода, это не больно.

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


                    А если и правда 100500 — так боль уже в том, что их 100500, где-то забыли про SRP, типичный God Object.

                    Давно вы практикуете гадание по числу методов? :-)


                    1. symbix
                      06.08.2016 02:09

                      Это не догматизм, это практика. Если мне на слово не верите, почитайте литературу. У того же Фаулера примеры из его практики.

                      Все, что мы знаем — что Copier должен уметь scan() и print(). Конкретные реализации Scanner и Printer могут не подходить. Может, у них у каждого независимая очередь, а нам тут нужна одна. Может, еще что. А может, сегодня подходят, а завтра нет. С делегированием такие проблемы решаются проще и безболезненнее.

                      По числу методов гадать нечего, это такая же объективная метрика, как и цикломатическая сложность.


                      1. vintage
                        06.08.2016 09:56

                        Это не догматизм, это практика. У того же Фаулера примеры из его практики.

                        В ваших устах это именно догматизм. А у того же Фаулера используется довольно нейтральное "предпочитайте". Я бы сформулировал проще: "не используйте наследование, если вам не нужно наследование — для повторного использования кода есть и другие техники".


                        Конкретные реализации Scanner и Printer могут не подходить.

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


                        Может, у них у каждого независимая очередь, а нам тут нужна одна.

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


                        По числу методов гадать нечего, это такая же объективная метрика, как и цикломатическая сложность.

                        Только имеет ещё меньше смысла. Вот у меня есть приложение ToDoMVC, полный интерфейс которого насчитывает 70 методов. Это много или мало? Если не использовать автоматическую делегацию агрегату (наследование), то конечно много — это ж чтобы добавить кнопочку в футер, нужно будет вручную повторить весь этот интерфейс.


                        1. symbix
                          06.08.2016 23:20

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

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

                          Разумеется, есть случаи, когда наследование абсолютно уместно. Например, что-то вроде Postgresql94QueryBuilder extends Postgresql90QueryBuilder extends PostgresqlGenericQueryBuilder extends AnsiSqlQueryBuilder.


                          1. vintage
                            07.08.2016 01:19

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


                            1. symbix
                              07.08.2016 04:37

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

                              Пусть наследуется, пусть что угодно — снаружи знать про это не надо, снаружи интерфейс.


                              1. vintage
                                07.08.2016 11:35

                                Интерфейс МФУ = Принтер+Сканнер+Копир. Этот интерфейс предполагает, независимую реализацию принтера и сканнера. Если вам нужен только копир, а принтер и сканнер не нужен, то довольно странно наследовать его от принтера и сканнера.


            1. areht
              06.08.2016 00:39

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

              «Не для науки ради, а так, чисто позырить...»

              Вам тут наследование что дало?


              1. vintage
                06.08.2016 00:53

                Реализацию обоих интерфейсов в одном объекте, очевидно.


                1. areht
                  06.08.2016 01:00

                  Очевидно, да. А дальше что?

                  Если у вас реализации интерфейсов не пересекаются, что дальше то? Кастим к одному из интерфейсов и получем обратно принтер, от которого наследовались?


                  1. vintage
                    06.08.2016 01:06

                    А что вы дальше ожидаете от МФУ?


                    1. areht
                      06.08.2016 01:13

                      Если вы 2 интерфейса засунули в один — это как принтер к сканеру днищами склеить. Перевернул — получил сканер, а не принтер. Это не то, что я ожидаю от МФУ.


                      1. vintage
                        06.08.2016 01:37

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


                        1. areht
                          06.08.2016 01:42

                          > один девайс, выполняющий 3 функции

                          Т.е. профит в нарушении SRP?


                          1. vintage
                            06.08.2016 02:05

                            Профит в появлении третьей функции, как результат объединение первых двух. Аналогичный случай:
                            InputRange + OutputRange = Channel.


                            1. areht
                              06.08.2016 02:13

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

                              > Аналогичный случай: InputRange + OutputRange = Channel.

                              А это с наследованием, что бы Channel к RangeBase было интереснее кастить? )


                              1. vintage
                                06.08.2016 10:07

                                А SRP тут, кстати, не нарушается. Копир не содержит реализацию ни принтера, ни сканера — он их берёт у предка. Когда нужно будет изменить разрешение сканирования по умолчанию — будет меняться класс Scanner, а не Copier.


                                А зачем вам кастить Channel к BaseRange?


                                1. areht
                                  06.08.2016 11:39

                                  То есть Copier можно отнаследовать ещё и от листа бумаги(холодильника и Array), и пусть печатает сам себя — это не нарушение SRP?

                                  То есть профит от наследования — в возможности создать god object «не нарушая SRP»?


                                  1. vintage
                                    06.08.2016 11:45

                                    Можно, если вам это почему-то нужно. Хотя, я затрудняюсь сказать зачем такое может понадобиться. Но нарушением SRP это опять же не будет.


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


                                    1. areht
                                      06.08.2016 11:54

                                      > Можно, если вам это почему-то нужно.

                                      Наследовать не «нужно». Никогда.
                                      Я вот от вас не могу добиться зачем вы отнаследовали 2 несвязанных класса.

                                      > Божественный объект — это объект, который содержит не связанную между собой реализацию

                                      И это именно то, что вы делаете.


                                      1. vintage
                                        06.08.2016 12:16

                                        Постановка задачи такая — нужен МФУ.


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


                                        1. areht
                                          06.08.2016 12:48

                                          > Постановка задачи такая — нужен МФУ.

                                          Мы ещё ваш код копира обсуждаем? Это не МФУ. На копире «scan» мне не нужен.
                                          Если нам нужен МФУ — у вас будет, например, 3 свойства *Settings: от принтера, сканера и МФУ. Это монстр Франкенштейна, а не МФУ.

                                          > В случае наследования, реализация находится в родителе.

                                          Если вы про god object — не имеет значения. God object — это проблема не реализации, а использования. Для внешнего кода не важно как именно класс агрегирует функционал всего.

                                          > В этом, собственно, и суть наследования — хранение общего поведения в отдельном классе (классах).

                                          Да ну? Для «хранения общего поведения в отдельном классе» наследование не нужно от слова «совсем»


                                          1. vintage
                                            06.08.2016 15:55

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


                                            Корневой неймспейс — вполне себе божественный объект в вашей интерпретации.


                                            А никто не говорит, что оно нужно. Оно удобно.


                                            1. areht
                                              06.08.2016 16:36
                                              +1

                                              > Нет смысла делать чисто копир, если можно сделать мфу.

                                              Нет смысла не сделать god object, понимаю.

                                              > Корневой неймспейс — вполне себе божественный объект в вашей интерпретации.

                                              В моей интерпретации неймспейс — не объект. Вы ещё и объект от неймспейса не отделяете?

                                              > А никто не говорит, что оно нужно. Оно удобно.
                                              > Можно, если вам это почему-то нужно.

                                              Ох…

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


                                              1. vintage
                                                11.08.2016 00:28

                                                У вас богообъектофобия? Вы видите их там, где их нет.


                                                Не отделяю. Я ещё и классы от объектов не отделяю. Вообще пропащий человек.


                                                А в чём удобство от повторения делегирования каждого метода?


                                                1. areht
                                                  11.08.2016 00:58

                                                  > А в чём удобство от повторения делегирования каждого метода?

                                                  — Доктор, когда я вот вот так вот делаю у меня болит..((
                                                  — А вы вот вот так вот не делайте


                                        1. babylon
                                          06.08.2016 19:00
                                          -1

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


                                          1. Idot
                                            06.08.2016 21:50

                                            babylon может статью с подробными пояснениями про нода-контейнеры напишете? *стало любопытно*


                                            1. babylon
                                              07.08.2016 00:44
                                              -1

                                              Для статьи слишком мало материала. Нода-контейнер любая нода, лежащая в массиве неймспейсов to


                                              1. Idot
                                                07.08.2016 08:35

                                                Если начать с введения, что такое Нода итп, то на статью вполне потянет.


                                                1. babylon
                                                  07.08.2016 16:48
                                                  -1

                                                  Idot Нода — наименьшая структурная единица. Родительские ноды лежат в массиве неймспейсов parent. Агрегирование (сборка) структуры происходит снизу вверх по индексам ключей. Работа сверху вниз от корня или от контекста, который заранее установлен. Контейнеры лежат в массиве неймспейсов from. Контенты — в to. Сигналы в массиве неймспейсов signals. Меньше параграфа.


              1. wholeman
                08.08.2016 11:45

                Вам тут наследование что дало?

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


                1. lair
                  08.08.2016 11:50

                  … а для этого не надо наследования. Для этого надо выставить публичный интерфейс "принтер".


                  1. wholeman
                    08.08.2016 12:34

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


                    1. lair
                      08.08.2016 12:48

                      У интерфейсов есть недостаток — их нужно реализовывать, хотя бы на уровне делегирования.

                      Это зависит исключительно от языка/фреймворка, которым вы пользуетесь. Но что самое важное, с точки зрения потребления этого класса (а вы написали именно о потреблении), эта проблема несущественна.


                      1. wholeman
                        08.08.2016 13:05

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

                        Я понял интерфейс, как в Java. Там он не имеет никакой реализации по определению. Конечно, в других языках может быть возможность определить для объекта интерфейс с реализацией, способом отличным от наследования, но зачем?


                        1. lair
                          08.08.2016 13:07

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

                          Чтобы избавиться от проблемы множественного наследования (и получить легкую/дешевую композицию).


                          1. wholeman
                            08.08.2016 13:31

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


                            1. lair
                              08.08.2016 13:32

                              Это пока вы не начали получать проблемы с неопределенным поведением.


                              1. wholeman
                                08.08.2016 13:49

                                Ну, раз 20 лет не получал, может и ещё 20 не получу.)


                    1. areht
                      08.08.2016 13:04

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


                      1. wholeman
                        08.08.2016 13:14

                        Факс в составе МФУ может сводиться к розетке RJ11 с интерфейсной платой. В рамках данной дискуссии это несущественно.


                        1. areht
                          08.08.2016 13:24

                          Ну, наверное, может. Хотя, я всегда факс видел на столе, а МФУ — отдельная тумбочка. Вот мне и было интересно каким наследованием это должно делаться.

                          Хотя, без наследования — тоже вариант.


                1. areht
                  08.08.2016 12:59

                  Т.е. вместо
                  Add(Copier.GetPrinter())
                  можно написать
                  Add(Copier)

                  Ну, принимается. Хотя ценность так себе.


                  1. lair
                    08.08.2016 13:09

                    … для этого, впрочем, наследование не нужно, нужно Add(IPrinter) и Copier: IPrinter (или implicit operator IPrinter(Copier copier))


                    1. areht
                      08.08.2016 13:18

                      Это где? в C# implicit operator к интерфейсу, вроде, нельзя.


                      1. lair
                        08.08.2016 13:23

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


                    1. areht
                      08.08.2016 13:58

                      Add(IPrinter) может от меня не зависеть, а implicit operator — это всё же костыль, которым лучше не злоупотреблять.

                      Я вообще не уверен, что хочу иметь на копире интерфейс принтера. I feel disturbance in Force.

                      Скорее MyUberDevice: IPrinter, ICopier


                      1. lair
                        08.08.2016 14:06

                        Ну так если Add не IPrinter, то мы и так в печали уже. А если оно таки IPrinter, то откуда мы это выставили — уже не важно, важно, что нас дальше не волнует, наследовались мы от какого-то принтера, или нет.


                  1. wholeman
                    08.08.2016 13:18

                    Хотя ценность так себе.

                    Для меня важно, что в случае наследования в список добавляется весь объект, а не его составная часть.


                    1. areht
                      08.08.2016 13:46

                      почему?


                      1. wholeman
                        08.08.2016 13:50

                        Эстетичнее.


                        1. areht
                          08.08.2016 14:04

                          hoarder nest


            1. BlessMaster
              06.08.2016 03:46

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


            1. babylon
              07.08.2016 18:02

              Конечно это агрегация. Проблема в том, что это ранняя агрегация. Ну или не проблема. Зависит от точки зрения :)


          1. wholeman
            08.08.2016 11:24

            В примере из статьи, скорее, просто проблема именования: название метода должно отражать процесс, то есть start — это подготовка устройства, которая вполне может происходить и параллельно для составных частей копира, а для печати/сканирования/копирования метод должен называться соответственно print/scan/copy, возможно с префиксом start_, если мы хотим не ждать окончания процесса, а получить отдельное сообщение о результате.
            Копир должен именно наследовать принтер и сканер, поскольку может использоваться как эти отдельные устройства, а не только их комбинация.


    1. f1inx
      05.08.2016 16:09
      +1

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


      1. vlad72
        06.08.2016 13:55

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


        1. Idot
          06.08.2016 14:19

          Что-то вроде Паскаля (или даже Дельфи), но для ООП?


          1. vlad72
            06.08.2016 15:05

            Да, ведь Java и возникла, чтобы сделать сложное (С++) простым. Но не было опыта, поэтому сделали по максимуму. Теперь надо ее минимизировать, чтобы «хоп-хоп и в продакшен» еще легче делать было. И это не только Java касается…

            Конечно, сам подход, что программисту надо о чем-то думать заранее, уже несовершенен. Но даже в ФП он присутствует…


    1. areht
      05.08.2016 19:19
      +1

      Проблема ромба не в том, что бы выбрать какую функцию start дергать. Проблема в том, что копир по кнопке «старт» не копирует (Карл!).


      1. oledje
        05.08.2016 21:45
        +4

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


        Class Copier {
            Scanner scanner
            Printer printer
            function start() {
                page = scanner.start();
                printer.start(page);
            }
        }

        Да и остальные примеры высосаны из пальца. Как уже неоднократно говорилось в коментариях к подобным статьям: плохая архитектура не проблема парадигмы.


        1. areht
          05.08.2016 22:00
          +1

          Ну, типа того. Осталось во всех 3-х классах переименовать start.


        1. BalinTomsk
          05.08.2016 22:45

          А зачем дополнительное инстанциирование?

          function start()
          {
              Scanner::start();
              Printer::start();
          }
          


          1. oledje
            05.08.2016 23:15

            За тем, что мы избавились от множественного наследования в пользу делегирования, как и завещала великая банда четырех. "Используйте делегирование вместо наследования". Наверно это можно повторять неустанно.
            Множественное наследование это мощный инструмент, но, как и любой другой мощный инструмент, должен быть использован с умом и осторожностью. Автор об этом не знает.


      1. Landgraph
        06.08.2016 11:34

        Конкретно в тексте у автора проблема именно в том, чтобы выбрать какую из функций start дёрнуть.

        Обратите внимание, что классы Scanner и Printer оба реализуют функцию start. Тогда какую функцию start унаследует класс Copier? Та, что реализована классом Scanner? Или классом Printer? Не могут же они обе унаследоваться.


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

        Я бы поставленную задачу решал как-то так:
        class Copier: public Scanner, public Printer {
        public:
        void start() { Printer::start(); Scanner::start(); }
        using Printer::print;
        using Scanner::scan;
        void copy() { Page *page = this->scan(); this->print(page); }
        }
        


  1. Cheater
    05.08.2016 14:05
    +8

    > Software Engineer and Architect, Teacher, Writer, Filmmaker, Photographer, Artist

    Какой разносторонний товарищ. Мне кажется, ФП ему нужно чисто в коллекцию титулов…


  1. maxru
    05.08.2016 14:06
    +3

    Статья для *banoe.it, а не хабра.


    1. herr_kaizer
      06.08.2016 09:29

      Такое там еще сильнее обольют.


  1. NeoCode
    05.08.2016 14:09
    +5

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


    1. C4ET4uK
      05.08.2016 14:47
      +6

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


      1. develop7
        05.08.2016 16:08
        +2

        Добро пожаловать в клуб Даннинга-Крюгера!


  1. Saffron
    05.08.2016 14:19
    +3

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

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


  1. Tiendil
    05.08.2016 14:23
    +12

    Читал в оригинале, увидел на хабре, думаю, кто ж решился этот трешак переводить… Смотрю: Mail.ru и даже не удивился — как всегда уверенно пробиваем очередное дно.


  1. MadridianFox
    05.08.2016 14:38
    +3

    Думаю много проблем в области ООП растут из того, что «умные делают а глупые учат». 99% всех объяснений ооп содержат в себе те самые 3 столпа, когда на самом деле их не три. Это лишь попытка систематизировать свойства ООП. И эта попытка стала очень популярной и отсюда куча однотипных и неверных примеров наследования. Да, вначале это кажется чем-то божественным, но потом, оказывается что надо отринуть привычное и делать композицию. Это кажется противоестественным потому что везде учат наследовать.


  1. pengyou
    05.08.2016 14:46
    +3

    Буллшит-бинго!


  1. Antervis
    05.08.2016 14:47

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


  1. lega
    05.08.2016 14:47
    +2

    Ты слышал про парня, который попрощался с OOП?
    О нет. Ещё один? Что же он сказал?

    Совсем недавно писали по этому поводу.


  1. wholeman
    05.08.2016 15:01
    +6

    Документы и компании для обрушения «столпа наследования» — классический приём демагогии: привёл два понятия, не связанных отношением «общее-частное» и на основе этого объявляем само отношение ненужным. Есть же случаи, когда это отношение работает, например, документы и отчёты, письма, заявления и т.д.

    Я открыл статью, задавшись вопросом: «А что взамен?», но так и не понял, чем так замечательно ФП и почему автор выбрал именно его.


    1. yul
      05.08.2016 15:43
      +1

      Тем, что там автор еще не «все понял».


      1. wholeman
        08.08.2016 12:21
        +2

        Понятно. Не осилил ООП — пошёл неосиливать ФП.


  1. KongEnGe
    05.08.2016 15:04
    +18

    Goto живо, а они ООП хоронят :)


  1. heleo
    05.08.2016 15:04

    Человек решает проблему иерархии переводя её в плоскость группировки и классификации… ЧуднО однако


  1. denegny
    05.08.2016 15:04

    в Ruby все объект


  1. chibitko
    05.08.2016 15:04
    +1

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


  1. hlogeon
    05.08.2016 15:07
    -5

    Божечки-матрешечки! Сколько уже можно? Предположу, что автор статьи через N-лет напишет «Почему ФП мертво», так и поняв, что мертво не ФП или ООП, а он, как инженер. Проблемы начинаются с самого начала, потому что автор подумал, что ООП — это способ переноса объектов реального мира в код, что само по себе, на мой взгляд, не очень правильно. Начало понимания ООП, на мой взгляд, как раз начинается с понимания того, что этого делать чаще всего нельзя. Попытка оправдать свою кошмарную архитектуру недостатками парадигмы(которы, конечно, безусловно есть) обречена на провал. Хороший инженер отличается от плохого тем, что может используя доступные ему инструменты делать качественные продукты. Автор же похож на типичную ТП, купившую зеркалку и возмонившую себя крутым фотографом, которой не вдомек, что качество твоей работы от фотоаппарата зависит далеко не в первую очередь. Что бы было понятней — вот фото конца 19 века, когда фотографам современные технологии даже в самых смелых мечтах и приснится не могли.
    image


    1. nikabc555
      05.08.2016 16:24
      +10

      Это не фото 19 века, а картина Arch of Constantine (Rome), нарисованная Бернардо Беллотто в 18 веке


      1. LoadRunner
        05.08.2016 16:56
        +1

        Какой век, такие и фото.


      1. hlogeon
        05.08.2016 21:18
        -1

        Ахах! Глупо вышло, не знаток искусства и фотографии(я же все-таки программист, а не фотограф), но я думаю, вы и сами без труда сможете найти старые фотографии, или очень красивые фотки снятые на обычные мыльницы или телефоны. Спасибо, что сказали, теперь запомню надолго, что это именно Бернардо Беллотто.
        Потерянное поколение XD


        1. Shamov
          06.08.2016 14:49
          +1

          Можно было выкрутиться, сказав, что это фотография картины. Прокси-объект… если говорить в терминах ООП.


  1. semenyakinVS
    05.08.2016 15:13
    +1

    «Демократия имеет много недостатков, но лучшего человечество не придумало» (с) У.Черчилль

    А если по существу — всё уже сказано выше. Автор статьи строит кривую архитектуру, после чего начинает ругает ООП за то, что архитектура получилась кривой. Если б я со своим почти нулевым опытом ФП бросился писать статью о ФП — от ФП вообще камня на камне не осталось бы. Кстати, о самом ФП автор пишет только, что ФП рулит… И всё (впрочем, это тоже уже заметили комментирующие выше).

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


    1. AcidBat
      08.08.2016 12:04
      +1

      Цитата Черчилля звучит немного по-другому:
      «Демократия — наихудшая форма правления, если не считать всех остальных.»


  1. potan
    05.08.2016 15:18
    +1

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


  1. HaruAtari
    05.08.2016 15:19
    +1

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


    1. symbix
      05.08.2016 15:23
      +1

      Я бы только добавил, что обмениваются сообщениями в соответствии с контрактами (это важно). А так целиком согласен.


      1. chaetal
        07.08.2016 21:26

        О каких контрактах речь? Почему это важно? Вы же не хотите сказать, что ООП не может быть без контрактов?


        1. symbix
          08.08.2016 01:19

          Потому что обмениваться произвольными сообщениями с кем попало довольно бессмысленно.


          1. Saffron
            08.08.2016 04:08
            +1

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


            1. chaetal
              08.08.2016 09:39

              …И Smalltalk так же делает. И даже имеет DoesNotUnderstand по этому поводу — мощнейшая вещь, показывающая что очень даже не бессмысленно.


            1. symbix
              08.08.2016 10:56
              +1

              А я не про типизацию. И erlang/smalltalk/ruby/etc — это не важно.

              Бессмысленно просить кофеварку помыть посуду, а пылесос сварить кофе.

              Контракт всегда есть. Он выражен в виде слова interface в коде, в юнит-тестах, в документации или в голове у разработчика — но он есть. Видишь суслика?


              1. chaetal
                08.08.2016 11:31

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


                1. symbix
                  08.08.2016 11:37

                  Не согласен с вами. ООП это не про язык программирования (объектно-ориентированную программу можно написать, например, на старом добром C), а про подход к проектированию программы. А когда мы думаем про объекты и сообщения, то есть проектируем программу в терминах объектов, мы не можем не думать о контрактах. Обязаны думать.


                  1. chaetal
                    08.08.2016 11:45

                    Да не надо со мной соглашаться. Тем более, что я про язык ни слова не говорил.
                    Но у термина «ООП» есть автор. Он и словами, и делами объяснил этот термин: что именно под ним подразумевается и в каком виде.

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


                    1. symbix
                      08.08.2016 12:09

                      Кажется, вы слишком буквально воспринимаете «отправку сообщений». Это не о реализации, а о принципе. О способе думать.

                      Вот в Objective C технически отправка сообщений, а в Swift-е — технически вызов метода. И ничего, ООП-программы писать можно и на том, и на другом.

                      На С можно обойтись структурой с указателями на функции и договориться первым аргументом передавать this (привет, python).


                      1. chaetal
                        08.08.2016 12:20
                        -1

                        Кажется, вы слишком буквально воспринимаете «отправку сообщений».

                        Вы хотите рассказать мне о том, как я это понимаю? :) Ну, ок, давайте…

                        Вот в Objective C технически отправка сообщений, а в Swift-е — технически вызов метода.

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

                        На С можно обойтись структурой с указателями на функции и договориться первым аргументом передавать this (привет, python).

                        И что же это будет, если не язык?


                        1. symbix
                          08.08.2016 12:25

                          > Что такое «технически отправка сообщений»? И что такое «технически вызов метода»?

                          Принципиальная разница, в том, в какой момент связываем сообщение с кодом-обработчиком — compile time или run time.

                          Хотя на самом деле все сложнее. Например, компиляторы Objective C могут оптимизировать «сообщение» в «вызов метода», если во время компиляции обрабатывающий код очевиден. Когда (и если) в PHP сделают JIT, там наверняка будет то же самое.

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

                          > И что же это будет, если не язык?

                          На уровне языка — структура и указатели. А объект и сообщение — у нас в голове.


                          1. chaetal
                            08.08.2016 12:32

                            Принципиальная разница, в том, в какой момент связываем сообщение с кодом-обработчиком — compile time или run time.

                            Ох, я начинаю жалеть, что вступил в беседу. Давайте вы сначала разберетесь хотя с тем, что передача сообщения не может быть реализована в «compile time», хорошо?

                            …А потом, надеюсь, и с другими понятиями. Удачи!


                            1. symbix
                              08.08.2016 13:25

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


    1. babylon
      05.08.2016 15:41

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


  1. chibitko
    05.08.2016 15:53

    «Вы не любите кошек? Да вы просто не умеете их готовить!»

    Заметил такую особенность в своём коде — почти все поля классов readonly, за исключением классов для данных.
    Как-то само собой стало так получатся, может поэтому нет проблем про которые пишет автор?
    Если нужно организовать in-memory DB использую разделяемые списки, как я понимаю чистое ФП этого не может, а вот мне надо.
    Так что ООП никуда не денется.


  1. franzose
    05.08.2016 16:06
    +3

    Прям ФП каминг-аут какой-то :)


    1. semenyakinVS
      08.08.2016 01:48
      +2

      Ага. «Нетрадиционно-ориентированное программирование»)


  1. mtivkov
    05.08.2016 16:15
    +4

    Процитирую статью с Хабра:
    Алан Кэй, создатель ООП, про разработку, Лисп и ООП


    ООП для меня это сообщения, локальное удержание и защита, скрытие состояния и позднее связывание всего. Это можно сделать в Smalltalk и в LISP.
    Мне жаль, что давным давно я использовал термин «объект» для этой темы, потому что из-за этого многие люди фокусируются на меньшей из идей.
    Большая идея это «сообщения».


  1. nikabc555
    05.08.2016 16:28
    +1

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

    Может кто-нибудь объяснить мне подробнее «Проблему ссылки (The Reference Problem)», а то автор статьи как-то не очень понятно ее расписал? а в поисковиках что-то нашел, но не то


    1. taujavarob
      05.08.2016 22:23

      Может кто-нибудь объяснить мне подробнее «Проблему ссылки (The Reference Problem)»


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

      Вам надо создать копию объекта B (B') и передать ссылку при создании объекта A на эту копию (на B'), а самим спокойно использовать данные объекта B.

      Но эту копию (объект B') не всегда можно создать.


      1. nikabc555
        07.08.2016 17:47
        +1

        На мой взгляд, эта проблема, также, как и многие другие, указанные в посте, вытекает из-за непродуманного проектирования, а не из ООП

        Например, на С++:
        Ничего не мешает передавать в А константную ссылку на В, если нужны 100% гарантии*, что данные в В не изменятся. В данном случае, если конструктор А требует неконстантную ссылку, то проект не скомпиляется — будет возможность продумать дальнейшие шаги по устранению до запуска программы
        Если объект А все-таки принимает неконстаную ссылку, значит он меняет что-то в В, значит создание А должно сопровождаться ожиданием, что в В что-то может измениться
        Объект А для своих внутренних нужд может изменять только свои приватные данные, а не внешние, т.е. В в данном случае
        То есть, при самом обычном (даже не самом хорошем) проектировании указанной проблемы с ссылкой не должно возникнуть, в принципе

        *100% гарантии все равно не будет, т.к. существует const_cast, но это крайний случай, который опять-таки вытекает из проектирования. Константные ссылки, константные методы и т.д. придумали не просто так


  1. fogone
    05.08.2016 16:31
    +2

    наследование является ключом к повторному использованию

    Нет
    Но переданный объект небезопасен!

    Нет
    Так что без лишних разговоров прощаемся с ОО-полиморфизмом, и приветствуем полиморфизм на основе интерфейсов.

    Простите, а ОО-пролиморфизм он не на основе интерфейсов?


    1. playermet
      06.08.2016 00:00

      Простите, а ОО-пролиморфизм он не на основе интерфейсов?
      Возможно ключ в том, что автор писал только на C++, где ключевых слов для интерфейсов нет.


      1. grossws
        06.08.2016 01:19

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


        1. playermet
          06.08.2016 02:26

          Я и не писал, что мешает. Акцент на способностях автора к осознанию этого.


      1. fogone
        06.08.2016 11:48

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


  1. babylon
    05.08.2016 16:49

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


  1. Idot
    05.08.2016 16:52

    Привет, функциональное программирование.

    … и где вторая половина статьи?

    Где вторая половина статьи, где объясняется, почему именно ФП, а не скажем ProLog или ещё что-то иное?


  1. customtema
    05.08.2016 18:28

    Как-то все слишком косно.

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

    Все это в сумме очень ускоряет разработку. По отдельности — ломает мозг.


  1. olegchir
    05.08.2016 19:18
    +9

    Небольшой обзор статьи в новый тэг #кунсткамера

    > Эта проблема — ещё одна трещина в Столпе Наследования.

    Это трещина не в наследовании, а в башке автора

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

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

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

    Аналитика у человека не было, сам он не то чтобы гений проектирования, поэтому подпер убогую идею костылями на С++ и Java, и плачет теперь что говно почему-то С++, а не его подход к решению задачи.

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

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


    В 1986 году Джо Армстронг сделал Эрланг. Оперативная память стоила очень дорого, и Джо пришлось капитально попотеть, чтобы сэкономить хоть немного. И процессоры были очень медленные, анализ контекста в компиляторе занимал очень много вычислительных ресурсов.

    А потом прошло 30 лет.

    3)
    > Я в течение десятилетий программировал на объектно-ориентированных языках.
    > private ArrayList[Object] a = new ArrayList[Object]();


    Вместо private List используется private ArrayList. Абстрагирование, полиморфизм подтипов — не, не слышали. Загримированный под матерого ООП кодера, Штирлиц никогда не был так близок к провалу.

    4)
    > Возьмём следующий базовый класс
    > public class Array { private ArrayList[Object] a…

    Знаете, чем хороша Java? Тем что в ней, к счастью, нет такого базового класса.

    Автор написал поверх класса List прокси с названием Array (sic!), и запроксировал в нем метод add(element). Потом запроксировал addAll, в котором полностью проигнорировал тот факт, что addAll и add это не какие-то произвольные операции, а жестко связанные. В addAll уже нельзя использовать оригинальный add, нужно использовать свой прокси. После столь свинского с собой обращения, всё похерилось. Конец был немного предсказуем, верно?

    5)
    > Мы должны работать только с интерфейсом. Это раздражающая тенденция...

    … раздражающе мешающая писать говнокод, ясно.

    6)
    > Идея иерархии “общее/частное”…
    > Каждый раз, создавая новую компанию, мне приходится решать проблему, связанную с выбором места для документации компании. Нужно ли мне сделать папку Документы, а внутри неё создать папку Компания? Или мне нужно сделать папку Компания, а внутри неё — Документы? Оба варианта рабочие, но какой из них правильный? Какой лучше?


    Вы действительно хотите сделать лучше? Тогда вот мой совет как вашего адвоката:

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

    7)
    > иерархия “общее/частное” не работает. Так для чего тогда хороши иерархии?
    > Для включения (Containment).


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

    С 1 сентября 1960 года (или когда там в продакшене появится ООП), писать на нем разрешается только отряду Мстители под руководством отца Тони Старка. (Marvel не похоже на людей, свято блюдущих хронологию)

    8)
    > Инкапсуляция, второй обрушившийся столп

    Учитывая объем текста, описывающий проблему, к этому моменту автор уже понял, что что-то пошло не так. Проклятое ООП не сдается даже на его территории — посте на Хабре.

    9)
    > The Reference Problem
    Автор сам придумал этот термин?
    Я вижу только https://en.wikipedia.org/wiki/Reference_class_problem
    и это вообще из статистики, а не программирования

    10)
    > Если ссылка на объект передаётся конструктору объектов, то он кладёт её в приватную переменную, защищённую инкапсулированием. Но переданный объект небезопасен! Почему? Потому в какой-то части нашего кода содержится указатель на объект, то есть код, вызывающий конструктор. Но он ДОЛЖЕН иметь ссылку на объект, в противном случае он не сможет передать её конструктору.

    Автор скорей всего как бы хотел сказать о паттернах fluent interface + builder, примененных в concurrent случае? Что кроме кроме религии запрещает ему сделать все доступы безопасными?

    11)
    > Конструктору придётся клонировать переданные объекты.

    А, автор решил нам продать defensive copying! Об этом рассказывают на первом курсе универа на предмете «программирование на языке высокого уровня» (ПЯВУ). Так что, кто не пробовал поступить даже на первый курс, или никогда не читал классические тексты по Java, или википедию, или вообще ничего, эта информация безусловно будет вам очень полезной.

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

    Ну а невозможно это потому что? Да черт его знает. Я уже задолбался писать этот комментарий, если честно :-)

    12)
    > Полиморфизм, третий обрушившийся Столп
    > Куда бы они не отправились, он был с ними, но всегда на вспомогательных ролях.


    Барбара Лисков и Джанет Винг, Андрей Александреску и Герб Саттер, Роберт «Uncle Bob» Мартин, Девид Хейден и Бертранд Мейер, и другие, менее популярные товарищи, плачут кровавыми слезами и крутятся в постелях как вентиляторы.

    13)
    > Блог компании Mail.Ru Group

    Мэйлру капец. Ясно.

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

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


    1. sumanai
      05.08.2016 21:04
      +1

      Проклятое ООП не сдается даже на его территории — посте на Хабре

      Это перевод, и изначальная статья была на каком-то там medium.com.
      Мэйлру капец. Ясно.

      Ну бывает, неудачно выбрали статью для перевода.

      С остальным согласен.


  1. olegchir
    05.08.2016 19:19
    +1

    (удалено)


  1. Alex_ME
    05.08.2016 20:05
    +1

    Опять! Недели не проходит, чтобы кто-нибудь не стал наезжать на ООП.


    Появился новый проект, я не забывал о своей идее с классом и испытывал большой энтузиазм. Без проблем. Повторное использование спешит на помощь. Нужно просто взять класс из другого проекта и применить его. Ну… вообще-то… не просто класс. Понадобится родительский класс. Но… Но это всё. Гхм… погодите… кажется, нужен будет ещё родитель родителя… А потом… в общем, нужны ВСЕ родители. Хорошо… хорошо… Я с этим разберусь. Без проблем.

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


  1. Azoh
    05.08.2016 20:55

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

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

    В общем, ждем статью «Прощай, функциональное программирование».


  1. babylon
    05.08.2016 21:09

    Интереснее было бы послушать мысли сотрудника mail.ru. Возможно эти мысли совпадают.


    1. symbix
      05.08.2016 23:35

      Сотрудники мейл.ру изложили свои мысли здесь: http://mailru.group/ :)


  1. termos_38
    05.08.2016 22:23

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


  1. adelier
    06.08.2016 00:00
    +2

    Вывод статьи меня несколько обескураживает. Ведь ФП не исключает ООП.


  1. vlad72
    06.08.2016 01:23

    Идеала не существует по определению. Можно только идеально применять отдельные инструменты для конкретных задач.


    1. vlad72
      06.08.2016 02:32

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


  1. ShapitoS999
    06.08.2016 01:33
    +1

    Эта статья — детский сад, парадигма не может быть виновата в своих недостатках, она может быть выбрана на ту или иную задачу, или совокупность задач. Надо заранее предполагать, какая более удобная в каждом случае должна быть выбрана парадигма. К примеру, Web же не кодят на bash. Думаю автор непрофессионален.


  1. softaria
    06.08.2016 11:02
    +1

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

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

    Проблема хрупкого класса не являтся проблемой ООП. Это просто — антипаттерн. Такой же, как, например, GOD-object. Не надо так писать. А если почему-то надо, то стоит запретить наследование таких классов.

    Вот тут , например, автор хорошо показывает, что стрелять себе в ногу можно и на функциональном языке. Было бы желание.


  1. Shamov
    06.08.2016 11:19
    +1

    У меня плохие новости. Дело в том, что выявление общих свойств у нескольких объектов требует IQ. Тесты на IQ составлены таким образом, что проверяют именно умение выявлять общие закономерности в приведённых частных проявлениях. Чем выше IQ, тем более сложные и запутанные кейсы человек может распутать. Так что если кому-то кажется, что иерархия «общее/частное» не работает, то скорее всего проблема не в иерархии, а в чём-то другом.


  1. i360u
    06.08.2016 12:30
    +5

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


  1. Toshiro
    06.08.2016 17:21
    -1

    Градус неадеквата статьи и отдельных веток комментариев просто зашкаливает.

    https://www.youtube.com/watch?v=HTLu2DFOdTg — я просто оставлю это здесь.


  1. chaetal
    07.08.2016 21:09

    Я все комменты не осилил, возможно пропустил… Но таки никого не коробит от этих «трех столпов ООП»? Абсолютно все на самом деле полагают, что ООП — это наследование, инкапсуляция и полиморфизм?!


    1. chaetal
      07.08.2016 21:27

      Все-таки есть такой комментарий!


    1. mx2000
      08.08.2016 02:58

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

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

      Ну и касательно повторного использования — если вспомнить времена Turbo Pascal 5.5 и становления Java — основная киллер-фича ООП, которая хорошо покупалась бизнесом, звучала именно как «возможность повторного использования кода». Это исторический факт.

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

      Такие дела.


      1. symbix
        08.08.2016 03:33

        Наследование != повторное использование.

        Профита от повторного использования ООП-кода ровно столько же, сколько от повторного использования не ООП-кода. Фреймворки, библиотеки, вот это все.


      1. chaetal
        08.08.2016 09:46

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


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


  1. WarKnife
    08.08.2016 11:51
    +2

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

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

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


    1. chaetal
      08.08.2016 12:09

      Для ООП никогда не существовало канонического определения, так как само понятие ООП распределено во множестве языков, его реализующих


      Вот это новое слово в истории IT! Оказывается, нам всем врали, что этот термин придумал какой-то там Alan Kay. Слова, оказывается, народные :)


      1. WarKnife
        08.08.2016 12:29
        +1

        Kay is one of the fathers of the idea of object-oriented programming, which he named, along with some colleagues at PARC and predecessors at the Norwegian Computing Center.


        Думаю, при чтении, следует вдумываться в текст. Также вам следует изучить термин «канонический» и отличия терминов «каноническое определение» и «идея»


        1. chaetal
          08.08.2016 12:38

          Думаю, при чтении, следует вдумываться в текст.

          Вот именно: «which he named». Да и другими источниками иногда пользоваться не мешает. Он сам неоднократно называл себя изобретателем термина, описывал при каких обстоятельствах это произошло. А также объяснял, что именно под этим термином понимается. И, например, такие слова как «инкапсуляция», «полиморфизм» я в его высказываниях не припомню.
          Другие люди тоже с удовольствием много раз говорили о нем как об авторе термина. И я не видел никого, кто бы пытался уличить его во вранье по этому поводу. Если вам что-то известно об этом — будет интересно узнать, что именно.

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

          А вот с этим я абсолютно согласен.


  1. Wuzaza
    08.08.2016 11:56
    +1

    Открываем любую книжку для посвященную ООП для начинающих в Java или C++, например Эккеля или Лафоре и в первых же главах, посвященных наследованию и полиморфизму мы видим указание на проблемы множественного наследования, и на проблемы последовательной инициализации классов при создании конструкторов потомков. И самое главное, о чудо! Мы видим решение этих проблем…
    Но зачем нам читать такие книжки, они же для новичков, а мы же «в течении десятилетий программировали на ООП». Лучше я напишу свою статью, где выведу на чистую воду языки, ставшие промышленным стандартом программирования…


  1. Crazy_as
    08.08.2016 12:00

    Маразм крепчал…
    А если по статье: слабая аргументация, практически все можно опровергнуть. Про полиморфизм дак вообще ничего внятного я не увидел.


  1. AdVv
    08.08.2016 12:03

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


  1. AntonL
    08.08.2016 12:03

    Пример с Array и ArrayCount возможно может встретиться, но в реальном проекте так писать не надо. Во всех технологиях есть подводные камни о которых стоит подумать прежде чем что то делать.
    Как уже писали
    Либо несколько изменить ArrayCount, либо оба Array и ArrayCount(если есть возможность).
    Что то мне подсказывает, что в текущей реализации будут и другие проблемы с использованием и ожидаемым результатом.


  1. uploadfor
    08.08.2016 12:03

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

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


    1. LifeKILLED
      14.08.2016 17:14
      +1

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


      1. vlad72
        14.08.2016 18:52

        Если так много комментов тема собрала, значит пусть пишет ))


  1. psyriccio
    08.08.2016 12:04

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


  1. Tiulkin
    10.08.2016 21:19

    Прощайте стереотипы, здравствуй здравый смысл. Завтра вы поймёте, что и ФП не является рецептом от всех болезней. Послезавтра засомневаетесь в парадигмах. Послепослезавтра научитесь верить внутреннему голосу. А вот после этого уже поймёте, что не так всё плохо и с ООП, и с ФП, а для собственника оплачивающего ваши плюшки бизнеса (о, ужас!) абсолютно фиолетово, каким именно образом убирается его головная боль и автоматизируется та или иная активность, т.к. IT – это всего лишь инструмент (да, мощный, но один из многих). А если собственником бизнеса вдруг окажетесь вы, так вообще количество откровений превысит все мыслимые и немыслимые ожидания.


    1. taujavarob
      11.08.2016 16:00
      +1

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


  1. vbif
    13.08.2016 01:50
    +2

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


    1. chaetal
      13.08.2016 10:00

      Точно подмечено! :)
      …Причем нельзя сказать, что за эти годы он стал мастером забивания гвоздей.


      1. taujavarob
        15.08.2016 14:18

        А потом изобрели… клей!


        1. chaetal
          15.08.2016 17:37
          -1

          Да, вот, проблема-то как раз в том, что уже давно никто ничего не изобретал.