Опубликован: 25.07.2012 | Уровень: специалист | Доступ: платный
Лекция 9:

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

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

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

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

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

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

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

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

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

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

С уверенностью можно сказать, что применение генератора не дает преимуществ в следующих случаях:

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

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

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

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

Все вышеперечисленное надо взвесить и принять решение о применении генератора.

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

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

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

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

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

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

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

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

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

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

  • опыт программирования на языке реализации генератора;
  • хорошее знание целевого языка(ов) и технологий, на котором будет генерироваться код;
  • хорошее владение инструментами ввода-вывода данных, таких как потоковый вывод в файл, знание XML, базы данных;
  • опыт тестирования приложений.

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

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

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

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

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

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

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

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

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

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

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