Jaký používáte návrh aplikace – model VS databáze

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
frosty22
Člen | 373
+
0
-

Zdravím,

již delší čas se podotýkám s věčným problémem rozvržení aplikace. V podstatě jde vždy o jedno a to samé – vytáhnou data z úložiště, nějakým způsobem je prezentovat a modifikovat. Chvíli jsem používal jako databázovou vrstvu Doctrine 1.3, která v podstatě dilema jak mít rozvržené modely řešila sama, ale nyní již nějaký čas používám NotORM či NetteDatabase a tady již je ta volnost větší.

K jádru problému, příklad mám web, kde mají být třeba články a ty mají kategorie. Jak si navrhnout model, aby byl, co možná nejpraktičtější, nejčistší a do budoucna i nejlépe přizpůsobivý.

Mít například objekt Article – zaregistruju jako službu, předám connection, a ten bude mít metody getArticleById, getListArticleByCategory, poté v presenteru volat tyto metody a výsledky předávat do template? Jako plus v tomto řešení vidím, když se změní zadání a články mají mít stav např. zkontrolován, tak upravím jen dotazy v objektu Article, a není třeba procházet všechny presentery a hledat kde všude je použita tato tabulka. Ale problém, na přidání článku mít metodu například add a předat jí pole hodnot? To už není tak cool, jako například ActiveRecord, který svou OOP logiku – článek je objekt, ten má nějaké property, má metodu save/delete …
… oproti tomu AR se přímo neslučuje s logikou DI, sice mohu udělat nějaké továrničky createArticle, createCategory, … ale opět dilema, jak moc je to cool :)

Dost by mě zajímalo, jak k této základní logice přistupujete vy, jaké máte osvědčené rozvržení. Již jsem četl něco o 5-vrstvém modelu, 3-vrstvém, atd. ale jak je to v praxi, co využíváte?

Děkuji za případné náměty, motivace :)

newPOPE
Člen | 648
+
0
-

Skus si este pozriet Doctrine 2.x. Tam je to urobene uplne inak (no active record) mozno to bude pre Teba cesta.

Filip111
Člen | 244
+
0
-

@frosty22: Používím dibi a v modelech mam metody jako getNeco, insertArticle, updateArticle apod. Jenže protože články jsou vícejazyčné, metodat updateArticle není triviální a je v ní několik kontrol a případně insert/update. Zkrátka se mi to nelíbí a je s tím často zbytečná práce.

Už několik měsíců uvažuji o přechodu na Doctrine 2, ale právě kvůli té vícejazyčnosti a celkově „rozrostlé“ databázi nevím jak to uchopit a jak nadefinovat entity. Každopádně bych moc rád hodil za hlavu problémy související s uložením nějakého objektu a nechal to na někom jiném…Doctrine2.

Tím spíš mě zaráží, že píšeš že jsi Doctrine používal a odešel od ní? Jaké jsi měl konkrétní důvody, resp. píšeš že máš teď větší volnost s notORM nebo Nette Db. Čím tě Doctrine 1.3 tak svazovala?

David Ďurika
Člen | 328
+
0
-

v praci pouzivame 5-vrstvovy model a Doctrine 2

  • Service (nie nette servica)
  • Entity
  • Repository
  • Mapper
  • Storage

Entita je presne to co si pisal, objekt (prepravka) kt. ma v sebe data (nevie sa ulozit ani zmazat)
uklada ju Service pomocou Repository (EntityManagera)

Servica ma metody ako update, save atd…

Vyhody:
Doctrine 2 riesi vci ako napr:

  • viac OOP
  • rychlejsi vyvoj
  • ked programator robi prezenter / Servicu nemusi riesit co ma kam ulozit ale len vola new new new a potom ->save()
  • ukladanie zavislosty
  • mazanie zavislosty

nevihody:

  • nemas taku kontrolu nad sql dotazmy

tak tolko moje skusenosti, z Doctrine este nerobim moc dlho takze vacsi odbornici ma budu vediet urcite v niecom doplnit/opravit

