Czy w przypadku ORM obsługującego sprawdzanie poprawności danych należy również wprowadzić ograniczenia w bazie danych?

13

Zawsze stosowałem ograniczenia na poziomie bazy danych oprócz moich modeli (ActiveRecord). Ale zastanawiałem się, czy to jest naprawdę wymagane?

Trochę tła

Niedawno musiałem przetestować jednostkę podstawową metodę automatycznego generowania znaczników czasu dla modelu. Zwykle test utworzyłby instancję modelu i zapisałby ją bez sprawdzania poprawności. Są jednak inne wymagane pola, które nie mają wartości null w definicji tabeli, co oznacza, że ​​nie mogę zapisać instancji, nawet jeśli pominę sprawdzanie poprawności ActiveRecord. Zastanawiam się więc, czy powinienem usunąć takie ograniczenia z samej bazy danych i pozwolić ORM je obsłużyć?

Możliwe korzyści, jeśli pominę ograniczenia w db, imo -

  • Może modyfikować regułę sprawdzania poprawności w modelu bez konieczności migrowania bazy danych.
  • Może pominąć walidację podczas testowania.

Możliwa wada?

Jeśli jest możliwe, że sprawdzanie poprawności ORM zakończy się niepowodzeniem lub zostanie ominięte, baza danych nie sprawdza ograniczeń.

Co myślisz?

EDYCJA W tym przypadku używam frameworka Yii , który generuje model z bazy danych, stąd też generowane są reguły bazy danych (chociaż ja też zawsze mogłem pisać je po generowaniu).

na
źródło
3
Jeśli dane w bazie danych można rutynowo modyfikować bez użycia ORM (inne aplikacje bez ORM lub, co gorsza, bezpośredni dostęp do bazy danych przez użytkowników), sprawdzanie poprawności naprawdę musi być w bazie danych.
Marjan Venema

Odpowiedzi:

16

Waszą naczelną zasadą powinno być: Nie powtarzaj się :

W inżynierii oprogramowania Don't Repeat Yourself (DRY) to zasada opracowywania oprogramowania mająca na celu ograniczenie powtarzania wszelkiego rodzaju informacji, szczególnie przydatna w architekturach wielowarstwowych. Zasada DRY jest określona jako „Każda wiedza musi mieć jedną, jednoznaczną, autorytatywną reprezentację w systemie”.

ORM jest zasadniczo dodatkową warstwą (lub warstwą, jeśli wolisz), wygodnie leżącą między aplikacją a magazynami danych. Ograniczenia powinny znajdować się w jednym miejscu i tylko w jednym, niezależnie od tego, czy będzie to ORM, czy przechowywanie danych, w przeciwnym razie wkrótce skończysz utrzymywać różne ich wersje. Ty naprawdę nie chcesz tego robić.

Jednak w praktyce większość pół przyzwoitych ORM automatycznie generuje dużą liczbę modeli na podstawie schematu danych. Mimo że nadal występuje powielanie, szanse na piekło utrzymania są minimalne, ponieważ za każdym razem generowany jest zduplikowany kod ORM. Idealnie byłoby nie mieć zduplikowanego kodu, ale kolejna najlepsza rzecz to automatycznie generowane ograniczenia.

Ponadto posiadanie ograniczeń w jednym miejscu niekoniecznie oznacza, że ​​powinieneś mieć wszystkie ograniczenia w tym samym miejscu. Niektóre, takie jak referencyjne ograniczenia integralności, mogą lepiej pasować do przechowywania danych (ale mogą zostać utracone, jeśli przejdziesz do innego magazynu danych), a niektóre, w większości te dotyczące skomplikowanej logiki biznesowej, lepiej pasują do Twojego ORM. Lepiej byłoby mieć wszystkie jabłka w tym samym koszu, ale…

Awarie

Wspominasz o niepowodzeniu ORM. Jest to absolutnie nieistotne dla twojego pytania, twoja aplikacja powinna traktować ORM i przechowywanie danych jako jeden podmiot. Jeśli zawiedzie, nie powiedzie się, ominięcie ORM w celu bezpośredniego połączenia z pamięcią danych nie jest dobrym pomysłem.

Omijanie ORM dla czegokolwiek innego

