|
© 18.04.2026
Александр Легалов
Приведение в маломальскую систему личных взглядов и постоянная их коррекция на любой предмет изучения или исследования позволяет, в первую очередь, упорядочить видение того, кто занимается этим предметом. Даже несмотря на то, что эти взгляды могут быть ошибочными и не ведут сложению всего пазла. Когда-то, еще в начале нулевых, у меня сформировалась определенная классификация парадигм и языков программирования, которую гораздо позднее зафиксировал у себя на сайте. По прошествии времени ряд проекций обновились, что во многом объясняется смещением интересов на определенные области программирования, не все из которых напрямую связаны с парадигмами. Эти изменения и отражены в данном тексте. Предполагается, что эти заметки являются неким драфтом, склонным к дальнейшим изменениям по мере интереса вернуться к этой теме. Если он появится...
Независимо от используемых подходов, языки и системы программирования обеспечивают техническую поддержку процесса разработки, окончательной целью которого является создание программы. Существуют различные классификации парадигм программирования, которые отражают отдельные характеристики. Однако зачастую, используя их, трудно оценить взаимосвязь применяемых стилей, а также разделить критерии и параметры, определяющие способы написания программ. Это затрудняет:
определение места разных парадигм в процессе разработки программ;
исследование критериев качества программного обеспечения и влияние на них различных подходов к программированию;
формирование моделей для исследования и оценки характеристик систем программирования;
создание инструментальных средств, обеспечивающих поддержку процессов разработки;
выработку новых методов построения программ, отличающихся от существующих или реализующих новые комбинации известных подходов.
Ниже делается попытка рассмотреть характеристики, связанные с процессами создания программ, и связать их с техниками кодирования.
В начале хотелось бы выделить обобщенные группы, определяющие независимые друг от друга различные параметры (принцип: разделяй и властвуй). Формирование общего восприятия программирования при этом может быть достигнуто путем комбинирования альтернативных характеристик, набираемых как из разных групп, так и внутри одной группы. Первоначальное разделение, связанное с отделением техники кодирования от других факторов, можно провести следующим образом:
характеристики, определяющие развертывание программ на используемые вычислительные средства (архитектура ПО или развертывание);
характеристики, задающие размещение объектов разрабатываемой программы по различным логическим группам (группирование или дизайн);
характеристики, фиксирующие технические приемы написания программ (техника кодирования).
Также следует отметить, что для каждой группы характеристик существуют свои инструментальные средства, обеспечивающие техническую, методическую, а зачастую и методологическую поддержку. За счет этих вспомогательных программных средств обеспечивается автоматизация и повышение эффективности процессов разработки программного обеспечения (ПО).
Архитектурные характеристики программного обеспечения
Архитектура или развертывание программного обеспечения определяет размещение создаваемых программных продуктов на различных компьютерных системах и средах, что во многом обуславливается выбором подходов к решению требуемой задачи предметной области. По сути на данном этапе определяется эффективность выполнения разработанного софта и его использование в реальных условиях. Разнообразие архитектур велико, и они неплохо описаны в различных источниках. Например, в [АрхРичардс Марк, Форд Нил. Фундаментальный подход к программной архитектуре. 2-е междунар. изд. — Астана: «Спринт Бук», 2026. — 544 с.]. В качестве далеко не полного примера и без детализации можно привести следующие варианты.
Развертывание программы на одном компьютере.
Отображение программ на суперкомпьютерные системы, используемые для высокопроизводительных вычислений.
Создание клиент-серверных приложений, осуществляющих взаимодействие с множеством пользователей. В рамках этого решения можно выделить множество разновидностей используемых в настоящее время.
Использование сервисной или микросервисной архитектур.
При разработке подобных решений акцент в большей степени осуществляется именно на развертывание продукта, а не на реализацию основных алгоритмов предметной области, которые обычно к этому моменту уже являются программно реализованными. Конечно зачастую осуществляется дополнительная подработка напильником, связанная с повышением эффективности взаимодействия между программными модулями, но суть решаемой задачи, ориентированной на определенную предметную область, при этом вряд ли изменяется. То есть, это не техника написания кода, а в большей степени организационно-профилактические мероприятия.
Вполне естественно, что необходимо создавать дополнительное системное и административное ПО, обеспечивающие поддержку целевых архитектур или использовать инструментальные средства, реализующие необходимое развертывание и функциональность. Однако это связано со вспомогательными решениями, ориентированными на поддержку функционирования различных приложений, развертываемых на соответствующих компьютерных системах, что в совокупности и определяет архитектуру ПО.
Существуют различные программные продукты и технологии, обеспечивающие инструментальную поддержку развертывания и использования программного обеспечения (DevOpc в помощь). На уровне сетевых и облачных решений можно отметить Kubernetes и другие, использованние которого позволяет поддерживать непрерывное развертывание. Также к инструментам данного уровня можно отнести средства виртуализации, например, Docker.
Еще один пример. Разработка параллельных программ, разворачиваемых на суперкомпьютерах, требует не только создания параллельных алгоритмов, и библиотек, обеспечивающих передачу сообщений (например, MPI), что больше уже связано с техникой кодирования. Помимо этого используются специальные инструментальные средства для администрирования, обеспечивающие выделение необходимого числа процессоров, постановку в очередь, сохранение промежуточных результатов и многое другое. Программы нужно разместить в соответствующей вычислительной среде с использованием средств планирования и организации вычислений, которые должны поддерживать эффективность обработки данных. Они влияют на динамику программы и ведут к ее трансформации в зависимости от используемых вычислительных ресурсов. Однако определяемые предметной областью и методами распараллеливания алгоритмические преобразования данных не изменяются, так как должны приводить в ходе вычислений к тем же результатам, что и аналогичные программы, выполняемые на других конфигурациях вычислительных систем.
Более детальное копание в архитектурных решениях не связано с моими текущими рассуждениями и интересами, так как вряд ли относятся к технике кодирования. Поэтому, поверхностно зафиксировав в классификации этот аспект, определяющий ряд соответствующих методов и парадигм программирования, я перехожу к рассмотрению других характеристик.
Группирование программы или дизайн
Характеристики данной группы определяют формирование модульной структуры программы. В целом объединение программных объектов в различные физические или логические единицы является одним из основных параметров, направленных на поддержку соответствующих критериев качества, среди которых можно отметить:
повторное использование кода;
поддержку эволюционного расширения;
эффективность сборки окончательного программного решения;
сокрытие и защиту (инкапсуляцию) кода и данных;
возможность формирования различных конфигураций из отдельных единиц компиляции.
В языках программирования существуют различные подходы к группировке программных объектов. Очень редко языки поддерживали написание только монолитного кода (в основном это ранние или достаточно простые языки программирования). Обычно разрабатываемые программы разделяются на отдельные составляющие, обеспечивающие их раздельную компиляцию, сборку или динамическое подключение. Среди используемых вариантов можно отметить следующие подходы к формированию отдельных групп программных объектов.
Группировка разработанного кода в единое монолитное решение, являющееся законченной программой. В ходе последующей компиляции формируется исполняемый файл. Такое решение может использовать различные системные и служебные библиотеки, но их применение прозрачно и осуществляется через обращение к соответствующим внешним функциям, данным или объектам.
Разделение разрабатываемой программы на отдельные единицы компиляции в виде файлов с использованием для их связывания заголовочных файлов (хедеров), описывающих интерфейсы в виде прототипов функций и ссылок на внешние объявления переменных (например, используется в Си).
Разбиение программы на модули как независимые единицы компиляции или компоновки. Связь между модулями осуществляется с использованием механизма импорта. В ряде языков при этом выделяются отдельно модули экспорта и модули реализации (как в Modula-2). Но также разделение экспорта и реализации может осуществляться и порождаться во время компиляции (Oberon).
Дополнительно разделение внутри единиц компиляции на пространства имен, используемых для группировки кода, размещаемого в разных единицах компиляции.
Формирование разнообразных вариантов пакетов.
Использование для группировки объектов при разработке программ с использованием объектно-ориентированного подхода. При этом все объекты (по Алану Кею) являются автономными и независимыми сущностями (биологическими клетками), взаимодействующими с другими только через свои интерфейсы.
Создание библиотек обеспечивает дополнительные вариант группировки и использования программных объектов. Наряду с архивацией нескольких единиц компиляции они также поддерживают различные варианты организации. В частности существуют статически и динамически подключаемые библиотеки. Последние при этом могут подключаться как во время компоновки программы, таки и в ходе ее выполнения.
Этот список можно продолжить, так как вариантов организации модульной структуры существует много. И много новых еще можно придумать.
Следует также отметить, что зачастую одни и те же термины различным образом трактуются в разных языках программирования, определяя тем самым разную организацию модульной структуры. Например, понятие пакта в Go или Java...
Пакет (package) в языке программирования Go — это основной способ организации кода, представляющий собой папку с одним или несколькими файлами *.go, имеющими одинаковое объявление package <name> в начале. Пакеты обеспечивают инкапсуляцию, разделяют код на модули и могут быть исполняемыми (package main) или библиотеками.
Пакет (package) в языке программирования Java — это механизм для организации классов, интерфейсов и подпакетов в логические группы (пространства имён), подобно папкам в файловой системе. Они предотвращают конфликты имен, упрощают навигацию по коду и управляют доступом к классам. Обычно пакеты именуются в обратном доменном стиле.
Использование методов группировки тоже вряд ли значительно влияет на технику кодирования и алгоритмы предметной области. Собирать, компоновать, тасовать код можно различным образом в разных языках программирования. Суть при этом их суть не меняется. Алгоритмы и данные уже разработаны и описаны в виде некоторого кода, который и размазывается по отдельным сущностям используемых модульных конструкций.
Как и на уровне развертывания, для повышения эффективности процесса разработки ПО используются специальные инструментальные средства, обеспечивающие автоматизацию группировки и ее эффективное сопровождение. Они могут быть простыми или сложными, универсальными или ориентированными на поддержку только конкретных языков программирования. В качестве примера поверхностно можно отметить различные системы сборки программ на Си и C++ (make, automake, qmake, cmake...), сборщики проектов, разрабатываемых на языках Go, Rust, Java (go build, cargo, maven, gradle, groovy). Очень много вспомогательных языков, масса разных инструментов...
Хотелось бы также отметить, что, независимо от используемой в том или ином языке программирования группировки программных объектов, ничего кардинального в разрабатываемое приложение не вносится. На мой взгляд достаточно просто перейти от одной модульной структуры к другой. Скорее всего не так сложно реализовать инструментальные средства, обеспечивающие эквивалентные преобразования одной любой группировки в другую. Я не вижу каких-то формальных и технических проблем, связанных с такими преобразованиями, если говорить о семантике. В принципе семантика и алгоритмическая составляющая в этих ситуациях не меняется.
К примеру, если бы язык программирования с определенным синтаксисом допускал возможность группировать программные объекты в различные модульные структуры, это позволило бы осуществлять подобные трансформации без особых проблем на уровне семантических моделей модулей. Пример подобной трансформации, сделанной, правда, в образовательной и развлекательной целях, представлен в материале, описывающем возможности эволюционного расширения программ с применением различных парадигм.
Имеет смысл об этом подумать и возможно сформировать некоторую семантическую модель, позволяющую описывать различные варианты модулей. Такие преобразования можно было бы связать с различными постобработками программ, например, с исправлением "неэффективных" модульных решений программистов. Тем более, что в настоящее время методы "сами знаете кого" (или чего? Как его будут именовать через некоторое время?) широко внедряются в программирование и широко рекламируются как замена программистов.
Я не собираюсь разбирать варианты группировки, так как они также лежат вне сферы моих текущих интересов. Мысли по этому поводу есть, но они, скорее всего, отобразятся в частные решения при разработке планируемых языков программирования.
Техника кодирования
Техника кодирования характеризует особенности написания кода на уровне языков программирования. Именно она определяет специфику отображения в программах алгоритмов и данных, используя как особенности синтаксиса, так и семантики языков программирования. К данной группе относятся следующие характеристики:
алгоритмизация (опирается на теорию алгоритмов);
однозначность (связана с системами типов);
композиция данных и функций (например, объекты или алгоритмы+данные);
уровни абстракций (надстройки определяющие метапрограммирование);
управление вычислениями (теория параллельных вычислений);
память (модели размещения данных и, возможно, кода).
Во многом именно различные варианты техник определяют методы разработки программ и ключевые парадигмы программирования.
в увеличенном виде
Методы алгоритмизации
Отображение алгоритма в код является одной из основных задач программирования. Особенности исполнителей алгоритмов определяют подходы к выполнению в них вычислений. Разнообразие методов алгоритмизации порождает множество поведенческих парадигм, каждая из которых характеризуется своей спецификой описания процессов обработки данных. Разные способы описания алгоритмов в языках программирования определяют стили кодирования, конкурирующие между собой со времени появления первых теоретических работ. Можно отметить следующие варианты (не все, я думаю, но другие меня сейчас не слишком интересуют):
императивное программирование;
функциональное программирование;
логическое программирование;
предметно-ориентированное программирование.
Исторически именно появление первых теоретических работ определило основные подходы к алгоритмизации, которые впоследствии вылились в разнообразные способы описания алгоритмов. В частности, машина Тьюринга во многом способствовала появлению и развитию императивного программирования. Опираясь на эту основу в дальнейшем была сформирована Фон-Неймановская архитектура, определяющая вычислительную машину, непосредственно исполняющую команды, заданные программистом. При этом команды явно связаны между собой только по управлению, а зависимость по данным выстраивается на основе образных ассоциаций программиста, мысленно осуществляющего проверку корректности логики их использования.
При разработке языков программирования императивный подход подвергся различным модификациям, связанным как с адаптациями к предметным областям, так и со стремлением повысить надежность процесса разработки программ. В частности появился такой императивный стиль, как структурное программирование. Сформировавшись на основе отрицания оператора goto данный подход написания программ первоначально с использованием трех предложенных операторов (последовательность, if, while) в дальнейшем получил ряд других структур управления и стал "иконой" императивного стиля. Это привело к отсутствию goto в ряде языков программирования.
В качестве другой разновидности императивного стиля можно выделить автоматное программирование, ориентированное на создание программы в виде модели состояний и переходов, что ведет к абстрагированию на этапе разработки от операций, связанных с обработкой данных. Теоретической основой данного стиля является теория автоматов. Основной упор делается на логику переходов между состояниями и условий, определяющих переходы. Это ускоряет построение общей схемы логического управления алгоритмом. Выделение в отдельную парадигму обычно определяется жестким следованием стилю написания программы, связанному с непосредственным представлением автоматной модели. Обычно данный стиль зачастую в языках не используется и реализуется через определенную дисциплину кодирования. Но можно отметить специализированные языки, непосредственно поддерживающие его, например, Рефлекс.
Функциональное программирование связано с работами Черча. Оно опирается на теорию рекурсивных функций и описывает процесс управления в виде отношений между ними. Управление явно не задается и определяется зависимостью между функциями, результаты выполнения которых используются в качестве аргументов других функций.
Следует отметить, что термин "функция" в этом тексте используется как для функций, так и для процедур. Обычно в современных трактовках термин "процедура" считается устаревшим и используется реже.
Логическое программирование опирается на логику исчисления предикатов, которая обуславливает организацию алгоритма, непосредственно не описывающую вычисления. Используемая для его выполнения машина логического вывода первоначально осуществляет анализ правил, задающих различные отношения, выбирая среди них на выполнение те, которые соответствуют заданным условиям. Для поддержки данной парадигмы разработаны соответствующие языки программирования и исполнительные системы.
Предметно-ориентированное программирование В данном случае рассматривается как множество других подходов к написанию программ, ориентированных на определенную специфику предметных областей. Таких языков много. В их основе лежат различные синтаксисы и семантики, способы представления программы. В данном случае более детальное их обсуждение лежит вне рамках данных заметок.
Также я не акцентирую внимания на понятии "Декларативное программирование". Часто оно объединяет функциональный и логический стили. Думаю, что сюда же можно отнести и многие предметно-ориентированные подходы. Но в целом это уже связано с детализацией представленных характеристик, а не их фрагментарного описания.
Каждый из представленных стилей задает специфическую интерпретацию понятий, связанных с поведением программы и обуславливает конкретные методы и приемы построения алгоритмов, которые могут сильно отличаться даже для одной и той же решаемой задачи.
Методы задания однозначности
Однозначность определяется правилами выполнения каждой операции или функции программы как в реальных, так и в виртуальных вычислительных системах. Каждая из операций (команд) программы имеет четкое описание, определяющее ее семантику. Знание этой семантики позволяет избегать ошибок при программировании.
Задание однозначности непосредственно связано с выполнением операций над данными и тем, как в конкретной операции интерпретируются обрабатываемые ею данные. Основной характеристикой данных является их тип, с которым и связывается множество выполняемых действий. Однако при этом однозначность между операциями и данными может определяться различными способами, определяя тем самым различные методы типизации. Можно выделит следующие варианты задания однозначности и используемые при этом методы типизации:
операционную однозначность;
статическую однозначность;
динамическую однозначность.
Операционная однозначность. Обеспечивается тем, что каждая выполняемая операция однозначно трактует свои операнды, которые задаются в бестиповом представлении. То есть, отсутствует какая-либо система контроля обрабатываемых данных. Весь контроль за корректностью возлагается на программиста, и его образные ассоциации по трактовке обрабатываемых данных. Данный вид однозначности обычно реализуется на уровне системы команд компьютерных систем. Также бестиповые операции используются в языках ассемблера, инструкции которых зачастую являются непосредственным отображением команд компьютера.
Статическая однозначность. Определяется статической типизацией данных. Это обеспечивает статический полиморфизмом операций, позволяющий однозначно определить тип результата до выполнения программы. При этом одни и те же обозначения операций могут использоваться над данными различного типа. Распознавание соответствия типов данных и операций осуществляется во время компиляции, что позволяет порождать код поддерживающий на выходе операционную однозначность, которая обеспечивает наиболее эффективное выполнение программ в современных компьютерах. Статическая однозначность реализуется в статически типизированных языках программирования.
Динамическая однозначность. Используется в системах с динамической типизацией данных. В этом случае при выполнении операций соответствие между ними и обрабатываемыми данными определяется во время выполнения. Обычно реализуется в динамически типизированных языках программирования. Вычисления чаще всего выполняются с использованием интерпретаторов.
Уровни абстракций (метауровни)
Уровни абстракций определяют системы понятий, определяющих абстрагирование алгоритмов и данных от особенностей физической организации компьютерных систем, предоставленных в распоряжение программиста для кодирования. Можно выделить следующие варианты абстракций, относящихся к техническим приемам.
Начальный уровень. Непосредственное использование понятий компьютерной архитектуры, при котором отсутствуют дополнительные абстракции, а осуществляется непосредственное отображение на память компьютера. В языках программирования к этому уровню можно отнести отображение переменных и подпрограмм, осуществляющих взаимодействие с этими переменными. Предполагается, что артефакты этого слоя непосредственно отображаются на компьютерную память, хотя при их создании могут использоваться и языки программирования. При этом, что в подпрограммах отсутствуют даже такие абстракции, как формальные параметры. Хотя последнее вряд ли принципиально.
К начальному уровню можно отнести и составные конструкции языков программирования, непосредственно отображаемые на вычислительную систему. Например, клонирование данных (описание переменных как подобие других переменных), встречалось в языке программирования PL/1. Одной из проблем данного способа описания является то, что его достаточно сложно оторвать от памяти для независимого использования и переносимости. Вместе с тем, к данному уровню можно отнести функции и процедуры, использующие формальные параметры, позволяющие абстрагироваться от явного выделения памяти при передаче в них фактических параметров.
Слой, состоящий из абстрактных типов. К нему можно отнести классы, абстрактные типы данных (АТД) и функции с их использованием в качестве формальных параметров. Основной спецификой является отсутствие непосредственного отображения этих абстракций на память компьютера до момента формирования экземпляров классов или переменных, которые и отображаются на память. Этим отображением занимается компилятор.
Макропроцессоры. Обеспечивают трансформацию одних текстов в другие. В целом они в большинстве случаев могут быть не связаны с семантикой конкретного языка программирования. Однако позволяют из более общих описаний формировать абстракции предшествующих уровней, не используя при этом семантический или синтаксический контроль для создаваемых конструкций.
Метаконструкции. Используются, как и макропроцессоры, для порождения текстовых или промежуточных представлений конструкций языков программирования. Однако обычно их синтаксис и семантика непосредственно интегрированы с целевым языком программирования, а порождаемые в результате программные объекты также являются синтаксически и семантически правильными конструкциями предыдущих уровней. Зачастую этот слой поддерживает генеративное программирование.
Языки метапрограммирования. Являются специально разработанными языками высокого уровня, обеспечивающими поддержку комплексного представления и трансформации всех предшествующих слоев. Зачастую при этом реализуются более сложные конструкции, ориентированные на поддержку метапрограммирования и генеративного программирования. Помимо этого на уровне таких языков могут поддерживаться методы формальной верификации программ.
Методы композиции данных и функций
Разнообразие композиций данных и функций определяется достаточно тривиально и вытекает из того, что программа состоит из алгоритмов и обрабатываемых ими данных. В результате возможны только три варианта.
алгоритмы, реализуемые в виде функций (подпрограмм, процедур), отделены от данных и используют последние в качестве своих аргументов и результатов, а программа при этом представляет совокупность функций и данных;
алгоритмы и данные образуют единую конструкцию, которая определяет некоторый смешанный программный объект, а программа формируется как совокупность таких объектов;
комбинация из раздельных данных и функций, а также смешанных программных объектов.
Эти три варианта могут рассматриваться на различных уровнях абстракции, образуя разнообразные соотношения. В принципе без уровней абстракции, а также в какой-то мере без организации памяти их рассмотрение во многих ситуациях вряд ли имеет смысл, так как любая программа уже является совокупностью алгоритмов и данных, образуя с одной стороны синглетон, а с другой являясь абстракцией для возможного порождения множества одновременно выполняемых экземпляров. Однако на этом уровне код уже написан и говорить об ее трактовки с точки зрения техники кодирования уже не имеет смысла. Уровни абстракции в данной ситуации во многом определяют то, как воспринимаются и интерпретируются эти композиции.
Изначально техника кодирования опиралась на использование базовых типов данных, предоставляемых компьютерными архитектурами и первыми языками программирования. Функции и процедуры использовали их в качестве основных исходных данных и формировали соответствующие результаты. Для обработки более сложных по структуре абстракций использовались образные восприятия, объединяющие в голове программиста несколько отдельных переменных.
Впоследствии для формирования структур данных появились абстракции, обеспечивающие соответствующие группировки базовых типов в более сложные конструкции. Это расширило технику кодирование и обеспечило более удобное непосредственное описание данных из различных предметных областей. Функции стали ориентироваться на обработку структурированных параметров. Сами абстракции строились по принципам "И-ИЛИ". К первой категории относились структуры (записи), а ко второй - объединения (вариантные записи). Из этих программных объектов выстраивались композиции данных, которые отображались на память в виде переменных различного типа. Данное направление, наряду с функциями, обрабатывающими данные определенной структуры, расширило возможности процедурной парадигмы программирования.
В ходе дальнейшего развития данного направления появились композиции, объединяющие в единую абстракцию данные и функции, что послужило толчком к развитию объектно-ориентированной парадигмы. С появлением классов возникли новые методы формирования функций (методов) и способов их взаимодействия. Также появились новые методы композиции и обработки данных, определившие ряд более эффективных решений по созданию программ, включая наследование и динамический полиморфизм.
В отличие от методов алгоритмизации, методы композиции программных объектов не определяют семантику выполнения решаемой задачи. Однако они оказывают существенное влияние на такие характеристики, как декомпозиция программных объектов, повторное использование кода, эволюционное расширение при добавлении в программу новой функциональности. Все это влияет на технику написания сопутствующего кода, который можно рассматривать как дополнительную сервисную обертку над целевыми алгоритмами предметной области. Композиция программных объектов оказывает существенное влияние при разработке больших систем. Именно она обуславливает основные тенденции в современном программировании, в частности, популярность и дальнейшее развитие объектно-ориентированного подхода.
Говоря о композиции программных объектов, можно отметить, что речь идет о небольшом числе форм их конструирования. Это агрегаты и обобщения, связанные между собой непосредственно, косвенно или с использованием ассоциаций. В настоящее время существуют разнообразные альтернативные подходы к формированию этих конструкций, каждый из которых обеспечивает эффективную поддержку тех или иных критериев качества. Наряду с традиционными формами конструирования, опирающимися на вложенность конструкций, сейчас широко используются подходы, обеспечивающие поддержку полиморфизма в той или иной форме, что, в свою очередь, повышает гибкость процесса разработки программного обеспечения. В частности можно выделить.
Процедурное программирование, опирающееся на традиционные абстрактные типы данных, представляющие агрегаты в виде структур (записей) и обобщения в виде объединений (вариантных записей). Обработка обобщений при этом в основном осуществляется функциями, которые перебирают варианты альтернативных типов посредством условных операторов или переключателей.
Объектно-ориентированное программирование, отличительной особенностью которого является обработка альтернатив с применением объектно-ориентированного динамического полиморфизма.
Свои варианты динамического полиморфизма на основе статической утиной типизации, являющегося разновидностью структурного полиморфизма, реализованы посредством интерфейсов в языке программирования Go и типажей в Rust.
Процедурно-параметрическое программирование позволило добавить динамический полиморфизм в процедурный подход, что позволило повысить гибкость при создании эволюционно расширяемых программ.
Разнообразные методы композиции программных объектов хорошо сочетаются с методами алгоритмизации, образуя симбиоз и различные мультипарадигменные стили. Они не противоречат друг другу. В связи с этим возникает недоумение при появлении и в настоящее время противопоставлений функционального подхода объектно-ориентированному. И это при наличии множества функциональных языков программирования в которых реализована ОО композиция! Также ничто не мешает применять различные методы композиции в пределах написания одной программы, если конечно это позволяет используемый язык программирования, предоставляющий соответствующие возможности (например, наш процедурно-параметрический Си).
Методы управления вычислениями
Методы алгоритмизации решаемой задачи тесно связаны с походами к управлению вычислениями, разнообразие которых обуславливается способами описания параллельных вычислений. Управление может варьироваться от последовательного до задания неограниченного параллелизма. Оно может задаваться явно программистом или неявно, когда используются отношения между данными и автоматическое управление ресурсами. Все разнообразие методов управления раскрывается как через архитектуры вычислительных систем, так и языков последовательного и параллельного программирования. Использование тех или иных приемов написания параллельных программ непосредственно влияет на технику кодирования и создаваемые при этом алгоритмы. Даже не смотря на то, что в целом функциональные преобразования данных должны приводить к одному результату при использовании одинакового алгоритма, техника кодирования, используемая при написании параллельных программ, может сильно отличаться для разных вычислительных систем. Это связано с разнообразием возможных стратегий управления вычислениями.
Используемые стратегии управления вычислениями сильно влияют на переносимость параллельных программ, так как именно они непосредственно отражают все ограничения, присущие как реальной вычислительной системе, так и виртуальной машине, определяющей особенности исполнителя конкретного языка программирования.
Варианты организации памяти
Разнообразие вариантов организации памяти достаточно сильно влияет на стили программирования. Они также во многом и часто завязаны на архитектуры реальных вычислительных систем или виртуальных машин. В целом характеристики памяти изучены достаточно хорошо. Я их просто отображу без особых комментариев.
В зависимости от уровня языков программирования в распоряжение предоставляются различные уровни абстракции памяти. Часто выбор между ними является задачей оптимизации или связан с повышением надежности программирования.
Заключение
Представленные выше характеристики показывают, что на технику программирования оказывает влияние множество факторов. Они могут образовывать разнообразные комбинации приемов, используемых различными программистами, каждый из которых выбирает те, которые ему ближе, связаны с используемыми языками программирования, предметной областью, пониманием жизни, религиозными убеждениями в том, что другие варианты разработки программ - это отстой. Разнообразие вариантов использования прямо указывает на то, что программирование должно по определению быть мультипарадигменным.
Другой крайности, связанной с тем, что когда-либо будет создан подход, покрывающий все возможные варианты построения кода с использованием единого языка, тоже вряд ли можно достичь. Найдутся те, которые будут обвинять такой мультипрадигменный язык перегруженным, ограничивая себя определенным уровнем минимализма. Поэтому, как и в случае с Вавилонской башней, вряд ли будет достигнут консенсус. По крайней мере до тех пор, пока всех кодеров не подомнет под себя сами знаете что (или кто?)...
Используемые источники
Ричардс Марк, Форд Нил. Фундаментальный подход к программной архитектуре. 2-е междунар. изд. — Астана: «Спринт Бук», 2026. — 544 с.
|