Architektura wielowarstwowa

0

Cześć. Zabieram się za projektowanie większej usługi, w zamyśle ma to być SaaS. Wpadłem na ciekawy pomysł i pomyślałem, że spróbuje swoich sił. Albo wyjdzie, albo nie, ale czegoś się nauczę, rozwinę ponad to co potrafię. W związku z tym, ze ma to być SaaS, a projekt ma być dostępny na wielu platformach, z racji sposobu korzystania z usługi zdecydowałem się na architekturę wielowarstwową. Najwyższa warstwa prezentacji zrealizowana będzie jako cienki klient na wszystkie popularne platformy PC (Windows, Mac, Linux) oraz na telefony i tablety ( WP , Android - innych systemów nie znam (jako programista) ). Inny powód to bezpieczeństwo systemu i danych - nikt nie będzie miał bezpośredniego dostępu do bazy danych, warstwa logiki serwuje gotowe informacje i zachowania. Teraz pozostaje kwestia warstwy danych. Najlepiej znam system Firebird. Piszę na co dzień w nim procedury i triggery. Serio potrafię stworzyć zaawansowane konstrukcję w języku bazy danych, oraz projektować ciekawe struktury. Założeniem jest polepszenie moich umiejętności w strefach które, chociaż troszkę znam i stworzyć aplikację, więc chce skupić sie na zrealizowaniu projektu i jego komercjalizacji, a nie na samym procesie tworzenia i poznawania. Zrozumiałe jest, że dlatego pewnie wybiorę system Firebird. Kłopot w tym, że mam wrażenie, że system Firebird nie jest stworzony do takiej architektury. Rozumiem, że można ograniczyć się do walidacji i replikacji jeżeli chodzi o warstwe danych. Firebird dodatkowo zachęca do zawierania logiki w triggerach i porcedurach. W obecnych projektach dużo logiki i algorytmów zaszywam w bazie danych. Część w programie. Łatwo byłoby zaszyć część logiki w warstwie logiki a część w warstwie danych w bazie. Spowodowałoby to niestety niemożliwość łatwej wymiany technologi warstwy danych, czy logiki. Jaka jest tendencja ? Powinno się łączyć warstwe danych i logiki czy odseparować i wszystkie algorytmy i logikę zaszyć w warstwie logiki ? Spowoduje to być może spadek wydajności ale ułatwi modernizację. Proszę o opinię na ten temat. Na siłę, można bazę danych ograniczyć do warstwy danych, a procedury i triggery jedynie do walidacji, kontroli i replikacji, tylko, że wtedy można by skorzystać z innego silnika, który ma lepsze zabezpieczenia, możliwość partycjonowania, a nie wspiera tak doskonale pisanie procedur i triggerów jak Firebird.

0

Czy może pracujesz w Zielonej Górze....?

Moja opinia:

  • warstwa logiki jest po to aby umieszczać w niej logikę
  • warstwa danych najlepiej aby była tylko pudełkiem na dane
0

Niestety, nie pracuje w zielonej. Co do twojej opini - tez tak uwazam, tylko ze firebird udostepnia wielkie mozliwosci jezeli chodzi o zaszycie logiki w bazie danych i chce posluchac opinii.

0

Po pierwsze - która wersja firebird? Ostatni raz z firebird pracowałem już dawno temu, ale za każdym razem się sparzyłem i wolałem zmienić na oracle/postgresa/mysql itp. No ale to było wieki temu jeszcze za czasów wesji chyba 1.x jak sie bawiło w delphi z tym ;)

Wracając do Twoich pytań - przy SaaS dobrze robisz z cienkim klientem, źle robisz z logiką w bazie. Serio - logika w bazie, jasne że to fajowy bajer jest, ale często stwarza problemy (nawet na super mega enterprise bazie oracla z tym PL/SQL) szczególnie przy zmianach wersji silnika (upgrade) i przenoszeniu na inny serwer(fizyczny serwer nowy, może zmiana OS). Sam widziałem jak kadra naukowa na wydziale sparzyła się na zaszyciu logiki w bazie... Oj, dużo maści na ból d... poszło i nie wiem jaki obecnie jest stan ich projektu, ale zdecydowali że muszą przenieść logikę z bazy do aplikacji.

