Еволюційний дизайн баз даних


За останнє десятиліття ми розробили і вдосконалили кілька методів, які дозволяють дизайну баз даних еволюціонувати паралельно з розробкою програми.
Це дуже цінна властивість гнучких методологій. Методи спираються на застосування безперервної інтеграції та автоматизованого рефакторінгу до розробки баз даних, а також на тісну взаємодію між розробниками додатків і адміністраторами БД. Ці методи працюють як в препродакшн і вже стартували системах, у свіжих проектах без легасі, так і в успадкованих системах.
В останнє десятиліття ми спостерігаємо зростання гнучких методологій. Порівняно зі своїми попередниками, вони змінюють вимоги до дизайну баз даних. Одне з найважливіших серед вимог – ідея еволюційної архітектури. В гнучкому проекті ви припускаєте, що не можете заздалегідь поправити вимоги системи. В результаті, мати деталізовану, чітку стадію дизайну на початку проекту стає непрактично. Архітектура системи повинна еволюціонувати одночасно з ітераціями софту. Гнучкі методи, зокрема, екстремальне програмування (XP), мають набір методик, які роблять цю еволюційну архітектуру практичною.
Коли ми та наші колеги з ThoughtWorks стали робити agile-проекти, ми зрозуміли, що нам потрібно вирішувати задачу еволюції баз даних, для підтримки еволюції архітектури. Ми почали приблизно у 2000 році з проекту, база даних якого в підсумку дійшла майже до 600 таблиць. У процесі роботи над цим проектом ми розробили методи, які дозволили поміняти схему і зручно мігрувати існуючі дані. Це зробило базу даних повноцінно гнучкою і эволюционируемой. Ми описали методи в більш ранніх версіях цієї статті, і її зміст надихнуло інші команди і toolsets. З тих пір ми використовували і далі розвивали методи в сотні проектів по всьому світу, від невеликих груп до великих багатонаціональних програм. Ми давно збиралися оновити цю статтю, і тепер така можливість з'явилася.