Editoval achtan (23. 4. 2012 9:40)

Ot@s
Backer | 476
+
0
-

Filip111 napsal(a):
Čím tě Doctrine 1.3 tak svazovala?

Diskutér mimo vlákno. Začalo to drobnostma typu, že z yamlu (vytvořeného z existující MySQL DB) zpětně nešlo vygenerovat SQL (velikost souboru 0). Cokoli, co vybočovalo s jakéhosi standardu definovaného průnikem všech funkčností z různých RDMS, dělalo problémy a muselo se jaksi ošetřovat (namátkou implementace použitelného fulltextu v CMSku). Konče tím, že složitější SQL dotazy jsem stejně musel psát v SQL (nebo si tvořit pohledy). Už mě nebavilo hledat, v čem je problém, co mám zapsat jinak atd… Pro jednoduché, univerzální, čisté návrhy, které si člověk udělá/promyslí sám, tak asi jo (což je myslím i cílová skupina). Na vše ostatní (já osobně) rozhodně ne.

Filip Procházka
Moderator | 4668
+
0
-

@**frosty22**, @**Ot@s**: Doctrine 1.3 je Titanik. Doctrine 2.2 je výborné ORM ;)

achtan napsal:

nemas taku kontrolu nad sql dotazmy

To máš pravdu jen částěčně. Doctrine se snaží ti pomáhat jak nejlíp umí. Tedy, spoustu věcí si naprototypuješ svižně a když potřebuješ optimalizovat sáhneš na strategie načítání (LAZY, EAGER, ..) nebo DQL.

Editoval HosipLan (23. 4. 2012 10:07)

frosty22
Člen | 373
+
0
-

Co se týče Doctrine, tak v podstatě jak píše @Ot@s i HosipLan s v2 nemám zkušenosti, a jen vím ,že je to diametrálně rozličná záležitost oproti v1.3, kterou máme nasazenou na jednom projektu, a v podstatě práce s ní mi přijde „mamutí“ – většinu dotazů ve finále člověk píše raději ručně, při i menší změně v DB struktuře, tak vznikne dost problémů, atd. Ano asi ji nepoužíváme, tak jak bychom měli – když by ji člověk nastudoval kompletně, jistě by šla využít efektivněji, ale není čas učit se měsíc(e) efektivní práci s něčím podobným. Oproti nyní Nette/Database, kde je to natolik transparentní, že není co řešit.

U V2 se též bojím, že na efektivní využívání bude nutné s ní delší dobu pracovat/studovat, proto jsem spíše chtěl volit cestu například „5 vrstvého modelu s Nette/Database“, či právě něčeho jiného, co možná někdo zde využívá. Přeci jen jsem si právě říkal, že když se Nette/Database využívá/rozvíjí, tak ho snad někdo efektivně využívá v podobných konstrukcích :)

Ale podle toho, co tak čtu, tak z toho vyplývá, že pokud chci mít logiku / větší OOP / v modelech, tak mám využít Doctrine?

David Ďurika
Člen | 328
+
0
-

frosty22 napsal(a):

>proto jsem spíše chtěl volit cestu například „5 vrstvého modelu s Nette/Database“

ked pouzijes nieco taketo tak budes mat ten isty problem ako s Doctrine 1.3 (mala smena v DB vyzaduje vela proramovania), ale v doctrine 2 to neplati

frosty22
Člen | 373
+
0
-

No to se mi přímo nezdá, přeci jen 5 vrstvý model neznamená velké množství psaní a vsadím se, že někdo již nějaký takový model využívá – přeci jen pokud by tedy byla toto pravda, tak z toho vyplývá, že v podstatě Nette/Database či NotOrm nemá moc svoje opodstatnění, respektive tedy, že je to pouze náhražka PDO, ale nedají se na tom stavět kvalitně OOP aplikace, aniž by bylo nutné valnou část doprogramovat.

