2. díl - Monolitická a dvouvrstvá architektura

Návrh Softwarové architektury a depencency injection Monolitická a dvouvrstvá architektura

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Úvod do softwarových architektur, jsme si vysvětlili pojem závislost v objektově orientovaném programování a na odstrašujících příkladech si ukázali proč je dobré programovat právě objektově. Jak je aplikace z objektů poskládaná nám udává její architektura. O různých architekturách bude pojednávat dnešní tutoriál.

Programování aplikací si můžeme představit jako stavbu výškové budovy. Pokud ji architekt špatně nevrhl, od určité výšky nám spadne. Musí mít pevnou páteřní strukturu. Neustálé dopisování kódu po celé aplikaci je denním chlebem programátorů, její konstrukce musí být proto na tolik kvalitní, aby to umožňovala. Pojmem "kvalitní" rozumějme samozřejmě tak dobré rozdělení odpovědnosti objektů, že i při stovkách tříd budeme vždy vědět kam sáhnout a celý projekt bude 100% přehledný. Že se to zdá nemožné? Ale kdepak. Asi vás nepřekvapí, že opět vytáhneme další návrhové vzory. Vezměme to ovšem postupně, abyste měli opravdu detailní přehled o různých architekturách.

Architektury

Nyní se budeme bavit o tzv. logických architekturách. Ty si nepleteme s architekturami fyzickými, které udávají jak je uspořádaný hardware, např. fyzická architektura klient-server. Nás v tomto kurzu zajímá uspořádání kódu v objektech.

Monolitická architektura

V této architektuře celá aplikace funguje jen jako jedna vrstva. Vrstvou myslíme jednu skupinu objektů. Tímto způsobem jsou často psané menší aplikace. Monolitická architektura je spíše antipattern a u větších aplikací bychom ji neměli používat. Na něčem se ale samozřejmě začít musí :)

Roury a filtry

Spíše pro ucelení si zmiňme ještě architekturu trubek (pipes), kterou používají UNIXové operační systémy. Funkcionalita je rozdělena do velkého množství malých samostatných programů, které se navzájem provolávají a předávají si data. Možná umíte v Linuxu pomocí trubek předávat data mezi různými příkazy. Linux je také ukázka toho, že systému může dobře fungovat, když jej sestavíte ze stovek malých programů, kde každý dělá dobře svou malou část práce.

Dvouvrstvá architektura

Dvouvrstvá architektura se často používá u API serverů nebo služeb obecně. Občas se také setkáme s pojmem SOA (Service-Oriented Architecture), který kromě softwarové architektury zahrnuje i tu logickou na serveru, typicky klient-server. Dvouvrstvé aplikace se vyznačují tím, že neprezentují data uživateli. Obvykle komunikují s nějakou další aplikací, přijímají od ní požadavky, zpracovávají je a vracejí výsledná surová data.

Nyní se dostáváme ke slíbeným architektonickým návrhovým vzorům. Jsou to:

  • Indirection - Pomocí prostředníků můžeme zjednodušit vazby mezi objekty a zpřehlednit aplikaci. Pokud do aplikace tedy paradoxně přidáme umělou vrstvu, která bude zprostředkovávat komunikaci mezi 2 skupinami objektů, bude aplikace jednodušší než bez této vrstvy. Někdy o těchto třídách hovoříme jako o servisních, neplést se službami (services).
  • Controller - Návrhový vzor Controller hovoří o Indirection ještě přesněji a věnuje se aplikacím, které komunikují s uživatelem (a to dělá naprostá většina aplikací). Říká, že veškerá komunikace s uživatelem by měla být soustředěna v oddělených objektech k tomu určeným, tzv. kontrolerech. Ty poté tvoří kontrolní vrstvu aplikace, v některých modifikacích se jí může říkat vrstva prezentační. Naopak třídy obsahující logické operace by měly být od komunikace s uživatelem úplně odstíněny. Takovým třídám s obchodní logikou se poté říká Modely, někdy je podle konkrétní implementace nazýváme entitními třídami, manažery (česky také správci) nebo repositáři.

V dvouvrstvé aplikaci tedy máme 2 skupiny objektů - Kontrolery a Modely.

Pokud bychom programovali API server, kterého bychom se ptali na všechna auta v databázi a on nám je poslal zpátky v nějakém výměnném formátu (tedy ne jako HTML stránku, ale jako data pro další strojové zpracování, např. v JSONu), vypadal by zdrojový kód aplikace takto:

Aplikaci rozdělíme na 2 složky - Modely a Kontrolery.

Modely/Spravce­Aut.php

Správce aut poskytuje logiku pro práci s auty. To je jeho odpovědnost. Podobně by např. logika pro uživatele by byla soustředěna ve třídě SpravceUzivatelu a tak dále. Závislost $databaze objektu předáme v konstruktoru.

class SpravceAut
{

        private $databaze;

        public function __construct($databaze)
        {
                $this->databaze = $databaze;
        }

        public function vratAuta()
        {
                return $this->databaze->query("SELECT * FROM auta")->fetchAll(PDO::FETCH_ASSOC);
        }

