что такое парадигма программирования
Чистая архитектура. Часть II — Парадигмы программирования
Эта серия статей – вольный и очень краткий пересказ книги Роберта Мартина (Дяди Боба) «Чистая Архитектура», выпущенной в 2018 году. Начало тут.
Парадигмы программирования
Дисциплину, которая в дальнейшем стала называться программированием, зародил Алан Тьюринг в 1938 году. В 1945 он уже писал полноценные программы, которые работали на реальном железе.
Первый компилятор был придуман в 1951 году Грейс Хоппер (бабушка с татуировкой Кобола). Потом начали создаваться языки программирования.
Обзор парадигм
Существует три основных парадигмы: структурное, объектно-ориентированное и функциональное. Интересно, что сначала было открыто функциональное, потом объектно-ориентированное, и только потом структурное программирование, но применяться повсеместно на практике они стали в обратном порядке.
Структурное программирование было открыто Дейкстрой в 1968 году. Он понял, что goto – это зло, и программы должны строиться из трёх базовых структур: последовательности, ветвления и цикла.
Объектно-ориентированное программирование было открыто в 1966 году.
Функциональное программирование открыто в 1936 году, когда Чёрч придумал лямбда-исчисление. Первый функциональный язык LISP был создан в 1958 году Джоном МакКарти.
Каждая из этих парадигм убирает возможности у программиста, а не добавляет. Они говорят нам скорее, что нам не нужно делать, чем то, что нам нужно делать.
Все эти парадигмы очень связаны с архитектурой. Полиморфизм в ООП нужен, чтобы наладить связь через границы модулей. Функциональное программирование диктует нам, где хранить данные и как к ним доступаться. Структурное программирование помогает в реализации алгоритмов внутри модулей.
Структурное программирование
Дейкстра понял, что программирование – это сложно. Большие программы имеют слишком большую сложность, которую человеческий мозг не способен контролировать.
Чтобы решить эту проблему, Дейсктра решил сделать написание программ подобно математическим доказательствам, которые также организованы в иерархии. Он понял, что если в программах использовать только if, do, while, то тогда такие программы можно легко рекурсивно разделять на более мелкие единицы, которые в свою очередь уже легко доказуемы.
С тех пор оператора goto не стало практически ни в одном языке программирования.
Таким образом, структурное программирование позволяет делать функциональную декомпозицию.
Однако на практике мало кто реально применял аналогию с теоремами для доказательства корректности программ, потому что это слишком накладно. В реальном программировании стал популярным более «лёгкий» вариант: тесты. Тесты не могут доказать корректности программ, но могут доказать их некорректность. Однако на практике, если использовать достаточно большое количество тестов, этого может быть вполне достаточно.
Объектно-ориентированное программирование
ООП – это парадигма, которая характеризуется наличием инкапсуляции, наследования и полиморфизма.
Инкапсуляция позволяет открыть только ту часть функций и данных, которая нужна для внешних пользователей, а остальное спрятать внутри класса.
Однако в современных языках инкапсуляция наоборот слабее, чем была даже в C. В Java, например, вообще нельзя разделить объявление класса и его определение. Поэтому сказать, что современные объектно-ориентированные языки предоставляют инкапсуляцию можно с очень большой натяжкой.
Наследование позволяет делать производные структуры на основе базовых, тем самым давая возможность осуществлять повторное использование этих структур. Наследование было реально сделать в языках до ООП, но в объектно-ориентированных языках оно стало значительно удобнее.
Наконец, полиморфизм позволяет программировать на основе интерфейсов, у которых могут быть множество реализаций. Полиморфизм осуществляется в ОО-языках путём использования виртуальных методов, что является очень удобным и безопасным.
Полиморфизм – это ключевое свойство ООП для построения грамотной архитектуры. Он позволяет сделать модуль независимым от конкретной реализации (реализаций) интерфейса. Этот принцип называется инверсией зависимостей, на котором основаны все плагинные системы.
Инверсия зависимостей так называется, что она позволяет изменить направление зависимостей. Сначала мы начинаем писать в простом стиле, когда высокоуровневые функции зависят от низкоуровневых. Однако, когда программа начинает становиться слишком сложной, мы инвертируем эти зависимости в противоположную сторону: высокоуровневые функции теперь зависят не от конкретных реализаций, а от интерфейсов, а реализации теперь лежат в своих модулях.
Любая зависимость всегда может быть инвертирована. В этом и есть мощь ООП.
Таким образом, между различными компонентами становится меньше точек соприкосновения, и их легче разрабатывать. Мы даже можем не перекомпилировать базовые модули, потому что мы меняем только свой компонент.
Функциональное программирование
В основе функционального программирования лежит запрет на изменение переменных. Если переменная однажды проинициализирована, её значение так и остаётся неизменным.
Какой профит это имеет для архитектуры? Неизменяемые данные исключают гонки, дедлоки и прочие проблемы конкурентных программ. Однако это может потребовать больших ресурсов процессора и памяти.
Применяя функциональный подход, мы разделяем компоненты на изменяемые и неизменяемые. Причём как можно больше функциональности нужно положить именно в неизменяемые компоненты и как можно меньше в изменяемые. В изменяемых же компонентах приходится работать с изменяемыми данными, которые можно защитить с помощью транзакционной памяти.
Интересным подходом для уменьшения изменяемых данных является Event Sourcing. В нём мы храним не сами данные, а историю событий, которые привели к изменениям этих данных. Так как в лог событий можно только дописывать, это означает, что все старые события уже нельзя изменить. Чтобы получить текущее состояние данных, нужно просто воспроизвести весь лог. Для оптимизации можно использовать снапшоты, которые делаются, допустим, раз в день.
Заключение
Таким образом, каждая из трёх парадигм ограничивает нас в чём-то:
Структурное отнимает у нас возможность вставить goto где угодно.
ООП не позволяет нам доступаться до скрытых членов классов и навязывает нам инверсию зависимостей.
Что такое парадигмы программирования и зачем они нужны
Знакомство с новыми парадигмами программирования может перевернуть вашу точку зрения на написание кода. Рассказываем, что это такое.
Парадигма программирования — это набор идей и понятий, которые определяют стиль написания программ, подход к программированию. Существует множество разных парадигм, но чаще всего используются императивная и декларативная, практически противоположные друг другу.
Императивная парадигма программирования
В императивной (англ. imperative — приказ) парадигме разработчик пишет для компьютера инструкции, которым тот следует. Инструкции могут быть следующие:
То есть программист говорит, что нужно сделать и в каком порядке, а компьютер выполняет приказы.
Отличительная черта императивной парадигмы — понятие состояния компьютера или программы. Состояние — это совокупность всех данных в определённый момент времени: переменных, массивов, счётчиков и так далее.
К императивной парадигме относятся следующие виды программирования:
Также императивную парадигму программирования можно считать более низкоуровневой, потому что программисту нужно знать, как работают программы.
Декларативная парадигма программирования
В декларативной парадигме разработчик описывает проблему и ожидаемый результат, но не пишет никаких инструкций. В декларативном программировании отсутствуют переменные, состояние и прочие понятия, которые свойственны императивной парадигме.
К декларативной парадигме относятся функциональное и логическое программирование.
Пишет о программировании, в свободное время создает игры. Мечтает открыть свою студию и выпускать ламповые RPG.
Примеры использования парадигм
Допустим, у нас есть массив следующих чисел:
Нам может понадобиться получить из этого массива все числа, которые больше 3, но меньше 100.
В декларативном программировании разработчик просто пишет следующее:
Программист не думает о том, как программа будет искать эти числа, он просто пишет, какой результат ему нужен.
В императивном программировании придётся самостоятельно написать код, который будет проверять все числа из массива N на соответствие условию и, если они подходят, записывать их в новый массив. То есть код будет выглядеть примерно так:
То есть в декларативном программировании разработчик говорит, что ему нужно. А в императивном — как это можно получить.
Давайте рассмотрим это на примере двух реальных языков:
C# (императивный) | SQL (декларативный) |
---|---|
int[] N = new int[] < 5, 1, 3, 9, 12, 583, 998, 7538, 72, 53, 71, 85, 7, 2, 9 >; List nums = new List (); for(int i = 0; i 3 && N[i] 3 AND num Зачем это нужно У вас мог появиться вполне логичный вопрос: Зачем использовать императивное программирование, если декларативное позволяет писать гораздо меньше кода?Есть несколько причин. Во-первых, декларативное программирование — это обёртка для императивного. Компьютер не может вот так просто понять, чего хочет программист, поэтому для него нужно написать конкретные инструкции, что и в каком порядке делать. Когда вы пишете запрос в SQL, его выполнение происходит по заранее описанным инструкциям. Поэтому нам нужно императивное программирование, чтобы заставить работать декларативное. Во-вторых, декларативное программирование не подходит для задач, для решения которых важно иметь доступ к состоянию программы — например, если нужно проверить, нажата ли кнопка или поставлена ли галочка в чекбокс. В декларативном программировании нельзя отследить ни само состояние, ни его изменение, поэтому не получится указать, что должно происходить в ответ на действия пользователя. В-третьих, императивное программирование даёт больше свободы, поэтому его чаще используют в творческих областях, особенно там, где важен порядок выполняемых действий. Каждая парадигма подходит для определённых задач: императивная лучше для работы с анимацией, графическими интерфейсами, скриптами, играми и многим другим, а декларативная — для вычислений и работы с данными. Поэтому вопрос «Какая парадигма лучше?» некорректен: они все хороши, если использовать их по назначению. ЗаключениеБольшинство языков поддерживают обе парадигмы, но заточены под одну из них. Один из таких языков — C#. Несмотря на то что это объектно-ориентированный язык программирования (императивная парадигма), в нём присутствуют элементы функциональной разработки (декларативная разработка). Освоить этот язык, особенности ООП, а также ознакомиться с функциональной разработкой вы можете на курсе «Профессия C#-разработчик». «Забытые» парадигмы программированияПолучилось так, что те парадигмы, которые раньше потом и кровью пробивались в свет через орды приверженцев традиционных методов постепенно забываются. Эти парадигмы возникли на заре программирования и то, почему они возникали, какие преимущества они давали и почему используются до сих пор полезно знать любому разработчику. Ладно. Введение это очень весело, но вы его все равно не читаете, так что кому интересно — добро пожаловать под кат! Императивное программирование
Это были машинные коды, языки ассемблера и ранние высокоуровневые языки, вроде Fortran. Ключевые моменты:В этой парадигме вычисления описываются в виде инструкций, шаг за шагом изменяющих состояние программы. В низкоуровневых языках (таких как язык ассемблера) состоянием могут быть память, регистры и флаги, а инструкциями — те команды, что поддерживает целевой процессор. В более высокоуровневых (таких как Си) состояние — это только память, инструкции могут быть сложнее и вызывать выделение и освобождение памяти в процессе своей работы. В совсем высокоуровневых (таких как Python, если на нем программировать императивно) состояние ограничивается лишь переменными, а команды могут представлять собой комплексные операции, которые на ассемблере занимали бы сотни строк. Основные понятия:Порожденные понятия:— Присваивание Языки поддерживающие данную парадигму:Как основную:— Языки ассемблера Как вспомогательную:— Python Стоит заметить, что большая часть современных языков в той или иной степени поддерживает императивное программирование. Даже на чистом функциональном языке Haskell можно писать императивно. Структурное программирование
Основоположниками структурного программирования были такие знаменитые люди как Э. Дейкстра и Н. Вирт. Языками-первопроходцами в этой парадигме были Fortran, Algol и B, позже их приемниками стали Pascal и C. Ключевые моменты:Эта парадигма вводит новые понятия, объединяющие часто используемые шаблоны написания императивного кода. В структурном программировании мы по прежнему оперируем состоянием и инструкциями, однако вводится понятие составной инструкции (блока), инструкций ветвления и цикла. Благодаря этим простым изменениям возможно отказаться от оператора goto в большинстве случаев, что упрощает код. Иногда goto все-же делает код читабельнее, благодаря чему он до сих пор широко используется, несмотря на все заявления его противников. Основные понятия:— Блок Языки поддерживающие данную парадигму:Как основную:Как вспомогательную:— C# Поддерживают частично: Опять-же большая часть современных языков поддерживают структурную парадигму. Процедурное программирование
Собственно еще раз были введены дополнительные понятия, которые позволили по-новому взглянуть на программирование. Этим понятием на этот раз была процедура. В результате возникла новая методология написания программ, которая приветствуется и по сей день — исходная задача разбивается на меньшие (с помощью процедур) и это происходит до тех пор, пока решение всех конкретных процедур не окажется тривиальным. Ключевые моменты:Процедура — самостоятельный участок кода, который можно выполнить как одну инструкцию. В современном программировании процедура может иметь несколько точек выхода (return в C-подобных языках), несколько точек входа (с помощью yield в Python или статических локальных переменных в C++), иметь аргументы, возвращать значение как результат своего выполнения, быть перегруженной по количеству или типу параметров и много чего еще. Основные понятия:Порожденные понятия:— Вызов Языки поддерживающие данную парадигму:Как основную:— C Как вспомогательную:— C# Поддерживают частично: Стоит отметить, что несколько точек входа из всех этих языков поддерживаются только в Python. Модульное программирование
Забегая вперед скажу, что модули тоже оказались неспособны сдержать с невероятной скоростью растущую сложность ПО и в последствии появились пакеты (это тоже модульное программирование), классы (это уже ООП), шаблоны (обобщенное программирование). Программа описанная в стиле модульного программирования — это набор модулей. Что внутри, классы, императивный код или чистые функции — не важно. Благодаря модулям впервые в программировании появилась серьезная инкапсуляция — возможно использовать какие-либо сущности внутри модуля, но не показывать их внешнему миру. Ключевые моменты:Модуль — это отдельная именованная сущность программы, которая объединяет в себе другие программные единицы, близкие по функциональности. Например файл List.mod включающий в себя класс List Папка Geometry, содержащая модули Shape, Rectangle и Triangle — тоже модуль, хоть и некоторые языки разделяют понятие модуля и пакета (в таких языках пакет — набор модулей и/или набор других пакетов). Модули можно импортировать (подключать), для того, чтобы использовать объявленные в них сущности. Основные понятия:Порожденные понятия:Языки поддерживающие данную парадигму:Как основную:— Haskell Как вспомогательную:— Java Поддерживают частично: В некоторых языках для модулей введены отдельные абстракции, в других же для реализации модулей можно использовать заголовочные файлы (в C/C++), пространства имен, статические классы и/или динамически подключаемые библиотеки. Вместо заключенияВ данной статье я не описал популярные сейчас объектно-ориентированное, обобщенное и функциональное программирование. Просто потому, что у меня есть свое, довольно радикальное мнение на этот счет и я не хотел разводить холивар. По крайней мере сейчас. Если тема окажется полезной для сообщества я планирую написать несколько статей, изложив основы каждой из этих парадигм подробно. Также я ничего не написал про экзотические парадигмы, вроде автоматного, аппликативного, аспект/агент/компонент-ориентированного программирования. Я не хотел делать статью сильно большой и опять-же если тема будет востребована, я напишу и об этих парадигмах, возможно более подробно и с примерами кода. Парадигма программированияПриверженность определённого человека какой-то одной парадигме иногда носит настолько сильный характер, что споры о преимуществах и недостатках различных парадигм относятся в околокомпьютерных кругах к разряду так называемых «религиозных» войн — холиваров. СодержаниеИстория терминаСвоим современным значением в научно-технической области термин «парадигма» обязан, по-видимому, Томасу Куну и его книге «Структура научных революций» (см. парадигма). Кун называл парадигмами устоявшиеся системы научных взглядов, в рамках которых ведутся исследования. Согласно Куну, в процессе развития научной дисциплины может произойти замена одной парадигмы на другую (как, например, геоцентрическая небесная механика Птолемея сменилась гелиоцентрической системой Коперника), при этом старая парадигма ещё продолжает некоторое время существовать и даже развиваться благодаря тому, что многие её сторонники оказываются по тем или иным причинам неспособны перестроиться для работы в другой парадигме. Термин «парадигма программирования» впервые применил Роберт Флойд в своей лекции [2] лауреата премии Тьюринга. Флойд отмечает, что в программировании можно наблюдать явление, подобное парадигмам Куна, но, в отличие от них, парадигмы программирования не являются взаимоисключающими:
Таким образом, по мнению Роберта Флойда, в отличие от парадигм в научном мире, описанных Куном, парадигмы программирования могут сочетаться, обогащая инструментарий программиста. Различные определенияДалеко не все авторы, использующие термин «парадигма программирования», решаются дать интенсиональное определение данному термину. Однако и те определения, которые удаётся найти, серьёзно отличаются друг от друга. Диомидис Спинеллис даёт следующее определение [3] :
Памела Зейв (Pamela Zave) даёт определение парадигмы как «способа размышления о компьютерных системах» (в оригинале «way of thinking about computer systems»). [7] Питер Вегнер (Peter Wegner) предлагает другой подход к определению термина парадигмы программирования. В его работе «Concepts and paradigms of object-oriented programming» [8] парадигмы определяются как «правила классификации языков программирования в соответствии с некоторыми условиями, которые могут быть проверены». Тимоти Бадд предлагает понимать термин «парадигма» как «способ концептуализации того, что значит „производить вычисления“, и как задачи, подлежащие решению на компьютере, должны быть структурированы и организованы». [9] Парадигма программирования как исходная концептуальная схема постановки проблем и их решения является инструментом грамматического описания фактов, событий, явлений и процессов, возможно, не существующих одновременно, но интуитивно объединяемых в общее понятие. Основные модели программированияПодходы и приёмыСм. такжеПримечанияЛитератураКент Бек • Гради Буч • Фред Брукс • Barry Boehm • Уорд Каннингем • Оле-Йохан Даль • Том Демарко • Эдсгер Вибе Дейкстра • Дональд Кнут • Мартин Фаулер • Чарльз Энтони Ричард Хоар • Watts Humphrey • Майкл Джексон • Ивар Якобсон • Craig Larman • James Martin • Мейер Бертран • Дэвид Парнас • Winston W. Royce • James Rumbaugh • Никлаус Вирт • Эдвард Йордан • Стив Макконнелл Моделирование данных • Архитектура ПО • Функциональная спецификация • Язык моделирования • Парадигма • Методология • Процесс разработки • Качество • Обеспечение качества • Структурный анализ) CMM • CMMI • Данных • Function model • IDEF • Информационная • Metamodeling • Object model • View model • UML ПолезноеСмотреть что такое «Парадигма программирования» в других словарях:ПАРАДИГМА ПРОГРАММИРОВАНИЯ — Совокупность идей и понятий, определяющая стиль написания программ, определяется набором инструментов программиста, а именно, языком программирования и используемыми библиотеками, определяет то, в каких терминах программист описывает логику… … Словарь бизнес-терминов Парадигма (значения) — Парадигма (от греч. παράδειγμα, «пример, модель, образец»): Парадигма (лингвистика) Парадигма в философии науки. Парадигма программирования Другие значения: Парадигма в риторике пример, взятый из истории или мифологии и приведенный с целью… … Википедия Парадигма — (Paradigm) Определение парадигмы, история возникновения парадигмы Информация об определении парадигмы, история возникновения парадигмы Содержание Содержание История возникновения Частные случаи (лингвистика) Управленческая парадигма Парадигма… … Энциклопедия инвестора Парадигма (программирование) — Парадигма программирования это совокупность идей и понятий, определяющая стиль написания программ. Парадигма, в первую очередь, определяется базовой программной единицей и самим принципом достижения модульности программы. В качестве этой единицы … Википедия Парадигма — (от греч. παράδειγμα, «пример, модель, образец») совокупность фундаментальных научных установок, представлений и терминов, принимаемая и разделяемая научным сообществом и объединяющая большинство его членов. Обеспечивает преемственность… … Википедия Парадигма (философия) — У этого термина существуют и другие значения, см. Парадигма (значения). Парадигма (от др. греч. παράδειγμα, «пример, модель, образец» Википедия Язык программирования — Язык программирования формальная знаковая система, предназначенная для записи компьютерных программ. Язык программирования определяет набор лексических, синтаксических и семантических правил, задающих внешний вид программы и действия,… … Википедия Языки программирования — Язык программирования формальная знаковая система, предназначенная для записи программ. Программа обычно представляет собой некоторый алгоритм в форме, понятной для исполнителя (например, компьютера). Язык программирования определяет набор… … Википедия Мультипарадигмальный язык программирования — Мультипарадигмальный язык программирования как правило, язык программирования, который был разработан специально как инструмент мультипарадигмального программирования, то есть изобразительные возможности которого изначально предполагалось… … Википедия Мультипарадигменный язык программирования — Под мультипарадигмальным языком программирования понимают, как правило, такой язык, который был разработан специально как инструмент мультипарадигмального программирования, т.е. изобразительные возможности которого изначально предполагалось… … Википедия
|