Джен реалізує нову юзер-історію
Для того, щоб отримати уявлення про те, як все це працює, давайте набросаєм в загальних рисах що відбувається, коли розробник (Джен) пише код, щоб реалізувати нову власну історію. Історія описує користувача, у якого є можливість бачити, шукати і оновлювати позицію, номер партії і серійний номер товарів, що знаходяться в наявності. Дивлячись на схему бази даних, Джен бачить, що в даний час немає ніяких полів в таблиці наявності товару, тільки одне поле inventory_code, яке є конкатенацией (об'єднанням) цих трьох полів. Вона повинна розділити єдиний код на три окремих поля: location_code, batch_number і serial_number.
Ось кроки, які вона повинна здійснити:
  • Додати нові стовпці таблиці inventory у вже існуючій схемі.
  • Написати скрипт міграції і розділити дані із стовпця inventory_code за створеним стовпців: location_code, batch_number і serial_number.
  • Змінити код програми для використання нових стовпців.
  • Змінити всі частини коду бази даних, такі як вибірки, збережені процедури і тригери, щоб вони використовували нові стовпці.
  • Змінити всі індекси, базируемые на inventory_code.
  • Закомитить скрипт міграції бази даних і всі зміни коду програми в систему керування версіями
Для додавання нових колонок і перенесення даних Джен пише скрипт міграції на SQL, який вона може порівняти з поточною схемою. Це і одночасно змінить схему і перенесе всі наявні дані про товари в наявності.
ALTER TABLE inventory ADD location_code VARCHAR2(6) NULL;
ALTER TABLE inventory ADD batch_number VARCHAR2(6) NULL;
ALTER TABLE inventory ADD serial_number VARCHAR2(10) NULL;

UPDATE inventory SET location_code = SUBSTR(product_inventory_code,1,6);
UPDATE inventory SET batch_number = SUBSTR(product_inventory_code,7,6);
UPDATE inventory SET serial_number = SUBSTR(product_inventory_code,11,10);

DROP INDEX uidx_inventory_code;

CREATE UNIQUE INDEX uidx_inventory_identifier
ON inventory (location_code,batch_number,serial_number);

ALTER TABLE product_inventory DROP COLUMN inventory_code;

Джен запускає скрипт міграції в локальній копії бази даних на своєму комп'ютері. Потім вона переходить до оновлення коду, щоб використовувати нові колонки. У процесі вона застосовує існуючий набір тестів до нового коду, щоб виявити будь-які зміни в поведінці додатки. Деякі тести, ті, які покривали комбіновану колонку, потрібно оновити. Можливо, потрібно додати ще якісь тести. Після того, як Джен зробила все це, і додаток пройшло всі тести на її комп'ютері, вона вантажить зміни в загальний проектний репозиторій, який ми називаємо mainline. Ці зміни включають в себе скрипти міграції та зміни коду програми.
Якщо Джен не занадто добре знайома з внесенням цих змін, їй пощастило, що вони універсальні для баз даних. Тому вона може зазирнути в книгу про рефакторинг баз даних. В мережі є довідка на цю тему.
Після того, як зміни виявляються в магістралі, вони підхоплюються сервером безперервної інтеграції. Він запускає скрипти міграції на копії бази даних в магістралі, а потім всі тести програми. Якщо все проходить успішно, цей процес буде повторюватися на кожному етапі Deployment Pipeline, включаючи тестування (QA) і staging. Той самий код, нарешті, запущено у production, на цей раз оновлюючи реальну схему бази даних і дані.
У невеликій користувача історії, як у прикладі, тільки одна міграція бази даних, великі користувальницькі історії часто розбиваються на кілька окремих міграцій для кожної зміни в БД. У нас правило — робити кожна зміна БД наскільки можливо маленьким. Чим менше, тим легше отримати правильний результат, а будь-які помилки швидко виявити і налагодити. Міграції, як у прикладі, легко поєднувати, так що краще робити багато дрібних.
Робота із змінами
Оскільки гнучкі методи стали популярними на початку 2000-х років, одна з найбільш очевидних характеристик це схильність до змін. Перед тим, як вони з'явилися, найчастіше уявлення про софт були такими: розуміння вимог на ранньому етапі, встановлення вимог, використання вимог як основи для дизайну, виконання дизайну, а потім виконання проекту. Цей керований планом цикл часто називають (зазвичай з насмішкою) водопадным підходом.
Такі підходи використовують у спробах звести до мінімуму зміни, що виливається в надмірну попередню роботу. А коли попередня робота закінчена, зміни призводять до серйозних проблем. В результаті, якщо вимоги змінюються, ці підходи ведуть до несправностей, а перегляд вимог — головний біль для таких процесів.
Гнучкі процеси мають інші методичні підходи до змін. Вони доброзичливі до змін навіть на пізніх стадіях розробки проекту. Зміни контролюються, але характер процесу робить їх вірогідними настільки, наскільки можливо. Частково — це відповідь на вбудовану нестабільність вимог багатьох проектів, частково — концепція більш якісної підтримки динамічних бізнес-структур і допомоги їм з змінами, в умовах тиску конкурентів.
Для того, щоб поставити цей процес на колеса, вам потрібно змінити ставлення до дизайну. Замість того щоб думати про дизайн як про фазу, яка закінчується перед фазою конструювання, ви дивитеся на дизайн, як на безперервний процес, який чергується з конструюванням, тестуванням і навіть доставкою. Такий контраст між плановим і еволюційним проектуванням.
Один з найважливіших вкладів гнучких методів — підходи, при яких у еволюційного дизайну є можливість тримати роботу під контролем. І замість звичного хаосу, який часто бере верх, коли конструювання не заплановано заздалегідь, ці методи народжують способи контролю еволюційного дизайну і роблять їх практичними.
Важлива частина цього підходу — итеративная розробка, коли повний життєвий цикл софта запускається багато раз за все існування проекту. Гнучкі процеси запускають повний життєвий цикл у кожній ітерації, завершуючи ітерацію робітникам, протестованим, інтегрованим кодом і невеликим підмножиною вимог кінцевого продукту. Ці ітерації короткий — від кількох годин до кількох тижнів: більш досвідчені команди використовують більш короткі ітерації.
Хоча інтерес до цих методів та їх використання зросли, один з найбільш важливих питань — як використовувати еволюційний дизайн для баз даних. Тривалий час група людей зі спільноти баз даних сприймала дизайн БД як щось обов'язково вимагає попереднього планування. Зміна схеми бази даних в кінцевих фазах розробки, як правило, призводить до розповсюджується дефектів програми. Крім того, зміна схеми після деплоя призводить до болючої міграції даних.
протягом останніх десяти з половиною років, ми брали участь у багатьох великих проектах, які використовували еволюційний дизайн БД і він успішно працював. Деякі проекти включали в себе більше 100 осіб у кількох робочих точках по всьому світу. Інші — понад півмільйона рядків коду, понад 500 таблиць. У деяких з них у production було кілька версій програми і кожне вимагало цілодобового обслуговування. В ході цих проектів нам траплялися ітерації тривалістю в місяць і тиждень, але більш короткі ітерації працювали краще. Методи, описані нижче, дозволили зробити це можливим.
З перших днів ми намагалися поширити методики на більшу кількість своїх проектів. Ми отримували більше досвіду від покриття більшої кількості випадків, і тепер всі наші проекти використовують цей підхід. Ми черпаємо натхнення, ідеї і досвід інших людей, що користуються цим підходом.
Обмеження
Перш ніж ми почнемо розбиратися з підходами, хочу сказати, що ми не вирішили всі проблеми еволюційного дизайну баз даних.
У нас були проекти з сотнями роздрібних магазинів, з їх власними базами даних, кожну з яких потрібно було оновлювати. Але ми ще не розглядали ситуацію, коли у великої групи сайтів є багато налаштувань. Як приклад, можна розглянути додаток для малого бізнесу, яка дозволяє робити налаштування схеми, задеплоенной в тисячах різних невеликих компаніях.
Все частіше ми бачимо, як люди використовують безліч схем, як частина єдиної середовища БД. Ми працювали з проектами, які використали за кілька подібних схем, але десятки або сотні — не пробували. Ми прогнозуємо протягом наступних кількох років розібратися з цією ситуацією.
Ми не вважаємо, що ці проблеми нерозв'язні. Зрештою, коли ми написали оригінальну версію цієї статті, ми не позбулися проблеми безперервної роботи або інтеграції БД. Ми знайшли способи, як з ними справлятися і сподіваємося, що розширимо межі еволюційного дизайну БД. Але поки цього не сталося, ми не будемо стверджувати, що не здатні вирішити подібні завдання.
Методики
Наш підхід до еволюційного дизайну БД побудований на кількох важливих методиках.
Адміністратори БД тісно взаємодіють з розробниками
Один з принципів гнучких методів — працівники з різними навичками і досвідом повинні дуже тісно взаємодіяти один з одним. Вони не повинні спілкуватися тільки через офіційні зустрічі і документи. Їм потрібно контактувати і працювати один з одним. Це впливає на всіх: аналітиків, керівників проекту, експертів у предметній області, розробників… і адміністраторів БД.
В кожній задачі, над якою працює розробник, потенційно потрібна допомога адміністратора БД. І розробники, і адміністратори повинні передбачати, чи будуть входити значні зміни схеми бази даних в задачу розробки. Якщо так, то розробник повинен проконсультуватися з адміністратором БД, щоб вирішити, як вносити зміни. Розробник знає, яка нова функціональність потрібно, а у адміністратора є єдине подання даних поточного додатка й інших додатків. Часто розробники мають уявлення про програму, над яким працюють, але не мають про всіх інших upstream або downstream залежностях схеми. Навіть якщо це єдиний додаток БД, у ньому можуть міститися залежності, про які розробник не в курсі.
У будь-який момент розробник може звернутися до адміністратора і попросити розібратися у змінах бази даних. Коли використовується парний стиль, розробник дізнається про те, як працює база даних, а адміністратор вивчає особливості вимог до бази даних. Найчастіше питання — звертатися з приводу змін до АБД чи ні — лежить на розробнику, якщо його турбує вплив змін на базу даних. Але АБД теж беруть ініціативу. Коли вони бачать вимоги, які, на їх думку, можуть зробити значний вплив на дані, вони можуть звертатися до розробників, щоб обговорити вплив на БД. АБД може також торкнутися міграції, оскільки вони зафіксовані в систему керування версіями. Так як зворотна міграція всіх дратує, ми виграємо від кожної маленької міграції, яку простіше реверсувати.
Щоб зробити це можливим, АБД повинен охоче йти назустріч і бути в доступності. Потрібно, щоб розробник міг легко нагрянути і задати декілька питань в слаке або хипчате — якому засобі зв'язку, яке використовують розробники. Коли ви організуєте робочий простір для проекту, постарайтеся щоб АБД і розробники сиділи ближче один до одного, щоб їм було легко контактувати. Переконайтеся в тому, що адміністратори в курсі будь-яких зустрічей, пов'язаних з дизайном програми, щоб вони могли легко підтягнутися. У робочих микроклиматах нам часто зустрічаються люди, що створюють бар'єри між адміністраторами БД і функціями розробки. Щоб еволюційний процес дизайну БД працював, потрібно стерти ці бар'єри.
Всі артефакти бази даних are version controlled with application code
Розробники значно виграють від використання контролю версій всіх своїх артефактів: коду програми, функціональних і модульних тестів, коду, на кшталт скриптів складання, Chef або Puppet скриптів, які використовуються для створення робочого оточення.

Рис 1: Всі артефакти бази даних у системі керування версіями, разом з іншими артефактами проекту
так само всі артефакти бази даних повинні бути в системі управління версіями, у тому репозиторії, який використовується усіма іншими. Переваги цього:
  • Все знаходиться в одному місці і будь-якому учаснику проекту легко знайти потрібне.
  • Кожна зміна бази даних зберігається, що дозволяє легко зробити перевірку при виникненні будь-якої проблеми. Ми можемо відстежити будь деплой бази даних та знайти необхідний стан схеми і допоміжних даних.
  • Ми не робимо деплои, якщо база даних не синхронізується з додатком, що призводить до повернення помилок і оновлення даних.
  • Ми можемо легко створювати нові середовища: для розробки, тестування і звичайно production. Все, що потрібно для створення працюючої версії додатка, повинно знаходитись в одному сховищі, щоб можна було швидко скопіювати і зібрати.
Усі зміни бази даних — це міграції
У багатьох організаціях існує процес, в якому розробники вносять зміни до бази даних за допомогою інструментів редагування схеми та ad-hoc SQL даних. Після того, як вони закінчують розробку, адміністратори БД порівнюють розроблену базу даних з базою даних у production і вносять туди відповідні зміни, переводячи додаток в робочий стан. Але production це робити складно, тому що контекстний індикатор змін, той що був в розробці, загубився. Потрібно знову розбиратися, навіщо були зроблені зміни, але вже іншій групі людей.
Щоб цього уникнути, ми вважаємо за краще фіксувати зміни під час розробки і зберігати їх як артефакт першого рівня, який можна потім протестувати і задеплоить з тим же процесом і контролем, як для змін в коді програми. Ми робимо це, відображаючи кожну зміну в базі даних, як скрипт міграції бази даних, які як і зміни в коді програми, знаходяться в системі контролю версій. Ці скрипти міграції включають в себе: зміни схеми, зміни коду бази даних, оновлення посилальних даних, оновлення даних про транзакції і виправлення проблем з даними з-за помилок у production.
Ось зміна, добавка min_insurance_value і max_insurance_value до таблиці equipment_type, з кількома дефолтними значеннями.
ALTER TABLE equipment_type ADD(
min_insurance_value NUMBER(10,2),
max_insurance_value NUMBER(10,2)
);

UPDATE equipment_type SET
min_insurance_value = 3000,
max_insurance_value = 10000000; 

Це зміна додає набір постійних даних до таблиць location та equipment_type.
-- Create new warehouse locations #Request 497
INSERT INTO location (location_code, name , location_address_id,
created_by, created_dt)
VALUES ('PA-PIT-01', 'Pittsburgh Warehouse', 4567,
'APP_ADMIN' , SYSDATE);
INSERT INTO location (location_code, name , location_address_id,
created_by, created_dt)
VALUES ('LA-MSY-01', 'New Orleans Warehouse', 7134,
'APP_ADMIN' , SYSDATE);

-- Create new equipment_type #Request 562
INSERT INTO equipment_type (equipment_type_id, name,
min_insurance_value, max_insurance_value, created_by, created_dt)
VALUES (seq_equipment_type.nextval, 'Lift Truck',
40000, 4000000, 'APP_ADMIN', SYSDATE);

При роботі з допомогою такого методу, нам ніколи не доводиться використовувати інструменти редагування схем, типу Navicat, DBArtisanor або SQL Developer, і ми ніколи не запускаємо бездротові DDL або DML, щоб додати постійні дані або виправити помилки. Крім оновлень в базі даних, які відбуваються через додатків, всі зміни робляться міграціями.
Називаючи міграції наборами команд SQL, ми розповідаємо тільки частина історії, але для того, щоб правильно їх застосовувати, нам потрібно щось ще.
  • Кожна міграція вимагає унікальної ідентифікації.
  • Потрібно відслідковувати, які міграції були застосовані до бази даних
  • Потрібно управляти обмеженнями послідовності дій між міграціями. У наведеному вище прикладі ми повинні застосувати на початку міграцію ALTER TABLE, інакше друга міграція не зможе додати вставку equipment type.
Ми обробляємо ці вимоги, привласнюючи кожної міграції порядковий номер. Він діє як унікальний ідентифікатор, і гарантує, що можна підтримувати порядок, в якому вони застосовуються в базі даних. Коли розробник створює міграцію, він поміщає SQL в текстовий файл всередині папки міграції, у межах репозиторію управління версіями проекту. Він дивиться на найвищий використовуваний в даний момент номер в папці міграції, і використовує це число разом з описом, щоб дати ім'я файлу. Сама рання пара міграцій може бути названа 0007_add_insurance_value_to_equipment_type.sql і 0008_data_location_equipment_type.
Для того, щоб відслідковувати застосування міграцій в базі даних, ми використовуємо changelog таблицю. Фреймворки міграції БД, як правило, створюють таблицю та автоматично оновлюють її кожен раз, коли застосовується міграція. Тоді база даних завжди може повідомити з якою міграцією була синхронізація. Якщо ми не використовуємо такий фреймворк, тому що таких не існує, на початку роботи ми автоматизуємо процес з допомогою скрипта.

Рис 2: Таблиця changelog, підтримувана фреймфорком міграції бази даних
З допомогою цієї схеми нумерації, ми можемо відстежити зміни, коли вони застосовуються до того безлічі баз даних, з якими ми працюємо.

Малюнок 3: Цикл скрипта міграції з моменту його створення до деплоя у production
Деякі з цих миграциий, ймовірно, знадобиться реалізувати частіше, ніж міграції, пов'язані з новими компонентами. У цьому сценарії ми помітили, що корисно мати окремий репозиторій міграції або папку для налагодження багів, які належать до даних.

Рис 4: Окремі папки для управління новими змінами компонентів бази даних і виправлень даних у production
Кожну з цих папок можна відстежувати окремо за допомогою інструментів для міграції бази даних: Flyway, dbdeploy, MyBatis або аналогічних. У кожній повинна бути окрема таблиця для зберігання кількості міграцій. Властивість flyway.table в Flyway використовується для зміни назви таблиці, де зберігаються метадані міграції.
Кожен має свій екземпляр бази даних
У більшості компаній-розробників використовується єдина база даних, спільно, усіма працівниками. Можливо, вони використовують окрему базу даних для тестувальників або staging, але принципово обмежують кількість активних баз даних. Спільне використання БД подібним чином — це наслідок того, що копії складно встановлювати і керувати ними. В результаті компанії мінімізують їх кількість. Контроль за тим, на кому відповідальність змінювати схему в таких ситуаціях різний: деякі компанії вимагають, щоб всі зміни робилися командами адміністраторів, інші дозволяють розробникам робити будь-які зміни, а адміністраторів приваблюють, коли зміни переходять на наступний рівень.
Коли ми почали експериментувати з гнучкими проектами, ми помітили, що розробники зазвичай працюють за однією схемою — використовують власну копію коду. Так само як люди вчаться, перебираючи різні варіанти, розробники експериментують з реалізацією компонентів і можуть зробити кілька спроб, перед тим як виберуть потрібну. Потрібно, щоб у них була можливість експериментувати у своєму робочому просторі, а потім завантажувати код в загальне сховище, коли все стабільно. Якщо всі працюють в одному просторі, то неминуче заважають один одному напівготовими змінами. Хоч ми і воліємо безперервну інтеграцію, коли інтеграції відбуваються не частіше ніж через кілька годин, особиста робоча копія відіграє важливу роль. Системи контролю версій підтримують цю роботу, дозволяючи розробникам працювати незалежно і підтримують інтеграцію їх роботи в mainline копію.
Такий поділ працює з файлами, але також може працювати з базами даних. У кожного розробника – свій екземпляр бази даних, який він може вільно змінювати, не впливаючи на роботу інших. Коли їх робота буде готова, вони можуть завантажити і розшарити зміни, і ми це побачимо в наступному розділі.
Ці окремі бази даних можуть бути або окремими схемами на загальному сервері або, що сьогодні зустрічається частіше, окремими базами даних, запущеними на ноутбуці або в терміналі розробника. Десять років тому ліцензування окремих баз даних обходилося надто дорого, сьогодні ж таке зустрічається рідко, в тому числі тому що стали популярні бази даних з відкритим вихідним кодом. Нам здалося зручним запускати базу даних на віртуальній машині розробника. Ми встановили білд бази даних на віртуальній машині, використовуючи Vagrant і "інфраструктура як код", щоб розробник не розбирався в деталях установки БД і не робив вручну.

Рис 5: Проблема використання єдиної схеми бази даних для всієї команди розробників

Рис 6: Кожен член команди отримує свою схему бази даних для розробки і тестування
Багато адміністратори досі сприймають кілька баз даних як зло, яке потрібно уникати із-за складнощів, але ми вважаємо, що можна легко управляти приблизно сотнями екземплярів бази даних. Головне, щоб інструменти дозволяли вам керувати базами даних в тому ж обсязі, що і файлами.
<target name="create_schema"
description="create a schema as defined in the user properties">
<echo message="Admin UserName: ${admin.username}"/>
<echo message="Creating Schema: ${db.username}"/>
<sql password="${admin.password}" userid="${admin.username}"
url="${db.url}" driver="${db.driver}" classpath="${jdbc.classpath}"
>
CREATE USER ${db.username} IDENTIFIED BY ${db.password} DEFAULT TABLESPACE ${db.tablespace};
GRANT CONNECT,RESOURCE, UNLIMITED TABLESPACE TO ${db.username};
GRANT CREATE VIEW TO ${db.username};
ALTER USER ${db.username} DEFAULT ROLE ALL;
</sql>
</target>

Створення схем розробки можна автоматизувати, використовуючи скрипт збірки, щоб зменшити навантаження на адміністраторів. Цю автоматизацію також можна обмежити лише середовищем розробки.
<target name="drop_schema">
<echo message="Admin UserName: ${admin.username}"/>
<echo message="Working UserName:${db.username}"/>
<sql password="${admin.password}" userid="${admin.username}"
url="${db.url}" driver="${db.driver}" classpath="${jdbc.classpath}"
>
DROP USER ${db.username} CASCADE;
</sql>
</target>

Наприклад, розробник приєднується до проекту, перевіряє код і починає встановлювати свою середовище розробки. Він використовує файл-шаблон build.properties і вносить зміни, наприклад встановлюючи Jen в якості db.username, і так далі для інших налаштувань. Після того, як налаштування зроблені, він може просто запустити create_schema і у нього буде своя схема на загальному сервері БД або на сервері БД його ноутбука.
З допомогою створеної схеми, він може запустити скрипт міграції бази даних, щоб зібрати весь вміст БД і наповнити свій примірник БД таблицями, індексів, уявленнями, послідовностями, збереженими процедурами, тригерами, синонімами та іншими специфічними об'єктами бази даних.
Такі сценарії існують і для видалення схем, якщо вони більше не потрібні, або просто тому, що розробник хоче все почистити і почати заново з новою схеми. Середовища баз даних повинні бути фениксами — регулярно згоряти і перебудовуватися при бажанні. При такому підході менше ризиків для накопичення характеристик середовища, не пристосованих до повторення чи перевірки.
Потреба у приватному робочому просторі зручна розробникам, але вона зручна і всьому іншому колективу. QA повинні створювати свої власні бази даних, щоб можна було працювати без ризиків заплутатися в змінах, про яких вони не знають. У адміністраторів повинна бути можливість експериментувати зі своєю копією бази даних, тому що вони експериментують з варіантами моделювання або підвищення продуктивності.
Розробники постійно інтегрують зміни бази даних
Незважаючи на те, що розробники часто експериментують у пісочниці, важливий момент — так само часто інтегрувати зміни, які вони здійснюють через безперервну інтеграцію (CI). CI включає настройку сервера інтеграції, який автоматично збирає і тестує mainline програми. У нас є залізне правило: кожен розробник робить інтеграцію в магістралі, хоча б один раз в день. Серед інструментів, що допомагають з інтеграцією — GoCD, SNAP CI, Jenkins, Bambooand Travis CI.

Рис 7: База даних змінюється, створюються міграції та інтегруються аналогічно кодом програми
На 7 зображенні показаний флоу того, як відбувається розробка міграцій бази даних, локальне тестування, перевірка в системі управління версіями, підхоплення сервером CI і застосування до інтеграційної базі даних, повторне тестування та упаковка для використання.
Давайте подивимося на приклад
1) Джен приступає до розробки, яка включає зміна схеми бази даних. Якщо зміна просте, наприклад, додавання колонки, Джен думає, як внести зміни напряму. Якщо складне, вона знаходить адміністратора БД і обговорює питання з ним.
Після того, як вона з'ясовує що робити зі зміною, вона пише міграцію.
ALTER TABLE project ADD projecttypeid NUMBER(10) NULL;

