Struktura datového modelu rubrika: Programování: PHP

1 frantisek.sitner
položil/-a 9.11.2014

Ahoj, už dlouhou dobu se snažím přijít na to, jak by měl vypadat datový model. Přečetl jsem snad už desítky článků, ale nikde jsem se nedobral k tomu, jaká je ta správná podoba a tak se omlouvám, pokud použiji špatný název. Nejvíce vycházím z článku pět vrstev modelu od Jana Tichého.

Má být v Mapperu a v Repository x metod typu findByID, findByName atd.? Pokud ne, tak kde tyto metody mají být a pokud ano, jak by měl vypadat interface pro Mapper?

Vrstva nad Mapperem je Repository, nebo DAO?

Dočetl jsem se, že by v Repository nemělo být save a delete.

Děkuji za odpovědi.

odkaz
2 Tharos
odpověděl/-a 10.11.2014

Psaní x metod typu findByID, findByName bych Ti příliš nedoporučoval, protože:

  • Porušuješ tím open-closed princip, který má své opodstatnění a vyplatí se jej v co největší míře dodržovat
  • Koleduješ si o to, že Ti z repositářů postupně vzniknou velké nepřehledné třídy

Namísto těchto metod bych Ti doporučil Query objekty a pokud bys používal třeba Doctrine 2, tak by Tvůj problém v řadě případů řešilo i DQL. Relevantní čtení je například tohle: http://filip-prochazka.com/blog/doctrine-a-service-vrstva-aneb-takto-mi-...

Oproti Query objektům nemají metody findByNecoSpecialniho asi žádné výhody.

Co se Repository, DAO, metod save a delete týče, hezky vysvětlená je tahle záležitost například zde: http://stackoverflow.com/a/8550228

Komentáře

  • frantisek.sitner : Ahoj, pochopil jsem to správně, že každý Query objekt je jeden dotaz, tedy místo jedné metody? 13.11.2014
  • fprochazka : Ahoj, doplnil bych ještě odkaz na ukázkovej našlapanej QueryObject https://github.com/Kdyby/Doctrine/blob/master/docs/en/resultset.md 16.11.2014
  • Tharos : @frantisek.sitner: Striktní pravidlo, že co taková findByBlaBla metoda, to Query objekt, je zbytečně svazující. Query objekty jsou skvělé v tom, že můžeš přes jejich API různě nastavovat jejich vnitřní stav a řídit tím, na jaké Doctrine Query Builder/fluent volání nad NDB/fluent volání nad Dibi/whatever se pak přeloží. Já mám například findBy metodu v abstraktním repositáři nadefinovanou tak, že jí můžu předat více Query objektů a ony se postupně aplikují. Je to nesmíně efektivní, mám například samostatný Query objekt pro vyhledání produktů podle filtru a pak samostantý Query objekt pro limit a offset kvůli stránkování. Nenapsal jsi, jaké frameworky používáš. Pokud například Doctrine, je velmi inspirativní a použitelné Kdyby\Doctrine. Pokud používáš něco jiného, dost možná si budeš muset něco málo z infrastruktury napsat sám. Já mám podobnou hotovou pro Lean Mapper, ale ten nefrčí až tolik, že bych si myslel, že používáš ten. :) Query Object je každopádně obecný princip a návrhový vzor hezky popsaný například Fowlerem (Google navede). 16.11.2014
  • maryo : @fprochazka: No nevím... Ty metody withLastPost, withCategory, withAnswersCount... Toho jsem se u takhle pojmutýho query objectu přesně bál. Nestudoval jsem to nějak podrobně, ale přijde mi, že jsou to přesně adepti na další objecty a jejich následný složení. Co když budu potřebovat místo ResultSetu jen jednu otázku s posledním postem, kategorií a počtem odpovědí? 16.11.2014
  • Honza Břešťan : U query objectu taky preferuju spis komponovatelnost, nez pridavani metod "do sirky". Extremni pripad jsou v .NETu IQueryable<T> queries (http://msdn.microsoft.com/en-us/library/vstudio/bb351562%28v=vs.100%29.aspx), ktere maji obecny sequence/stream-like interface, kazda operace vrati novou IQueryable<T> instanci a daji se donekonecna skladat. Jednotlive implementace pak resi pruchod poskladanym stromem, jeho preklad na dotazovaci jazyk (at uz to je SQL a nebo treba Twitter API), nejakou prvotni optimalizaci a odeslani treti strane (DB, knihovna, remote API...). Da se kolem toho snadno postavit sada domain-specific dotazu (at uz objektu nebo funkci), ktere jsou ale porad stejne komponovatelne. Vychozi bod pro podobne reseni muze byt jak nejaky Command/QueryExecutor (kteremu se preda finalni query), tak Repository+UoW (kde repository slouzi jako vychozi query rikajici zhruba "... FROM X ..." a ke ktere se pak funkcni/objektovou kompozici prilozi zbytek). Tharosem popisovane reseni bude asi podobne, jen se ta kompozice deje az v repository predanim a postupnym vykonavanim vic queries misto prubezneho skladani, kde clovek pracuje porad s jednim objektem. 16.11.2014
  • Kit : @Jan Břešťan: Mám to řešení .NETu chápat jako variantu na téma Decorator? 16.11.2014
  • Honza Břešťan : V podstate jo. Implementovat se to da jak jako decorator (nejjednodussi, hned po funkci) tak eager transformaci te predane query (kazda nova query pak obsahuje primo kompletni expression tree misto toho, aby vlastila jenom svoji cast a zbytek query stranou (neznam implementaci, ktera by to delala takhle). Hodim na github par prikladu. 16.11.2014
  • Honza Břešťan : Ten priklad query funkci/objektu a kompozice: https://gist.github.com/jbrestan/18db80101122a169fd1b Aby nedoslo k mylce, ve vsech tech prikladech se strankovani provede na strane DB a na aplikacni server dorazi jen max jedna stranka dat. Za to je zodpovedny IQueryProvider te predane originalQuery. 16.11.2014
  • Kit : Díky, je to z toho patrné. 16.11.2014
  • Tharos : Abych jenom nepopisoval, co mám na mysli, vyňal jsem z jednoho svého e-shopu ukázku, jak lze se mnou popsanými Query objekty pracovat. https://gist.github.com/Tharos/8680094dddc708f65c27. Takovýto styl práce se mně osobně nejvíce osvědčil. Ještě k diskuzi výše – osobně si dávám záležet, aby mi jeden Query objekt vždycky řešil jednu nějakou smysluplnou věc a v praxi je pak skládám. Hlídám si, aby mi nerostly moc „do šířky“, protože to vede ke stejným problémům, k jakým vedou právě findByBlaBla metody. 16.11.2014
  • fprochazka : @maryo @Jan Břešťan: však já nepsal, že query objekt má být jenom jeden na entitu, jak si to zorganizuješ ve svém projektu je tvoje věc :) 9.12.2014

Pro zobrazení všech 8 odpovědí se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.