Również nie jest to dobry pomysł. Może się to jednak zdarzyć z różnych powodów:

  1. Starsze części aplikacji, które zostały zbudowane przed wprowadzeniem ORM.

    To jest trudne i dokładnie taka sytuacja mam teraz do czynienia , stąd moje ciągłe powtarzanie „utrzymania piekła”. Albo utrzymujesz części inne niż ORM, albo przepisujesz je, aby użyć ORM. Druga opcja może początkowo mieć większy sens, ale jest to decyzja oparta wyłącznie na tym, co dokładnie robią te części aplikacji i na ile wartościowe byłoby całkowite przepisanie na dłuższą metę.

    Spróbuj zmienić klucz w źle zaprojektowanej tabeli MySQL 2 * 10 ^ 8 wierszy (bez przestojów), a zrozumiesz, skąd pochodzę.

  2. Nietypowe części aplikacji, które absolutnie muszą bezpośrednio komunikować się z przechowywaniem danych:

    Jeszcze trudniejsze. ORM to wymyślne narzędzia, które zajmują się prawie wszystkim, ale czasem przeszkadzają, a nawet są absolutnie bezużyteczne. Modne hasło (tak naprawdę buzzphrase) to niedopasowanie impedancji obiektowo-relacyjnej , po prostu mówiąc, ORM nie jest technicznie możliwe do zrobienia wszystkiego , co robi relacyjna baza danych, a dla niektórych rzeczy, które robią, istnieje znaczna obniżka wydajności.

Komentarze

Z punktu widzenia integralności danych ograniczenia MUSZĄ znajdować się w bazie danych, a POWINIEN być w aplikacji. Co się stanie, jeśli aplikacja jest dostępna za pośrednictwem Internetu i aplikacji komputerowych, aplikacji mobilnej lub usługi internetowej? - Luiz Damim

W tym przypadku dodanie dodatkowej warstwy byłoby niezwykle pomocne, a jeśli mówimy o aplikacji internetowej, wybrałbym interfejs API REST. Zbyt uproszczonym projektem byłoby:

wprowadź opis zdjęcia tutaj

ORM będzie znajdować się między interfejsem API a magazynami danych, a wszystko, co kryje się za interfejsem API (łącznie z nim), będzie uważane za jedną całość z różnych aplikacji.

Yannis
źródło
Zwykle definiujesz schemat w ORM, który jest następnie dublowany w bazie danych, dzięki czemu masz drugi poziom pewności.
Josh K
2
@JoshK Mówisz drugi poziom pewności, mówię piekło utrzymania. Nie mówię jednak, że nie masz racji ...
yannis
Ma sens. Teraz podążam tą drogą. Dzięki!
na
1
Gdy miniesz punkt, w którym jeden lub dwóch programistów wykonuje prace związane z kodowaniem i bazami danych, staje się koniecznym złem. Jeśli użyjesz dobrej ORM, wygeneruje również migracje dla Ciebie. Kiedy dojdziesz do tego stopnia, że ​​masz dedykowanego DBA, nie ma sposobu, aby to obejść, nie pozwolą, aby tabele pływały bez ograniczeń. Prostym sposobem, aby uniemożliwić ludziom rejestrację bez wiadomości e-mail, jest ograniczenie poziomu przechowywania.
Josh K
1
Z punktu widzenia integralności danych ograniczenia MUSZĄ znajdować się w bazie danych, a POWINIEN być w aplikacji. Co się stanie, jeśli aplikacja jest dostępna za pośrednictwem Internetu i aplikacji komputerowych, aplikacji mobilnej lub usługi internetowej?
Luiz Damim
20

To jest naprawdę bardzo trudne pytanie i uważam, że jest to bardzo kontrowersyjny temat.

Jak zauważył Yannis Rizos w swojej odpowiedzi, posiadanie logiki ograniczeń zarówno w bazie danych, jak i w warstwie ORM wydaje się naruszać DRY, co „może prowadzić do koszmarów związanych z utrzymaniem, złego faktoringu i logicznych sprzeczności”.

Jednak usunięcie logiki ograniczeń z bazy danych i zachowanie jej tylko w warstwie ORM nie działałoby, jeśli spełniony jest jeden z następujących warunków:

  1. Ręczne aktualizacje DB (wydaje się, że zdarzają się w każdej firmie)

  2. Aktualizacje DB z innego systemu, który nie zawsze może łatwo współdzielić logikę ograniczeń ORM (np. / Skrypt Perla, który wykonuje rutynowe zadania, gdy warstwa ORM jest zaimplementowana w Hibernacji i używana przez aplikację Java do codziennej aktywności)