        // Další metody pro práci s auty, např. přidávání nových aut, vyhledávání aut, mazání aut, editace aut...

}

Modely vůbec neřeší komunikaci s uživatelem, pouze poskytují logické operace v rámci své odpovědnosti.

Kontrolery/Au­taKontroler.php

Kontroler bude přijímat požadavky od uživatele, v našem případě bude uživatelem sice opět stroj, který volá náš API server, ale i ten se stále počítá jako uživatel. Na základě přijatých požadavků zavolá kontroler příslušné modely a vrátí výsledek jejich práce. Jeho smyslem je pouze zprostředkování komunikace mezi uživatelem a modelovou/logickou vrstvou aplikace. Typicky se kontrolery snažíme psát co nejkratší a slouží pouze jako "dráty" mezi uživatelem a logikou.

class AutaKontroler
{

        private $spravceAut;
        private $databaze;

        public function __construct($databaze)
        {
                $this->databaze = $databaze;
                $this->spravceAut = new SpravceAut($this->databaze);
        }

        public function vsechna()
        {
                echo(json_encode($this->spravceAut->vratAuta()));
        }

        // Případné další akce jako jedno($id), odstran($id), ...

}

Kód by měl být srozumitelný. Na kontroleru je zavolána akce, která se má provést. Kontroler získá data od modelu, který vůbec neví o nějakém uživateli nebo požadavku, stará se jen o data v rámci své odpovědnosti, tedy o data aut. Kontroler se naopak vůbec nestará o data, ta si nechá poslat a stará se o to jaká data uživatel chce a jak mu je pošle. Následně tato data pošle uživateli pomocí funkce json_encode(). V reálu bychom funkci předali ještě nějaké další parametry a kontroler by asi dědil od nějakého předka, ale tím se nyní nezatěžujme.

Jelikož je na ITnetwork zvykem předkládat kompletní řešení, ukažme si i jak by systém vnitřně kontroler podle požadavku zavolal. Jde o velmi zjednodušenou ukázku, pokud vás zaujme, níže je uveden odkaz na kompletní implementaci a další informace.

index.php

Po přechodu na index.php se prvně registruje autoloader, hledající třídy nejprve ve složce Kontrolery a poté ve složce Modely. Inteligentnější implementace viz další PHP kurzy. Pokud programujete v jiném jazyce než v PHP, pak se vaše třídy pravděpodobně načítají plně automaticky a je jedno v jaké jsou složce/balíčku.

Představme si, že se nacházíme na adrese:

localhost/index.php?kontroler=Auta&akce=vsechna

Z toho potřebujeme poznat, že se má vytvořit AutaKontroler a na něm zavolat metoda vsechna(). Kód by měl mít alespoň intuitivně srozumitelný, přidal jsem do něj také komentáře.

<?php

// Jednoduchý autoloader
// Pro jiné programovací jazyky ignorujte
spl_autoload_register(function($nazevTridy) {
    if (file_exists("Kontrolery/$nazevTridy.php"))
        require("Kontrolery/$nazevTridy.php");
    else
        require("Modely/$nazevTridy.php");
});

// Vytvoření instance databázové třídy
$databaze = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'root', '');
// Vytvoření příslušného kontroleru podle URL adresy
$nazevKontroleru = $_GET['kontroler'] . "Kontroler";
$kontroler = new $nazevKontroleru($databaze);
// Zavolání metody podle URL adresy na konroleru
$kontroler->$_GET['akce']();

Pro získání všech aut od serveru bychom tedy otevřeli tuto adresu:

localhost/index.php?kontroler=Auta&akce=vsechna

A zpátky by se k nám dostal nějaký takovýto JSON:

[
        {
                "auta_id":"1",
                "barva":"modra",
                "spz":"123ABC"
        },
        {
                "auta_id":"2",
                "barva":"cervena",
                "spz":"456DEF"
        },
        {
                "auta_id":"3",
                "barva":"cerna",
                "spz":"789GHI"
        }
]

Akce samozřejmě mohou mít ještě parametry a typicky používáme tzv. pretty URL. URL adresa dvouvrstvé aplikace by tedy mohla vypadat i např. takto:

aplikace.cz/clanky/vyhledej/php

Podle ní by se zavolal ClankyKontroler, na něm metoda vyhledej() s parametrem php. Části webové aplikace, která podle URL adresy volá příslušné kontrolery, se říká Router. V ukázce výše byl hodně minimalistický. Router, který by uměl předávat i parametry metodám, podporoval pretty URL a uměl např. chybové stránky, by byl o chlup delší. Můžete se na něj podívat v kurzu Jednoduchý redakční systém v PHP objektově (MVC). Funkční aplikace je ke stažení v příloze jako u všech našich lekcí.

V příští lekci, Třívrstvá architektura a další vícevrstvé architektury, si vysvětlíme třívrstvou architekturu, opět včetně funkčního příkladu.


 

Stáhnout

Staženo 11x (7.99 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
5 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (2)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!