.. które nic nie wnoszą a tylko bardziej komplikują życie. O jakich przykładach mówię? O przykładowych aplikacjach w technologii .NET. Tak, wiem, że Ayende jak i wielu innych nie raz jechali po pewnych konkretnych przypadkach (i dalej jeżdżą). Jednak do mnie dopiero ostatnio dotarło, że dobrych przykładów to szukać jak ze świeczką.
Zacznijmy od początku. Rozpoczynamy nowy projekt, i jednym z wymagań jego jest posiadanie audytu każdej prawie operacji użytkownika. Jak tylko zacząłem sobie uświadamiać – log każdej operacji – zaświeciła mi się w głowie żarówka: przecież posiadając log operacji będę mógł zrobić undo operacji, tak działa Google Contacts, tak działa Remember The Milk.
Nie ma co, podjarałem się jak nie wiem co, widziałem już do czego dążę, pora była zabrać się za implementację prototypu. W głowie mi coś tam świtało że Greg Young napisał kiedyś ogólny post o CQRS i Event Sourcingu. Szybki search w gógle dał wynik. Przemyślałem to co przeczytałem i stwierdziłem, że tak, o to mi chodzi – posiadając log eventów jestem wstanie dość szybko i sprawnie wykonać zarówno undo jak i redo.
To był ostatni moment kiedy byłem podjarany tym pomysłem, ostatni, bo przykłady spowodowały że miałem ochotę coś rozwalić. Nie licząc jednego przykładu (z tych, które znalazłem) wszystkie implementacje CQRS jak i Event Sourcing są po prostu o dupę potłuc. Najgorsze jest to, że nie szukałem framework (a tylko takie znajdywałem) a szukałem po prostu przykładu jak to można rozwiązać mój problem (przykładowa implementacja, podejścia itp.), chciałem zobaczyć czy jestem wstanie na tym pracować (czy CQRS jest naprawdę tym czymś i czy Event Sourcing załatwia lub pomaga załatwić to co chcę osiągnąć) a nie mam czasu by pisać wszystko od nowa powtarzając błędy poprzedników.
Mały disclaimer: nie uważam, że programiści pracujący nad tymi frameworkami są kiepscy, uważam, że są i to niektórzy zajebiście dobrzy i super fajnie, że postanowili coś takiego napisać, nauczyć się i wynieść coś z tego.
Po pierwsze wszystkie frameworki są nad wyraz skomplikowane. Coś co zajmuje 3-5 plików cs jest nagle rozdmuchane do niewiadomych rozmiarów. Po co stworzyć framework jak MVVM toolkit light, lepiej od razu do niego dodać 20 różnych wsparć dla baz danych, tworzyć abstrakcję nad abstrakcją – no bo się przyda jak będę chciał dodać ekstra bazę danych, która jeszcze nie istnieje ale pewnie ktoś ją kiedyś stworzy.
Po drugie, wszystkie zakładają, że robię DDD, baa przykłady wykorzystania ich pokazują na przykład jak stworzyć DDD za pomocą jednej klasy Notatnik… no bez przesady. Jak już chcecie coś takiego pokazać, zróbcie przykład który jest godny DDD i który jest właściwy. Tak jakby żadna z osób nigdy nie czytała bloga Ayende który cały czas wytyka takie rzeczy. Aż dziw bierze.
RYS ncqrs DDD WTF
Po trzecie mimom tego iż sam Greg wspomniał o tym w jego dokumencie opisującym CQRS i Event Sourcing, każdy ale to dosłownie każdy dalej zamiast zrobić logiczną nazwę Event Provider ID, nazywa to Aggregate Root ID. To tak jakby mało było tego, że cała reszta jest ściśle powiązana z DDD to jeszcze z założenia wszystkie te proste frameworki z założenia chcą być skomplikowanie. Tego absolutnie nie rozumiem.
Po czwarte, nie spotkałem frameworku, w którym by mi się z pryjemnością pisało. Każdy z nich trochę inaczej podchodzi do tematu i każdy trochę inaczej podchodzi do event sourcingu. Co jest fajne, ale jeżeli ja mam brać w using event sourcing to chyba coś jest nie tak. Event Sourcing powinien być przezroczysty dla jakiegokolwiek programisty, na pewno nie powinno się to wiązać z myśleniem czy ja aby na pewno nie zapomniałem o czymś? Z przykładów wywnioskowałem tylko jedno: posiadając Event Sourcing muszę posiadać CQRS oraz nie mogę mieć implementacji CQRS bez Event Sourcingu. Co framework to tym bardziej zakręcone rzeczy z coraz bardziej banalnymi i zarazem skomplikowanymi przykładami jego wykorzystania. Jeden na przykład by wyświetlić 3 informacje na ekranie potrzebował 100 linijek kodu – przykład! Wykorzystania! Frameworku! Coś chyba jest nie tak.
Do tego jeszcze można dodać rzecz nie bywałą, ale chyba często spotykaną w świecie .NET, kompilacja tych frameworków wcale do prostych nie należy. A to brakuje IIS, a to wymagany jest SQL Express, a to wymagany jest SQL z konkretną nazwą bazy oraz schematem którego nigdzie znaleźć nie można, a to brakuje referencji, a to ktoś linkuje do katalogu bin, który jest pusty bo w końcu na github nie trzyma się dllek. Poziom skomplikowania procesu build wcale nie był powiązany ze skomplikowaniem frameworku .
A jak kompilacja może i działa z miejsca to strona projektu daje taki o to wynik:
Po obejrzeniu tego co znalazłem naprawdę zastanawiam się co chodziło po głowie twórcą danego rozwiązania – jedyną rzeczą jaka mi przychodzi na myśl to pokazanie jak z czegoś prostego zrobić coś co jest tak skomplikowane, że się odechciewa na to patrzeć. Choć jeden framework w dokumentacji miał wyraźnie napisane, że powstał on dla konkretnego projektu i teraz jest on udostępniony.
Podobała mi się odpowiedź Grega na te wszystkie przepiękne przykłady – zrobione to samo co każdy z frameworkow tylko, że w 500 linijkach. Da się prosto? Da, to po jakiego grzyba komplikować sprawy proste?
Jeżeli byłbym osobą uczącą się programowania, to patrząc na to co jest dostępne stwierdziłbym, że jest to coś super ciężkiego, skomplikowanego i na razie poza moim zasięgiem. Czy naprawdę o to nam chodzi?
Na przykład jakbym miał pokazać long polling w javascript to raczej nie pisałbym masywnego kodu, a jedynie wkleił taką o to funkcję:
(function poll() { $.ajax({ url:'@Url.Action("TimeTest", "DropDowns")' , success: function (data) { $('#time').append('<li>' + data.time + '</li>'); } , dataType: 'json' , type: 'POST' , complete: poll , timeout: 30000 }); })();
To naprawdę takie trudne? Czy do tego trzeba tworzyć niebywale skomplikowane frameworki?
Pewnie bym sobie poklną pod nosem i olał te przykłady gdyby nie to, że zacząłem w tym samym czasie uczyć się Node.js, gdzie community od Node mnie rozwaliło na łopatki. Od banalnych przykładów poprzez w pełni działające witryny. Krok po kroku, jak z tego można korzystać, co można łączyć, jak to łączyć. Dlaczego lepiej jest zainstalować paczkę niż samemu to pisać. Implementacja wzorca? Ok nie ma problemu to nie jest takie trudne, wystarczy stworzyć taki moduł i to będzie działać o tak i następnie mamy paczkę gotową do re-użytkowania. A nie wiesz co, tu masz 10MB kodu źródłowego (sama pliki tekstowe), nie ma sensu byś sam to pisał bo jak widzisz jest to tak skomplikowane, że lepiej to zostaw nam.
Po prostu szczęka mi opadła. W ciągu 3 tygodni nauki Node, mogę powiedzieć, że rozumiem jak działa (na jakiej zasadzie), jak napisać prostą aplikację, jak wykorzystać WebSockets, jak zrobić undo managera czy nawet event sourcing w kilku banalny modułach i wile innych rzeczy.
W tym samym czasie na community wokół .NET udało mi się parę razy siarczyście przekląć – kolejny przykład jeszcze bardziej komplikujący coś prostego z mizernym wytłumaczeniem o co autorowi chodziło i jeszcze gorszym przypadkiem wykorzystania.
Zastanawia mnie gdzie leży problem? Bo i tu i tu ludzie są łebscy, ale nikt nie stworzy wydumanego framework dla node (albo dla przykładu Event Sourcing helper dla Clojure, czy też w Scala <podobny do Grega>) bo niby po co? Zaś dla .NET? jasna, doda jeszcze 6 abstrakcji nad abstrakcjami bo może kiedyś w przyszłości stwierdzi, że zamiast EF będzie wykorzystywał SimpleDB albo MongoDB więc już warto to uwzględnić w przykładzie bo jak ktoś się uczy to musi wiedzieć, że tak się to robi. A potem przychodzi się do firmy i ma się: Model w NH, następnie Active Record, potem Business Logic classes library, które opakowuje Active Record do tego klasy pomocnicze, klasy bazowe przyjmujące po 4! generyczne typy parametrów. Aktualizacja modelu NH wymaga aktualizacji 4 innych klas a dopiero potem aktualizacji klas, które z tych klas korzystają – poplątanie z poplątaniem. Do tego stopnia, że w którymś momencie dodanie 5 własności kończyło się 2-3h pracą. Na pytanie skąd taka architektura? Odpowiedź padła: o z tego przykładu na codeplex (sic!).
Więc wszystko wraca do punkty wyjścia – zbyt skomplikowane przykłady rozwiązań powodują sieczkę w głowie programistów. Szczerze, sam sobie zadaje pytanie przeglądając przykłady czy ja jestem tępy czy to ktoś zrobił tak bym ja tego nie rozumiał?
Podsumowanie
Po co ten post? Trochę by mi ulżyć trochę ku przestrodze twórcom takich frameworków. U mnie skończyło się na napisaniu własnego prostego kodu, który spełnia stawiane oczekiwania i to głównie na podstawie kodu Grega.
Wykorzystanie czyjegoś frameworku, który w założeniach jest ponad miarę skomplikowany mijało się z celem. Przykładowy prototyp wymagał mniej więcej tyle samo linii kodu z wykorzystaniem framework jak i z napisaniem swojego kodu plus kodu z niego korzystającego.
Zresztą jak mnie pamięć nie myli (a nie mogę tego znaleźć więc możliwe, że tak) to Greg wspominał o tym, żeby nie tworzyć frameworków dla CQRS i Event Sourcingu, dlatego też napisał swój przykład, by pokazać, że to nie jest i nie powinno być skomplikowane.
Albo weźmy pragmatyczne podejście Procenta z przykładem MVP dla WinForms. Proste? Tak, wymaga dużo kodu? Nie. To po jakiego grzyba MS stworzył coś co wymaga: instalki, odpowiednich typów projektu i masy dodatkowych referencji a w rezultacie daje to samo co przykład Procenta?
Jakoś nie mogę dać za wygraną i ciągle próbuje to zrozumieć – po co, dlaczego, ale jakoś mi to nie wychodzi. Może ty czytelniku będziesz wstanie mi na to odpowiedzieć, może nakierujesz w dobrą stronę. Może masz odmienne zdanie albo moją paplaninę traktujesz jako obrazę lub pisanie bez konkretów?
Mały disclaimer: nie twierdzę, że w świecie .NET nie ma dobrych przykładów, jest ich masa, ale ciężko czasami jest je znaleźć, dużo łatwiej jest trafić na śmiecia niż na coś co ma ręce i nogi.
PS.: pomyśleć, że tylko chciałem zobaczyć przykładową implementację/sposób rozwiązania… a skończyło się chyba na mały rant’cie i to jeszcze implementacji CQRS i Event Sourcingu :(
PS2.: by nie było, jestem zwolennikiem Open Source i lubię widzieć, jak ludzie tworzą i rozwijają swoje projekty, ale są projekty dobre (NH, nServiceBus, xUnit etc.) jak i złe (nie będę wymieniać). Na dobrych można się wzorować albo aż chce się je wykorzystać. Złe no cóż, różnie bywa… Są też projekty pośrednie – wyśmienite playgroundy (w końcu świat nie jest czarno-biały)
Nie myślałeś, że to może dlatego, że jednak (uwaga: własna obserwacja) .NET używany jest w firmach, gdzie dominują ciężkie metodyki, z dużą ilością dokumentacji i abstrakcjami na abstrakcjach, gdzie liczy się masywna architektura, a nie jakiś tam "adżajl"? Z tego też powodu przykłady są dostosowane do takiego stylu, frameworki spełniają wymagania liczby warstw abstrakcji i wszystko jest cacy dla tego właśnie biznesu?
tutaj raczej poruszyles inny problem: sposob zarzadzania projektami/myslenia korporacyjnego. gdzie na poczatku musi powstac wszystko i jest myslenie globalne robione sa rzeczy zbedne itp.
jednak czy to ma wplyw na to, ze ludzie tworza przyklady wlasnie pod to? nie sadze, raczej moze ludzie wywodza sie z takiej korporacji i dlatego tez tworza takie przyklady – innego sposobu nie znaja?
wezmy Udiego – on chyba caly czas siedzi w tych wlasnie "ogromniastych" projektach, jednak jego przyklad z Domain Events jest po prostu wyczes, prosty, jasny i praktyczny.
moze wiec to jest wina tak jak mowisz sposobu myslenia? nie wiem :(
Oczywiście – być może nie, ot taka moja hipoteza, a Twoje ulepszenie jej też mi się podoba :) Udi to człowiek nader utalentowany i może jemu takie "pranie mózgu" nie zaszkodziło, a reszcie się niestety nie udało :P
Aleś się zirytował:).
Zgadzam się że przykłady są w większości zbyt skomplikowane – nie skupiają się na tym co chcą pokazać, ale na całej otoczce która w danym kontekście nie ma żadnego znaczenia.
Nie zgadzam się natomiast, że "_nie mogę mieć implementacji CQRS bez Event Sourcingu_". Najpierw CQRS, potem "nad tym" ES.
Wbrew pozorom nie jest to temat prosty, ale po poświęceniu kilku godzin na zapoznanie się materiałami opublikowanymi (głównie) przez Grega można to ogarnąć. Kiedyś pobawiłem się trochę CQRS i wrzuciłem efekt na githuba ( https://github.com/maniserowicz/ProcentCqrs ). Co prawda prawie nic tam nie ma, ale poszczególne commity i tagi pokazują na co na początku zwracałem uwagę (podział na read/write, wykorzystanie NH po stronie write i simpledata po stronie read, testy jednostkowe etc…).
@Procent
z tym _nie moge miec implementacji_ chodzilo mi o przyklady. kazdy z nich zakladal ze obie rzeczy sa scisle powiazane ze soba w roznym stopniu.
dla mnie CQRS to CQRS a Event Sourcing to Event Sourcing. jednak jezeli mam to polaczyc, to do mojej aktualnej architektury powinienem moc dodac event sourcing bez wiekszych zmian w projekcie. jezeli mam bus do wysylania command, to event sourcing podpinam pod ten bus – ES jest tutaj niewidoczny. ja to tak rozumiem.
jakbym mial robic otoczke na CQRS by wprowadzic ES (na przyklad otaczac wyslanie command using) to raczej bym tego nie chcial robic.
zreszta w Twoim przykladzie tez tak jakby to zakladasz, gdybys mial teraz podpiac ES to raczej bys to zrobil w CommandBus albo gdzies tam a nie w kontrolerze opakowal commandSender.Send by dodac ES :)
wiec chyba po prostu musialem nie wyraznie napisac to o co mi chodzilo :)
Trafione w punkt. Idealne.
Gutek, to co piszesz o przykładach dobrze wpisuje się w nieco ogólniejszą obserwację dotyczącą sposobów przekazywania wiedzy w książkach, prezentacjach, etc. i sprowadza się do zgrubnego podziału na tych, którzy dzieląc się swoją wiedzą zdają się mówić ‘zobacz jakie to proste’ oraz tych, którzy dają do zrozumienia ‘zobacz jaki jestem mądry’. Odnoszę wrażenie, że to co odróżnia pierwszych od drugich, to doświadczenie i faktyczna wiedza, choć może też wynikać z tego, że często open source wykorzystywany jest przez wiele osób do ‘zademonstrowania swoich umiejętności’ przed potencjalnym pracodawcą, a niekoniecznie rozwiązania rzeczywistego problemu.
A potem człowiek czyta i się zastanawia czy naprawdę jest aż tak pozbawiony inteligencji i wyobraźni. Mnie np. fascynowało zawsze to, iż napisany na moje potrzeby kontener IoC składa się z grubsza z około 10 klas, a te dostępne w sieci mają co najmniej 10 razy tyle.
Comments are closed.