Sugerowałoby to, że dodajesz logikę ograniczeń do bazy danych i usuwasz z warstwy ORM , aby zapobiec naruszeniu SUCHEGO. Może to jednak prowadzić do przypadków, w których kod aplikacji nie może z powodzeniem uchwycić faktycznego problemu i przekazać go użytkownikowi (chociaż jako programista debugujący problem najprawdopodobniej możesz). W przypadku niektórych projektów może to być nie do przyjęcia.

Ostatnią opcją jest zautomatyzowanie tworzenia ograniczeń w ORM (i dowolnym innym systemie) na podstawie ograniczeń DB (lub, naprawdę ... odwrotnie). Chociaż ostatecznie skończysz z dwiema lub więcej implementacjami ograniczeń, nie będzie to naruszeniem zasady DRY opisanej w „The Pragmatic Programmer”, ponieważ zalecają one wykorzystanie generowania kodu w celu uniknięcia naruszeń DRY. Oczywiście nie jest to takie proste, ponieważ na przykład każda zmiana ograniczenia DB może wymusić przebudowę i ponowne wdrożenie wszystkich aplikacji, które z niego korzystają (nie jest to trywialne w automatyzacji).

Naprawdę należałoby to ocenić indywidualnie dla każdego przypadku . Mogę ci powiedzieć, że do tej pory spotkałem się z pustymi spojrzeniami, gdy sugeruję, aby logika ograniczeń nie była powtarzana.

smp7d
źródło
2
Właśnie skończyłem pracę i zastanawiałem się nad rozszerzeniem mojej odpowiedzi, tak aby była mniej więcej tym, co właśnie opublikowałeś. Dobra odpowiedź!
yannis
3

Zdecydowanie dodałbym ograniczenia do bazy danych jako moją domyślną opcję. Wynika to z faktu, że w przedsiębiorstwie najważniejsze są dane, a jakość danych ma ogromne znaczenie. @Yannis Rizos wprowadził do dyskusji zasadę SUCHEGO. Kolejną zasadą jest Obrona w głębi. W przypadku danych skorzystałbym z tej zasady.

Pracowałem w prawdziwych przedsiębiorstwach, w których DB ma dane utworzone 30 lat temu. To było i nadal jest dostępne przez aplikację COBOL, a teraz przez aplikację .Net. Za 10 lat może to być aplikacja producenta, która wie. Nastąpiło połączenie, a miliony wierszy danych przekonwertowano i przeniesiono z innej firmy do tej bazy danych za pomocą SQL. Żadna ORM nie może tego zrobić. Najważniejsze jest pozostanie danych, zmiany aplikacji, zmiana sposobu generowania danych. Dlaczego więc nie zmniejszyć ryzyka uszkodzenia danych?

softveda
źródło
2

Myślę, że robisz to do pewnego stopnia.

  • Główne ograniczenia powinny istnieć w ORM - języki programowania są znacznie bardziej elastyczne, łatwiej jest je testować i łatwiej dostosowywać, gdy zmieniają się wymagania; przynajmniej nie musisz się martwić poprawkami DDL. I generalnie unikasz trudnych do przetestowania problemów z regresją danych.

  • Niektóre bardzo twarde i szybkie ograniczenia powinny również istnieć w bazie danych. Nie mówię na przykład o nazwach, które nie mają wartości zerowych. Mówię o takich rzeczach, jak integralność referencyjna lub wymaganie pewnych absolutnie kluczowych identyfikatorów. Wymagania strukturalne, aby Twój kod nie musiał zajmować się „co, jeśli Zamówienie zawiera nieistniejący produkt”.

Wyatt Barnett
źródło
1

Baza danych jest IMO jedynym miejscem, w którym DRY może zostać naruszone, ponieważ jeśli coś omija Twój ORM i ma złe dane, to tyle. Koniec gry. Uszkodzenie danych jest zabójczym ciosem.

Wayne Molina
źródło
Tylko baza danych? Mogę wymyślić wiele przypadków, w których zachowanie związane z danymi powinno istnieć na kilku warstwach (logicznych lub fizycznych), nawet jeśli dane w ogóle nie zostaną utrwalone. Czasami możliwe jest posiadanie jednego kodu źródłowego i ograniczenie „duplikacji” do wdrożonych bibliotek dll.
mike30