ALTER TABLE project ADD (CONSTRAINT fk_project_projecttype
FOREIGN KEY (projecttypeid)
REFERENCES projecttype DEFERRABLE INITIALLY DEFERRED);

UPDATE project
SET projecttypeid = (SELECT projecttypeid
FROM projecttype
WHERE name='Integration');

Додавання обнуляемого стовпця — це назад сумісний зміна, тому вона може інтегрувати зміна, не змінюючи код додатка. Але якщо це не назад сумісний зміна, ніби поділу таблиці, то Джен знадобиться змінити код програми.
2) Після того, як Джен закінчить зміни, вона готова до інтеграції. Перший крок — оновлення локальної копії Джен з магістралі. Це ті зміни, які зробили інші члени команди, поки вона працювала над своїм завданням. Потім вона перевіряє свої зміни, працює з оновленнями, пересобирая базу даних і проганяючи всі тести.
Якщо вона стикається з проблемами з-за змін, зроблених іншими розробниками — змін, які конфліктують з її змінами — вона повинна виправити ці проблеми у своїй копії. Як правило, такі конфлікти легко поправити, але іноді вони виявляються заплутаними. Часто такі ускладнені конфлікти ведуть до необхідності обговорення між Джен і її колективом, щоб розібратися в накладках.
Після того, як її локальна копія знову в робочому стані, вона перевіряє, з'явилися додаткові зміни поки вона робила виправлення. Якщо були, Джен потрібно повторити інтеграцію з новими змінами. Зазвичай відбувається не більше одного або двох подібних циклів, перед тим, як її код повністю інтегрується в магістралі.
3) Джен пушит зміни в магістралі. Оскільки зміна назад сумісний з існуючими кодом програми, вона може інтегрувати зміни бази даних перед оновленням коду програми — це звичайний приклад Parallel Change.
4) Сервер CI виявляє зміни в магістралі і починає нову збірку, яка містить міграцію бази даних.
5) Сервер CI використовує свою копію бази даних для складання, тому застосовує скрипт міграції бази даних до бази даних, щоб провести зміни в міграції. Крім того, він запускає інші кроки складання: компілювання, модульні тести, функціональні тести і подібні.
6) Після того, як збірка успішно завершується, сервер CI пакетирует артефакти складання і передає їх. Артефакти складання містять скрипти міграції бази даних, для застосування їх до баз даних у downstream середовищах, таких як Deployment Pipeline. Артефакти збірки також містять код програми, пакетований в jar, war, dll і інші.
Саме такий метод безперервної інтеграції зазвичай використовується в управлінні вихідним кодом програми. Вищевказані кроки показують, що код бази даних розглядається як частина вихідного коду. Подібний код БД — DDL, DML, Data, вибірки, події, що ініціюють процедуру, збережені процедури — знаходяться під управлінням конфігурації, так само як і вихідний код. Кожен раз, коли відбувається успішна збірка, збираючи артефакти БД і артефакти програми в єдине, ми отримуємо повну синхронізовану історію версій як програм, так і баз даних.
Маючи вихідний код програми, більшу частину мук від інтеграції із змінами можна ліквідувати, якщо використовувати системи управління вихідним кодом і різні тести локальних середовищах. Щодо баз даних зусиль застосовується трохи більше, тому що в базі даних є дані (стану), які повинні зберігати своя бізнес логіка. (Ми поговоримо докладніше про автоматизованому рефакторинге бази даних пізніше). Крім того, адміністратор БД повинен стежити за будь-якими змінами БД і переконуватися, що вони вписуються в загальну картину схеми бази даних і архітектуру даних. Щоб все це працювало, великі зміни не повинні бути сюрпризом в момент інтеграції, тому адміністраторам потрібно тісніше співпрацювати з розробниками.
Ми наполягаємо на більш частих інтеграції, тому що зрозуміли, що набагато простіше робити безліч невеликих інтеграцій, а не рідкісні великі, це той випадок, коли Частота Знижує Складність. Борошна від інтеграції ростуть експоненціально зі збільшенням обсягу інтеграції, так що безліч невеликих змін виявляються набагато легше на практиці, навіть якщо це здається багатьом нелогічним.
База даних складається з схеми і даних
Коли ми говоримо про бази даних, ми маємо на увазі не тільки схему бази даних і її код, але і значна кількість даних. Ці дані складаються з звичайних обов'язкових даних додатки, таких як незмінний список всіх держав, країн, валют, типів адрес і різних специфічних даних. Ми також можемо включити деякі зразки тестових даних, наприклад, кілька шаблонів клієнтів, замовлень і т. д. Ці дані-зразки не потраплять у production, якщо тільки спеціально не потрібні для тіста працездатності або семантичного моніторингу.
Ці дані існують з кількох причин. Основна причина — запуск тестування. Ми віддані шанувальники використання значного набору автоматизованих тестів, для стабілізації розробки програми. Такий набір тестів — поширений підхід гнучких методів. Щоб такі тести проходили ефективно, має сенс працювати над базою даних, яка заповнена тестовій інформацією, яку всі тести очікують побачити.
Ці зразки даних повинні управлятися версіями, щоб знати, де їх знайти, коли знадобиться заповнити нову базу даних, тому у нас є запис змін, яка синхронізується з тестами та кодом програми.
Зразок тестових даних дозволяє тестувати міграції, коли змінюється схема бази даних і допомагає тестувати код. Коли є тестові дані, ми просто змушені стежити за тим, що будь-які зміни схеми також обробляють зразки даних.
У більшості проектів, які ми бачили, ці зразки даних були фіктивними. Але попалося кілька проектів, де використовувалися реальні дані. В цих випадках дані були витягнуті з передували успадкованих систем з автоматизованими скриптами перетворення даних. Очевидно, що конвертувати всі дані відразу ж неможливо, тому що в попередніх ітераціях збирається тільки маленька частина нової бази даних. Але ми можемо використовувати Incremental Migration для розробки скриптів перетворення і отримати необхідні дані вчасно.
Це не тільки допоможе позбутися від проблем перетворення даних на ранніх етапах, це спростить роботу зі зростаючою системою вузьким фахівцям, оскільки вони знайомі з даними, на які вони дивляться, і часто можуть допомогти виявити скрипти, що викликають проблеми з базами даних і архітектурою додатків. В результаті ми прийшли до висновку, що потрібно намагатися вводити реальні дані з самої першої ітерації проекту. Jailer здався нам корисним інструментом у такому процесі.
Усі зміни бази даних — це рефакторинг бази даних
Зміни, які ми робимо в базі даних, змінюють спосіб зберігання в ній інформації, встановлюють нові способи зберігання або видаляють сховище, яке більше не потрібно. Але ні одна із змін бази даних, саме по собі, не змінює загальну поведінку програми. Отже, ми можемо розглядати їх як підходять під визначення рефакторінгу.
зміна, внесена у внутрішню структуру програми, яка робить його більш зрозумілим і легко змінюваним, без зміни його спостережуваного поведінки
Визнаючи це, ми зібрали і задокументували безліч рефакторингов. Складаючи каталог, ми пропонуємо полегшені шляхи для коректних змін, так як ми можемо слідувати кроків, які ми успішно робили раніше.
Одне з найбільш помітних відмінностей в рефакторингах бази даних у тому, що вони включають три різні зміни, які мають відбуватися одночасно.
  • Зміна схеми бази даних
  • Міграція даних в базі даних
  • Зміна коду доступу до бази даних
