Refaktoryzacja baz danych na produkcji

Jako że jestem na świeżo po lekturze książki Refactoring Databases, która stanowiła główny materiał do mojej pracy magisterskiej dot. oceny przekształceń to też postanowiłem podzielić się z wami kilkoma ciekawostkami o procesie refaktoryzacji. Właściwie w tym wpisie poruszę wyłącznie kwestię w jaki sposób wdrażać zmiany w schemacie bazy danych na środowisku produkcyjnym bazując na sugestiach autorów książki.

Pierwsza rzecz, która rzuciła mi się w oczy po lekturze to to, że wcale ten żmudny i długotrwały proces refaktoryzacji wcale nie musi być jakoś niezwykle trudny i ryzykowny. Oczywiście wprowadzanie zmian na produkcji, a już w szczególności tam gdzie trzymamy dane nie jest sielanką i zawsze niesie pewne niebezpieczeństwa. Niemniej stosując się do opisanych tutaj wskazówek można to ryzyko zminimalizować. Zacznijmy od tego, że zanim wykonamy refaktoryzacje to musimy ją odpowiednio przetestować i to w dodatku nie raz. Potrzebujemy w tym celu kilku środowisk z bazą danych. Programista opracowujący refaktoryzacje potrzebuje własnego serwera bazy danych na wyłączność, to jasne. Osobnego środowiska będzie potrzebował zespół takiego dewelopera, który z kolei dokonuje integracji całej aplikacji z taką poprawką. Podobnie jak zespoły QA, product owner na UAT itp. Zatem kolejna istotna sprawa to automatyzacja wdrażania takiej bazy danych, każde środowisko musi instalować najnowsze poprawki bazy danych całkowicie niezależnie od użytkownika. Gdy przy tym jesteśmy to warto wspomnieć o wersjonowaniu bazy danych, tj. posiadaniu zestawu narzędzi, które będą w stanie nam zapewnić monitorowanie zmian na bazie oraz zdolność do ich wycofywania (patrz np. Doctrine Migrations). Posiadać powinniśmy również szereg różnego rodzaju automatycznych testów regresyjnych czy integracyjnych. Natomiast samo opracowanie refaktoryzacji zdaniem autorów książki warto wykonać w duchu TDD, gdzie np. opracowujemy test sprawdzający istnienie refaktoryzowanych kolumn czy kluczy obcych działając przy tym iteracyjnie. Całość tego procesu dopełniają wyzwalacze, których zadaniem jest utrzymywać produkcyjną bazę danych jednocześnie w dwóch stanach (przed i po refaktoryzacji). W momencie, w którym uznamy że wszystkie dane poprawnie się przeniosły do nowego schematu, można stary schemat i wyzwalacze usunąć. Poniżej przykład takiego wyzwalacza dla przekształcenia podziału na kolumny (zmieniamy kolumnę nazwa na imię i nazwisko).

CREATE OR REPLACE TRIGGER SynchronizacjaNazwyUzytkownika
BEFORE INSERT OR UPDATE
ON Uzytkownicy
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
DECLARE
BEGIN
IF :NEW.Imie IS NULL THEN
:NEW.Imie := pobierzImie(Nazwa);
END IF;
IF :NEW.Nazwisko IS NULL THEN
:NEW.Nazwisko := pobierzNazwisko(Nazwa);
END IF;
END;

W tej sytuacji, gdy będzie dodawany lub aktualizowany rekord z nazwą użytkownika jednocześnie zostaną zaktualizowane nowo wprowadzone kolumny imie i nazwisko (o ile poprawnie zaimplementujemy funkcje wyłuskujące takie dane, tutaj pobierzImie, pobierzNazwisko). W kolejnej iteracji będzie można usunąć kolumnę nazwa.

Ostatnią istotną kwestią jest znalezienie właściwego “okna” czasowego na przeprowadzenie zmian na bazie produkcyjnej i poinformowanie o takim terminie wszystkich zainteresowanych. Najlepiej by to był czas względnego spokoju, gdy baza nie jest nadzwyczaj obciążona, w szczególności gdy używamy chmurowych środowisk bazodanowych w klastrze 😉

aaa i pamiętajcie, zawsze warto mieć kopie! Powodzenia!