Введение в многоэтапное метапрограммирование и метаязыковую абстракцию
Перевод Introduction to Staged Metaprogramming and Metalinguistic Abstraction, Vladimir Ivanov, May 2008.
Данная статья — начало серии статей о метапрограммировании (metaprogramming). Статья представляет вашему вниманию две техники: многоэтапное метапрограммирование (staged metaprogramming) и метаязыковую абстракцию (metalinguistic abstraction). В статье обсуждаются мифы о метапрограммировании, раскрываются некоторые принципы метаязыковой абстракции и многоэтапного метапрограммирования.
1. Что такое метапрограммирование?
В соответствии с определением в Википедии, метапрограммирование — это написание компьютерных программ, которые конструируют другие программы или манипулируют ими как данными... В множестве случаев, это позволяет программистом сделать намного больше работы за единицу времени по сравнению с написанием кода вручную.
Метапрограммирование не является «серебряной пулей», однако оно известно как техника, позволяющая значительно повысить продуктивность программиста. Вероятнее всего, вы не пишете машинный код вручную. Вместо этого вы используете наиболее подходящий высокоуровневый язык программирования _____ (вставьте название).
Компилятор или интерпретатор вашего любимого языка — ярчайший пример метапрограммирования, которое действительно повышает вашу продуктивность. Более того, я полагаю, что метапрограммирование — единственный известный путь значительного увеличения продуктивности путём уменьшения сложности[1].
2. Метапрограммирование и индустрия разработки ПО
Почему метапрограммирование сейчас не в «мейнстриме»? Я попытался задать этот вопрос моим коллегам и получил следующие ответы:
- «Метапрограммирование — это только для ГУРУ».
- «Для этого необходимо писать парсеры/компиляторы/интепретаторы/трансляторы/и т. п. — а это всё очень сложно».
- «Программы, генерирующие другие программы, очень тяжело понимать и отлаживать».
- «Метапрограммирование — большинство людей просто не знают что это такое... Это и причина и следствие одновременно».
- «Множесто людей думают, что метапрограммирование означает использование шаблонов C++».
- «Очень сложно найти людей, умеющих это делать. Куда более практичнее нанять сотню индийцев и решать задачу традиционным путём».
- «Метапрограммирование пригодно исключительно для больших проектов/систем/проблем».
- «Это же глупо (и ужасно) создавать и учить сотни языков программирования».
- «Реклама больших компаний заставляет людей использовать другие методы».
- «Нехватка инструментов. Нехватка теории».
Некоторые из вышеприведенных утверждений — истинны. Однако некоторые — лишь широко распространённый миф. Одна из целей этой серии статей — систематизировать и представить публике материал, который покажет, что:
- Метапрограммирование может быть простым. Оно может быть доступным не только для ГУРУ.
- Метапрограммирование может быть эффективно использовано для предметных областей различного масштаба и задач разной сложности.
- Метапрограммирование приходит в «мейнстрим» прямо сейчас, вместе с ростом сложности решаемых задач.
3. Метаязыковая абстракция
Метаязыковая абстракция — это процесс решения сложных задач путём создания нового языка или создания словаря с целью лучшего понимания предметной области. Такие языки в настоящее время называют языками предметной области (DSL — Domain Specific Languages). В то время как DSL — термин относительно новый, метаязыковая абстракция — старый и хорошо известный путь решения задач[2].
Метаязыковая абстракция предполагает использование языка в качестве основного инструмента абстракции, точно так же, как процедурный подход оперирует процедурами, ООП — классами, АОП — аспектами.
Алгоритм решения задач, с использованием этого подхода, может выглядеть так:
- Опишите решение вашей задачи, используя высокоуровневый DSL.
- Выберите целевую платформу. Это может быть любая платформа, выбранная вами, или же та, которая требуется напрямую (примеры: другой DSL, машинные коды, язык программирования общего назначения).
- Если ваш DSL легко и естественно может быть преобразован в примитивы выбранной платформы — сделайте это (напишите процедуру преобразования). Готово.
- Замените исходную задачу другой (более простой) задачей: сделать ваш DSL запускаемым на целевой платформе. Идите на п. 1
В простых случаях языки могут наслаиваться друг на друга. В более сложных случаях они могут образовывать иерархию.
Какие преимущества даёт принцип метаязыковой абстракции?
- Программы могут быть более читабельными, их легко сопровождать, если они пишутся с использованием языка близкого к требованиям.
- Возможность следования правилу DRY (Do Not Repeat Yourself) — не повторяйся!
- Решения имеют тенденцию быть более готовыми к радикальным и непредсказуемым изменениям требований.
Почему последнее утверждение может быть правдой? Функциональные требования, по большей части, привязаны к высокоуровневым слоям металингвистической абстракции. Они «закодированы» в платформенно-независимой и близкой к предметной области форме. Нефункциональные требования склонны быть привязанными к низким слоям металингвистической абстракции. Даже непредсказуемое требование портирования программы на экзотическую платформу может быть исполнено путём замены низких уровней абстракции, без переписывания или влияния на верхние.
4. Действительно ли метапрограммирование сложно?
Любая простая задача может быть решена сложным путём при использовании любой техники. Метапрограммирование — не исключение. Просто не стоит идти этим путём.
Если вы хотите обречь себя на провал в метапрограммировании, воспользуйтесь следующими советами:
- Изобретите ещё один язык программирования общего назначения, решая задачу управления кофейным автоматом.
- Придумайте экзотический синтаксис для ваших языков, который вам потом будет сложно парсить.
- Выберите инструменты/языки/фреймворки, которые не позволяют легко манипулировать/преобразовывать AST.
- Выберите инструменты/языки/фреймворки, которые требуют 5+ лет опыта работы, прежде чем программист может начать делать что-либо серьёзное.
Во избежание создания переусложнённых решений, целесообразно следующее:
- Пусть ваш DSL будет простым, насколько это вообще возможно.
- Думайте о вашем DSL в терминах его AST и держите его синтаксис как можно ближе к AST. Это поможет вам избежать написания парсеров и отладчиков.
- Выбирайте простые, легкие в изучении инструменты и языки (или подмножества языков) для того, чтобы обеспечить возможность быстрого присоединения новых людей к проектной команде.
- Выберите один из «программируемых языков программирования». То есть, расширяемый язык программирования, напрямую поддерживающий гомогенное метапрограммирование (homogeneous metaprogramming[3]).
Должны ли мы минимизировать количество слоёв метаязыковой абстракции с целью уменьшения сложности? Если ваш ответ — «да», рассмотрите следующую аналогию: должны ли мы минимизировать количество функций при использовании функциональной декомпозиции или количество классов при ООП с целью упрощения? Конечно же, ответ — «нет». Мы можем извлечь преимущество из хорошо структурированного (fine-grained) дизайна с тонкими, простыми, хорошо изолированными слоями абстракций. Но, разумеется, сложность поддержки не должна расти экспоненциально с увеличением количества языков. К примеру, при процедурном подходе, языки программирования позволяют легко разделять процедуры на части, когда требуется.
Продолжение следует...
61 коментар
Підписатись на коментаріВідписатись від коментарів Коментарі можуть залишати тільки користувачі з підтвердженими акаунтами.