Таким чином, коли ми описуємо рефакторинг бази даних, ми повинні описати всі три аспекти змін і переконатися, що всі три застосовуються, перед тим як застосовувати інші рефакторинги.
Як і рефакторинг коду, рефакторинги бази даних дуже маленькі. Ідея збору груп маленьких змін в послідовності, точно така ж як і у випадку з кодом. Тривимірний характер змін робить таку практику більш важливою.
Багато рефакторинги бази даних, на зразок додати нову колонку, можна робити без оновлення всього коду, що має доступ до системи. Якщо код буде використовувати нову схему, не знаючи про цю схему, колонка просто не буде використовуватися. У багатьох змін, правда, немає такої властивості і ми називаємо їх деструктивними. Деструктивним змінам потрібно трохи більше уваги, ступінь якого залежить від ступеня деструктивності.
Прикладом незначного деструктивного зміни служить зробити колонку non nullable, яке перетворює колонку, допускає значення null, не допускає таке значення. Деструктивне воно тому, що якщо будь-який існуючий код не встановить її значення, то ми отримаємо повідомлення про помилку. У нас також виникнуть проблеми, якщо в існуючих даних присутні null.
Ми можемо уникнути проблем з існуючими нулями (ціною трохи інших проблем), привласнюючи базові дані будь-яким рядів, що містять нулі. Для проблеми не присвоєння (або присвоєння нуля) у нас є два варіанти. Один з них встановити для колонки значення за замовчуванням.
ALTER TABLE customer
MODIFY last_usage_date DEFAULT sysdate;

