Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

1. diel - Úvod do softvérových architektúr

Okolo dependency injection je veľké halo. Tento návrhový vzor používajú väčšie frameworky k odovzdávanie závislostí vnútri aplikácie. Pochopiť DI nie je úplne triviálne, samotnému mi trvalo pomerne dlho, než som ju začal používať aspoň intuitívne a vzor som pochopil kompletne, až keď som si ho sám implementoval vo svojom frameworku. V tomto kurze návrhu softvéru vás prevediem rôznymi spôsobmi odovzdávania závislostí v tej istej aplikácii, kde postupnými krokmi a pokusy dospejeme k tomu, že DI je jediná správna možnosť. Uvedieme si samozrejme názorné príklady, ktoré si podrobne popíšeme. Tento kurz teda dáva DI do kontextu s ďalšími zlými spôsobmi odovzdávania závislostí, napr. Singleton alebo ServiceLocatory a vysvetľuje ich nevýhody. Tým sa odlišuje od samostatných článkov tu na sieti, kde sú popísané rôzne spôsoby odovzdávania závislostí samostatne, ale vytráca sa kontext, čo veľmi sťažuje pochopenie v jadre jednoduchého princípu. Na konci kurzu si dokonca ukážeme aj minimalistickú implementáciu vlastného DI kontajnera na iba 50 riadkov. Tento kurz predpokladá znalosť aspoň základov objektovo orientovaného programovania.

Dependency Injection (DI)

Hoci sa DI používa najmä vo webových frameworkoch, nie je obmedzená len na webové aplikácie. Problém odovzdávanie závislostí medzi objektmi existuje v každej objektovej aplikácii, ktorá má už treba len 10 tried. So zvyšujúcim sa počtom tried bez DI problémy s návrhom eskalujú. Ako ukážku som vybral jednoduchú webovú aplikáciu v PHP, ale DI sa samozrejme používa úplne rovnako napr. V Jave (Bean) alebo v C# .NET, prípadne v ďalších jazykoch. Znalosti sa vám určite budú hodiť na pohovore, môžem potvrdiť, že sa na to pýtajú takmer všade. Je to jedna zo znalostí pokročilejších programátorov.

Čo je to závislosť

Informačné systémy obsahujú zvyčajne veľké množstvo kódu. Pre porovnanie, informačný systém ITnetwork.cz je napísaný niekoľkých sto tisíckami riadky kódu. Aby sme sa v takom kóde vyznali, rozdeľujeme informačné systémy na objekty. ITnetwork.cz je poskladaný zo stoviek objektov, ktoré sú prehľadne začlenené do menných priestorov (balíčkov). Keďže podľa princípu SRP (Single Responsibility Principle) by každý objekt mal byť zodpovedný len za jednu oblasť, je výsledná aplikácia zložená z väčšieho množstva menších objektov, ktoré spolu komunikujú. Týmto rozdelením získame prehľadnosť a znovupoužitelnost komponentov, ďalšie aplikácie môžeme skladať z už existujúcich univerzálnych objektov. V monolitických aplikáciách nabitých v jednom súbore býva často problém použiť čokoľvek niekde inde a tiež sa v ňom vôbec vyznať.

Sa SRP súvisia ďalšie princípy:

  • High Cohesion (Vysoká súdržnosť) - Zodpovednosť za určitú oblasť aplikácie (napr. Správu používateľov) by sme mali sústrediť do jedného miesta, do čo najmenšieho počtu tried (napr. Za užívateľa by mal byť zodpovedný SpravceUzivatelu).
  • Low Coupling - (Nízka previazanosť) - Zodpovednosť by mala byť objektom pridelená tak, aby museli komunikovať s čo najmenším počtom iných objektov. Keďže objekty sa sústredí len na jednu malú časť aplikácie, logicky potrebujú čas od času využiť funkcií iných objektov. Napr. SpravceUzivatelu nebude bežne komunikovať so správcom automobilov, nemal by k tomu mať dôvod. O tom, ako zodpovednosť rozdeliť existuje niekoľko ďalších poučiek, ktoré ale nie sú predmetom tohto kurzu.

V každej objektovej aplikácii sa nám teda stane, že objekt potrebuje komunikovať s iným objektom. Vznikajú tak závislosti. Samozrejme nechceme, aby sa objekty vytvárali stále znovu, ale aby bola vytvorená vždy jedna jediná inštancia každej závislosti (niekedy sa im hovorí aj služby / servisy) a tá bola odovzdávaná tam, kde je potreba. Napr. inštanciu databázové triedy Db vytvoríme raz a potom odovzdáme všetkým objektom, ktoré potrebujú komunikovať s databázou, treba triede SpravceUzivatelu. Podobných služieb, ktoré využívajú ďalšie objekty, by sme určite vymysleli mnoho, okrem databázy je to napr. Odosielanie emailov, logovanie, aktuálne prihlásený používateľ a podobne.

Závilosti je teda potrebné prístupu objektu k nejakým ďalším objektom. Niekedy takto hovoríme o skladanie objektov, jeden objekt používa niekoľko ďalších k svojej funkcii.

Ako to všetko začalo

Aby sme dosiahli čo najväčšieho pochopenie prínosu DI, vezmime to úplne od začiatku. Už som spomenul, že ukážky budeme písať v jazyku PHP. Ten má štandardné C-like syntax, mal by teda byť čitateľný pre naprostú väčšinu programátorov. Pre ukážky myslím poslúži skvele, vy si princípy veľmi ľahko premietnete do svojich programovacích jazykov.

