Diskuze: Filozofie Nette modelů - proč to není špatně?

Tvůrce

Zobrazeno 16 zpráv z 16.
V tvé otázce mi nějak chybí otázka. Co že je na tom podle tebe konkrétně špatně?
Nette nemá ORM, proto tam není User entita. Můžeš si zkusit tu entitu udělat a data na ní namapovat. Zjistíš, že to není tak jednoduché a že napsat ORM framework je dost práce. Proto se to bez něj tak nedělá.
Kdyby tam entita byla, neměla by určitě mít metody update()
ani delete()
, protože Active Record je antipattern. Entita by
neměla mít odpovědnost za své odstranění z nějakého kontextu, ale ten
kontext by ji měl odstraňovat. Proto by update/delete metody byly v nějaké
User service.
Tohle je třeba kód poctivě ukradený z předmětu, co se zabývá specificky Nette na FIT ČVUT, tak bych předpokládal, že to bude používat nějaké best practices.
To podle mě záleží na tom, na jak velký projekt se to použije. Jestli se ti vyplatí nějak obalovat to, co ti ten model vrací, do entity, nebo by to znamenalo zbytečný čas navíc.
Jasně, můžeš později zjistit, že bys třeba některou vlastnost potřeboval udělat virtuální... a máš problém. Na druhou stranu, když se takový požadavek později vynoří, znamená to, že se jedná o něco, s čím jsi v době zadání nepočítal a převedením vlastnosti do virtuální podoby jen oddaluješ nevyhnutelné (tohle samozřejmě hodně záleží na okolnostech).
Co se týče toho, že ti to vrací třeba nějaké pole s klíči odpovídajícími názvům sloupců v DB tabulce a případné změny názvů těchto sloupců – tento případ pořád ještě lze umlátit zavedením konstant na ty názvy. Pak teoreticky stačí jen měnit hodnoty těch konstant a nemusíš dělat nějaké šílené globální find & replace.
Vůbec bych neměl problém uvádět takový kód na tom předmětu jako "správný", když se vysvětlí, jaké má potenciální nedostatky. A bude se třeba pokračovat na tu entitu. Vždycky je potřeba najít kompromis mezi mírou abstrakce (= možnost dobře reagovat na změnu požadavků) a třeba čitelnosti/přehlednosti, výkonu.
Dobře, ale jak v tomto uděláš refactoring? Prostě nemáš na výběr nic
lepšího než global search &replace.
Není přeci třeba nějaký bloated ORM framework. Mně se o veškeré ORM
stará dohromady as 550 řádků + konkrétní implementace (2 primitivní
metody a mapu atributů), takže overhead je minimální.
ActiveRecord je antipattern, takže budeme vracet ActiveRow
a
Selection
?
Abych odpověděl na otázku, co je špatně: Pokud něco změním, musím to
hledat v:
To si koleduje o strašně moc chyb. Když místo toho budu mít na jednom
místě stringy a potom se na ně buď budu odkazovat, nebo budu používat
vlastnosti entity (a důsledně budu dělat typehinty), dokážu velice snadno
něco měnit, protože např. IDE mi dokáže jednoznačně najít všechny
použití této konkrétní vlastnosti a jediné, kde to musím najít ručně
jsou šablony.
Když všude budu mít pole se stringovými klíči, nepůjde to měnit nebo
dokonce můžu udělat překlep a jediné místo, kdy zjistím, že to je
špatně je, až se to dostane k databázi a ta řekne, že nezná
sloupeček.
Jasně, můžeš později zjistit, že bys třeba některou vlastnost potřeboval udělat virtuální... a máš problém. Na druhou stranu, když se takový požadavek později vynoří, znamená to, že se jedná o něco, s čím jsi v době zadání nepočítal a převedením vlastnosti do virtuální podoby jen oddaluješ nevyhnutelné (tohle samozřejmě hodně záleží na okolnostech).
Mám docela dost velký problém, protože buď musím přepsat prakticky všechny modely, nebo si na jednom modelu zavedu mezivrstvu a budu všude dělat výjimky - hodně štěstí s tím.
Přitom kdybych měl od začátku mezivrstvu - třeba jen wrapper
ArrayHash
, co by tahal vše přes __get, __set, půjde to
relativně snadno...
Co se týče toho, že ti to vrací třeba nějaké pole s klíči odpovídajícími názvům sloupců v DB tabulce a případné změny názvů těchto sloupců – tento případ pořád ještě lze umlátit zavedením konstant na ty názvy. Pak teoreticky stačí jen měnit hodnoty těch konstant a nemusíš dělat nějaké šílené globální find & replace.
Já to třeba používám, ale proč to nepoužívá nikdo jiný (resp.
neviděl jsem to nikde jinde)? To je přeci v podstatě kopírování kódu -
tedy skoro jako opisovat všude ten samý kód místo vytvoření metody. Když
chceš potom tohle předělat, musíš to udělat úplně stejně jako kdybys
všude kopíroval kód místo metody.
Přesto se zdá, že to nikoho nevzrušuje...
A těch 550 řádků ti jako i mapuje joiny a optimalizuje je? To bych potom docela rád viděl. Migrace třeba je pak kapitola sama pro sebe.
Stringy si samozřejmě koledují o chyby, ale ORM je prostě složité.
Proto ho Nette nemá, proč myslíš, že tam není? A na ČVUT bys očekával co? Že
si nejdříve napíší vlastní ORM a pak udělají ty příklady v tom nebo
jak? Bez ORM prostě entity nemají smysl a Nette ORM nemá. Snad jsem ti
odpověděl.
Jasně, že nedělá, ORM je pro to dost honosný název . mapuje to jednoduché modely na
ty pole, o optimalizace se stará Nette database.
A když uděláš dotaz třeba na články a jejich autory
(SELECT title, description, first_name, last_name FROM article JOIN user USING (user_id)
),
tak ti to potom namapuje na co?
Implicitně se to neumí namapovat na nic, ale pomocí polymorfismu se dá tohle manuálně přepsat na cokoliv, co chceš.
Tím se ale vzdalujeme o samotného tématu, má ORM třída je celkem irelevantní, já jsem chtěl vědět, proč se to dělá tak, jak se to dělá.
Nevzdalujeme, psal jsi, že stačí napsat 550 řádků, tak se snažím dopátrat toho, zda je to pravda nebo ne. Pokud ne, tak nemá smysl dále diskutovat a můžeme se spokojit s tím, že ORM FW si prostě sám nenapíšeš. Pokud ano, řekni mi jak bys vypsal takový seznam článků s jejich autory s tím tvým FW?
Asi takto:
class Article extends Entity
{
/**
* @var User
*/
public $author;
/**
* Return class which serves as a map between db and model
* @return string
*/
protected function getMapClass()
{
return TArticles::class;
}
/**
* Returns the name of the table related
* @return string
*/
public function getTableName()
{
return 'article';
}
protected function importSpecial(IRow $row)
{
$author = new User;
$user->importFromDb($row[TUsers::author]);
$this->author = $user;
}
}
class TArticles {
const id = 'id';
}
Neříkám, že to stačí pro všechno, ale je to takový základ, co si může napsat každý a potom rozšiřovat. Asi ne na úlohách ze cvičení, ale třeba masivní projekty by něco takového použít určitě mohly... ale nepoužívají (co jsem měl možnost vidět)
Měl jsem v plánu to napsat, ale začal jsem si procházet tu mou
implementaci a zjistil jsem, že jsem to psal v době, kdy jsem neznal
lazyloading... takže abych to provedl, nebylo by to vůbec efektivní.
A když se zamyslím nad tím, jak se to musí udělat tak, aby to bylo hezké,
vlastně se to musí udělat jako takový fancy obal pro to, jak se to dělá,
takže je vlastně všechno jasné Je tedy škoda, že nemá Nette vestavěné ORM, ale aby se to dalo
udělat dostatečně obecně, byla by to strašlivá obluda...
Mám dojem, že chodíš na srazy, někdy bych se na to stejně rád
podíval, jestli se tam potkáme
Já to nejspíš jednou přepíšu pořádně a někam ten kód hodím jako knihovnu.
Zobrazeno 16 zpráv z 16.