Объектно-ориентированное программирование – самая большая ошибка компьютерных наук |
||
МЕНЮ Главная страница Поиск Регистрация на сайте Помощь проекту Архив новостей ТЕМЫ Новости ИИ Голосовой помощник Разработка ИИГородские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Искусственный интеллект Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Нейронные сети начинающим Психология ИИ Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Творчество ИИ Техническое зрение Чат-боты Авторизация |
2021-01-27 02:44 C++ и Java, вероятно, являются одними из худших ошибок, которые когда-либо делала компьютерная наука. Многие выдающиеся программисты, включая создателя ООП Алана Кея, критиковали и продолжают критиковать эти языки за то, что они извратили первоначальную идею и породили самую печально известную парадигму современной разработки. К несчастью, современное ООП приобрело огромную популярность. Это позволило ему нанести огромный ущерб экономике – триллионы долларов – и даже убить (в буквальном смысле) тысячи человек! Почему же ООП так опасен? *** Представьте, что вы садитесь в свою хорошо знакомую машину и едете по хорошо знакомому маршруту. И вдруг что-то идет не так, как всегда. Вы отпускаете педаль газа, но машина продолжает ускоряться! Давите на тормоз – не помогает! Страшно? Подобный инцидент произошел в 2007 году с Джин Букаут – и еще с сотнями водителей Toyota Camry. Десятки человек погибли. Производитель ссылался на залипание педалей, человеческий фактор и даже половые коврики, однако истинным виновником оказалось программное обеспечение автомобилей. Команда экспертов 18 месяцев разбирала кодовую базу Toyota – и нашла сотни потенциальных причин возникновения непреднамеренного ускорения. Код в целом был запутанным и беспорядочным – то, что на сленге называется «спагетти». Из-за этого Toyota пришлось отозвать более 9 млн автомобилей и выплатить более 3 млрд долларов. Проблема спагетти Подобные инциденты не уникальны – и это пугает. Например, два самолета Boeing 737 Max потерпели крушение из-за ошибки, вызванной спагетти-кодом (346 жертв, 60 млрд долларов ущерба). То же самое может случиться, например, на атомной электростанции или в реанимационной палате. Как ни странно, программный код пишется прежде всего для людей. Мартин Фаулер говорил, что любой дурак может написать код, понятный компьютеру, а хорошие программисты пишут код, понятный людям. Если код непонятен, то очень скоро он перестанет работать. Спагетти-код непонятен, связи между его частями не очевидны. Любое изменение может что-нибудь сломать. На такой код невозможно писать тесты, его сложно расширять и больно поддерживать. Откуда берется спагетти-код? Со временем любой код может превратиться в спагетти. По мере усложнения он становится все более и более запутанным, энтропия растет – и в один прекрасный момент вы уже имеете дело со клубком зависимостей. Чтобы бороться с этим нужны строгие ограничения, вроде ограничения скорости на дорогах. Причем такие ограничения должны быть максимально автоматизированы и не зависеть от человеческого фактора. В идеале их должна накладывать сама парадигма программирования. ООП – корень зла ООП не накладывает на код никаких ограничений, которые могли бы предотвратить его запутывание. Безусловно, есть лучшие практики разработки – внедрение зависимостей, TDD, Domain Driven Design, которые реально помогают. Однако они не внедрены в парадигму, не обеспечиваются ей, и нет инструментария, который мог бы следить за их соблюдением. Встроенные фичи ООП только добавляют путаницы. Например, инкапсуляция скрывает и рассеивает состояние по всей системе. Преимущества полиморфизма еще сомнительнее – мы не знаем точно, какой путь выполнения выберет наша программа. Если вдобавок ко всему этому приходится иметь дело с несколькими уровнями наследования, спагетти-код обеспечен. Ссылочные типы В большинстве объектно-ориентированных языков данные передаются по ссылке, то есть разные участки программы могут иметь дело с одной и той же структурой данных – и менять ее. Это превращает программу в один большой сгусток глобального состояния и противоречит первоначальной идее ООП. Алан Кей, создавая свой язык Simula, предполагал, что части программы будут общаться между собой подобно биологическим клеткам, то есть независимо. Они должны были посылать друг другу сообщения, оставаясь закрытыми от внешнего мира (инкапсуляция). Но в современном ООП одни «клетки» проникают внутрь других и меняют их состояние. Это приводит к большой связанности кода. Изменения в одном месте программы могут привести к неожиданным последствиям в другом. Предсказуемость Склонность к спагеттификации – не единственная проблема ООП-парадигмы. Работая с ПО мы обычно хотим, чтобы оно было надежным и предсказуемым. Если
Если эта цитата вам не нравится, то это потому, что недетерминированность в целом никуда не годится. Вот пример кода, который просто вызывает функцию: Мы не знаем, что делает эта функция, но кажется, что она всегда возвращает один и тот же результат для одних и тех же входных данных. А вот другой код: Эта функция вернула разные значения для одних и тех же входных параметров. Функция Что делает функцию детерминированной или недетерминированной?
Результат работы функции Функция Детерминированный код предсказуем, недетерминированный – нет. Непредсказуемость Давайте рассмотрим простую функцию сложения: В большинстве языков программирования операция сложения реализуется на аппаратном обеспечении, то есть за нее отвечает очень надежный процессор. Поэтому мы всегда можем быть уверены, что функция Теперь немного усложним задачу – введем в бой объекты: Пока все идет хорошо. Давайте внесем небольшое изменение в тело функции Что случилось? Внезапно результат перестает быть предсказуемым! В первый раз код сработал нормально, но с каждым последующим запуском его вывод становился все более и более неожиданным. Другими словами, функция больше не детерминирована. Почему это вдруг произошло? Потому что функция начала вызывать побочные эффекты, изменив значение за пределами своей области действия. *** Детерминированная программа гарантирует, что Недетерминированные программы – это полная противоположность. В большинстве случаев вызов Каковы последствия недетерминированного кода? В нем легко появляются дефекты – баги, которые заставляют разработчиков тратить драгоценное время на отладку и значительно ухудшают качество работы ПО. Чтобы сделать наши программы более надежными, мы должны в первую очередь заняться их детерминизмом. Побочные эффекты Что такое побочный эффект? Если вы принимаете лекарство от головной боли, но оно вызывает у вас тошноту, то тошнота является побочным эффектом. Проще говоря, этот что-то нежелательное и не связанное с основной задачей препарата. Вернемся к нашей функции сложения: Функция Так как объекты передаются по ссылке, то и объект Чистота Разобравшись с детерминизмом и побочными эффектами, мы готовы говорить о чистоте. Чистая функция – это функция, которая одновременно детерминирована и не имеет побочных эффектов. То есть у нее всегда предсказуемый результат работы, и она не делает ничего лишнего. Чистые функции имеют множество преимуществ:
И так далее. Проще говоря, чистые функции возвращают радость в программирование. Насколько чисто ООП? Для примера давайте поговорим о двух фичах ООП — геттерах и сеттерах. Результат геттера зависит от внешнего состояния — состояния объекта. Многократный вызов геттера может привести к различным выходным данным, в зависимости от состояния системы. Это делает геттеры изначально недетерминированными. Сеттеры предназначены для изменения состояния объекта, что делает их по своей сути побочными эффектами. Таким образом, все методы в ООП (кроме, возможно, статических) либо не детерминированы, либо вызывают побочные эффекты. Следовательно, ООП – это что угодно, только не чистое программирование. Чистое решение Есть ли что-то, что может спасти программирование – луч надежды в мрачном мире программных сбоев? Что-то достаточно надежное и детерминированное, чтобы на нем можно было строить качественное ПО? Это математика. В computer science математика воплотилась в парадигме функционального программирования, основанного на системе лямбда-исчисления. А на чем основано современного ООП? Уже не на биологических законах клеток, как планировал Алан Кей. Оно базируется на множестве нелепых идей вроде классов и наследования, склеенных скотчем, чтобы лучше держались. Основной строительный блок функционального программирования – функция в ее математическом понимании. В большинстве случаев – чистая функция, детерминированная и предсказуемая. Программа, составленная из таких функций, тоже становится предсказуемой. Значит ли это, что в такой программе нет багов? Конечно нет. Однако и баги в ней детерминированы. Для одних и тех же данных всегда будет возникать одна и та же ошибка, что существенно облегчает ее исправление. Как я тут оказался? До появления процедур и функций в программировании широко использовался оператор Очень похожий процесс происходит сейчас с ООП. Только вместо вопроса «как я попал в эту точку исполнения», мы спрашиваем «как я попал в это состояние». ООП (и императивное программирование в целом) не может нам ответить. Когда все передается по ссылке, любой объект может быть изменен другим объектом – и парадигма не накладывает никаких ограничений, чтобы это предотвратить. Инкапсуляция совсем не помогает – вызов метода для мутации некоторого поля объекта ничем не лучше, чем его непосредственная мутация. Программы быстро превращаются в месиво зависимостей и глобального состояния. Функциональное программирование избавит нас от сложных вопросов. Когда состояние остается неизменным, оно не вызывает проблем. Раньше многие разработчики сопротивлялись рекомендации прекратить использовать А как же спагетти-код? В ООП есть много лучших практик, которые теоретически должны помочь справиться со спагеттификацией, например, предпочтение композиции наследованию. Однако сама парадигма ООП не накладывает никаких ограничений и не следит за применением этих практик. Можете ли вы поручиться, что джуниоры в вашей команде будут их соблюдать? В функциональном программировании есть только композиция. Функции вызывают другие функции, большие функции состоят из малых. Это единственный способ построения программ. Иначе говоря, парадигма программирования сама навязывает лучшую практику, она является нативной, естественной. Когда у нас нет мешанины связей и зависимостей, разработка, тестирование и рефакторинг становятся удовольствием. Но ООП и ФП дополняют друг друга! Жаль вас разочаровывать, но это не так. Объектно-ориентированное программирование – полная противоположность функциональному. Оно нарушает многие фундаментальные принципы:
Программисты ООП тратят большую часть своего времени на исправление ошибок. Программисты ФП – на написание работающего кода. Действуйте, пока не поздно ООП было очень большой и ужасно дорогой ошибкой. Давайте все, наконец, признаем это. Если ваш автомобиль работает на объектно-ориентированном ПО, вы не можете быть спокойны. Пришло время принять меры. Мы все должны осознать опасность ООП и начать делать маленькие шаги в сторону функционального программирования. Это не быстрый процесс, реального сдвига можно ожидать не раньше, чем через 10 лет, однако он должен произойти. В ближайшем будущем ООП-программисты станут «динозаврами», как сейчас разработчики на COBOL. C++, Java, C# умрут. TypeScript тоже умрет. Начните изучать функциональное программирование прямо сейчас! F#, ReasonML и Elixir – все это отличные варианты для начала. Присоединяйтесь к надвигающейся революции! Источники Источник: proglib.io Комментарии: |
|