Jak zasugerować użycie ORM zamiast procedur przechowywanych?

31

Pracuję w firmie, która korzysta z procedur przechowywanych tylko dla wszystkich danych, co sprawia, że ​​bardzo denerwujące jest utrzymywanie synchronizacji naszych lokalnych baz danych, ponieważ każde zatwierdzenie musimy uruchamiać nowe procesy. W przeszłości korzystałem z podstawowych ORM i uważam, że doświadczenie jest znacznie lepsze i czystsze. Chciałbym zasugerować kierownikowi ds. Rozwoju i reszcie zespołu, że rozważamy użycie pewnego rodzaju ORM do przyszłego rozwoju (reszta zespołu zna tylko procedury składowane i nigdy nie używała niczego innego). Obecna architektura to .NET 3.5 napisany jak .NET 1.1, z „boskimi klasami”, które używają dziwnej implementacji ActiveRecord i zwracają nietypowe zestawy danych, które są zapętlone w plikach za kodem - klasy działają mniej więcej tak:

class Foo { 
    public bool LoadFoo() { 
        bool blnResult = false;
        if (this.FooID == 0) { 
            throw new Exception("FooID must be set before calling this method.");
        }

        DataSet ds = // ... call to Sproc
        if (ds.Tables[0].Rows.Count > 0) { 
            foo.FooName = ds.Tables[0].Rows[0]["FooName"].ToString();
            // other properties set
            blnResult = true;
        }
        return blnResult;
    }
}

// Consumer
Foo foo = new Foo();
foo.FooID = 1234;
foo.LoadFoo();
// do stuff with foo...

Prawie nie ma zastosowania żadnych wzorców projektowych. Nie ma żadnych testów (nikt inny nie wie, jak pisać testy jednostkowe, a testowanie odbywa się poprzez ręczne załadowanie strony internetowej i przeglądanie). Przeglądając naszą bazę danych mamy: 199 tabel, 13 widoków, aż 926 procedur przechowywanych i 93 funkcje. Około 30 tabel jest używanych do zadań wsadowych lub rzeczy zewnętrznych, pozostałe są używane w naszej podstawowej aplikacji.

Czy w tym scenariuszu warto w ogóle zastosować inne podejście? Mówię o posunięciu się naprzód tylko dlatego, że nie wolno nam refaktoryzować istniejącego kodu, ponieważ „działa”, więc nie możemy zmienić istniejących klas na użycie ORM, ale nie wiem, jak często dodajemy nowe moduły zamiast tego dodawania / naprawy bieżących modułów, więc nie jestem pewien, czy ORM jest właściwym podejściem (zbyt dużo zainwestowanych w procedury składowane i DataSets). Jeśli jest to właściwy wybór, jak mam przedstawić przypadek użycia takiego? Z mojej głowy jedyne korzyści, jakie mogę wymyślić, to czystszy kod (choć może nie być, ponieważ obecna architektura nie jest t zbudowany z myślą o ORM, abyśmy mogli w zasadzie sforsować ORMy w przyszłych modułach, ale stare nadal będą korzystać z DataSets) i mniej kłopotów, aby pamiętać, jakie skrypty procedur zostały uruchomione, a które należy uruchomić, itd., ale o to chodzi i nie wiem, jak przekonujący byłby to argument. Utrzymanie jest kolejnym problemem, ale wydaje się, że nikt poza mną nie martwi się.

