Введение в генерацию программного кода

Организация процесса разработки и применения генераторов

Показывать лекцию целиком

В предыдущих лекциях мы рассмотрели концепцию генерации кода, ее преимущества и недостатки, были показаны примеры. Изучены технологии генерации, такие как CodeDom, T4. Также была рассмотрена технология XSLT. Она хоть и не создана специально для генерации кода, но очень эффективно ей подходит. Одна лекция была связана с генерацией уровня баз данных – это лекция про генерацию запросов SQL; в приложении А рассмотрена генерация пакетов PL/SQL. Была приведена информация по другим применениям генерации кода: для выполнения тестирования, формирования документации, разработки пользовательского интерфейса, работы с данными. В данной заключительной лекции мы рассмотрим очень важную тему: организацию процесса разработки и сопровождения генератора кода.

С чего начать?

С чего начать применение генерации кода? С технологической точки зрения, при отсутствии опыта желательно выполнять манипуляции текстом. Этот простой способ не потребует изучения и овладения специфическими технологиями генерации кода. Для разработки генератора вполне хватит знаний и опыта, достаточных для разработки проекта вручную. Какое содержимое лучше генерировать? Для начала лучше генерировать не все приложение, а только ту его часть, которая легко поддается генерации. Обкатка техник генерации на небольшом участке кода приложения позволит быстрее ввести генератор в действие, осознать его преимущества, избежать ошибок на ранней стадии проекта. Риск и потери времени в случае неудачи будут минимальными. Выбирайте ту часть приложения, которая имеет наибольшую повторяемость участков кода. Например, уровень базы данных. Когда убедитесь в эффективности применения генераторов для вашего проекта и найдете пути ее достижения, вы можете расширить области применения генератора.

Начинать применение генерации кода можно также на небольших одноразовых работах рутинного характера. Хорошими кандидатами на применение генерации являются проведение рефакторинга, изменение форматирования, оптимизация кода. При исполнении этих задач могут выполняться относительно простые изменения кода, но которые присутствуют в большом количестве и серьезно влияют на качество приложения. В случаях переименования переменных, изменения стандартной функциональности в большом количестве модулей, изменения структуры кода и других подобных действий ручное обновление будет долгим и рутинным по сравнению с реализацией генерации. Нужно только создать небольшой генератор, который преобразует стандартный существующий код в стандартный код в новом формате.

Оценка целесообразности применения генератора

Теперь рассмотрим случаи, когда можно точно сказать, что генерация кода даст преимущества и наоборот, когда генерация будет точно неэффективна. Также рассмотрим методы оценки эффективности применения генератора в тех случаях, когда заранее сложно определить целесообразность его применения.

