Предпосылки
«Polyglot Persistence»
Сейчас редко можно найти проект, где использовалась бы одна единственная СУБД, обычно это целый зоопарк (в хорошем смысле этого слова) хранилищ. Старая добрая реляционка в качестве основного хранилища (финансовые данные, данные для отчетов), документная база для корпоративного интернет-магазина и онлайн каталога товаров, графовая для рекомендательных сервисов, распределенная БД для хранения логов и пользовательских сессий. Плюс большое количество инстансов этих БД. Т. о. увеличивается общая сложность всей системы – становится сложнее проектировать, сложнее разрабатывать и поддерживать. Появляется необходимость миграции данных из одного хранилища в другое, оперативного развертывания и обновления в среде разработчика, тестовой среде, в промышленной.
«Лихие 90-е»
Лично у меня складывается (и уже довольно давно) такое ощущение, что технология и инструменты разработки БД застряли где-то в середине 90-х. В мире разработки приложений постоянно появляются новые и совершенствуются старые инструменты разработки, которые позволяют собирать быстрее, тестировать больше, писать меньше. В Java это старые добрые Ant и Maven, захватывает новые территории Gradle. Постоянно развиваются IDE (Visual Stuido, Visual Stuido Code, Idea, Eclipse, NetBeans etc) (очень интересно, что получится из Language Server Protocol). В моде многочисленные DevOps, Continuous Integration/Delivery/Deployment инструменты. Однако в области инструментов для разработки БД наблюдается какое-то затишье. Есть устоявшийся набор больших жирных (и в основном не дешевых) графических IDE, есть несколько миграторов, ну и в принципе все. Поэтому разработчики приложений часто стараются максимально изолироваться от конкретной СУБД, отдав работу с ней полностью на откуп ORM. При этом жертвуя уникальностью каждой СУБД, которая имеет свои особенности, свои сильные и слабые стороны (голое описание синтаксиса одной только команды Create Table в документации Oracle составляет больше 20 страниц).
«Импортозамещение»
Последние 2-3 года увеличился спрос на миграцию с закрытых СУБД на открытые. При этом вполне возможен вариант, что через какое-то время отношения «потеплеют» и отечественные компании снова потянутся обратно за «плюшками» на «Ораклы» и «SQL сервера». Поэтому БД не должна представлять из себя огромный древний неподъемный монолит, вызывающий ужас у разработчиков и трепет у администраторов. Она должна быть мобильной (готовой в любой момент, без потерь, в короткие сроки, частично или полностью переехать на другую СУБД), прозрачной, хорошо документированной, а ее исходный код и конфигурация должны находится под управлением системы контроля версий. В ней должны легко ориентироваться как разработчики и DBA, так и аналитики.
«Корпоративный сектор»
Разработка больших корпоративных БД редко отдается на аутсорсинг, т. к. компании зачастую не доверяют свои данные сторонним лицам. Т. о. это приходится делать силами собственных специалистов-разработчиков, которые при этом находятся в некой информационной изоляции. В итоге разным командам приходится самостоятельно решать довольно похожие проблемы разными (зачастую очень неочевидными и даже экзотическими) способами. Где хранить исходный код объектов бд, использовать ли для этого СКВ, если да - то как, как обеспечить контроль версий разных экземпляров БД, как формировать миграции, как устанавливать обновления и многое другое. Практически в каждой такой команде есть своя самописная утилита или набор скриптов, которая что-то обновляет, накатывает, разворачивает (и редко кто знает, как она работает). Разработка усложняется в разы, становится узкоспециализированной, а порог входа высоким.
Идея
Инструменты и среды для разработки БД обычно являются большими, полностью закрытыми и сложными в реализации (и обычно в использовании), т. к. это достаточно сложная и дорогая задача - обеспечить поддержку всех (даже основных) СУБД в одном инструменте силами одной команды разработчиков. Как итог - они плохо расширяются (кастомизируются) и плохо интегрируются с другими инструментами. Если в СУБД появилась новая фича, то в инструментах разработки ее поддержка появится не сразу, или вообще не появится, если разработчик не посчитает нужным.
Т. о. появилась идея - сделать максимально конфигурируемый и открытый инструмент для разработки БД. Одно из основных (но не единственное) средств конфигурирования - это старый добрый SQL, с помощью которого можно получить практическую любую метаинформацию из любой СУБД (к тому же необязательно реляционной, многие современные модные NoSQL также предоставляют свои собственные QL – например CQL в Cassandra) и произвести любую операцию (создать объект, удалить, проверить на существование, сгенерировать исходный код, собрать статистику, перестроить индексы и многое другое). А структурировать с помощью xml/json/yaml. Плюс возможность дополнить это кастомными скриптами (e. g. Groovy, Ruby, JS) при необходимости. Т. о. будет некий универсальный движок, не зависящий ни от какой-либо СУБД, ни от драйвера (JDBC/ etc), и набор текстовых конфигурационных файлов, в которых будет описана структура конкретной БД (набор объектов, их иерархия), способы доступа к ним, шаблоны для генерации исходного кода, расширенная логика поведения и пр. Каждая конфигурация для конкретной СУБД будет в полной мере охватывать ее функционал, являться нативной для СУБД и для конкретного flow команды разработчиков. Появилась новая возможность в СУБД – для этого достаточно внести небольшие изменения в конфиг (либо поискать в репозитории таких конфигураций, возможно это уже кто-то сделал).
Можно подготовить расширенные конфигурации для популярных БД (Postgres, MySql, Oracle, Cassandra). Далее разработчики смогут адаптировать их под свои нужды, расширять и реализовывать поддержку других СУБД. Этими конфигами можно обмениваться т. о. перенимая лучшие практики разработки от других разработчиков.
Как например популярные SCM инструменты: Chef (где для конфигурации используются т. н. Cookbook, которые пишутся на Ruby-диалекте, и огромное количество которых доступно в Chef Supermarket), Puppet (расширяется с помощью модулей, хостятся на Puppet Forge) и Ansible (конфигурируется с помощью собственного DSL - Playbooks). Или Yeoman, который расширяется генераторами, написанными на JS (чтобы опубликовать свой генератор, достаточно загрузить его на npmjs. org), т. о. для web-разработчиков (и не только) доступно огромное количество генераторов для самых разных js-фреймворков. Похожую философию можно применить и для инструмента разработки БД под разные СУБД.
Более подробно с инструментом можно ознакомиться здесь.
Техническая реализация
Сердце инструмента – это обычный REST-сервис, а каждый объект базы данных является его ресурсом. Т. о. ресурс - это сама БД, схема, пользователь, роль, индекс и т. д. Для разных СУБД разные наборы ресурсов, например, только для Oracle будут доступны такие ресурсы как: plsql-пакет (причем head и body так же могут быть разными ресурсами, а могут и одним, зависит от конфигурации), материализованное представление, advanced queue, iot-table, external-table и прочие прелести, для Postgres – каталоги, inherited tables, для Cassandra – составной PK (партиционная часть плюс кластерная), user defined types и т. д.
Т. о. с помощью URI мы можем обратиться к какому-либо объекту/объектам БД и выполнить над ним какие-либо действия (посмотреть информацию, удалить, создать, проверить на существование и пр.) (причем для этого не обязательно выполнять подключение к БД, вместо нее может выступить СКВ, под управлением которой находятся эти объекты).
Шаблон URI:
тип/имя/команда[/]?опции
«Тип» – наименование типа объекта БД (схема, таблица, индекс, триггер etc);
«Имя» – имя объекта БД, включая его иерархию. Например, для индекса: «имя_бд».«имя_схемы». «имя_таблицы». «имя_индекса». Иерархия ресурсов может отличаться в зависимости от СУБД, например в Oracle DB-пользователь строго соответствует своей схеме, а вот в Postgres схемы и пользователи не зависимы друг от друга + еще дополнительно есть каталоги.
«Команда» – имя команды, которую нужно выполнить над указанным объектом/объектами (создать, удалить, проверить на существование, собрать статистику, перекомпилировать, запустить, остановить, обновить, проиндексировать и т. д.); Является не обязательным, если не указан, то будет выполнена команда, указанная по умолчанию в конфигурации (обычно create или info);
Типы объектов, их иерархия и команды полностью описываются в текстовых конфигурационных файлах в декларативном виде (в зависимости от конкретной СУБД и потребностей пользователей).
«/» - слеш в конце основной чаcти URI означает, что в результат будут включены так же и дочерние объекты указанного объекта. Например, для схемы БД будут также выбраны ее таблицы и view, а для таблицы индексы, колонки и ключи. Является не обязательным, если не указан, то дочерние объекты исключаются;
«Опции» – любые дополнительные условия или параметры (дополнительные фильтры для поиска, выбор формата для отображения информации об объекте etc).
Например:
«table/hr. persons» – позволяет получить информацию о таблице «Persons» (по умолчанию будет сгенерирован и возвращен DDL создания объекта);
«table/hr. persons/drop» – вернет команду для удаления таблицы, т. е. что-то типа «drop table hr. persons»;
«table/hr» – получим DDL всех таблиц схемы HR;
«table/hr/drop» – список команд для удаления всех таблиц схемы HR;
«table/hr. p*/drop» – команды удаления всех таблиц схемы HR, с имена с символа «P» ;
«index/hr. persons» – DDL для всех индексов таблицы hr. persons;
«index/hr. persons.*idx» – DDL для всех индексов таблицы hr. persons, с суффиксом «idx» в имени;
«procedure/market. rebuild» – команды для пересборки всех процедур в схеме «market».
СУБД-специфичные ресурсы:
«queue/hr.*_salary_calculated_queue/stop» – команда для остановки обработки всех очередей схемы HR, выполняющих расчет заработной платы;
«package_body/hr. calc*/rebuild» – пересобрать все body пакетов схемы HR с префиксом «calc»;
«job/processing/pause» – приостановить выполнение задач в схеме «PROCESSING».
Можем воспользоваться красотой http-сервисов, добавив в запрос заголовок Accept.
Например, для всех индексов схемы «PERSONS» можем получить информацию в следующих форматах:
«GET --header 'Accept: text/plain' …/index/hr. persons.*idx» - DDL-код создания индексов;
«GET --header 'Accept: application/xml' …/index/hr. persons.*idx» - liquibase-миграции в формате xml
«GET --header 'Accept: application/json' …/index/hr. persons.*idx» - описание в формате json
«GET --header 'Accept: application/zip' …/index/hr. persons.*idx» - исходный DDL-код объектов, упакованный в zip архиве в специальной файловой структуре (которая также кастомно определяется в конфигурационном файл), такой архив можно распаковать и закомитить в СКВ.
И немного экзотики, следующий запрос может вернуть диаграмму со всеми объектами схемы «HR» (допустим сформированную с помощью dot и graphviz):
«GET --header 'Accept: image/jpeg' …/table/hr»
Если изменить тип запроса на POST, то можем получить дополнительную функциональность – сервис не будет возвращать сгенерированные команды, а сразу выполнит их на текущей (или другой) БД:
«POST …/index/hr/rebuild» - произвести ребилд всех индексов в схеме «HR»;
«POST …/index/hr/gather_stat» - собрать статистику для всех индексов в схеме «HR»;
«POST …/job/hr.*calc_average_salary/start» - запустить указанные джобы;
«POST …/queue/hr.*main_queue/stop» - остановить обработку указанных очередей.
Так же можем «навесить» нужный функционал на остальные типы запросов http (PUT, DELETE, HEAD etc).
Ресурсы так же могут быть интегрированы с бизнес-областью (например, таблицы для проекта интернет- магазина, таблицы для модуля расчета заработной платы, таблицы для онлайн бронирования – у всех у них могут быть какие-либо свои особенности), разделены на модули.
Более детально можно ознакомиться в онлайн демо приложении, ссылки описаны здесь.
Наличие RESP API делает возможным простую интеграцию с самыми различными приложениями и инструментами, а также дает возможность реализовать графический web-интерфейс любой сложности.
Конфигурирование сервиса (под конкретную СУБД и конкретный flow команды) осуществляется в основном с помощью xml (для описания структуры) и sql (с помощью него можно легко, прозрачно и быстро получать практически всю полезную метаинформацию о БД). На данный момент используется xml Spring конфигурирование.
Для конфигурирования созданы следующие компоненты:
«Reader» - определяет способ поиска объектов, указанных в ресурсе. На данный момент полностью реализован только SqlReader, который ищет объекты в словарях СУБД, на основании пользовательского sql-запроса. Т. е. мы сами определяем, как найти объект в базе. Планируется FileSystemReader, который смог бы производить поиск объектов в файловом хранилище или в различных репозиториях (GitReader, HgReader, SvnReader etc);
«Generator» - отвечают за «внешний вид» найденного объекта. Например, «TemplateGenerator» может сгенерировать исходный код на основании указанного шаблона. Также есть шаблоны для генерации html-описаний, json, xml-миграций (liquibase) и прочее. А «SQLGenerator» может обратиться за помощью к самой БД (например в Oracle есть пакеты для генерации DDL – DBMS_METADATA);
«Aggregator» - когда объекты найдены и представлены в каком-либо нужно нам виде, то их нужно как-то агрегировать вместе. На данный момент существует TextAggregator, который собирает все объекты вместе на основании шаблона, и ZipAggregator, который разложит полученные объекты по файлам и папкам в заданной структуре и упакует в zip-файл, чтобы отдать в качестве ответа на запрос.
Здесь можно найти пример описания структуры таблицы в формате xml, а здесь yaml-файл с sql-запросами и шаблонами для генерации представлений объектов.
Краткий обзор существующих инструментов
· Большой набор больших коммерческих графических DB IDE, которые позиционируют себя, как универсальные средства на все случаи жизни – навигация по объектам, редакторы sql (и sql-подобного) кода, инструменты для администрирования БД, (кое-где) интеграция с СКВ, сравнение объектов БД, средства для моделирования и дизайна данных и еще много всего полезного (и не очень). На рынке существуют как старые и хорошо известные игроки (Toad, Oracle PLSQL Developer, Oracle SQL Developer, dbForge, EMS и многие другие), так и новые решения, такие как JetBrains DataGrip (в недавнем прошлом 0xDBE, официально зарелизенный в прошлом году) и DbVisualizer (так же появившийся в 2016). Минусы: обычно сильно платные, полностью закрытые, внести какие-либо изменения в работу, подстроить под себя такие средства достаточно сложно. Стремящаяся к нулю способность к интеграции с другими средствами разработки (обычно это чистый GUI, без консоли (или с ее зачатками) и какого-либо API).
· Близкий по мысли (но не по духу) – это DBmaestro. Является DevOps-инструментом, который позволяет интегрировать БД с СКВ, build automation, CI. Минусы: закрытый полностью коммерческий инструмент, у него нет «магазина» с расширениями (как я понял, он вообще слабо кастомизируется). Не имеет интерфейсов кроме графического (ни API, ни REST, ни даже CLI).
· Серия продуктов от Redgate, в частности SQL Source Control и SQL Compare. Позволяют довольно тесно интегрироваться с СКВ и выполнять сравнение объектов из разных БД. Минусы: работает только с MS SQL Server, так же обладает исключительно графическим интерфейсом и слабо кастомизируется.
· phpMyAdmin и phpPgAdmin уже давно пользуются популярностью, web-морда - можно получить доступ к админке базы откуда угодно без установки чего-либо на клиенте. Ограничены в функционале, жестко заточены под конкретную бд, сложны в установке, имеют ограниченный функционал по сравнению с desktop-решениями.
· SchemaCrawler - также достаточно древний и до сих пор остающийся популярным тулз. Распространяется с открытым исходным кодом, обеспечивает навигацию по объектам БД, строит по ним выходные таблицы или диаграммы dot. Минусы: только CLI, ограничен возможностью jdbc-драйверов, скромный функционал, сложный API.
· dbeaver - это чистая gui ide, но зато полностью открытая, довольно популярная, разрабатывается силами одного энтузиаста. Минусы: так же базируется на jdbc, каждый объект бд описывается набором классов, в них же прописывается кастомный sql (если есть). Чтобы добавить/изменить объект нужно обладать java-скилами, а также разбираться в коде самого проекта. Достаточно плотно интегрирован с визуальной средой (eclipse).
· scheme2ddl – достаточно популярная утилита, не смотря на то, что умеет выгружать исключительно оракловые объекты в жесткую фиксированную файловую структуру, используя при этом только стандартный генератор DDL-кода – DBMS_METADATA. Расширяемости практически ноль, весь код доступа к БД и ее структура жестко «зашиты» в приложении. Общался с автором, он говорит, что ему периодически приходят pull request’ы с новыми фичами, а еще больше писем с разными предложениями по расширению – но большинство из них он отклоняет, т. к. хочет сохранить максимальный unix-way.
PS
В книге «Рефакторинг баз данных. Эволюционное проектирование» авторы описывают похожие проблемы (эволюционное проектирование и разработка БД, рефакторинг, проблемы коммуникаций между разработчиками приложений и разработчиками БД и многое другое), а также прогнозируют в недалеком будущем появление инструментов, которые позволили бы решить эти проблемы (на страницах даже содержатся примеры java-кода). С первого выпуска этой книги прошло 11 лет, по моему мнению, подходящий инструмент (несмотря на большое обилие различных ide, библиотек и фреймворков) так и не появился.