UPDATE customer
SET last_usage_date =
(SELECT MAX(order_date) FROM order
WHERE order.customer_id = customer.customer_id)
WHERE last_usage_date IS NULL;

UPDATE customer
SET last_usage_date = last_updated_date
WHERE last_usage_date IS NULL;

ALTER TABLE customer
MODIFY last_usage_date NOT NULL;

Інший — змінювати код програми під час рефакторінгу. Ми воліємо такий варіант, якщо можемо гарантовано мати доступ до всього кодом, який оновлює базу даних, що зазвичай легко зробити, якщо база даних використовується тільки одним додатком, і важко, якщо вона спільна.
Більш складний випадок — поділ таблиці, зокрема, якщо доступ до таблиці раскидан по всьому коду програми. Якщо випадок саме такий, потрібно щоб всі знали, що скоро буде зміна і могли підготуватися до нього. Обдуманим вчинком буде почекати спокійного моменту, наприклад, початку ітерації.
Будь-деструктивне зміна набагато простіше, якщо доступ до бази даних прокладений через кілька модулів системи. Так легше знайти і оновити код доступу до бази даних.
загалом, найголовніше вибрати процедуру, оптимальну саме для того виду змін, які робите ви. Якщо сумніваєтеся, спробуйте перейти на бік спрощення змін. З досвіду ми обпікалися рідше, ніж думають інші, і маючи суворе конфігураційне управління всією системою не важко відкотитися назад, у випадку самого страшного сценарію.
Фаза переходу
Ми вже згадували ті труднощі, які з'являються, коли ми стикаємося з деструктивним рефакторінгом бази даних і не можемо легко змінити код доступу. У цих проблем ростуть роги та ікла, коли у вас база даних загальна і, можливо, її використовує безліч додатків і звітів. В такому разі вам потрібно серйозніше подбати про те, начебто перейменування таблиці. Щоб убезпечити себе від рогатих проблем, звернемося до фази переходу.
Фаза переходу — це період часу, коли база даних одночасно підтримує і старий шаблон доступу, і нові. Це дає більш старих систем час мігрувати на нові структури з їх власною швидкістю. (Турбота про зміни в базі даних, включаючи DDL, DML і міграції даних у процесі розробки, забезпечує максимальний сенс для групи даних, уникаючи пакетної міграції всіх змін групи даних під час деплоя без контексту.)