Наличие большого объема устойчивых шаблонов, хорошая стандартизированность стиля кода свидетельствует о том, что приложение является хорошим кандидатом на генерацию. Практически всегда выгодно генерировать код баз данных, код манипуляции данными, или любой другой зависящий от них код. Перечислим вкратце условия и конкретные случаи, когда применять генератор выгодно:

  • манипуляции с данными и форматами;
  • базы данных;
  • код, содержащий обращения к базам данных;
  • хорошо стандартизированный код;
  • большой объем повторяющегося кода.
  • С уверенностью можно сказать, что применение генератора не дает преимуществ в следующих случаях:

  • малый объем разрабатываемого кода. Если в обозримом будущем не собираетесь создавать похожее приложение, то проще разработать программу вручную, чем тратить время на проектирование, разработку и внедрение генератора;
  • при разработке уникального и нигде не повторяющегося кода.
  • При оценке повторяемости хорошо также взвешивать повторяемость кода не только внутри приложений, но и внутри целой группы приложений, которыми вы возможно занимаетесь. Даже если какая-то функциональность не повторяется в границах одного приложения, она может встречаться в других приложениях. В этом случае разработанный генератор и шаблоны можно полностью или частично применять для генерации других приложений.

    Во всех остальных случаях взвешивать за и против, оценивать и сравнивать надо:

  • время на ручную разработку кода, документирование, тестирование;
  • время на разработку генератора, создание шаблонов и введение метаданных;
  • выгоды от генерации в виде согласованности, безошибочности и т.д.;
  • затраты ресурсов на сопровождение генератора.
  • Все вышеперечисленное надо взвесить и принять решение о применении генератора.

    Возникающие предубеждения против применения генераторов

    В силу специфики генерации кода возникают самые разные толкования и убеждения, которые являются либо ложными, либо не совсем верными. Также они возникают из-за того, что генерация кода не так часто используется при реализации программных проектов и у разработчиков мало практического опыта в этой области. Понимание и работа с предвзятыми мнениями является важным для правильной организации работы, обучения и настроя разработчиков. Итак, перечислим и рассмотрим наиболее часто возникающие предубеждения.

    Генератор оставит программистов без работы. Нужно понимать, что генератор не отменяет программирование вообще, он только устраняет необходимость проведения рутинной работы по созданию многочисленных похожих блоков кода. Время программиста освобождается для выполнения более уникальных и интересных задач. Разработка и усовершенствование самого генератора также является нетривиальной и интересной задачей. В любых приложениях всегда есть много областей приложения сил для дальнейшего усовершенствования, оптимизации и расширения. И даже при применении генератора здесь останется много работы по развитию и улучшению приложения. Освободившиеся временные ресурсы следует использовать как раз для этой цели.

    Сгенерированный код плохо поддается контролю. Могут возникать опасения, что сгенерированный код будет малопонятным кодом громадного объема, который создается за секунды и поведение которого непредсказуемо. Следует отметить, что подобные соображения могут появиться только тогда, когда разработчик плохо представляет, какой код ему нужен и по каким шаблонам создается сгенерированный код и насколько они соответствуют друг другу. В сгенерированном коде разработчик должен разбираться так, как будто он сам написал его вручную. Понимание кода должно быть на таком же уровне, а генератор только устраняет необходимость создавать его вручную. Фактически, генератор создает тот же код, который разработчику пришлось бы написать вручную, только теперь это делается быстрее и эффективнее. Насчет непредсказуемости поведения можно сказать, что для исключения подобной ситуации генератор можно использовать еще и для тестирования. Сам генератор тоже должен быть тщательно протестирован. При таком подходе подобные опасения становятся необоснованными.

    В работе генератора полностью разбирается только его разработчик. Когда генератор разрабатывается одним человеком, то возникают справедливые опасения, что стоит ему покинуть группу, как генератор перестанет использоваться. Чтобы этого не происходило нужно уделять достаточно внимания качественному обучению (все заинтересованные лица должны свободно разбираться в работе генератора) и более интенсивному внедрению генерации в процесс разработки.

    Требования к приложению и его архитектура определены не до конца. Тот факт, что структура приложения еще не определена и требования окончательно не выработаны, может служить контр-мотивацией к началу разработки генератора. В результате пройдет много времени пока структура приложения станет более ясной, и создание генератора начнется запоздало. Такой подход не является продуктивным. Разработку генератора нужно выполнять, даже если архитектура проекта не является законченной, использовать для этого информацию, известную на данный момент. Это позволит увидеть и опробовать предварительный вариант кода проекта уже на ранней стадии и избежать ошибок проектирования, добавит доверия к генератору. Когда информации о приложении станет больше, достаточно будет изменить генератор и шаблоны.

    Код приложения слишком сложен или велик для того, чтобы его можно было сгенерировать. Даже в случае очень сложных приложений практически всегда присутствует часть кода, в которой содержится стандартная функциональность. Стандартизация и разбиение кода на уровни позволяет упростить отдельные компоненты приложения и повысить удобство их генерации. К тому же в большинстве приложений используются базы данных, которые являются идеальными кандидатами на генерацию. И даже если базы данных не используются (что бывает редко), все равно могут применяться другие структуры для хранения, ввода-вывода данных. Подобные структуры также хорошо поддаются генерации.

    Сгенерированные запросы SQL будут неэффективными. Эффективность запросов может быть повышена за счет денормализации базы или использования материальных представлений. Сгенерированные сложные представления могут по эффективности быть приближены к написанным вручную. Полезно ввести возможность замены сгенерированного запроса на запрос, созданный вручную. В таком случае сгенерированный запрос может быть заменен на более эффективный. Можно даже не генерировать запросы SQL, а просто иметь возможность указывать в метаданных уже готовый запрос, который будет подставляться в сгенерированный код. Тем не менее, большинство запросов эффективно генерируются автоматически.

    Усилия, затраченные на разработку генератора, могут оказаться непомерно большими. Чем больше и масштабнее проект, тем больше выгод для него дает генерация кода, особенно на начальном этапе. Для небольших же проектов разработка генератора действительно может дать меньше эффекта вследствие меньшего объема генерируемого кода. Однако даже в этом случае есть факторы, которые могут перевесить данное обстоятельство. Затраты времени не являются единственным, хотя и очень важным показателем для принятия решения о применении генератора. Другими факторами являются значительно улучшенная согласованность кода, его качество и уровень абстракции. Кроме того, созданный генератор небольшого проекта можно использовать также на других похожих небольших проектах. Хоть на разработку генератора первого проекта уйдет немало времени и выигрыш в затраченных усилиях будет небольшой, для последующих же проектов он будет весьма значительным, так как потребуется только немного изменить генератор и большая часть кода будет готова.

    Не хватает навыков для разработки и применения генератора. Могут возникать опасения, что разработка генератора окажется сложным делом и потребует специальные навыки и знания. Фактически же потребуется следующее:

  • опыт программирования на языке реализации генератора;
  • хорошее знание целевого языка(ов) и технологий, на котором будет генерироваться код;
  • хорошее владение инструментами ввода-вывода данных, таких как потоковый вывод в файл, знание XML, базы данных;
  • опыт тестирования приложений.
  • Как видим, эти знания и навыки в любом случае требуются программисту, внедряющему проект. Также могут помочь, но не являются обязательными, технологии вроде T4 и XSLT, очень редко CodeDom. С точки зрения самого процесса генерации нужно представлять себе, какой в результате нужен код. Разумеется, надо уметь генерировать код манипуляцией текстом. Отсюда следует, что для применения генерации никаких сверхъестественных навыков не требуется.

    Управление ручным кодом

    Даже в самом благоприятном случае применения генератора всегда будет существовать часть кода, которая написана вручную. Это может быть библиотека функций, реализация какого-нибудь специального алгоритма, или например, модуль безопасности приложения. Особенно это касается тех приложений, архитектура которых имеет сложную структуру и большое число нюансов и деталей.

    Если для таких приложений стараться использовать только автоматическую генерацию, то потребуется создание новых шаблонов для каждого особенного случая в приложении. Такое занятие будет крайне неэффективным с точки зрения затрат времени. Гораздо проще каждый уникальный неповторяющийся код написать вручную.

    Наличие в системе как ручного, так и автоматически сгенерированного кода порождает необходимость согласования их взаимодействия, а также различения их друг от друга в процессе разработки и обновления существующего кода.

    Одной из главнейших задач при этом является обеспечение невозможности замены актуального ручного кода устаревшим сгенерированным. Другой задачей является сведение к минимуму ситуаций, когда сгенерированный код заменяется ручным. Такие ситуации становятся возможными, когда сгенерированный код модифицируется вручную и осуществляется плохой контроль и разделение ручного и сгенерированного кода. Если впоследствии код генерируется заново и сохраняется, то ручные модификации могут быть утеряны. Это создает необходимость:

  • Обеспечения раздельного хранения ручного и сгенерированного кода (в разных объектах, файлах и т.д.) для существенного облегчения контроля за ручным и автоматическим кодом. Таким образом минимизируется риск потери изменений.
  • Установки уведомлений в сгенерированном коде о том, что это автоматический код и не должен быть модифицирован вручную. Нужно проинформировать, что если это будет сделано, то при повторной генерации кода изменения могут быть утеряны.
  • Создания системы контроля над хранением и изменением ручного и сгенерированного кода. Нужно решить, какая часть кода приложения будет генерироваться, а какая должна будет создана вручную. Ручной код может постепенно замещаться сгенерированным кодом (по мере подготовки шаблонов). Это подразумевает, что какая-то часть кода уже разработана вручную и есть возможность создавать на ее основе шаблоны и генерировать похожий код.
  • Необходимо понимать, что плохой контроль и отсутствие четкого разделения ручного и автоматически сгенерированного кода могут привести к крайне нежелательным последствиям.

    Потери ручного кода могут возникать также при переводе старого ручного кода на автоматический. Может оказаться, что не все возможности старого кода были внедрены в автоматический, либо это было сделано некорректно. Одним словом, необходимо создать систему контроля и тестирования кода.

    Рассмотрим основные способы разделения ручного и сгенерированного кода:

  • Наследование классов. Позволяет разделить ручной и сгенерированный код в разных классах и разных файлах;
  • Частичные классы. Позволяют реализовывать один класс в нескольких файлах;
  • Регионы. Можно выкладывать сгенерированный код внутри сворачиваемых блоков кода. Например, использовать директиву #region в C#;
  • Заменяемые элементы. В хранимых процедурах можно выделять отдельные секции, куда записывается сгенерированный код. Либо автоматический код будет храниться в отдельных процедурах. Правила именования процедур должны учитывать разницу в автоматическом и ручном коде;
  • Комментарии. Содержат информацию об автоматическом или ручном способе формирования кода. От предыдущего способа отличается тем, что секции сгенерированного кода отделяются не именованными блоками, а комментариями. Включаются предупреждения в виде комментариев о том, что код сгенерирован и ручная модификация запрещена. Секции кода, разработанные вручную, тоже могут содержать комментарии о запрете его замены автоматически сгенерированным. Генератор при обнаружении этих комментариев не будет заменять код.
  • Обучение пользователей

    Если генератор закуплен у стороннего поставщика или будет применяться не самим разработчиком, а другими специалистами, то их обучению следует уделить особое внимание. Ведь настройка созданного сторонним производителем генератора для целей вашего проекта может потребовать немало усилий. Без обучения в такой специфической области, как генерация кода высока вероятность, что разработчики будут испытывать трудности технического, а руководители организационного характера. Целью обучения является доведение до пользователей генератора следующей информации:

  • Возможности генератора кода. Что и как может делать генератор.
  • Ограничения при применении генератора. Информация о том, чего не следует ждать от него.
  • Преимущества применения генерации кода. Возможные недостатки.
  • Архитектура генератора. Дать представление о том, как работают метаданные, о правилах предметной области, о шаблонах в данном конкретном генераторе. Дать информацию об используемой технологии генерации кода.
  • Процесс подготовки и запуска генерации. Объяснить и показать как идет процесс генерации. Как заполняются метаданные, создаются и изменяются шаблоны, как запускается генератор, как с ним работать. Какая используется схема взаимодействия ручного и сгенерированного кода. Как работает сгенерированный код и как управлять им.
  • Показать возможности дальнейшего усовершенствования генератора. Здесь главное не переусердствовать и быть реалистичным, давать только ту информацию, которая в конкретные сроки практически может быть реализована.
  • Необходимо ознакомить с документацией генератора и инструкциями пользователя.
  • Предубеждения против применения генераторов. Надо рассказать, какие предубеждения могут возникать касательно применения генераторов, почему не все из них верны, как преодолеть другие. Это нужно сделать обязательно.
  • Обучение проводится в виде семинаров, тренингов, бесед, составления и раздачи учебных материалов.

    Обучение поможет лучше понять генерацию кода и избежать искаженных оценок ее применения. Например, может встречаться скептическое отношение к ней. Либо от нее ожидают выполнение функций, которые имеют мало общего с реальностью. В результате это может привести к ошибкам и разочарованию. Вообще, при применении генератора могут возникать интересные и неоднозначные мнения с широким разбросом. Ее могут воспринимать как полезный дополнительный инструмент, не влияющий существенно на процесс разработки. Часто встречается мнение, что легче разработать код самому, чем тратить время на изучение генерации. Может возникать отношение к генератору как к удачной находке, воспользовавшись которой можно затратить освободившееся время на свои личные дела и о которой руководство не должно ненароком узнать.

    По этим причинам хорошее обучение и равноценное вовлечение как можно большего числа программистов в разработку и использование генератора является очень важным.

    Простота в использовании

    Если генератор неудобно использовать, устанавливать, настраивать, либо он работает ненадежно, это будет серьезным препятствием к тому, что генератор вообще будет применяться. Особенно это касается добавления и изменения метаданных и шаблонов. Нет смысла в избавлении от рутинной работы путем применения генератора, если это впоследствии оборачивается затрудненной и проблематичной настройкой самого генератора. Даже если такой генератор дает выигрыш во времени, недоверие к его работе может привести к прекращению его использования. Тот факт, что генератор кода применяется преимущественно программистом, не значит, что необязательно уделять много внимания удобству, простоте применения и восприятия работы генератора. Наоборот, удобный интерфейс увеличит эффективность работы программиста. А это не может не сказаться положительно на проекте. С точки зрения практического применения генератор должен обладать следующими свойствами:

  • простота использования,
  • удобство пользовательского интерфейса,
  • надежность установки и работы.
  • Генератор должен подсказывать инженеру, что было сделано, какой код был создан или изменен. Обязательно должны поддерживаться настройки по умолчанию, что существенно облегчит ввод метаданных. Крайне желательно создать удобный графический интерфейс.

    Генерация одним нажатием клавиши

    Хорошей практикой при генерации кода является организация шаблонов в единую систему и передачу метаданных таким образом, чтобы код генерировался одним нажатием клавиши или одной командой. Для создания такого процесса необходимо:

  • применять вложенные иерархические шаблоны,
  • разработать скрипт для последовательного применения шаблонов ко всем метаданным.
  • Вложенные шаблоны удобно применять, так как становится возможным вызывать одни шаблоны из других. Эти шаблоны-потомки могут применяться также внутри других больших шаблонов. Если возникнет необходимость сделать одинаковые изменения в нескольких похожих шаблонах, достаточно идентичные места в них сделать вложенным шаблоном и делать изменения только в нем.

    Программным путем можно пройтись в цикле по всем метаданным и применить соответствующие шаблоны. Это позволит сэкономить существенное количество времени по сравнению с одиночным применением шаблона (генерирующим один блок кода) и делает возможным генерацию кода всего приложения одним нажатием клавиши.

    Документация

    Создать подробную документацию на генератор необходимо для того, чтобы заинтересованные лица могли получать полную исчерпывающую информацию в любой момент времени. Документация как минимум должна содержать следующие сведения:

  • назначение и цели генератора;
  • архитектура и алгоритм работы;
  • преимущества и недостатки конкретного генератора;
  • техническая информация: структура папок, используемые файлы, их описание, назначение и форматы;
  • особенности работы генератора, включая обнаруженное некорректное поведение.
  • Кроме того нужны инструкции пользователя по выполнению частых операций:

  • запуска генератора,
  • обновления и заполнения метаданных,
  • обновления шаблонов,
  • установки генератора,
  • описания методов решения возникающих проблем.
  • Если вы не являетесь единственным, кто использует генератор, то наличие документации значительно облегчит освоение применения генератора другим пользователям и повысит успешность применения генератора. Отсутствие документации будет существенно тормозить его развитие и распространение для более широкого применения. И даже если вы все-таки единственный, кто применяет генератор, в случае вашего ухода письменная информация о генераторе окажет большую помощь вашему преемнику.

    Ключевые моменты в построении генераторов

    Рассмотрим моменты, которые важно соблюдать при проектировании, разработке, внедрении и применении генераторов:

  • В самом начале написать код вручную и протестировать его. Перед разработкой шаблонов и структуры метаданных надо создать стандартный код вручную - как минимум по два варианта на создаваемый шаблон. После успешного завершения тестирования на основе этого кода будут создаваться шаблоны и структура метаданных. Которые впоследствии могут корректироваться.
  • Создать систему контроля изменений кода. Сгенерированный код не должен заменяться ручным и наоборот.
  • Уделять должное внимание ручному кодированию, не перестараться с генерацией.
  • Язык реализации генератора должен выбираться независимо от языка кода приложения. Генератор решает совсем иную задачу и является другим проектом.
  • Интегрировать генератор в среду разработки. Эффективное взаимодействие генератора и среды разработки позволит программисту получить еще больше преимуществ. В некоторых случаях есть возможность разрабатывать генератор таким образом, чтобы он мог подключаться в виде модуля в среду разработки, либо использовать классы и разного рода файлы, которые применяются в среде разработки. Можно также генерировать такие файлы.
  • Интерфейс сделать дружественным для более удобного и быстрого применения.
  • Создать документацию для того, чтобы всем заинтересованным лицам было ясно, что ожидать от генератора и как с ним работать.
  • Уделять достаточное внимание обучению применения генератора всех заинтересованных лиц.
  • Поддерживать генератор для долгосрочного использования. Разработка генератора - это только начало дела, дальнейшая поддержка работы генератора является длительной и постоянной деятельностью.
  • Стараться внедрить генератор на как можно более ранней стадии.
  • Для хорошей стандартизации важно сформировать удобные и логически понятные правила именования всего в приложении - начиная от переменных, объектов и методов и заканчивая классами, модулями, файлами и папками. Также аналогичная функциональность в разных методах должна реализовываться максимально сходным образом.
  • Покупать или разрабатывать?

    Генератор можно не только разработать, но и приобрести, либо применять генератор с открытым исходным кодом. Рассмотрим плюсы и минусы самостоятельной разработки в сравнении с покупкой генератора.

    Самостоятельная разработка. Плюсы:

  • вы имеете полный контроль над генератором,
  • свободное управление развитием генератора.
  • Минусами самостоятельной разработки являются:

  • нужны ресурсы на обучение пользователей;
  • нужны ресурсы на дальнейшую поддержку генератора;
  • версия генератора должна находиться в соответствии с версией среды разработки, т.к. они могут меняться и развиваться;
  • нужны время и усилия разработчиков.
  • Покупка генератора. Плюсами являются:

  • не нужны время и усилия на проектирование и разработку генератора,
  • можно получить в наследство развитое общество пользователей генератора,
  • для обучения инженеров может использоваться документация поставщика генератора,
  • поставляемые в комплекте с генератором шаблоны могут оказаться полезными.
  • Минусами при покупке генератора являются:

  • может потребоваться значительное количество времени и ресурсов на приведение настроек генератора в соответствие с требованиями;
  • генератор может работать не так как ожидалось. Есть риск непредвиденного поведения;
  • нет контроля за развитием генератора. Если поставщик выпускает новую версию своего продукта, то предыдущие два пункта вновь могут оказаться актуальными.
  • затраты бюджета на приобретение генератора;
  • может оказаться, что генератор спроектирован и разработан не слишком удачно для приведения его в соответствие с требованиями проекта. На выяснение этого факта может уйти неприемлемое количество времени.
  • Также рассмотрим плюсы и минусы применения бесплатного генератора с открытым исходным кодом. Они практически те же, что и при покупке генератора, но имеются дополнительные плюсы и минусы.

    Плюсы применения бесплатного генератора с открытым исходным кодом:

  • можно самостоятельно изменять генератор для своих нужд,
  • нет затрат бюджета на приобретение генератора.
  • Минусы применения бесплатного генератора с открытым исходным кодом:

  • для самостоятельного изменения потребуется детально разобраться в коде генератора;
  • новая версия генератора может вступить в противоречие с собственноручно измененной версией генератора.
  • Заключение

    До недавнего времени создание программного обеспечения напоминало изготовление товаров в средние века ремесленниками. Средства, позволяющие хоть как-то автоматизировать их труд, применялись ограниченно, либо вообще не применялись. В те времена, как и сейчас при создании программного обеспечения, качество товара и время, затраченное на его производство, в большей мере зависело от мастера, его опыта и умений, чем от технологического процесса. Сегодня программирование в какой-то степени является интеллектуальным ремесленничеством. В настоящее время намечается переход от ремесленного типа программирования к промышленному. Не утихают попытки автоматизировать производство программного обеспечения, генераторы кода применяются все шире, развиваются дисциплины метапрограммирования, порождающего программирования, фабрик приложений. Даже создаются генераторы генераторов, то есть программы, генерирующие генераторы кода.

    И хотя многое сделано в этом направлении, надо пройти еще больший путь к полной автоматизации программирования. Неизвестно сколько времени на это уйдет, какие препятствия и подводные камни еще встретятся.

    Вернуться к учебному плану