Основные представления о генерации кода
Что такое генерация кода?
Генерация кода - это автоматическое создание программного кода специальным приложением, при котором по заданным условиям полностью или частично формируется исходный код программы. Такое специальное приложение называется генератором кода. Получается, что это программа, создающая программный код.
Идея генерации кода не является новой. Например, формирование машинного кода из программы на ассемблере было придумано давно. Компиляторы языков высокого уровня являются, по сути, генераторами низкоуровневого кода. На этапе появления языков высокого уровня под генерацией кода подразумевалась именно генерация машинного кода. Сейчас же все чаще под этим имеют в виду генерацию исходного кода на одном из языков высокого уровня. Именно такая генерация и является темой данного курса. Другим примером генераторов могут служить технологии ASP.Net и PHP. Они генерируют HTML-разметку на основе программного кода. В средах Visual Studio и Delphi генерация кода также используется очень часто.
Технологии реализации генератора
При разработке генератора следует различать язык программирования, на котором реализован генератор и язык программирования, на котором генератор осуществляет вывод автоматически созданного кода. Ясно, что они могут как различаться, так и совпадать. Генератор может быть написан на языке C#, а выводить код на PL/SQL, или наоборот.
Генератор не является частью программного кода проекта, можно даже сказать, что генератор является другим проектом и выполняет другие задачи, отличные от задач проекта. Поэтому технология его реализации необязательно должна совпадать с технологией, применяемой при разработке программного проекта.
В данном курсе мы будем рассматривать примеры, генерирующие программный код на языках C#, PL/SQL, а также запросы SQL. Большинство из примеров написано на языке C#. Разумеется, что генератор можно реализовывать и с применением других технологий. Наиболее оптимальный выбор будет зависеть от условий проекта. При этом будут использоваться другие шаблоны и техники, но принципы генерации останутся теми же.
Ключевые составляющие генерации кода
Как уже отмечалось выше, все повторяющиеся действия могут быть автоматизированы. Генераторы получают на входе информацию о структуре, данных и параметрах предметной области, шаблоны, согласно которым будет выполняться генерация, а на выходе выводят готовый программный код.
При правильном задании условий и параметров, корректной разработке генератора большая часть кода может быть автоматически сгенерирована - программисту остается только вручную доделать оставшуюся часть работы. Для того, чтобы программный код мог быть создан генератором, необходимо наличие следующих трех ключевых компонентов:
- шаблоны программного кода (образцы по которым будет создан код);
- метаданные предметной области (структура, которую мы пытаемся смоделировать в программе);
- правила предметной области (правила, которые определяют структуру и поведение метаданных предметной области, обычно они внедряются в самой программе генератора).
Эти ключевые понятия в том или ином виде содержатся во всех генераторах кода.
Допустим, что есть программа, генерирующая простой запрос SELECT для полей одной таблицы. Метаданными будут названия таблицы и ее полей, шаблон будет содержать ключевые слова SELECT, FROM, WHERE и указывать, в каком месте поставить имена таблицы и полей. Правилами предметной области будут правила построения запроса SELECT, понятия таблицы и полей, а также другие правила из теории баз данных.
Наличие правил предметной области необходимо при реализации любого проекта, даже без применения генерации. Они являются своего рода требованиями, основой, критериями оценки реализуемого проекта. На рис. 1.2 представлена схема отношения предметной области к создаваемому коду.
Разумеется, на этом рисунке все рассматривается только по отношению к коду. Такие этапы реализации приложения, как проектирование, документирование, тестирование и другие, опускаются. Программный код является своеобразным отражением предметной области, реального мира.
При автоматической же генерации схему можно представить в следующем виде:
Правила предметной области определяют, какими будут шаблоны, метаданные и генератор. Генератор же на основе метаданных и шаблонов строит автоматически сгенерированный код.
Условия эффективного применения генераторов
Генераторы лучше всего применимы в проблемной области, требующей выполнения множества коротких, схожих итераций. Хорошими кандидатами являются базы данных, где один и тот же шаблон проектирования применяется много-много раз к множеству таблиц базы данных. Структура каждой таблицы может быть уникальной, но правила и условия, применяемые к полям таблицы при разработке кода почти одинаковы. В таких случаях гораздо быстрее можно создать генератор и получить за короткое время большой объем кода, чем выполнять разработку вручную.
Области применения
Потенциально может применяться в любом случае, в котором есть возможность автоматизировать процесс создания электронной информации. Практически наиболее применимыми областями являются:
- приложения баз данных (объекты бизнес логики, поддержка транзакций);
- SQL запросы (DDL и DML);
- приложения, взаимодействующие с базами данных, использующие их для ввода-вывода данных;
- классы и структуры объектно-ориентированных языков программирования;
- тестирование программного кода;
- техническая документация на программу.
Кроме описанных выше случаев генерация кода может применяться для автоматического создания разного рода скриптов, конфигурационных, командных файлов, макросов и т.д. Хорошими кандидатами являются любого рода манипуляции с данными, например работа с файлами, конвертирование форматов и др.
Преимущества применения генерации
Применение генерации в разработке программного кода проекта дает следующие преимущества:
- структурированность и согласованность исходного кода приложения (сгенерированного машиной). Генератор позволяет с точностью до символа соблюдать правила написания кода, применяемые в организации. Программисты перенимают чистый и структурированный стиль сгенерированного кода, то есть учатся у генератора хорошему оформлению программы;
- согласованность на уровне архитектуры приложения. Применение генератора дает уверенность в том, что создаваемый код соответствует изначально спроектированной структуре приложения и шаблонам. Если какую-то функциональность не получается реализовать с помощью генератора, это служит сигналом к тому, что она не соответствует изначальной архитектуре;
- высокое качество кода и облегченное исправление ошибок. Программа стабильна и свободна от ошибок (предполагается, что подавляющая часть ошибок исправлена уже на этапе отладки самого генератора). Если же все-таки имеются ошибки, то их поиск и исправление можно вести как на более абстрактном уровне шаблонов, так и в сгенерированном коде;
- гибкость к изменениям. Если требования поменяются, можно только обновить шаблоны, генератор и/или метаданные и сделать массированный вывод новой версии кода. Есть возможность относительно легко и безболезненно переходить на другие платформы и технологии; Сводятся к минимуму ошибки, возникающие из-за человеческого фактора, например, опечатки;
- скорость разработки. Если метаданные уже определены и введены, то генерация огромного объема кода может производиться за невероятно короткое время - буквально за секунды;
- единый источник информации о приложении. В приложениях, которые пишутся вручную, простое изменение имени таблицы или столбца может повлечь за собой серию изменений во многих участках кода. При генерации же метаданные находятся в отдельном источнике и поэтому достаточно изменить название таблицы или столбца в том месте, где определяется схема, и пересоздать код;
- наглядность бизнес логики. В приложениях, которые пишутся вручную, смысл бизнес логики теряется в сотнях и тысячах строк программного кода. Генераторы же используют файлы метаданных, в которых видна вся структура программируемой предметной области, её поведение, исключения и т.д. Гораздо легче понять, что делает приложение на высоком уровне абстракции. Метаданные могут использовать эксперты в предметной области приложения;
- усовершенствованный процесс разработки кода. Теперь появляется возможность больше времени уделять проектированию приложения, так как процесс создания кода будет занимать меньше времени. Уменьшается срок выполнения проекта, повышается удобство сопровождения проекта. Также с помощью генератора можно быстро изготавливать множество прототипов кода, анализируя и тестируя которые можно избегать ситуаций, когда ошибка допущена на этапе проектирования, а выявлена была уже в процессе разработки;
- программисты концентрируются на более интеллектуальных областях разработки. Что позволяет лучше использовать их профессиональные навыки, быстрее повышать квалификацию;
- улучшение удобства работы программистов. Код становится намного чище и проще, так как генерируется только то, что требуется сейчас;
- улучшение мотивации и интереса к работе у программистов. Все вышеперечисленное делает работу разработчика более интересной, насыщенной и продуктивной, что не может не сказываться положительно на мотивации, а это является очень важным фактором, влияющим на успех проекта.
Иными словами, генератор позволяет разработчикам концентрировать больше внимания на интеллектуальной части работы, а не на рутинной.
Недостатки применения генераторов кода
Однако имеются также минусы и ограничения в применении генерации кода:
- Применение генератора может быть эффективно не во всех случаях. Если в проекте мало повторяющегося кода, объем проекта недостаточно большой, если код сложно поддается генерации, может оказаться, что легче написать приложение вручную.
- Практически всегда присутствует часть кода, которую нужно создать вручную. Объем такого кода может быть различным на разных проектах. В основном это уникальные, единожды встречающиеся в приложении шаблоны кода, которые нет смысла генерировать. Их проще написать один раз вручную. Например, это может быть модуль авторизации пользователя или библиотека функций.
- Возникает необходимость сопровождения генератора. Если генератор разрабатывался не только для изначального создания кода, а также для применения на протяжении всего жизненного цикла приложения, то это значит, что параллельно с сопровождением и развитием приложения надо будет сопровождать и развивать и сам генератор. Если это приобретенный у поставщика генератор, то сделать это будет очень сложно, либо невозможно.
- Необходимо обучать применению генераторов. При внедрении генератора, а также в ходе эксплуатации после каждого его изменения надо обучать всех имеющих непосредственное отношение к генератору особенностям его применения. Также это надо делать для новоприбывших сотрудников.
Характеристики генераторов кода
В зависимости от того, каким образом организованы входные и выходные данные, масштабности выводимого кода, а также того, каким образом обслуживается впоследствии этот код, могут отличаться характеристики генераторов. Приводимые здесь характеристики являются в большей степени относительными, призванными облегчить понимание разницы между большим количеством разнообразных генераторов, и не являются предметом строгой классификации. Давайте рассмотрим эти характеристики.
Методы генерации:
- с применением шаблонов. В этом случае повторяющийся код хранится в шаблонах. Они также хранят инструкции или программный код для встраивания определенным способом метаданных в шаблон. Примерами являются технологии XSLT и T4, которые мы рассмотрим в нашем курсе;
- прямой подстановкой текста. Генерируемый код представляется в виде набора строк, который формируется после манипуляций текстом, результат выводится в текстовый файл. Этот метод является самым простым и интуитивно понятным для программиста. При применении этого метода шаблоны существуют, но они запрограммированы в коде генератора;
- объектным моделированием. Элементы программного кода моделируются в генераторе программными объектами. Примером является технология CodeDom. Такие понятия как классы, типы, объекты, переменные, выражения и т.д. в ней представлены классами из пространства имен CodeDom. Манипулируя объектами этих классов можно создавать программный код.
Осуществляемые действия:
- генерация с нуля. Код генерируется из шаблонов и метаданных, предварительно созданного кода не существует;
- модификация. Каким-либо образом изменяется уже существующий код, например, добавляется параметр в определенные части кода, добавляются комментарии. В этом случае первоначальный код играет роль шаблона, а также может содержать метаданные.
Где хранятся шаблоны:
- в коде генератора (шаблоны могут быть представлены в виде функций, процедур, блоков кода);
- в отдельном источнике (чаще всего в файлах шаблонов).
Где хранятся и откуда извлекаются метаданные:
- специализированные файлы с иерархической структурой, например XML-файлы;
- файлы языков проектирования вроде UML, DSL;
- другие файловые источники вроде Excel, Visio, текстовые файлы;
- базы данных;
- другие приложения или веб-сервисы;
- данные вводятся пользователем через интерфейс приложения;
- код генератора - значения метаданных присваиваются переменным в самом коде (такое может быть в случае, когда требуется сгенерировать код только один раз).
Где хранятся правила предметной области:
- в основном отражаются в коде генератора, шаблонах, метаданных;
- могут также дополнительно храниться в отдельных источниках (настроечные файлы, UML диаграммы, базы данных).
Способ ввода исходных данных:
Шаблоны и метаданные вводятся из разных источников - в отдельном источнике хранятся шаблоны кода, а в отдельном источнике хранятся метаданные.
Шаблоны и метаданные вводятся из одного источника - например, это может быть программный код с комментариями. Код приложения представляет собой шаблон, а в комментариях в специальном формате содержатся метаданные.
Универсальный генератор - шаблоны, метаданные и правила предметной области находятся в разных источниках. Это сложный вид генератора и очень гибкий. Может быть малоприменим на практике.
Данные не вводятся - вся информация для генерации находится в самом коде генератора. Этот другой крайний случай хорошо годится для одноразовых работ, когда схожая разработка в будущем не предвидится. При этом не тратится время на разработку пользовательского интерфейса, ввода-вывода данных.
Способ вывода результата:
Запись результата в новой локации - входные данные берутся из одного источника, генерируется код и результат записывается в другую локацию. В большинстве случаев применяется эта техника.
Замена результатом входного источника - входные данные берутся из одного источника, генерируется код и результат перезаписывается в этот же источник. Этим способом видоизменяется существующий код. Данная техника может быть полезна в относительно небольшом числе случаев. Например, в случае добавления обработки параметра во все файлы проекта. Желательно, чтобы генератор сохранял резервные копии изменяемого кода.
Завершенность кода:
Незавершенный - сгенерированный код нуждается в дальнейшей ручной модификации. Часто это является показателем того, что генератор недоработанный, сырой, либо код плохо поддается генерации.
Завершенный - сгенерированный код не нуждается в модификации и его можно выложить в производственную схему. Это не означает, что программный проект не содержит вручную созданного кода, просто сгенерированный код интегрируется без изменений с вручную созданным кодом.
Масштаб генерации:
Отдельные участки кода приложения - применяется, когда есть необходимость немного поменять код приложения, который на данный момент не обслуживается генератором.
Определенный модуль или группа файлов - может применяться при первоначальном пробном тестировании работы генератора.
Уровень в архитектуре приложения - генерируется только один уровень в архитектуре приложения. Очень часто это уровень базы данных, так он легче всего поддается генерации и от него зависит работа всех остальных уровней. Генерация других уровней без уровня базы данных потеряет много в своей эффективности.
Все уровни в архитектуре приложения - на каждом уровне приложения применяется сгенерированный код. Применяется, когда выработаны шаблоны, позволяющие сгенерировать большую часть приложения.
Языковая техника - при таком масштабе применения генератора выработано достаточное количество шаблонов достаточного качества, чтобы покрывать основные возможности языка или технологии.
Кем разработан генератор:
Внутри организации - компания сама является владельцем генератора и абсолютно свободно может распоряжаться ею.
Приобретен у поставщика - генератор не находится под контролем организации, трудно или невозможно будет влиять на ход его развития.
Доступ к исходному коду:
Есть доступ - генератор разработан самостоятельно или используется генератор с открытым исходным кодом.
Нет доступа - генератор разработан вне организации и доступ к исходному коду закрыт.
Краткие итоги
Генератор кода - это программа, автоматически создающая исходный код приложения. Генератор не является частью программного кода проекта. Он является другим проектом и выполняет другие задачи. Поэтому технология его реализации необязательно должна совпадать с технологией, применяемой при разработке программного проекта.
Для генерации кода должны быть определены метаданные, шаблоны и правила предметной области. Правила предметной области определяют, какими будут шаблоны, метаданные и генератор. Генератор же на основе метаданных и шаблонов строит автоматически сгенерированный код.
Генераторы лучше всего применимы в проблемной области, требующей выполнения множества коротких, схожих итераций. Областями применения являются приложения баз данных, код доступа к базам данных, SQL запросы, классы и структуры объектно-ориентированных языков программирования, тестирование программного кода, техническая документация на сгенерированный код.
Преимущества: структурированность и согласованность исходного кода и архитектуры приложения, удобство и улучшение эффективности работы программистов, высокое качество кода и облегченное исправление ошибок, высокая скорость разработки, гибкость к изменениям, наличие единого источника информации о приложении, наглядность бизнес логики, усовершенствованный процесс разработки кода, а также улучшение мотивации разработчиков.
Недостатки: генерация не во всех случаях может быть эффективной, всегда присутствует код, который надо разработать вручную, необходимость сопровождения не только приложения, но и самого генератора, необходимость уделять много внимания обучению работе с генератором.
Генераторы обладают такими характеристиками как способ ввода метаданных, шаблонов, правил предметной области, вывода сгенерированного кода, метод и масштаб генерации, завершенность сгенерированного кода, наличие доступа к исходному коду.
Заключение
Технология генерации кода является эффективной и мощной техникой с потенциально безграничными возможностями. Целью данного курса является демонстрация того, что разработка программ, создающих другие программы, в большинстве практических случаев не является чем-то сверхсложным. В курсе мы рассмотрим примеры генераторов, начинать будем с самых простых примеров, заканчивать более сложными. Также необходимо отметить, что генератор кода не является волшебной палочкой, решающей все проблемы. Если допущены ошибки на этапе проектирования, или идея проекта, скажем так, не самая лучшая, то никакой генератор не может гарантировать успех проекта. Генератор кода - это инструмент, а грамотное применение инструмента - задача того, кто им пользуется.
В данной лекции мы рассмотрели общую информацию, касающуюся генераторов. В следующей лекции мы рассмотрим этапы построения генераторов и практические примеры генераторов с разнообразными характеристиками, а также сгенерированный ими код.