Рис 8: Рефакторинг бази даних, застосований до успадкованої базі даних і фази, які вона повинна пройти перед реалізацією
ALTER TABLE customer RENAME to client;

CREATE VIEW AS customer
SELECT id, first_name, last_name FROM client;

Для прикладу перейменуванням, розробник може створити скрипт, який перейменовує таблиці customer в таблицю client, а також створює вибірку customer, яку можуть використовувати існуючі програми. Це паралельне зміна підтримує новий і старий доступ. Правда він додає складність, тому важливо його видалити коли прийде час міграції у downstream системи. У деяких компаніях це можна зробити за кілька місяців, а в деяких таке може зайняти роки.
Вибірки – це один метод для здійснення фаз переходу. Ми також використовуємо перемикаючі події бази даних, які зручні для таких випадків, як перейменування колонки.
Автоматизація рефакторингов
Оскільки рефакторинг став популярним для коду програми, багато мови отримали хорошу підтримку для автоматичних рефакторингов. Автоматизація спрощує і прискорює рефакторинг швидким виконанням різних кроків без втручання людини і тому виключає людські помилки. Така автоматизація також існує для баз даних. Фреймфорки зразок LiquiBase і Active Record Migrations дозволяють використовувати DSL для застосування рефакторингов бази даних, що дозволяє застосовувати міграції баз даних стандартним способом.
Але такі види стандартизованих рефакторингов не дуже підходять для баз даних, так як правила роботи з міграцією даних і успадкованими даними дуже сильно залежать від специфічної практики команди. А ми воліємо проводити рефакторинг бази даних за допомогою скриптів міграції та фокусуємося на інструментах автоматизації.
Ми пишемо кожен скрипт, як ви бачили, об'єднуючи SQL DDL (для зміни схеми) і DML (для міграції даних) і поміщаємо результат в репозиторій. Автоматизація у нас гарантує, що ми ніколи не застосуємо ці зміни вручну, лише за допомогою засобів автоматизації. Таким способом ми підтримуємо порядок рефакторингов і оновлюємо метадані бази даних.
Ми можемо застосовувати ці рефакторинги до будь-якого стану бази даних, щоб тримати їх синхронізованими з останньої робочої або будь попередньою версією. Інструмент використовує метаінформацію з бази даних, щоб дізнатися поточну версію, а потім застосовує кожен рефакторинг між знайденою і необхідної версією. Ми можемо використовувати цей підхід для оновлення версій розробки, версій тестування і баз даних у production.
Оновлення БД у production нічим не відрізняється від тестування БД, ми застосовуємо один і той же набір скриптів до різних даних. Ми воліємо робити часті релізи, тоді поновлення залишаються дрібними, а значить протікають значно швидше і вирішувати будь-які виникаючі проблеми легше. Найпростіший спосіб робити ці оновлення, відключати БД production поки оновлення застосовуються, це працює в більшості ситуацій. Можна застосовувати оновлення та за активної БД, але про методи такого підходу доведеться написати окрему статтю.
Крім автоматизації майбутніх змін, можна обміркувати можливість автоматизації зворотних змін для кожного рефакторінгу. В цьому випадку у вас буде можливість звернути зміни в базі даних таким автоматизованим способом. Ми не довели економічну ефективність і достатню користь цієї методики, до того ж, у ній не виявилося гострої потреби, але тут працює той самий основний принцип. Зазвичай ми намагаємося писати міграції так, щоб фрагмент доступу до БД міг працювати як із старою, так і з новою версією бази даних. Це дозволяє оновлювати БД, підтримуючи майбутні потреби і тримати її в активному стані, залишати її запущеної в production, і тільки потім, як тільки ми побачимо, що все працює без проблем, завантажувати оновлення, яке використовує нові структури даних.
Інструментів, які автоматизують застосування міграцій БД, сьогодні багато, серед них Flyway, LiquiBase, міграції MyBatis, DBDeploy. Ось застосування міграції з Flyway.
psadalag:flyway-4 $ ./flyway migrate
Flyway 4.0.3 by Boxfuse