A pokud tedy tomtu takto je, tak v podstatě by možná nebylo na škodu jako feature request, dodělat nějaký modelový návrh – repository / mappery / entity apod. :)

David Ďurika
Člen | 328
+
0
-

frosty22 napsal(a):
No to se mi přímo nezdá, přeci jen 5 vrstvý model neznamená velké množství psaní a vsadím se, že někdo již nějaký takový model využívá

ho hej zacnes pri malom a poziadavky budu stale narocnejsie a nakoniec zistis ze pracujes na novom ROM, naco vymyslat koleso… ?

tak z toho vyplývá, že v podstatě Nette/Database či NotOrm nemá moc svoje opodstatnění, respektive tedy, že je to pouze náhražka PDO, ale nedají se na tom stavět kvalitně OOP aplikace, aniž by bylo nutné valnou část doprogramovat.

no torcha si to zvelicil… ale nieco na tom bude :)

frosty22
Člen | 373
+
0
-

No s novu vymýšlením kola máš jistě pravdu, v podstatě mě zajímalo, jestli již něco takového pro Nette není hotové, či to není někde „schovené“ v nette (v DI či podobně :)), jelikož by mě překvapilo, kdyby ne. Přeci jen v tomto případě, by nemělo Nette/Database takové pole působnosti a Nette by se spíše propagovalo ve spolupráci s Doctrine.

Šaman
Člen | 2666
+
0
-
  • Kdo zná Doctrine a umí s ní, tomu nedělá problém implementovat ji jako model v Nette projektech. Ale kdo Doctrine neumí a/nebo nemá rád, tomu by v Nette přílišná vazba na Doctrinu vadila. Myslím, že asi proto tu nic takového není.
  • Nette docela dlouho razilo cestu být nezávislé na databázové vrstvě, ani Dibi nebylo nikdy součást Nette, aby si mohl uživatel vybrat, co mu vyhovuje. Bohužel pak David změnil názor, hodně se mu zalíbilo NotORM a na něm založil nativní Nette\Database. Osobně bych dal přednost Dibi, ale to je asi věc vkusu.
  • Co se týče hotového řešení, tak zatím není žádný dokonalý ORM, někteří jazykové tvrdí, že už z principu žádný ultimátní ORM být nemůže. Objekty a relace jsou natolik odlišné přístupy k datům, že každý pokus o mapování objektů do relací musí řešit kompromisy.

K původní otázce: Buď použiješ nějaký ORM na základ modelu (model != ORM). Nebo si třeba navrhneš vlastní strukturu modelové vrstvy.

  • První modely jsem si psal ručně: základem byly entity ála ActiveRecord, ale protože se načítaly a ukládaly ručně psanou rutinou, tak jsem nebyl omezen strukturou tabulky v db (automatika má snahu ukládat jeden objekt jako jeden řádek tabulky, já si mohl objekt rozložit třeba do několika tabulek a pak ho z nich také načíst).
  • Pak jsem měl kolekce entit (vzdáleně by odpovídaly repozitářům v 5ti vrstvém modelu). Kolekce byla třída poděděná z ArrayObject a uměla vyhledat a vrátit kolekci podle parametrů (řešila vyhledávání, řazení a limity).
  • Mezivrstva, použitá při práci s úložištěm bylo Dibi. Vyhovovalo mi, že píšu téměř čisté SQL dotazy a přitom mám možnost vyměnit úložiště (přejít na jinou relační databázi).
  • Úložiště byla MySQL, ale vzhledem k Dibi to je úplně jedno.
  • Nakonec jsem zjistil, že na některé složité operace potřebuji pracovat s více kolekcema (např. při změně článku bylo potřeba přesunout původní článek do archívu s příslušnými tagy a nahradit ho novou verzí). Když jsem tutéž věc potřeboval na dvou místech, objevil jsem (něco jako:) servisní vrstvu – všechny dílčí modely jsem obalil jednou třídou Model, která si vytvářela malé modely sama podle potřeby. A všechny dotazy šly přes ní. Jednoduché dotazy jen delegovala, složitější úlohy řídila sama. Na úrovni presenteru jsem tedy cokoliv s daty řešil přes $this->model->udělej/nastav/vraťNěco(). A nešlo jen o práci s úložištěm, ale i kontrola práv, změna jazyka apod. Model zkrátka fungoval jako autonomní vrstva, které presenter jen zadával úkoly, ale nijak do nich pak nezasahoval. Presentery se pak hodně smrskly a zpřehledněly
  • a úplně nakonec jsem na Poslední sobotě viděl přednášku na 5ti vrstvý model a mohl jsem začít refaktorovat celý návrh od začátku :)