Firebird ogólnie w nowszych wersjach wydaje się fajną bazą, ale niestety mało popularną. Moja rada na teraz z całą aplikacją: posłuchaj rady @Szczery i oddziel dane od logiki. Rób tak jak napisałeś - trigery i procedury co najwyżej do walidacji (ale i tak dla pewności zaszyj to też w warstwie logiki). Do tego replikacje/partycjonowanie bazy i ogólnie skalowalność bazy też wydziel poza bazę. Może i dłużej przez to zejdzie Ci z wystartowaniem projektu, ale później oszczędzi wieeeelu zmartwień.

0

Tendencja jest taka zeby nie upychać logiki w bazie jeśli nie jest to czymś podytkowane ;]
W twoim przypadku zastanowiłbym się nad jakąś warstwą REST a nie tylko klientem webowym albo cienkim. Przy czym webowy ma ten plus że jest jeden i pomyka na wszystkim ;)

0

@serge, na czym polega doskonałość wspierania procedur i wyzwalaczy w Firebird? W czymś jest lepszy od pozostałych SZBD?
Nie rozumiem też, czemu chcesz używać wyzwalaczy do walidacji... Od tego są ograniczenia integralnościowe.

Generalnie baza danych jest od danych, nie od logiki. Aczkolwiek, stosowanie procedur ma sens, a nawet jest konieczne, przy operacjach dużych ilościach danych.

0

@somekind - chociażby zaawansowany system triggerów, gdzie dostępnych 32k pozycji wykonania ( kolejności), procedury składowane i konstrukcje języka PSQL podobny do Oracla, bardzo podobno do imperatywnych języków, konstrukcje for select, executre statement. Forki FB udostępniają pisanie procedur w językach "normalnych", co ma być wprowadzone w wersji 3.0. Posiadając dobry framework, można zbudować całośc aplikacji bazodanowej i jej zachowanie na procedurach i triggerach.

Nie rozumiem części dot. integralności. Jeżeli mampole PESEL, to nie chce móc wpisać tam błędnego peselu, więc na BIU należy procedurą sprawdzić, czy jest ok i ew. exception. Interface, czy warstwa logiki powinna pilnować, ale potrafię sobie wyobrazić jakieś procedury transferowe,lub zakładanie automatyczne w kodzie i wtedy triggery są dodatkowym poziomem zabezpieczeń.

Chyba macie racje i ostatecznie postanowiłem zostawić warstwe danych dla danych.

1
serge napisał(a):

chociażby zaawansowany system triggerów, gdzie dostępnych 32k pozycji wykonania ( kolejności), procedury składowane i konstrukcje języka PSQL podobny do Oracla, bardzo podobno do imperatywnych języków, konstrukcje for select, executre statement. Forki FB udostępniają pisanie procedur w językach "normalnych", co ma być wprowadzone w wersji 3.0. Posiadając dobry framework, można zbudować całośc aplikacji bazodanowej i jej zachowanie na procedurach i triggerach.

Dobra, a jest coś, czego nie mają inne bazy? Bo to co wymieniłeś (z wyjątkiem może tych kolejności triggerów) jest dostępne chociażby w MSSQL.

Posiadając dobry framework, można zbudować całośc aplikacji bazodanowej i jej zachowanie na procedurach i triggerach.

Nie przeczę, tak się robi od 30 lat.

Nie rozumiem części dot. integralności. Jeżeli mampole PESEL, to nie chce móc wpisać tam błędnego peselu, więc na BIU należy procedurą sprawdzić, czy jest ok i ew. exception. Interface, czy warstwa logiki powinna pilnować, ale potrafię sobie wyobrazić jakieś procedury transferowe,lub zakładanie automatyczne w kodzie i wtedy triggery są dodatkowym poziomem zabezpieczeń.

Jeśli dane do bazy mogą trafiać bezpośrednio, to wówczas faktycznie należy zrobić checki na kolumnach tabel. Ale gdy z bazy korzysta wyłącznie aplikacja, albo warstwa webserwisów, i nikt nie ma bezpośredniego dostępu, walidację lepiej zrobić po stronie logiki biznesowej, a nie bazy.