Database: jdbc:oracle:thin:@localhost:1521:xe (Oracle 11.2)
Successfully validated 9 migrations (execution time 00:00.021 s)
Creating Metadata table: "JEN_DEV"."schema_version"
Current version of schema "JEN_DEV": << Empty Schema >>
Migrating schema "JEN_DEV" to version 0 - base version
Migrating schema "JEN_DEV" to version 1 - asset
Migrating schema "JEN_DEV" to version 2 - asset type
Migrating schema "JEN_DEV" to version 3 - asset parameters
Migrating schema "JEN_DEV" to version 4 - inventory
Migrating schema "JEN_DEV" to version 5 - split inventory
Migrating schema "JEN_DEV" to version 6 - equipment type
Migrating schema "JEN_DEV" to version 7 - add insurance value to type equipment
Migrating schema "JEN_DEV" to version 8 - data location equipment type
Successfully applied 9 migrations to schema "JEN_DEV" (execution time 00:00.394 s).
psadalag:flyway-4 $ 

Розробники можуть оновлювати свої бази даних на вимогу.
Як пояснювалося вище, перший крок інтеграції змін в mainline — витягти будь-які зміни, що сталися поки ми виконували свою частину роботи. Це не тільки основна частина стадії інтеграції, вона часто буває корисною, перед тим, як ми закінчимо, тому що тоді ми зможемо оцінити вплив будь-яких змін, про які говорили колеги. В обох випадках головне — мати можливість легко витягнути зміни з mainline і застосувати їх до своєї локальної бази даних.
ми пуллим зміни в свій робочий простір. Зазвичай це досить просто, але іноді виявляється, що хтось із колег завантажив міграцію в mainline поки ми працювали над своєю. Якщо ми писали міграцію з ідентифікатором 8, ми побачимо як інша міграція з цим же номером з'явиться в папці міграцій. Інструмент міграції повинен це виявити.
psadalag:flyway-4 $ ./flyway migrate
Flyway 4.0.3 by Boxfuse

Database: jdbc:oracle:thin:@localhost:1521:xe (Oracle 11.2)
ERROR: Found more than one migration with version 8
Offenders:
-> /Users/psadalag/flyway-4/sql/V8__data_location_equipment_type.sql (SQL)
-> /Users/psadalag/flyway-4/sql/V8__introduce_fuel_type.sql (SQL)
psadalag:flyway-4 $

Як тільки ми помітимо конфлікт, перший крок буде простим: нам потрібно пронумерувати свою міграцію у 9, тоді вона переприменится поверх нової міграції в магістралі. Після перенумерації потрібно протестувати існуючі міграції на конфлікт. Для цього потрібно почистити базу даних, а потім застосувати всі міграції, включаючи нову 8 і свою перенумерованную 9 до порожньої копії БД.
psadalag:flyway-4 $ mv sql/V8__introduce_fuel_type.sql sql/V9__introduce_fuel_type.sql
psadalag:flyway-4 $ ./flyway clean
Flyway 4.0.3 by Boxfuse

Database: jdbc:oracle:thin:@localhost:1521:xe (Oracle 11.2)
Successfully cleaned schema "JEN_DEV" (execution time 00:00.031 s)
psadalag:flyway-4 $ ./flyway migrate
Flyway 4.0.3 by Boxfuse

Database: jdbc:oracle:thin:@localhost:1521:xe (Oracle 11.2)
Successfully validated 10 migrations (execution time 00:00.013 s)
Creating Metadata table: "JEN_DEV"."schema_version"
Current version of schema "JEN_DEV": << Empty Schema >>
Migrating schema "JEN_DEV" to version 0 - base version
Migrating schema "JEN_DEV" to version 1 - asset
Migrating schema "JEN_DEV" to version 2 - asset type
Migrating schema "JEN_DEV" to version 3 - asset parameters
Migrating schema "JEN_DEV" to version 4 - inventory
Migrating schema "JEN_DEV" to version 5 - split inventory
Migrating schema "JEN_DEV" to version 6 - equipment type
Migrating schema "JEN_DEV" to version 7 - add insurance value to type equipment
Migrating schema "JEN_DEV" to version 8 - data location equipment type
Migrating schema "JEN_DEV" to version 9 - introduce fuel type
Successfully applied 10 migrations to schema "JEN_DEV" (execution time 00:00.435 s).
psadalag:flyway-4 $