Tak jsem se trochu rozepsal. No což, může za to Frosty22 :) Tohle není téma na pár řádků..

Editoval Šaman (23. 4. 2012 23:57)

frosty22
Člen | 373
+
0
-

Šaman děkuji ti velice za příspěvek, osobně jsem jedině rád, že jsi se rozepsal, v podstatě si potřebuji utříbit myšlenky, jakou cestou jít :)

V jednoduchosti tedy stále mám jistě dilema – nyní již na několika projektech (již skoro rok a půl) používám dříve dibi, poté notorm a nyní nette/database, a jelikož to nejsou zrovna malé projekty (průměr 100 tabulek), tak jsem postupem času zjistil, že mám dosti chaos ve směru úložiště (databáze) a OOP přístup. V podstatě jsem doposud jen tvořil stylem objektů, které mají metody jak na získávání dat getNeco a ty vracejí N řádků, ale i zároveň metody typu insert/save/add .. což se s tím pracovat samozřejmě dá, ale není vůbec hezké OOP. U pár jiných věcí jsem použil vzor ActiveRecord, jinde ne, a ejhle je v tom prostě bordel. Co se týče Doctrine 1.3, tak z tou mám zkušenosti z úprav u jiného projektu, a tam právě mi přímo nesedlo její používání, zvláště u sofistikovanějších dotazů na databázi, velkých importů kde vytvářet objekty pro každý řádek byl problém atd.

Nyní bych, ale velice rád u dalších projektů si právě sjednotil onen systém, a donutil ho být více OOP a hlavně jednotný, logický – chci se vyvarovat v podstatě toho bordelu a mít strukturu. Nyní tedy vůči diskuzím výše přemýšlím, že se asi podívám nakonec po Doctrine 2, jelikož ta by mohla přinést, to jenž potřebuji, pouze jen spíše ze zvyku, jsem sháněl zda-li neexistuje tato logika/systém i pro Nette/Database, aby člověk se nemusel tolik odklonit od již zavedeného, a též tedy to budu muset prosadit u kolegů v práci (leč tedy na projektech převážně pracujeme samostatně, ale i tak jednota vládla, alespoň v používaných technologiích, když né v kódech).

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

Dám vlastní příklad – na projektech používáme výborné ORM od kolegy Petra Procházky, postavené v podobném duchu jako je Doctrine 2. Základem jsou entity, které mohou být mapovány do tabulek, do více tabulek, klidně třeba i do souborů… (vrstva faktického úložiště) záleží čistě na nastavení odpovídajícího repozitáře, respektive na implementaci mapperu, se kterým repozitář pracuje (toť 3 vrstvy – Entita, Repository, Mapper).

Já jako programátor si celkem rychle nadefinuju entity (Petrovo ORM jde poměrně deklarativní cestou), dopíšu k nim repozitáře a mappery (obvykle děláme s MySQL, takže používáme tzv. DibiMapper, který prostě základní úkony jako getById, findAll, insert atd. implementuje přes Dibi).

Hlavní část přijde v páté, servisní vrstvě. Některé věci, jako třeba získání entity článku a její předání do šablony pro vypsání, dělám prostě přímo přes repositář (ten vždy mapper zapouzdřuje uvnitř, s mapperem se pracuje pouze v repository) v presenteru ($this->context->articlesRepository->getById($id)). Nicméně složitejší úkony jako přidání článku nejlépe implementuji ve vlastní třídě. Třídě, která od ničeho nemusí dědit, a která má jasný úkol vyjádřený jednou vhodně pojmenovanou public metodou. V tomto případě třeba ArticleFactory s metodou create().

