Ile logiki biznesowej powinna wdrożyć baza danych?

107

Pracowałem w niektórych projektach, w których większość logiki biznesowej została zaimplementowana w bazie danych (głównie poprzez procedury składowane). Z drugiej strony słyszałem od innych programistów, że jest to zła praktyka („Bazy danych służą do przechowywania danych. Aplikacje służą do reszty”).

Które z tych podejść jest ogólnie lepsze?

Zalety wdrażania logiki biznesowej w DB, o których mogę myśleć, to:

  • Centralizacja logiki biznesowej;
  • Niezależność rodzaju aplikacji, języka programowania, systemu operacyjnego itp .;
  • Bazy danych są mniej podatne na migrację technologii lub duże refaktoryzacje (AFAIK);
  • Brak przeróbek dotyczących migracji technologii aplikacji (np. .NET do Java, Perl do Python itp.).

Wady:

  • SQL jest mniej produktywny i bardziej złożony w programowaniu logiki biznesowej, ze względu na brak bibliotek i konstrukcji językowych, które są najbardziej zorientowane na aplikacje;
  • Trudniejsze (jeśli w ogóle możliwe) ponowne użycie kodu przez biblioteki;
  • Mniej produktywne IDE.

Uwaga: bazy danych, o których mówię, są relacyjnymi, popularnymi bazami danych, takimi jak SQL Server, Oracle, MySql itp.

Dzięki!

Raphael
źródło
3
Odpowiedź na to pytanie może być przydatna.
Blrfl
7
Ten argument został już wyczerpująco omówiony . Co jeszcze możemy znacząco dodać do rozmowy tutaj?
Robert Harvey
2
@gnat: Nawet nie blisko.
Robert Harvey
1
podobny do programmers.stackexchange.com/questions/158534/…
minusSeven 10.04.13
7
Weź pod uwagę, że baza danych będzie daleko ( daleko ) przeżywać twoją aplikację. Baza danych może nawet przeżyć języka piszesz aplikację w. Sam dane zazwyczaj jest firma, a baza danych powinna być w stanie chronić integralność danych w niej zawartych. W tym duchu każde ograniczenie klucza obcego polega, szczerze mówiąc, na wdrożeniu reguły biznesowej. O ile nie pozbędziesz się wszystkich ograniczeń relacyjnych w relacyjnej bazie danych, naprawdę nie będziesz w stanie całkowicie wyjąć logiki biznesowej z bazy danych.
Craig

Odpowiedzi:

82

Logika biznesowa nie wchodzi do bazy danych

Jeśli mówimy o aplikacjach wielowarstwowych, wydaje się całkiem jasne, że logika biznesowa, rodzaj inteligencji, która prowadzi określone przedsiębiorstwo, należy do warstwy logiki biznesowej, a nie do warstwy dostępu do danych.

Bazy danych wykonują kilka rzeczy naprawdę dobrze:

  1. Przechowują i pobierają dane
  2. Ustanawiają i egzekwują relacje między różnymi podmiotami danych
  3. Zapewniają środki do zapytania danych w celu uzyskania odpowiedzi
  4. Zapewniają optymalizację wydajności.
  5. Zapewniają kontrolę dostępu

Teraz możesz oczywiście kodyfikować w bazie danych wszelkiego rodzaju rzeczy, które dotyczą twoich problemów biznesowych, takich jak stawki podatkowe, rabaty, kody operacyjne, kategorie i tak dalej. Ale działania biznesowe podejmowane na tych danych nie są generalnie zakodowane w bazie danych, z różnych powodów, o których wspominają już inni, chociaż w bazie danych można wybrać akcję i wykonać ją gdzie indziej.

I oczywiście mogą istnieć rzeczy, które są wykonywane w bazie danych z powodu wydajności i innych powodów:

  1. Zamknięcie okresu obrachunkowego
  2. Chrupanie liczb
  3. Nocne procesy wsadowe
  4. Przełączanie awaryjne

Naturalnie nic nie jest wygrawerowane w kamieniu. Procedury przechowywane są odpowiednie dla szerokiego zakresu zadań po prostu dlatego, że żyją na serwerze bazy danych i mają pewne zalety i zalety.

Procedury przechowywane w dowolnym miejscu

