[Из песочницы] Научное программирование: часть 1
Наука в программировании — быль или реальность? Сколько её в языках и почему идут холивары о приемуществах одних языков над другими? Если интересно — прошу под кат.
Давным-давно идут «священные войны» в которых обсуждаются и критикуются различные подходы в написании программ и в самом программировании, критикуется в основном Объектно-Ориентированное Программирование (раз, два, три).
Егор Бугаенко критикует ООП на практических примерах (раз, два, видео), используя идеи Девида Уэста и, как я понял, недавно пошел в сторону теории. Эффективность этих споров стремится к нулю. Почему? Потому что все эти споры ведутся уже на основе реализаций каких-то мыслей, практик и мнений отдельных людей, а не на основе теоретических работ. Научного метода и подхода с его теориями, гипотезами, аксиомами, экспериментами, доказательствами и фактами в последнее время в этих спорах и «войнах» нет от слова вообще!
В математике, как и в любой другой науке, любые теоремы и теории требуют доказательств. Как пример: Теорема Пифагора. Сначала идет теория, а за ней практика. В программировании такого подхода не придерживаются уже несколько десятков лет. Всё заменено догмами и мнением отдельных личностей, которых иногда называют «евангелистами» или «пророками». Они своим словоблудием продвигают в массы только нужные им идеи, не заботясь ни о теории, ни о доказательствах (Посмотрите конференции и презентации по ИТ). Где здесь наука, а где религия? И не скатываемся ли мы в мракобесие и веру в слова написанные давно и не требующих доказательств? Слышали про сторонников плоской Земли? Ничего не напоминает по части подходов по убеждению и упоротости?
И вот в таком кураже последние 30–40 лет программисты, ослепленные религиозными убеждениями от проповедников ООП или ФП, строили абстракции поверх других абстракций, новые языки поверх других языков, новые фреймворки и библиотеки поверх старых. А зачем это все было нужно? Ради упрощения и производительности своей работы по написанию программ. Только этот путь привел в тупик. Потому что вместо упрощения получили усложнение и изучение теперь не алгоритмов, а API и документации к очередному модному фреймворку, а может и нескольким. Теперь баги стали искать не только в своем коде, но и в чужом. Отладку кода приходится делать через тонны прокси, паттернов архитектуры и шаблонов проектирования, хелперов, фреймворков и библиотек. И, как показывают исследования, выигрыша в скорости написания кода от применения ООП нет вообще.
Немного истории. С чего всё началось? Сначала было процедурное программирование, затем структурное и за ним на сцену вышло императивное программирование. Некоторые люди додумались ввести понятие объекта — так родилось обьектно-ориентированное программирование. И в этот момент произошел крутой поворот повернувший всю индустрию в то состояние, в котором мы сейчас находимся.
Введение объекта должно было быть теоретически обосновано. Но этого не произошло. Вместо этого каждый язык внедрял понятие объекта по своему. И каждый разработчик языка трактовал постулаты ООП на свой вкус и цвет. Особо упоротые фундаменталисты придумали Функциональное Программирование основанное на математике, списках и функциях высшего порядка. Звучит серьезно и даже немного научно обосновано, ведь математика — вещь нужная и полезная, только вот какое отношение к реальному миру имеют списки и функции?
Какие задачи решает чистое ФП без использования состояний и есть ли это оптимальный, удобный и правильный способ со стороны человека — вот такой вопрос нужно задать «пророкам» ФП. И его задают (раз, два).
Разработчики функциональных языков начали применять у себя некоторые парадигмы из ООП для того, чтобы выйти из области прикладных задач по математике в область задач реального мира. В ответ некоторые ООП языки реализовали у себя парадигмы из ФП. И «Смешались в кучу кони, люди » ©
В итоге реализация чистых парадигм ООП и ФП в текущих языках как в песне — «Я его слепила из того что было, а что было то и полюбила»! И получается, что без теоретических работ и научной базы, все эти языки лишь плод фантазий и желаний их разработчиков. И таких языков больше сотни! А так быть не должно! В идеале должно быть всего 2 низкоуровневых языка и 3–4 высокоуровневых, построенных на их основе.
Могу предположить, что когда вводили понятие объекта — за основу приняли то, что видели вокруг себя — человека и животных. И в этом была главная ошибка которая позже вырастет до огромных размеров! Таким образом, возможно, появилось наследование (предок-потомок и связь между ними объясняется наследованием, но как быть с другими объектами в мире? И что значит само определение слова «наследование» в реальном мире? Кровь и ДНК? Азотистые основания?). Как остальные термины, а именно абстракция, инкапсуляция и полиморфизм, относятся именно к ООП? А предоставить доказательства такой связи как-то не потрудились. Ведь написать можно что угодно и звучит логично, только проблема в том, что приведенные аргументы к ООП отношения не имеют. Ведь в ООП была сделана логическая ошибка —(неполная индукция) был произведен переход от одного частного случая ко всему общему множеству. Чтобы это показать, приведу пример — если можно за основу взять только живых существ с наследованием, то почему же, следуя этой же логике, не взять за основу планету или целую галактику? Ведь планета или галактика тоже наследница других объектов из космоса и имеет состояние и какое-то поведение. Или все горы представить как объекты без наследования и практически без поведения.
Почему любой объект должен или может использовать наследование от другого объекта кто-то потрудился объяснить и доказать? Ударение на слове «доказать»!
Ведь если начинаешь сильно задумываться над этим, то возникает смутное предчувствие: здесь не обошлось без обмана, манипуляций и ошибок! Ведь ценность слов оценивается по возможности их логически и аргументированно доказать опираясь на факты и данные. Иначе можно придумывать какой угодно бред вплоть до розовых единорогов! Или по-другому — чем ваши слова отличаются от слов религиозного фанатика-экстремиста сбежавшего из психбольницы?
Но так было не всегда. Вот примеры научного подхода:
1. книга «Электронные цифровые машины и программирование» А.И. Китова.
2. теорема Бёма — Якопини.
Не так много как хотелось бы, и, возможно, где-то есть еще много примеров научных работ, но их найти очень сложно. Подавляющее большинство пользуется всякими «библиями» и статьями для аргументации и дискуссий (в реальности это даже слишком громкое слово для этого процесса).
Попробуем применить к программированию науку и опираться только на её достижения, результаты и методы.
Введем базовые определения для терминов:
Обьект — наименьшая неделимая сущность, также известная нам как химический элемент, имеющая множество свойств и множество моделей поведения реализуемые через методы. У объекта есть 2 типа методов: 1) для получения его свойств, 2) для изменения его состояния.
Модель поведения — интерфейс для взаимодействия с объектом.
Процесс — вид взаимодействия над элементами (гравитация, свет, нагревание, излучение).
Факты:
1. Всё в окружающем мире состоит из мельчайших неделимых химических элементов и поэтому за основу главного объекта необходимо брать именно химический элемент обладающий множеством моделей поведения.
2. Химические элементы могут объединяться во множества.
3. Химические элементы взаимодействуют между собой (реакция), находятся под действием разных процессов.
4. Каждый химический элемент имеет свое состояние на каком-то промежутке времени и может его менять под воздействием внешних процессов.
5. Процессы также являются объектами или их множеством и с помощью своей модели поведения могут изменять химические элементы.
Приняв за основу изложенные факты и данные, проанализировав свойства и поведение элементов, их взаимодействие и процессы между ними, выделим несколько принципов:
1. Есть 2 типа объектов: элементарные (атомарные) и реакционные (процессные). Элементарные объекты могут, при соблюдении определенных условий, возвращать из методов, меняющих их состояние, новые объекты.
2. Реакционные объекты знают интерфейсы объектов с которыми работают.
3. Все свойства объекта должны быть определены как приватные и неизменяемые, объекты как публичные и неизменяемые, а методы только публичные.
4. Существует только один тип проверяемого исключения — Exception.
5. У элементов нет такого понятия как NULL. Вместо этого должен быть или 0, пустая строка, массив с одним элементом или пустая коллекция элементов.
6. У элементов нет наследования ни в каком виде.
7. Также нет дженериков, аннотаций, приведения типов, внутренних и локальных классов, анонимных классов и лямбд, Enum-ов, статических методов и атрибутов.
8. Нет абстрактных классов и методов.
9. Элементарные объекты не могут возвращать данные которые могут быть изменены. Можно только попросить этот объект что-то с ними сделать — так как только он отвечает за их хранение и изменение. Изменение элементарного объекта происходит только с помощью реакционного объекта.
10. Для хранения состояния необходимо использовать структуры данных, такие как массивы, очереди, коллекции, списки и мапы.
11. Объекты вступающие в реакцию друг с другом могут вернуть другой обьект или изменить свое состояние.
12. Структуры данных очень важны. Реакционные объекты могут принимать в качестве параметров метода множество (коллекцию) разных объектов и могут возвращать множество разных объектов как результат работы метода.
13. Методы используют формальную логику (с высказываниями, алгеброй логики и логическими операциями) и циклы выраженную в виде синтаксиса языка, для работы с данными и возвращают результат или изменяют состояние объекта (или его множества).
14. Тело метода должно занимать от 1 до 10 строчек кода без пропусков.
15. Тело класса должно занимать от 5 строк до 2 высот экрана монитора без пропусков. Чем меньше тело класса и метода — тем лучше.
Гипотеза:
1. Если исключить из ЯП (Язык Программирования) возможность наследования, статические методы и атрибуты, абстрактные классы, то в проекте код станет минимум на 10–20 процентов меньше.
2. Если исключить из кода в проекте все антишаблоны проектирования, то код станет минимум на 10–15 процентов меньше.
3. Чем меньше и проще объекты, тем проще их понимать, тестировать и изменять.
4. Тестирование объектов будет проходить быстрее (см п.3).
5. Отладка метода будет проходить быстрее (см п.3).
6. Написание новых классов будет проходить быстрее (см п.3)
Таким образом, приняв во внимание факты, принципы и созданную гипотезу (если она подтвердится экспериментально), мы можем вывести свою Элементарную или Атомную теорию программирования.
Если бы в 60-е и 70-е годы такой подход был принят за основной стандарт, то мы бы не испытывали сейчас столько негатива и растерянности с существующим зоопарком языков и подходов.
В следующей части будем экспериментально доказывать нашу гипотезу и дополнять теорию. Задавайте вопросы по теории в комментариях. Серьезно отнеситесь к этому делу и думайте.