Neviem, ale ja to poznám ako lasagne-ový kód. Aj keď cibuľa je možno lepšia..
Lasagne znám v jiném významu – kód, který se sice programátor snažil rozdělit do vrstev, ale jednotlivé vrstvy nakonec prorostly: https://en.m.wikipedia.org/wiki/Spaghetti_code#Lasagna_code
Budeme-li brát v úvahu i "Vícevrstvé architektury", jsou podobné principy návrhu architektury systémů známy již desítky let. Věřím, že drtivá většina studovaných programátorů se jimi řídí a již desítky let se snaží vrstvy oddělovat. V oboru jsem skoro už dvacet let. Pracuji převážně na velkých informačních systémech, které dané principy dodržují/dodržovaly.
Zatím jsem nezažil, že by si někdo troufnul vyměnit jednu z těch vrstev v obalu té cibule s tím, že zbytek se nechá skoro beze změny. Např. výměna prezentační vrstvy ve velkém systému je skoro nemožná, hlavně proto, že prakticky je i v prezentační vrstvě spousta business logiky (např. "pokud zaškrtnu tenhle checkbox, tak schovej tyhle dvě políčka" - v informačních systémech takováhle pravidla tvoří troufnu si říct vlastně většinu všech business rules). Nebo pokud někdo napíše danou aplikaci pro konkretní databázi (např DB2), tak i kdyby jste měli všechna DML a DDL v SQL standardu, tak vám to s jinou databázi prostě fungovat nebude (respektive ono se to rozjede, ale dáte ruku do ohně za to že to funguje naprosto stejně? :)).
Z mojí zkušenosti se ke starším systémům buď začal přilepovat kód v nové technologii (např souběh dvou prezentačních vrstev) a nebo se celý systém vzal a přepsal se komplet do nových technologií. Pokud někdo někdy zažil něco jiného prosím napište níže - mám na mysli systémy velikosti řádově statisíců řádek, fungujících mnoho let.
Takže s článkem souhlasím, s vrstvením souhlasím, ale pouze pro účely snadnějšího porozumění systému jako celku. Vrstvení za účelem možné "snadné" výměny nějaké části je teorie, kterou jsem v praxi opravdu nezažil a nemyslím si že je možná.
Čím jsem starší, tím víc mám pocit, že se stačí držet SOLID principů (https://en.wikipedia.org/wiki/SOLID) nejenom v návrhu tříd, ale i v návrhu modulů či integrace systémů... zbytek tak nějak vyplyne sám...
24. 1. 2020, 08:28 editováno autorem komentáře
@wajtr
Tak jest. Skoro každá déle exitující firma to tak má. Málokterá má čas peníze a chuť pořád všechno přepisovat a ještě dostatečně často. V momentě kdy i celou aplikaci zahodí a napíše znova, jako tuším třeba Aukro, tak se nevyhne tomu co píšete a od určité chvíle se iz toho nového systému stává to co píšete.
Každopádně bych pro Vás měl jeden běžný příklad užití vrstvení za účelem výmeny technologie - jsou to databázové mappery jako Doctrine (php) nebo Hibernate (Java) které pokud jsou správně implementovány do aplikace (persistence, repository, facade, ...) umožňuji kompletní výměnu datového úložiště - přímo a prakticky se tak děje např. u Doctrine kdy pro účely automatizovaného testování použijete SQLite DB a pro aplikaci třebe MariaDB nebo MySQL. Abych byl férový, narazili jsme na jednu (ale jedinou) obezličku kterou jsme kvůli použití SQLite pro testy museli vyřešit v jednom Repozitáři.
Samozřejmě i tak je to u složitější aplikace často něco za něco.
24. 1. 2020, 09:16 editováno autorem komentáře
Jo, jenže proč bych je měl spouštět po každé změně? Od toho tu je právě oddělení na doménový model, infrastrukturu, kam patří repositories a aplikační vrstvu (use-cases). Když už, tak tyhle testy oproti DB nakonec pouštím na CI/CD serveru. Pokud se hrabu v doménovém modelu, vůbec mě tohle nezajímá víz pojem "Persistence ignorance"
24. 1. 2020, 16:27 editováno autorem komentáře
@uetoyo
Pokud vyvíjíte složitou aplikaci s velmi složitými ? obsáhlými daty, ke všemu ješté od píky, mockovat MB odpovědí v rúzných kombinacích je fakt opruz a ztráta času v týdnech. Moct si spustit testy (třeba celou složku) při psaní nějaké složitejši logiky bez penalizace kolikrát chcete v čase 1s nad reálnou DB je k nezaplaceni - ne vzdy jenom čtete a používáte jednu entitu bez vazeb, že ....
Nehledě na to že když si neco do té Vaší oddělené vtrstvy namockujete a na druhém konci aplikace data zmenite, tak tu chybu objevíte už pri vývoji, ne az po commitech a cekánim na CI/CD testy a vracenim se od dalsi rozdelane prace. A dalsim kolečkem mockováni a CI/CD.
Jinak spouštění určité části testů při každé změně je jedna z běžných praxí, Test Driven Development.
24. 1. 2020, 23:02 editováno autorem komentáře
"Jinak spouštění určité části testů při každé změně je jedna z běžných praxí, Test Driven Development." Jasně, ale když máte oddělené vrstvy např. doménovou, tak nepouštím vedle jednotkových testů i integrační po každé změně na svém lokálu. Ještě jinak ...když změna náleží doménové entitě (entitám) tj. operuje jen nad ní, nezajímá mě persistence tj. integrační testy. __TDD není o tom pouštět všechny testy, které navíc vůbec nesouvisí se změnou, kterou jsem udělal__.
25. 1. 2020, 11:57 editováno autorem komentáře
@uetoyo
"Jasně, ale když máte oddělené vrstvy např. doménovou, tak nepouštím vedle jednotkových testů i integrační po každé změně na svém lokálu"
Však to taky nikdo netvrdil. Ale ne vždy pracujete jenom s jednotkami, že? Např. při hledání problému nebo jejich zkoušením ... Pokud děláte něco složitějšího než "Rabit::sayHello" často pracujete opakovaně s funkcionálními testy. Např. když budujete větší API - jednotky si sice napíšete, ale k čemu je Vám endpoint když si nezkusíte že Vám skutečně něco vrací - což je význam funkcionálních, resp. integračních*, testů. Kruh uzavřen.
*Často se rozdíl stírá s komplexitou a variabilitou aplikace, AFAIK neexistuje jednoznačné rozlišení pro každý případ. Teorie a definicí je samozřejmě hromada, není nutno sem nějakou rychle vygooglenou kopírovat.
"Ještě jinak ...když změna náleží doménové entitě (entitám) tj. operuje jen nad ní, nezajímá mě persistence tj. integrační testy. __TDD není o tom pouštět všechny testy, které navíc vůbec nesouvisí se změnou, kterou jsem udělal__."
1) To nikdo netvrdil
2) Až budete opravdu pravidelně a poctivě testovat zjistíte, že "testy, které navíc vůbec nesouvisí se změnou" je celkem pravidelný zdroj překvapení co všechno je možné rozbít na různých koncích aplikace.
25. 1. 2020, 12:15 editováno autorem komentáře
'Až budete opravdu pravidelně a poctivě testovat zjistíte, že "testy, které navíc vůbec nesouvisí se změnou" je celkem pravidelný zdroj překvapení co všechno je možné rozbít na různých koncích aplikace."' Ještě jednou: některé testy pouštíme na CI/CD. Nemá smysl je pouštět na lokále. Ano, pokud dělam změnu která řeže projekt vertikálně, tak se to samozřejmě může dotknout různých částí aplikace. Nevím z čeho hned vyvozujete, že někdo pravidelně a poctivě netestuje.
@uetoyo
Z čeho tak vyvozuji? Vyvozuji tak z toho co tu tvrdíte. Např. ten Váš "vertikální řez" - když se nad tím zamyslíte, tak pokud nemáte jednovrstvou aplikaci, tak Váš kód v oné vrstvě bude mít vždy nějaký vertikální dopad. A je to přesně obsahem oné poznámky:
Až budete opravdu pravidelně a poctivě testovat zjistíte, že "testy, které navíc vůbec nesouvisí se změnou" je celkem pravidelný zdroj překvapení co všechno je možné rozbít na různých koncích aplikace."
Spletl jsem se ale v jedné věci. Na toto není ani potřeba mít žádné zkušenosti s testováním. To, co je obsahem zmíněného výroku, je přesně důvodem velmi častých problémů nasazování netestovaného kódu do produkce a častým zdrojem překvapení zejména mladých programátorů - že úpravou nějaké malé blbosti v jedné vrstvě rozbili nějakou funkcionalitu v úplně jiné vrstvě o 50 souborů vedle, přestože se pokusili po opravě kód ještě prověřit fulltextem IDE.
Nikdo Vás taky nenutí pouštět všechny testy úplně pokaždé, ale většinou (mrkněte do manuálu) se dají pustiti testy jenom pro nějakou jednu dvě složky, něco jako např.
tests/[func|unit]]/{*}HandlingService
(pokud to teda nemáte všechno úplně na jedné hromadě) a nebo se dá často filtrovat podle názvu, např. něco jako
./run --filter "Users|Aeroplane"
či třeba jenom
./run tests/functional/services/someService::testHandleSomething
což ale může zahrnovat i dalších x vrstev, y souborů a hromadu dat - přes loginy a externí služby .... je dobré moct si vyzkoušet hned na místě že to co bylo zaneseno do testů funguje i po opravě. Napsal jsem dobré, ale je to úžasné, protože mezi tím nemusíte pootvírat dalších milion blbin k další věci než Vám dojede CI/CD a vy zjistíte že jste něco nedomyslel.
A nebo si můžete napsat funkcionální test pro novou metodu a jeho opakovaným spouštěním dokonce zjišťovat jak aplikace funguje, co Vám různé služby vrací a postavit tak úplně novou funkcionalitu (Test Driven Development) nebo prokázat že to zatím nejde a můžete to každému kolegovi jako proof of koncept s užitím debugeru a datových fixtur nechat ukázat třeba 1000x za sebou - a když Vám to pak třeba opraví tak to můžete zrovna nechat jako test - aniž byste se k tomu např. musel pořád proklikávat dokola nějakým rozhraním a lovit nějaké něco někde po lozích a konzolích nějakých aplikací a browserů .... To v CI/CD budete dělat těžko ;-)
25. 1. 2020, 17:55 editováno autorem komentáře
Z čeho tak vyvozuji? Vyvozuji tak z toho co tu tvrdíte. Např. ten Váš "vertikální řez" - když se nad tím zamyslíte, tak pokud nemáte jednovrstvou aplikaci, tak Váš kód v oné vrstvě bude mít vždy nějaký vertikální dopad.
To je nesmysl. Servisní funkce co provádí nějakou kalkulaci, ovlivní ukldádání do DB? Každá metoda co náleží nějaké entitě ovlivní hned všechny další vrstvy aplikace? Prosím stáhněte si nějakou knihu o DDD. Osobně nemám v době dockeru problém si pustit testy i nad DB lokálně, ale často to stačí až na CI/CD serveru. Pěkný večer přeji.
26. 1. 2020, 20:54 editováno autorem komentáře
@uetoyo
Hmmm, takže nezamyslel.
* Servisní funkcí předpokládám myslíte funkci v nějaké službě (třídě)
1) V textu který citujete je věta tak pokud nemáte jednovrstvou aplikaci. Bavíme se o apliaci a jejich vrstvách a o tom Vašem "vertikálním řezu", vzpomínáte? Je to opět i v té citaci kterou jste uvedl.
2) To že najdete nějakou konkrétní funkci která nedělá nic s databází nic neznamená, použitá může být na spustně jiných míst a už vůbec to neznamená že jsou takové funkce všechny. I tato Vaše funkce bude nějaký další kód ovlivňovat, pokud to není 'main' funkce s výpisem do konzole z HelloWorld Tutoriálnu. Minimálně bude Vaše aplikace mít nějakou zobrazovací vrstvu.
3) Je hezké že si pouštíte testy i lokálně. Tak proč píšete věci jako
eště jednou: některé testy pouštíme na CI/CD. Nemá smysl je pouštět na lokále. Ano, pokud dělam změnu která řeže projekt vertikálně, tak se to samozřejmě může dotknout různých částí aplikace.
a teď ještě přinášíte příklad který by snad neměl ani vertikální rozměr mít?
Co se mi tu vlastně snažíte tvrdit? Že běžné jsou aplikace které nemají vrstvy a testování po změnách na localhostu je nesmysl?
Díky už nám to asi všem stačilo -- mě už určitě. Máte v tom jasno, není třeba to dál rozebírat. Půjčtě si knihu, třeba tuhle: https://pragprog.com/book/swdddf/domain-modeling-made-functional nebo tuhle https://www.manning.com/books/functional-and-reactive-domain-modeling
27. 1. 2020, 21:37 editováno autorem komentáře
A ještě naposled pro vás:
> These tests are slower than in-memory unit tests, but that’s ok. They don’t need to be executed as often as unit tests. Only when persistence logic changes occur which usually happens more rarely than domain logic modifications.
http://www.taimila.com/blog/ddd-and-testing-strategy/
27. 1. 2020, 22:13 editováno autorem komentáře
@uetoyo
Ale já tyto věčné debaty ohledně strategie testováni znám. Samozřejmě na to mám svůj názor, argumenty a znám i spoustu argumentů ostatních stran. Tak argumentuji, nemusím se schovávat za obecné odkazy a tvrzení demonstrované na urcitých řekněme specifických pripadech. Dokonce existují i názory že stačí jenom plné unit testy, někomu stačí jenom code coverage a dokonce jsem nedávno mluvil s člověkemz jiné firmy který se přiznal že nedavno na pohovoru rekl ze testy jsou ztrata času - vsak vi co měnil. To vám neprisuzuji, to jenom abyste videl že tezí je mnoho, já měl za to ze se bavime o reálné praxi a zkusenostech.
Jako myslete si o mě co chcete, ale z denodenní praxe testování vím, že se celkem často chyba nebo zmena projeví i vvdalsich vrstvach aplikace - ono je to taky logicky tím že ty tvrsvy a jejich akce jsou na sebe navázané.
No a speciálně pro Vás: Začnete mluvit o "řezu vrstvami", občas to vztáhnete jenom na vrsrvu persistence (jako v itaci vyse) a příklad dáte s funkcí v nějaké evidentne jednovrstvé implementaci. Asi byste si ty okazy měl projít nejprve sám a pak to vyzkouset i prakticky. Já Vám prakticky priklad dam.
Nedavno jsem opravoval funkci v jedné službě (třída), unit testy jsem upravil, pustil jsem functionalni testy podle jmena (asi 3) a zjistil jsem, ze v jine metode kde je tato funkce pouzita v jednom prípade nastane situace ktera me nenapadla. Kdybych to chtěl zkoušet normálně v dev instanci tak budu muset naklikat asi 4-6 scénářů. Takže behem minuty jsem to zjistil, pak opravil a nechal při MR jet v pipeline testy 25 minut. Tak Vám děkuji za praktickou radu nepustit func. test na localhostu a cekat ? času na pipeline a mezitím někde začínat neco druhého a pak snad i třetího a kdovi kolikátého. Dekuji, rozhodně se Vaší rady drzet nebudu
"Jako myslete si o mě co chcete, ale z denodenní praxe testování vím, že se celkem často chyba nebo zmena projeví i vvdalsich vrstvach aplikace - ono je to taky logicky tím že ty tvrsvy a jejich akce jsou na sebe navázané." Může být, to nepopírám, ale při vhodném vrstvení se to nemusí stávat často. A to vám tak vadí, že vám takový fail odchytne CI/CD server?
Já totiž jen tvrdil , že některé testy nemá smysl pouštět u sebe, že se odchytnou na CI/CD serveru. Pokud tedy jsou napsané. Což tedy i podporuje tu vaši zkušenost, že jste něco nedomyslel a nakonec to spadlo na nějakých integračních/funkčních testech. To spouštíte např. testy pro všechny verze interpreteru na lokále? Od toho právě máme CI/CD. A tady nám reálně věci padají např. na různých verzích Pythonu apod. nebo dokonce někomu na různých verzích OS. To, že to všechno projde u Vás ještě vůbec nic neznamená. Ale to bude nekonečná debata co? Já to zkrátím, protože vaše texty se prodlužují.
@uetoyo
A) "Může být, to nepopírám, ale při vhodném vrstvení se to nemusí stávat často."
Tak s tím se dá souhlasit. Každopádně se to dá pomocí testů velice jednoduše zkontrolovat - ano, dokud neproběhnou všechny testy, je to lehce indikační, dá se něco minout, to nezastírám.
B) [1] "Já totiž jen tvrdil , že některé testy nemá smysl pouštět u sebe, že se odchytnou na CI/CD serveru."
Dovolte abych Vám odcitoval
[2] "Jo, jenže proč bych je měl spouštět po každé změně? Od toho tu je právě oddělení na doménový model, infrastrukturu, kam patří repositories a aplikační vrstvu (use-cases). Když už, tak tyhle testy oproti DB nakonec pouštím na CI/CD serveru. Pokud se hrabu v doménovém modelu, vůbec mě tohle nezajímá víz pojem "Persistence ignorance" " [ 24. 1. 2020 16:24 uetoyo]
S [1] bych souhlasil a pravidelně to dělám. S [2] bych nesouhlasil.
C) "To spouštíte např. testy pro všechny verze interpreteru na lokále? Od toho právě máme CI/CD"
Ne, a už jsem to psal
"Nikdo Vás taky nenutí pouštět všechny testy úplně pokaždé, ale většinou (mrkněte do manuálu) se dají pustiti testy jenom pro nějakou jednu dvě složky, něco jako např.
tests/[func|unit]]/{*}HandlingService (pokud to teda nemáte všechno úplně na jedné hromadě) a nebo se dá často filtrovat podle názvu, např. něco jako
./run --filter "Users|Aeroplane"
či třeba jenom
./run tests/functional/services/someService::testHandleSomething což ale může zahrnovat i dalších x vrstev, y souborů a hromadu dat "
D) "To, že to všechno projde u Vás ještě vůbec nic neznamená"
Ano i ne. Není to nutná ani postačující podmínka, ale pro ulehčení si práce a zefektivnění procesu je to velmi užitečné. Ono totiž ani to že Vám projdou testy na CI/CD neznamená že jste otestoval všechno a neexistuje tam nějaká chyba která tam byla zanesena před tím nebo nějakou opravou. Pak jsou na řade quality testy ale tak co si do nich nenapíšete to tam nemáte a chybu lze udělat i v psaní testů - taky se mi stalo mnohokrát.
@Jakub Daňek
No to záleží co s danou databází provádíte. Každopádně pro lokální testování je velmi výhodné použít dobře cashovatelnou databázi. Pak samozřejmě v rámci buildu do dev (a dále) prostředí použijete "reálnou" verzi databáze. To se dá v konfiguraci i dockeru udělat hierarchií config files celkem jednodušše
IMHO proti skutečně reálné databázi (ta/ty skutečně reálné instance s se skutečnými uživatelskými daty) nebudete testovat nikdy. Vždy existuje nejaká alespoň minimální změna v konfiguraci nebo reálném stavu pro různá prostředí.
Nevím, co je to dobře „cashovatelná“ databáze, každopádně i takovému PostgreSQL lze spustut separátní instanci. Kdysi jsem to ubastlil bez Dockeru (předpokládalo to volný port a nainstalovanou vhodnou verzi PostgreSQL), s Dockerem to půjde ještě lépe.
Ano, pro účely integračních testů jsem tomu vypnul takové „zbytečnosti“ jako fsync [1], aby to bylo rychlejší. Pravda, takové nastavení se odlišovalo od produkce, kde je fsync důležité, ale za tu rychlost testů to stálo a i tak to poskytovalo mnohem věrnější výsledky než testování oproti SQLite.
Ono testování je vždy kompromis. Vždy chceme co nejvěrnější výsledky s co nejnižším úsilím a co nejrychlejšími testy. To někdy jde proti sobě. Mít na produkci PostgreSQL a testovat na SQLite znamená používat databázi s jinými specifiky, jinými tichými defaulty (včetně řazení) apod. V době Dockerové typicky není velký rozdíl mezi náročností rozjet SQLite a rozjet PostgreSQL, takže těžko se pro to hledá dobrý důvod. Ani ORM nemusí člověka 100% odstínit od rozdílů – na to by muselo srazit možnosti všech databází na úroveň té nejméně pokročilé.
Naproti tomu takový zakázaný fsync má celkem popsané dopady. Pokud nedojde k tvrdému vypnutí (které nás stejně nezajímá, když v takovém případě databázi zahodíme a vytvoříme novou a prázdnou), rozdíl by měl být pouze v rychlosti. To čistě teoreticky samozřejmě nějaký rozdíl může udělat (pak bychom ovšem ani nemohli použít debugger [2]), ale riziko vidím jako řádově nižší než u použití jiného RDBMS.
[1] https://www.postgresql.org/docs/9.5/non-durability.html
[2] https://en.m.wikipedia.org/wiki/Heisenbug
@Vít Šesták
Jej, to mi nedošlo ... měl jsem na mysli cache databáze aby se nemusela před každým testem obnovovat do výchozího stavu, ne cache dotazů apod.
My máme např. v local dev prostředí asi 9 Docker kontejnerů (komplet local dev env) - některé simulují služby dostupné v amazonu jako RDS (Databáze) nebo nějaký Cloud (to jsem nenastavoval já ani jednou a nikdy se s tím nemuselo nic dalšího řešit ...) a některé (hlavně aplikace) běží přímo v Amazon Elastibeanstalk jako kontejner aplikace nahrávané přes CI/CD. Pro testy na localhostu používáme SQLite, je to jeden soubor, běžně je dostupný v daném kontejneru tato DB je cacheovaná mezi testy. Jak jsem psal, je tam jenom jedno místo u kterého se musel udělat jedena podmínka kvůli nějaké funkcionalitě která se v SQLite chová jinak - je to sice zásah do aplikace "pouze" kvůli testům, zdálo by se to nepřípustné, na druhou stranu je to místo kde už je vyzkoušené že při změně typu databáze bude/byl nějaký problém :-) tedy funkce specifická pro aktuální technologii ...
Tady už se dostávám na tenký led, ale ještě jsem neviděl že by větší databáze běžely v kontejnerech, takže stejně se nějakému ladění defaultů nevyhnete a při každé změně na produkci musíte konfigurovat i vývojové prostředí. Nejlepší to určitě není, ale zatím jsem se fakt už ve více firmách setkal pouze s tím že databáze prostě běžela někde na vlastní pěst, často "Managed" nějakým dohledovým centrem jako služba. Je pravda, že když se to začne rozcházet moc, nejde každá obezlička použít ... DOckerové farmy jsem ještě nepoužíval, naposledy když jsem o tom četl tak tam byla větička o jakémsi experimentálním cosi a běhu v produkci na vlastní riziko .... nevím. nejsem machr přes databáze ...
@Jakub Daněk
Ano, nemusí tam fungovat všechno, v celé aplikaci máme jedno takové místečko (vyřešeno jednou podmínkou), ale pro lokální vývoj je to (minimálně v našem případě naprosto) dostačující. Celá aplikace je v Docker kontaineru Symfony+Doctrine, pro lokální vývoj je použitá SQLite která se mezi testy nemusí uvádět znova a znova do výchozího stavu, pak letí celý kontejner někde ke konci CI/CD procesu do produkce a po cestě už _všechny_ testy valí oproti reálné nedockerizované databázi.
My s tím právě měli problémy a ne vždy bylo na první pohled zřejmé, že problém vzniká rozdílnou DB. V době kdy není problém si v dockeru pustit libovolnou databázi na lokálu mi to přijde jako zbytečný odklon od produkčního prostředí.
Podobně s tím cachováním db mezi testy - podle mého to snižuje opakovatelnost testů, protože se obecně mění vstupní podmínky (testy se pravděpodobně pouští v náhodném pořadí, občas se nějaké testy mění nebo přidávají/ubírají). A já od testů očekávám, že ověřují, že se testovaná část systému chová po změně stejně jako předtím. A k tomu potřebuji kontrolované prostředí.
Výše píšete, že nikdy nemáme testovací prostředí úplně shodné s produkčním. To je sice pravda, ale není to pro mě argument pro to se od něj cíleně vzdalovat.
Abych to shrnul: chápu důvody proč se to používá, ale v dnešní době mi to přijde překonané.
@Jakub Daněk
Už jsem to psal výše, špatně jsem se vyjádřil. Cacheovaná je celá databáze - její výchozí stav, ne dotazy a kdoví co to umí ještě.
"V době kdy není problém si v dockeru pustit libovolnou databázi na lokálu mi to přijde jako zbytečný odklon od produkčního prostředí."
No, on to problém je. Pro vývoj si ji sice hezky spustíte, ale (abych byl konkrétní) v našem případě teď aktuálně trvá uvedení databáze do výchozího stavu asi 5 min. a ještě je v DEV prostředí navázaná na další - ale ty jsou obnovit rychleji. Těžko si lze představit takto spustit třeba 8 testových metod a před každou uvést databázi do výchozího stavu. Dost nepříjemné je když to musíte udělat 3x za sebou při manuálním testování. S použitím SQLite pod Doctrine je to v řádu vteřin.
"Výše píšete, že nikdy nemáme testovací prostředí úplně shodné s produkčním. To je sice pravda, ale není to pro mě argument pro to se od něj cíleně vzdalovat."
Neoznačoval bych použití jiné databáze pro účely spouštění lokálních testů za účelové vzdalování. Pro vývoj na localhostu máme samozřejmě plně dockerizované prostředí - několik DB instancí a script na jejich uvedení do výchozího stavu i s default daty. Tím se taky hned objeví problém v běhu testů pod jinouo DB. Nicméně pokud má být datový engine zaměnitelný, těžko pak argumentovat tím že je to problematické. Mohu Vám říct že v našem případě rozhodně není a aplikaci bych hodnotil jako nejméně středně složitou, možná i více.
"Abych to shrnul: chápu důvody proč se to používá, ale v dnešní době mi to přijde překonané."
Řekl bych že naopak. Díky modernímu přístupu a abstrakci se z toho dá velmi dobře těžit. Říkáte co je špatně, ale jak je to tedy správně? Máte nějaký konkrétní příklad na nějaké větší/složitější aplikaci?
Co je správně přece říkám: testovat proti stejné databázi. Uvádíte, že problém je dlouhá inicializační doba. Nevím, co to všechno obnáší, ale nešel by vytvořit docker image s už nainicializvanou databází? Vytvoření nového kontejneru z image je pak otázka pár vteřin.
Jinak mé komentáře k tématu směřovaly k obecnému případu, a k tomu co je principielně (imo) správně. Každá odchylka by pak měla být dobře podložená a udělaná s vědomím všech důsledků + zadokumentovaná. Což např. pro Vás očividně platí - databáze startující 5 minut je při vývoji samozřejmě k ničemu. Možné řešení viz výše, ale detaily znáte samozřejmě jen Vy.
Je to vždycky něco za něco, vývoj software se nedělá na krásu, ale na účelnost (tedy měl by). Pokud databáze startuje rychle, je dražší hledání podivnosti kvůli rozdílnému RDBMS. Pokud databáze startuje pomalu, vyjde levněji akceptovat fakt, že se v některých případech mohou chovat různé databáze jinak.
P.S: Už jsem si asi vzpomněl v čem byl tehdy problém: nebyly plně kompatibilní nějaké datové typy a museli jsme udržovat dvě sady DDL skriptů. Myslím, je to dávno :).
@Jakub Daňek
Nejde o to jak rychle startuje dazabáze, uvedení databáze do výchozího stavu (data) je časově nepřijemné - speciálně pro použití v testech. O tom je tu řeč.
"Nevím, co to všechno obnáší, ale nešel by vytvořit docker image s už nainicializvanou databází?"
Já měl za to že to máte pořešené a poučíte mne jak se to dělá správně.
Já ale chápu, že jde o dobu inicializaci dat.
A řešení jsem Vám navrhl: udělejte si docker image, který už obsahuje inicializovanou databázi.
Jestli je ve Vašem projektu něco, co takové použití znemožňuje nevím. Taky se Vám to asi nevyplatí předělávat, když máte stabilní odladěné prostředí. Pro nový projekt by mi to přišlo lepší.
@Jakub Daněk
Dobře, připustím že Docker dokonale substituje skutečné produkční prostředí - protože pokud databáze neběží někde jako úplně stejný Docker kontejner i na produkci, vždy je celkem šance že bude v něčem jiná. Připomenu že docker není 1:1 virtuál, ale má vytvořit možnost spustit stejný kontejner jak ve výjovém, tak produkčním prostředí.
Uvedl jste "Nevím, co to všechno obnáší, ale nešel by vytvořit docker image s už nainicializvanou databází?". Možná jsem to špatně pochopil, ale to mi nepřipadá jako "používám to a vím že je to lepší".
Takovou verzi s dockerem jsem používal pro "ručně" spouštěné testy s unit test docker conteinerm od maintainera a nějakým mým vlastním - budu ten projekt muset pohledat, ale pamatuji že tam byl nějaký dowside. A to ještě nevím jak se k tomu postaví buildové prostředí na serverech - zatímco tady mi stačí zkopírovat jeden soubor s daty a dokonce na takové testování existuje běžně používaná knihovna. Ale nasadil jste mi brouka do hlavy, to je pravda, musím se mrknout jestli se mi nepodaří s tím nějak pokročit, možná prokázat co je lepší.
30. 1. 2020, 17:48 editováno autorem komentáře
Mně přišlo, že jsme si úplně nerozuměli. Tohle řešení máme vyzkoušené a ulehčilo nám to hodně starostí spojených právě s udržováním testovací databáze. Konkrétně pro konfiguraci kontejnerů pro testy používáme: https://www.testcontainers.org/. Testy samotné neběží v kontejneru, ale na pracovní stanici/build serveru a jen si spouští kontejner s databázi.
Docker samozřejmě produkční prostředí plně nenahradí (pokud teda nemáte produkční databázi v dockeru, ale to patří spíš do kategorie těch horších nápadů). Myslím, že celá naše debata je vlastně o tom, jaké kompromisy jsme ochotni udělat a které nám přijdou lepší/horší :).
@Jakub Daněk
Děkuji za link, určitě se na to podívám, zdá se dokonce na letmý pohled že tam toho není moc :-)
No ona ta debata vlastně vznikla na zaměnitelnosti vrstev, takže to o čem se bavíme jsou teoreticky dvě strany jedné mince - bavili jsme se o zaměnitelnosti vrstev, ale jedna strana mince vlastně je že není dobré je zaměňovat (a testovat v idálně přesně odpovídajících kontejnerech) a druhá, ta o které mluvím já, je dbát na praktickou zaměnitelnost, testovat s použitím jiných databází (vlastně jenom kvůli rychlosti testů), ale pak nemít plně shodné prostředí s produkčním.
Ano, uvědomuji si že mluvím o vrstvách, zatímco reálně řeším/řešíme jenom datovou vrstvu - to ale vlastně protože nevěřím, z hlediska mých praktických zkušeností, na to, že když použitím nějaké technologie budujete nějakou třeba prezzentační vrstvu několik let, tak ji můžete nějak jen tak zaměnit výměnou nějakého enginu. To je utopie a krom databázového uložiště a systémů postavených na APIs jsem neviděl že by se někdy něco takového měnilo nebo se dalo vyměnit bez zahození a znovunapsání.
Aplikační vrstvy mi dávají vetší smysl z důvodu testování a možnosti řekněme substituce v rámci vrstvy, nebo spíš dekompozice v třídách, ale jinak asi prakticky ne ....
31. 1. 2020, 12:48 editováno autorem komentáře
Dobrý den,
V ideálním případě je cibulová architektura vhodná k výměně jedné z vrstev. V reálném případě si dokážu představit, že výměna si bude žádat nějaké úpravy, ovšem myslím si, že použitím této architektury se vám podaří minimalizovat nutný čas programátorů k výměně. Pokud může být programátor k tomu připraven, proč tomu nejít pomocí architektury naproti?
Nesouhlasím s Vámi v tom, když tvrdíte, že "pokud zaškrtnu tenhle checkbox, tak schovej tyhle dvě políčka" je bussiness rule. Něco takového je specifikace chování UI a nemá nic společného s tím, jak bussiness zákazníka funguje.
Cibulová architektura bude i umožňovat lehčí koexistenci dvou prezentačních vrstev, kterou zmiňujete. Jelikož je přepis celé prezentační vrstvy velmi náročný na finance a čas, tak by měla architektura aplikací podporovat možné scénáře vývoje co nejlépe.
SOLID principy jsou výborné principy a Cibulová architektura je podporuje na úrovni vrstev.
Souhlasím, že se tyto principy používájí obecně už dlouho a určitě se najdou vývojáři, kteří jen neví, že se tomu takhle říká.
K té výměně:
1) Pokud máte aplikační logiku ve vnějších vrstvách, tak si o problémy přímo říkáte a není to problém architektury ale kvality implementace. Souhlasím že je to, bohužel, běžná praxe.
2) Pokud chcete něco nahrazovat, musíte přesně znát kontrakt včetně vedlejších účinků. Pak jste schopni zaručit funkčnost i po nahrazení. V praxi to samozřejmě není úplně jednoduché, pomáhá kvalitní pokrytí testy.
3) A asi nejdůležitější pro myšlenku jako takovou: nelze hodnotit jak "snadné" je nahradit konkrétní implementaci vrstvy za jinou v absolutních číslech (protože do toho hodně mluvít velikost projektu, kde zrovna Vámi zmiňované systémy jsou peklo na údržbu tak nějak z principu), ale spíš v porovnání s tím, jak složité by to bylo, kdyby byla architektura navržena a naimplementována špatně.
Má osobní zkušenost je, že důsledné dodržování podobných pravidel vede k výrazně snazší a levnější údržby projektu včetně dalšího vývoje. Přičemž výměnou vrstvy je možno rozumět i třeba migrace na novější verzi technologie, což už není operace úplně neobvyklá.
Naopak, pokud je systém opravdu velký a implementace není dostatečně kvalitní, je lepší do toho moc nesahat, přesně jak píšete.
> Vrstvu persistence si v cibulové architektuře můžete představit jako plugin do vrstvy application.
Já s touto představou mám trochu problém, protože pojem plugin znám já (i Wikipedia: https://en.m.wikipedia.org/wiki/Plug-in_(computing) ) jako něco, co přidává funkčnost nějakému existujícímu [a tedy samostatně funkčnímu] programu. Jenže program bez perzistence typicky není samostatně funkční. Šlo by o tom debatovat u textového editoru, kde mohu psát text, ale uložit to musím přes Ctrl+C a Ctrl+V někam jinam. Snad úplně bez debat to je u adresáře kontaktů, kde bez perzistence nebudou fungovat ani tak základní věci jako hledání kontaktů.
Navíc u toho textového editoru bych si plugin pro perzistenci představoval asi jako něco, co by mohlo řešit i kus uživatelského rozhraní. Mohlo by to řešit dialog pro ukládání a načítání (a podle pluginu bychom mohli mít třeba podporu labelů nebo různé druhy hledání). Také by takový plugin mohl mít GUI pro řešení případných konfliktů, když více uživatelů upravuje jeden dokument. Toto ale příliš nesedí s tím, že prezentace je někde jinde.
Dobrý den,
Plugin přidává funkčnost existujícímu programu. Cibulová architektura může být použita i bez persistence, ovšem tomu musí odpovídat i zadání aplikace. Pokud je nelogické, aby program fungoval bez persistence, tak je očekáváno, že vrstva persistence bude existovat.
Vyobrazení pomocí pluginu mělo podpořit představu čtenáře o tom, že je možné tuto vrstvu vyměnit. V jádře aplikace budeme držet předpis, jakým chceme s daty pracovat a v jakém tvaru ukládat, aktualizovat, mazat či číst. To, jaká databáze či technologie je použita na uložení stavu dat, by nás v jádře aplikace nemělo zajímat.
Pokud chcete aby plugin s vaší aplikací fungoval, potřebujete naimplementovat nějaký komunikační kanál. V našem případě by to byly například rozhraní návrhového vzoru repository.
Použití výrazu "plug-in" je možná trochu nešťastný (on obecně je ten článek psaný tak nějak netechnicky), nicméně s myšlenkou se nedá než souhlasit.
Je možné napsat komponentu tak, její hlavní modul obsahuje jen doménu a aplikační logiku + rozhraní pro persistenci a následně existují 4 moduly s různými implementacemi v různých technologiích (ORM framework, čisté sql, mongo, textový soubor).
Vy si následně vyberete, kterou dvojici modulů přidáte do svého projektu, dle vlastních potřeb.
Článek je opravdu pojmut méně technicky. Chtěl jsem představit myšlenku a poskytnout popřípadě užitečné odkazy pro detailnější zkoumání.
Každopádně naprosto souhlasím. Jak říkáte, 4 moduly a jejich implementace bych udržoval ve společných knihovnách a použil tu, která je vhodná pro danou doménu nejvíce. Zde se přibližujeme už velmi k architektuře Microservices + DDD, kterou nyní vyvíjíme.
Podle našich dlouholetých zkušeností je u klasických webových víceuživatelských aplikací základem správně navržená databáze. Databáze umožní definovat vztahy mezi objekty, pravidla pro hodnoty atributů, i pohledy na data. Navíc je v jistém smyslu "univerzální" z pohledu technologického vývoje. Správná aplikace je pak jen datově řízená záležitost nad správně postavenou databází. Většinou totiž samotná aplikace je jen způsob, jak se k datům dostat.
I pro ostatní naprosto odlišné aplikace (např. grafický editor, počítačová hra) je klíčový moment způsob ukládání dat (konvence) a práce s nimi. Když si vezmete např. počítačovou hru, ta se opírá o možnosti nějakého herního enginu - a v konečném důsledku opět skončíte u způsobu, jakým se ukládají data a jakými metodami se s takto uloženými daty následně ve vytvořeném systému pracuje.
24. 1. 2020, 09:17 editováno autorem komentáře
Dobrý den,
Tímto přístupem jste výkonostně, návrhově i technologicky velmi závislí na třetí straně jako například na Microsoft SQL Serveru. V posledních letech příchází do módy NoSQL dokumentové databáze. Jakým způsobem byste řešili přechod na jinou, modernější technologii?
Obávám se, že takové webové aplikace mají kratší životnost, než by mohly být.
U každého většího řešení budete vždycky závislý na nějaké třetí straně . Kdo říká že ne, tak nemluví pravdu. Technologie přicházejí a odcházejí, ale principy rozumného návrhu platí obecně.
Mimochodem Vámi uvedené příklady nepoužíváme, ale jádra problému se to netýká. Pokud nebudete mít rozmyšleno, co jsou data a jak s nimi budete pracovat, ja tvorba aplikace -nebo její výměna- zbytečná. Také to, zda použiji nonSQL nebo SQL (pracujeme s obojím), je vedlejší.
„U každého většího řešení budete vždycky závislý na nějaké třetí straně . Kdo říká že ne, tak nemluví pravdu.“
To nikdo nepopírá, ale je nutno si vybrat tak, aby jádro aplikace bylo v nejméně závislých technologiích s nejmenšími změnami. Je rozdíl napsat dom. model v specializovaném jazyku specializované DB, nebo použít obecný programovací jazyk, na který existuje několik IDE či překladačů a bude tady ještě za 30 let.
Nerozumiem argumentacii "prichazi do mody". Aplikaciu predsa vyvijam s cielom aby poskytovala co najvacsi vykon, dostupnost a dala sa jednoducho udrziavat. To, ci je alebo nie je nejaka technologia aktualne "v mode", by nemalo hrat ziadnu rolu. Prave naopak, ak pouzijem desiatkami rokov overenu technologiu, mam istotu, ze "detske choroby" tejto technologie uz boli odstranene.
Je jasne, ze pouzitie SQL databazy je v niektorych pripadoch "overkill", ale pri zavislosti od tretej strany je predsa jedno, ci to je MongoDB alebo PostgreSQL.
Dobrá, souhlasím, že sem použil nešťastný výraz. Móda na to opravdu nemá vliv. Ovšem nové databázové přístupy vznikají z nějakého důvodu. Vezměte si Elastic Search. Je to mnohem vhodnější nástroj pro fulltextové vyhledávání než relační databáze. ElasticSearch je mladý a odhaduji že před deseti lety zde nebyl. Můžeme poskytnout větší výkon aplikace, ale je ho nemožné do Vaší aplikace zakomponovat nebo je to velmi náročné a zákazník to nebude chtít zaplatit. Tím pádem aplikace "hnije"
„Podle našich dlouholetých zkušeností...“
Éééé...
„...je u klasických webových víceuživatelských aplikací...“
Web je jen formou prezentace, u aplikací s jinými či více graf. rozhraními to neplatí???
„...základem správně navržená databáze.“
A je to tady - databázocentrická aplikace!
„Databáze umožní definovat vztahy mezi objekty, pravidla pro hodnoty atributů, i pohledy na data.“
To patří do doménového modelu, ne persistentní vrstvy.
„Navíc je v jistém smyslu "univerzální" z pohledu technologického vývoje.“
Bohužel není, každá DB má trochu jiné vlastnosti, v případě rozdílných typů hodně jiné vlastnosti.
Databáze je vrstvou (dle cibule částí), která se bude jistě měnit mnohem častěji než jazyk, ve kterém je napsaný dom. model, tudíž není strategické do ní umisťovat obchodní logiku. Dále: Co uděláte, když nebudete mít data uložena jen v oné jedné jediné DB, ale třeba ve 3 zcela různých? A nebo v nějakém úložišti přes HTTP? Kde bude potom umístěn dom. model s logikou? Jak bude komunikovat se zbytkem?
Taky jsem dělal v jedné velké, české, nejmenované firmě, kde bylo vše zadrátováno v DB, a to rovnou ve 3 typech RDB (to k té vaší „univerzálnosti“). Muselo se to dělat 3x, testovat se to pořádně nedalo, bylo to chybové a ukrutně pracné. O existenci dokumentových, objektových, sloupcových, časových a jiných typech DB vedení ani vývojáři netušili. Když se řešila nějaká nová vlastnost, nikdy se neřeklo „to přijde do dom. modelu sem a sem“, první bylo „do té a té tabulky dáme tenhle a tenhle sloupec“. Od konce.
Jako bonus bylo SQL v některých místech prorostlé až do prezentační vrstvy. Jakákoliv změna GUI či DB by znamenala roky úprav, což bylo nereálné, takže SW buďto nechat zabetonovaný, nebo začít úplně znovu. A to se vyplatí!
Proč zrovna tolik vrstev abstrakce? Každá vrstva přináší kód navíc, který nic nedělá, ale musí se udržovat. Rozhraní, se kterým se musí ostatní programátoři seznámit. Práce s vaší vlastní vrstvou pro ně bude komplikovanější než práce přímo s rozšířenou a dobře zdokumentovanou knihovnou, kterou znají z jiných projektů. Kvůli každé maličkosti musí přidávat funkcionalitu do každé z vrstev.
Pokud nad Vaší otázkou budu přemýšlet z hlediska mého projektu, který je použit na microservices, tak mi tolik vrstev abstrakce dávají smysl. Každá "servisa" má tuto architekturu. Každá může použít vhodnější typ databáze a přitom si zachovat velmi podobný tvar jako jiná "servisa". Programátor se zorientuje dobře v každé z nich a dokumentaci knihovny bude řešit až pokud se bude potázet s konkrétní technologií.
Pokud vytvoříme klubko špaget s použitím různých technologií a kód nebude mít řád podpořený přehlednou abstrakcí(architekturou), tak i když jsou technologie dobře zdokumentovány, tak si myslím, že se časově dobereme k horšímu výsledku.
Nehledě na to, že pokud se pokusíme na takový kód napsat unit test, tak spíše selžeme.
> mého projektu
problémy, o kterých jsem psal, vyniknou hlavně při práci na cizích projektech. Moderní frameworky od psaní vlastní tzv. domain vrstvy většinou odrazují. Cílem je omezit množství kódu specifického pro vaši aplikaci na minimum. Architekturu dodává framework.
24. 1. 2020, 10:59 editováno autorem komentáře
@gilll
No dokonce, viděl jsem přednášku nějakého maníka z teamu Doctrine ORM a ten tam říkal, že vývoj aplikace by měl být postavený jenom na entitách bez jakéhokoliv úložného enginu, ale tak beru to trochu trošku více méně jako "drsnou hlášku do přednášky" než nejlepší každodenní praxi. To už je až příliš šílená abstrakce a ani není nutná bych řekl, často se ví dopředu kde ty data budou ...
24. 1. 2020, 23:53 editováno autorem komentáře
@uetoyo
"Zajímavé. Docela bych tuhle metodu vývoje chtěl vidět, nikoliv však zažít."
Tak pokud jste někdy pracoval s Entitami (jak je používá např. Doctrine ORM) tak prostě pracujete na základě znalostí deklarovaných metod a návratových typů, nakonec si něco namockujete do testů nebo použijete pro testy datové fixtury které použijete pro mockování. Na tom nic není. Ale není to řekl bych úplně nutné vzhledem k tomu že je to méně konfortní oproti vývoji kdy stejně víte jestli svá data stavíte na MySQL nebo Postgre či co, protože i přes teoretické žádané vlastnosti ORM, ona ta ORM nakonec stejně nějaké queries poskládat musí, že ... a ony ty automaticky skládané dotazy mohou velice rychle začít dělat výkonostní problémy. A dělají. Pak se dají sice použít nějaké Native Query, pak už se ale nebavíme z 1/2 o ORM i když to pořád ještě nějaké výhody přináší
25. 1. 2020, 18:18 editováno autorem komentáře
@gilll
Neřekl bych protože striktní oddělení domain vrstvy od ORM stále dává možnost logicky i prakticky oddělit vrstvy aplikace od sebe - je to fakt výhodné např. při testování jednotlivých vrstev - jednou jsem dokonce zažil že se zvažoval přechod z jednoho zdroje dat (i engine) na jiný a díky neoddělení vrstev se to stalo prakticky nemožné a tak se přišlo s tím že se zdroje zkombinují a víte jak? Tak že se vrstvy začaly striktně oddělovat, protože každý už si byl vědom budoucích problémů. Uznávám ale že budování takové aplikace je místy až overhead a bobtná a bobtná ... pro menší jednoúčelové aplikace, speciálně takové se kterými počítá napříště (třeba za dva roky) spíš zahodit než opravovat to smysl moc nedává.
Heh, "Moderni ORM frameworky" jsou dobre tak leda na vysmahnuti dema typu Pet Shop.
Protoze snaha ORM frameworku o univerzalni API k ruznym DB enginum vede zakonite ke spolecnemu jmenovateli vsech podporovanych enginu. A ze napr MSSQL donedavna nepodporoval ani takovou trivialitu jako je LIMIT/OFFSET a Hibernate pak vybiral 10 radku uprostred milionradkove tabulky jak u debilu, ze nacetl milion radku a 999990 jich zahodil.
U nejakeho eshopu bylinkovych caju s 250 polozkami je to jedno, tam je ostatne jedno jak bude architektura.
Jakmile ale potrebuju pracovat s vetsimi daty, potrebuju vyuzivat i jeji featury, jinak si z Oraclu vyrobim tupou foxku se vzdalenym pristupem.
Takze v realu skoncim s ORM frameworkem pouze za ucelem mapovani databeans a vlastni vykonny kod dela sada PLSQL procedur na miru reseneho problemu.
Postgresovsky INSERT INTO WHEN CONFLICT UPDATE, nebo Oracle MERGE INTO neudelas v ORM nijak, nebo BRUTALNE NEEFEKTIVNE.
Zrovna nedavno jsem videl selmostroj, ktery pres ORM tahal z DB desetisice radku z vice tabulek, provadel vypocty, megabajty dat litaly tam a sem po siti, pomale jak prase, IO load k nebesum.
Po nahrazeni PLSQL si tomcat stahne tu jednu vysledkou integer KPI metriku...
Přikláním se k Youdovi z pohledu programátora, který začínal na Androidu (Java pak Kotlin). Problém , je právě v tom, že udělat ORM neni jen tak a není to všude. Navíc až když to ORM bude hodně dobře udělaný, tak se to možná vyrovná kombu SQL+dynamické struktury+Replismus (Aka co se dělá v Clojure a JS).
Další podle mě důkazem, že na Javě něco smrdí je rozpad JVM ekosystemu do vice jazyků (Groovy, Java, Kotlin, Scala, Clojure). Samozřejmě důvodem, jsou i fičury jazyka, ale při pohledu do komunit nejde jen o to, liší se celkově i mentální modely vývoje SW.
Ale kdeze.
Muj argument stoji na tom, ze pokud ma LIBOVOLNY ORM fungovat jako abstraktni vrstva nad DB enginem a tedy umoznit i vymenu DB enginu aplikace, musi zkratka a proste podporovat pouze ty featury, co podporuji VSECHNY podporovane databaze.
Coz je pak v realu SELECT, JOIN, CRUD a zhasiname.
Opravdu jsem jeste nevidel ORM, ktery by treba umel napr. vyuzivat Oracle XMLFOREST, coz je ve spolupraci s XSLT sakra silny nastroj. Nebo oracle stromova hierarchie pomoci CONNECT BY PRIOR
Pak se ORM pouziva s native queries a sadou PLSQL procedur pouze za ucelem mapovani entity beans a tim konci pribeh o abstraktni vrstve nad DB enginem.
Presne tak pouzivam ORM ja.
Anebo to nekdo namatla zoufale nefektivne a pak studuje debug logy, jaky REALNY select z toho ORM zprasku vylezl, aby byl schopen proindexovat tabulky at se zbavi full scanu a nested loops query planovace.
@Youda
"Zrovna nedavno jsem videl selmostroj, ktery pres ORM tahal z DB desetisice radku z vice tabulek"
A právě proto je stále ještě potřeba programátor aby zhodnotil situaci, využil případně výhod a vyhnul se nevýhodným situacím. A proto taky AFAIK ORM Frameworky umožňují používat tzv. Native Query, zatímco můžete s výhodou používat další neměné výhody, jako např. PDO, escapování atd, atp ...
Ano, taky jsem milionkrát viděl jak někdo v cyklu tahal entitu po entitě klidně pro tisíce idček, ale takovou *** ehm můžete udělat i bez ORM. A to jsem taky viděl nejednou. Často se to stane náhodou, např. někde o 4 úrovně níž je nějaká jedna metoda která tohle způsobí, nicméně zde už je to na programátorovi a jeho zájmu o to co se děje "pod kapotou" když něco píše ...
Aha takze my pracujeme s dogmami. Ty chces ale pouzivat rucne kodovanie na vsetko a logiku kodovat v PLSQL. HAHAHA. Prezradim ti tajomstvo. Ide o to ze ten ORM framework ti v pohode vyriesi 80-95% pripadov. Ostane si urobis rucne. Bud cez bulk update, alebo native query alebo ... . Takze tolko starym dogmam.
Myslím, že se míjíte v tom, o jakých systémech píšete. U jednoduchého systému, který nepotřebuje ani pořádnou relační databázi a prostě jsou jen data z nějakého důvodu uložená v tabulkách (a používá třeba MySQL) opravdu ORM vyřeší třeba 95 % případů. Pokud ale máte velký systém, který potřebuje pořádnou relační databázi a potřebuje z ní dostat to nejlepší, ale ORM nepomůže. Protože účelem ORM je skrýt před programátorem databázovou vrstvu, zatímco v těchhle případech ji naopak potřebuje mít pevně v rukou. Pak se hodí mít nějaké mapování mezi tabulkami a objekty, ale ne ORM.
@Filip Jirsák
Tak asi by bylo nejlépe vysvětlit co je to
1) pořádná relační databáze
2) nějaké mapování mezi tabulkami a objekty, ale ne ORM
Účelem ORM není skrýt databázovou vrstvu, to je pouze teoretické zadání a často se opakuje pro základní vysvětlení v quickstart tutoriálech, ale účelem ORM je mapovat objekty na databázi. Debug a optimalizace dotazů, jejich kontrola, je stejně běžná jako u jakékoliv jiné práce s daty. Sasmozřejmě je pro některé operace výhodnější použít ORM Native Query, nicméně s těmi čísly taženými z klobouku bych se moc neoháněl.
Pokud opravdu využíváte relace, tak vlastně duplikujete to co dělá ORM. ORM Vám pro spoustu operací poskytuje automatizaci aniž byste si ji musel psát sám a dokonce můžete i využívat výhod jaké obecně veřejné knihovny/frameworky mají.
29. 1. 2020, 13:22 editováno autorem komentáře
Ne nutně je třeba mezi vrstvami budovat vlastní abstrakci. A ne ve všech jazycích přináší abstrakce nutný balast kód navíc (např. se podívejte jak realizuje "rozhraní" Dart).
Rozdělení na vrstvy má rozdíl například i (a skoro bych řekl hlavně) v tom, jakým směrem vám jdou závislosti uvnitř kódu. To vám i třeba později, když je to potřeba, umožní rozdělit monolit na více služeb bez většího refactoringu. Je to případ právě té doménové vrstvy.
Tady není asi úplně prostor to rozepisovat, ale dobře udělaná architektura práci šetří, nepřidělává. Zlepšuje orientaci v projektu, nezvyšuje složitost. Pokud se tak někde děje, je ta architektura navržená nebo naimplementovaná blbě.
K vašá otázce na "proč zrovna tolik vrstev": Onion architecture vychází ze zkušeností z mnoha projektů. Stejně jako spousta jiných architektur. Prací každého inženýra/architekta je zvážit možná řešení pro daný problém a zvolit to v danou chvíli nejlepší. Silver bullet neexistuje.
Ono na papíře to vypadá krásně a je dobré, že se začátečník dozví, že má dělat interfacy, ale realita je bohužel poněkud složitější.
To co dělá výměnu komponenty složitou je změna kontraktu a to jak moc se aplikace na danou komponentu odkazuje. Samotný interface moc nepomůže, když je kvůli výměně třeba změnit způsob volání funkcí (parametry, pořadí, ...) a je to rozlezlé na tisíci místech. Naopak pokud mám odkazy na danou komponentu lokalizované v nějaké malé části, tak ji (pravděpodobněji) snadno vyměním i když tam ten interface nebude.
Jinými slovy, žádná architektura nepomůže, pokud se ty špagety stejně rozlezou v aplikační nebo doménové vrstvě, na druhou stranu architektura není zas tak podstatná, pokud jsou věci oddělené a uklizené.
Píšu to proto, že jsem v posledních letech svědkem toho, jak se dogmaticky a extrémně aplikují SOLID principy a všelijaké architektury s devastujícími dopady na aplikaci samotnou. Takže prosím všeho s mírou, dobré integrační testy a uklízet po sobě, to se mi osvědčilo nejlíp :-)
Tak trochu pokritizujem a prihrejem svoju polievocku. Vrstvy v architekture mam roky. Potom sa zistovalo ktore a ako ich rozdelit. A tak vznikli nejake best practices a pre DB orientovane aplikacie ktorych je 99% sme prijali za standard DDD (Domain Driven Design). No potom prisli programatori a zacali to kazit, kod si pisali kde ako chceli a ked ste ich tvrdo nekontrolovali a netrestali tak to prznili kde sa dalo. Tak sme prisli s MDA (Model Driver Architecture). Takze v nejakom DSLku si navrhnete entity, rozhranie, ... a vela kodu to vygeneruje. Programator potom dostane uz iba svoj maly piesocek ktory neviem preliezt alebo je lahke zistit kedy sa o to pokusa. Ak mate zaujem sa trochu pohrat skuste napriklad toto: http://sculptorgenerator.org/ a Documentation -> Advanced Tutorial. Tam sa dozviete ako jednoducho udrazat model, api pod jednou strechou, architektovi umoznuje velku flexibilitu a silu obmedzit programatorov v przneni kodu a zavedie poriadok do projektu.
Neviem inac preco sa tu teraz o tom pise, toto boli zaujimave temy mozno tak 10-15 rokov dozadu.
Dostane vygenerovane predpripravene metody. Default uz maju nejaku implementaciu v base classe ktory sa vzdy pregeneruje. Plus ma vygenerovany interface.
Pokial do vygenerovaneho classu nezasiahne tak ten sa pri dalsom generovani tiez vygeneruje nanovo. To je dobre v case burliveho uvodneho vyvoja kedy sa hlavne hrabete v model.btdesign.
Potom ked si uz nejaku metodu upravite a zmenite rozhranie tak interface vas prinuti tuto metodu implementovat. Standardne CRUD (findById, findByCondition, save, delete, ...) operacie sa generuju automaticky. Je to enterprise grade vyskusane na vela velkych projektoch. Podporuje to aj dalsie rozsirenie pre CQRS a EventSourcing pripadne mozte vygenerovat rovno aj webovu aplikaciu alebo REST.
Pěkný projekt. Našel sem nedávno v projektu https://github.com/ddd-by-examples/library toto https://www.archunit.org , ale zatím jsem to nezkoušel.
Technologická nezávislost na databázi je obtížně dosažitelná. Např. SAP a podobné firmy to řeší specializovanými "plugins", které překrývají rozdíly mezi jednotlivými databázemi. Vyčerpávajícím způsobem se k tomu vyjadřuje Tom Kyte již ve starší knize: https://www.knihydobrovsky.cz/autori/thomas-kyte-169801, kterou ale lze nadále doporučit - její větší část je nadále aktuální. Resp. tentýž autor v jiné knize (Oracle Expert Architecture) píše o úskalích převodu aplikace napsané pro MSSQL na Oracle DB a naopak. Nezávislost na databázi je iluze - v praxi se opakovaně setkávám se špatně fungujícími aplikacemi v důsledku ignorování vlastností kontkrétního RDBMS. Resp. v "malých rozměrech" na dnešním HW funguje lecos, ale realita se ukáže na aplikaci datově náročnější a s větším množstvím "concurent users".
Souhlasím že nezávislost na DB je iluze, pokud už s tou DB musím pracovat. Ale DDD právě odděluje doménovou vrstvu od té perzistetntní. Takže když se hrabu v modelu, nic takového neřeším -- repositories jsou definované jen pomocí rozhraní. Pokud se hrabu v infrastruktuře, tak už při implementaci řeším jestli to repository pracuje s MySQL, Postgresem nebo jiným typem úložiště.
Pokud jsou ale systém prorostlý ukládáním do DB už na úrovni modelu, tak to asi je docela problém.
Dobrý den,
podle příspěvků se zde sešla řada zkušených programátorů. Já toho využiju a zeptám se takto do pléna na radu.
Jsem odborností strojař a v rámci svého působení se učím programovat v Pythonu. Pokud rozlišujete kodery a programátory, pak jsem zatím koderem. Používám OOP a učím se postupně data structures a design patterns. Dosud jsem psal převážně jednoúčelové skripty, kdy jsem nic moc nepotřeboval. Našel jsem si příslušnou knihovnu, udělal pár tříd a bylo hotovo. Můj "interface" s kolegy je převážně nějaký textový soubor s daty a výsledky.
Začínám ale pracovat na větší aplikaci a rád bych se naučil, jak to dělat dobře. Tedy jaké jsou best practises v oblasti architektury. Hledal jsem na to nějakou knihu, která by mě uvedla do tématu, ale našel jsem pouze tuto: amzn.to/2tbgE3s a nejsem si jistý, jestli je to, co hledám.
Rád bych se proto obrátil na Vás - zkušené programátory, zda byste mě mohli odkázat správným směrem. Hledám tedy něco, od čeho bych se mohl odpíchnout při programování své první větší aplikace. Nerad používám čistě přístup pokus-omyl. Raději si o problematice nejdříve něco nastuduju, abych věděl, co vlastně dělám. Zároveň aplikaci nechci jenom nějak zbastlit, ale rád bych u toho pochopil všechny důležité principy a jako výsledek dostal kvalitní aplikaci, se kterou půjde dál pracovat. Vůbec mi nevyhovují online kurzy, nejlépe se mi učí z knih, či online textů (které si můžu vytisknout).
Pokud tedy víte o knihách, článcích, skriptech nebo přednáškách, které by mi v tomto smyslu pomohly, budu velice rád, když se o ně podělíte.
Často tady u článků čtu "nářky" nad (ne)kvalitou začínajích programátorů. Rád bych se z této množiny posunul někam dále. Berte to tedy i tak, že teď máte možnost někoho popostrčit správným směrem.
Kdyby byl někdo ochotný k příležitostnému mentoringu/code review, byl bych velmi vděčný.
Snad to není příspěvěk zcela mimo, případně se omlouvám.
PS: a.jelinek zavinac pm.me
Tohle jste zkoušel?
Pokud nechcete studovat vědu tak bych začal třeba zde:
https://wiki.python.org/moin/BeginnersGuide
https://devguide.python.org/
Při procházení určitě narazíte na spoustu problematiky a termínů které se budete moct doučit a tak dále, kdoví kam až tahle králičí nora vede ;-)
Bývá taky dobré prohledat Google (hlavně Gitlab, Github) a najít si nějaké velmi známé projekty, najít si jejich reference, tam se často "jako ve výkladní skříni" dají najít odstrašující i poučující příklady. Idálně i pohledat nějaké projekty z Vašeho oboru.
Dále bych hledal, třeba zase Googlem, nějaké "Python best practices" a podobně, tohle by Vás mělo dovést do neuvěřitelně rozlehlé říše znalostí a polemik o problematice. Dá se i googlem pohledat reference na nejlepší Python knihy (třeba do autobusu) jak papírové tak do čtečky.
Ještě byste mohl možná zkusit přidat se do nějaké komunity, navštívit nějakou Python akci a pod. Třeba objevíte někoho z Vašeho okolí atp. Nicméně bez učení pokus-omyl to určitě nepůjde a vězte že neexistuje žádný konečný definitivně jasný správný názor/manuál - a i to se v čase a s verzemi mění.
Ano, zní to dost obecně a taky je, ale bez školy (kde se budete muset učit hodně věcí navíc) nebo kurzů (které nechcete) je to IMHO to nejjednodušší co můžete udělat teď hned.
Některé principy se nemění, některé neplatí úplně vždy, ale dost se toho mění s časem a technologiemi, je to cesta na dlouhou trať která nemá konce řekl bych ;-)
Několik základních rad (vycházím ze zkušenosti):
1. Než začneš psát, zkus si základní věci rozvrhnout na papíře
2. Nenech se svést ke zneužívání jednoduchých datových struktur. Žádný dict dictů dictů v situacích, kde je struktura dat pevně daná a známá - hezky to zabal do tříd s konstruktory apod.
3. Používej srozumitelné identifikátory tříd, proměnných apod. Ušetřené písmenko fakt v těchto situacích nestojí za to.
4. Jednotlivé stavební bloky dělej co nejsamostatnější, nemíchej jednotlivé vrstvy mezi sebou a to ani v komentářích - nepiš do funkcí a metod, kdo je používá a proč.
5. Nesnaž se vynalézat kolo; pokud existuje stabilní použitelná knihovna, používej ji.
6. Nauč se dobře pracovat s nástroji typu pylint a vyjdi jim vstříc - pokud danému kódu pylint nerozumí a píše chyby, zkus to napsat jinak.
7. Nepiš nic, co nepotřebuješ. Soustřeď se na funkčnost, která je pro aplikaci nezbytná.
8. Zkus si časem nastudovat jiná paradigmata, zejména funkcionální programování. Otevře Ti to oči.
9. Nauč se porozumět složitosti algoritmů, ať se nezabýváš mikrooptimalizacemi, které nic podstatného nespraví.
10. Pořád se snaž zlepšovat svoje postupy a nástroje. Co můžeš, zautomatizuj.
Příručka Ti možná pomůže, ale je potřeba si udělat pořádek v hlavě a přemýšlet nad vším samostatně a kriticky. Zároveň nezůstávat v zóně komfortu.
26. 1. 2020, 12:43 editováno autorem komentáře
@jelinek_strjr
PS: Určitě mrkněte na SOLID.
Psal jste že kurzy nemáte rád, ale jsou i kurzy online (např. Udemy mě teď tak z hlavy napadá), není to vůbec drahé (seženete i třeba za $10) a pokud takto začínáte, věřím že Vás to do začátku hodně nakopne a ušetří čas, dřinu a tím i peníze. A nebojte, co jsem viděl tak tam bývá hodně odkazů a materiálů.
Za mě doporučím určitě se podívat na prvních 6 částí Clean Coders. Je to o tom jak strukturovat kód a pak unit testy. https://cleancoders.com/videos?series=clean-code&subseries=fundamentals .
Jak už bylo zmiňováno SOLID principy, tedy kniha Clean Code.
Problém je v tom, že člověk přečte knihu a nespojí si všechny věci dohrami a až na základě zkušeností si začne uvědomovat, co kdy platí za jakých podmínek. Kdy co dodržovat a kdy je to hovadina.
Nevýhodou je, SOLID a Clean Code je částečně i dost záplata na to jak špatné je OOP a jakou komplexnost a problémy generuje. Navíc mi příjde, že Clean Code dost prosazuje OOP a nedává do kontextu s Funkcionálním programováním. Navíc je v mnoha věcech dost fanatický.
Problém SW Engineeringu je právě v tom, že se v čase dost vyvíjel a prosazovali se často věci od kterých se postupně upustilo. Takže dosud nevím o nějakém materiálu o kterém by se dalo říct: ''Tohle přečteš a seš dobrý programátor". Skutečnost je spíš taková, že člověk se musí prohrabat spoustu nesmyslama, aby přišel k něčemu dobrému. (IMHO jako tento článek)
Další věc je, že se často nevyplatí o věcech dlouho teoretizovat a jít do toho. Jak se říká "Nejlepší analýza je implementace". Tedy je lepší něco zkusit, ale mít poté možnost to dobře refaktorovat a měnit, když je to nesmysl. A na to, aby se to dalo dobře měnit potřebuješ něco z 6 částí Clean Coders. A přece jen jsme lidi a produktivita se odvíjí hodně od toho jak to člověka bavý. Zmého pohledu je zábavnější psát kód něž neco dokola analyzovat (něco čeho se také týká sOlid - Open-Closed principle).
Dostal jste tu spoustu dobrých rad, tak jen doplním ještě navíc:
* napoprvé se to nepovede, zbastlíte to a za 5 let si budete rvát vlasy, co jste to spáchal. Je to normální. Nenechte se tím odradit. Načíst se dá jen omezená množina věcí, zbytek je o zkušenosti. Zkušenost se dá nabýt od zkušených kolegů a dobrých vyučujících na VŠ. Pokud ani jedno nemáte, nezbývá Vám, než si tu zkušenost udělat sám.
* rozvrhněte systém od shora (velké logické celky, procesy, komponenty - věci které z podstaty věci patří k sobě) dolů (konkrétní moduly/třídy/funkce). Nedjřív myslete z pohledu uživatele, zákazníka. A až když jste si jistý, že víte co se po vás chce se zamyslete nad tím, jak by se to dalo naprogramovat.
* nebuďte líný psát automatické testy, je to opruz skoro pro každého, ale alternativa bez nich je strašná
* kdykoliv budete mít potřebu vzít kus kódu a rozkopírovat ho na víc míst, zastavte se, zamyslete a zjistěte kde vám chybí třída/metoda/funkce :)
* komentujte i zřejmé věci, API, atributy, ne zcela triviální algoritmy
* přehlednost a standardizace jsou důležitější než cool-factor, pokud je projekt větší než triviální a životnost delší než krátká (pokud tedy neděláte něco tak nového, že na to standardní řešení nestačí, ale to je jiná story). Používejte ozkoušené knihovny, technologie, principy
* pokud přejímáte řešení problému ze stack overflow či blogu, buďte si nejdřív jistý, že chápete co přesně to do detailu dělá, jinak si koledujete o problémy (výkonostní, bezpečnostní).
Přidám ještě pár připomínek k předchozím. Přijde mi z toho dotazu, že očekáváš, že po nastudování dostatečného množství knih a pouček sedneš a napíšeš dobrou aplikaci. Obávám se, že tak to nefunguje. Jednak principy se časem (trochu) mění, druhak během implementace ani nepoznáš, že jsi něco nedodržel nebo zbastlil. To se ukáže až časem, kdy to budeš potřebovat rozšířit a implementovat nové požadavky atd.
Naštěstí SW umožňuje aplikaci libovolně předělávat a považuju za jednu z klíčových dovedností toto využít. Vychází to z agilních praktik, extrémního programování a konkrétně jde o to, aby se programátor nebál nedělat nic navíc (i když ví, že to řešení časem nebude stačit) a následně to vylepšil když to stačit přestane.
Kolikrát vidim, že se na začátku projektu rozhodne technologie, architektura atd. Následně se to implementuje, přičemž se řeší hromada složitostí, aby to bylo připraveno na budoucnost (která ale bude stejně jiná než kdo čekal) a přitom se nemění architektura ačkoli už dávno nevyhovuje současnosti.
Není nic špatného když si něco nastuduješ, ale zároveň se neboj pustit do prototypů a průběžných předělávek když jsou potřeba.