Kodowanie wszystkich zadań przechowywania, zarządzania i pobierania danych w procedurach przechowywanych jest pewne, a korzystanie z powstałych usług danych jest pewne. Z pewnością skorzystasz z maksymalnej możliwej optymalizacji wydajności i bezpieczeństwa, jaką mógłby zapewnić serwer bazy danych, i to nie jest mała rzecz.

Ale co ryzykujesz?

  1. Blokada dostawcy
  2. Potrzeba programistów ze specjalnymi zestawami umiejętności
  3. Spartańskie narzędzia programistyczne, ogólnie
  4. Niezwykle szczelne połączenie oprogramowania
  5. Brak podziału obaw

I oczywiście, jeśli potrzebujesz usługi internetowej (i tak zapewne do tego właśnie zmierza), nadal będziesz musiał ją zbudować.

Jaka jest typowa praktyka?

Powiedziałbym, że typowym, nowoczesnym podejściem jest użycie Mapera relacyjno-obiektowego (takiego jak Entity Framework) do tworzenia klas modelujących tabele. Następnie możesz porozmawiać z bazą danych za pośrednictwem repozytorium, które zwraca kolekcje obiektów, co jest bardzo znane każdemu kompetentnemu twórcy oprogramowania. ORM dynamicznie generuje SQL odpowiadający Twojemu modelowi danych i żądanym informacjom, które następnie serwer bazy danych przetwarza, aby zwrócić wyniki zapytania.

Jak dobrze to działa? Bardzo dobrze i znacznie szybciej niż pisanie procedur przechowywanych i widoków. Zasadniczo obejmuje to około 80% wymagań dostępu do danych, głównie CRUD. Co obejmuje pozostałe 20%? Zgadłeś: procedury składowane, które bezpośrednio obsługują wszystkie główne ORM.

Czy możesz napisać generator kodu, który robi to samo co ORM, ale z procedurami przechowywanymi? Oczywiście że możesz. Ale ORM są na ogół niezależne od dostawcy, dobrze zrozumiałe dla wszystkich i lepiej obsługiwane.

Robert Harvey
źródło
3
Dziękuję za wspaniałą odpowiedź, @Robert Harvey. Ale myślałem o argumencie „zablokowania dostawcy”: nie używając konkretnej technologii (np. Stosu .NET lub Java) do zbudowania aplikacji, również blokady dostawcy? Czy są zalety blokowania dostawcy stosu zorientowanego na aplikację w porównaniu z rozwiązaniem DB?
Raphael
3
@RobertHarvey, ale część logiki aplikacji, która jest w .NET, jest nadal zablokowana w .NET. To samo dotyczy PHP i Java.
Pacerier
2
@Pacerier: Poprzez nazwę dostawcy blokady mam na myśli dostawcę bazy danych. W praktyce baza danych (i stos programowania) rzadko są zastępowane.
Robert Harvey,
2
@ kai: Cóż, nie możesz mieć tego na dwa sposoby. Albo używasz kodów pośredniczących i próbnych i żyjesz z faktem, że test jest sztuczny, albo piszesz test, który jest realistyczny i żyjesz z pewnym opóźnieniem. Wątpię jednak, aby twój kompromis wynosił 10 minut vs. 30 sekund.
Robert Harvey
3
Może późno, ale jestem zdania, że ​​procedury składowane wdrażające logikę biznesową należą do warstwy logiki biznesowej, a nie warstwy danych. Są jakby oddzielnym językiem bez potrzeby ORM.
Paralife
16

Mocno wierzę w to, by logika biznesowa była jak najdalej od bazy danych. Jednak jako programista wydajności mojej firmy doceniam to, że czasami konieczne jest osiągnięcie dobrej wydajności. Ale myślę, że jest to konieczne znacznie rzadziej niż twierdzą ludzie.

Kwestionuję twoje zalety i wady.

Twierdzisz, że centralizuje ona logikę biznesową. Przeciwnie, myślę, że to je decentralizuje. W produkcie, nad którym obecnie pracuję, używamy procedury składowanej w dużej części naszej logiki biznesowej. Wiele naszych problemów z wydajnością wynika z wielokrotnego wywoływania funkcji. Na przykład

select <whatever>
from group g
where fn_invoker_has_access_to_group(g.group_id)