0

MSSQL to proteza triggera ;p Tutaj masz wiele trigerów na różnych pozycjach, podział na trigery Before , After , na Insert, Update, Delete. Do tego dochodzą zmienne kontekstowe widziane jako globale per połączenie, lub per transakcje. Zmienne typu new old, czyli np. na trigerze before insert, old.Pole - to wartość przed insertem, a new.Pole to wartość która zaraz będzie zainsertowana i można ją zmienić ! Dodatkowo wykrywanie które pola sie zmieniły. W MSSQL trzeba kombinować. Dodatkowo triggery na connect, start transacion, rollback transacion i commit transaction. Wysyłanie fbeaventów deterministycznie do aplikacji z bazy danych etc ... MSSQL tego nie ma z tego co wiem.

0
serge napisał(a):

MSSQL to proteza triggera ;p Tutaj masz wiele trigerów na różnych pozycjach, podział na trigery Before , After , na Insert, Update, Delete. Do tego dochodzą zmienne kontekstowe widziane jako globale per połączenie, lub per transakcje. Zmienne typu new old, czyli np. na trigerze before insert, old.Pole - to wartość przed insertem, a new.Pole to wartość która zaraz będzie zainsertowana i można ją zmienić ! Dodatkowo wykrywanie które pola sie zmieniły. W MSSQL trzeba kombinować.

Nic nie trzeba kombinować, dane wstawiane są w tabeli inserted, dane usuwane w tabeli deleted, możesz sobie z nimi robić co chcesz. Nie ma co prawda triggerów before, są za to instead of.
Serio, piszesz o rzeczach, które chyba każdy SZBD jakoś obsługuje, i w każdym da się upchnąć całą logikę biznesową w bazie. ;P

0

Nie mówię, że nie ma, ale FB to ułatwia. Zamiast sięgać do tabeli inserted, w trigerze beofore update można odwołac się do wartości new.pesel, wywołać procedurę i wrócić do wartości old i puścić eavent do apki, lub exception. Nie mówiąc już, że można zrobić to tak, że wszystkie dobre dane się zupdatują, a nie zupdatuje się jedynie pesel, a wyjątek nie dokona rollbacka pełnego, bo jest konstrukcja łapania wyjątków, czyli mogę złapać wyjątek, o błędny pesel, w autonomicznej transakcji zupdatować pola które są ok, a transakcje obecną zrollbackować. To jest przypadek updatu, a teraz insert - dla danego persona insertuje nowy kalendarz, w osobnej tabeli są dni kalendarza i są procedury naliczające kiedy są święta etc. Wystarczy jeden update do tabeli kalendarzy z kluczem na osobe, a trigery AI założą dni kalendarza i naliczą święta, dni wolne etc. Analogicznie, trigger BD, zablokuje usunięcie kalendarza jeżeli są dni z dowiązanym grafikiem z sensownym komunikatem, a jak nie ma to trigger AD posprząta struktury po kalendarzu. Nie każdy SZBD to posiada i jest to takie proste. Zresztą zaczyna się flame, a nie miało chodzić o systemy bazodanowe, tylko o ideę jaką najlepiej zastosować w architekturze wielowarstwowej.

0

Zapewne wielu osobom to co, poniżej napisałem nie przypadnie do gustu, bądź co gorsza zranię w ten sposób ich poglądy odnośnie programowania we właściwy sposób. Mam to na względzie i wiem, że takie programowanie nie jest zalecane w dużych firmach czy korporacjach, ale jeśli mówimy tutaj o budowaniu oprogramowania wielowarstwowego z podziałem na wiele klientów przez jednego programistę to nigdy bym nie postawił na takiego gościa, który staranną uwagę chce przywiązać do wszystkiego co robi :)

@serge, jeśli siedzisz typowo w backendzie i na dodatek bliżej bazy danych to utworzenie wielowarstwowej usługi będzie dla Ciebie tworzeniem rzeźby z gówna :D Jestem zdania, że wielowarstwowa usługa to dobra rzecz, ale w Twoim przypadku ten wybór powien uzmysłowić Ci jedno. Czeka na Ciebie wiele roboty i nauki. Może nawet za wiele.

