Diskuze: Servicy on-demand
- manwe
- Člen | 44
Zdravim,
v kancelari resime u jednoho vetsiho projektu to, ze casto v komponentach/prezenterech automaticky (bezmyslenkovite) injectujeme z DI kontejneru ruzne servicy, protoze se obcas hodi (nejsou kriticke pro vykresleni komponenty, ale komponenta je treba ruzne casto vyuziva).
Uvedu priklad – komponenta EventDetail vykresluje detail udalosti.
V udalosti je moznost zaslat hromadny e-mail vsem pozvanym ucastnikum.
O zasilani e-mailu se stara servisa MailService. Realne se to poslani
hromadneho e-mailu vyuzije tak pri 1 vykresleni kompoenenty z 1000, takze
v 999 pripadech z 1000 se vytvari servica, ktera neni realne potreba.
V bezne situaci bych udelal neco jako
class EventDetail extends BaseControl{
protected $mailService;
protected $event;
// mailService se vytvari v DI kontejneru pri vytvareni komponenty
public function __construct(Event $event, MailService $service){
$this->mailService = $service;
$this->event = $event;
}
protected function sendMassEmail($subject, $text){
$this->mailService->sendMassEventEmail($this->event, $subject, $text);
}
}
Ted dochazime do situace, ze se zacina projekt znatelne zpomalovat, protoze
DI kontejner musi casto vytvaret pomerne slozite servicy, ktere se casto
nepouziva, jen proto, ze se „obcas“ v komponente/presenteru hodi.
Vedeme tedy diskuzi o tom, jak nejlepsim zpusobem servisy vytvaret realne
„on-demand“ – jak to resite vy?
Aktualne se klonim k moznosti
class EventDetail extends BaseControl{
protected $event;
public function __construct(Event $event){
$this->event = $event;
}
protected function sendMassEmail($subject, $text){
// mailService se vytvari v DI kontejneru az pri realnem odesilani e-mailu
$mailService = $this->getPresenter()->context->getByType(MailService ::class);
$mailService->sendMassEventEmail($this->event, $subject, $text);
}
}
(prime sahani do contextu z BasePresenteru bych jeste obalil nejakou metodou, ale princip zustava)
Jak to resite vy?
Diky za nazory.
Editoval raddy668 (5. 2. 2019 11:05)
- David Matějka
- Moderator | 6445
protoze DI kontejner musi casto vytvaret pomerne slozite servicy
v čem je složité vytváření services? v inicializaci služby bys měl pouze přiřazovat vstupy z kontruktoru (a setup metod) do class properties
jinak nette má na to koncept accessoru, funguje to podobne jako generované tovarny, ale nevytváří to nové instance, ale vrací tu stejnou (z DI kontejneru). ale je to spíše workaround na špatné návrhy aplikace.
a taháním services z contextu se tak trochu vracíš do doby nette < 2.1, kdy DI nefunguvalo tak jak nyní a používal se právě pattern services locatoru
- manwe
- Člen | 44
Vim ze se servica nevytvari vickrat v DI kontejneru.
Vem si to, ze mas treba nejakou slozitejsi servicu, ktera vyuziva dalsich X servis (nerikam ze je to tak dobre, ale ne vsechno v projektu muzes ovlivnit), takze kdyz si ji nainjectuju do nejake komponenty takovou slozitou servisu a nevyuziju, tak treba instancuju 10 trid zbytecne (a ja nemuzu realne prochazet kazdou z tech servis a optimalizovat ji, aby v konstruktoru treba realne delala jenom to nejmene nutne veci). A tohle se treba deje 20–30× pri vykresleni nejake stranky v administraci.
To pak ten chod uz fakt zpomali…
- David Matějka
- Moderator | 6445
chápu, co chceš říct.
Pokud není v tvých silách optimalizovat vytváření těch závislostí, tak použij ten accessor. jde asi o nejmenší zlo – máš tak stále celkem jednoznačně definované závislosti, které předáváš přes DI, ale vytvářejí se lazy.
edit: ale i tak bych zkusil nejdřív spustit profiler nad aplikací a třeba zjistíš, že ta optimalizace není tak komplikovaná :)
- duke
- Člen | 650
raddy668 napsal:
Vim ze se servica nevytvari vickrat v DI kontejneru.
To není to, co se ti snažil @DavidMatějka říct. Mluvil o konceptu automaticky generovaného accessoru v kontrastu s konceptem automaticky generované factory (který DI kontejner také podporuje, a který v případě factory vytváří vždy novou instanci).
raddy668 napsal:
Vem si to, ze mas treba nejakou slozitejsi servicu, ktera vyuziva dalsich X servis (nerikam ze je to tak dobre, ale ne vsechno v projektu muzes ovlivnit), takze kdyz si ji nainjectuju do nejake komponenty takovou slozitou servisu a nevyuziju, tak treba instancuju 10 trid zbytecne (a ja nemuzu realne prochazet kazdou z tech servis a optimalizovat ji, aby v konstruktoru treba realne delala jenom to nejmene nutne veci). A tohle se treba deje 20–30× pri vykresleni nejake stranky v administraci.
To pak ten chod uz fakt zpomali…
Pokud by to tak skutečně bylo, tak by přesně toto řešil ten accessor, protože by odložil instancování všech těch závislostí (resp. jen těch dosud jinde nepoužitých) složité servisy do doby, než bys na tomto accessoru zavolal metodu get.