Problem z tym podejściem polega na tym, że ogólnie (w niektórych przypadkach może to być fałsz) zmusza bazę danych do uruchomienia funkcji N razy, raz na rząd. Czasami ta funkcja jest droga. Niektóre bazy danych obsługują indeksy funkcji. Ale nie można indeksować każdej możliwej funkcji względem każdego możliwego wejścia. Czy potrafisz

Typowym rozwiązaniem powyższego problemu jest wyodrębnienie logiki z funkcji i scalenie jej z zapytaniem. Teraz złamałeś enkapsulację i zduplikowaną logikę.

Kolejny problem, jaki widzę, to wywoływanie procedur przechowywanych w pętli, ponieważ nie ma możliwości połączenia ani przechowania przechowywanych zestawów wyników proc.

declare some_cursor
while some_cursor has rows
    exec some_other_proc
end

Jeśli wyciągniesz kod z zagnieżdżonego proc, następnie ponownie zdecentralizujesz. Dlatego musisz wybierać między enkapsulacją a wydajnością.

Ogólnie uważam, że bazy danych są złe w:

  1. Obliczenie
  2. Iteracja (są zoptymalizowane do ustawiania operacji)
  3. Równoważenie obciążenia
  4. Rozbiór gramatyczny zdania

Bazy danych są dobre w:

  1. Blokowanie i odblokowywanie
  2. Utrzymywanie danych i ich relacje
  3. Zapewnienie integralności

Biorąc drogie operacje, takie jak pętle i analizowanie ciągów, i utrzymując je w warstwie aplikacji, możesz skalować aplikację w poziomie, aby uzyskać lepszą wydajność. Dodawanie wielu serwerów aplikacji za modułem równoważenia obciążenia jest zwykle znacznie tańsze niż konfigurowanie replikacji bazy danych.

Masz jednak rację, że oddziela logikę biznesową od języka programowania aplikacji, ale nie rozumiem, dlaczego jest to zaleta. Jeśli masz aplikację Java, masz aplikację Java. Przekształcanie wiązki kodu Java w procedury składowane nie zmienia faktu, że masz aplikację Java.

Preferuję utrzymywanie kodu bazy danych na trwałości. Jak utworzyć nowy widżet? Musisz wstawić do 3 tabel, które muszą być w transakcji. To należy do procedury składowanej.

Zdefiniowanie, co można zrobić z widgetem oraz reguł biznesowych dotyczących wyszukiwania widgetów należy do Twojej aplikacji.

Brandon
źródło
8
W SQL Server tylko słabo napisane sps muszą być wywoływane w pętli, możesz wysłać mu zestawy danych w parametrze i wykonać proces oparty na zestawach.
HLGEM
2
Program SQL Server wygeneruje nieoptymalny plan zapytań za każdym razem, gdy w klauzuli WHERE występuje UDF.
Jim G.
7
Wygląda na to, że problem z wydajnością nie wynika z logiki bazy danych a aplikacji. Jest po prostu źle napisany i zaprojektowany. Ten problem podąży za tobą w świecie ORM tak samo. ORM mogą powodować prawdziwy ból głowy poza operacjami CRUD. Jeśli w Twoim systemie jest dużo danych i jest to system raportujący, zachowaj ostrożność.
sam yi
To prawda. Większość naszych problemów z wydajnością wynika po prostu ze źle napisanego kodu i nadmiernie złożonej architektury. Ale nadal uważam, że wkładamy niewłaściwy rodzaj pracy do naszych baz danych. Kodowanie jak najwięcej do bazy danych spowodowało, że zrobiliśmy rzeczy, w których baza danych nie jest dobra.
Brandon
1
Ten przykład jest nawet argumentem, aby umieścić podstawowe elementy logiki biz w DB: aby uniknąć iteracyjnego podejścia (pętli kodu lub kursora zamiast wyrażeń opartych na zestawie), takich jak zaraza. Programiści mają tendencję do traktowania zbiorów obiektów w sposób iteracyjny (pętla, trawers), co prawdopodobnie prowadzi do niepotrzebnych obciążeń lub problemu SELECT N + 1 w przypadku wielu pojedynczych zapytań w obie strony. Używając wyrażeń SQL lub wyrażeń opartych na języku (np. LINQ), będą oni zmuszeni do użycia podejścia opartego na zestawie, o ile to możliwe.
Erik Hart
10