Ten projekt będzie wymagał sprytniejszego myślenia niż "czy ta baza jest nadal fajna? czy pisać w niej obsługę walidacji?". Musisz przeobrazić się w bestię - krzyżówkę weterana Java bądź C# znającego dziesiątki wzorców, dobrych praktyk i typowego PHPowca z indi, który jednym pierdnięciem potrafi zrobić kilka funkcji.

Musisz wiedzieć w jaki sposób produkować kod szybko i tanio, a jednocześnie w miarę znośnie. Co z tego, że zrobisz zajebiście wydają obsługę walidacji czy wprowadzania danych po stronie firebirda jeśli ta funkcjonalność nikomu się nie przyda?

Dlatego lepiej jest myśleć, że każda funkcjonalność jaką robisz ma nóż na gardle. Staraj się używać możliwie dużo gotowego kodu, polegaj na frameworkach, bibliotekach - samemu twórz jak najmniej, a gdy musisz dodać coś od siebie to nie przesadzaj z testami, nadmiernie czystym kodem i optymalizacjami. Po prostu oszczędzaj na każdym kroku, bo się nie wyrobisz.

Gdy będziesz miał dzieci lub więcej obowiązków to wątpię byś miał wiele tego czasu na tworzenie własnych i dużych projektów :)

Pozdrawiam,
I życzę samych sukcesów!

1

A mi się tam podejście kolegi @serge podoba. To jest taki wstęp do clean architecture. Deklaratywne programowanie w stylu:

userStorage.createNewUser(userData);

I się "samo robi" tzn. wraz z userem tworzy wszystkie potrzebne przyległości w stylu kalendarz itp. to czy będzie to robić baza danych triggerami czy jakiś serwis za pomocą n-wywolań to już rzecz drugorzędna.

Co mi się nie podoba to chęć zaszycia logiki w bazie. Wbrew pozorom nie jest to tak fajne jak @serge opisujesz. Po pierwsze tworzysz bardzo silne powiązanie z konkretnym dostawcą RDMS. To nie jest dobre. Takie rozwiązanie powoduje, że nie masz separacji pomiędzy danymi, a logiką. Na upartego można by napisać klienta jako prosty wrapper na bazę danych, który będzie wołał odpowiednie procedury. Baza danych będzie zatem zajmować się nie serwowaniem danych, czyli tym do czego zostala stworzona, będzie obrabiać logikę biznesową.
Mam świadomość, że możliwość użycia triggerów do zarządzania danymi, szczególnie jak ogarniasz ten temat, jest bardzo fajna lecz nie tędy droga.
Po drugie tak zbudowany system nie jest testowalny. Hej przecież można przeklikać testy, powiesz. No właśnie w momencie gdy ręcznie uruchamiasz testy oznacza to, że będziesz tracić czas. Testy aplikacji powinny być całkowicie zautomatyzowane. Kolejnym problemem jest niezależność testów. Czy używając triggerów będziesz wstanie napisać testy, które będą wzajemnie niezależne? Raczej nie, a jeżeli już tak to kazdy test będzie musiał zerować stan aplikacji. Czyli mówiąc po ludzku usuwać i wgrywać na nowo schemat, ale tylko ze sobą! W dodatku dane do testów będą musiały zostać wgrane przed utworzeniem triggera.
Przykład - testujemy usuwanie użytkownika. Mamy do sprawdzenia TRZY elementy:

  • trigger BD sprawdzajacy stan kalendarza
  • delete usuwający kalendarz
  • trigger AD "sprzątający"
    To są trzy OSOBNE zadania, ale nie ma możliwości napisania testów niezależnych. Chyba, że każdy test dostanie swój nowy schemat BEZ zainstalowanych pozostałych elementów. Jednakże nie widzę możliwości uruchomienia triggera bez uruchomienia zapytania! Zatem zamiast testować te funkcjonalności oddzielnie musisz je przetestować wszystkie na raz. Tracisz zatem niezależność testów. Wdodatku przygotowanie danych testowych (coś w końcu trzeba mieć by usunąć) będzie odbywało się za pomocą... triggerów(utrata niezależonści testów dla różnych funkjonalnosci) albo ręcznie(czas przygotowania danych).
    Trzecim problemem jest utrata skalowalności. Jak już wcześniej wspomniałem baza danych będzie zajmować się zarówno logiką biznesową jak i serwowaniem danych. Pytanie co stanie się gdy logika biznesowa zacznie być "ciężka", będzie wymagać wielu zasobów takich jak wątki czy pamięć? Oczywiście ucierpi na tym serwowanie danych. Trzeba będzie zreplikować serwer, bawić się w klastry i to wszystko po to by baza zajmowała się podstawową czynnością jaką jest serwowanie danych! Co będzie w odwrotnej sytuacji? Bedziesz miał dużo danych, a praca z nimi będzie wymagać dużo zasobów (sortowania, joiny dużych tabel itp.). W takim momencie najlżejsza nawet logika będzie zwalniać ponieważ współdzieli zasoby. Tu dochodzi jeszcze jeden problem. Ponieważ logika wykorzystuje mechanizmy serwowania danych np. wspomniane sortowanie to odpadają ci szybkie optymalizacje jak np. usunięcie sortowania z zapytań (przesunięcie go do logiki albo jeszcze lepiej GUI).