Uvnitř vytvořím instanci entity Article, persistuji ji v repositáři a následně volám flush() všech změn na entitách (stejně funguje i Doctrine 2). Někdy je například přidání článku spojeno se založením komentářového vlákna… taky to provedu v ArticleFactory. Jindy se při vytvoření článku odešle email, nebo třeba notifikace všem, kdo sledují autora… taky to provedu v ArticleFactory. Tato třída mi nyní shrnuje funkcionalitu „přidání článku“ včetně všech souvisejících dílčích úkonů. Mohu ji snadno testovat (předám jí pouze mock repositáře, mock komentářového repozitáře, mock maileru…), má příjemné API (takže presentery zůstavají přehledné), snadno se udržuje (má jasně definovanou úlohu).

Hlavní výborná feature tohoto návrhu je, že ORM v něm stojí pouze jako ORM (nikoliv jako celý model, kterým ani není). Je to jedna složka modelu, „stavební kámen“ jeho části (jiné části mohou být ještě úplně jiného druhu, webové služby, knihovny atd.).

Editoval vojtech.dobes (24. 4. 2012 12:45)

frosty22
Člen | 373
+
0
-

Děkuji za příspěvek, podíval jsem se na ono ORM, které zmiňuješ a vypadá zajímavě, otázka spíše zda začít používat systém, který zatím není tolik rozšířen a jak na onom fórum píše sám Petr Procházka, tak ještě není tak vyladěné. Ale na druhou stranu je na tomto velice dobře vidět, že nejde jen tak jednoduše si rozdělit aplikaci na vrstvy (lépe řečeno udělat si jednoduché „ORM“).

Plánuji se přeci jen detailněji podívat na schopnosti opěvované Doctrine 2, pouze tedy první věc, která by mě zajímala (beru dle zkušeností s Doctrine 1.3) – jak jste na tom s návrhem databáze. Osobně jsem zvyklí používat MySQL Workbench a zde s modelem synchronizovat databázi. U D2 však převládá asi síla YAMLu a generace entit z něj? Jistě jde i tedy vygenerovat entity přímo z databáze, ale ot. zda-li je to stejně efektivní? či máte jiný nástroj, jako alternativu pro Workbech? Osobně si asi nedokáži představit navrhovat databázi v YAMLu, aniž bych viděl schémata a vše si jen představovat :)

Filip Procházka
Moderator | 4668
+
0
-

Dle mého je obrovský omyl generovat entity.

Když pracuješ s ORM, tak tě nezajímají tabulky ale entity. Tedy je principielně špatně navrhovat databázi a pak z toho generovat entity. Nedělejte to, nikdo, nikdy.

Tedy správně je napsat entity s annotacemi a databázi generovat z nich. Jinak nepoužíváš ORM, ale jakousi spatlaninu, co nikdy nebude fungovat správně.

frosty22
Člen | 373
+
0
-

Našel jsem tedy nějaký nástroj ORM Designer (bezplatná alternativa zatím nebude?), čili ten již by měl sloužit k návrhu entit jako takových? Či tedy ty přímo píšeš entity samotné? To si zatím asi nedovedu představit u většího projektu, kdybych vizuálně neviděl ony vazby.

Filip Procházka
Moderator | 4668
+
0
-

Základ je papír + tužka :)

Kdysi jsem měl nápad generovat kód z Violetu. Když si potřebuju něco nakreslit a jsem líný vytahovat papír, tak to stačí.

frosty22
Člen | 373
+
0
-

No papír a tužka, to je osvědčená a využívaná metoda, tj. pravda – pouze potom z nich psát ony entity, musí být trošku „oser“, hlavně tedy ony relace :) Naštěstí tedy onen tvůj generátor z Violetu vypadá zajímavě :)