Wayne Molina
źródło
8
Wygląda na to, że masz więcej problemów niż po prostu przekonanie zespołu do korzystania z ORM. Wydaje mi się, że Twój zespół nie zna pewnych dobrych praktyk programistycznych (tj. Wzorców projektowych, testów jednostkowych). Są to ważniejsze kwestie, z którymi musisz się zmierzyć.
Bernard,
6
Jak na ironię, myślę, że w ciągu około 5 lat rozwoju poznałem tylko garstkę osób / zespołów, które były świadome takich rzeczy, jak wzorce projektowe i testy jednostkowe; zazwyczaj jestem jedynym facetem w firmie, który wie o tych sprawach.
Wayne Molina
3
@Wayne M: Trochę mnie to niepokoi, ale nie jestem tym zaskoczony.
Bernard
2
Uważam to za bardzo ... przygnębiające. To dziwne, gdy coś sugerujesz i wyglądasz jak „jeleń w świetle reflektorów”, który wskazuje, że druga osoba nie ma najmniejszego pojęcia, o czym mówisz ani dlaczego ktoś miałby to rozważyć. W przeszłości zdarzało mi się to kilka razy.
Wayne Molina
2
Jestem wielkim fanem procedury składowanej, więc mój komentarz jest stronniczy, ale całkowicie nie zgadzam się z całym założeniem. Lubisz ORM i chcesz tego używać. Reszta zespołu jest jednak w porządku z przechowywanymi procesami. Po co zmuszać ich do tego, co lubisz?
Darknight

Odpowiedzi:

47

Przechowywane procedury są złe, często są powolne i mniej więcej tak wydajne, jak zwykły kod po stronie klienta.

[Przyspieszenie jest zwykle spowodowane sposobem zaprojektowania interfejsu klienta i procedury składowanej oraz sposobem zapisywania transakcji jako krótkich, ukierunkowanych serii SQL.]

Procedury przechowywane są jednym z najgorszych miejsc do umieszczenia kodu. Dzieli twoją aplikację na dwa języki i platformy zgodnie z często losowymi regułami.

[Pytanie to zostanie ocenione z wynikiem około -30, ponieważ wiele osób uważa, że ​​przechowywane procedury mają magiczne moce i muszą być stosowane pomimo problemów, które powodują.]

Przeniesienie całego kodu procedury składowanej do klienta znacznie ułatwi wszystkim.

Nadal będziesz musiał od czasu do czasu aktualizować schemat i model ORM. Jednak zmiany schematu są odizolowane od zmian ORM, co pozwala na pewną niezależność między aplikacjami a schematem bazy danych.

Będziesz mógł testować, naprawiać, utrzymywać, rozumieć i dostosowywać wszystkie te procedury przechowywane podczas ich przepisywania. Twoja aplikacja będzie działać mniej więcej tak samo i stanie się znacznie mniej krucha, ponieważ nie rozpadasz się już na dwie różne technologie.

ORM nie są magią, a dobre umiejętności projektowania baz danych są absolutnie niezbędne, aby działały.

Ponadto programy z dużą liczbą klientów SQL mogą stać się wolne z powodu złego myślenia o granicach transakcji. Jednym z powodów, dla których procedury przechowywane wydają się być szybkie, jest to, że procedury przechowywane zmuszają do bardzo, bardzo ostrożnego projektowania transakcji.

ORM nie wymuszają w magiczny sposób ostrożnego projektowania transakcji. Projektowanie transakcji wciąż musi być wykonywane tak samo ostrożnie, jak podczas pisania procedur przechowywanych.