Зазвичай це працює на ура, але періодично трапляються конфлікти, просто тому, що хтось з розробників перейменував таблицю, в яку ми вносили зміни. У такому випадку потрібно з'ясувати, як вирішити конфлікт. Тут і відкривається цінність невеликих міграцій: з ними легше виявити і розібратися з конфліктами.
Як тільки зміни бази даних інтегровані, потрібно повторно запустити пакет тестів, на випадок, якщо міграція з магістралі призведе до поломки якого-небудь тесту.
Ця процедура дозволяє нам працювати незалежно один від одного короткими проміжками, навіть без підключення до мережі, а потім інтегрувати, коли нам це зручно. Коли і як часто ми робимо цю інтеграцію, повністю залежить від нас, за умови, що ми синхронізувалися перед завантаженням в магістралі.
Чітко розділити весь код доступу до бази даних
Для того, щоб зрозуміти наслідки рефакторингов бази даних, потрібно бачити, як база даних використовується додатком. Якщо SQL розкиданий як попало по базі вихідного коду, це зробити дуже важко. Тому дуже важливо мати чистий рівень доступу до бази даних, показує, де і як вона використовувалася. Для цього ми радимо слідувати одному з структурних патернів сховища даних з книги Patterns of Enterprise Application Architecture.
Наявність чистого рівня бази даних має кілька цінних побічних переваг. Він мінімізує кількість блоків у системі, управляти якими можуть тільки розробники зі знанням SQL, і полегшує життя тим розробникам, які часто не дуже кваліфіковані в SQL. Адміністратору він дає чистий блок коду, в якому той може побачити, як використовувалася база даних. Це допомагає готувати індекси, оптимізувати базу даних, і розглядати SQL, щоб зрозуміти, як її можна змінити для кращої роботи. Це дозволяє адміністратору бази даних краще розуміти, як використовується база даних.
Робіть більше релізів
Коли ми писали першу версію цієї статті більше десяти років тому, концепція більш частого релізу софта мала мало підтримки. Але зростання інтернет-гігантів показав, що часті релізи — ключова частина успішної стратегії цифрової індустрії.
Для кожної зміни зафіксованого в міграції, ми можемо легко задеплоить нові зміни у тестовій і production середовищі. Той тип еволюційного проектування баз даних, який ми обговорюємо тут, одночасно дозволяє робити часті релізи, а також отримує користь з фідбек, одержуваного від реального використання софта.
Варіації
Як і будь-який інший набір методів, вони повинні бути різноманітними в залежності від обставин, ось деякі з тих, з якими ми зіткнулися.
Кілька версій
Простий проект може вижити тільки з єдиною гілкою, а значить, однією версією бази даних. У більш складних проектах потрібна підтримка декількох версій для AB тестування або запуску деплоев коли відбуваються Canary Releases і, отже, декількох різновидів баз даних проекту. Кожному релізу можуть вимагатися свої тестові дані, зміни для тестування конкретного компонента або виправлення певних багів. Це нічим не відрізняється від управління декількома версіями коду production, але з невеликою родзинкою, суть якої в тому, що база даних повинна підтримувати декілька релізів програми.
Ще один метод, який ми вважаємо корисним — єдиний репозиторій для бази даних і всіх інших версій програми, що залежать від сховища бази даних. Вам потрібно контролювати, що всі версії коду працюють з тією ж версією бази даних, а значить, форсувати базу даних мати зворотну сумісність з усіма попередніми версіями програм, які знаходяться у production.
Доставка змін з додатком
В деяких проектах ми вже бачили, що зміни застосовані до продукту повинні бути поширені серед тисяч кінцевих споживачів. У таких видах проектів краще давати додатком оновлювати себе самому, пакетуванням всіх змін бази даних разом з додатком (тому що ми не маємо навіть приблизного уявлення з якої версії оновлюється клієнт), і дати додатком оновити базу даних при запуску, використовуючи фреймворки, наприклад, [Flyway]http://flywaydb.org/ або один з його численних подоб.
Кілька додатків, що використовують одну базу даних
У багатьох корпораціях безліч додатків виявляються в результаті з однією загальною базою даних — патерн інтеграції Shared Database. В таких ситуаціях, коли один додаток вносить зміна в базу даних, цілком ймовірно, що зміна зламає інші додатки. Щоб уникнути цього, краще витягнути базу даних, яка використовується всіма залежними додатками, у вигляді окремого сховища коду. Цей загальний репозиторій бази даних повинен бути покритий автоматизованими поведінковими тестами, які дають впевненість, що перехресні залежності додатків протестовані, і зупиняти збірку, якщо залежні додатки порушені. Це не відрізняється від варіанту, коли є расшаренный програмний компонент, зі своїм сховищем коду.
NoSQL бази даних
Наша стаття концентрується на реляційних базах даних почасти тому, що оригінал був про них, почасти тому, що досі ми переконуємося в їх більшій поширеності. І ми, можна сказати, знайомі з NoSQL базами даних, які останнім часом стали більш поширеними. Повноцінне обговорення того, як їх обслуговувати еволюційним шляхом, тягне на ще одну статтю, але ми спробуємо дати їм поверхневий огляд.
Бази даних NoSQL заявлені як інструменти краще пристосовані до еволюційного шляху, оскільки більшість з них "бессхемные". Але їх бессхемность не позбавляє нас від необхідності обслуговувати схеми, оскільки неявна схема в них існує. Будь-код, що має доступ до бази даних, побічно висловлює таку схему. Цією схемою потрібно управляти, фактично використовуючи ті ж методи міграції даних в репозиторії вихідного коду. Відсутність схеми зберігання дає нам іншу техніку для підтримки декількох стратегій читання різних версій. Це може спростити управління еволюцією баз даних, але нам ще є про що турбуватися.
Вам не потрібна армія адміністраторів БД
Використання перерахованих методів по відчуттях вимагає багато роботи, але по факту не вимагає гігантського колективу. У багатьох проектах у нас було по тридцять з гаком розробників, а у всій команді (включаючи QA, аналітиків і управляючих) було близько сотні співробітників. В будь-який день у нас з'являлося близько сотні примірників різних схем, зібраних на персональних робочих станціях. При цьому вся активність вимагала одного повного робочого дня адміністратора та кількох розробників, які розуміють робочий процес і послідовність, які виконували б часткову підтримку і перевірку.
У невеликих проектах не потрібно навіть таке. Ми використовували такі методи в невеликих проектах (близько десяти чоловік), і зрозуміли, що в повному робочому дні адміністратора немає необхідності. Замість цього ми покладаємося на пару розробників, цікавих до проблем БД, які виконують завдання адміністратора парт-тайм і, в разі необхідності, залучаємо адміністраторів, щоб прийняти рішення по дизайну або архітектурі.
Це можливо завдяки автоматизації. Якщо ви вирішили автоматизувати всі завдання, ви можете виконувати багато роботи, не задіюючи великої кількості людей. Особливо коли такі інструменти як DevOps і схожі (Puppet, Chef, Docker, Rocket, and Vagrant) стали популярними.
З тих пір, як ми працюємо в цьому стилі багато років, ми вирішили покладатися на бази даних, які можуть еволюціонувати так само, як код програми, учащать цикли релізів і рухати софт в production швидше. Описані методи тепер — частина нашого звичного способу роботи. Але наша мета не тільки поліпшити власні методи, але і поділитися своїм досвідом з програмною індустрією. Чим більше подібних технік освоюють інші, тим більше софта реалізує потреби людей, а прогрес, який досягається з допомогою такого софту збагачує життя в цілому.
(Переклад Наталії Басс)
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.