неделя, ноември 14, 2010

Database Version Control за PHP програмисти

За разлика от version control системите за source code като svn или git, доста по-малко са познати подобните за бази данни.
До сега съм виждал няколко подхода:

1) На който му трябва най-новата база данни по която работим - да се оправя.
В една папка в svn-a, с оригиналното име "sql"q всеки който прави промени направо слага пълен експорт на неговата си база данни, като файла задължително се казва нещо от типа -
project-20100618(stefka).sql
+ освен ти сам, няма кой друг да ти счупи базата данни
- много, наистина много файлове за малко време, ровене
- трудна промяна на отделни полета в таблица


2) Правил си промени по базата данни - хайде сега да ги добавиш в един файл. 
Същото като в предишния вариант, но файла е само един и всеки добавя само промените, които е направил.Файла е просто project.sql
+ относително лесно се вижда какво е променяно след като се пусне един diff (или WinMerge)
- голямо ровене става из тоя файл
- всеки го мързи да merge-ва файлове в следствие на което никой не качва промените си, докато не е твърде наложително

3) Ще правиш промени ? Я затвори тоя phpmyadmin!
Начина заради който пиша тоя пост, въобще. Не пишеш sql, не ползваш някой database designer - а създаваш таблици  и описваш промени чрез php.
Става въпрос за ruckusing. Да покажа направо..
пишеш нещо такова в конзолата (не само за Linux):

php generate.php createUsersTable
което генерира един файл с два метода - up() и down()
и в него пишем нещо като:

function up(){
   $table = $this->create_table('users');
   $table->column('username', 'string', array('null'=>false));
   $table->column('password', 'string', array('null'=>false));
   $table->finish();
}
и съответно
function down(){
   $this->drop_table('users');
}

Единия казва какво трябва да се случи ако качваме revision нагоре, другия какво трябва да се направи за да се върнем в изходно положение.

Влизаш обратно в конзолата и изпълняваш:
php main.php db:migrate
и таблицата се създава. Имаш методи за създаване и премахване на - бази данни, таблици, колони в таблица и т.н., които покриват 99% от необходимата функционалност. За всичко останало имаш прекрасния метод query, които праска чист sql.

Защо ги правим всички тия финтове?
Когато commit-на генерираните файлове, колегата изпълнява и при него db:migrate и вече е с последната версия. Това е, без повече главоболия. Ако по някаква причина съм счупил нещо, на db:migrate му казваш - Абе, я ме върни 1 revision назад и всичко е песен.

- Има хипотетичен шанс да счупиш нещо на другарчето
+ Бързо е
+ Лесно е
+ Готино е
+ Модерно е ;)
Можете да видите още примери тук - http://code.google.com/p/ruckusing/wiki/CompleteExamples


Малко безполезно инфо:
Доста време търсих нещо подходящо, което да замени първите 2 начина на работа и дори мислех да започна да си пиша сам нещо такова.
Моята идея беше да се проверяват разликите между 2 export-а в xml формат и да се генерира само sql кода, който да докара първата база данни до втората. Тоест ако имаме в една таблица, която експортирана изглежда така:

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
)
и друга
CREATE TABLE  `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
)

В такава ситуация, понеже съм мързелив човек, директно drop-вам моята таблица и paste-вам новия код. За да си спестя глупостите и да не се налага наново да си импортирам данните, моята система трябваше да генерира един sql файл за миграция, който да съдържа:
ALTER TABLE  `users` ADD  `email` VARCHAR( 255 ) NOT NULL
Аз да си го изпълня и всичко да си е ок.

За мен лично, този вариант е по-добър от ruckusing, дори и само заради това че ми е странно да си пиша таблиците на php. Все пак прецених, че не е чак толкова по-готино, че да си загубя няколко дена да го напиша. Ако някой го радва и му се губи време, да драсне.