Neštruktúrovaný kód

Prvá aplikácia sa písali tak, že sa na začiatku súboru pripojilo k databáze, spustil sa nejaký SQL dotaz, potom sa vypísal kúsok HTML stránky, vypísala sa dáta opäť pomocou programovacieho jazyka, potom sa vypísal zvyšok stránky. Takáto aplikácia vyzerala asi takto:

<?php
$databaze = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8mb4', 'jmeno', 'heslo');
$auta = $databaze->query("SELECT * FROM auta")->fetchAll();
?>
<table>
<?php foreach ($auta as $auto) : ?>
    <tr>
        <td><?= htmlspecialchars($auto['spz']) ?></td>
        <td><?= htmlspecialchars($auto['barva']) ?></td>
    </tr>
<?php endforeach ?>
</table>

Vidíme, že sa mieša SQL s PHP (databázová knižnica PDO) as HTML kódom. To všetko v jednom súbore. V tejto ukážke sa zdá zvolená stratégia ako správna, avšak až budú v raz súbore desiatky tisíc riadkov a nám sa bude do ladenia SQL dotazov pliesť kód štýlovanie vzhľadu tlačidiel, určite zistíme, že to nie je spôsob, ktorým sme schopní vytvoriť reálnu komerčné aplikáciu. Aj ITnetwork v minulosti takto fungoval, je to už pekná riadok rokov. Boli sme na strednej škole as architektúrou sme nemali žiadne skúsenosti.

Aplikáciu síce môžeme rozdeliť aj takto do viacerých súborov, ale rovnako nad ňou nebudeme mať nikdy úplnú kontrolu. Všetky súbory budú mať prístupné všetky dáta zo všetkých súborov. Tým vznikajú globálne väzby a začínajú sa nám nekontrolovane prepisovať dáta a identifikátory, stačí zvoliť ten rovnaký názov funkcie alebo premennej ako sme použili v inom súbore. A to je veľmi jednoduché, verte mi :) Podobný neobjektové kód našťastie v moderných jazykoch už písať ani nedá.

Ani rozdelenie kódu do funkcií by nám nepomohlo. Funkcie, teraz myslím tie v starších jazykoch, na rozdiel od metód objektov, nemajú žiadny kontext. Aj keď si urobíme niekoľko súborov a každý s niekoľkými funkciami, nevyhneme sa kolíziám názvov funkcií. To PHP so svojimi starými funkciami vyriešilo naozaj škaredými a dlhými názvami, ktoré sú ešte veľmi neštandardné. Napr. väčšina funkcií pre prácu s poľom začína na array_, ale dĺžku poľa nám vráti funkcie count(). Keď funkcie nepatrí objektom, začneme sa po chvíli strácať v ich názvoch a hlavne budeme mať problém so zdieľaním dát, čo vyriešime buď nebezpečnými globálnymi premennými alebo naše funkcie budú mať príliš veľký počet parametrov.

Ukážme si ešte jeden odstrašujúci príklad z redakčného systému Wordpress, pravdepodobne jednej z najhoršie napísané aplikácie z tých populárnych v PHP. Pozrite sa, čo sa stane, keď píšete aplikáciu úplne bez architektúry:

Ťahák Wordpress funkcií - Softvérové architektúry a dependency injection

Len z malej ukážky globálnych funkcií vidíme, že niektoré začínajú na "the", zrejme kolidovali s inými bez "the", niektoré na "wp_", niektoré na "get_". Brrr. Snáď som vás presvedčil, že funkcia chce nutne napojiť na objekty, aby nedochádzalo ku kolíziám názvov. Viac objektov môže mať potom pokojne funkciu s rovnakým názvom, podľa objektu sa pozná, ktorá sa má zavolať a IDE nám je tiež na objekte automaticky ponúka. Nemusíme si ich teda pamätať a nepotrebujeme žiadne ťaháky, ako je ten na obrázku vyššie. Je škoda, že takto niektorí ľudia ešte programujú. Poďme sa otriasť a neobjektové svet už radšej opustiť.

Príklad s výpisom áut nás bude sprevádzať celý seriál a ukážeme si na ňom všetky možné spôsoby odovzdávania závislostí, až dôjdeme až k Inversion of Control a práve Dependency Injection, ktorá je jeden z druhov IOC.

Objektový kód

Problémy "všetko v jednom súbore" alebo "veľa podivne pomenovaných funkcií s mnohými parametrami" rieši objektovo orientované programovanie (mimo ďalšie výhody ako dedenie a podobne). Už však vieme, že sa musíme zaoberať tým, ako aplikáciu na objekty rozdelíme a hlavne ako budú potom komunikovať so svojimi závislosťami. Predpokladám, že základy OOP ovládate, ak nie, absolvujte prosím najskôr kurz OOP vo vami vybranom jazyku, pozri navigačné menu.

Pokračovať budeme v nasledujúcej lekcii, Monolitická a dvojvrstvová architektúra , kde si predstavíme rôzne objektové architektúry.


 

Všetky články v sekcii
Softvérové architektúry a dependency injection
Preskočiť článok
(neodporúčame)
Monolitická a dvojvrstvová architektúra
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
4 hlasov
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity