Jak dużą część logiki biznesowej realizować po stronie DB

0

Cześć,

nie wiem czy dość precyzyjnie nazwałem temat, ale już wyjaśniam o co mi chodzi.

Jestem na etapie projektowania aplikacji, i zaczęło mnie zastanawiać jak dużą część projektu powinna realizować baza danych i od czego to zależy jaką cześć działania tworzonego systemu realizować po stronie bazy danych a jaką po stronie apliakcji w warstwie logiki.
Przedstawię kilka scenariuszy i liczę na pomoc w wyborze oraz co najważniejsze o uzasadnienie dlaczego tak, a nie inaczej jest najlepiej.

Załóżmy, że realizujemy system do obsługi biblioteki. Baza danych przechowuje autorów, książki, klientów i wypożyczenia. Książki i klienci i są identyfikowani na podstawie kodu kreskowego.

Scenariusz 1 - duża cześć realizowana po stronie bazy danych. Baza bardzo mocno pilnująca integralności.
Mam tu na myśli przykładowo:

  • duża liczbę check-constraint'ów i triggerów sprawdzających poprawność np kodu kreskowego, uniemożliwiających np wypożyczenie danej książki więcej razy niż jest jej w magazynie lub niedopuszczenie do wypożyczenia książki klientowi, który jest na czarnej liście.
  • dużą liczbę procedur składowanych służących do dodawania nowych książek lub autorów
  • relacje z określonymi działaniami akcji delete i update.

Scenariusz 2 - średnia ilość logiki realizowana po stronie danych

  • sprawdzanie kodu kreskowego i możliwej ilości wypożyczeń sprawdzane po stronie aplikacji
  • baza danych zawiera np triggery, które służą jedynie automatyzacji niektórych czynności - np trigger dokonujący wpisu w historii przy kasowaniu wypożyczenia.
  • relacje mają określone działania delete i update
  • dodawanie/edycja rekordów i sprawdzanie poprawności realizowane z aplikacji

Scenariusz 3 - brak realizacji logiki po stronie bazy danych

  • baza danych zawiera jedynie tabele i relacje z określonymi działaniami delete i update.
  • sprawdzanie i wszelkie wpisy realizowane ze strony aplikacji

Dodam, że do obsługi bazy danych użyję ORM'a.
Oraz, że warstwa danych nie musi niezależna od warstwy logiki (co w przypadku uniezależnienia jej mogłoby przemawiać za opcją 1)

Czekam na ciekawe i wyczerpujące wypowiedzi oraz wasze praktyki w tym względzie :-)

0

Moim zdaniem opcja nr 1.
Może się tak zdarzyć że będziesz musiał coś zrobic w bazie "ręcznie", pomijając sam system z którym jest związana, warto wtedy mieć pewną kontrolę. Ustawienie odpowiednich zabezpieczeń w czasie tworzenia bazy nie jest specjalnie skomplikowane i szansa na "błąd" jest mniejsza, a w kodzie który będzie się z nią łączył programista zawsze może się gdzieś pomylić. Zawsze lepiej mieć 2 poziomy gdzie jest sprawdzana poprawność (tzn i w samym kodzie i w bazie).
Modyfikacje samej aplikacji są znacznie częstsze niż modyfikacje bazy. Ot choćby ze wzgledu na samą spójność danych, czy na fakt że system ma działać cały czas, także w czasie wprowadzania mdyfikacji. W czasie każdej modyfikacji może się gdzieś wkraść błąd i baza która nie będzie filtrować danych się rozspójni.

0
lukasz___ napisał(a)
  • duża liczbę check-constraint'ów i triggerów sprawdzających poprawność np kodu kreskowego, uniemożliwiających np wypożyczenie danej książki więcej razy niż jest jej w magazynie lub niedopuszczenie do wypożyczenia książki klientowi, który jest na czarnej liście.

Moim zdaniem to są zdecydowanie zadania aplikacji. Baza ma przechowywać i udostępniać dane, a nie myśleć.

Shalom napisał(a)

Zawsze lepiej mieć 2 poziomy gdzie jest sprawdzana poprawność (tzn i w samym kodzie i w bazie).

I dwa miejsca do poprawki w razie zmiany wymagań, czyli dwa razy więcej możliwości popełnienia błędu.

W czasie każdej modyfikacji może się gdzieś wkraść błąd i baza która nie będzie filtrować danych się rozspójni.

Możesz podać jakiś przykład?

0

@somekind nie demonizowałbym że będzie dwa razy więcej miejsc do wprowadzania zmian kiedy zmienią się wymagania. Constrainty nie dają nam aż tak wielkiej możliwości filtrowania danych, bo raczej nie obejmują filtrowania dziedzinowego, związanego z logiką jako taką, tylko takie związane z typem danych, formatem, zakresem itd. Bo ja rozumiem że autor przedstawił opcję "ustawione jakieś constrainty lub ich brak". A ustawienie obostrzeń typu PESEL ma 11 cyfr, wzrost może mieć zakres 0-300cm, rasa może być jedną z X itd to są raczej rzeczy które nie ulegną nagle zmianie i warto ustawić sprawdzanie ich w bazie, przynajmniej tak mi się wydaje ;)

Przykład? Każda sytuacja gdy "zniknie" nam sprawdzanie jakiegoś warunku spójności. Choćby jakieś głupie sprawdzanie czy coś jest wpisane dużą literą czy małą.

0
  1. wystawiasz "goła" bazę na świat (np. umożliwiasz obcym aplikacją grzebanie w bazie - wystaw im tylko i wyłącznie procedury ze sprawdzaniem wprowadzanych danych do zmiany danych i widoki do odczytu - nikt nie wpisze Ci głupot do bazy), baza jest zamknięta dla obcych aplikacji - jak Ci wygodniej - wsadzisz więcej logiki do bazy to będziesz miał jej mniej w aplikacji. Zalety - zazwyczaj serwer BD jest "ciut" mocniejszy od kompa gdzie działa aplikacja, jeśli masz aplikację rozbitą na moduły to logikę masz tylko w jednym miejscu, wadą może być to, że czasami trzeba się napocić aby zrobić coś w sql-u czy co tam baza obsługuje, co w aplikacji zrobił byś w przysłowiowych trzech linijkach.
    Odnośnie sprawdzania takich rzeczy jak poprawność pesel po stronie bazy to ma to dwie niezaprzeczalne wady - po pierwsze aby sprawdzić czy dane są poprawne musisz je do bazy wysłać i po drugie nie masz możliwości zakomunikować userowi błędnych danych od razu po wpisaniu - trzeba ja najpierw wysłać do bazy a to w 99,9% przypadków robi się po wpisaniu wszystkich danych
0
Shalom napisał(a)

A ustawienie obostrzeń typu PESEL ma 11 cyfr, wzrost może mieć zakres 0-300cm, rasa może być jedną z X itd to są raczej rzeczy które nie ulegną nagle zmianie i warto ustawić sprawdzanie ich w bazie, przynajmniej tak mi się wydaje ;)

I nagle okazuje się, że prawo się zmieniło i PESEL ma 15 znaków. Albo wzrost ma być ograniczony do 600 cm, bo otwieramy filię biblioteki dla żyraf. I musimy zmienić to w bazie, w logice aplikacji i być może w interfejsie, jeśli textbox był jakoś ograniczany.

Pozostaje też kwestia wydajności - constrainty i triggery spowalniają działanie bazy. Pytanie czy możemy sobie na to pozwolić czy też nie.

Przykład? Każda sytuacja gdy "zniknie" nam sprawdzanie jakiegoś warunku spójności. Choćby jakieś głupie sprawdzanie czy coś jest wpisane dużą literą czy małą.

To czy coś ma być wpisane WIELKĄ czy małą literą jest sprawdzane w aplikacji. Jeśli w aplikacji coś się zmieni, to przecież i tak przed wdrożeniem nowej wersji musi przejść testy, które wykryją ewentualną nieprawidłowość.

Zaszywanie logiki w BD ma sens chyba tylko wtedy, jeśli utrzymaniem aplikacji mają zajmować się bazodanowcy. Ale to chyba i tak średnie wyjście, bo nie rozbudują w ten sposób funkcjonalności aplikacji, mogą co najwyżej zmienić pewne operacje.

0

Witam,

Ja osobiście nigdy nie byłem zwolennikiem trzymania logiki w bazie danych. Dla mnie baza danych jest "magazynem" do ich przechowywania (pisanie procedur czy funkcji to rozwiązania w przypadku kiedy w aplikacji pojawi się wąskie gardło i przeniesienie logiki do bazy rozwiązuje problem wydajnościowy), a miejsce logiki jest w aplikacji. Ktoś wspomniał, że serwery są bardziej wydajne i to powód żeby przenieść tam logikę. Owszem serwery są bardziej wydajne, ale dlaczego rozwiązaniem nie może być dodatkowa warstwa na serwerze (np. przez remoting, WCF), wtedy mamy układ klient->serwer->baza-danych (gdzie warstwy serwera i bazy są na jednej maszynie), a rola klienta sprowadza się do wywołania funkcji na serwerze aplikacji. Kolejne punkty, z którymi może być problem przy realizacji projektu z logiką po stronie bazy danych.

  1. Wersjonowanie w systemie kontroli wersji
  2. Wykonywanie testów jednostkowych
  3. Debugowanie (osobiście mam porównanie między narzędziem Visual Studio 2010 / MS Sql 2008 - debugowanie po stronie bazy danych to koszmar...)
  4. Zarządzanie kodem

Kolejna sprawa to optymalizacja i sprawy wydajnościowe po stronie bazy danych. Jeżeli chodzi o wydajność i umiejętności tworzenia procedur to oczywiście dla wyjadaczy nie ma tutaj porównania. Tylko niestety prawda jest taka, że w wielu firmach istnieją samozwańczy wyjadacze, a po analizie ich procek, okazuje się, że pełno tam kursorów tajemniczych tabel tymczasowych i zbędnych triggerów, co w porównaniu z istniejącym narzędziami ORM (np. Fluent NHibernate ) pod względem wydajnościowym wypada blado (narzędzie te są naprawdę dopracowane i potrafią "wycisnąć" na tyle sensowne zapytanie, że problem optymalizacji się nie pojawi). Co do optymalizacji to tak naprawdę pytanie powinno być ile jest wstanie znieść (czekać) końcowy użytkownik na reakcje systemu. Robienie optymalizacji dla własnej idei, bez konkretnego uzasadnienia i świadomości ze funkcja wykona się 1-2 sek szybciej jest zupełnie nieadekwatne do kosztów jakie trzeba ponieść przy realizacji projektu (a jakby nie patrzeć o te właśnie koszty rozchodzi się najbardziej). Pomijam tutaj oczywiście systemy, które z założenia klienta muszą być bardzo szybkie.

Ostatnia sprawa to właśnie koszty. Jak na moje stwierdzenie, że tworzenie aplikacji z logiką po stronie bazy danych, a pisaniem aplikacji z logiką po stronie klienta (dodatkowo z wykorzystaniem narzędzia ORM) będzie szybsze (czyt. tańsze) jest w błędzie. Ja szczerze mówiąc, wole napisać aplikacje dwa razy szybciej (ponieść mniejsze koszty jej wytworzenia), kosztem tego, że klient nie padnie z wrażenia jeżeli chodzi o szybkość działania.

0

Wg mnie baza powinna pilnować spójności danych na takim podstawowym poziomie ale jednak, reszta jako część logiki w aplikacji.

0

Wg mnie baza powinna pilnować spójności danych na takim podstawowym poziomie ale jednak, reszta jako część logiki w aplikacji.

A co konkretnie oznacza "taki podstawowy poziom" ?

0

Własności krytyczne z punktu widzenia aplikacji, przeciwdziałanie sytuacji w której dane znajdą się w stanie bardzo trudnym do naprawienia- np w przytoczonym przykładzie żeby nie można było wypożyczyć 2 razy książki w tym samym czasie lub żeby 2 osoby nie mogły wypożyczyć tej samej książki naraz. Dużo zależy od systemu i jego implementacji.

0

Ok, a mając jeden centralny serwer bazy danych i 50 klientów używających jej, rozproszonych po różnych instytucjach. W przypadku konieczności dokonania zmian w logice: czy łatwiej jest zmienić procedurę w bazie danych, czy rozdystrybuować aktualizację na 50 klientów? To tak a propos zalet trzymania większej ilości logiki w bazie. Według mnie, walidacja danych nie powinna byc oparta tylko na bazie danych, ale procedury realizujące większość bardziej zaawansowanych funkcji - czemu nie?

0
othello napisał(a)

Ok, a mając jeden centralny serwer bazy danych i 50 klientów używających jej, rozproszonych po różnych instytucjach. W przypadku konieczności dokonania zmian w logice: czy łatwiej jest zmienić procedurę w bazie danych, czy rozdystrybuować aktualizację na 50 klientów?

Wtedy zmienia się WebService'y realizujące logikę biznesową. Przecież aplikacje klienckie nie pracują na bazie bezpośrednio, a przynajmniej nie powinny.

To tak a propos zalet trzymania większej ilości logiki w bazie. Według mnie, walidacja danych nie powinna byc oparta tylko na bazie danych, ale procedury realizujące większość bardziej zaawansowanych funkcji - czemu nie?

Argumenty @dwe to za mało?

0

Przy NoSQL nie ma takich dylematów :)
Podobnie, jeżeli jakaś ogromna baza ma mnóstwo żądań na sekundę, to utrzymywanie jakiejś mega spójności też jest niemożliwe (z powodów wydajnościowych).

0

Przecież aplikacje klienckie nie pracują na bazie bezpośrednio, a przynajmniej nie powinny.

No moze i nie powinny, faktem jest natomiast, że to co ja widzę wokół siebie, to albo jakiś orm na bazie bezpośrednio, albo normalnie przez ado (lub ado.net) tez na bazie bezpośrednio.

0
othello napisał(a)

No moze i nie powinny, faktem jest natomiast, że to co ja widzę wokół siebie, to albo jakiś orm na bazie bezpośrednio, albo normalnie przez ado (lub ado.net) tez na bazie bezpośrednio.

I z bazy korzysta więcej niż jedna aplikacja?

No bo załóżmy, że z jednej bazy korzysta ich 10, zmienia się procedura składowana i działa teraz zgodnie ze specyfikacją 9, a 1 aplikacja działać przestaje. I mamy ładnego kalafiora.

0

Powiem więcej. Z bazy korzystają przykładowo różne wersje tej samej aplikacji. Więc co się robi? Najlepiej to zrobić kolejny widok/procedurę z taką samą nazwą, ale np. końcówką _v2, _v3 itd. Taki to sposób na tzw. "wsteczną kompatybilność". Dołóżmy do tego totalną niechęć do dodawania komentarzy w procedurach/tabelach/widokach itd, zwłaszcza niepopularne jest dodawanie komentarza do pól tabeli, parametrów procedur, niechęć do używania relacji (a po co, w kodzie aplikacji sobie dopilnujemy spójności danych, w bazie to wystarczy mieć luźne tabele) oraz to że na takich zasadach system ewoluował od powiedzmy 10 lat aby mieć wyobrażenie jak wygląda baza danych dziś...

Mam wrażenie że to nierzadko się spotyka. Niestety.

0

W mojej poprzedniej pracy też tak było, z tymże to były bazy naszych wewnętrznych firmowych aplikacji (tzn. dla klienta zewnętrznego, ale hostowane u nas), nie wystawione na zewnątrz w żaden sposób. No i to nie były typowe aplikacje biznesowe, tam był naprawdę ostry nacisk na wydajność, której klient wymagał, więc nie dziwię się, że większa część logiki i API było po stronie bazy.

0

a tam się spieracie, popatrzcie na ror - tam w bazie żadnej logiki nie ma, nawet pojęcie fk nie istnieje, wszystko w app i nikt nie narzeka :P
(prawdziwe dla ror 2.3.x w nowszych nie wiem, chociaż są osobne gemy do tego)

0

Logika w bazie to koszmar - głównie ze względu na maintenance.
Dodać procedurkę składowaną jest prosto.
Ale tak jak już napisano w bazach danych:

  • często brak komentarzy
  • brak systemu wersjonowania
  • utrudnione debugowanie
  • kod współdzielony przez wszystkie aplikacje

Logika powinna być tam gdzie jej miejsce:

Architektura 3-warstwowa:

  • walidacje, graficzne fajerwerki - klient
  • obliczenia finansowe, procesowe, wymagające mocnego CPU - serwer logiki / aplikacji
  • kontrola zakresu danych ('A' lub 'B'), kontrola spójności (unikalność, NULL) - serwer baz danych

Przy czym triggery nie są najciekawszym rozwiązaniem bo wykonują się bezkontekstowo - zawsze.
A czasami jest tak, że jesteśmy pewni danych i/albo wykonujemy masowe aktualizacje wtedy triggery są tylko przeszkodą.

1 użytkowników online, w tym zalogowanych: 0, gości: 1