Pracowałem w 2 różnych firmach, które miały odmienne zdanie na ten temat.

Moją osobistą sugestią byłoby użycie Procedur składowanych, gdy czas wykonania jest ważny (wydajność). Ponieważ procedura składowana jest kompilowana, jeśli masz złożoną logikę do wysyłania zapytań do danych, lepiej zachować ją w samej bazie danych. Ponadto wyśle ​​tylko ostateczne dane do twojego programu na końcu.

W przeciwnym razie myślę, że logika programu powinna zawsze znajdować się w samym oprogramowaniu. Dlaczego? Ponieważ program musi być testowalny i nie sądzę, że istnieje prosty sposób na testowanie jednostkowe procedury składowanej. Nie zapominaj, że program, który nie jest testowany, jest złym programem.

Dlatego zachowaj ostrożność, gdy jest to konieczne.

Jean-François Côté
źródło
3
Procedury przechowywane są testowane jednostkowo. Zobacz tutaj kilka technik.
Robert Harvey,
4
afaik, test jednostkowy nigdy nie korzysta z bazy danych ani pliku. Tak więc technicznie „testowanie jednostkowe” procedura przechowywana nie jest testowaniem jednostkowym i będzie powolne jak diabli. Zestaw testów jednostkowych powinien zostać uruchomiony w ciągu kilku sekund (a może minut przy bardzo dużej aplikacji) w dowolnym momencie podczas programowania.
Jean-François Côté
1
OP mówił o „logice biznesowej”, a logika biznesowa powinna zostać przetestowana jednostkowo. Umieszczając go w procedurze przechowywanej, łączysz go z zapytaniem do bazy danych, co spowalnia cały proces. Tak jak powiedziałem, możesz użyć procedury składowanej (nie jest to przestępstwo), ale zaciera linię między logiką biznesową a warstwą bazy danych, co jest złe. Używaj go ostrożnie :)
Jean-François Côté
1
Jeśli utworzysz bazę danych i niezbędne obiekty, sp, przetestujesz, a następnie ją zburzysz, będzie to test jednostkowy. Testuje jednostkę pracy.
Tony Hopkinson
2
Czy mit nie podważa wzrostu wydajności dzięki procedurom przechowywanym?
JeffO
9

Jest środek, który musisz znaleźć. Widziałem przerażające projekty, w których programiści używają bazy danych jako niczego więcej niż drogiego magazynu kluczy / wartości. Widziałem innych, w których programiści nie używają obcych kluczy i indeksów. Na drugim końcu spektrum widziałem projekty, w których większość, jeśli nie cała logika biznesowa, jest zaimplementowana w kodzie bazy danych.

Jak zauważyłeś, T-SQL (lub jego odpowiednik w innych popularnych RDBMS) nie jest najlepszym miejscem do kodowania złożonej logiki biznesowej.

Staram się zbudować całkiem przyzwoity model danych, używam funkcji bazy danych do ochrony moich założeń dotyczących tego modelu (tj. FK i ograniczeń) oraz oszczędnie używam kodu bazy danych. Kod bazy danych jest przydatny, gdy potrzebujesz czegoś (np. Sumy), którą baza danych robi bardzo dobrze i może zaoszczędzić ci przenoszenia zillionowych rekordów przez drut, kiedy ich nie potrzebujesz.

Dan Pichelman
źródło
2
Używanie bazy danych jako „zawyżonego” magazynu kluczy / wartości jest całkowicie prawidłową techniką, o czym świadczą legiony praktyków NoSQL.
Robert Harvey
1
@RobertHarvey Masz oczywiście rację, ale jakoś mój brzuch nadal nalega, aby istniało prostsze / tańsze / szybsze rozwiązanie niż baza danych, jeśli wszystko, czego potrzebujesz, to magazyn kluczy / wartości. Muszę dowiedzieć się więcej o NoSQL.
Dan Pichelman,
2
Nie widzę używania procedur przechowywanych jako lekarstwa na źle zaprojektowaną bazę danych.
JeffO,
2
@RobertHarvey, dosłownie przeczytałem „zawyżone ceny kluczy / magazynu wartości”. Wstrzymanie licencji Oracle lub SQL Server na coś takiego, gdy istnieją opcje takie jak MongoDB dostępne za darmo, wydaje się marnowaniem pieniędzy.
Raphael
@Raphael Lub możesz użyć PostgreSQL 😉
Demi
9