Podsumowując. Samo podejście jest fajne i pozwala na tworzenie oprogramowania, które będzie łatwe w utrzymaniu. Jednak obrana przez ciebie metoda realizacji jest praktycznie najgorsza z możliwych, ponieważ tracisz już na wstępie wszystkie bonusy wynikajace z zastowowania zasad clean architecture.

0
serge napisał(a):

Nie mówię, że nie ma, ale FB to ułatwia. Zamiast sięgać do tabeli inserted, w trigerze beofore update można odwołac się do wartości new.pesel, wywołać procedurę i wrócić do wartości old i puścić eavent do apki, lub exception.

Tabele inserted i deleted to właśnie Twoje new i old.

Nie mówiąc już, że można zrobić to tak, że wszystkie dobre dane się zupdatują, a nie zupdatuje się jedynie pesel, a wyjątek nie dokona rollbacka pełnego, bo jest konstrukcja łapania wyjątków, czyli mogę złapać wyjątek, o błędny pesel, w autonomicznej transakcji zupdatować pola które są ok, a transakcje obecną zrollbackować.

Dla mnie to brzmi trochę tak jak zaprzeczenie idei transakcji. No, ale update części kolumn w triggerze da się zrobić w każdej bazie, która tylko na triggery pozwala, we wspomnianym MSSQL wystarczy wstawić z inserted tylko prawidłowe kolumny.

To jest przypadek updatu, a teraz insert - dla danego persona insertuje nowy kalendarz, w osobnej tabeli są dni kalendarza i są procedury naliczające kiedy są święta etc. Wystarczy jeden update do tabeli kalendarzy z kluczem na osobe, a trigery AI założą dni kalendarza i naliczą święta, dni wolne etc. Analogicznie, trigger BD, zablokuje usunięcie kalendarza jeżeli są dni z dowiązanym grafikiem z sensownym komunikatem, a jak nie ma to trigger AD posprząta struktury po kalendarzu.

Wstawienie/usunięcie danych z innej tabeli triggerem to też nie jest nic czego nie da się zrobić w innych bazach. Tylko to generalnie nie ma sensu, już lepiej napisać procedurę, która to wszystko tworzy. Przynajmniej wszystko jest wtedy jawne, i nie dzieje się żadna "magia".

Nie każdy SZBD to posiada i jest to takie proste.

A dokładnie, który nie posiada?

Może i triggery w FB są lepsze niż gdziekolwiek indziej, chociaż mnie Twoje opisy nie do końca przekonują, ale to nadal triggery, czyli nie miejsce na logikę biznesową, i generalnie coś, czego lepiej używać jak najrzadziej, a najlepiej wcale.

2

Ten FireBird na pewno jest taki wspaniały? Czytając prasóweczkę trafiłem na http://www.benedykt.net/2014/07/26/cena-darmochy/ i jeżeli prawdą jest, że nie da się usunąć tabeli przy podpiętych użytkownikach, to tego systemu lepiej kijem nie dotykać.

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