W wielu podejściach do tworzenia oprogramowania, takich jak metodyki zwinne, projektowanie oparte na domenie oraz analiza i projektowanie zorientowane obiektowo, zachęcamy do stosowania jednego iteracyjnego podejścia do programowania.
Dlatego nie powinniśmy robić naszego modelu domeny poprawnie przy pierwszym uruchomieniu projektu. W miarę upływu czasu zmieniamy model, ponieważ z czasem lepiej rozumiemy dziedzinę problemową.
Poza tym, nawet jeśli staramy się uzyskać idealny model z góry, co, jak już jestem przekonany, jest bardzo trudne, wymagania mogą się zmienić. Więc po program został wdrożony do produkcji, użytkownicy końcowi mogą zauważyć, że pewien wymóg nie został do końca poznany, lub, co gorsza, niektóre wymóg brakowało.
Chodzi o to, że po wdrożeniu oprogramowania może się okazać, że będziemy musieli zmienić model. Jeśli tak się stanie, mamy problem: produkcyjna baza danych zawiera ważne dane użytkownika i jest już dopasowana do formatu starego modelu .
Aktualizacja kodu może być trudnym zadaniem, jeśli kod nie jest dobrze zaprojektowany i jeśli system jest duży. Ale można to zrobić z czasem, mamy narzędzia takie jak Git, które pomagają nam to zrobić bez uszkodzenia wersji gotowej do produkcji.
Z drugiej strony, jeśli model się zmieni, jeśli właściwości klas znikną, czy cokolwiek innego, baza danych również powinna się zmienić. Ale mamy problem: istnieją już dane, których nie można utracić, co jest już sformatowane dla starego modelu.
Wydaje się, że relacyjna baza danych stanowi tutaj barierę uniemożliwiającą iteracyjny rozwój, a nawet aktualizację oprogramowania, gdy jest to wymagane przez użytkowników końcowych.
Jednym ze sposobów, które już zastosowałem, było kodowanie specjalnej klasy, która mapuje stare tabele bazy danych na nowe. Zatem klasy te pobierają dane w starym formacie, konwertują je na format używany przez nowy model i zapisują w nowych tabelach.
To podejście nie wydaje się najlepsze. Moje pytanie brzmi: czy istnieją dobrze znane i zalecane podejścia do pogodzenia iteracyjnego rozwoju z relacyjnymi bazami danych?
źródło
Odpowiedzi:
Nie muszą to być specjalne klasy, ale tak, potrzebujesz czegoś, co zabierze bazę danych w poprzednim formacie i skonwertuje ją na bieżącą.
Chodzi o to, że musisz opracować proces pisania i testowania tych skryptów i dyscypliny, aby nigdy nie dotykać ręcznie testowych i produkcyjnych baz danych, ale zawsze za pomocą skryptów migracyjnych.
Za każdym razem, gdy musisz dokonać zmiany w bazie danych, piszesz skrypt, który to zrobi, zarówno w SQL, jak i przy użyciu warstwy ORM, i zatwierdzasz ją do kontroli wersji wraz ze zmianami, które wymagają nowego schematu. Następnie masz skrypt sterujący, który zaktualizuje bazę danych, stosując wszystkie skrypty migracji, które nie zostały jeszcze zastosowane w sekwencji.
I upewnij się, że modyfikujesz tylko dowolne udostępnione środowiska programowania, testowania i kontroli jakości, stosując skrypty i wycofując je do wcześniejszej wersji, jeśli nie działają, więc możesz mieć pewność, że będą działać zgodnie z przeznaczeniem, gdy uruchomisz je w środowisku produkcyjnym .
Nowa instalacja odbywa się po prostu przez zastosowanie wszystkich skryptów. Po pewnym czasie możesz mieć ich setki i myśleć, że jest to bardzo nieefektywne, ale nie wpadnij w pułapkę próby optymalizacji. Instalacja jest jednorazową czynnością, a jej niezawodność jest atutem, dzięki czemu jest szybka.
@Doc Brown już połączył Martin Fowler: Ewolucyjny projekt bazy danych i /programming/334059/agile-development-and-database-changes , i dodałbym Alexa Papadimoulisa: Zmiany w bazie danych zrobione dobrze , co jest krótsze i ma kilka przykładów.
Jako porządny przykład narzędzia implementującego taki proces sugeruję Alembic . Opiera się na frameworku Python SQLAlchemy , ale można go używać z innymi językami i strukturami, jeśli nie mają one własnej obsługi migracji. Strona Wikipedii poświęcona migracji schematów zawiera więcej takich narzędzi .
źródło
O dziwo, to jest właśnie ten problem, przed którym stoi mój obecny zespół programistów. Pytanie zawiera kilka pytań cząstkowych, więc zostaną one rozwiązane niezależnie.
Przede wszystkim, czy relacyjna baza danych zbyt mocno ogranicza model danych, utrudniając zmiany?
Z pewnością , ale niekoniecznie z podanych powodów. Niestety wszechstronność systemów zarządzania relacyjnymi bazami danych prowadzi również do ich upadku. RDBMS został pierwotnie opracowany, aby oferować stosunkowo prostą platformę do przechowywania danych, która akceptuje duże zestawy danych i zmniejsza je do stosunkowo niewielkich rozmiarów. Dokonano tego kosztem złożoności modelu danych i wymaganej mocy obliczeniowej. Wraz ze wzrostem złożoności bazy danych powstały procedury składowane, widoki, funkcje i wyzwalacze, aby pomóc administratorom baz danych w radzeniu sobie ze złożonością w spójny i skalowalny sposób.
Niestety model relacyjnej bazy danych nie jest zorientowany obiektowo i naturalnie nie odwzorowuje obiektów rzeczywistych, jak powinien model danych. To prowadzi nas do potrzeby użycia narzędzi pośredników, takich jak mapery obiektowo-relacyjne i tym podobne. Niestety, podczas gdy narzędzia te mają wyraźne miejsce w dzisiejszym świecie programistycznym, ich użycie jest ukierunkowane jedynie na objaw problemu relacyjnej złożoności danych, a nie na przyczynę leżącą u jego podstaw, czyli niedopasowanie modelu danych do świata rzeczywistego.
Prowadzi to do drugiej części pytania, która była raczej założeniem, ale powinno być postrzegane jako pytanie: czy powinniśmy zrobić dobry model domeny za pierwszym razem?
Tak, do pewnego stopnia. Jak wskazano w pytaniu, rzadko jest możliwe pełne zrozumienie problemu, gdy rozpoczynamy proces projektowania. Jednak różnica między całkowicie niepoprawnym modelem danych, w przeciwieństwie do modelu, który może być modyfikowany w miarę lepszego zrozumienia domeny, to model, który spójnie odwzorowuje rzeczywisty świat. Oznacza to, że musimy dołożyć wszelkich starań, aby stworzyć początkowy model danych, który byłby zgodny z naszym rozumieniem problemu w kategoriach jego rzeczywistych podmiotów. Jeśli zaczniemy normalizować niewłaściwe jednostki, model danych będzie zły na dwa sposoby, a odzyskiwanie będzie trudne.
Pod wieloma względami przejście na rozwiązania baz danych „Bez SQL” wynika z problemów związanych z niespójnością modelu danych. Wykorzystanie zorientowanego obiektowo podejścia bez SQL powoduje, że myślimy więcej o mapowaniu między naszymi obiektami w kodzie a tymi w prawdziwym świecie - a kiedy napotykamy niespójność, często jest to oczywiste, ponieważ jest niemożliwe do zaimplementowania w naszym Baza danych. To prowadzi do lepszego ogólnego projektu.
To prowadzi do ostatniego pytania: czy relacyjny model danych jest niespójny z podejściem zwinnym?
Nie, ale wymagana jest większa umiejętność. Podczas gdy w świecie bez SQL dodawanie pola lub konwertowanie właściwości na tablicę jest trywialne, robienie tych rzeczy w świecie relacyjnym wcale nie jest trywialne. Potrzeba co najmniej kogoś, kto jest w stanie zrozumieć zarówno relacyjny model danych, jak i realne podmioty, które reprezentują. Ta osoba jest osobą, która ułatwi aktualizację modelu relacyjnego w miarę rozumienia zmian modelu rzeczywistego. Nie ma srebrnej kuli, aby rozwiązać ten problem.
źródło
Nie chodzi o to, aby refaktoryzować tak bardzo, że model zmienia się nie do poznania. Nawet przy iteracyjnym rozwoju powinieneś naprawdę budować na istniejących elementach, a nie przekształcać je na części.
Daje to 2 główne opcje radzenia sobie z dużymi zmianami, gdy tylko się pojawią: pierwszą jest zbudowanie warstwy DB jako interfejsu API, użycie procedur przechowywanych, aby można je było dostosować do klienta bez zmiany podstawowego schematu danych.
Innym sposobem jest zastąpienie tabel odrobiną migracji danych. Gdy wymagana jest zmiana na dużą skalę, tworzysz nowy schemat i wdrażasz zestaw skryptów, aby przenieść stare dane i wmasować je w nowy format. Wykonanie tego kosztuje czas, dlatego polegasz bardziej na tańszych metodach modyfikacji dostępu do danych (np. Za pośrednictwem SP) jako pierwszego wyboru.
Więc: 1. staraj się myśleć z wyprzedzeniem, aby nie trzeba było niczego zmieniać.
Polegaj na opakowaniach lub interfejsach API, więc zmiany są ograniczone lub mogą być ukryte w izolowanym komponencie
Jeśli zajdzie taka potrzeba, poświęć trochę czasu na prawidłowe uaktualnienie.
Te kroki dotyczą wszystkiego, nie tylko baz danych.
źródło