Jeśli logika biznesowa obejmuje operacje na zestawach, najprawdopodobniej dobrym miejscem jest baza danych, ponieważ systemy baz danych są naprawdę dobre w wykonywaniu operacji na zestawach.

http://en.wikipedia.org/wiki/Set_operations_(SQL)

Jeśli logika biznesowa wymaga pewnego rodzaju obliczeń, prawdopodobnie należy do procedury bazy danych / sklepu, ponieważ bazy danych nie są tak naprawdę zaprojektowane do zapętlania i obliczania.

Chociaż nie są to twarde i szybkie zasady, jest to dobry punkt wyjścia.

Jon Raynor
źródło
6

Nie ma jednej właściwej odpowiedzi na to. To zależy od tego, do czego używasz bazy danych. W aplikacji korporacyjnej logika w bazie danych wymaga kluczy obcych, ograniczeń, wyzwalaczy itp., Ponieważ jest to jedyne miejsce, w którym wszystkie możliwe aplikacje współużytkują kod. Ponadto umieszczenie wymaganej logiki w kodzie ogólnie oznacza, że ​​baza danych jest niespójna, a dane niskiej jakości. Może się to wydawać trywialne dla devloper aplikacji, który tylko nie rozumie, jak działa GUI, ale zapewniam cię, że ludzie próbujący wykorzystać dane w raportach zgodności uważają to za bardzo denerwujące i kosztowne, gdy dostają kary pieniężne w wysokości miliarda dolarów za posiadanie danych, które nie nie przestrzegaj poprawnie zasad.

W środowisku nieregulacyjnym, gdy nie dbasz o cały zestaw rekordów i tylko jedna lub dwie aplikacje trafiają do bazy danych, być może uda ci się utrzymać wszystko w aplikacji.

HLGEM
źródło
3

Po kilku latach pytanie jest nadal ważne ...

Prosta praktyczna zasada: jeśli jest to ograniczenie logiczne lub wszechobecne wyrażenie (pojedyncza instrukcja), umieść je w bazie danych (tak, klucze obce i ograniczenia sprawdzania również są logiką biznesową!). Jeśli jest to proceduralne, zawierające pętle i gałęzie warunkowe (i tak naprawdę nie można ich zmienić w wyrażenie), umieść je w kodzie.

Unikaj baz danych zrzutu śmieci

Próby umieszczenia naprawdę całej logiki biznesowej w kodzie aplikacji prawdopodobnie zdegenerują (relacyjną) bazę danych do kosza na śmieci, gdzie projekt relacyjny jest w większości całkowicie pomijany, gdzie dane mogą mieć dowolny niespójny stan i brakuje normalizacji (często głównie XML, JSON , CSV itp. Kolumny kosza).

Ten rodzaj logiki opartej tylko na aplikacjach jest prawdopodobnie jednym z głównych powodów wzrostu NoSQL - oczywiście z wadą, że aplikacja musi zadbać o całą logikę, która była wbudowana w relacyjną bazę danych od dziesięcioleci. Jednak bazy danych NoSQL są bardziej odpowiednie do tego rodzaju przetwarzania danych, na przykład dokumenty danych zachowują w sobie „integralność relacyjną”. W przypadku relacyjnych baz danych jest to po prostu nadużycie, powodujące coraz więcej problemów.

Wyrażenia (oparte na zestawie) zamiast kodu proceduralnego

W najlepszym przypadku każde zapytanie lub operacja na danych powinny być kodowane jako wyrażenie, a nie kod proceduralny. Świetnym wsparciem jest to, gdy języki programowania obsługują wyrażenia, takie jak LINQ w świecie .NET (niestety, tylko zapytania obecnie, bez manipulacji). Po stronie relacyjnej bazy danych od dłuższego czasu uczy się, jak preferować wyrażenia instrukcji SQL zamiast proceduralnych pętli kursora. Więc DB może zoptymalizować, wykonać operację równolegle lub cokolwiek, co może być przydatne.

Wykorzystaj mechanizmy integralności danych DB