S.Lott
źródło
19
+1, ponieważ procedury składowane to całkowity ból przy pracy
Gary Rowe
3
: „(Nie mam problemu z procedurami przechowywanymi. To dla mnie kolejna warstwa abstrakcji.
Mike Weller,
3
Jeśli utworzymy SP, silnik bazy danych zapisze go w postaci skompilowanej i utworzy ścieżkę wykonania, aby działał jak najszybciej. Ale ORM wysyła SQL za każdym razem, które muszą zostać skompilowane i uruchomione przez silnik bazy danych. Myślę, że wolniej będzie używać ORM zamiast Procedury składowanej.
DeveloperArnab
4
Zabawny. Powróciliśmy z ORM do procedur przechowywanych tylko z powodu .. SPEED. Nie tyle czasu potrzebujemy na programowanie, ile czasu ORM na rzeczy takie jak zmaterializowanie obiektów, wyszukiwanie obiektu, aktualizacja na różnych klientach. SP, gdzie piekło jest znacznie szybsze. Jeden przykład: odczyt 30 000 obiektów z DB przy użyciu nowego nowoczesnego ORM wymaga ... no cóż. limit czasu po 2 minutach. Wywołanie procedury składowanej i uzyskanie wyniku - 2 sekundy. Tak - istnieje wiele sztuczek, takich jak stronicowanie, aby zredukować znacznik do DB z DB - ale duża różnica, jeśli chodzi tylko o to, że można użyć ORM lub
Offler
2
@DeveloperArnab: To może być prawda 20 lat temu, ale współczesne silniki DB są dość wyrafinowane i potrafią rozpoznawać wcześniej wykonane zapytania i ponownie wykorzystywać plany wykonania, różnica w prędkości jest obecnie tak niewielka, że ​​nie gwarantuje dodatkowych kłopotów z SP.
whatsisname
20

Procedury przechowywane są dobre, szybkie i bardzo wydajne i są idealnym miejscem do umieszczenia kodu związanego z danymi. Przeniesienie całego tego kodu do klienta ułatwi ci trochę jako programistę klienta (nieco, ponieważ nadal będziesz musiał aktualizować schemat i model ORM, gdy zmiany je zmieniają), ale stracisz cały istniejący kod i sprawisz, że Twoja aplikacja działa wolniej i prawdopodobnie jest bardziej delikatna, biorąc pod uwagę utratę wszystkich umiejętności SQL.

Zastanawiam się, czy DBA siedzą tam i mówią „och, każde zatwierdzenie, muszę ponownie ściągać klienta, powinniśmy zamiast tego przenieść cały kod do formularzy DB”.

W twoim przypadku powinieneś być w stanie zastąpić istniejący niestandardowy ORM (tj. Twoje zabawne klasy) komuś innym bez żadnych strat, z wyjątkiem zmian w sposobie pisania kodu za kodem. Możesz także zachować SP, ponieważ większość (wszystkich?) ORM chętnie je nazywa. Tak więc poleciłbym zastąpienie tych klas „Foo” ORM i odtąd. Nie zaleciłbym wymiany twoich SP.

PS. Wygląda na to, że masz dużo wspólnego kodu w klasach kodu, co sprawia, że ​​same w sobie stanowią wzorzec projektowy. Jak myślisz, jaki jest wzór? (ok, może nie być najlepszy, a nawet dobry, ale wciąż jest to DP)

Edit: a teraz z Dapper , każdy powód, aby uniknąć sprocs nad ciężkiej ORM nie ma.

gbjbaanb
źródło
3
+1, oczywistym pierwszym krokiem jest przejście do ORM i użycie tego do mapowania wyników istniejących procedur przechowywanych na obiekty. Pozbądź się tego całego ds.Tables[0].Rows[0]["FooName"].ToString()badziewia. Menedżer uwielbia procedury przechowywane? On je zatrzyma. Ale fizycznie niemożliwe byłoby argumentowanie, że przeniesienie całego tego powtarzalnego kodu bojlera na coś wygenerowanego przez, powiedzmy, LINQ na SQL, było złe.
Carson63000,
11
Nie mogę uwierzyć, ile „złego” jest w twoim poście. Twoje porównanie z DBA narzekającym na konieczność wyciągnięcia kodu jest nieodpowiednie i całkowicie bezsensowne. Przede wszystkim baza danych jest USŁUGĄ, która służy do przechowywania i pobierania danych, koniec historii. LOGIC, jak sama nazwa wskazuje, przechodzi do warstwy logiki biznesowej, która jest częścią kodu API. Bardziej delikatna aplikacja odsuwa się od sproców? Mówisz poważnie, czy tylko trollujesz? TDD aplikacja z logiką w sprocach i powiedz mi, ile to jest zabawy. Również ORM nie powinny być przełączane. Bazy danych są, ponieważ są tylko USŁUGĄ.
Matteo Mosca,
5
Naprawdę nie rozumiem, dlaczego niektórzy uważają, że baza danych jest jakąś świętą ziemią, w której wszystko jest święte. Pomyśl o tym. Kiedy firma zewnętrzna udostępnia Ci usługę, czy daje ci bezpośredni dostęp do swojej bazy danych, czy też maskuje ją za interfejsem API? Aby skorzystać z popularnego przykładu, skorzystaj z dowolnej usługi Google. Ty, programista, łączysz się z ich publicznym API, nawet nie wiesz, która baza danych jest pod nim, czy w ogóle istnieje baza danych. W ten sposób projektujesz solidne i oddzielone oprogramowanie. Bazy danych nie są przeznaczone do bezpośredniego dostępu przez aplikacje. Są do tego środkowe poziomy.
Matteo Mosca,
5
@Matteo Mosca: jasne, ale w jaki sposób oprogramowanie pośrednie uzyskuje dostęp do bazy danych ... jest klientem bazy danych. „klient” nie oznacza „GUI” lub „aplikacji komputerowej”. W warstwach aplikacji jest wiele szarych obszarów - czy sprawdzanie poprawności odbywa się w graficznym interfejsie użytkownika, czy w logice serwerowej / biznesowej? Powinien zostać umieszczony na serwerze, aby był przejrzystym projektem, ale będzie to naprawdę kiepskie pod względem wydajności i czasu reakcji użytkownika. Podobnie, często umieszczasz logikę w bazie danych, gdy poprawia ona wydajność i (w tym przypadku) poprawność danych.
gbjbaanb
4
Przepraszam, ale nadal się nie zgadzam. W dniu, w którym musisz wdrożyć aplikację w innym środowisku, w którym nie używasz tej samej technologii DB, z której korzystałeś, znajdujesz się w sytuacji, w której aplikacja nie może zostać uruchomiona, ponieważ nie masz wszystkich sprocków w nowej bazie danych .. i nawet jeśli je odtworzysz (co jest całkowitym bólem), mogą być różne, ze względu na różnice w dialektach SQL itp. Scentralizowany interfejs API z logiką i sprawdzaniem poprawności, udostępniany przez standard (np. SOAP lub REST) ​​rozwiązuje to problem i dodaje testowalności, wersjonowania i spójności.
Matteo Mosca
13

Wygląda na to, że próbujesz poprowadzić swój zespół od jednej skrajności (procedury składowane i zestawy danych) do drugiej (pełna ORM). Sądzę, że istnieją inne, bardziej inkrementalne zmiany, które można wprowadzić w celu poprawy jakości kodu warstwy dostępu do danych, które zespół może chętniej zaakceptować.

Na wpół upieczony kod implementacji aktywnego rekordu, który opublikowałeś, nie jest zbyt elegancki - zaleciłbym zbadanie Wzorca Repozytorium, który jest łatwy do zrozumienia i wdrożenia i jest bardzo popularny wśród programistów .NET. Ten wzór jest często kojarzony z ORM, ale równie łatwo można tworzyć repozytoria za pomocą zwykłego ADO.NET.

Co do DataSet - fuj! Biblioteki klas będą znacznie łatwiejsze w obsłudze, jeśli zwrócisz obiekty o typie statycznym (lub nawet dynamicznym). Wierzę w tę ilustrację wyjaśnia moją opinię o DataSet lepiej niż mogłem.

Ponadto możesz porzucić zapisane procy bez przeskakiwania do ORM - nie ma nic złego w używaniu parametru SQL SQL. W rzeczywistości zdecydowanie wolę to niż używanie przechowywanych proc, chyba że masz skomplikowane procedury, które oszczędzają na wielu podróżach w obie strony na serwer. Ja też go nienawidzę, gdy otwieram starszą bazę danych i widzę niekończącą się listę procedur CRUD.

Nie zniechęcam do korzystania z ORM - generalnie używam ich w większości projektów, nad którymi pracuję. Widzę jednak, dlaczego próbowanie wprowadzenia jednego do tego projektu i twojego zespołu może być bardzo trudne, brzmi to tak, jakby przestali się uczyć nowych rzeczy około 8 lat temu. Powiedziawszy, że zdecydowanie spojrzę na nową rasę „Micro ORM”, takich jak Dapper (używany do zasilania tej strony nie mniej) i Massive , z których oba są niezwykle łatwe w użyciu i trzymają cię bliżej SQL niż typowe ORM i które Twój zespół może chętniej zaakceptować.

richeym
źródło
2
Myślę, że problem polega na tym, że kiedy aplikacja została napisana, nie było żadnych ważnych ORM dla platformy .NET, więc zrobiono to w inny sposób (ASP.NET 1.1) i nikt nigdy nie pomyślał, aby zrobić to (lub cokolwiek innego) inaczej aż dołączyłem kilka miesięcy temu.
Wayne Molina
1
+1 dla Wytwornego. Właśnie zacząłem używać go w projekcie i jest niezwykle łatwy do wdrożenia i użycia. Jestem już wielkim fanem.
SLoret
4

Jestem w podobnej sytuacji, właściwie nasz sprzęt, władza i polityka przechodzą na stronę bazy danych, więc wszystko przechodzi procedurę składowaną. Niestety są one kłopotliwe dla kodera, szczególnie jeśli chodzi o generowanie metadanych i kodu, ponieważ w procedurach przechowywanych nie ma tak bogatych metadanych jak tabele.

Niezależnie od tego nadal możesz pisać elegancki i czysty kod za pomocą przechowywanych proc. Obecnie sam wdrażam wzorzec repozytorium ze wszystkimi procedurami przechowywanymi. Sugerowałbym, aby spojrzeć na FluentAdo.net na jego genialny pomysł podczas mapowania z lidera danych z powrotem do twoich obiektów biznesowych. Wziąłem kawałek tego pomysłu i zmieniłem jego przeznaczenie na moje domowe rozwiązanie.

Justin
źródło
3

JFTR - jestem skromnym programistą PHP, ale brzmi to jak kwestia polityczna.

Biorąc pod uwagę skalę „zgnilizny” napędzającej aplikację, to - pomijając najlepsze praktyki - pojawiłby się znaczny narzut, aby ją wykorzenić. Brzmi to tak, jakby graniczyło z terytorium przepisywania.

Czy możesz zagwarantować, że zaproponowana przez ciebie alternatywa przyniosłaby korzyści uzasadniające koszty dla firmy? Podejrzewam, że ROI tego przedsięwzięcia może być trudne do sprzedania firmie. Chyba że aplikacja jest niestabilna lub możesz udowodnić zasadność przeglądu pod względem finansowym - może to być trudne.

Czy ORM jest jedyną alternatywą dla SPROCS? Istnieje kilka wzorców projektowych między pełnowymiarowym ORM a waniliowym SQL. Być może mógłbyś rozpocząć proces od stopniowego przenoszenia SPROCS z DB do DBAL. Istnieje oczywiście niebezpieczeństwo, że z czasem przerośnie to w ORM - ale będziesz miał krok bliżej celu.

sunwukung
źródło
2

Kilka lat temu przeszliśmy z SP na ORM.

W jednym przypadku musieliśmy zaktualizować 80 tabel. Stary model szacowania oszacowałby na to 80 godzin w przypadku entlib i SP. Zrobiliśmy to w 10 :)

Dało nam to o 80% mniej czasu poświęcanego na tworzenie warstwy dostępu do danych.

Shiraz Bhaiji
źródło
1
I nie możesz napisać skryptu aktualizacji tabeli, dlaczego?
Darknight
Zajmowało to złożony obiekt w pamięci i zapisywało go jako relacyjną bazę danych do raportowania. Napisaliśmy program, który zrobił refleksję nad obiektem, aby utworzyć strukturę tabeli.
Shiraz Bhaiji
-1

Bardziej wydaje mi się, że podstawowym problemem jest to, że Twoje wdrożenia nie działają poprawnie i automatycznie.

Może być łatwiej ustawić silnik ciągłej kompilacji, który wie, jak manipulować bazami danych w razie potrzeby po każdym zatwierdzeniu.


źródło