Znów o migracji baz danych słów kilka

Kiedyś twierdziłem, że migracja bazy danych składa się z migracji struktury i migracji danych. Z tym akurat trudno się sprzeczać, ale co gorsza twierdziłem, że to są osobne sprawy i można je załatwić przy pomocy osobnych narzędzi.
Otóż zmieniłem zdanie i twierdzę, że należy mieć jedno narzędzie.

Oto przykład. Wyobraź sobie System Rezerwacji Czegokolwiek ;) Możesz tam zarezerwować na przykład stolik w restauracji, albo koparkę gdy przebudowujesz swój ogród.

System do tej pory, dla każdego rodzaju rezerwacji wyliczał status rezerwacji (nowa, w trakcie, zakończona) w sposób dynamiczny. Rezerwacja stolika w restauracji jest zakończona, kiedy w systemie widnieje płatność za posiłek. Dla koparki to już za mało: musi zostać wystawiona faktura, istnieć przelew, a poza tym musi zostać dołączony dokument odbioru sprzętu w dobrym stanie.

Teraz okazuje się, że warto (ze względu na wydajność) zapisywać status jako cache, aby nie musieć wyliczać go za każdym razem. Rozważmy teraz dwa podejścia do migracji.

System z niskim (albo żadnym) poziomem abstrakcji, czyli pliki sql…

Masz dobre narzędzie, w którym możesz przeprowadzić migrację struktury bazy. Bez problemu napiszesz zapytanie alter table, dodasz pole. Jednak jeśli chcesz w tym samym systemie zmigrować dane (czyli dla wszystkich istniejących już rezerwacji na produkcji wyliczyć status i ustawić go w nowym polu) masz dwa wyjścia.

Albo napiszesz logikę biznesową odpowiadającą za wyliczanie statusów po raz drugi, albo napiszesz osobny skrypt, który będzie miał dostęp do obiektów biznesowych, gdzie zwyczajnie wywołasz metodę i jej wynik zapiszesz w nowym polu.

Pierwsze rozwiązanie jest oczywistą stratą czasu, no i oczywiście ryzykujesz wprowadzenie nowych błędów do systemu. W drugim przypadku, musisz zapamiętać że przy wdrożeniu nowego rozwiązania należy odpalić skrypt migracji. Jedna migracja z drugą nie są powiązana, a być powinny – uruchomienie jednej bez drugiej, albo w osobnej kolejności nie ma sensu.

Liquidbase

Tu warto wspomnieć o systemach, które wprowadzają pewien poziom abstrakcji (np. liquidbase), jednak jest to jedynie abstrakcja od silnika bazy danych. Nadal niestety nie mają one dostępu do obiektów biznesowych.

System o wysokim poziomie abstrakcji, zintegrowany z całą aplikacją

Oczywiście mam tu coś konkretnego na myśli. Najlepszym przykładem jaki znam są migracje w Ruby on Rails. Rozwiązanie wyglądałoby mniej więcej tak (pseudoPHPkod)

 class Migration1 {
   function up() {
     /* struktura */
     dodaj_pole_do_tabeli("rezerwacja", "status", "integer");
     /* dane */
     $rezerwacje = pobierz_wszystkie_rezerwacje(); //2
     foreach($rezerwacje as $rezerwacja) {
         $rezerwacja->status = $rezerwacja->wyliczStatus(); 
         $rezerwacja->zapisz();
     }
   }
   function down(){
     usun_pole_z_tabeli("rezerwacja", "status")
   }
 }

Widać tu wyraźnie, że migracja jest jednym spójnym krokiem. Migracja struktury i następująca zaraz po niej migracja danych. Sama klasa migracji ma bezpośredni dostęp do warstwy logiki biznesowej i może z niej bez przeszkód korzystać.

Piszę to dlatego, ze próbowałem pierwszego sposobu, gdyż jest on łatwiejszy w implementacji, gdy twój framwork nie ma zaimplementowanego sposobu drugiego. I przekonałem się, że warto albo zmienić framework na taki, który oferuje sposób drugi. Albo włożyć więcej energii w dostosowanie środowiska pracy aby jednak migracje były na wysokim poziomie abstrakcji.

Share Button

Leave a Reply

Your email address will not be published. Required fields are marked *