воскресенье, 20 мая 2012 г.

Кодогенерация - для чего она?

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

Кодогенерация - для чего она?

Давайте представим себе, что мы разрабатываем некоторое тиражируемое приложение (например игру), использующее БД для хранения своих данных. Android не балует нас разнообразием, и когда мы говорим "встроенная БД", мы имеем в виду SQLite и только её :)

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

Это действительно очень удобно, но ... что делать если мы используем какой-то визуальный редактор (например при проектировании уровней)? Наш редактор уровней, в процессе работы, внесет изменения в ЛОКАЛЬНУЮ встроенную БД, используемого нами устройства, минуя исходный код нашего приложения! Как нам передать эти изменения пользователям?

Конечно, если мы используем эмулятор, не составляет труда скопировать с него сгенерированную нашим приложением БД, но, во первых, пользоваться эмулятором может быть неудобно, и во вторых, что нам делать с полученным файлом БД дальше?

В этом месте нам на помощь приходит кодогенерация. Действительно решение тривиально - если для тиражирования изменений БД необходимо внести новый КОД в метод onUpgrade, почему бы не сделать это автоматически, учтя при этом все изменения, внесенные в локальную БД приложением?
Android позволяет записать текстовый файл в файловую систему устройства (при наличии WRITE_EXTERNAL_STORAGE uses-permission в манифесте), вот мы и сформируем файл, содержащий код на языке Java. Впоследствии этот файл можно будет забрать с устройства и добавить его в исходный код проекта, решив, тем самым, проблему тиражирования изменений.

Мы уже почти наполовину решили нашу задачу :) Осталось только спроектировать как все это будет выглядеть.


Мы разделим реализацию нашего Content Provider-а на три Java-класса. ProviderMetadata будет содержать реализацию DatabaseHelper, предоставляющую базовую функциональность, ProviderPatches будет содержать тиражируемые изменения и формироваться кодогенератором, а CodegenProvider реализует API используемое приложением для взаимодействия с БД.

Здесь следует обратить внимание, что константу DATABASE_NAME содержащую имя используемой нами БД, мы определяем на самом верхнем уровне в CodegenProvider, а DATABASE_VERSION в классе, содержащем реализацию патчей. Класс ProviderMetadata свободен от какой-то конкретике и может повторно использоваться в любых наших приложениях.

Все это прекрасно, но с чем именно будет работать наш обобщенный и до предела отвязанный от конкретики (почти сферический) ProviderMetadata? Как бы смешно это не звучало, но для того чтобы программа могла писать программы, ей необходимы данные, которые описывают данные :) то есть МЕТАданные.

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


Таблица version будет содержать список патчей, сформированных для нашего приложения. В таблице table мы будем хранить описание таблиц, а в таблице column - столбцов (привязанные к патчам БД). Для таблиц мы будем сохранять их имена, а для столбцов, дополнительно описания типов данных (data_type) и признака NOT NULL (is_not_null). Для чего нам потребуется поле alias_name, я расскажу позже.

Подведем итог


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

Комментариев нет:

Отправить комментарий