В компьютерном программировании функционально -ориентированное программирование ( FOP ) или функционально-ориентированная разработка программного обеспечения ( FOSD ) — это парадигма программирования для генерации программ в линейках программных продуктов (SPL) и для поэтапной разработки программ.
FOSD возник из основанных на слоях конструкций и уровней абстракции в сетевых протоколах и расширяемых системах баз данных в конце 1980-х годов. [1] Программа представляла собой стек слоев. Каждый слой добавлял функциональность к ранее составленным слоям, а различные композиции слоев производили различные программы. Неудивительно, что возникла необходимость в компактном языке для выражения таких конструкций. Элементарная алгебра отвечала всем требованиям: каждый слой представлял собой функцию ( преобразование программы ), которая добавляла новый код к существующей программе для создания новой программы, а конструкция программы моделировалась выражением, т. е. композицией преобразований (слоев). Рисунок слева иллюстрирует наложение слоев i, j и h (где h находится внизу, а i — наверху). Для выражения этих конструкций использовались алгебраические обозначения i(j(h)), i•j•h и i+j+h.
Со временем слои были приравнены к функциям, где функция является приращением в функциональности программы. Парадигма проектирования и генерации программ была признана как результат оптимизации реляционных запросов, где программы оценки запросов были определены как выражения реляционной алгебры, а оптимизация запросов была оптимизацией выражений. [2] Линейка программных продуктов представляет собой семейство программ, где каждая программа определяется уникальным составом функций. С тех пор FOSD превратилась в изучение модульности функций, инструментов, анализов и методов проектирования для поддержки генерации программ на основе функций.
Второе поколение исследований FOSD было посвящено взаимодействиям функций, которые возникли в телекоммуникациях. Позже был придуман термин программирование, ориентированное на функции ; [3] эта работа выявила взаимодействия между слоями. Взаимодействия требуют адаптации функций при составлении с другими функциями.
Третье поколение исследований было сосредоточено на том факте, что каждая программа имеет несколько представлений (например, исходный код, make-файлы, документация и т. д.), и добавление функции в программу должно разрабатывать каждое из ее представлений так, чтобы все они были согласованными. Кроме того, некоторые представления могут быть сгенерированы (или получены) из других. В разделах ниже описывается математика трех последних поколений FOSD, а именно GenVoca, [1] AHEAD, [4] и FOMDD [5] [6] , а также предоставляются ссылки на линейки продуктов, которые были разработаны с использованием инструментов FOSD. Кроме того, четыре дополнительных результата, которые применимы ко всем поколениям FOSD, это: метамодели FOSD , кубы программ FOSD и взаимодействия функций FOSD.
GenVoca ( гибрид названий Genesis и Avoca) [1] — это композиционная парадигма для определения программ линеек продуктов. Базовые программы — это 0-арные функции или преобразования, называемые значениями :
f -- базовая программа с функцией f h -- базовая программа с функцией h
а функции — это унарные функции/преобразования, которые разрабатывают (изменяют, расширяют, совершенствуют) программу:
i + x — добавляет функцию i в программу x j + x — добавляет функцию j в программу x
где + обозначает композицию функций. Дизайн программы — это именованное выражение, например:
p 1 = j + f — программа p 1 имеет функции j и f p 2 = j + h — программа p 2 имеет функции j и h p 3 = i + j + h — программа p 3 имеет функции i, j и h
Модель GenVoca домена или линейки программных продуктов представляет собой набор базовых программ и функций (см. MetaModels и Program Cubes ). Программы (выражения), которые могут быть созданы, определяют линейку продуктов. Оптимизация выражений — это оптимизация проектирования программ , а оценка выражений — это генерация программ .
Функции GenVoca изначально были реализованы с использованием методов препроцессора C ( #ifdef feature ... #endif
). Более продвинутая техника, называемая слоями миксинов , показала связь функций с объектно-ориентированными проектами на основе совместной работы.
Алгебраические иерархические уравнения для проектирования приложений ( AHEAD ) [4] обобщили GenVoca двумя способами. Во-первых, они раскрыли внутреннюю структуру значений GenVoca как кортежи. Каждая программа имеет несколько представлений, таких как источник, документация, байт-код и make-файлы. Значение GenVoca — это кортеж представлений программы. Например, в линейке продуктов парсеров базовый парсер f определяется его грамматикой g f , исходным кодом Java s f и документацией d f . Парсер f моделируется кортежем f=[g f , s f , d f ]. Каждое представление программы может иметь подпредставления, и они тоже могут иметь подпредставления, рекурсивно. В общем случае значение GenVoca — это кортеж вложенных кортежей, которые определяют иерархию представлений для конкретной программы.
Пример. Предположим, что терминальные представления — это файлы. В AHEAD грамматика g f соответствует одному файлу BNF, источник s f соответствует кортежу файлов Java [c 1 …c n ], а документация d f — кортежу файлов HTML [h 1 …h k ]. Значение GenVoca (вложенные кортежи) можно изобразить в виде направленного графа: граф для парсера f показан на рисунке справа. Стрелки обозначают проекции, т. е. отображения кортежа на один из его компонентов. AHEAD реализует кортежи как файловые каталоги, поэтому f — это каталог, содержащий файл g f и подкаталоги s f и d f . Аналогично, каталог s f содержит файлы c 1 …c n , а каталог df содержит файлы h 1 …h k .
Во-вторых, AHEAD выражает функции как вложенные кортежи унарных функций, называемых дельтами . Дельты могут быть уточнениями программы (преобразованиями, сохраняющими семантику), расширениями (преобразованиями, расширяющими семантику) или взаимодействиями (преобразованиями, изменяющими семантику). Мы используем нейтральный термин «дельта» для обозначения всех этих возможностей, поскольку каждая из них встречается в FOSD.
Для иллюстрации предположим, что функция j расширяет грамматику на Δg j (добавляются новые правила и токены), расширяет исходный код на Δs j (добавляются новые классы и члены, а существующие методы изменяются) и расширяет документацию на Δd j . Кортеж дельт для функции j моделируется как j=[Δg j ,Δs j ,Δd j ], который мы называем дельта-кортежем . Элементы дельта-кортежей сами могут быть дельта-кортежами. Пример: Δs j представляет изменения, которые вносятся в каждый класс в s f функцией j, т. е. Δs j =[Δc 1 …Δc n ]. Представления программы вычисляются рекурсивно путем вложенного сложения векторов. Представления для парсера p 2 (чье выражение GenVoca равно j+f) следующие:
p 2 = j + f -- выражение GenVoca = [Δg j , Δs j , Δd j ] + [g f , s f , d f ] -- подстановка = [Δg j +g f , Δs j +s f , Δd j +d f ] — составить кортежи поэлементно
То есть грамматика p 2 является базовой грамматикой, составленной с ее расширением (Δg j +g f ), источник p 2 является базовым источником, составленным с ее расширением (Δs j +s f ), и так далее. Поскольку элементы дельта-кортежей сами могут быть дельта-кортежами, композиция рекурсивна, например, Δs j +s f = [Δc 1 …Δc n ]+[c 1 …c n ]=[Δc 1 +c 1 …Δc n +c n ]. Подводя итог, значения GenVoca являются вложенными кортежами программных артефактов, а признаки являются вложенными дельта-кортежами, где + рекурсивно составляет их путем сложения векторов. Это суть AHEAD.
Представленные выше идеи конкретно раскрывают два принципа FOSD. Принцип единообразия гласит, что все программные артефакты обрабатываются и изменяются одинаково. (Об этом свидетельствуют дельты для различных типов артефактов выше). Принцип масштабируемости гласит, что все уровни абстракций обрабатываются единообразно. (Это приводит к иерархической вложенности кортежей выше).
Первоначальная реализация AHEAD — это AHEAD Tool Suite и язык Jak, которые демонстрируют как Принципы Единообразия, так и Масштабируемости. Инструменты следующего поколения включают CIDE [10] и FeatureHouse. [11]
Feature-Oriented Model-Driven Design ( FOMDD ) [5] [6] объединяет идеи AHEAD с Model-Driven Design ( MDD ) (также известной как Model-Driven Architecture ( MDA )). Функции AHEAD фиксируют синхронное обновление программных артефактов при добавлении в программу функции. Но существуют и другие функциональные связи между программными артефактами, которые выражают деривации. Например, связь между грамматикой g f и ее исходным парсером s f определяется инструментом компилятора-компилятора, например, javacc. Аналогично связь между исходным Java s f и его байт-кодом b f определяется компилятором javac. Диаграмма коммутации выражает эти связи. Объекты являются представлениями программы, направленные вниз стрелки являются деривациями, а горизонтальные стрелки являются дельтами. На рисунке справа показана диаграмма коммутации для программы p 3 = i+j+h = [g 3 ,s 3 ,b 3 ].
Фундаментальным свойством коммутирующей диаграммы является то, что все пути между двумя объектами эквивалентны. Например, один из способов вывести байт-код b 3 парсера p 3 (нижний правый объект на рисунке справа) из грамматики g h парсера h (верхний левый объект) — вывести байт-код b h и уточнить до b 3 , в то время как другой способ уточняет g h до g 3 , а затем вывести b 3 , где + представляет собой дельта-композицию, а () — это функция или применение инструмента:
Существуют возможные пути для получения байт-кода b 3 парсера p 3 из грамматики g h парсера h. Каждый путь представляет собой метапрограмму , выполнение которой генерирует целевой объект (b 3 ) из начального объекта (g f ). Существует потенциальная оптимизация: прохождение каждой стрелки коммутирующей диаграммы имеет стоимость. Самый дешевый (т. е. кратчайший) путь между двумя объектами в коммутирующей диаграмме — это геодезический , который представляет собой наиболее эффективную метапрограмму, которая производит целевой объект из заданного объекта.
Диаграммы коммутации важны по крайней мере по двум причинам: (1) существует возможность оптимизации генерации артефактов (например, геодезических) и (2) они определяют различные способы построения целевого объекта из исходного объекта. [5] [12] Путь через диаграмму соответствует цепочке инструментов: для того, чтобы модель FOMDD была последовательной, должно быть доказано (или продемонстрировано посредством тестирования), что все цепочки инструментов, которые сопоставляют один объект с другим, на самом деле дают эквивалентные результаты. Если это не так, то либо в одном или нескольких инструментах есть ошибка, либо модель FOMDD неверна.