Jeśli chodzi o RDBMS z ograniczeniami klucza obcego i sprawdzania, kolumn obliczeniowych, ewentualnie wyzwalaczy i widoków, jest to miejsce do przechowywania podstawowej logiki biznesowej w bazie danych. Właściwa normalizacja pomaga zachować integralność danych, aby zapewnić unikalny i wyraźny przypadek danych. Nawet jeśli musisz powielić go w kodzie i DB, te podstawowe mechanizmy integralności danych nie powinny zostać pominięte!

Procedury przechowywane?

Procedury przechowywane są w dzisiejszych czasach rzadko potrzebne, ponieważ bazy danych przechowują skompilowane plany wykonania dla SQL i wykorzystują je ponownie, gdy pojawi się to samo zapytanie, tylko z różnymi parametrami. Zatem argument prekompilacji dla SP nie jest już prawidłowy. Można przechowywać lub automatycznie generować zapytania SQL w aplikacji lub ORM, które przez większość czasu znajdą wstępnie skompilowane plany zapytań. SQL jest językiem wyrażeń, o ile nie używa się jawnie elementów proceduralnych. Zatem w najlepszym przypadku używasz wyrażeń kodu, które można przetłumaczyć na SQL.

Podczas gdy strona aplikacji, w tym wygenerowany ORM, SQL, nie znajduje się już w bazie danych, w przeciwieństwie do procedur przechowywanych, nadal liczę go jako kod bazy danych. Ponieważ nadal wymaga znajomości SQL i bazy danych (z wyjątkiem najprostszego CRUD), a przy prawidłowym zastosowaniu działa znacznie inaczej niż kod proceduralny zwykle tworzony w językach programowania takich jak C # lub Java.

Erik Hart
źródło
2

To zależy od biznesu, jego kultury i dziedzictwa. Pomijając względy techniczne (zostały omówione z obu stron), podane odpowiedzi mówią, że sprowadza się to do tego, skąd pochodzą ludzie. W niektórych organizacjach dane są najważniejsze, a DBA jest potężną postacią. Jest to typowe scentralizowane środowisko, centrum danych z dołączoną do niego grupą terminali. Preferowanie w tego typu środowisku jest jasne. Pulpit może się radykalnie zmieniać wiele razy, zanim cokolwiek zmieni się w centrum danych, a pomiędzy nimi będzie niewiele.

Drugi koniec spektrum to czysta architektura 3-poziomowa. A może wielopoziomowy w biznesie zorientowanym na sieć. Prawdopodobnie usłyszysz tutaj inną historię. DBA, jeśli istnieje, będzie tylko pomocnikiem, który wykonuje niektóre zadania administracyjne.

Współczesny twórca aplikacji będzie miał większe powinowactwo z drugim modelem. Jeśli dorastałeś z dużym systemem klient-serwer, prawdopodobnie byłbyś w innym obozie.

Często występuje tu tak wiele nietechnicznych czynników związanych ze środowiskiem, że nie ma ogólnej odpowiedzi na to pytanie.

Martin Maat
źródło
2

Pojęcie logiki biznesowej jest otwarte na interpretację. Budując systemy, chcemy zapewnić integralność bazy danych i jej zawartości. Pierwszym krokiem powinny być różne granty dostępu użytkowników. Jako bardzo prosty przykład rozważmy aplikację ATM.

Aby uzyskać saldo konta, należy dokonać wyboru w odpowiednim widoku. Ale aby przelać środki, transakcja powinna zostać zamknięta w procedurze przechowywanej. Logika biznesowa nie powinna mieć możliwości bezpośredniego aktualizowania tabel dla kwot kredytu i obciążenia.

W tym przykładzie logika biznesowa może sprawdzić saldo przed zażądaniem przeniesienia lub po prostu wywołać zapisany proc dla przeniesienia i zgłosić awarię. IMHO, logika biznesowa, w tym przykładzie, powinna uprzednio sprawdzić, czy dostępne są wystarczające środki i czy istnieje rachunek docelowy, i dopiero wtedy wywołać fundusze transferowe. Jeśli między początkowymi krokami a przechowywanym wywołaniem proc nastąpi kolejne obciążenie, tylko wtedy zwrócony zostanie błąd.

CyberFonic
źródło
Dobry przykład i wyjaśnienie.