1 часть. Ораклява
Как-то меня перекинули на мой первый серьезный проект. Главная проблема была в том, что из проекта ушел основной разработчик, проект оказался в середине большого переписывания, а мне знания передавались неспециалистом в формате вуду-практик. Этих плясок было достаточно, чтобы поддерживать хоть какое-то подобие жизни.Оправившись от шока и расчистив эпсилон-окрестность, стало легче дышать и уже можно было подумать о переписывании отдельных кусков. К тому моменту у нас уже была система контроля версий. Большая часть бизнес-логики хранилась в Oracle, разухабистые пакеты с большими портянками селектов. Меньшая часть запросов (тоже здоровые портянки) хранилась прямо в коде. [Проблемам хранения бизнес-логики в БД посвящен отдельный псто, полный боли и страданий.] А вот это-как раз сильно напрягало: в случае проблем с запросом, нужно его скопировать из эклипса, вставить в скуль девелопер, убрать все кавычки, заменить JDBC-шные двоеточия на амперсанды, а внести изменения и повторить в обратном порядке - весь этот процесс дичайше накалял. Да и вообще здоровенные запросы сильно мешали чтению кода. И почему в java нет многострочных строк, как в питоне?
Первая попытка была - вынести все запросы в XML файл, обрамить их в , дать им имена и подгружать запросы в коде. После первой же попытки пришлось дополнительно обрамить их в
<![CDATA[]]>
. DBA вздохнул с облегением, но размазанность кода между двумя системами сильно напрягала.Когда мы узнали про REF CURSOR, то быстро отказались от файлика с запросами и наконец-то перенесли все запросы в одно место - БД, рассовав их по пакетам. Приложение полностью диссоциировало на две независимые сущности: запросы, сложнее SELECT * FROM и схема в ведении DBA, всё остальное - принадлежит разработчикам.
Все бы ничего, если бы не один эпизод. Мы враппили все пакеты в целях секурности и однажды завраппили рабочую базу с последними изменениями. Несколько часов паники и отчаяния, пока мы не нашли unwrap. Сразу после этого отчаянно захотелось версионировать схему, которая содержала критически важный код.
Старый добрый exp позволяет экспортировать схему без сжатия и данных, что позволяет видеть диффы между версиями. Мы быстро прикрутили Ant-таск, который перед коммитом экспортировал схему. Все было великолепно, до второго коммита, который показал дифф. Одна строка реальных изменений привела к разнице во всех до единой строках экспорта, которыйх просто херил все переносы строк и переносил строки в районе 80-й колонки. Попытки выставить бесконечную, или просто разумно большую ширину буфера не привели абсолютно ни к какому эффекту.
Я отчаялся и начал искать решение. Схему можно было получить вручную выполнив запросы из командной строки, но sqlplus плевать хотел на задаваемую ширину буфера и результат не отличался от того, что давал exp. Но случилось чудо: JDBC оказался более сговорчивым и отдавал схему as-is не расставляя переносы, как ему вздумается. Я быстро накидал плагин для ant (который потом передеал на простую командную строку) и выложил на GitHub - первый и последний рабочий проект на git.

2 Часть. Пайсон
На новой работе, попробовав написать на PHP, я быстро отказался в пользу Django. Это был дивный новый мир, где был человеческий ORM и не нужно было руками переносить данные из курсоров в доменные объекты. Я просто забыл про написание CRUD-запросов, которые составляли 95%. И никакой логики с базе: рабочая база накатывается с нуля одной командой; никакого оракла: работать можно с любой базой, на любой машине, хоть с sqlite (который идет с питоном), если лень ставить мускуль или постгрес. После монструозности оракла, я парил.Когда появились реальные данные и я задумался, как накатывать схему (стандартный механизм весьма примитивен), под рукой оказался South, который ставился в одну строку, САМ искал отличия в схеме, позволял мигрировать в обе стороны (конечно, учитывая потери данных), и пытался откатить схему к стабильному состоянию в случае ошибки. Это была просто сказка. Кстати, когда объявили сбор средств на кикстартере для интеграции South в Django, деньги нашлись мгновенно, причем насобирали в 7 РАЗ больше необходимого.
3 часть. Ынтырпрайз или жаба возвращается
Я вернулся на java, где царил JPA, под капотом которого спрятался Hibernate. Легкость ушла, но осталось понимание того, как делать правильно. С переходом на GitFlow код стабилизировался, и мы решили потренироваться с миграцией между стабильными версиями схемы, хотя на тот момент это не было нужно.В качестве средства миграции мы выбрали flyway, который действительно был легковесным, если сравнивать с остальным миром ынтырпрайза. Он не находил сам разницы между схемами, не позволял возвращаться назад, в случае ошибки просто падал с ошибкой не предпринимая действий по откаду к стабильному состоянию - решения принятые авторами flyway. Тем не менее, он работал с обычными SQL-скриптами, что, в приципе, было достаточно для существования.
Мы быстро освоились и на данный момент у нас более семидесяти миграций. Часть миграций исправляет миграции, написанные для неудачных ветвей разработки и это уже составляет некотороую проблему, поэтому хочется коллапсировать все миграции до самой последней версии, находящейся в продакшене.
Но самая большая проблема поджидала нас, откуда никто не ожидал: распределенное версионирование. В распределенности сильно искажено понятие времени, как упорядоченной последовательности событий. Мы одновременно с коллегой начали вести разработку, моя миграция была создана раньше и получит меньший номер (который мы берем в формате
V201203211847__init_schema.sql), чем его. Проблемы начнутся, если он вольет свои изменения в гланую ветвь раньше меня: его миграция окажется последней и спрячет мою, с меньшим номером. Как автоматически решать эту проблему, мы еще не придумали, поэтому просто обновляем метки времени перед слиянием, если кто-то добавил миграцибю до нас.