Materiály k predmetu Tvorba informačných systémov

0. Úvod

Tento dokument slúži ako doplnkový sumarizujúci text s informáciami, ktoré boli pokryté v kurze. Nemal by byť jedinou náhradou štúdijnej literatúry. V jednotlivých odporúčaných publikáciách pôvodní autori uvádzajú informácie rozpísané podrobnejšie a čitateľovi odporúčame sa im nevyhnúť. Tej-ktorej príslušnej špecializácii sa daní autori venujú dlhodobo a zozbierali svoje skúsenosti a poznatky do učebnicového formátu. Tento dokument teda iba zoskupuje materiál z rôznych zdrojov do jedného celku, tak ako sme ho postupne na prednáškach preberali a ako sa na neho budeme odkazovať aj v záverečnom teste.

Informatika ako disciplína sa delí na mnoho podoblastí. Jej rozdelenie by sme mohli urobiť podľa rozličných uhlov pohľadu. Či sa ale dívame na základy informatiky ako vedy alebo na jej množstvo aplikácií, jedno podstatné kritérium rozdeľuje informatikov na dve kategórie ľudí:
  1. výskumníkov, čiže ľudí, ktorí sa zaoberajú novými metódami, algoritmami, reprezentáciou dát, programovacími jazykmi, ... teda tých, ktorí rozširujú poznanie ľudstva o automatickom spracovávaní informácií na počítačoch;
  2. tvorcov reálnych systémov nasadených do prevádzky, ktorí spravidla používajú už overené - často štandardizované postupy, nástroje, metódy a technológie na to, aby v organizovanom procese vytvorili dielo podľa potreby praxe.
Tak ako žiadne iné, ani toto rozdelenie nie je čierno-biele a nájdeme výskumníkov, ktorí vytvárajú informačné systémy a naopak inžinierov, ktorí pri tvorbe systémov prispievajú aj k pokroku informatických vied a rozvoju nových technológií.

Uvedené rozdelenie budeme považovať za naše východisko a v celom tomto predmete sa zameriame na druhý typ aktivity, čiže budovanie rozsiahlejších informačných systémov podľa konkrétnej požiadavky praxe. Hoci štúdium na FMFI UK je väčšinou orientované na získavanie poznatkov pre vykonávanie prvého typu aktivity, každý informatik by mal mať dobrý prehľad o informatike aj z hľadiska "inžinierskeho" - čiže z hľadiska zaužívaných efektívnych postupov pri budovaní systémov. Alternatívny názov nášho predmetu by teda mohol byť "Úvod do softvérového inžinierstva". Softvérové inžinierstvo má veľa spoločného s inými inžinierskymi odvetviami - proces vývoja nového výrobku, diela, má svoje pravidlá - tak ako stavbár nemôže začať stavať múr bez toho, aby mu najskôr architekt nenavrhol plány celej stavby a statik nespočítal, či stavba vydrží očakávanú záťaž, tak ani informatik nemôže začať písať program bez toho, aby najskôr so zákazníkom poriadne nedohodol, čo ten naozaj potrebuje a poriadne si neuvedomil ako bude výsledok vyzerať, z akých častí bude zložený, aké budu medzi časťami závislosti a rozhrania.

Na druhej strane, preložiť kus zdrojového kódu z miesta na miesto je oveľa jednoduchšie ako preložiť vymurovanú stenu, to však nemení nič na tom, že čím viac o výslednom systéme na začiatku vieme, tým menej bolestný následný vývoj bude. Napriek tomu situáciu informatikov nepríjemne ovplyvňujú viaceré faktory: Rozvoj informačných technológií je veľmi rýchly. Podmienky, v ktorých bude vyvíjaný systém pracovať, sa priveľmi rýchlo menia a pri dodaní systému môže platiť už niečo celkom iné ako na začiatku vývoja. V porovnaní s inými oblasťami je vývoj hotových systémov veľmi lacný. Pred začiatkom "murovania steny" často nie je možné "nakresliť" a prediskutovať kompletný výsledný "obraz" pripravovaného systému. Naviac, vývojári si niekedy sami nie sú istí, ako sa systém, ktorý plánujú vyvinúť, bude v praxi správať, koľko námahy a času si vývoj vyžiada. Preto sa dnes softvérové inžinierstvo snaží reagovať na tieto javy vytváraním flexibilnejších postupov a súborov odporúčaní ako takýto chaos zvládnuť.

Pri uvažovaní nad celkom nám v informatike veľmi často pomáha abstrakcia. Umožňuje nevšímať si detaily na nižšej úrovni, zamerať sa na konkrétny problém bez straty kontroly nad celkom a vysporiadať sa tak s obrovskou zložitosťou celého systému. Abstrakcia je jeden z najužitočnejších mechanizmov v informatike vôbec a cvičenia, pri ktorých si uvedomíme, čo presne abstrakcia prináša, napr. písanie programov s viacvrstvovou hierarchickou architektúrou alebo práca s abstraktnými kolekciami vo vyšších programovacích jazykoch ako Python a Java by už pre nás mali byť známe veci, na ktorých môžeme stavať.

Text je rozdelený do 11 kapitol podľa tém prednášok takto: V prvej kapitole sa venujeme vývoju IS z hľadiska atribútov kvality, zadefinujeme viaceré pojmy softvérového inžinierstva, fázy vývoja a hlavne vysvetlíme rozličné modely vývoja softvéru. Hoci sa modely skoro nikde nepoužívajú vo svojej presnej podobe, tento prehľad stále patrí do povinných základov softvérového inžinierstva. V druhej kapitole podrobne rozoberieme fázu špecifikácie, ktorej kvalita je pre úspešnosť výsledného diela najdôležitejšia. Vývojári pri špecifikovaní a navrhovaní zobrazujú štruktúru, vzťahy, správanie jednotlivých častí systémov graficky - v názorných obrázkoch. Aby po sebe navzájom tieto obrázky dokázali čítať, zaužíval sa jednotný štandard na tvorbu diagramov - UML. V tretej kapitole sa zoznámime s najviac používanými druhmi diagramov UML. V štvrtej kapitole sa venujeme architektúre a návrhu softvérového systému - časť na ktorej dôsledné vypracovanie v praxi kvôli obmedzeným zdrojom často bohužiaľ nedochádza. Každý systém ale nakoniec nejakú architektúru a návrh má a je užitočné poznať ciele a prostriedky pri tvorbe "ideálneho" návrhu systému. Piata kapitola je prehľadom najpoužívanejších návrhových vzorov - čiže ustálených postupov pri tvorbe architektúry a návrhu, ktoré vývojári využívajú opakovane v rozličných informačných systémoch. Poznanie týchto (mohli by sme povedať štandardných) postupov urýchľuje a skvalitňuje vývoj. V súčasnosti nie je žiaden informačný systém izolovaný od zvyšku sveta - nejakým spôsobom si s okolím a ostatnými aplikáciami vymieňa údaje, nadväzuje na ich funkcionalitu. Šiesta kapitola sa venuje otázkam vzájomného prepájania aplikácií do väčších celkov, čiže integrácii aplikácií. Ukážka jednej z mnohých technológií, ktorá je používaná najmä v rozsiahlych aplikáciách vytvorených na platforme Java EE - technológie anotácií v zdrojových kódoch, je stručne uvedená v siedmej kapitole. Vo fáze implementácie informačného systému - teda samotného naprogramovania jeho častí - vývojári musia v praxi používať zásady písania čistého kódu. Inak by sa vytvorené systémy veľmi skoro stali neudržiavateľné, ak by vôbec niekedy vznikli. Zásadám čistého kódu podľa knihy A.C. Martina sa venuje ôsma kapitola. Záverečné tri kapitoly sú stručnejšie a vychádzajú z pozvaných prednášok hostí. Deviata kapitola objasňuje zásady a odporúčania dnes tak populárneho agilného vývoja pomocou metódy SCRUM. Desiata kapitola je o mäkkých zručnostiach (soft skills) - čiže osobnostných spoločenských vlastnostiach a zručnostiach, ktoré si môžeme systematicky budovať s cieľom dosahovania efektívnejšej spolupráce, vzájomného porozumenia pri práci na vývoji systémov i vôbec a zamedzovaniu zbytočných konfliktov. Posledná kapitola uvádza prehľad základných faktov o informatizácií štátnej správy v Slovenskej Republike, ktorá je podmienkou efektívneho fungovania spoločnosti v dnešnej dobe.

1. Uvedenie pojmov softvérového inžinierstva a modely vývoja informačných systémov

1.1. Kategórie SW

Vyvíjaný softvér môžeme rozdeliť do dvoch kategórií:

Krabicový softvér, ktorý je vytváraný pre veľkú skupinu zákazníkov, dodáva alebo predáva sa vo veľkých nákladoch, je určený na všeobecné použitie - čiže typicky pokrýva viacero rôznych používateľských scenárov, poskytuje množstvo funkcií, pričom väčšina používateľov využíva len malú časť z nich. Príkladmi sú známe operačné systémy, textové alebo grafické editory, počítačové hry, výukové programy, programy na vytváranie alebo prehrávanie multimédií, antivíry, zálohovací softvér a podobne. Niekedy sa označuje aj termínom COTS (Commercial off the shelf), hoci sem patrí aj nekomerčný open-source softvér vyvíjaný širokou komunitou vývojárov dobrovoľníkov. V prípade krabicového softvéru používatelia majú len malý a zväčša nepriamy vplyv na proces vývoja SW.

Softvér na mieru - vytvorený pre jedného, alebo úzku skupinu zákazníkov "na mieru" pokrývajúc ich konkrétne potreby. V takomto prípade používateľ využíva takmer všetku funkcionalitu softvéru a aktívne vstupuje do procesu vývoja. Príkladmi môže byť softvér pre kuriérsku doručovaciu službu, telekomunikačného operátora, kníhkupectvo, alebo transfúznu stanicu.

1.2. Štandardy a atribúty kvality

Medzinárodná organizácia pre štandardizáciu (ISO), ktorú rešpektuje aj Hospodárska rada OSN, prijala koncom 80. rokov rodinu štandardov ISO 9000, ktoré špecifikujú požiadavky na systémy riadenia kvality výroby (nielen softvéru). Ak spoločnosť postupuje podľa uvedených štandardov, malo by to zákazníkovi zaručiť, že jeho očakávania na kvalitu výrobku budú splnené. Spoločnosť, ktorá požadované štandardy na kvalitu výrobného procesu dodržiava, môže požiadať o vydanie certifikátu. Vtedy prebehne tzv. certifikačný audit, ktorý môže vykonať iba spoločnosť, ktorá je na tento účel akreditovaná (tento typ povolania sa ľudovo niekedy označuje "kvalitár"). Od prvej verzie bola rodina štandardov ISO 9000 štyrikrát novelizovaná, naposledy v septembri 2015 a organizácie majú tri roky, aby svoje postupy zosúladili s novými štandardami. Aplikovanie štandardov ISO 9000 na oblasť softvérového inžinierstva upravuje samostatný štandard ISO 90003.

Z hľadiska kvality softvéru ako takého (čiže nie kvality procesu vývoja, ale kvality výsledného produktu) existuje iný štandard ISO, konkrétne ISO/IEC 25010 (čo je nová verzia ISO 9126). Tento štandard definuje sadu atribútov kvality, ktoré môžeme využiť pri zbieraní a kontrole požiadaviek na systém, stanovovaní cieľov návrhu, testovaní, alebo hodnotení výsledného systému, či má požadované vlastnosti.

Pôvodný štandard rozdeľoval atribúty kvality na externé, interné a atribúty kvality pri používaní systému. Externé atribúty sú také, ktoré môžeme pozorovať "zvonku" - sú určené správaním sa systému, príkladom takéhoto atribútu je výkon - t.j. napr. ako rýchlo nám systém na dotaz zobrazí odpoveď pri zaťažení paralelnými dotazmi od rozličných používateľov.

Interné atribúty naopak vieme posúdiť až pri pohľade "dovnútra" systému - a udávajú kvalitu návrhu, zdrojového kódu, čiže napr. či je softvér flexibilný vzhľadom na zmenu požiadaviek, modulárny, obsahuje minimum závislostí a podobne.

Atribúty kvality pri používaní systému sú určené až pri reálnom nasadení systému do prevádzky a vyplývajú z konkrétnych interakcií používateľov so systémom.

Novší štandard rozlišuje len atribúty typu "Product quality" a atribúty typu "Quality in Use", sú znázornené na obrázku 1.


Obr. 1: Atribúty kvality výrobku, podľa ISO/IEC 25010.


Obr. 2: Atribúty kvality pri používaní, podľa ISO/IEC 25010.

Prečítajme si spolu tento zoznam atribútov a zamyslime sa nad tým, čo jednotlivé atribúty označujú:

A Kvalita výsledného systému

Functional suitability - či vyvinutý softvér robí všetko, čo má robiť (kompletnosť), či to robí správne (correctness) a primeraným spôsobom (appropriateness), čiže ani priveľmi nezjednodušuje ani príliš zbytočne nekomplikuje.

Reliability - celková spoľahlivosť systému, t.j. systém je odladený, bez chýb a nepadá (maturity), vždy, keď má byť k dispozícii tak k dispozícii je (availability), výpadok nejakého komponentu má minimálny vplyv na jeho prevádzkyschopnosť (fault tolerance), a ak k prerušeniu prevádzky predsa len dôjde, systém je schopný sa spamätať a uviesť do bezchybného chodu (recoverability).

Performance efficiency - využívanie zdrojov, čiže dobrá práca s časom - žiadne zbytočné čakania, prestávky a odstávky (time behavior), optimálne využitie ostatných zdrojov - pamäť, disk, procesor, papier, prenos údajov po sieti (resource utilization) a kapacita, čiže vyčísliteľné výkonnostné hranice systému ako napr. maximálny počet používateľov, maximálny počet záznamov, ktoré systém zvládne efektívne spracovať alebo evidovať, maximálny počet súčasne uskutočňovaných transakcií a podobne (capacity).

Usability - sa týka skúsenosti používateľa, ktorú pri práci so systémom získava - primeranosť (appropriatness), zrozumiteľnosť (recognisability), dobrá podpora pre rýchle naučenie sa práce so systémom - či si používateľ naň zvykne ľahko (learnability), efektívnosť ovládania - požadovanú funkcionalitu docielime jasne, prehľadne a jednoducho (operability), odolnosť voči nesprávnym vstupom alebo správaniu používateľa - systém nás upozorní pred tým ako sa nám niečo podarí poškodiť (user error protection), úhľadnosť (aesthetics), a možnosť prispôsobenia sa používateľského rozhrania handicapovaným používateľom (accessibility).

Maintainability - čiže udržiavateľnosť systému je veľmi dôležitý interný atribút kvality, hovoríme tu o modularite, čiže členení systému na nezávislé komponenty - moduly, ktoré možno do systému ľahko pridať alebo odobrať a vytvárať tak bez zložitých úprav rozličné konfigurácie pre rozličných používateľov jednoduchým zapájaním modulov do výsledného celku (modularity), možnosť využiť časti systému aj v iných systémoch (reusability), čím automaticky získavame dobre navrhnuté rozhrania medzi modulmi, minimálnosť týchto rozhraní a väčšiu nezávislosť modulov, schopnosť ľahkého náhľadu do útrob systému počas jeho činnosti - čo môže veľmi zrýchliť a zjednodušiť hľadanie poruchy, chyby alebo anomálie v systéme(analysability), jednoduchá modifikovateľnosť, možnosť úprav funkcionality (modifiability) a ľahká otestovateľnosť - čiže štruktúrovanosť aplikácie do samostatných modulov, pre ktoré máme možnosť napísať nezávislé jednotkové testy a jednoznačná a prehľadná architektúra, jasné vstupné a výstupné formáty údajov, všetko, čo nám dovolí napísať čo najspoľahlivejšie testy (testability).

Security - čiže bezpečnosť z hľadiska ochrany údajov a prístupu k nim, treba mať na pamäti, že slovenské slovo bezpečnosť môže vyjadrovať aj iný typ bezpečnosti - bezpečnosť práce/neohrozenia zdravia - vtedy hovoríme v angličtine o safety. Security zahŕňa nevyzradenie utajovaných údajov (confidentiality), zabezpečenie neporušiteľnosti údajov a komunikačných kanálov (integrity), nezapierateľnosť autora podpisu alebo autorizácie (non-repudiation), jednoznačná vyvoditeľnosť zodpovednosti za každú akciu (accountability), overiteľná nefalšovanosť informácií, autentickosť (authenticity).

Compatibility - vo svojej základnej forme predstavuje možnosť spoločného prevádzkovania rozličných systémov súčasne vedľa seba (co-existence), v rozšírenej forme sú systémy súčinné, vymieňajú si údaje, alebo aktívne zdieľajú zodpovednosť za jednotlivé úlohy, ktoré plnia (interoperability).

Portability - alebo prenositeľnosť systému na inú softvérovú alebo hardvérovú platformu: schopnosť prispôsobenia sa špecifikám tej-ktorej platformy (adaptability), možnosť prevádzky na príslušnej platforme (installability). V prípade jednotlivých komponentov systému sa prenositeľnosť vzťahuje aj na vymeniteľnosť jednotlivých komponentov aplikácie bez toho, aby to ovplyvnilo funkcionalitu - napr. výmena databázového ovládača alebo GUI knižnice (replaceability).

B Kvalita systému v prevádzke

Satisfaction - celková spokojnosť používateľa so systémom - užitočnosť (usefulness), dôveryhodnosť (trust), uspokojenie (pleasure), pohodlie (comfort).

Effectivness - jednoduchá dosiahnuteľnosť želaných cieľov pri práci s programom, systém robí správne veci, aby dosiahol želaný výsledok.

Freedom from risk - obmedzenie rizík neželaných výsledkov pri práci so systémom zahŕňa zamedzenie akcií s neželanými dopadmi na hospodárenie používateľa (economic risk mitigation), ochrana zdravia (health and safety risk mitigation), ochrana životného prostredia (environmental risk mitigation).

Efficiency - úspornosť, program dosahuje želané ciele minimalizovaním použítých zdrojov, úsporne.

Context coverage - schopnosť systému fungovať vo všetkých možných situáciách / kontextoch, ktoré boli špecifikované (context completeness) i tých, ktoré špecifikované priamo neboli (flexibility).

Atribúty kvality softvéru sa často používajú pri špecifikovaní tzv. non-functional requirements, čiže požiadaviek, ktoré sa nevzťahujú na funkcionalitu. Sú to požiadavky, ktoré sa netýkajú priamo toho ČO má vyvíjaný systém robiť, ale AKO KVALITNE to má robiť.

1.3. Štruktúra nákladov na vývoj softvéru, úspešnosť SW projektov a stakeholderi

Pre typické projekty vytvárané na zákazku platí, že celkové náklady po odovzdaní prvej kompletnej a funkčnej verzie do používania sú ešte 2-3-krát väčšie ako náklady potrebné na vývoj. Je to fáza evolúcie softvérového diela, počas ktorej je potrebná oprava zistených nedostatkov, doplnenie funkcionality podľa dodatočných požiadaviek zákazníka, udržiavanie rozličných verzií, ktoré boli nasadené do jednotlivých prevádzok.

Fáza vývoja systému po okamih jeho odovzdania si spravidla vyžiada veľmi veľkú časť nákladov na testovanie (okolo 40%).

V 90-tych rokoch a v prvej dekáde nového milénia sa uskutočnilo viacero plošných prieskumov úspešnosti softvérových projektov. Výsledky ukazujú, že približne štvrtina projektov vývoja softvéru bola celkom neúspešná. Ďalších približne 50% nedopadlo podľa očakávaní a len zhruba štvrtina projektov uspela bez výhrad. O čom tieto čísla hovoria? Dokazujú, že vývoj informačných systémov je veľmi zložitý a krehký proces, účastníci kontraktov a ani vývojári nemajú realistické očakávania, neexistujú spoľahlivé postupy práce, chýbajú skúsenosti s odhadovaním rozsahu prác, manažéri nevedia nastaviť vhodné pravidlá práce na projektoch a pružne reagovať na vznikajúce ťažkosti počas vývoja a komunikácia medzi všetkými zainteresovanými účastníkmi je nedostatočná a zlá.

Termín stakeholder pochádza z anglického "stake" - čo v základnom význame označuje najaký stĺp ale v prenesenom nejaký podiel (predstavme si skupinu ľudí, každý drží jeden stĺp, na ktorom spočíva nejaká rozsiahlejšia stavba - povedzme most, každý z nich má svoj podiel na tom, že stavba drží - a pochopiteľne tým pádom má do celej stavby čo rozprávať a prípadne chce mať svoj podiel na vyberanom mýte od každého, kto prejde po moste).
Stake je teda určitý podiel a stakeholder je držiteľ nejakého podielu. V kontexte vývoja informačných systémov je stakeholderom každý, kto akýmkoľvek spôsobom zasahuje do vývoja alebo ho ovplyvňuje. Medzi hlavných stakeholderov patria:
iné typické roly sú:

1.4. Fázy vývoja informačného systému

Vývoj každého systému je iný a má svoje špecifiká, napriek tomu v každom z nich môžeme identifikovať činnosti podobného charakteru, ktoré sa vykonávajú viac-menej v nasledujúcom poradí:
  1. Špecifikácia požiadaviek: jej cieľom je vytvorenie uceleného dokumentu označovaného ako Requirements Document, alebo Katalóg požiadaviek (niekedy Špecifikácia požiadaviek), ktorý obsahuje zoznam jednotlivých požiadaviek zadávateľa na funkcionalitu i výslednú kvalitu vyvíjaného softvéru. Špecifikácia by mala byť písomnou dohodou medzi zadávateľom a riešiteľom, ktorá je pre obe strany záväzná. Špecifikácia odpovedá na základnú otázku "ČO má systém robiť?"

  2. Návrh systému: v tejto fáze vývojári zanalyzujú zozbierané požiadavky, vyberú vhodné technológie, navrhnú architektúru systému, rozdelenie na moduly, ich vzájomné rozhrania, rozhrania aplikácie navonok vrátane používateľského rozhrania, perzistentnú vrstvu - dátový model databázy a formáty súborov, komunikačné protokoly, pripravia si testovacie scenáre pre validačné a akceptačné testy, podrobne navrhnú vnútornú štruktúru komponentov, modelujú správanie a interakciu častí systému. Výsledkom by v ideálnom prípade mal byť dokument s názvom Software Design Description, alebo jednoducho Návrh systému. Dokument by mal obsahovať podrobný návod pre vývojárov, ako majú systém vyvinúť, pričom by mal byť natoľko dôsledný a podrobný, aby dve nezávislé vývojárske skupiny, ktoré podľa návrhu budú postupovať, vyvinuli softvér s ekvivalentnou funkcionalitou a vlastnosťami. V praxi sa stretávame aj s tým, že skupina vývojárov, ktorá vypracuje návrh, je iná ako tá, ktorá systém implementuje. V iných spoločnostiach, ktoré postupujú pri vývoji softvéru viac živelne, často návrh ako taký nevzniká a tím sa snaží držať krok len s dokumentom popisujúcim špecifikáciu. To je možné iba v menších tímoch a na menších projektoch. Návrh odpovedá na základnú otázku "AKO sa bude systém implementovať?"

  3. Implementácia: vytvára sa zdrojový kód jednotlivých modulov podľa návrhu. Jednotlivé elementy sa hneď testujú jednotkovými testami. Do zdrojového kódu sa píšu dokumentačné komentáre.

  4. Verifikácia a validácia: overenie, že systém spĺňa špecifikované požiadavky (verifikácia) a že spĺňa očakávania používateľa (validácia). Túto kontrolu vývojári musia vykonávať v celom procese vývoja, avšak najviac prostriedkov sa na ňu vynakladá po implementácii.

  5. Evolúcia: nastáva po odovzdaní prvej plne funkčnej verzie systému. Systém sa opravuje a upravuje podľa dodatočných požiadaviek alebo zistení zadávateľa a používateľov. Nastáva pri každom vývoji informačného systému a väčšinou pohltí veľké množstvo nákladov, s ktorými treba vopred počítať.

1.5. Priebežné procesy pri vývoji IS

Počas všetkých fáz vývoja informačného systému prebiehajú viaceré procesy, ktorým musí byť venovaná potrebná pozornosť. Ide predovšetkým o:

Odhadovanie - čiže stanovovanie nákladov, rozsahu prác a potrebných zdrojov - personálnych i materiálnych.

Plánovanie - čiže rozdeľovanie úloh, práce a zdrojov do časových harmonogramov, určovanie míľnikov, stanovovanie postupností a nadväzností úloh a ich vzájomnej nezávislosti, aktualizovanie plánu podľa dosiahnutých priebežných výsledkov.

Organizácia práce - vytváranie a aktualizovanie pracovného kolektívu, rozdeľovanie úloh a kontrola ich plnenia, organizovanie pracovných stretnutí, stanovovanie zodpovednosti, určovanie toku vstupov, výstupov, dokumentov a spolupráce tímov a jednotlivcov. Vhodné motivovanie pracovníkov - finančné i iné, zlepšovanie a utužovanie vzťahov na pracovisku.

Na tieto činnosti sa bežne používa softvér na organizáciu práce, ktorý je často previazaný s celým informačným systémom organizácie, systémom na zdieľanie dokumentov. Príkladom softvéru na správu projektu môže byť komerčná sada nástrojov Oracle Primavera, alebo open-source systém OpenProject.

Typickým nástrojom je Ganttov diagram, zobrazujúci grafické rozloženie naplánovaných úloh v čase, ich členenie na podúlohy, závislosť ich následnosti, množstvo už splnenej práce. Na x-ovej osi je čas z hľadiska dní/týždňov/mesiacov, riadky na y-ovej osi zodpovedajú jednotlivým riešeným úlohám, väčšinou tiež zoradeným chronologicky, čo ale nie je podmienkou a niekedy ani nie je možné. Vyplnené obdĺžniky znázorňujú plánované trvanie úlohy v čase.


Obr. 3. Príklad Ganttovho diagramu.

Každý skutočný softvérový projekt má dokumenty i zdrojové súbory uložené v centrálnom repozitári. Vývojári majú z repozitára "vytiahnuté" lokálne kópie súborov, na ktorých pracujú. Po dokončení ucelenej časti úprav novú verziu posielajú naspäť do repozitára. V niektorých projektoch každá zmena podlieha schváleniu zodpovedným pracovníkom - v prípade zdrojových kódov musí prejsť kontrolou, tzv. code review, kde sa stráži čistota kódu, použitie dohodnutých štandardov i správna sémantika programov. Do repozitára sa nikdy neposielajú programy, ktoré sú syntakticky nesprávne a ani sa nedajú skompilovať.

Každý absolvent nášho predmetu musí ovládať prácu aspoň s jedným konkrétnym systémom na správu zdrojových súborov, napr. Subversion (svn), Git, resp. GitHub, alebo komerčným nástrojom Microsoft Team Foundation Server (tfs).

Atribútom kvality softvéru sme sa už venovali vyššie a na ich dosiahnutie je potrebné, aby bol kvalitný aj samotný proces vývoja, je predpokladom výslednej kvality vyvinutého systému. Preto nezanedbateľným priebežným procesom je aj neustále zabezpečovanie kvality práce. Sem patrí aj príprava štandardných postupov a procedúr, checklistov, štruktúry a obsahu vypracovávaných dokumentov, kontrola a meranie efektívnosti kvality práce.

1.6. Modely vývoja IS

Pri tak náročnom procese ako je vývoj informačného systému je potrebné postupovať podľa nejakého rámca, podľa ktorého sa organizuje celá práca. Hovoríme o rozličných modeloch vývoja informačných systémov. Modely stanovujú pravidlá, postupy, pracovnú terminológiu, formu dokumentácie, nadväznosť fáz, vstupy a výstupy fáz, druhy pracovných schôdzí, zjednodušujú plánovanie a riadenie vývoja, pomáhajú vývojárom lepšie sa zorientovať vo svojich zodpovednostiach a skontrolovať, že ich výstupy sú v súlade s očakávaniami ostatných členov vývojového tímu.

Medzi základné všeobecné modely vývoja IS patria nasledujúce: vodopádový model, evolučný model, inkrementálny model, vývoj s opakovaným použitím komponentov, vývoj formálnymi metódami, špirálový model, Unified process a Rational Unified Process, agilné metódy a open source. Pri každom z nich sa pozastavíme a uvedieme ich výhody a nevýhody.

Jednotlivé modely môže skúmať z hľadiska toho, či členovia vývojových tímov v každom okamihu rozumejú, čo majú robiť a prečo (pochopiteľnosť) a aktuálny stav celého procesu a úlohy na ktorých všetci pracujú sú známe (viditeľnosť), či je postup na jednotlivých etapách rýchly a svižný, alebo prácne zdĺhavý (rýchlosť), nakoľko je daný model podporovaný automatizovanými prostriedkami - napr. nástrojmi CASE (Computer-Aided Software Engineering).

1.6.1. Vodopádový model

Ide o najstarší model vývoja, ktorý je inšpirovaný ostatnými inžinierskymi disciplínami. Vychádza z postupnosti realizovaných etáp, pričom vyžaduje, aby každá etapa bola celkom ukončená vrátane dokumentácie pred začatím nasledujúcej etapy. Dôraz je preto kladený na dôkladné vypracovanie a zdokumentovanie každej etapy, aby sa predišlo potrebe znovu otvárať predchádzajúce etapy po ich ukončení. V praxi sa tomu ale dá iba zriedka kedy podarí celkom vyhnúť.


Obr. 4: Vodopádový model vývoja IS.

Výhodou vodopádových modelov je ľahšie udržovanie a kontrolovanie pracovnej disciplíny, dobrá zdokumentovanosť všetkých činností, dobrá viditeľnosť a najmä možnosť zvoliť optimálnu architektúru, prostriedky, technológie a naplánovať celý proces vývoja, keďže všetky požiadavky sú známe pred začatím fáz návrhu i implementácie.

Potreba špecifikovať všetky požiadavky na začiatku je zároveň aj hlavnou nevýhodou, existuje isté riziko určenia nesprávnych požiadaviek a najmä, zadávateľ si na začiatku vývoja často nedokáže predstaviť, čo všetko bude od systému vyžadovať. Návrat k predchádzajúcim etapám je náročný, keďže každá spätná zmena má dopad na všetky nasledujúce fázy, ktoré treba reštartovať. Pri zlyhaní plánu pri vodopádovom modeli vývoja nie je k dispozícii žiadna predbežná verzia a buď sa pokračuje, až kým systém nie je celý hotový, alebo sa vývoj musí ukončiť bez výsledku ("všetko alebo nič"). Vodopádový model je možné používať iba vtedy, ak sú požiadavky na systém vopred dostatočne jasné.

1.6.2. Evolučný model

Pri evolučnom vývoji sa systém vyvíja po častiach, pričom každá nová verzia sa špecifikuje, vyvíja a následne testuje, čím postupne vznikajú jednotlivé verzie systému, ktoré už sú prevádzkovateľné, hoci neobsahujú celú funkcionalitu. Vychádza sa iba z hrubého všeobecného opisu cieľovej aplikácie.


Obr. 5: Evolučný model vývoja IS.

Veľkou výhodou evolučného vývoja je, že sa špecifikácia vytvára postupne a skúsenosti používateľov z prevádzky predchádzajúcej verzie sa využijú pri špecifikovaní nasledujúcich verzií. V prípade, že sa minú zdroje (čas, peniaze), je možné nasadiť poslednú funkčnú verziu a projekt nezlyhal celkom. Zákazník má prvú fungujúcu verziu k dispozícii oveľa skôr a môže ju hneď začať používať. Nevýhodou je, že model nevyžaduje dostatočnú disciplínu pri vytváraní dokumentácie a preto je málo viditeľný. Keďže požiadavky nie sú vopred známe, štruktúra systému a jeho architektúra často nie je optimálna, neustále zmeny vedú k vyššej pravdepodobnosti vzniku chýb. Tento model vývoja nezodpovedá typickému modelu kontraktov / objednávok, kde sa väčšinou dohodne čo treba dodať, koľko to bude stáť, ako dlho to bude trvať a systém sa realizuje a dodá. V tomto prípade je potrebné neustále vyjednávať a dohadovať dodatky, čo je náročnejšie na manažovanie, keďže ku každému z nich by sa správne mali vyjadriť všetci stakeholderi, k čomu často nedochádza, alebo sa tomu nevenuje dostatočná pozornosť a to vedie k neskorším problémom. Model je vhodný najmä na systémy u ktorých sa neočakáva dlhodobá prevádzka a sú menšieho alebo stredného rozsahu. Veľkosť projektu sa niekedy vyjadruje v tisíckach riadkov kódu (KLOC), čo má výpovednú porovnávaciu hodnotu najmä pri použití štandardných programovacích jazykov typu C++ alebo Java a dodržiavaní zásad čistého kódu.

1.6.3. Inkrementálny model

Je kombináciou vodopádového a evolučného modelu vývoja. Podobne ako v evolučnom modeli prebieha vývoj po relatívne malých prídavkoch, inkrementoch. Odlišuje sa od neho väčším dôrazom na dokumentáciu, viditeľnosť, disciplínu a manažovateľnosť procesov. Pred začiatkom vývoja prebehne zozbieranie hrubých požiadaviek na celý system a naplánovanie vývoja na jednotlivé inkrementy. Na základe toho sa navrhne architektúra celého systému. Počas vývoja sa postupne navrhujú, implementujú a testujú vznikajúce verzie, pričom jednotlivé inkrementy môžu byť vyvíjané odlišnými postupmi - nevyžaduje sa jednotný prístup počas celého vývoja, ak si to okolnosti vyžadujú.


Obr. 6: Inkrementálny model vývoja IS.

Má rovnaké výhody ako evolučný model, ale čiastočne sa zbavuje nevýhody nízkej viditeľnosti, neoptimálnej architektúry a náročnej manažovateľnosti.

1.6.4. Vývoj s opakovaným použitím komponentov

V tomto prípade nemožno ani tak hovoriť o samostatnom modeli, ktorý pokrýva celý proces vývoja, ako skôr o jeden aspekt, ktorý sa väčšinou kombinuje s iným modelom. Cieľom je maximalizovať úsporu času a prostriedkov pri vývoji viacerých informačných systémov, ktoré majú spoločné prvky, vyčleniteľné do samostatných univerzálnych, alebo ľahko prispôsobiteľných komponentov. Znovupoužitie komponentov si vyžaduje určitú flexibilitu vývojového procesu už pri špecifikácii - nakoľko systém sa špecifikuje s východiskom existujúcich znovupoužiteľných komponentov, pričom sa dosahuje kompromis medzi ideálnou funkcionalitou a vlastnosťami systému na jednej strane a reálnymi možnosťami, ktoré sa dajú dosiahnuť využitím existujúcich komponentov. Ďalšou výhodou popri úsporách je otestovanie zdieľaných komponentov vo viacerých rozličných situáciách, čo môže viesť k robustnejšiemu a modulárnejšiemu návrhu a odladeniu chýb, ktoré by ostali skryté a objavili sa neskôr počas prevádzky. Nevýhodou popri nutných kompromisoch je čiastočná strata kontroly nad budúcim vývojom a podporou produktu, keďže znovupoužité komponenty "žijú" vo viacerých systémoch, na ktoré sa môžu v budúcnosti vzťahovať odlišné požiadavky.


Obr. 7: Vývoj s opakovaným použitím komponentov.

1.6.5. Vývoj formálnymi metódami

Podobne ako predchádzajúci model ani tento nie je samostatným a kompletným scenárom na proces vývoja informačného systému, ale akási "prísada", ktorá sa väčšinou kombinuje s iným modelom. Motiváciou je vyvinúť systém, o ktorého vlastnostiach sa dá formálne niečo tvrdiť - napr. že výpočet zaručene skončí v stanovenom čase, alebo vždy vykoná správnu akciu požadovanú v špecifikácii, alebo nikdy nedôjde k zablokovaniu paralelne vykonávaných výpočtových vlákien. Je teda vhodný najmä pre vývoj systémov (alebo ich častí) s veľkými nárokmi na spoľahlivosť, bezpečnosť, presnosť. Pri vývoji sa vytvorí klasická špecifikácia, ktorá sa formalizuje do zvoleného formalizmu. K formalizmom existujú simulátory, analyzátory a softvérové knižnice, rozširujúce klasické programovacie jazyky o nové prvky určené na formálne usudzovanie o činnosti programu, ktoré je často založené na nejakej verzii predikátovej logiky.




Obr. 8: príklad postupu pri vývoji systému formálnymi metódami: z pôvodnej formálnej špecifikácie sa dôkazmi (Px) získavajú verzie R1, R2, ..., až pokiaľ výsledok nie je priamo spustiteľný program. Metóda vychádza z myšlienky, že dokázať správnosť jednotlivých transformácií je jednoduchšie, ako priamo dokazovať správnosť výsledného programu.

1.6.6. Špirálový model

Ide o špecifický model zameriavajúci sa predovšetkým na určenie rizík a ich priorít. Metodológovia si uvedomovali množstvo informačných systémov, ktoré boli neúspešné a preto sa do centra pozornosti dostáva nepretržitá práca s rizikami vývoja a neustála prioritizácia aktivít podľa rizík vývoja. Podľa toho, ktoré riziká sú v tom-ktorom projekte dôležitejšie, získame aplikovaním špirálového modelu nejaký konkrétny model vývoja, ktorý môže byť napr. vodopádový, evolučný, alebo inkrementálny. Pri vývoji špirálovým modelom sa postupuje cyklicky po špirále a opakujú sa štyri základné činnosti: 1. Zadefinovanie cieľov vyžadovaných stakeholdermi, od ktorých závisí úspešnosť projektu 2. Nájdenie a vyhodnotenie rozličných prístupov k dosiahnutiu týchto cieľov 3. Určenie a eliminovanie rizík, ktoré plynú zo zvoleného prístupu alebo skupiny prístupov 4. Získanie súhlasu všetkých stakeholderov, na ktorých závisí úspešnosť projektu a realizácia nasledujúceho cyklu. Dôraz je teda na to, aby sa predišlo nevhodným špirálam vo vývoji, kde by sa prirýchlo začalo s návrhom a implementáciou systému, pričom by sa zanedbali niektoré dôležité aspekty - podcenili riziká.


Obr. 9: špirálový model vývoja informačných systémov.

1.6.7. Unified Process a Rational Unified Process

V 90-tych rokoch v softvérovom inžinierstve dominovali rozličné metódy objektovo-orientovaného softvérového návrhu, ktoré kládli dôraz na mierne odlišné aspekty, používali čiastočne sa líšiace diagramy a postupy. Zároveň vznikala prvá verzia unifikovaného modelovacieho jazyka UML. Prvky z pôvodne samostatných metód - Boochova metóda, Rumbaughove OMT, Objectory (z prostredia spoločnosti Ericsson) - ktoré sa pripojilo k spoločnosti Rational Software a dlhou históriou nástrojov na podporu vývoja softvéru i autori týchto metód sa zlúčili pod krídlami spoločnosti IBM v úsilí o vytvorenie jednotného, flexibilného a podrobného frameworku na tvorbu informačných systémov. Výsledkom je Unified Process, ktorý je ďalej podrobnejšie špecializovaný v metóde Rational Unified Process (a niekoľkých ďalších, napr. Agile Unified Process alebo Oracle Unified Method). Prístup by sa dal charakterizovať ako 1) Use-Case driven, čiže tvorba systému vychádza z používateľských scenárov, ktoré sú základom pre špecifikáciu, analýzu a návrh, 2) Architecture-centric, čiže úvodné iterácie vývoja sa sústreďujú na vytvorenie architektúry - spustiteľného jadra systému na ktorom sa stavia a 3) Iterative and incremental, čiže vývoj pozostáva z jednotlivých malých iteračných cyklov vývoja, pričom v priebehu vývoja sa množstvo práce venovanej jednotlivým aktivitám priebežne mení. Podobne ako v špirálovom modeli je veľký dôraz na určenie rizík hneď od začiatku vývoja. Celkový životný cyklus vývoja Unified Process pozostáva zo štyroch fáz: Inception (rozbeh), Elaboration (rozpracovanie), Construction (budovanie), Transition (odovzdanie). Činnosť na vývoji je rozdelená do deviatich disciplín: šesť inžinierskych: Business Modeling (modelovanie existujúcich procesov a vzťahov v cieľovej doméne informačného systému a hľadanie potenciálnych zlepšení), Requirements (zbieranie, formulovanie, analyzovanie požiadaviek), Analysis and Design (analýza hotových požiadaviek, návrh systému), Implementation (tvorba kódu podľa návrhu), Test (verifikácia a validácia hotového kódu vzhľadom na návrh, špecifikáciu, a používateľov), Deployment (nasadenie systému do prevádzky) a tri podporné disciplíny: Configuration and change management (správa verzií a zmien), Project management (riadenie projektu), Environment (zabezpečenie vhodných nástrojov a celkového prostredia pre vývojárov).


Obr. 10: Rational Unified Process

Jednotlivé fázy su rozdelené do niekoľkých (spravidla 3-týždňových) iterácií. Každá z fáz má stanovené ciele, ktoré sa počas nej vývojári usilujú dosiahnuť, ako vidno na nasledujúcom obrázku.


Obr. 11: Ciele jednotlivých fáz vo vývojovom modeli Unified Process

Výhodou UP a RUP je dôkladná a podrobná rozpracovanosť, vysoká flexibilita a dôraz na úspešné nasadenie projektu zameraním sa na riziká. Nevýhodou sú vysoké náklady na manažment a celková komplexnosť.

1.6.8. Open-source

Jedna z najúspešnejších softvérových spoločností - Microsoft Corporation počas desaťročí používala uzatvorený spôsob vývoja, kde k zdrojovým kódom systému mali prístup len vývojári. Podstatný dôvod je ochrana vlastníctva a práv, aby si spoločnosť udržiavala svoje interné know-how a konkurenčnú výhodu oproti ostatným spoločnostiam na trhu. Táto stratégia sa ukázala byť ako pomerne úspešná, keďže na poli operačných systémov pre stolné počítače, kancelárskych softvérových balíkov, i vývojových nástrojov si firma udržala po desaťročia vedúcu pozíciu na trhu. Na druhej strane vidíme úspešný príbeh operačného systému Linux, ktorého prvú verziu napísal jeden nadšenec, zverejnil svoj zdrojový kód a otvoril systém pre vývojárov z celého sveta, ktorí do ďalších verzií systému prispievali pridávaním nových a vylepšovaním existujúcich nástrojov, aplikačného softvéru, rôznych verzií používateľského rozhrania a pod. Vznikla tak obrovská komunita vývojárov distribuovaných po celom svete, ktorí venujú svoj čas a úsilie - niekedy zadarmo, niekedy za odmenu sponzorovanú spoločnosťami, ktoré v systéme vidia potenciál - vývoju otvorených systémov. Prístup open-source umožňuje dosahovať vyššiu stabilitu a bezchybnosť, keďže všetci používatelia a vývojári môžu v prípade nedostatkov hľadať a opravovať chyby priamo v zdrojových kódoch, urýchľuje pokrok informačných technológií vôbec - keďže informácie a technológie sú dostupnejšie a uľahčuje znovupoužiteľnosť komponentov a častí kódu vôbec. Napomáha prenositeľnosti programov na rôzne platformy, keďže portovania pre každú platformu sa môže zhostiť iný tím. Tieto prednosti otvorenej platformy zrejme nakoniec pochopila aj firma Microsoft, keď relatívne nedávno ohlásila, že jej populárna vývojová platforma .NET, ktorej súčasťou je jazyk C# prejde do režimu open-source.

2. Tvorba katalógu požiadaviek (Requirements Specification)

Prvou veľkou a najdôležitejšou fázou vývoja informačného systému je tvorba katalógu požiadaviek (Requirements Document), ktorý podrobne určuje, čo má produkt robiť na základe požiadaviek zadávateľa.

Výsledný katalóg požiadaviek musí byť napísaný jazykom, ktorý je zrozumiteľný. Jednak má byť zrozumiteľný pre vývojový tím: nemôže sa spoliehať na odbornú terminológiu a poznatky z domény informačného systému bez toho, aby boli vysvetlené. Po druhé musí byť zrozumiteľný aj pre zadávateľa: čiže nemôže obsahovať nevysvetlenú terminológiu a poznatky ani z oblasti softvérového inžinierstva. Katalóg požiadaviek má byť čitateľný a zrozumiteľný pre všetkých stakeholderov, ktorí s ním musia byť podrobne zoznámení a zadávateľ ho musí schváliť. Medzi nich teda patria: zadávateľ - kontroluje, či spísané požiadavky spĺňajú všetky potreby, ktoré na systém majú; manažéri vývojového tímu - využívajú ho pri plánovaní a riadení procesu vývoja; designéri - podľa katalógu požiadaviek vytvárajú návrh systému; vývojári - postupujú podľa návrhu, ale ten sa odkazuje na katalóg požiadaviek, ktorý im pomáha pochopiť systém, ktorý vyvíjajú; tvorcovia testov - podľa katalógu požiadaviek vytvárajú validačné testy; správcovia výsledného systému - katalóg požiadaviek formuluje požiadavky aj na údržbu systému po jeho dodaní. Výsledný dokument je záväzný pre obe strany a systém sa podľa neho ďalej navrhuje, implementuje a testuje. Hlavným účelom katalógu požiadaviek je poskytnúť zoznam jednotlivých nedeliteľných požiadaviek, ktoré sú jednoznačné a zrozumiteľné. Zoznam má byť vzhľadom na cieľovú funkcionalitu kompletný a konzistentný. Mal by byť tématicky členený do jednotlivých častí. Samostatnú časť tvoria tzv. non-functional requirements, čiže "ostatné požiadavky", ktoré určujú požiadavky nevzťahujúce sa na funkcionalitu. Predpisujú napr. kvalitu a vlastnosti systému - zväčša vyjadrené formou atribútov kvality informačného systému, ktoré sú vysvetlené v predchádzajúcej kapitole.


Obr. 12: Rôzne druhy ostatných požiadaviek (non-functional requirements).

2.1. Štruktúra dokumentu katalógu požiadaviek

Pre väčšiu zrozumiteľnosť sa zaužívala štandardizovaná štruktúra katalógu požiadaviek - jeho členenie na kapitoly. Tvorbu katalógu požiadaviek popisuje viacero medzinárodných štandardov. V roku 1993 vznikla prvá verzia štandardu 830, ktorý bol aktualizovaný v roku 1998. Po dlhšej prestávke bol v roku 2011 vydaný nový štandard IEEE/ISO/IEC 29148. V prvých dvoch štandardoch (v ktorých vychádzame aj v našom tímovom projekte) je dokument členený na nasledujúce kapitoly - pričom každý projekt si presnú štruktúru podkapitol upraví podľa potreby, ide len o odporúčanú štruktúru:

1. Introduction
1.1 Purpose of requirements document
1.2 Scope of the product
1.3 Definitions, acronyms and abbreviations
1.4 References
1.5 Overview of the remainder of the document
2. General description
2.1 Product perspective
2.2 Product functions
2.3 User characteristics
2.4 General constraints
2.5 Assumptions and dependencies
3. Specific requirements: Covering functional, non-functional and interface requirements
4. Appendices
Index

Ako každý iný "slušný" dokument má katalóg požiadaviek v úvode v stati 1.1 napísané načo je dokument určený a pre koho je určený. Aby čitateľ dokumentu vedel, čo práve drží v ruke - hoci má nejakú predstavu, vždy je dobré, ak mu to autori pripomenú a jasne zadefinujú.

V stati 1.2. je opísaný rozsah systému: čo ešte patrí do systému, ktorý sa bude vyvíjať a čo už je za hranicami jeho pôsobnosti, čo všetko - v hrubých rysoch pokrýva jeho funkcionalita?

Stať 1.3. je slovník pojmov. Nezavádzame ju "na silu" len preto, aby bola, ale treba si uvedomiť, že dokument budú čítať aj ľudia, ktorí nevedia o doméne do ktorej sa ide informačný systém nasadiť skoro nič a podobne ľudia, ktorí majú len veľmi hmlistú predstavu o tvorbe informačných systémov. Preto kedykoľvek v texte použijeme nejaký pojem, ktorý nemusí byť automaticky zrejmý všetkým čitateľom, pridáme ho do slovníka pojmov a vysvetlíme ho tam. Naopak, neuvádzame tu zbytočne prehľad terminológie, ktorú nepoužívame alebo nie je pre informačný systém podstatná.

V stati 1.4. sa odkazujeme na všetky externé informácie, dokumenty, zákony, nariadenia, interné predpisy, technologické postupy, manuály, dátové súbory, ktoré dal zadávateľ k dispozícii, zaužívané postupy a pod. Všetko, čo nejakým spôsobom ovplyvňuje vznikajúci informačný systém a existovalo pred tým, ako začala práca na vývoji.

Záver úvodnej kapitoly každého odborného dokumentu (tu stať 1.5) spravidla obsahuje stručný komentovaný prehľad nasledujúcich kapitol, aby sa čitateľ vedel v celom dokumente zorientovať a rýchlo sa zamerať na to, čo práve hľadá alebo sa ho týka.

Celá druhá kapitola (General description) je popis plánovaného systému prirodzeným jazykom, plynulými vetami bez toho, aby sme išli do veľkých podrobností. Stať 2.1 zasadzuje systém do kontextu, díva sa na neho z nadhľadu (perspektívy). Stať 2.2 by mala obsahovať stručný opis celej funkcionality - tak, aby čitateľ z neho získal kompletnú predstavu, čo všetko systém bude robiť. Stať 2.3 má definovať používateľské role, čiže typy používateľov, ktorí so systémom budú interagovať. Všeobecné obmedzenia v stati 2.4. určujú ktoré predpisy a existujúca prax a akým spôsobom majú vecný vplyv na plánovaný systém. Predpoklady a závislosti - stať 2.5. stanovuje konkrétne rozhrania systému s jeho okolím a ich vlastnosti.

Najdôležitejšou kapitolou dokumentu je tretia kapitola, ktorá obsahuje kompletný zoznam všetkých požiadaviek na systém. Každá požiadavka musí mať svoje označenie (číslo alebo nejaký iný identifikátor), aby sa na ňu dalo odkazovať z ostatných dokumentov - najmä z návrhu a testovacích scenárov a krátky popis, typicky v rozsahu 1-3 viet. V tretej kapitole je teda znovu vymenované všetko čo systém bude robiť, požiadavky sa môžu odkazovať na pojmy, dokumenty a informácie uvedené v predchádzajúcich kapitolách katalógu požiadaviek.

Pri využití tohto štandardu narážame na dilemu, ak zadávateľ sám nevie sformulovať svoju ucelenú predstavu a viaceré otázky ostanú nezodpovedané. Vývojári majú na výber: buď ich katalóg požiadaviek bude odpovedať aj na tieto otázky, alebo zachytí len presne tie požiadavky, ktoré zadávateľ požadoval. V druhom prípade ale treba vytvoriť ďalší dokument, ktorý plní úlohu kompletného katalógu požiadaviek. Svojvoľným výberom z alternatív v prípade vynechania dôležitých odpovedí bez toho, aby sme ich skonfrontovali so zadávateľom, by ľahko mohla nastať situácia, keď by zadávateľ s dodaným výsledkom nebol spokojný. Úlohou vývojárov, ktorí pripravujú špecifikáciu, je sformulovať aj tie požiadavky na systém, ktoré zadávateľ zamlčal a skonfrontovať s ním výslednú verziu špecifikácie. V tomto kontexte je užitočné rozlišovať medzi: zámermi a cieľmi zadávateľa a jeho konkrétnymi požiadavkami. Zatiaľ čo zámery a ciele len odpovedajú na otázku "Prečo má informačný systém vzniknúť?", konkrétne požiadavky odpovedajú na otázky "Čo presne má systém robiť?". V niektorých informačných systémoch zadávatelia nevedia určiť žiadne požiadavky, iba stanoviť svoje zámery a ciele.

Novší štandard 29148 z roku 2011 odpovedá ná tieto otázky a požiadavky rozdeľuje do 3 kategórií, pričom môžu vzniknúť tri samostatné dokumenty:
  1. Stakeholder requirements specification (StRS)
  2. System requirements specification (SyRS)
  3. Software requirements specification (SRS)
Prvý zachytáva želania používateľov, ktoré dokážu sami sformulovať (user requirements). Druhá iterácia vychádza z prvej, ale už požidavky rozdeľuje na "Functional requirements" a pridáva množstvo kategórií pre non-functional requirements, pre zorientovanie sa uvedieme aspoň ich zoznam: Performance requirements, System interfaces, Human system integration requirements, Maintainability, Reliability, System modes and states, Physical requirements, Adaptability requirements, Environmental conditions, System security, Information management, Policies and regulations, System life cycle sustainment, Packaging, handling, shipping and transportation. Tretia iterácia už podrobne popisuje všetky konkrétne požiadavky na takej podrobnej úrovni, aká je potrebná, aby bolo na základe tejto špecifikácie možné vypracovať jednoznačný návrh systému.

Rozdelenie na tri časti je pekne znázornené na nasledujúcom obrázku, kde vidíme, že zámery a ciele zadávateľa sa nachádzajú v priestore "problému". Samotný popis čŕt systému a presných detailných požiadaviek na softvér už patria do priestoru "riešenia", ktoré na základe potrieb navrhuje a predkladá vývojový tím.


Obr. 13: Problem space vs. solution space

2.2. Fázy procesu tvorby špecifikácie požiadaviek

Povedali sme si čo je predmetom fázy špecifikácie, aká je štruktúra výsledného dokumentu a konečne sa môžeme zamerať na proces špecifikácie podrobnejšie. Robíme to preto, že fáza špecifikácie je najdôležitejšou fázou celého vývoja informačného systému, nesmie sa podceniť a treba jej venovať dostatočnú pozornosť a úsilie. Na všetky chyby, ktoré sa v tejto fáze urobia, neskôr vývojový tím veľmi draho doplatí.

Hlavným problémom pri tvorbe špecifikácie je, že vývojári nie sú expertmi v oblasti, pre ktorú systém implementujú (v cieľovej doméne informačného systému) a zadávateľ si nevie predstaviť, ako bude výsledný systém vyzerať, nepozná technické možnosti a schopnosti vývojového tímu. Tento problém je fundamentálnou prekážkou toho, aby vznikol systém, ktorý optimálne rieši potrebu zadávateľa a výsledok je vždy "zlý" a neoptimálny. Nanajvýš je možné usilovať sa o čo najväčšie priblíženie sa optimálnemu riešeniu a dosiahnuť sa to dá iba dobrou, intenzívnou a efektívnou komunikáciou medzi zadávateľom a vývojovým tímom.

Vytváranie špecifikácie (Requirements Engineering) má nasledujúce fázy:
  1. Requirements elicitation, čiže zbieranie požiadaviek
  2. Requirements analysis and negotiation, analýza a vyjednávanie
  3. Requirements documentation, zapisovanie výslednej podoby
  4. Requirements validation, kontrola a schvaľovanie

Obr. 14: Fázy tvorby špecifikácie požiadaviek

Podobne ako pri celom vývoji informačného systému, aj tu treba postupovať iteratívne. Zozbieranie požiadaviek sa takmer nikdy nepodarí počas jedného stretnutia so zadávateľom. Množstvo informácií je obrovské, je nutné sa v ňom zorientovať, informácie usporiadať, nájsť priority, hierarchiu a súvislosti. Tento iteratívny proces vystihuje špirálový model procesu tvorby požiadaviek na nasledujúcom obrázku:


Obr. 15: Špirálový model tvorby požiadaviek

Pri tvorbe požiadaviek narážame na množstvo problémov:

2.2.1 Fáza zbierania požiadaviek

Proces zbierania požiadaviek je schématicky zachytený na nasledujúcom obrázku.


Obr. 16: Špecifikácia: fáza zbierania požiadaviek.

Základným predpokladom pre dobrú komunikáciu je vybudovanie dôvery medzi zadávateľom a vývojovým tímom. Zadávateľ, ktorý tímu dostatočne nedôveruje nebude schopný formulovať požiadavky zrozumiteľne a bez predsudkov. Dosiahnutie tejto dôvery nie je jednoduchý proces, ale je nutnou podmienkou úspešnosti projektu.

Najskôr je potrebné identifikovať ciele zadávateľa, vrátane jeho podnikateľského zámeru a sformulovať hrubý opis problému, ktorý má informačný systém riešiť, v rámci akých existujúcich obmedzení.

Pred samotným zbieraním požiadaviek je potrebné získať čo najviac informácií o pozadí informačného systému do ktorého sa bude nasadzovať, oblasti - doméne ktorú bude riešiť (napríklad ak riešime informačný systém pre hasičov, tak treba zistiť čo najviac informácií o tom, ako hasiči pracujú) a o systémoch, ktoré sa v organizácii už používajú

Informácie, ktoré sme v predchádzajúcom kroku získali potrebujeme spracovať a zorganizovať.

Napokon sa zameriame na zbieranie konkrétnych požiadaviek od všetkých zainteresovaných stakeholderov.

Komunikácia so stakeholdermi prebieha formou rozhovorov (interviews). Základné druhy interviews sú:

zatvorené (closed interview) - keď vývojári majú vopred sformulované otázky, na ktoré potrebujú poznať odpovede otvorené (open interview) - keď dopredu nie je stanovená presná agenda a diskusia o systéme prebieha voľným spôsobom s otvoreným koncom.

Rozhovory sú úspešné, ak ich účastníci majú schopnosť nie len rozprávať, ale najmä počúvať. Je potrebné pružne reagovať na myšlienkové pochody druhej strany a vyjadrovať sa a formulovať vety presne a jednoznačne. Aj v prípade otvorených interviews je stakeholderom vhodné dať oporný bod, z ktorého sa môžu o potrebách na systém rozhovoriť.

Vhodným nástrojom pri zbieraní požiadaviek sú používateľské scenáre. Sú to príbehy, ktoré opisujú príklady interakcie používateľa so systémom - ako by mohol byť systém používaný. Mali by obsahovať: Analyzovaním zapísaných scenárov získavame zoznam konkrétnych jednotlivých požiadaviek na systém.

V niektorých prípadoch a pri rozsiahlejších informačných systémoch môže byť proces zbierania požiadaviek natoľko komplikovaný, že sa oplatí do organizácie vyslať zástupcu vývojového tímu, ktorý v organizácii pôsobí nejaký čas, zúčastňuje sa bežných činností a pozoruje ako to vnútri organizácie funguje. To, čo pri rozhovoroch stakeholderi popíšu sa môže líšiť od ich skutočnej dennej praxe. V spoločenských vedách sa tento odbor nazýva Etnografia a môže sa uplatniť v prenesenej forme aj pri zbieraní požiadaviek na informačný systém.

Pri zbieraní požiadaviek môže situáciu uľahčiť prototyp, čiže prvotná (nekompletná, zjednodušená) verzia systému. Používatelia môžu s prototypom experimentovať, zistiť ako si vývojári predstavujú výsledný produkt a odovzdať im hodnotnú spätnú väzbu ohľadne svojich požiadaviek na systém - už si vedia predstaviť ako bude výsledok vyzerať a tak zrazu presne vedia čo potrebujú. Takýto prototyp musí byť vyvinutý rýchlo a preto sa často používajú špecializované nástroje a vývojové prostredia na rýchle prototypovanie, ktoré nespĺňajú všetky vlastnosti (napr. z hľadiska bezpečnosti, stability, prenositeľnosti a pod.), ktoré budú kladené na výsledný systém, ale o to rýchlejšie umožňujú stakeholderom vidieť základnú kostru alebo používateľské rozhranie aplikácie. Naviac aj samotní vývojári pri vytvorení prototypu objavia nedostatky (nekonzistentnosť, chýbajúce informácie), ktoré zanechali v špecifikácii a majú možnosť ich takto včas opraviť.

Rozlišujeme dva základné druhy prototypovania:
  1. Throw-away prototyping - vytvorený prototyp sa použije na získanie spätnej väzby, potom sa zahodí a systém sa vytvorí od začiatku - väčšinou v nejakom inom vývojovom prostredí
  2. Evolutionary prototyping - vytvorený prototyp sa robí už v cieľovom vývojovom prostredí a stáva sa základom, prvou verziou cieľovej aplikácie, modifikuje sa a (často vo viacerých iteráciách) z neho vzniká výsledný systém. Pozri tiež: evolučný model vývoja IS v predchádzajúcej kapitole.
Cena, ktorú za luxus prototypovania (platí najmä pre prvý typ) vývojový tím zaplatí, nie je nízka: Ďalšie prístupy k prototypovaniu:
Funkcionalitu výsledného systému môžeme modelovať prototypom bez použitia informačných technológií.
Paper prototyping: skupina ľudí, ktorí sedia za okrúhlym stolom si môžu informácie vymieňať, ukladať na lístočkoch papiera a simulovať tak procesy, ktoré má vykonávať informačný systém. Takto môžu odhaliť chýbajúce procesy, duplicitu, neefektívnosť a celkovo demonštrovať funkcionalitu systému.
Wizzard of Oz prototyping: jeden človek nahrádza celý informačný systém a komunikuje s používateľmi, ako keby komunikovali s informačným systémom, môže si pritom viesť agendu na papieri.

2.2.2 Fáza analýzy a vyjednávania požiadaviek

Po zozbieraní požiadaviek od jednotlivých stakeholderov sa často stáva, že nie sú jednoznačné, sú navzájom v konflikte (nekonzistentnosť), niektoré informácie chýbajú. Netreba to chápať ako zlyhanie, ale ako prirodzený proces, ktorý je najmä pri viacerých stakeholderoch očakávaný. Predmetom druhej fázy tvorby špecifikácie je analýza zozbieraných poŽiadaviek a vyjednanie zladenia zistených problémov so stakeholdermi. Aj na túto fázu si musíme naplánovať dostatok času a zdrojov.


Obr. 17: Špecifikácia: fáza analýzy a vyjednávania požiadaviek

Táto fáza sa prirodzene prelína s fázou zbierania požiadaviek a problémy sa riešia priebežne hneď ako sa objavujú. Pri kontrole správnosti požiadaviek môžeme použiť nasledujúci zoznam kontrolných bodov (checklist) - každý bod vyjadruje nejaký problém, ktorý treba opraviť - požiadavku buď odstrániť, alebo preformulovať:
Vo fáze anlýzy požiadaviek si všímame interakciu - vzájomné vzťahy a súvislosti medzi jednotlivými požiadavkami. Pre názornosť môžeme interakcie zobraziť v interakčnej matici.

2.2.3. Fáza validácie požiadaviek

Na rozdiel od fázy analýzy a vyjednávania - keď pracujeme so surovým zoznamom požiadaviek, fáza kontroly / validácie požiadaviek pracuje s kompletným návrhom výsledného dokumentu potom, ako boli nezrovnalosti odstránené. Kým charakteristickou otázkou procesu analýzy by malo byť: "Have we got the right requirements?" - získali sme tie pravé požiadavky?, charakteristickou otázkou fázy validácie by malo byť: "Have we got the requirements right?" - sú už požiadavky v poriadku? Pri kontrole dokumentu prechádzame jednotlivé požiadavky, pričom môžeme naraziť na nasledovné situácie:

Requirement clarification: požiadavka nie je zapísaná dostatočne zrozumiteľne, treba ju spresniť. Missing information: stále existujú niektoré informácie, ktoré v dokumente nie sú zachytené, dokument treba aktualizovať dovtedy, kým nebude kompletný. Requirements conflict: v dokumente sa nachádzajú požiadavky, ktoré sú v konflikte - kontakt so zainteresovanými stakeholdermi musí konflikt vyriešiť. Nerealistická požiadavka: požiadavka sa využitím dostupných technológií za prítomnosti aktuálnych obmedzení nedá implementovať, treba ju upraviť po konzultácii so stakeholdermi.

Pri kontrole výsledného katalógu požiadaviek si všímame nasledujúce vlastnosti a v prípade nedostatkov uplatníme jednu z uvedených štyroch akcií:

Understandability: zrozumiteľnosť = bude formulácia požiadavky zrozumiteľná pre všetkých čitateľov dokumentu? Redundancy: duplicita = je niektorá informácia redundantná? t.j. dá sa odstrániť bez toho, aby to malo na obsah celkového dokumentu nejaký dopad? Completeness: úplnosť = sú uvedené všetky informácie a všetky požiadavky? Ambiguity: nejednoznačnosť = sú všetky pojmy v požiadavkách jednoznačne zadefinované? môže sa stať, že niektorí čitatelia ich pochopia inak? Consistency: vzájomný súlad = existujú dve rôzne požiadavky, ktoré nie sú celkom v súlade a skrývajú nejaké rozpory? Organization: usporiadanosť = je dokument usporiadaný a členený zmysluplne? sú súvisiace požiadavky rozumne zoskupené? Conformance to standards: súlad so štandardmi = sú všetky požiadavky a dokument v súlade so štandardami? ak nie, sú odlišnosti od štandardu dostatočne zdôvodnené? Traceability: vystopovateľnosť = je pôvod každej požiadavky jasný a dostatočne zdokumentovaný? ak by malo dôjsť k zmenám požiadaviek, vieme zistiť od ktorého stakeholdera, z ktorého interview, alebo kvôli ktorému obmedzeniu alebo štandardu sa daná požiadavka v dokumente vyskytla?

3. Diagramy UML

Pri špecifikovaní a navrhovaní informačných systémov si vývojári pomáhajú schémami, obrázkami, diagramami. Obrázky slúžia jednak ako vhodné médium - podklad diskusie vývojárov a jednak pre čitateľov dokumentov, aby sa oveľa rýchlejšie a prehľadnejšie zorientovali v informáciách ktoré dokument sprostredkúva. Naviac, obrázky svojou grafickou reprezentáciou umožňujú vytvoriť model - čiže abstraktné zjednodušenie systému, na ktorom je možné pozorovať, analyzovať, skúmať a navrhovať závislosti, štruktúru, správanie, tok informácií, tok riadenia, stavy, scenáre udalostí a ďalšie aspekty. Do 90-tych rokov existovalo niekoľko rôznych notácií pomocou ktorých sa modely informačných systémov zakresľovali. Pri spájaní týchto úsilí do modelu vývoja Rational Unified Process opísaného v predchádzajúcej kapitole vznikol jednotný grafický jazyk na zakresľovanie diagramov používaných pri špecifikácii a návrhu informačných systémov: jazyk UML (Unified modeling language). Jednotnosť notácie umožňuje vývojárom pochopiť význam diagramov vytvorených inými vývojármi. Situácia keď jeden vývojár číta dokument vytvorený iným vývojárom je veľmi bežná: Je zrejmé, že ak by každý používal iný spôsob zakresľovania diagramov, dochádzalo by k zbytočným nedorozumeniam a chybám. Aktívne ovládanie jazyka UML preto patrí k základným poznatkom, ktoré si má osvojiť každý informatik. Hoci jazyk UML a jednotlivé diagramy nebudeme študovať do maximálnej hĺbky, uvedieme účel a základné pravidlá najbežnejších UML diagramov. Do roku 2004 sa používala verzia UML 1, odvtedy postupne vznikali jednotlivé aktualizácie verzie UML 2. Tieto verzie sa líšia v grafickej reprezentácii a svojich možnostiach, preto pri kreslení diagramov je dôležité skontrolovať, že používate nástroj, ktorý podporuje aktuálnu verziu jazyka.

3.0. Entitno-relačný diagram (ERD)

Entitno-relačný diagram nepatrí do jazyka UML, lebo ten sa zameriava predovšetkým na objektový návrh, zatiaľ čo ERD je všeobecnejší. Napriek tomu je ERD veľmi bežný a často využívaný. Znázorňuje vzťahy (relácie) medzi entitami. Entita je niečo, čo sa dá nazvať podstatným menom. Diagram sa typicky používa na modelovanie priestoru domény pre ktorú sa informačný systém vyvíja (napr. mliekárenský podnik, ak vyvíjame informačný systém pre výrobu mliečnych výrobkov). Entity sa zakresľujú do obdĺžnikov. Vzťahy medzi entitami (relácie) sú v kosoštvorcoch a sú prepojené so všetkými entitami, ktoré do daného vzťahu vstupujú. Entity aj relácie môžu mať svoje atribúty, ktoré sa do diagramu môžu zakresliť ako ovály spojené so svojou entitou/reláciou úsečkou. Medzi entitami môže byť vzťah generalizácie/špecializácie vyjadrený trojuholníkom. Vzťah môže byť pomenovaný. Vzťahy medzi entitami môžu mať vyjadrenú násobnosť (koľkokrát sa daná entita daného vzťahu zúčastňuje).


Obr. 18: Príklad entitno-relačného diagramu.

Na obrázku je zobrazená doména autoservisu. V servise pracujú dva druhy zamestnancov: mechanik a obchodník, každý je určený atribútmi meno a číslo. Mechanik vykonáva opravy, čo je vyjadrené reláciou Mechanic - Does - RepairJob, pričom oprava má svoje atribúty: popis, číslo opravy, cena za materiál a cena za prácu. Medzi entitami RepairJob (oprava) a Car (automobil) je takisto vzťah n:1 - jeden konkrétny automobil mohol podliehať viacerým opravám. Vzťah nákup automobilu (Buys) sa týka troch entít: Obchodník nakupuje daný automobil od nejakého klienta.

Diagram dátového modelu, čiže tabuľky, ich atribúty a vzťahy medzi tabuľkami sa niekedy tiež označuje ako entitno-relačný diagram. Jeho účel je odlišný - dokumentuje podrobnú štruktúru databázy, čiže perzistentnej vrstvy informačného systému - je povinnou súčasťou návrhu každého systému, ktorý do externej pamäte ukladá dáta. Naopak klasický ERD sa skôr využije pri špecifikácii na modelovanie vzťahov v doméne, pre ktorú sa systém špecifikuje.

3.1. Diagram používateľských scenárov (UML Use-case diagram)

Diagram modeluje činnosti, ktoré informačný systém pri interakcii s používateľmi poskytuje.

Diagram sa používa najmä v skorších fázach vývoja, pri špecifikácii a analýze. Slúži na pomenovanie základných hrubých používateľských scenárov a rozličných rolí, v ktorých používatelia vystupujú pri interakcii so systémom. Definuje ktoré roly sa zúčastňujú ktorých scenárov.

Jednotlivé činnosti (scenáre, prípady použitia) sú zakreslené ako ovály, sú vyjadrené slovne v nedokonavom tvare. Nemali by to byť jednorázové akcie, ale nejaké postupy, ktoré sa skladajú z viacerých krokov. Používateľské roly sa nazývajú aktori a sú zakreslené ako schématické postavičky. Jedna fyzická osoba môže vystupovať aj v rozličných roliach. Aktorom nemusí byť živá bytosť, môže to byť aj fyzická entita, ktorá v systéme hrá nejakú aktívnu rolu. Od aktorov vedú úsečky k oválom, ktoré reprezentujú scenáre, ktorých sa daný aktor zúčastňuje. V prípade potreby je možné scenáre rozkresliť podrobnejšie: pomocou relácie extends alebo pomocou relácie uses (niekedy označovanej includes). Extends znamená, že príslušný nadscenár môže zahŕňať príslušnú špecializáciu, pričom spravidla sa prejaví len jedna z možných špecializácií. Relácia uses/includes znamená, že príslušný nadscenár vždy zahŕňa aj všetky zobrazené prepojené podscenáre. V prípade aktorov môžeme využiť reláciu generalizácie (dedičnosť) na vyjadrenie vzťahu medzi dvomi aktormi - všeobecnejším a jeho konkrétnejšou špecializáciou. Znamená to, že konkrétnejší aktor sa môže zúčastniť všetkých scenárov ako aktor všeobecnejší, ale zúčastňuje sa nejakých špecifických scenárov naviac.


Obr. 19: príklad Use-case diagramu.

Diagram používateľských scenárov nikdy nemôže byť použitý len tak, bez podrobnejšieho vysvetľujúceho textu. Používateľské role, aj uvedené scenáre treba podrobne konkretizovať. Use-case diagram slúži najmä ako sumarizujúci pohľad a prehľad všetkých (alebo zvolenej skupiny) používateľských scenárov.

3.2. Sekvenčný diagram

Sekvenčný diagram sa spravidla týka jedného konkrétneho scenára. Môže byť využitý pri podrobnom analyzovaní používateľského scenára zachyteného v use-case diagrame na hrubo-zrnnej úrovni, alebo na vyšpecifikovanie následnosti komunikácie objektov (čomu väčšinou zodpovedá volanie metód príslušných objektov) na podrobnej a nízkej úrovni. Sekvenčný diagram sa zvlášť hodí na zakreslenie nejakého komunikačného protokolu.

Diagram sa zakresľuje ako skupina zvislých prerušovaných čiar, pričom každá z nich zodpovedá jednej entite a v hornej časti diagramu je popísaná. Zvislé čiary zodpovedajú plynutiu času - ten plynie v celom diagrame synchronizovane a rovnako, zhora smerom nadol. Scenár začína tak, že jedna entita vyšle do druhej entity správu, znázornenú vodorovnou šípkou. To spôsobí vytvorenie kontextu spracovania správy na danej cieľovej entite - je zobrazený úzkym zvislým obdĺžnikom a trvá dovtedy, kým požiadavka nie je celá spracovaná. Entita typicky oslovuje ostatné entity v diagrame zaslaním ďalších správ, ktoré nasledujú neskôr v čase (čiže nižšie). Tie opäť vedú k vytvoreniu kontextu na spracovanie danej správy, znovu oslovujú ďalšie entity atď. Správy sú vždy konkretizované textom umiestneným nad šípkou. Po spracovaní požiadavky entita odpovedá návratovou správou (bodkovaná čiara) a presne v tom okamihu jej kontext zaniká. Na jednej entite môže vzniknúť aj nový kontext, pokiaľ predchádzajúci kontext trvá. Jazyk UML dovoľuje v sekvenčnom diagrame špecifikovať časti, ktoré sa nevykonajú vždy (optional, znázornené rámčekom s označením opt v rohu), alebo viaceré alternatívne časti, ktoré sa vykonajú podmienene, v závislosti od splnenia stanoveného predikátu (alt). Podobne je možné zakresliť cykly (loop), prípadne súčasne vykonávané aktivity (par).


Obr. 20: Príklad sekvenčného diagramu. Iný pekný príklad, v ktorom vidno vnorené kontexty: tracemodeler.com

3.3. Diagram komunikácie

Diagram vyjadruje rovnakú informáciu ako sekvenčný diagram, ale celkom iným spôsobom: Entity sú zobrazené ako obdĺžniky a správy, ktoré si entity navzájom posielajú sú vyjadrené ako šípky nad spojnicami medzi entitami. Postupnosť komunikácie je určená číslami pred správami, napr. správa 1 Show Map je prvá, za ňou nasleduje správa 1.1 Get Map, potom 1.2 Get Map, atď. neskôr správa 2. Find Route, 2.1 Get Route, atď. Význam tohto diagramu spočíva v tom, že na rozdiel od sekvenčného vidíme statické rozloženie entít na ploche, vidíme ktoré spolu navzájom nekomunikujú a ktoré áno a aká intenzívna je táto komunikácia.


Obr. 21: Príklad komunikačného diagramu.

3.4. Stavový diagram

Stavový diagram je veľmi špecifický, ale dôležitý nástroj modelovania správania sa nejakej entity. Každý stavový diagram musí mať jasne určenú entitu, ktorej stavy zobrazuje. Stav entity je pasívny, nie je to akcia. Stav trvá nejakú dobu, entita v ňom zotrváva po určitú dobu, kým nenastane nejaká udalosť, alebo sa nevykoná nejaká akcia. Následkom udalosti/akcie sa entita dostáva do ďalšieho stavu. Niektorý zo stavov je počiatočný, niektoré stavy môžu byť označené ako koncové. Stavy sa zakresľujú ako ovály a orientované šípky znázorňujú dvojice stavov, medzi ktorými existuje prechod. Stavové prechody sú popísané udalosťami/akciami, ktoré vedú ku stavovému prechodu. Nasledovaním stavových prechodov môže dochádzať k cyklom. Ľubovoľný stav diagramu môže byť prepojený prechodom s ľubovoľným iným. Treba si uvedomiť rozdiel medzi stavovým diagramom a diagramom činností. Zatiaľ čo stavový diagram zobrazuje pasívne stavy, diagram činností (activity diagram, niekedy nazývaný aj flow-chart, po slovensky vývojový diagram) zobrazuje postupnosť akcií, ktoré spolu tvoria nejaký postup/algoritmus. Zameriavajú sa teda na celkom odlišný uhol pohľadu na určitý proces. Niektoré stavy môžu mať vnútornú štruktúru rozobratú na podstavy: takýto stav má vnútri svoj iniciálny stav a stavové prechody vychádzajúce von automaticky opúšťajú príslušný nadstav. Stavové prechody nadstavu sa môžu realizovať z ľubovoľného podstavu.


Obr. 22: Príklad stavového diagramu pre entitu Kurz. Na obrázku vidíme využitie makro-stavov, ktoré vnútri tvorí samostatný stavový diagram. Stavové prechody vnútri makro-stavu nie sú na obrázku kvôli priestoru popísané, ale pri dôslednom modelovaní by popísané mali byť. Každý stavový prechod v stavovom diagrame má byť popísaný udalosťou/akciou/časovým horizontom.

3.5. Diagram činností (vývojový diagram/flow chart)

Diagram činností - hoci používa graficky podobnú notáciu ako stavový diagram vyjadruje zakreslenie postupnosti krokov s možnými cyklami, vetvením a paralelným spracovaním. V obdĺžnikoch sú zakreslené jednotlivé príkazy/atomické činnosti, sú prepojené orientovanými úsečkami, ktoré znázorňujú tok riadenia (beh programu). Do kosoštvorcov sa zapisujú podmienky vetvenia a na hrany, ktoré z nich vychádzajú sa zapisujú prípady na základe ktorých dochádza k vetveniu toku výpočtu.


Obr. 23: Príklad diagramu činností (activity diagram).

3.6. Diagram komponentov

Diagram komponentov ponúka statický pohľad na štruktúru a architektúru systému podľa nejakého konkrétneho členenia. Diagram tvoria pomenované obdĺžniky s ikonou komponentu v rohu zodpovedajúce veľkým celkom, ktoré sú prirodzene odčleniteľné od zvyšku aplikácie. Sú prepojené s ostatnými komponentami s ktorými komunikujú - túto komunikáciu s pravidla definujú verejne prístupné rozhrania daného komponentu - znázornené uzavretým krúžkom, resp. otvoreným polkruhom (poskytovateľ, vs. klient) pripojeným krátkou úsečkou k zodpovedajúcemu komponentu. Komponentový diagram môže znázorňovať aj hierarchickú štruktúru komponentov - keď sú menšie komponenty zapúzdrené do väčšieho, v tom prípade v diagrame môžu byť použité "delegation connectory", ktoré smerujú vonkajšie rozhrania na rozhrania vnútorných komponentov.


Obr. 24: Príklad komponentného diagramu (component diagram).

3.7. Diagram tried (UML Class diagram)

Diagram tried je jeden z najpoužívanejších diagramov UML. Znázorňuje triedy použité v systéme, alebo jeho časti, prípadne ich metódy a polia a vzťahy medzi triedami. Medzi triedami môžu byť tri základné vzťahy: generalizácia, agregácia a asociácia. Triedy, medzi ktorými je vzťah sú prepojené úsečkou so zodpovedajúcim symbolom. Prvý z nich vyjadruje vzťah dedičnosti - jedna trieda je špecializáciou inej - dedí z nej všetky vlastnosti a pridáva nejaké svoje špecifické črty. Generalizácia sa znázorňuje trojuholníčkom na strane všeobecnejšej triedy. Agregácia označuje vzťah celok-časť. Na strane celku sa zakresľuje kosoštvorec. V prípade, že je prázdny, ide o bežnú agregáciu, ak je plný, ide o kompozíciu. Kompozícia je silnejšia agregácia, kde celok a časť nemôžu samostatne existovať a dávajú zmysel len ako celok. Asociácia je všeobecný vzťah medzi dvoma triedami, nevyjadruje sa žiadnym symbolom a stanovuje, že jedna trieda nejakým spôsobom využíva služby druhej. Špecifickým typom asociácie je dependencia, ktorá sa definuje takto: medzi triedou A a triedou B je dependencia, ak zmena funkcionality v triede B môže vynútiť úpravy v triede A.


Obr. 25: Príklad triedneho diagramu (class diagram).

Špeciálnym prípadom triedneho diagramu je package diagram, ktorý namiesto tried zobrazuje celé balíky tried. Pri triednom diagrame si treba uvedomiť, že to, čo zobrazuje sú typy údajov, nie údaje samotné. Diagram teda len znázorňuje aké sú vzťahy medzi jednotlivými typmi dát, ktoré v aplikácii používame.

3.8 Diagram objektov (UML Object diagram)

Naopak, diagram objektov - hoci sa syntakticky veľmi podobá triednemu diagramu nezobrazuje typy, ale konkrétne údaje, tak ako sa vyskytujú v pamäti počas behu aplikácie. Ak má automobil štyri kolesá, tak v objektovom diagrame budú zobrazené štyri obdĺžniky označené príslušnými názvami objektov reprezentujúcich jednotlivé kolesá automobilu.


Obr. 26: Príklad objektového diagramu (object diagram).

3.9. Diagram rozmiestnenia elementov (UML Deployment diagram)

Deployment diagram zobrazuje rozloženie komponentov na jednotlivých výpočtových uzloch počas reálnej prevádzky systému. Je v ňom zobrazené aké rôzne výpočtové uzly (fyzické počítače) systém bude využívať, aká bude ich rola (klient, databázový server a pod.), aká bude topológia ich vzájomného prepojenia, aké komunikačné protokoly sa budú na komunikáciu medzi komponentami používať.




Obr. 27: Príklady deployment diagramov.

3.10. Diagram dátových tokov (data-flow diagram)

Na záver uveďme diagram dátových tokov, určený na modelovanie toku informácií medzi procesmi a externými a internými dátovými úložiskami. Zobrazuje konkrétne kúsky informácií a procesy, ktoré si informácie medzi sebou vymieňajú. Externé úložiská (resp. vstupy a výstupy dát do modelovaného systému) sú označené obdĺžnikmi, interné úložiská dát sú pomenované medzi dvoma vodorovnými čiarami, konkrétne informácie (typy tečúcich údajov) sú popísané na šípkach, ktoré znázorňujú zdroj a cieľ toku informácií. Procesy sú označené kruhmi. Tento diagram síce nie je súčasťou UML, je omnoho starší, ale umožňuje modelovať tok údajov medzi procesmi jedinečným spôsobom, takže sa stále bežne používa.


Obr. 28: Príklad data flow diagramu.

3.11. Príklad

Využitie UML diagramov si ukážeme na malom príklade. Naším cieľom bude navrhnúť systém pre elektronické voľby. Niečo podobné už funguje v Estónsku viac ako 10 rokov. Elektronické voľby (a zvlášť cez Internet) nikdy nemôžu byť natoľko bezpečné a spoľahlivé ako ručné sčítavanie hlasov, kde si do volebnej komisie každá strana môže menovať svojich členov, ktorí dohliadajú na regulérnosť volieb. Za regulérnosťou sa skrýva viacero požiadaviek: Tieto požiadavky vôbec nie je jednoduché zabezpečiť, viaceré štúdie skôr naznačujú, že je to nemožné. Zvlášť, ak by sa občanom dovolilo voliť zo svojho počítača cez Internet.
Predpokladajme však, že sa riziká podarí znížiť na prijateľnú úroveň. Elektronické voľby potom umožnia: V tejto časti použijeme jazyk UML na modelovanie častí informačného systému zabezpečujúceho elektronické voľby.

3.11.1. Use-case diagram


Obr. 29: Use-case diagram pre IS elektronické voľby.

Modelovanie volebného informačného systému začíname zobrazením všetkých podstatných funkcií, ktoré systém plní v use-case diagrame (diagram používateľských scenárov) a uvedomením si pre ktoré rozličné používateľské roly je každá takáto funkcionalita dostupná. Každej použivateľskej roli zodpovedá jedna grafická postavička. Ak je medzi niektorými rolami vzťah generalizácie, v diagrame sú spojené šípkou, smerujúcou od špecifickejšej roly ku všeobecnejšej. V našom prípade má používateľská rola volič k dispozícii funkcionalitu, ktorá je pre neho špecifická, napr. počas voľby označuje kandidátov, ale zároveň má k dispozícii všetku funkcionalitu, ktorá je dostupná pre všeobecnejšiu rolu verejnosť, keďže je jej špecializáciou.
Každý ovál zodpovedá nejakej ucelenej funkcionalite (use case), ktorej dosahovanie sa realizuje vykonaním určitého scenára - postupnosti krokov, ktoré nie sú v tomto diagrame viditeľné, ale môžu byť zobrazené v sekvenčnom diagrame. V niektorých prípadoch však môžeme podstatné časti príslušného scenára zdôrazniť aj tu - najmä, ak im zodpovedá nejaká samostatne ucelená podfunkcionalita. V tomto príklade správca jednej volebnej udalosti, ktorý konfiguruje nejakú volebnú udalosť, musí nastaviť systém voľby a potom pozadávať kandidátov (príp. strany). Preto je v diagrame šípka smerujúca od use-case Konfiguruje volebnú udalosť ku use-case Nastavuje systém voľby i k use-case Zadáva kandidátov, obe označené stereotypom << include >>.
Podľa typu voľby môže volič buď len vyberať jednu stranu, resp. kandidáta (napr. v prezidentských voľbách), alebo v inom type volieb môže krúžkovať kandidátov. Preto je používateľský scenár volí "rozšírený" voliteľne o podscenár vyberá stranu alebo kandidáta, alebo podscenár označuje kandidátov. Oba sú teda špecializáciou všeobecnejšieho scenára volí a tento vzťah generalizácie/špecializácie, resp. realizácie/doplnkového voliteľného rozšírenia je vyjadrený prototypom << extend >>. V oboch prípadoch sa volič musí autentifikovať a na záver potvrdiť svoj volebný výber a preto sú tieto ďalšie dva podscenáre označené prototypom << include >>. V niektorých prípadoch volič nielen vyberá stranu, ale okrem toho môže svoje preferenčné hlasy určiť zakrúžkovaním kandidátov. Preto jeden z podscenárov je zároveň potenciálne súčasťou druhého podscenára.
Na tomto diagrame je dôležité všimnúť si, že funkcionalita popísaná v ováloch aa vyjadruje nedokonavým vidom slovies: vytvára, konfiguruje, zadáva, volí a pod. Nie je vhodné použiť ani neurčitok (voliť, vytvoriť, konfigurovať), ani rozkazovací spôsob (vytvor, konfiguruj), ani žiadnu inú formu (vytvorenie, voľba, konfigurácia...). Ešte raz si všimnime šípky medzi scenármi A -> B: v prípade doplnkového/voliteľne pridaného podscenára ide šípka smerom od špecializácie ku všeobecnejšiemu use-case (<< extend >>) - otázka: je A rozšírením B?, zatiaľ čo v prípade zahrnutia podscenára v komplexnejšom scenári (<< include >>) smeruje šípka od komplexnejšieho k čiastkovému, jednoduchšiemu, zahrnutému scenáru - otázka: je B súčasťou A?

3.11.2. Stavový diagram


Obr. 30: Stavový diagram pre IS elektronické voľby.

Informačný systém nikdy nebude plniť svoj účel správne, ak jeho tvorcovia nepochopili životný cyklus entít, ktoré v systéme hrajú kľúčové úlohy. Každá entita prechádza cez určité stavy a svoj stav mení v závislosti na svojej interakcii s okolitým svetom - spravidla v okamihu nejakej uskutočnenej udalosti alebo po uplynutí určitej stanovenej doby. Stavový diagram UML znázorňuje pasívny prechod nejakej entity medzi jej stavmi a udalosti, ktoré zmenu stavu takejto entity spôsobujú. Zvolenou modelovanou entitou môže byť ľubovoľná entita z domény problému informačného systému. Tento typ diagramu je možné použiť, ak za entitu vezmeme samotný informačný systém, prípadne jeho používateľské rozhranie, ale v tomto príklade a aj v príkladoch, ktoré nás počas tímového projektu a písomných testov budú zaujímať, budú modelované stavy inej entity. V tomto prípade ide o entitu voľby.
Každý stav entity je vyjadrený nejakým oválom, každý ovál vyjadruje nejaký stav entity. Každý prechod do ďalšieho stavu (šípka medzi dvoma oválmi) by mal byť popísaný textom - udalosťou, pri ktorej k prechodu medzi stavmi dochádza. Výsledkom je potenciálne cyklický orientovaný graf. Modelovať stavy enity sa dá na rôznej hrubozrnnosti, čím môžeme dostať diagram na markoskopickej úrovni, hoci každý - alebo len niektoré - z jeho stavov obsahujú podrobnejší diagram. Do stavového diagramu entita vstupuje cez počiatočný stav (čierny kruh) a vystupuje väčšinou cez koncový stav (kruh v kružnici).

3.11.3. Sekvenčný diagram


Obr. 31: Sekvenčný diagram opisujúcu scenár "volí" s doplnkovou možnosťou zrušenia hlasu pre IS elektronické voľby.

V sekvenčnom diagrame plynie čas zhora nadol. Na x-ovej osi sú zobrazené jednotlivé entity. V prípade podrobného návrhu entity zodpovedajú objektom nejakých tried, pri menej podrobnom diagrame entity zodpovedajú celým komponentom. Môže ísť aj o entity z domény problému informačného systému (napr. archív, predseda volebnej komisie, štatistický urad a pod.), ak modelujeme časový priebeh nejakého scenára v reálnom svete a interakciu medzi skutočnými entitami. Vodorovné šípky (spravidla nejdú šikmo - necestujú v čase! - pokiaľ nechceme zvlášť znázorniť, že doručenie správy nejaký čas trvá - v tom prípade môže byť šípka aj šikmo smerom nadol) znázorňujú komunikáciu medzi entitami v zmysle: jedna entita posiela druhej entite nejakú správu uvedenú v texte nad šípkou. V prípade objektov ide spravidla o volanie metódy, kde môžeme uviesť aj argumenty volanej metódy. Tento diagram je veľmi vhodný na pochopenie postupnosti a poradia správ pri komunikácii počas nejakého konkrétneho používateľského scenára (často sekvenčný diagram zodpovedá jednému oválu/scenáru z use-case diagramu). Zvislé prerušované čiary zodpovedajú životnosti (časovej platnosti) jednotlivých entít. Ak nejaká entita vzniká uprostred príslušného scenára, tak sa aj jej hlavička (obdĺžnik s názvom entity) uvedie až v príslušnom čase. V tomto prípade vznikla entita FrešovHlas, (podobne zodpovedajúci objekt triedy AnonymizovanyHlas) až keď ho objekt triedy VolebnaMiestnost vytvoril a preto je hlavička tejto entity uvedená v strede diagramu. Ak nejaká entita naopak v nejakom čase prestane existovať, tak je jej zvislá čiara ukončená hrubým šikmým krížom. V našom prípade bol objekt evidujúci hlas zrušený, lebo o to požiadal sám volič. Pomocou vetvenia (rámček s alt/alternative v ľavom hornom rohu) môžeme vyjadriť alternatívne cesty scenára podľa platnosti nejakej podmienky, ktorá je tiež vyjadrená pod slovíčkom alt v hranatých zátvorkách. Podobne, rámčeky s popisom opt, resp. loop vyjadrujú časti scenára, ktoré sa nie vždy, resp. opakovane vykonajú. Pre úplnosť: existujú aj rámčeky par a critical, ktoré označujú časti scenára, ktoré sa vykonávajú paralelne, resp. takú podčasť, ktorá obsahuje kritický úsek scenára, ktorý sa môže vykonávať naraz iba jeden raz (v jednom výpočtovom vlákne - critical region), pre ešte väčšiu úplnosť pozri uml-diagrams.org. Na zvislých osiach sú umiestnené prázdne zvislo-úzke obdĺžniky, ktoré vyjadrujú dobu, po ktorú je nejaká správa entitou spracovávaná. Mali by začínať presne v okamihu, keď správa príde a väčšinou končia, keď sa odpovedná správa vracia naspäť entite, ktorá poslala správu, čo príslušný obdĺžnik vytvorila. Entita môže počas spracovávania správy zavolať svoju vlastnú metódu (pošle správu sama sebe) - v tom prípade spracovávanie pôvodnej správy stále pokračuje ďalej, ale vytvorí sa ďalší - prekrývajúci obdĺžnik zodpovedajúci časovému intervalu spracovania vnorenej správy. Notácia spracovávania správ predpokladá, že po poslaní správy inej entite prechádza kontext spracovania (mohli by sme povedať "výpočtové vlákno") do príslušnej entity, až kým správu nespracuje a neodpovie na ňu. V programovaní to zodpovedá volaniu metódy - výpočtové vlákno so zavolaním metódy odíde spracovávať zavolanú metódu. Naopak, ak má ísť o asynchrónnu správu poslanú medzi dvoma entitami, ktoré obe ďalej pokračujú (každá má "svoje výpočtové vlákno"), tak sa šípka môže nakresliť s polovičným profilom, alebo bez výplne. V záhlaví entít sa môžu vyskytnúť anonymné inštancie nejakých tried (napr. :VolebnaMiestnost), alebo priamo nejaké špecifické inštancie určitých tried (napr. Frešo:Občan). Samotná inštancia (objekt) zvykne byť podčiarknutá. Pre úplnosť: ak je entitou zúčastňujúcou sa komunikácie objekt v nejakej používateľskej roli, tak namiesto obdĺžnika možno použiť piktogram používateľskej roly (postavičku), prípadne ikony i názvy iných stereotypov - pozri tracemodeler.com.
Diagram na obrázku vyššie znázorňuje priebeh používateľského scenára volí s doplnkovou funkcionalitou umožnenia zrušiť už hodený hlas (ak voľby stále prebiehajú). Predtým ako občan vyplní svoju voľbu na volebnom termináli, sa na základe jeho autentifikácie preukazom overuje, či je platným voličom v danej volebnej miestnosti (táto verzia systému neprakticky predpokladá, že volič má voliť iba vo svojom volebnom obvode, hoci aj toto obmedzenie tradičných volieb je jedným z tých, ktoré by bolo možné elektronickými voľbami ľahko prekonať).

3.11.4. Triedny diagram


Obr. 32: Triedny diagram vybranej časti IS elektronické voľby ktorá rieši voľbu vo volebnej miestnosti.

Triedny diagram zobrazuje podrobnosti tried a vzťahy medzi triedami - čiže medzi typmi dátových údajov, ktoré aplikácia používa. Pod podrobnosťami máme na mysli zoznam metód (a ich argumentov a návratových hodnôt), ktoré chceme znázorniť a zoznam jej atribútov (= premenných). Obe môžu byť dekorované viditeľnosťou: + = public, - = private, # - protected, prípadne ~ - package. Ak pre myšlienku, ktorú diagramom chceme vyjadriť, zoznam metód a atribútov nie je podstatný, trieda môže byť vyjadrená aj obyčajným obdĺžnikom obsahujúcim len názov triedy. Medzi triedami rozlišujeme tri základné typy vzťahov (relácie):
generalizácia - zodpovedá vzťahu nadtrieda-podtrieda a vyjadruje sa prázdnym trojuholníčkom na strane nadtriedy
agregácia - zodpovedá vzťahu celok-časť a vyjadruje sa kosoštvorcom na strane celku. Ak je kosoštvorec plný, ide o silnejšiu verziu agregácie - kompozíciu, ktorá značí, že časť je neoddeliteľnou súčasťou celku a nemá samostatne reálny význam. Vzťah celok-časť sa prakticky často realizuje tak, že v triede, ktorá je celkom, sa vyskytuje odkaz na príslušnú časť vo forme atribútu. Názov tohto atribútu sa potom zvykne písať ako textový popis čiary vyjadrujúcej agregáciu, namiesto toho, aby sa uviedol priamo v zozname atribútov triedy.
asociácia - zodpovedá nejakému inému vzťahu medzi triedami - typicky keď metóda alebo atribút jednej triedy využíva (ako argument, alebo návratovú hodnotu) objekty druhej triedy. Táto relácia môže byť orientovaná (orientovaná šípka) alebo nie (čiara nie je ukončená šípkami).

Všetky tri druhy vzťahov sú tzv. dependenciou, čiže závislosťou medzi triedami, ktorú je možné znázorniť aj priamo pomocou prerušovanej čiary a ktorá je vždy orientovaná: dependencia A -> B označuje, že zmena triedy B môže vyvolať nutnosť úprav v triede A. Na vzťahoch medzi triedami je možné zobraziť násobnosť vzťahu (1 na 1, 1 na mnoho, mnoho na mnoho, prípadne počty aj presnejšie špecifikovať). Napríklad na obrázku vyššie je vidno, že každému voličovi (1) zodpovedá jeden alebo žiaden hlas (0..1).
Očakáva sa, že v triednych diagramoch, ktoré na tomto predmete vytvoríte, použijete všetky tri uvedené základné typy vzťahov medzi triedami aj ich násobnosti.

3.11.5. Deployment diagram


Obr. 33: Deployment diagram pre IS elektronické voľby.

Deployment diagram vyjadruje prevádzkový pohľad na systém - na akých hardvérových zariadeniach bude systém v prevádzke nainštalovaný, ako budú prepojené komunikačnými spojeniami a aké komunikačné protokoly sa na týchto prepojeniach použijú. Na hardvérových zariadeniach (sú označené 3D krabicami) a stereotypom (<< device >>) sú prevádzkované jednotlivé komponenty systému (obdĺžniky s ikonkou komponentu v rohu), ktoré tam môžu byť prevádzkované v rámci nejakého výpočtového prostredia - napr. aplikačného servra Tomcat. Výpočtové prostredie je označené stereotypom << execution environment >> a zobrazené 3D krabicou vnútri svojho hardvérového zariadenia, pričom komponenty sa umiestňujú priamo do tohto prostredia - ak je, pravda, na zariadení vyjadrené. Iné obmedzenia (napr. OS = Linux) príslušného výpočtového uzla sú vyjadrené v záhlaví v zložených zátvorkách. Pokiaľ chceme zobraziť aj jednotlivé artefakty, ktoré sa na príslušné zariadenie inštalujú (súbory, balíčky, aplikácie), môžeme ich vyjadriť obdĺžnikom so stereotypom << artifact >> a napr. ikonou súboru. Pri prevádzke tieto artefakty po spustení tvoria nejaký koponent, čomu zodpovedá stereotyp << manifest >>, príklad je uvedený na obrázku.

3.11.6. Activity diagram

Pre zaujímavosť a na odlíšenie od stavového diagramu sa pozrime ešte na príklad Activity diagramu, ktorý je UML verziou tradičných vývojových diagramov (flow-chart). UML Activity diagram používa rovnaký grafický jazyk ako stavový diagram, ale zobrazuje niečo iné: zatiaľ čo stavový diagram zobrazuje pasívne stavy nejakej entity a akcie/udalosti, ktoré vedú k zmenám stavu, sú uvedené pri šípkach medzi dvojicami stavov, v activity diagrame je zobrazený nejaký postup pozostávajúci z krokov (akcií), ktoré sú uvedené v ováloch. Šípky znázorňujú iba postupnosť/následnosť jednotlivých akcií. Vetvenie na rôzne alternatívy sa značí pomocou kosoštvorca, s jedným vstupným a minimálne dvoma výstupnými prepojeniami. Nasledujúci príklad zobrazuje postupnosť krokov voliča pri interakcii s volebným terminálom.


Obr. 34: Activity diagram interakcie voliča s terminálom pre IS elektronické voľby.

4. Návrh

Návrh je najnáročnejšou fázou tvorby informačného systému. V praxi sa mu často nevenuje dostatočná pozornosť, čo vedie k neoptimálnym systémom s krátkou životnosťou a množstvom chýb. Základ návrhu tvorí architektúra systému. Pri návrhu sledujeme základný princíp vysokej súdržnosti a nízkej fragmentovanosti. Môžeme sa inšpirovať stavebníctvom. Na prvom obrázku je systém s vysokou súdržnosťou a malým počtom vzájomných spojov jednotlivých komponentov. Na druhom obrázku je opačný prípad. Prvý variant je z hľadiska návrhu oveľa vhodnejší ako druhý, pretože ak by z nejakého dôvodu došlo k modifikácii, ktorá by viedla k posunutiu stredového upínacieho bodu, tak by sa museli zmeniť všetky segmenty, ktoré sú v ňom uchytené.


Obr. 35: Základný princíp pri navrhovaní: efektívna architektúra.


Obr. 36: Základný princíp pri navrhovaní: neefektívna architektúra.

4.1. Architektonické pohľady na systém

Architektúra softvérového systému je základná kostra systému na ktorú sa upínajú všetky komponenty. Môžeme ju študovať z hľadiska statického - opisuje softvérové, hardvérové a dátové prvky a vzťahy medzi nimi, alebo dynamického - opisuje tok informácií a procesov. Rozlišujeme niekoľko základných architektonických pohľadov na systém (mohli by sme povedať pri pohľade na systém si nasadíme rozličné okuliare, ktoré umožňujú vidieť rozličné aspekty):

4.2. Ciele pri tvorbe návrhu

Napriek tomu, že sa môžu zdať prirodzené, je dobré uvedomiť si, aké ciele by sme pri tvorbe návrhu mali sledovať:

4.3. Štruktúra dokumentu Software Design Description

Výsledkom úsilia fázy návrhu informačného systému by mal byť dokument, podľa ktorého sa systém dá priamo naprogramovať. Návrh by mal byť dostatočne konkrétny na to, aby doviedol dve skupiny, ktoré by postupovali nezávisle podľa jedného návrhu, k veľmi podobnému výsledku. Vychádzajúc zo štandardu IEEE 1016, ktorý od prvej verzie z roku 1987 bol dvakrát upravovaný (1998, 2009), návrh softvéru by mohol mať nasledujúcu štruktúru - opäť ide len o odporúčanie, ktoré sa prispôsobuje príslušnému projektu:
1. Introduction
1.1 Purpose
1.2 Scope
1.3 Definitions, acronyms, and abreviations
2. References
3. Decomposition description
3.1 Module decomposition
3.1.1. Module 1 description
3.1.2. Module 2 description
3.2 Concurrent process decomposition
3.2.1. Process 1 description
3.2.2. Process 2 description
3.3 Data decomposition
3.3.1 Data entry 1 description
3.3.2 Data entry 2 description
4. Dependency description
4.1 Intermodule dependencies
4.2 Interprocess dependencies
4.3 Data dependencies
5. Interface description
5.1 Module interface
5.1.1 Module 1 description
5.1.2 Module 2 description
5.2 Process interface
5.2.1 Process 1 description
5.2.2 Process 2 description
6. Detailed design
6.1 Module detailed design
6.1.1 Module 1 detail
6.2.2 Module 2 detail
6.2 Data detailed design
6.2.1 Data entity 1 detail
6.2.2 Data entity 2 detail

4.4. Objektový návrh

4.4.1. Základné princípy OOP

Objektovo-orientované programovanie sa do centra softvérového priemyslu dostalo koncom 80-tych a začiatkom 90-tych rokov, keď sa ukazovalo, že dáta sú pri návrhu softvérového diela a pri jeho životnom cykle oveľa podstatnejšie a stabilnejšie ako funkcionalita, ktorá sa nad týmito dátami vykonáva. Namiesto dovtedy zaužívanej dekompozície systému (rozdelenie na menšie podčasti) na základe funkcionality sa dôležitejšou stávala dekompozícia na základe dát. Dáta sa prirodzene formovali do štruktúr - zväčša popisujúcich atribúty nejakej entity => objektov.

Prvým masovo rozšíreným OOP jazykom bol stále pomerne nízkoúrovňový jazyk C++, ktorý neriešil vážny a fundamentálny problém: rozsiahlejšie projekty narážali na nejasne definované kompetencie pri správe pamäti. Ak si jednotlivé komponenty programu (myslíme metódy) preposielajú (najmä rozsiahlejšie) údaje uložené v objektoch vytvorených v dynamickej pamäti, nie je celkom jasné - a jazyk to nijak nedefinuje, či adresát má na starosti aj odstránenie objektu z pamäti. Ak je ten istý objekt rozoslaný viacerým adresátom, žiaden z nich nemôže zodpovedať za jeho odstránenie z pamäti - niekto iný ten objekt možno ešte potrebuje. Ak sa má o jeho uvoľnenie z pamäti postarať odosieľateľ, ten tiež nemá kontrolu nad tým, kedy adresáti už objekt nepotrebujú a možno odosielateľ už dávno neexistuje, kým adresáti s objektom pracujú naďalej. Odpoveďou na tento problém je všetko stále kopírovať, čo je ale veľmi zlá stratégia efektívneho narábania s pamäťou i s procesorovým časom. Vzniká tak paradox, že na jednej strane nízkoúrovňový a veľmi efektívny jazyk, akým je jazyk C, bol rozšírený o chybne koncipovanú správu dynamickej pamäte objektov v C++ a hoci nedávny štandard vo verzii C++11 sa situáciu za cenu neelegantného skomplikovania jazyka snažil zachrániť, podstatne kvalitnejšie riešenie zaviedli jazyky rodiny Java v 90-tych rokoch a vytlačili jazyk C++ z role priemyselného štandardu. Spustiteľný program v Jave už nie je len skompilovaný kód (binárny strojový kód ako v prípade C++, bytecode v prípade jazyka Java - ale stále je to len skompilovaný kód), ale potrebuje špeciálne výpočtové prostredie - virtuálny stroj (virtual machine), ktorý má okrem iného na starosti správu dynamickej pamäte. Virtuálny stroj sám a ku každému jednému objektu eviduje, či je objekt ešte niektorým komponentom využívaný a keď nie je, automaticky ho z pamäti odstráni (garbage collection) bez toho, aby sa o to programátor musel starať. V tom prípade sa nič nemusí kopírovať, všetky komponenty zdieľajú tú istú kópiu objektu a všetky objekty sa preposieľajú odkazom (referenciou). A ak niekde náhodou naozaj potrebujeme kópiu, tak si objekt explicitne vyklonujeme (metóda clone()). Tento významný posun znamenal odstránenie jedného z najproblematickejších miest, kde môžu vznikať programátorské chyby, ktoré sa veľmi ťažko hľadajú a opravujú. Preto sa dnes v praxi siaha po jazyku C++ iba v prípadoch, keď ide o kritické systémy, kde záleží na presnom načasovaní udalostí, resp. maximálnom výkone (renderovanie grafiky, riadenie hardvéru, vedecké výpočty) a kde automatická správa pamäte (garbage collection) vedie k neočakávanej variabilite v odozve systému, ktorú si nemožno dovoliť. Predsa len interpretovanie platformovo nezávislého javovského bajtkódu nemôže byť rovnako efektívne, ako beh programu preloženého priamo do strojového kódu procesora. V tých prípadoch (keď Java a spol. nevyhovuje) však väčšinou vystačíme s elegantnejším, lepšie čitateľným, jednoduchším a zrozumiteľnejším jazykom C. V poslednom desaťročí sa aj jazyky rodiny Java dostávajú postupne do úzadia, najmä kvôli zmene platformy - väčšina informačných systémov sa presúva na web, kde Java nie je kľúčovým hráčom, aj keď aplikačné servre založené na technológii Java EE sú silnou, populárnou a stále sa rozvíjajúcou technológiou. Otázna je aj situácia na mobilných zariadeniach, kde sa síce používa Java na platforme Android, ale kód beží na neštandardnom virtuálnom stroji, iné platformy (iOS) našli tiež iné alternatívy ako Java.

Vráťme sa k OOP. Čiže dáta sa v OOP dostali v informačných systémoch viac do pozornosti. Objekty (po slovensky predmet) oveľa viac začali zodpovedať novej úlohe, ktorú informačné systémy začínali plniť: počítače už nemali len "počítať" - vykonávať pre človeka náročné výpočty, ale informačné systémy odrážali a nahrádzali situácie z reálneho sveta - čiže informačné systémy sa stávali modelmi reality a objekt sa osvedčil ako základný stavebný prvok modelov reality zloženej z entít a vzťahov medzi entitami. Nad dátami reprezentovanými objektami sa vykonávajú operácie (nejaké čiastkové výpočty) a ukázalo sa, že tieto operácie je dobré umiestniť čo najbližšie k dátam - priamo do objektov. Tak sa z objektu stáva nielen súbor údajov o nejakej entite (jeho atribútov), ale aj súbor operácií - nejakých elementárnych alebo aj zložitejších funkcií, ktoré vieme na entite realizovať. Napríklad, ak je v objekte Student uložené rodné číslo študenta, tento objekt môže obsahovať operáciu (metódu) vek(), ktorá z rodného čísla vypočíta aktuálny vek študenta. Tento koncept - dátový typ s množinou definovaných operácií na týchto dátach s jasne určeným významom - sa často označuje ako abstraktný dátový typ (ADT). Typickým príkladom je typ zásobník, ku ktorému sú definované operácie vlož prvok na vrch zásobníka (push), vyber prvok z vrchu zásobníka (pop) a zisti, či zásobník je prázdny (isEmpty).

V systéme sa typicky nachádza viacero objektov, ktoré majú rovnakú štruktúru. Napríklad, v akademickom informačnom systéme tvoria základné evidované údaje o každom študentovi samostatný objekt, každému študentovi zodpovedá jeden objekt v systéme. Všetky takéto objekty majú rovnakú štruktúru a tá je predpísaná definíciou typu objektu, čiže jeho triedou. Vidíme, že trieda (class) je typom štruktúrovaných údajov a objekt (object) je hodnotou - jedným konkrétnym prípadom (inštanciou triedy). Čiže napr. medzi triedou Student a nejakým konkrétnym objektom tejto triedy (ktorý obsahuje napr. základné údaje o študentke Alexandre) je vzťah rovnakého druhu ako napr. medzi typom premennej "int" a hodnotou 7: trieda vs. objekt je ako typ vs. hodnota. Pripomeňme však ešte raz, že k objektu a triede patria aj operácie, ktoré príslušná trieda definuje. Operácie patria aj triede aj objektu: trieda ich zadefinuje a nad konkrétnymi objektami operácie pracujú.

OOP sa v skratke často definuje ako kombinácia troch hlavných vlastností jazyka: OOP = inheritance + polymorphism + encapsulation, čiže dedičnosť, polymorfizmus a zapúzdrenie údajov. Kľúčovú rolu hrá aj abstrakcia, čo označuje princíp hľadania spoločných vlastností rozličných vecí vytváraním ich zovšeobecnení. Zovšeobecnenie je abstrakciou definujúcou spoločné vlastnosti všetkých pôvodných vecí. Vzniká tým hierarchia konceptov, všeobecný koncept s vybranými spoločnými vlastnosťami (generalization) a sada rôznych vecí, kde každá k spoločným vlastnostiam pridáva niečo svoje špecifické (specialization). Napríklad, v grafickom editore používateľ vytvára kružnice a elipsy, úsečky, body, obdĺžniky, mnohouholníky a podobne, ale všetky majú spoločné niektoré vlastnosti a operácie: majú polohu v dokumente určenú súradnicami (x, y), vieme ich posunúť o vektor [dx, dy] operáciou move(dx, dy), vedia sa do dokumentu na svojej pozícii nakresliť (draw(Document d)). Tieto spoločné vlastnosti a operácie vyberieme do abstraktnejšieho pojmu útvar. V OOP jazyku sa uvedená situácia modeluje tak, že jednotlivým druhom útvarov zodpovedajú triedy (napr. trieda Kruznica, trieda Bod, atď.), ktoré sú podtriedami nadtriedy Útvar. Tiež hovoríme, že podtriedy sú od nadtriedy odvodené, resp. ich rozširujú (kľúčové slovo extends v jazyku Java). Inheritance čiže dedičnosť označuje schopnosť jazyka OOP definovať takéto abstrakcie. Podtriedy dedia všetky vlastnosti nadtried, sú niečím špecifické - niečím sa od svojich nadtried odlišujú. Vo väčšine jazykov má každá trieda najviac jednu nadtriedu, ale nadtrieda môže mať viacero podtried. Ak sa nejaký typ entity hodí do viac ako jednej abstrakcie, väčšina OOP jazykov dovoľuje vytvoriť tzv. interfejsy, kde jedna špecifická trieda môže spĺňať charakteristiku viacerých abstraktnejších pojmov - každý definovaný svojím interfejsom. Napríklad trieda Človek, určená na reprezentáciu ľudských bytostí a ich vlastností (atribúty farba očí, farba vlasov, telesná hmotnosť, veľkosť chodidla a pod.) môže byť odvodená od abstraktnejšieho konceptu Cicavec (ktorý napríklad definuje atribút priemerná doba kojenia), ale zároveň v inej (mohli by sme povedať ortogonálnej) hierarchii je odvodený od konceptu Suchozemský živočích, kde môžu byť atribúty ako dĺžka kroku, alebo počet nôh. Jazyk C++ umožňuje aj takúto viacnásobnú dedičnosť, hoci väčšina iných jazykov len na úrovni interfejsov, kde (napr. v jazyku Java) nie je možné definovať atribúty, ale len operácie. Interfejs je len predpisom rozhrania (zoznamu operácií), ktoré musí trieda, ktorá tento interfejs implementuje, definovať. Nie je však problém do interfejsu zaradiť gettery a settery (operácie, ktoré vrátia hodnoty príslušných atribútov) a tým sa s uvedeným príkladom viacnásobnej dedičnosti vysporiadať. V príklade sú uvedené len gettery:

public interface Cicavec 
{
  /** @returns priemerna doba kojenia v tyzdnoch */
  public int primernaDobaKojenia();
}

public interface SuchozemskyZivocich
{
  /** @returns dlzka kroku v milimetroch */
  public int dlzkaKroku();

  /** @returns pocet noh zivocicha */
  public int pocetNoh();
}

public class Clovek implements Cicavec, SuchozemskyZivocich
{
  public java.awt.Color farbaOci() { ... }
  public java.awt.Color farbaVlasov() { ... } 
  ...
  public int primernaDobaKojenia() { ... }
  public int dlzkaKroku() { ... }
  public int pocetNoh() { ... }
}

Vráťme sa k príkladu grafického editora s útvarmi a všimnime si, že vo všeobecnej triede Útvar je definovaná operácia draw(Document d), ktorú prekrýva každá zo špecifických podtried. Za jedným menom (draw) sa teda skrývajú rozličné tvary: poly-morph => polymorphism. Ak si vytvoríme pole objektov triedy Útvar, do tohto poľa nám princípy dedičnosti OOP dovoľujú priradiť aj ľubovoľnú podtriedu triedy Útvar, pretože každá podtrieda triedy Útvar má všetko, čo útvar má mať a preto ju môžeme použiť v ľubovoľnej situácii, kde sa útvar vyžaduje. Iterujme cez toto pole a na každej položke poľa vykonajme operáciu draw(). Program v OOP jazyku automaticky zvolí tú správnu metódu draw() z tej triedy, akej je príslušná položka poľa.


Utvar utvary[] = new Utvar[10];
Document d;
...
u[0] = new Kruznica(100, 100, 5);
u[1] = new Obdlznik(200, 200, 7, 4);
...

for (Utvar u : utvary)
  u.draw(d);             // na tomto mieste sa volaju rozne metody draw => polymorfizmus

Položme si ešte tieto otázky: Ako bude kompilátor vedieť, ktorú zo všetkých metód draw() má na danom riadku programu zavolať? Ako sa takýto pekný polymorfizmus v OOP jazykoch v skutočnosti dosahuje?

Kompilátor bežne prekladá volanie funkcie, procedúry, metódy priamo do strojovej inštrukcie procesora "CALL adresa". Adresa nasledujúcej inštrukcie sa odloží na zásobník, riadenie programu z tohto miesta prejde na inštrukciu na udanej adrese - tam sa nachádza kód príslušnej funkcie a po dosiahnutí inštrukcie "RET" (return) sa zo zásobníka vyberie adresa nasledujúcej inštrukcie, aby program pokračoval na tom mieste, odkiaľ bola daná funkcia zavolaná. Toto v prípade polymorfizmu nie je možné, lebo z daného miesta programu je potrebné zavolať vždy inú metódu draw(). Preto musí byť v každom objekte uložená aj jeho trieda (čiže jeho typ) a kompilátor pri preklade na danom riadku programu vygeneruje kód, ktorý najskôr zistí, akého typu je objekt v premennej u. Potom sa pozrie do tabuľky virtuálnych metód - inými slovami - zistí si adresu tej správnej metódy draw() - a tú zavolá.

Napokon základná vlastnosť OOP jazykov encapsulation - zapúzdrenie údajov vyjadruje možnosť skryť lokálnu implementáciu týkajúcu sa objektu pred objektami iných tried. Metódy iných tried sa k atribútom označeným príznakom "private" nedostanú. Objekty by navonok mali zverejniť (príznakom "public") čo najmenej svojich atribútov (ideálne žiadne) a čo najmenej operácií (len tie, ktoré sú nevyhnutné). Vďaka tomu v systéme bude vznikať menej vzájomných implementačných závislostí medzi triedami. Nielen že bude kód čitateľnejší, ale bude najmä ľahšie modifikovateľný - v prípade zmien, ktoré sa netýkajú zverejneného rozhrania stačí urobiť zmeny v rámci jednej triedy.

Hoci väčšina systémov sa aj dnes navrhuje v objektovom návrhu, nadšenie z OOP už čiastočne opadlo. Významným faktorom je znovu prechod systémov na web. Jeden typický http request na webový server zväčša znamená len rýchle a efektívne spustenie krátkeho skriptu. Klientský kód sa zasa píše v jazyku Javascript, ktorý kvôli svojej netypovosti zaužívané princípy OOP opustil. Nie je to faktor jediný. Prvotné nadšenie z OOP opadlo kvôli nepraktickosti objektových frameworkov s priveľmi zväzujúcimi hierarchiami tried. Ako uvidíme čoskoro pri nárhovom vzore dekorátor, rozšírenie triedy o nejakú funkcionalitu je možné robiť nielen prostredníctvom relácie generalizácie (dedičnosť), ale aj pomocou relácie agregácie (vzťah celok - časť).

4.4.2. Objektová normalizácia

Z databázových systémov poznáme normálne formy pre dátový model pre relačné databázy. Podobne existujú normálne normy pre objektové dátové modely, ktoré sa od relačných databáz odlišujú najmä tým, že umožňujú v pamäti ľahšie reprezentovať kolekcie dát, t.j. situácia je o niečo jednoduchšia. Podrobný návrh komponentov by sme vždy mali skontrolovať, či spĺňa všetky tri normálne formy.

1ONF: Trieda je v prvej objektovej normálnej forme, ak jej objekty neobsahujú skupinu opakujúcich sa atribútov. Takéto atribúty je potrebné vyčleniť do objektov novej triedy a skupinu opakujúcich sa atribútov nahradiť jednou väzbou na kolekciu objektov tejto novej triedy. Schéma je v 1ONF, ak všetky triedy sú v 1ONF.


Obr. 37: 1ONF - pôvodný model pred normalizáciou obsahuje názov a cenu o troch rôznych produktoch v oboch triedach.


Obr. 38: 1ONF - normalizovaný model vytiahol údaje o produktoch do samostatnej triedy, pričom trojice pôvodných atribútov nahradil odkazom na kolekciu. To umožňuje odkazovať sa aj na viac ako tri atribúty v prípade potreby a odstraňuje nevhodnú duplicitu atribútov.

2ONF: Trieda je v druhej objektovej normálnej forme, ak jej objekty neobsahujú atribút, alebo skupinu atribútov, ktoré by boli zdieľané s nejakým iným objektom. Zdieľané atribúty treba vyčleniť do objektu novej triedy a vo všetkých objektoch, kde sa vyskytovali nahradiť väzbou na tento objekt novej triedy. Schéma je v 2ONF, ak sú všetky triedy v 2ONF.
Obr. 39: 2ONF - model po normalizácii - údaje uvedené teraz v triede Kontrakt boli predtým zdieľané medzi triedami Objednávka a Dodávka, preto ich možno vyčleniť do samostatnej triedy a v oboch triedach použiť referenciu na príslušný kontrakt s podrobnými informáciami. Vďaka tomu môže jeden kontrakt obsahovať aj viacero objednávok a dodávok.

3ONF: Trieda je v tretej objektovej normálnej forme, ak jej objekty neobsahujú atribút alebo skupinu atribútov, ktoré majú samostatný význam nezávislý na objekte, v ktorom sú obsiahnuté. Ak také atribúty existujú, je potrebné ich vyčleniť do objektu novej triedy a v objekte, kde sa nachádzali nahradiť väzbou na tento objekt novej triedy. Schéma je v 3ONF, ak sú všetky triedy v 3ONF.


Obr. 40: 3ONF - model po výslednej normalizácii - údaje o dodávateľoch a klientoch boli oddelené od údajov o kontrakte do samostatnej triedy. To dovoľuje jednej osobe vystupovať vo viacerých kontaktoch bez nebezpečnej duplicity. Naviac, adresy osôb boli tiež vyčlenené do samostatnej triedy. To dovoľuje viacerým osobám zdieľať rovnakú adresu.

Pri navrhovaní reprezentácie dát je potrebné dôkladne zvažovať akými druhmi dotazov budeme dáta vyvolávať. Pre rozličné frekvencie rôznych typov dotazov sa hodia rozličné reprezentácie.

Proces refaktorizácie je proces pri ktorom meníme štruktúru kódu (alebo jeho návrhu) tak, aby sme dosiahli prehľadnejší, prípadne efektívnejší kód. Príkladmi refaktorizácie na úrovni návrhu môžu byť:
  1. presunutie metódy do nadtriedy: metóda nadtriedy sa detí, takže funkčnosť inštancie zostáva nezmenená
  2. presunutie deklarácie dátovej položky do nadtriedy
  3. rozdelenie kódu jednej metódy na dve metódy, kde kód jednej metódy obsahuje volanie druhej metódy
  4. operácie inverzné k op. 1-3
  5. premenovanie mena triedy alebo metódy alebo dátovej položky
  6. vrátane premenovania všetkých volaní alebo použití
  7. vykonanie transformácie podľa pravidla nejakej normálnej formy

4.5. Základné typy softvérovej architektúry

Softvérová architektúra tvorí základnú kostru aplikácie, zahŕňa softvérové komponenty a vzťahy medzi nimi. Architektúra skrýva menej podstatné informácie modulov a je abstraktným pohľadom na systém. Definuje hlavne vzťahy medzi komponentami, ostatné vlastnosti a informácie skrýva. Návrh okrem architektúry obsahuje aj informácie o použitých algoritmoch a dátových štruktúrach a o vzhľade používateľského rozhrania. Architektúra pomáha dosahovať vlastnosti systému resp. bráni ich dosiahnutiu; býva ťažké ju v priebehu projektu meniť. V softvérovom inžinierstve sa zaužívalo niekoľko štandardných architektonických štýlov. Navzájom sa nutne nevylučujú, dajú sa rôzne kombinovať a myšlienky v nich obsiahnuté často slúžia ako inšpirácia pre individuálnu architektúru vytváraného systému.

4.5.1. Pipes and filters

Začnime jednoduchým motivačným príkladom - každý čitateľ tohto dokumentu je zrejme aspoň občasným používateľom OS Linux. Sila rodiny OS Unix spočíva v myšlienke - v jednoduchosti je sila, čo znamená, že UNIX obsahuje množstvo drobných utilít, ktoré je možné navzájom prepájať v skriptoch a tak dosiahnuť obrovskú flexibilitu systému. Jedným z bežných spôsobov prepájania programov je ich reťazenie pomocou operátora pipe (|), ktorý spôsobí, že štandardný výstup jedného programu sa automaticky presmeruje na štandardný vstup ďalšieho programu, takouto kombináciou vieme v príkazovom riadku (command line) jednoducho poskladať užitočné aj komplikovanejšie povely. Napríklad, nasledujúci povel:
$ ps aux | grep programcok | grep -v grep | awk '{print $2}' | xargs kill 
zastaví proces, ktorý bol spustený s menom programcok, pričom ps aux vylistuje podrobný zoznam všetkých procesov, grep programcok vyberie len tie riadky zo zoznamu procesov, ktoré obsahujú slovo programcok, lenže tam sa objaví aj samotný proces grep, takže následne grep -v odfiltruje tie, ktoré obsahujú slovo grep - ostane riadok jediný vo formáte
kluka    18441  0.0  0.0   9608  4252 pts/8    S+   Sep05   4:38 programcok
a pomocou programu awk z neho vyberieme druhý stĺpec obsahujúci id procesu (pid), ktorému pošleme signál 9 príkazom kill s argumentom pid, pričom program xargs zabezpečí, že argumenty programu kill budú poskladané zo vstupu, ktorý dostane príkaz xargs. Každá z uvedených štandardných linuxových utilít robí malú transformáciu, kde transformuje vstupné údaje na výstupné, takým utilitám v architektúre typu pipes and filters hovoríme filtre a sú poprepájané komunikačnými kanálmi (rúrami = pipes).

Z hľadiska architektúry informačného systému nemusí byť zapojenie filtrov len lineárne. Niektoré filtre môžu syntetizovať viacero vstupov do jedného výstupu, alebo naopak produkovať viacero výstupov z jedného vstupu, alebo vo všeobecnosti môžu mať viacero vstupov a výstupov. Poprepájaním fitrov teda vznikne orientovaný graf, ktorý tvorí architektúru v štýle pipes and filters.

Komunikácia nemusí prebiehať cez presmerovaný štandardný vstup a štandardný výstup ako je v našom linuxovom príklade. Každý operačný systém resp. jazyk poskytuje rôzne nástroje - napr. Unix poskytuje komunikačný kanál systémovým volaním pipe(), v každom systéme sú dostupné TCP sockety, vo webovom prostredí websockety, v prostredí Java EE napr. technológia JMS (Java Messaging Service) a ďalšie.

Veľkou výhodou takejto architektúry je vysoká modularita - jednotlivé filtre sú celkom nezávislé od vnútornej implementácie a internej reprezentácie dát iných filtrov, jediné, čo potrebujeme zabezpečiť je zladiť formát dát prenášaných v komunikačných kanáloch. Hociktorý filter je možné nahradiť alternatívnym, ktorý robí z vonkajšieho hľadiska tú istú činnosť, ale dosahuje ju inými prostriedkami. Vysoká modularita umožňuje dobrú znovupoužiteľnosť komponentov a je predpokladom väčšej životnosti softvéru. Obrovskou výhodou tejto architektúry je dobrá paralelizovateľnosť výpočtu, ktorá je prakticky zadarmo - bez toho, aby sa programátor akokoľvek musel starať o problémy synchronizácie procesov, ktoré sú bežné a spôsobujú ťažkosti v iných prístupoch k paralelizácii (napr. výpočtové vlákna - thready). Každý z filtrov, ktorý má vo vstupnom bufri dostupné dáta môže počítať. Ak je vnútorná architektúra filtrov tiež postavená na pipes and filters, tak týmto spôsobom môžeme získať stovky až tísice filtrov, ktoré sa môžu vykonávať súčasne - napr. na modernom paralelnom hardvéri podporujúcom výpočty na GPU.

Nevýhodou tejto architektúry je, že vyžaduje vysoký tok dát - každý filter má typicky na vstupných kanáloch nejaké vstupné bufre, na výstupných zasa výstupné a tak sa pri každej, často aj elementárnej čiastkovej operácii všetky dáta kopírujú cez bufre a interné reprezentácie jednotlivých filtrov. To má logický dopad na nižší výkon v porovnaní s architektúrami, ktoré sú optimalizované na úspornosť zdrojov, hoci často za cenu nižšej prehľadnosti a modularity.


Obr. 41: Schématické znázornenie architektonického štýlu pipes and filters.

4.5.2. Dávkové spracovanie / batch

V niektorých prípadoch je vhodné, aby sa dáta nespracovávali priebežne, on-line, aktuálne, ale všetky naraz, v dávke. Typickým príkladom je spracovanie mesačnej alebo ročnej uzávierky účtovníctva, kde je potrebné vytvoriť požadované mesačné alebo ročné správy, ktoré nie je vhodné vytvárať skôr, keďže položky objednávok, faktúr a transakcií niekedy neprichádzajú v správnom poradí, neskôr sa podľa potreby ešte upravujú a podobne. V dávkovom spracovaní sa všetky údaje pripravia do jedného alebo viacerých dátových zdrojov, odštartuje sa výpočet, ktorý ich rad za radom spracuje a vyprodukuje požadované výstupy. Dávkové spracovanie sa často štartuje automaticky v čase, keď systém nie je zaťažený bežnou prevádzkou (nočné dávkové spracovanie). Tu treba brať zreteľ na ošetrenie mimoriadnych prípadov, vytváranie podrobných záznamov priebehu spracovania dávok, náročnosť ladenia a testovania, keďže si vyžaduje prítomnosť testovacieho tímu mimo bežný pracovný čas. Práca sa pri dávkovom spracovaní typicky člení do jednotlivých úloh (job), ktoré pozostávajú z mnohých položiek (item).

Rozličné vývojárske frameworky majú zabudovanú podporu (knižnice) na riešenie dávkového spracovania. Napr. Java EE obsahuje Batch Processing Framework so sadou tried zabezpečujúcich riadenie dávkového spracovania - programátor píše kód metód, ktoré spracovávajú jednotlivé položky a konfiguruje sekvenčnú alebo paralelnú postupnosť spracovania. Podobne, rozsiahly javovský framework Spring pre vytváranie veľkých podnikových aplikácií obsahuje svoj vlastný Spring Batch Framework.


Obr. 42: Rozdielne prístupy k dávkovému spracovaniu - rozdelenie na paralelne spracovávané položky umožňuje zvýšiť efektívnosť architektonického štýlu batch processing.

4.5.3. Client / server

Client = zákaznik, server = sluha. Ako už názov naznačil, ide o architektúru, kde jedna strana (server) poskytuje nejakú službu, ktorá je typicky dostupná viacerým zákazníkom. V oboch roliach však v architektúre vystupujú softvérové komponenty, nie reálni zákazníci, alebo sluhovia. Komponent sluha teda obsluhuje iný komponent - zákaznika. Poskytuje mu nejakú jasne definovanú službu podľa dohodnutého komunikačného rozhrania. Zákazník oslovuje sluhu, aby mu službu dodal. Sluha môže svoje poskytované služby aj niekde zverejniť, aby o nich zákazníci vedeli a aby sa dozvedeli špecifikáciu rozhrania, ktorým majú sluhu osloviť. Pod službou si tu môžeme predstaviť rozličné veci - či už ide o dodanie nejakých konkrétnych dát alebo súborov z/do úložiska, realizovanie nejakého konkrétneho výpočtu, overenie bezpečnostného certifikátu, obsluha nejakého fyzického alebo elektronického zariadenia, môže ísť o čokoľvek. Medzi problémy, ktoré server musí riešiť, patrí prístup k zdieľaným zdrojom: ak naraz spracováva požiadavky viacerých klientov, alebo naopak serializácia - zoradenie jednotlivých požiadaviek klientov do poradia spracovania podľa stanovených kritérii priority.

Výhodou tejto architektúry je nízke previazanie komponentov (low coupling), zvlášť, pokiaľ je serverovské rozhranie definované tak, že obsahuje len nevyhnutné položky a všetky sú dostupné cez ten istý vstupný bod - čo napr. webový server spĺňa, keďže príma požiadavky v univerzálnom protokole HTTP.

Dnes najrozšírenejším príkladom tejto architektúry je webový server, ktorý poskytuje vyžiadané webové stránky webovým klientom - väčšinou internetovým prehliadačom. Iné príklady servrov sú: tlačový server, databázový server, aplikačný server, ale v roli servera môže vystupovať aj ľubovoľný konkrétny komponent informačného systému a poskytovať nejakú internú službu ostatným komponentom toho istého systému. Komunikácia medzi komponentami typicky využíva nejakú komunikačnú technológiu (napr. TCP/IP - sockety alebo datagramy), alebo priamo technológiu podporujúcu poskytovanie služieb (SOAP, REST a pod.).


Obr. 43: Schématické znázornenie architektonického štýlu client / server.

4.5.4. Master / slave

Ak na zabezpečenie určitej funkcionality nestačí jeden počítač, ale je vhodnejšie použiť celú skupinu počítačov, môžeme využiť architektúru master/slave. Jeden centrálny počítač (master) rozdeľuje prácu a zodpovedá za celkový výsledok. Ostatné počítače (slaves) pravidelne kontaktujú mastera, či pre ne nemá nejakú novú úlohu. Po pridelení čiastkovej úlohy pracujú, až kým ju nevyriešia a napokon svoj výsledok odošlú na mastra. Master čiastkové výsledky integruje do celkového výsledku.

Vo väčšine prípadov je práca nastavená flexibilne vzhľadom na počet pripojených slaveov, ktorí sa k procesu priebežne pripájajú a odpájajú. Master by sa mal postarať aj o situácie, keď slave nedodá svoj čiastkový výsledok včas a prideliť prácu inému slaveovi. Slaveovia, ktorí sú aktívni, masterovi pravidelne hlásia svoj stav - pripravený alebo obsadený.


Obr. 44: Schématické znázornenie architektonického štýlu master / slave.

Architektúra master/slave sa často kombinuje s architektúrou client/server, keď celá skupina master so svojimi slaveami poskytujú nejakú službu clientovi. Client posiela zložitú úlohu na mastera, ktorý ju rozdelí na čiastkové úlohy pre svojich slaveov a po ukončení poskytne celkový výsledok clientovi.


Obr. 45: Kombinácia architektúry client / server a master / slave: server poskytuje výpočtové služby, client odošle vstupné dáta a popis úlohy, ktorú treba vypočítať, na server/master. Ten spravuje skupinu slaveov. Z nej vybere vhodného slavea, ktorý je práve voľný a poskytuje požadovaný typ výpočtu. Odošle mu vstupné údaje a popis úlohy. Po dopočítaní slave pošle výsledok na mastera, kde čaká vo fronte dovtedy, kým si ho client nevyzdvihne. Každý slave sa pravidelne hlási masterovi zaslaním datagramu (protokol UDP), ostatná komunikácia prebieha cez TCP sockety.

4.5.5. Paralelné komunikujúce procesy

Už dávno sa počítače nepoužívajú len ako lepšie kalkulačky - na vykonávanie postupností zložitejších výpočtov. Informačné systémy nahrádzajú množstvo činností, ktoré sa v minulosti robili ručne, výmenou fyzických papierov a dokumentov, komunikáciou reálnych ľudí a inštitúcií a ich rozhodnutiami a pod. Informačné systémy sú teda modelmi reality. Pre realitu je však typické, že množstvo vecí sa deje naraz, súčasne. Informačný systém (keďže za sekundu počítač dokáže vykonať miliardy operácií) takúto paralelnú realitu zvláda obslúžiť aj sekvenčne - stačí, ak si ku každej paralelne vykonávanej aktivite zriadi potrebné dátové štruktúry a ak nejaká aktivita trvá dlhšie, tak na jeden raz z nej urobí vždy len jeden malý krok, aby výsledok vyzeral tak, že všetky potrebné aktivity sústavne napredujú. Avšak, ak bude vnútorná architektúra informačného systému lepšie zodpovedať realite - to znamená každú z paralelne vykonávaných operácií obslúži samostatný výpočtový proces (alebo výpočtové vlákno - thread), tak bude výsledný informačný systém prehľadnejší, zrozumiteľnejší, jeho architektúra bude pre túto situáciu vhodnejšia. A to je základ myšlienky architektonického štýlu paralelných komunikujúcich procesov.

Príkladom môže byť bankový informačný systém, ktorý naraz umožňuje viacerým zákazníkom vyberať / vkladať v bankomatoch (po anglicky ATM - automated teller machine). Namiesto toho, aby jeden centrálny bankový systém neustále komunikoval so všetkými aktívnymi ATM, môže byť každý zákazník obslúžený samostatným procesom. Výhodou je, že tento proces sa môže zákazníkovi neustále venovať a napr. reagovať okamžite na jeho interakciu (rozhodne sa prerušiť transakciu, a pod.), aj keď spracovanie jeho operácií v banke trvá najaký čas - deje sa asynchrónne, v pozadí.

Podobná situácia nastáva v systémoch, ktoré komunikujú s akýmikoľvek fyzickými entitami - nielen ľuďmi, napr. obsluha rozličných zariadení, strojov, senzorov vo fabrikách alebo v iných automatizovaných systémoch, vstupno/výstupných zariadení počítača, alebo aj rôznych úloh, ktoré informačný systém zabezpečuje súčasne a nesúvisia priamo s vonkajším fyzickým svetom - každá úloha môže byť riešená v samostatnom procese.

Dôležitým rysom v tejto architektúre je zvolenie vhodného komunikačného a synchronizačného protokolu vrátane komunikačnej i synchronizačnej technológie - procesy či vlákna?, dátové štruktúry v zdieľanej pamäti, či sockety, alebo webové sľužby?, flagy/semafóry/mutexy/monitory/bariéry? zbernica/sériová komunikácia/počítačová sieť?

Variantom tejto architektúry je multi-agentová architektúra, ktorá sa vyznačuje tým, že každý proces (v tomto prípade agent) si užíva vysoký stupeň autonómnosti, čiže väčšinou sám zodpovedá a sám riadi svoje konanie, má k dispozícii spôsoby ako zbierať informácie z prostredia, v ktorom pôsobí a spôsoby, ktorými môže vykonávať v prostredí akcie podľa svojho rozhodnutia. Multi-agentová architektúra dosahuje vysokú modularitu a znovupoužiteľnosť, v multi-agentových systémoch typicky možno pridávať/odoberať agentov bez toho, aby to ovplyvnilo činnosť zvyšku systému.

Samotný architektonický štýl paralelných procesov ani multiagentová architektúra neodpovedajú na množstvo otázok, ktoré musia návrhári pri využití tohto štýlu vyriešiť a väčšinou sa kombinuje s nejakými inými architektonickými štýlmi.

4.5.6. Systémy založené na udalostiach

Koncept, ktorý s udalosťami úzko súvisí, je stav. Každá udalosť, ktorá sa niekde udeje - či už v reálnom svete, alebo v informačnom systéme, má za následok, že sa nejakej entite zmenil stav. Napríklad: udalosť Bill udrel Freda znamená, že sa Fredovi zmenil stav brady, lebo ju už má rozbitú. Vybudovanie informačného systému podľa tohto architektonického štýlu znamená, že väčšina jeho funkcionality sa deje, resp. aktivuje vtedy, keď sa zmenil stav, čiže nastala nejaká udalosť. Udalosť vedie k notifikácii (poslanie správy) tých komponentov, ktoré na danú zmenu stavu chcú nejakým spôsobom reagovať. Následkom notifikácie o udalosti je vykonanie postupnosti akcií. Tie potenciálne môžu viesť k ďalším zmenám stavu a teda k aktivovaniu ďalšej a ďalšej funkcionality.

Čitateľ si určite rád ako cvičenie predstaví relevantné príklady využitia tejto architektúry. Tu si predstavme akademický informačný systém: štúdijný program, ktorý je zverejnený na fakultnej webovej stránke, vie ručne vygenerovať (vyexportovať) správca AISu. Vhodnejší model by bol, ak by sa po každej zmene v informačnom liste nejakého predmetu (udalosť => zmena stavu) funkcionalita exportu aktivovala automaticky. Modul, ktorý export realizuje, sa vopred zaregistruje, aby dostával o zmenách v informačných listoch notifikácie. Ešte lepšia možnosť: notifikáciu nedostane nejaký exportovací modul, ale objekt, ktorý zodpovedá príslušnému štúdijnému programu. Každý štúdijný program potom odchytáva notifikácie o zmenách vo všetkých svojich predmetoch. Ak je nejaký predmet zaradený vo viacerých štúdijných programoch, automaticky takto dojde k vyexportovaniu všetkých z nich.

Tento architektonický štýl sa mimoriadne dobre hodí na programovanie grafických používateľských rozhraní (GUI), ktoré fungujú na princípe udalostí - interakcie používateľa so systémom - výber v menu, stlačenie tlačidla, navigácia na stránke, to sú všetko udalosti. Treba len pripomenúť, že GUI nie je jediné využitie tohto štýlu a udalosti môžu zodpovedať aj ľubovoľnej zmene akejkoľvek entity, ktorú systém modeluje.

Do extrému vo využití tohto architektonického štýlu ide programovaci jazyk JavaScript, kde sa cez notifikácie na udalosti realizuje úplne všetko. Táto filozofia vyplýva z dvoch cieľov: 1) krátka odozva na interakciu používateľa s webovou stránkou, 2) jednovláknová architektúra - všetko sa deje v tom istom výpočtovom vlákne, čo dramaticky zamedzuje vzniku problémov pri synchronizácii viacerých vlákien. Aby sa pomocou jedného výpočtového vlákna dosiahla rýchla odozva, akékoľvek operácie, ktoré trvajú nejaký nezanedbateľný čas je potrebné urobiť asynchrónne a ich ukončenie považovať za udalosť, ktorá generuje notifikáciu, na ktorú sa zareaguje v najbližšom možnom čase - keď dojde na rad pri jednovláknovom spracovaní všetkých už čakajúcich notifikácií.

Postupné vykonávanie udalosťami aktivovaného kódu sa často realizuje dátovou štrktúrou event queue. V okamihu, keď nejaká udalosť nastane, sa požiadavka na jej spracovanie zaradí na koniec frontu. Tam počká až dovtedy, kým na ňu nepríde rad. Ostatné udalosti čakajúce vo fronte pred ňou nastali skôr. Preto budú spracované prv. Aby reakcia systému na udalosti netrvala dlho, je potrebné, aby spracovanie ľubovoľnej udalosti prebehlo v čo najkratšom čase. Aplikácie môžu generovať udalosti napríklad aj preto, že chcú odštartovať vykonávanie nejakej inej časti kódu, niekedy čoskoro potom, čo dokončia spracovanie svojej požiadavky, prípadne nastavia generovanie istej udalosti v pravidelných časových intervaloch.

4.5.7. Architektúra zameraná na služby (Service Oriented Architecture, SOA)

Ide o jeden z modernejších štýlov, blízky príbuzný architektúr software as a service (SAAS), data as a service, platform as a service a všetko objímajúci cloud. Vychádza zo stále väčšej potreby prepájania rôznych aplikácií a služieb, ktoré niekedy v čase návrhu ani nie sú známe. To si vyžaduje pri zverejnení nejakej služby zverejniť aj rozhranie, ktorým je táto služba dostupná. A to v takom formáte, aby mu iný informačný systém mohol porozumieť automaticky, bez potreby zásahu vývojára. Typickým príkladom sú webové služby (web services) vybudované technológiou SOAP. Takáto webová služba, ktorá je dostupná cez Internet, zverejňuje aj tzv. SOAP descriptor, čo je XML súbor podrobne popisujúci zverejnené rozhranie. Tým pádom je voči takémuto descriptoru možné automaticky vytvoriť triedy, ktoré takéto služby volajú a plynule ich zaradiť do systému, ktorý bol vyvinutý skôr ako samotná služba. V dnešnej rýchlo sa meniacej dynamickej dobe je takto možné priebežne vyberať z dostupných servrov, ktoré požadované služby poskytujú. Tento medzikrok často realizuje broker, u ktorého sa jednotlivé servre poskytujúce služby registrujú a ktorý dokáže realizovať požiadavky klientov prispôsobené na rozhranie toho-ktorého servra.


Obr. 46: Service-oriented architecture.

4.5.8. Virtual machine

Pod pojmom stroj (machine) sa v tomto kontexte chápe počítač ako taký. Počítač ako zariadenie, ktoré dokáže realizovať výpočet podľa zadaného programu. Virtuálny stroj je teda tiež počítač, ktorý realizuje výpočet podľa zadaného programu, ale nie fyzický, ale len virtuálny - čiže je to model fiktívneho počítača. Reálny počítač je nahradený softvérom, ktorý ho emuluje, virtuálnym strojom.

Výhody tohto prístupu sú viaceré. Jednak programy, ktoré sú napísané pre virtuálny stroj a nie pre reálny stroj, môžu bežať na ľubovoľnom reálnom stroji, na ktorom je k dispozícii príslušný virtuálny stroj. Ďalej, tento výpočet môže byť pod lepšou kontrolou - virtuálny stroj môže neustále monitorovať, čo program robí a priraďovať mu práva, obmedzenia, priority, spravovať jeho zdroje podľa potreby. Ale hlavne - virtuálny stroj nemusí byť univerzálnym počítačom s operačným systémom, ktorý poskytuje všetky komplexné služby, ale len jednoduchým jednoúčelovým interpretrom, ktorý dokáže spracovávať skripty riešiace úzku vymedzenú skupinu úloh. Napriek tomu v rámci takto vymedzeného sveta poskytuje veľkú flexibilitu a univerzálnosť a nie je zaťažený rozhodnutiami o poskytovanej funkcionalite vytvorenej v čase návrhu systému, až v čase vytvárania skriptov, ktoré virtuálny stroj spracováva. To môže byť oveľa neskôr, dávno po jeho nasadení do prevádzky.

V učebnici Software Engineering - Modern Approaches je uvedený nasledujúci príklad programu spracovávaného virtuálnym strojom, ktorý mohol napísať v takto špecializovanom jazyku aj samotný používateľ:
Balance checking / add excess to account + subtract deficit from saving;
Save report / c:Reports + standard headings + except replace "Ed'' by "Al'' PrintReport / standard headings
e-mail report to Jayne@xyz.net.

4.5.9. Repository

V tomto architektonickom štýle sú základom pre architektúru systému dáta, množstvo dát. Často sú tieto dáta trvácne a v systéme sa k nim pristupuje viacerými spôsobmi, z viacerých komponentov, viacerými používateľmi. Vtedy má zmysel dáta uskladniť v centrálnom sklade dát - typicky v databáze. Repozitár môže mať aj inú podobu - napríklad súborový alebo webový server, na ktorom je uložených množstvo súborov alebo hypertextových dokumentov tiež spadá pod tento architektonický štýl, alebo centrálna adresárová služba, ktorá eviduje autentifikačné údaje používateľov, ktoré sú spoločné pre celú rodinu aplikácií.

Samostatným variantom je tzv. blackboard architektúra, kde blackboard je úložiskom prevažne dočasných dát a slúži na výmenu údajov medzi jednotlivými komponentami v zmysle: všetci vidia na tabuľu, každý na ňu môže čokoľvek napísať a tým sa dorozumievať s ostatnými - blackboard môže byť komunikačnou platformou v multi-agentových systémoch. Výhodou architektúry v štýle repository je možnosť centrálneho riešenia zálohovania, bezpečnosti a prístupových práv, zotavenia z poruchy a pomerne dobrá možnosť dopĺňania ďalšej funkcionality, ba i aplikácií, ktoré pracujú s údajmi v repozitári. Medzi nevýhody patrí komplikovanosť dátového modelu - ak databáza zahŕňa všetky údaje z celého systému, množstvo závislostí je veľké a málo prehľadné - čo v prípade nutnosti zmeny dátového modelu spôsobí problémy, centrálne zabezpečenie niektorých služieb (zálohovanie, bezpečnosť...) nemusí vyhovovať všetkým častiam aplikácie. V prípade veľkej prevádzky nemusí repozitár stačiť obslúžiť všetky požiadavky a distribuovanie repozitára na viacero počítačov môže byť komplikované.


Obr. 47: Príkladom frameworku, ktorý zovšeobecňuje prístup k repozitárom rôznych druhov je oraclovský Data Anywhere Architecture a jej Repository API.

4.5.10. Hierarchická / vrstvová

Ako dobrá ilustrácia nám tu môže poslúžiť organizácia softvéru na bežnom PC. Na najnižšej vrstve je samotný hardvér - procesor, pamäť, vstupné a výstupné zariadenia, ktoré komunikujú na nízkoúrovňovom protokole a svoju funkcionalitu vystavujú cez vstupno/výstupné porty dostupné cez inštrukcie strojového kódu OUT a IN, resp. cez priamy prístup do pamäte. S týmto hardvérom na tejto úrovni programy nikdy nekomunikujú. Na vrstve nad hardvérom je jednak základný systém, ktorý je uložený v pamäti ROM - BIOS (basic input/output system), alebo jednotlivé hardvérové ovládače, ktoré sú zavedené do jadra operačného systému. S nimi komunikujú všeobecnejšie služby operačného systému (súborový systém, vstup z klávesnice, myši, výstup na obrazovku), nad nimi sú ďalšie, ešte všeobecnejšie služby operačného systému (grafický okienkový manažer, správca programov a procesov a pod.) Tieto služby sú využívané dynamicky i staticky linkované knižnicami, poskytujúcimi komplexnú funkcionalitu rôznym aplikáciám a o vrstvu ďalej nájdeme samotné aplikačné programy... Každá vrstva komunikuje s vrstvou pod sebou a poskytuje o rád všeobecnejšiu funkcionalitu vrstve nad ňou.


Obr. 48: Príklad hierarchickej / vrstvovej architektúry pri využití technológie OpenGL.

Vrstvová hierarchická architektúra sa nemusí týkať len celého počítača a operačného systému. Tu sa zaoberáme informačnými systémami a nie operačnými systémami. V tomto štýle môžu byť vybudované aj samotné aplikácie/informačné systémy. Jednotlivé vrstvy sú typicky realizované balíčkami tried (packages), ktoré skrývajú podrobnosti pred ďalšími vrstvami. Pre dosiahnutie jednotlivých zložiek celkovej funkcionality aplikácie môže existovať viacero paralelných vrstvení. Je vecou designu, na aké konkrétne vrstvy a do koľkých vrstiev bude návrh rozdelený. Vrstvová architektúra (layered architecture) úzko súvisí s tzv. "Three tier" architektúrou, kde je informačný systém rozdelený na 3 samostatné poschodia - prezentačné (používateľské rozhranie), dátové (úložisko perzistentných dát - databáza) a aplikačné (logika, stredné poschodie). Rozdiel medzi "three tier" a "layered architecture" je v tom, že pri "three tier" beží každé poschodie na inej infraštruktúre/platforme (napr. webový prehliadač - prezentačné poschodie, aplikačný server - aplikačné poschodie, databáza - dátové poschodie. Analogicky môže existovať "one tier" aplikácia, ktorá celá beží na jednej platforme (desktop alebo mobil), ale má (napríklad) tri vrstvy - vtedy ide o vrstvovú architektúru.

4.5.11. Zdieľaná pamäť vs. skrývanie informácií

Architektonický štýl zdieľaná pamäť niekedy označuje skupinu štýlov (Blackboard, Data-centric, Rule-Based system), ale v našom kontexte máme na mysli to, že jednotlivé komponenty informačného systému majú uložené údaje v spoločnej pamäti a majú k nim spoločný prístup. Je to v zásadnom rozpore so štýlom skrývanie informácií, ktorý vychádza z enkapsulácie v objektovo-orientovanom programovaní. Pri použití zdieľanej pamäte sa porušuje základný cieľ pri tvorbe návrhu - minimálne rozhrania, keďže komponenty majú prístup k detailným údajom uloženým v zdieľanej pamäti a vznikajú medzi reprezentáciou dát a jednotlivými komponentami závislosti, ktoré je vhodné pri návrhu minimalizovať. Jeho využitie je napriek tomu na mieste vtedy, keď sú v zdieľanej pamäti uložené (väčšinou) nemenné údaje veľkého rozsahu, s ktorými potrebuje pracovať viacero komponentov - často, opakovane, rýchlo. Namiesto toho, aby si komponenty tieto údaje medzi sebou preposielali - a tým zaťažovali zbernicu, procesor i pamäť vytváraním osobitných kópií, údaje sú uložené v pamäti len raz a všetky komponenty s nimi môžu pracovať. Napríklad, obrázok z kamery s obrovským rozlíšením, v ktorom rôzne algoritmy využívajú rôzne údaje, iné ho zasa vizualizujú, škálujú, alebo inak spracovávajú - stačí, aby bol v pamäti len jeden raz. Komunikácia cez zdieľanú pamäť je maximálne rýchla, pretože je priama - počas komunikácie nevyužíva žiadne medzivrstvy operačného systému, nepotrebuje prepínanie kontextu medzi user a kernel módom. Vo väčšine operačných systémov je komunikácia cez zdieľanú pamäť možná aj medzi rôznymi procesmi. Systémové volania OS dovoľujú alokovať úsek pamäte, ktorý si viaceré procesy namapujú do svojho adresného priestoru. Napríklad v systémoch Linux existujú systémové volania shmget(2), shmat(2), vo Windows sú to CreateFileMapping(), OpenFileMapping().

4.5.12. Microservices

Tento architektonický vzor je najviac up-to-day so súčasným dianím vo svete informačných systémov a údajne je základom takých gigantov, ako sú Netflix, eBay, Amazon, the UK Government Digital Service, realestate.com.au, Forward, Twitter, PayPal, Gilt, Bluemix, Soundcloud, The Guardian a mnohých ďalších. Štýl vychádza z notorických skúseností vývojárov o častej potrebe zmien požiadaviek počas reálneho nasadenia systému. Preto sa usiluje o maximálne oddelenie komponentov, ktoré tvoria systém - každý z nich je samostatnou aplikáciou, ktorá poskytuje čo najmenšiu množinu konzistentných služieb ostatným komponentom, typicky cez nejaký rýchly, jednoduchý a transparentný protokol (napr. REST). Realizovanie zmeny v systéme si potom vyžaduje len úpravu niektorej služby a minimálnú vyžiadanú úpravu rozhraní služieb, takýto systém sa jednoduchšie aktualizuje priamo počas prevádzky systému, dovoľuje inkrementálny vývoj a plynulé nasadzovanie jednotlivých častí ako sa dokončujú. Každý komponent je jednoduhcšie samostatne otestovateľný. Microservices sú v kontraste so systémami, ktoré sa spoliehajú na pokročilé a komplikované komunikačné platformy (enterprise service bus), ktoré sú typické pre SOA. Naopak, microservices používajú čo najjednoduchšie komunikačné kanály a s čo najjednoduchšími rozhraniami - a preto ich popularita rastie. Narozdiel od bežných podnikových aplikácií, ktoré zvyknú ukladať údaje do jednej spoločnej databázy má typicky každá služba v rámci tejto architektúry svoje perzistentné úložisko. To potenciálne vedie k dočasným vzájomným nekonzistenciam údajov a jednotlivé služby sa musia medzi sebou nejak synchronizovať, čo môže predstavovať výzvu, niekedy až prekážku pri nasadzovaní aplikácií podľa tejto architektúry.

5. Návrhové vzory

Návrhové vzory sú ustálené postupy pri tvorbe návrhu, ktoré vývojári informačných systémov používajú znova a znova a preto im pre zjednodušenie dali meno a podrobne ich analyzovali, aby pri tvorbe ďalších systémov, v ktorých sa rovnaké situácie znovu vyskytnú, mohli využiť existujúce skúsenosti a priamo v nich aplikovať optimálne postupy. Týmto sa podobajú na architektonické štýly. Rozdiel je v tom, že návrhové vzory často riešia len malý čiastkový problém v návrhu, zatiaľ čo architektonické štýly ovplyvňujú celkovú architektúru aplikácie.

Každý návrhový vzor je určený svojim menom, krátkym popisom účelu, a vychádza z nejakej konkrétnej situácie v reálneho života pri tvorbe informačného systému. Viaceré zdroje pre každý konkrétny návrhový vzor ukazujú príklad implementácie zodpovedajúcej situácie, popisujú roly zúčastnených prvkov v danej situácii, zakresľujú triedny a objektový diagram zovšeobecnenej situácie a uvádzajú výskyty návrhového vzoru v známych informačných systémoch.

Vychádzajúc z knihy Design Patterns (Erich Gamma et.al.) si pomenujme 22 známych návrhových vzorov, ktoré su v nej uvedené. Delia sa na tri typy: Creational - slúžia alebo nejak súvisia s vytváraním nových inštancií, Structural - určujú štruktúry, ktoré zjednodušujú stavbu návrhu, jeho architektúru, Behavioral - pokrývajú určité správanie, interakciu medzi objektami.

5.1. Creational Patterns

Tieto návrhové vzory sa týkajú spôsobu vytvárania nových objektov.

5.1.1. Abstract Factory
Provide an interface for creating families of related or dependent objects without specifying their concrete classes

Abstract Factory je trieda (príp. interface), ktorá poskytuje funkcie na vytváranie inštanciíi nejakej skupiny tried. Namiesto toho, aby sme priamo volali konštruktory príslušných tried, ktorých inštancie chceme na danom mieste vytvoriť, si vypýtame referenciu na factory ("fabriku"). Jej metódy vedia vrátiť nové inštancie potrebných typov. V skutočnosti k danej abstract factory existuje jedna (väčsino viacero) podtried - concrete factory, ktoré prekrývajú uvedené metódy. Inštancie vracajú až implementácie metód v podtriedach (v concrete factories).

Význam takéhoto triku spočíva v tom, že náš kód sa stáva nezávislý od konkrétnych implementácii potrebných tried. Inštancie, ktoré takto získame spĺňajú požadované vlastnosti, ale v skutočnosti sú inštanciami nám neznámych tried, ktoré sú podtriedami nami požadovaných tried. V závislosti od prostredia, v ktorom náš kód beží, môžeme získať inú "konkrétnu fabriku", ktorá vracia objekty iných tried, ale tieto implementačné detaily sú pre náš kód skryté. Vďaka tomu je náš kód prenositeľnejší a môže fungovať v rozličných prostrediach bez zmien. Abstract factory je väčšinou súčasťou nejakého frameworku a týmto spôsobom poskytuje jednotné rozhranie pre aplikácie aj keď je framework implementovaný pre rozličné platformy.

Príkladom je framework pre vytváranie rôznych GUI widgetov - okienok, scrollbarov, dialógov, progressbarov a podobne. Aplikácia, ktorá chce vytvárať objekty uvedených typov, požiada framework o "fabriku". Framework - podľa toho, na ktorej platforme práve beží, vráti "fabriku", ktorá vracia objekty pre príslušnú platformu - napr. v systéme MS Windows vráti objekt, ktorý vie zobraziť windowsové okno, v systéme xwindows vráti objekt, ktorý zobrazuje X-ovské okno. Aplikácia od "fabriky" takto získava objekty, ktorých typ je všeobecný (napr. okienko) a nestará sa o to, na ktorej platforme práve beží.

Abstract factory má často metódy podľa vzoru factory method, ale môže využiť aj prototype. Concrete factory je často singleton.


Obr. 49: Štruktúra návrhového vzoru Abstract Factory (Wikimedia).

5.1.2. Builder
Separate the construction of a complex object from its representation so that the same construction process can create different representations.

Builder je abstraktná trieda, ktorá ponúka sadu čiastkových krokov, z ktorých je možné skladať zložitejšie objekty. Tento abstraktný builder má viacero konkrétnych podtried (konkrétnych builderov), ktorí tie isté čiastkové kroky realizujú iným spôsobom, iným štýlom, v inom formáte a podobne. Vďaka tomu môžeme napísať algoritmus, ktorý pozostáva z týchto čiastkových krokov, ale ktorý je nezávislý od toho-ktorého podrobného formátu. Náš algoritmus využíva abstraktný builder a ním definované metódy, ktoré sa v skutočnosti realizujú jednou z možných implementácií v jednom z konkrétnych builderov prekrývajúcich príslušné metódy.

Príkladom takéhoto buildra môže byť konverzia textu. Abstraktný builder ponúka elementárne stavebné kroky ako - pridať znak, ukončiť odstavec, zmeniť font textu a podobne. Konkrétne buildery môžu byť napr. tri rôzne - jeden, ktorý produkuje plain ASCII text, druhý, čo produkuje TeX-ový zdroják, tretí, ktorý zobrazuje text v nejakom grafickom widgete. Každý z nich interpretuje jednotlivé kroky po svojom. Trieda, ktorá tento builder využije môže mať za úlohu zparsovať (prečítať) súbor vo formát RTF. Počas dekódovania RTF súboru postupne volá jednotlivé krokové operácie konverzného buildra. Tento algoritmus prečítania RTF súboru bude však univerzálny a môžeme ho ľahko spojiť s ľubovoľným typom konvertera (plain ASCII, TeX, widget) bez toho, aby sme ho akokoľvek potrebovali meniť.


Obr. 50: Príklad využitia návrhového vzoru Builder.

5.1.3. Factory Method
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

Factory method je taká metóda v nejakej abstraktnej triede (túto triedu nazvime Creator), ktorá zodpovedá za vytvorenie určitého typu inštancie (tento typ nazvime Product). V skutočnosti však inštanciu vytvára prekrývajúca metóda v nejakej konkrétnej podtriede Creatora a vracia inštanciu nejakej podtriedy triedy Product. Napriek tomu môžu iné metódy Creatora použiť túto factory method - len vždy dostanú inštanciu z nejakej vhodnej zodpovedajúcej podtriedy triedy Product, podľa toho, na ktorej podtriede Creatora sú volané.

Trieda Creator a Product je teda typicky súčasťou nejakého frameworku, pričom súčasťou tohto frameworku je aj nejaká ďalšia funkcionalita využívajúca inštancie typu Product. Používateľ tohto frameworku - nejaká naša cieľová aplikácia definuje podtriedu Creatora - nejakého konkrétneho Creatora, ktorého prekrývajúca factory method bude vracať inštanciu nejakej našej triedy odvodenej od frameworkovej triedy Product.

Napríklad, si predstavme framework, ktorý umožňuje evidovať viacero dokumentov používateľa a už má implementovanú metódu NewDocument(), ktorá zavolá factory method na vytvorenie dokumentu (ten však framework nedefinuje) a pridanie tohto dokumentu do zoznamu evidovaných dokumentov. Náš systém, ktorý takýto framework využije vytvorí podtriedu triedy, ktorá eviduje dokumenty a prekryje v ňom factory method, ktorá bude vytvárať dokument nášho typu. Táto situácia je zachytená na nasledujúcom obrázku, pričom trieda Application je v roli Creator, trieda Document je v roli Product, MyApplication je v roli ConcreteCreator a MyDocument je v roli ConcreteProduct.


Obr. 51: Príklad použitia návrhového vzoru Factory Method.

5.1.4. Prototype
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

Opäť si pomôžme motivačným ilustračným príkladom zo sveta OS Linux. Vytváranie nového procesu v unixových systémoch sa realizuje pomocou systémového volania fork(). Toto volanie zduplikuje proces, ktorý fork() zavolal. Výsledkom je, že namiesto predchádzajúceho jedného procesu bežia v systéme zrazu dva identické procesy, ktoré sa (zjednodušene povedané) líšia len v návratovej hodnote volania fork() - pôvodný (rodičovský) proces dostane nenulový identifikátor (pid) novo-vytvoreného procesu, nový proces (dieťa) dostane nulu. Keďže programová pamäť je read-only (proces nemá možnosť meniť za behu svoj vlastný kód), táto pamäť je zdieľaná medzi oboma procesmi. Všetky dáta aj informácie, ktoré o procese eviduje operačný systém, sa zduplikujú (v prípade vhodnej implementácie sa dáta môžu zduplikovať až pri prvom zápise do príslušnej stránky - technika copy on write). Tento postup (fork()) sa používa aj vtedy, keď nejaký proces chce odštartovať iný program - najskôr sám seba zduplikuje pomocou fork() a až potom jeho dcérsky proces zavolá systémové volanie exec(), ktoré nahradí aktuálne bežiaci program novým, načítaným zo spustiteľného súboru. Prečo je to tak?

Operačný systém eviduje o procesoch množstvo informácií - prístupové práva, otvorené súbory, premenné prostredia, priorita a pod. Pri vytvorení nového procesu tak povediac "na zelenej lúke" by musel stráviť netriviálny čas tým, aby zistil, čo všetko má do týchto svojich interných tabuliek o novom procese povypĺňať. Oveľa jednoduchšie je zobrať údaje o nejakom existujúcom procese (a najlepšie rovno o tom, ktorý ten nový proces vytvára) a skopírovať ich - naklonovať ich. Je to rýchlejšie, úspornejšie a jednoduchšie. A to je zároveň myšlienka návrhového vzoru Prototype pri objektovom návrhu OOP (pozor! ilustračný príklad s fork() je len analogická situácia, ilustračný príklad na pochopenie princípu, ale tam ide o niečo iné ako o návrh systému v OOP).

Návrhový vzor prototyp predpisuje, že nové inštancie nejakej triedy (alebo často skôr skupiny tried zastrešenej nejakou spoločnou abstraktnou nadtriedou) sa nevytvárajú volaním konštruktora. Namiesto toho sa vyrábajú naklonovaním nejakej existujúcej inštancie (napr. v jazyku Java obsahuje každá trieda metódu Clone()). Výsledkom je zjednodušenie a zrýchlenie kódu a tým aj zamedzenie vzniku potenciálnych chýb.

5.1.5. Singleton
Ensure a class only has one instance, and provide a global point of access to it.

Asi najjednoduchší návrhový vzor, ktorý hovorí o tom, že nejaká trieda má v celom systéme iba jednu inštanciu - v celej aplikácii existuje jediný objekt danej triedy. Táto trieda by mala poskytovať nejakú statickú (triednu) metódu, ktorá vráti príslušnú inštanciu. V prípade, že inštancia ešte neexistuje, najskôr ju vytvorí.

Singleton využívame napríklad v prípade, že potrebujeme nejaké globálne nastavenia, ktoré majú byť zdieľané a viditeľné v celej aplikácii, môže ísť o nejaké globálne počítadlo, či štatistiky, debugovací, či logovací komponent. V niektorých prípadoch sa môže hodiť, ak singleton je súčasťou nejakého frameworku a aplikácia si definuje svoju vlastnú verziu, odvodenú od singletonovej triedy, v takom prípade sa na vytváranie jeho inštancie často používa factory method namiesto konštruktora.

5.2. Structural Patterns

Druhá skupina návrhových vzorov rieši rozličné situácie v návrhu, kde sa z jednotlivých objektov a tried formujú zložitejšie štruktúry, ktoré ale majú nejaký zaužívaný účel, formu, či vlastnosti.

5.2.1. Adapter
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

Tento bežný návrhový vzor (tiež nazývaný Wrapper) potrebujeme vždy vtedy, keď potrebujme využiť nejakú existujúcu knižnicu, framework, alebo implementáciu, ale trieda, ktorá v nej poskytuje potrebnú funkcionalitu má iný interfejs, ako v našom prípade má mať. Preto impelementujeme "obaľovaciu" triedu, ktorá nič nerobí, len prekladá formát volaní z jedného interfejsu na druhý.


Obr. 52: Príklad použitia návrhového vzoru Adapter.

V príklade chceme využiť existujúcu triedu TextView, aby sme ju zaradili do kresliaceho editora, ktorý vyžaduje, aby všetky nakresliteľné prvky spĺňali predpis definovaný abstraktnou triedou Shape. Hoci TextView obsahuje väčšinu potrebnej funkcionality, metódy majú iné názvy. Napríklad metóda GetExtent() vráti obdĺžnik, v ktorom sa textový element nachádza a mala by sa volať BoundingBox(). Preto vytvoríme adaptér TextShape, ktorý bude "obalovať" inštanciu triedy TextView: jeho metóda BoundingBox() len prepošle výsledok metódy GetExtent(). V komplikovanejšom prípade by formát dát mohol byť iný (napr. relatívna pozícia namiesto absolútnej) a adapter by musel preposielané údaje aj nejakým jednoduchým spôsobom transformovať. Naopak, niektorá funkcionalita v obalovanej triede nemusí byť vôbec prítomná a úlohou adaptéra je doplniť ju - v tomto prípade pridáva metódu CreateManipulator() a samostatnú triedu TextManipulator, ktorá potrebnú funkcionalitu dopĺňa.

5.2.2. Bridge
Decouple an abstraction from its implementation so that the two can vary independently.


Obr. 53: Problematická situácia, ktorá vedie k použitiu návrhového vzoru Bridge.

Za návrhovým vzorom Bridge sa skrýva pomerne komplikovaný, ale o to zaujímavejší koncept. Vysvetlime si to na nasledujúcom príklade. Predstavme si knižnicu pre programovanie používateľského rozhrania, ktorá chce byť prenositeľná na rôzne platformy a mala by fungovať v rozličných okienkových systémoch. Túto platformovú prenositeľnosť môžeme dosiahnuť napríklad pomocou generalizácie - aplikácia bude používať abstraktnú triedu Window a každá okienková platforma zadefinuje svoju podtriedu (napr. XWindow, WPFWindow a pod.) Aplikácia potom bude vytvárať inštanciu príslušnej podtriedy a pracovať s ňou pomocou univerzálneho typu Window.

Toto riešenie (bez použitia nejakej abstract factory) prináša problém, lebo náš kód, ktorý bude knižnicu využívať, bude predsa len platformovo závislý (vytvára predsa inštanciu konkrétnej podtriedy), ale čo horšie, ak sa knižnica bude rozrastať a bude chceť vytvárať rôzne špecializačné podtriedy triedy Window - napr. triedu IconWindow, ktorá slúži trebárs na vizualizáciu ikoniek vo forme okienok, narazíme na ťažkosti. V tomto prípade bude od triedy Window odvodená trieda IconWindow, lenže, aby sme dosiahli prenositeľnosť na platformy, každá platforma bude musieť definovať aj svoju podtriedu triedy IconWindow (XIconWindow, WPFIconWindow). Pridanie ďalšej platformy si vyžiada pridanie tried pre každý typ okna... To už vedie k pomerne nepraktickému organizovaniu kódu.

Myšlienka návrhového vzoru Bridge je vytvorenie dvoch paralelných hierarchií - jedna bude riešiť otázku platformy, ale ponúkne dostatočnú sadu elementárnych operácií tak, aby bolo možné vytvárať podtriedy v druhej hierarchii, ktorá už bude od implementácie celkom nezávislá a bude sa týkať iných aspektov - okienko pre ikonky, dočasné okienko (transient) a pod. Nasledujúci obrázok zachytáva triedny diagram pre opísaný príklad.


Obr. 54: Príklad použitia návrhového vzoru Bridge.

Na pravej strane je hierarchia implementácií pre rozličné okienkové systémy. Abstraktná trieda WindowImp obsahuje všetky potrebné elementárne operácie, ktoré sú platformovo špecifické. Ostatná funkcionalita frameworku si vytvára vlastnú - platformovo nezávislú hierarchiu, pričom trieda Window bude len obsahovať referenciu na príslušnú práve využívanú implementáciu.

5.2.3. Composite
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

Tento návrhový vzor je veľmi zrozumiteľný - ide o vytvorenie stromovej štruktúry. Typickým príkladom je grafický editor, kde používateľ môže kresliť elementárne tvary (kružnica, čiara, obdĺžnik, text), ale editor mu zároveň dovoľuje vytvárať tvary nové, ktoré vznikajú zoskupovaním existujúcich označených tvarov (funkcia "group"). Takto vytvorené tvary sa zasa správajú ako elementárne a používateľ ich ďalej môže zoskupovať do väčších tvarov. Vzniká stromová štruktúra obsahujúca elementárne tvary a ich zoskupenia. Triedny diagram pre opísanú situáciu je zobrazený na nasledujúcom obrázku.


Obr. 55: Príklad použitia návrhového vzoru Composite.

5.2.4. Decorator
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

Návrhový vzor Decorator je nádhernou ukážkou obmedzení vytvárania hierarchií tried v OOP a príkladom ako sa s nimi dá vysporiadať iným spôsobom. Predstavme si ešte raz framework pre okienkový systém, ktorý umožňuje aplikáciám vytvárať pekné GUI a poskytuje na to sadu tried. Napríklad poskytuje triedu TextView, možno aj triedu ImageView, CalendarView, alebo MapView a podobne. Každá z nich vytvára okienko s nejakým špecifickým obsahom, ktorý je možné zobraziť pomocou metódy draw(), ako to predpisuje ich spoločná abstraktná nadtrieda VisualComponent. Neskôr sa autori frameworku rozhodnú pridať k textovému okienku scrollbar a tak vytvoria podtriedu TextViewWithScrollBar. Táto trieda bude tiež definovať prekrývajúcu metódu draw(), ktorá (zjedodušene povedané) najskôr nakreslí obsah okienka pomocou super.draw() a potom dokreslí scrollbar. Lenže, samozrejme, ak chcú pridať scrollbar aj k ostatným typom okienok, tak budú musieť vyrobiť aj podtriedy ImageViewWithScrollBar, CalendarViewWithScrollBar atď. čo je pomerne nepraktické a zrejme vznikne veľa duplicít. Ešte horšie to začne byť, keď okrem scrollbaru budeme chcieť pridať špeciálny rámček (TextViewWithBorder), alebo toolbar (TextViewWithToolbar) a nebodaj ešte aj rozličné kombinácie - so scrollbarom aj toolbarom, s toolbarom a rámčekom atď.

Návrhový vzor Decorator je recept na takéto a podobné situácie. Dovoľuje k existujúcim triedam pridať funkcionalitu oveľa praktickejším spôsobom: pomocou relácie agregácie. Dobre si pozrite navrhované riešenie na nasledujúcom obrázku:


Obr. 56: Príklad použitia návrhového vzoru Decorator.

V hornej časti je objektový diagram (znázorňuje objekty v pamäti počas behu aplikácie), v dolnej časti triedny diagram (zobrazuje len vzťahy medzi typmi). Abstraktná trieda Decorator "zastrešuje" všetky typy dekorátorov - čiže tried, ktoré pridávajú určitý typ funkcionality. Príkladom je ScrollDecorator, ktorý pridáva scrollbar a BorderDecorator, ktorý pridáva rámček. Od pôvodnej triedy, ktorej funkcionalita je rozširovaná (napr. TextView), nie je odvodená podtrieda - ako sme popisovali vyššie a ako by bolo v OOP bežné. Namiesto toho dekorátor obsahuje referenciu na inštanciu, ktorej funkcionalitu rozširuje (premenná component v triede Decorator). Zmena je len malinká - namiesto toho, aby sa volalo super.draw() sa z Decorator.draw() volá component->Draw(). Čiže aby sa nakreslil obsah okienka sa nezavolá zdedená verzia draw(), ale trieda draw() komponentu, ktorý práve dekorátor "obaľuje". Príslušná prekrývajúca metóda draw() daného dekorátora potom dokreslí potrebnú pridanú časť (napr. scrollbar). Obrovskou výhodou je, že v premennej component nemusí byť len TextView, ale môže tam byť ľubovoľný iný VisualComponent! Takto môžeme jedným ScrollDecoratorom pridať scrollbar podľa potreby ľubovoľnému okienku nielen TextView. A čo viac, dekorátory môžeme kombinovať navzájom, pretože Decorator je sám tiež VisualComponentom, takže ho iný decorator môže "obaliť" ďalšou funkcionalitou. Táto situácia je zobrazená v objektovom diagrame hore: objekt aTextView, ktorý je triedy TextView je časťou objektu aScrollDecorator a spolu vytvárajú textové okienko so scrollbarom a ako celok tvoria VisualComponent, ten je naďalej časťou objektu aBorderDecorator triedy BorderDecorator.

Veľmi dôležité je uvedomiť si tu, že funkcionalita, ktorú decorátor pridáva, vôbec nemusí byť o grafike, alebo o GUI. Naopak, môže to byť ľubovoľná funkcionalita pridaná k nejakej existujúcej triede. Typickým príkladom sú vstupné a výstupné streams v jazyku Java. Trieda InputStream, ktorá dokáže prečítať iba jeden znak metódou read() môže byť obalená dekorátorom ObjectInputStream, ktorá dokáže na jedno volanie načítať celý serializovaný objekt. ObjectInputStream je ale len dekorátorom nad nejakým iným InputStreamom, či už je to FileInputStream, SocketInputStream, StringBufferInputStream, alebo iný.

5.2.5. Facade
Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

Hoci dom často ukrýva na svojom hospodárskom dvore všeličo, hostia do neho vstupujú cez malebnú fasádu. Návrhový vzor Facade je malebnou fasádou nejakého rozsiahlejšieho systému, alebo jeho časti, cez ktorú vstupuje väčšina iných komponentov, ktorí vystačia s bežným použitím jeho funkcionality.

Príkladom môže byť knižnica, ktorá zabezpečuje funkcionalitu kompilátora nejakého programovacieho jazyka. Pozostáva z viacerých častí - napr. scanner, parser, typový analyzátor, abstraktný syntaktický strom a podobne, ale pri bežnom použití kompilátora tieto vnútorné komponenty nie je potrebné oslovovať priamo. Vstupná brána do knižnice umožňuje kompilátoru poslať zdrojový kód na skompilovanie a vráti program reprezentovaný vo vykonateľnej podobe. Niektoré špecifické aplikácie môžu potrebovať komunikovať s jednotlivými komponentami priamo - nad rámec rozhrania, ktoré poskytuje fasáda, čo je v prípade potreby tiež možné.

Iným príkladom je dnes populárna microservices architektúra, kde systém poskytuje viacero rozličných služieb, ktoré sú distribuované na rôznych výpočtových uzloch. Pre klientský softvér, ktorý k takejto sade služieb pristupuje externe, je pohodlnejšie ak je zriadená vstupná brána, ktorá presne eviduje na ktorých uzloch sú práve príslušné služby inštalované a dostupné. Niečo podobné zabezpečujú napríklad technológie Zuul od Netflixu a Spring Cloud Gateway.


Obr. 57: Schématický obrázok porovnávajúci systém "bez fasády" a výsledok po aplikovaní návrhového vzoru Facade.

5.2.6. Flyweight
Use sharing to support large numbers of fine-grained objects efficiently.


Obr. 58: Situácia, ktorá vedie k využitiu návrhového vzoru Flyweight: znaky v dokumente chceme reprezentovať objektami, ale majú veľa spoločných vlastností, preto na rovnaký znak použijeme ten istý objekt.

V niektorých systémoch sa určité typy objektov vyskytujú vo veľkom množstve. Pritom, určité vlastnosti majú všetky objekty daného typu spoločné a v niektorých sa líšia. Ak spoločné vlastnosti zdieľané skupinou objektov vytiahneme von do samostatného zdieľaného objektu (ktorý sa označuje Flyweight), tak môžeme potenciálne ušetriť množstvo zdrojov. Pri vytváraní nového objektu sa vždy zistí, či už zodpovedajúci flyweight existuje, alebo nie. Ak nie, tak sa vytvorí a zaradí sa do "poolu" aktívnych flyweights, inak iba použije referencia na existujúci flyweight z poolu. Flyweighty v pooli nedokážu vykonať väčšinu operácií samostatne, pamätajú si len tzv. intrinsic state - informácie spoločné pre všetky objekty, ktoré príslušný flyweight zdieľajú a ten nestačí. Preto tieto operácie dostávajú zvyšné údaje (nezdieľané, extrinsic state) vo svojom argumente (pozri metódu Operation(extrinsicState) na obrázku).


Obr. 59: Triedny a objektový diagram pre štruktúru návrhového vzoru Flyweight.

5.2.7. Proxy
Provide a surrogate or placeholder for another object to control access to it.

Proxy alebo zástupca je objekt, ktorý slúži ako náhrada pre skutočný objekt. Dôvody, prečo chceme použiť náhradu môžu byť veľmi rôzne. Proxy je vo väčšine vlastností neodlíšiteľný od skutočného objektu, ale v niečom sa líši - niečo pridáva, upravuje, vylepšuje, mení. Príkladom proxy je objekt, ktorý môžeme použiť namiesto obrázka zaradeného do dokumentu. Úlohou objektu je daný obrázok udržiavať, ale napr. pri otvorení dokumentu, alebo nejakej stránky, keď je potrebné rozsiahly obrázok načítať zo súboru alebo počítačovej siete, by sme potrebovali, aby sa nezdržovalo čakaním na úplné načítanie a zobrazenie obrázka. Namiesto toho sa použije proxy, ktorý sa postará, aby sa obrázok natiahol a zobrazil hneď ako to bude možné, ale metóda, ktorý tento objekt vytvorila nemusí čakať. Postará sa o to proxy. Iný príklad použitia proxy môže byť logovanie prístupu k nejakému objektu, prípadne obmedzenie takéhoto prístupu podľa privilégií. Príklad na obrázku zobrazuje triedu ImageProxy, ktorá vie vrátiť rozmery obrázka bez toho, aby bol obrázok načítaný. V prípade, že obrázok nebude treba nikdy zobraziť (napr. sa nachádza v neviditeľnej časti dokumentu za hranicou displeja), tak nikdy nebude načítaný a ušetria sa zdroje. Ak bude vyžadovaný samotný obsah obrázka, tak až v tom čase sa načíta zo súboru.


Obr. 60: Príklad využitia návrhového vzoru Proxy.

5.3. Behavioral Patterns

5.3.1. Chain of Responsibility
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

V mnohých aplikáciách komponenty reagujú na udalosti, ktoré vznikajú v iných komponentoch. Vtedy je vždy potrebné vytvoriť mechanizmus na odovzdanie notifikácie komponentom, ktoré na udalosť chcú reagovať. Jednou možnosťou je priama notifikácia: ak komponent vie, ktoré všetky komponenty má pri tej-ktorej udalosti notifikovať, môže napríklad zavolať ich dohodnutú metódu.

Často to tak nie je. V čase návrhu komponentu, kde udalosť vzniká, nie je známe, v ktorých komponentoch sa bude spracovávať. Môže sa to aj dynamicky meniť, v závislosti od toho, kde a ako sa príslušný komponent používa. Napríklad, predstavme si systém na riešenie porúch. Jednotlivé servisné prvky systému dokážu riešiť rôzne druhy porúch, ale vopred to nie je dané, priebežne pribúdajú nové servisné prvky, alebo nahrádzajú staré. Keď vznikne porucha - informácie o nej sa zabalia do objektu reprezentujúcu poruchovú udalosť a pošlú sa prvému prvku v reťazi, ten posúdi, či poruchu vie vyriešiť úplne, čiastočne, alebo vôbec. V posledných dvoch prípadoch prepošle udalosť ďalšiemu prvku v reťazi. V inom príklade si predstavme dialógové okno, v ktorom je viacero ovládacích prvkov rozložených do hierarchickej štruktúry - panely, podpanely, skupiny rádiobuttonov a pod. Pri kliknutí myši potrebujeme, aby na túto udalosť zareagoval ten správny komponent, na ktorý sa kliklo. Podobne, ak je časť dialógového okna dočasne zakrytá a po odkrytí sa má znovu aktuálne nakresliť - netreba kresliť celé okno, ale len tie podčasti, ktoré majú prienik s oblasťou, ktorá sa má prekresliť. Postupnosť komponentov vytvorí reťaz, cez ktorú sa udalosť o kliknutí/prekreslení oblasti bude postupne preposielať, až kým nedosiahne ten komponent, ktorý sám vie, že má udalosť spracovať. V takýchto situáciách potrebujeme nejaký univerzálny mechanizmus na doručovanie notifikácií o udalostiach.

Návrhový vzor Chain of Responsibility rieši takéto prípady. Všetky komponenty, ktoré majú záujem spracovávať udalosti z nejakého zdroja, sú zoradené v reťazi "handlerov". Zdroj, ktorý notifikáciu o udalosti generuje, má len referenciu na prvý handler v reťazi. Ten udalosť buď spracuje, alebo ju pošle ďalšiemu handleru v reťazi. Hovoríme, že notifikácia nemá explicitný (zreteľne uvedený) cieľ, ale má len implicitného adresáta (takého, čo vyplynie z aktuálne platnej reťaze handlerov). Handler sa môže rozhodnúť, či udalosť spracoval kompletne, alebo či na ňu síce nejak zareaguje, ale pošle ju aj ďalším handlerom v reťazi, alebo či sa ho netýka a iba ju pošle ďalej. V princípe sa môže stať, že na niektoré udalosti žiaden handler nezareaguje - je na návrhu a implementácii, aby boli všetky potrebné prípady pokryté korektne. Návrhový vzor nepredpisuje, či sa reťaz handlerov má vytvoriť pomocou novo-zadefinovaných referencií (ako ukazuje obrázok nižšie), alebo či sa využije už nejaká existujúca hierarchická štruktúra handlerov - ako by to mohlo byť v prípade hierarchických grafických ovládacích prvkov v dialógovom okne.


Obr. 61: Štruktúra návrhového vzoru Chain of Responsibility.

5.3.2. Command
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

Ako sme uviedli v predchádzajúcom, princípy OOP vychádzajú z myšlienky dekompozície na základe dát, čiže informácií. Údaje, ktoré prirodzene patria spolu vytvárajú uzavreté štruktúry dát - objekty. V niektorých situáciách môže byť takouto informáciou (dátami) aj inštrukcia (príkaz). To je aj prípad návrhového vzoru Command, kde objekt triedy Command nesie informáciu o tom, aký príkaz sa má vykonať, resp. sa už vykonal. To nám umožňuje generovať požiadavky na vykonanie príkazov bez toho, aby sme vedeli o aké príkazy ide, alebo evidovať zoznam vykonaných príkazov počas nejakej postupnosti príkazov (session).

Predstavme si framework na vytváranie používateľského menu. Tento framework by mal aplikácii dovoliť pohodlne konfigurovať priradenie príkazov k jednotlivým položkám menu. Namiesto toho, aby sme to realizovali cez nejaké číselné kódy príkazov a potom v dlhej podmienke v štýle switch...case... rozlíšili podľa čísla o aký príkaz ide, môžeme frameworku priamo posunúť inštanciu nejakej podtriedy triedy Command, ktorá bude implementovať metódu execute(). Po zvolení zpodpovedajúcej položky menu framework zavolá metódu execute() nášho objektu a tá zabezpečí že sa vykoná požadovaný príkaz. Ak by sme do rozhrania pridali aj metódu undo(), postupnosť vykonávaných príkazov by framework mohol evidovať (história operácií) a po požiadavke používateľa na vykonanie kroku späť (undo), prípadne viacnásobného návratu (undo-undo-undo...) by sa len volali metódy undo() na objektoch zodpovedajúcich príkazom vykonaným v predchádzajúcich krokoch. Podobne by sme mohli pridať redo(), aby sa dalo v histórii presúvať oboma smermi.


Obr. 62: Príklad využitia návrhového vzoru Command vo frameworku na vytváranie použivateľského menu

Skombinovaním vzoru Command so vzorom Composite je možné vytvárať makrá.

5.3.3. Interpreter
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

Na chvíľu urobme malú nepovinne-informatívnu odbočku do teoretickej informatiky - ak sa čitateľ ešte nestretol s formálnymi gramatikami, súrodencami formálnych automatov. Jazyk je nejaká množina slov, ktoré sú postupnosťami symbolov z abecedy, množiny povolených symbolov. Napríklad, nech abeceda pozostáva iba z jedného symbolu Σ1 = {a}. Jazyk L1, ktorý obsahuje všetky možné slová vytvorené z párneho počtu symbolov a (skrátene môžeme zapísať L1 = {a2n; n > 0}), sa dá vygenerovať takouto gramatikou:
γ => aa
γ => aaγ

Ako vidíme, gramatika používa aj iné symboly ako sú v abecede, sú to pracovné symboly z abecedy Γ1 = {γ} (tzv. neterminálne symboly), ktoré sa môžu počas budovania slov jazyka využiť, ale nakoniec sa musia zmeniť na terminálne symboly z gramatiky Σ1, iba také sa môžu vyskytovať v slovách jazyka. γ je počiatočný symbol, z ktorého začína odvádzanie každého slova. V každom kroku odvodenia použijeme jedno z pravidiel gramatiky, čím nahradíme nejaký neterminál na ľavej strane pravidla reťazcom na pravej strane pravidla. V našom prípade teda druhé pravidlo vygeneruje o jedna menej dvojíc symbolov a, ako je potrebný počet a nakoniec sa neterminál γ zmení prvým pravidlom na dvojicu symbolov a.

Podobne by sme pre abecedu Σ2 = {a,b} a jazyk L2 = {anbm; n,m > 0} mohli napísať gramatiku:
γ => aγ
γ => aβ
β => bβ
β => b
Zaujímavejšie to začne byť napr. pri jazyku L3 = {anbn}, obsahujúcom všetky slová pozostávajúce z nejakého počtu symbolov a na začiatku slova nasledovaných rovnakým počtom symbolov b. Tento jazyk sa už takouto gramatikou vygenerovať nedá. Pod takouto máme na mysli regulárne gramatiky, kde na ľavej strane môže byť iba jeden neterminál a na pravej strane môže byť buď jeden terminál, alebo jeden terminál a jeden neterminál. Regulárne gramatiky majú rovnakú vyjadrovaciu silu ako konečné stavové automaty - množina jazykov, ktoré generujú, resp. rozpoznávajú je rovnaká (poteším sa, keď sa zamyslíte nad tým, prečo je to tak). Pre L3 môžeme zostrojiť gramatiku:
γ => aγb
γ => ab

takáto gramatika je bezkontextová - čo znamená, že na ľavej strane je vždy práve jeden neterminál. Aj takáto gramatika naráža na svoje hranice, napr. jazyk L4 = {(a*b*)*, počet symbolov a, b je rovnaký} - čiže jazyk, v ktorom sú všetky slová s ľubovoľne pomiešanými symbolmi a, b, ale zastúpené v rovnakom počte, napr. abbbaa, babbbaaa, baba. Tu si môžeme pomôcť frázovou gramatikou, ktorá dovoľuje aj na ľavej strane pravidla viac ako jeden neterminál:
γ => αγβ
γ => αβ
αβ => βα
α => a
β => b
prvé dva riadky vygenerujú jazyk so slovami s neterminálmi vo formáte αnβn a tretí riadok dovolí symbolom β podľa potreby predbehnúť symboly α, nakoniec sa všetky neterminály α, β zmenia na a, b.

Gramatiky podľa svojej vyjadrovacej sily tvoria tzv. Chomského hierarchiu (regulárne -> bezkontextové -> kontextové -> frázové). Frázová gramatika generuje jazyk, ktorý je rozpoznateľný nejakým Turingovým strojom (sú to ekvivalentné formalizmy).

Pre iniciatívneho čitateľa so záujmom o prémiové body ponúkame na precvičenie nasledujúce príklady:
  1. vytvorte čo najjednoduchšiu gramatiku pre generovanie anglických viet v nasledujúcich formátoch: Podmet prísudok, Podmet prísudok prísl.určenie, Prívlastok podmet prísudok prísl.určenie, kde podmet môže byť John, Student, Man, Box, prísudok môže byť works, sits, looks, stands, prívlastok môže byť foreign, nice, busy, crazy a príslovkové určenie môže byť safe, high, low, late.
  2. čo najjednoduchšiu gramatiku pre jazyk {w=anbncn; n > 0}, napr. slová abc, aabbcc, aaaabbbbcccc
  3. ...pre jazyk {w=ai; i=2n; n >= 0}, čiže napr. a, aa, aaaa, aaaaaaaa, aaaaaaaaaaaaaaaa
  4. ...pre jazyk {w=axby; kde y > 0 je deliteľné bezo zvyšku x > 0}, napr. abb, aaabbbbbbbbb, aabbbbbb
  5. ...pre jazyk {w={0..9}*; w je deliteľné 3}, napr. 3,6,9,12,15,123,309
Originálne riešenia (môžu byť aj v LaTeXu) nahrajte do zodpovedajúcej zostavy.
Hoci tu uvedené jazyky sú pomerne jednoduché, podobným spôsobom je možné zadefinovať aj gramatiku pre ľubovoľný programovací jazyk, kde terminálmi sú jednotlivé kľúčové slová, operátory a ostatné syntaktické prvky jazyka. Často sa pri tom používa gramatika v štýle BNF. Za týmito prvkami jazyka sa skrýva aj sémantika - aký majú reálny význam (napr. operátor + vykonáva sčítanie svojich argumentov).

V kontexte uvedenej vsuvky si predstavme nejaký jednoduchý špecializovaný jazyk - napr. na programovanie pohybov robotického ramena pripojeného k vesmírnej stanici. Návrhový vzor Interpreter rieši tento druh situácie, pričom účelom interpretra môže byť buď len sparsovanie programov zapísaných v jazyku a vybudovanie abstraktného syntaktického stromu (AST) k vstupnému programu, za účelom ďalšej analýzy a spracovania, prípadne vykonania, alebo môže byť úlohou interpretra rovno zadaný program aj vykonať. Pre danú gramatiku môžeme vybudovať hierarchiu tried zodpovedajúcich jednotlivým druhom pravidiel a pravidlám ako takým. V prípade zložitejších gramatík sa odporúča radšej použiť externé nástroje na parsovanie.


Obr. 63: Príklad hierarchie tried pri použití návrhového vzoru Interpreter - objektová reprezentácia vyjadrujúca jedno pravidlo regulárneho výrazu "((cats|dogs) repeat) and raining".

5.3.4. Iterator
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

Iterator je jeden z najbežnejšie používaných návrhových vzorov, ktorý umožňuje postupne prechádzať cez všetky prvky združené v nejakom objekte, ktorý združuje množinu prvkov. Podstatné je, že interface iterátora je univerzálny, a použiteľný pre rozličné zbierky prvkov rôzneho typu. Dnešné moderné jazyky obsahujú zabudované syntaktické štruktúry na automatické vytváranie a používanie iterátorov, ale v tomto prípade máme na mysli používateľom definované agregované štruktúry, cez ktoré má zmysel potenciálne iterovať univerzálnym spôsobom nezávisle od vnúrornej reprezentácie objektu, ktorý interface iterátora spĺňa. Iterator predpisuje operácie posunutia sa na nasledujúci prvok, prezretia aktuálneho prvku, test na koniec procesu iterovania a prípadne reset na začiatočný prvok. Iterátor môže postupovať buď v náhodnom poradí, alebo podľa nejakého operátora usporiadania.


Obr. 64: Štruktúra návrhového vzoru Iterator. V roli Aggregate je nejaký abstraktný interface pre kolekcie, v roli ConcreteAggregate je nejaká konkrétna kolekcia, napr. HashSet, ConcreteIterator je potom taký iterátor, ktorý dokáže prechádzať prvky toho konkrétneho HashSetu, pre ktorý bol vytvorený.

5.3.5. Mediator
Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

Na dosiahnutie netriviálnej funkcionality pomocou OOP je vždy potrebné, aby viaceré objekty navzájom interagovali a spolupracovali. Ak je táto interakcia "zadrôtovaná" priamo v nich, vzniká množstvo závislostí, znižuje sa znovupoužiteľnosť a flexibilita. Návrhový vzor mediátor odporúča vytvoriť samostatnú triedu, ktorej objekt má na starosti koordináciu viacerých objektov, vďaka čomu medzi nimi nevznikajú pevné väzby v čase návrhu - čiže sa môžu vyvíjať nezávisle na sebe. Mediator je objekt, ktorý konfiguruje prepojenie objektov v danej konkrétnej situácii.

Príkladom môže byť dialógové okno, v ktorom je použitých viacero kontroliek - tlačidlá, listboxy, editovacie okienka, textové popisy, obrázky a podobne. Všetky tieto objekty ponúkajú univerzálny interface na prácu s nimi a jeden objekt (mediátor) má na starosti správne skĺbenie ich funkcionality. Napríklad dialógové okienko na výber fontu textu môže obsahovať zoznam fontov, výber hrúbky písma (light, medium, bold, heavy), štýlu (normálny, kurzíva), veľkosti v bodoch, možnosť úspornej šírky, obsahuje náhľad krátkeho textu vo zvolenom štýle, ktorý sa automaticky aktualizuje pri akejkoľvek zmene nastavenia. Niektoré fonty však neposkytujú všetky možnosti, takže pri vybratí fontu v listboxe sa nedostupné možnosti automaticky skryjú. Mediátor má na starosti komunikáciu s rozhraniami všetkých čiastkových objektov dialógu a poskytuje jednoduchý interface na riadenie dialógu navonok. Jednotlivé objekty sa na seba priamo neodkazujú, akúkoľvek interakciu riešia cez mediátora.


Obr. 65: Príklad interakcie objektov využitím návrhového vzoru Mediator.

5.3.6. Memento
Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.

Hoci z princípov OOP vyplýva, že podrobnosti svojho vnútorného stavu má objekt pred ostatnými objektami skrývať (enkapsulácia), niekedy je vhodné, aby sme vnútorný stav objektu vedeli odložiť, uchovať a neskôr v prípade potreby použiť na to, aby objekt svoj pôvodný stav zrekonštruoval do podoby v čase uchovania jeho vnútorného stavu. Takto získaný vnútorný stav sa označuje Memento. Od objektu sa očakáva, že bude obsahovať metódu na získanie Mementa - odtlačku jeho aktuálneho stavu a na nastavenie jeho stavu podľa odtlačku získaného niekedy predtým. Celú situáciu obhospodaruje nejaký iný objekt - Caretaker. Je znázornená v triednom diagrame na obrázku.


Obr. 66: Triedny diagram pre návrhový vzor Memento.

5.3.7. Observer
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Observer opisuje základný mechanizmus ako sa v systémoch založených na udalostiach šíria notifikácie od zdroja udalosti, kde nastala zmena stavu, k objektom, ktoré sú na príslušnej udalosti závislé. Návrhový vzor definuje univerzálny interface, pomocou ktorého sa môžu objekty zaregistrovať ako odoberatelia notifikácií o zmene stavu nejakého konkrétneho objektu. Objekt, ktorého zmena stavu je pozorovateľná, musí splniť rozhranie Subject, s dvomi metódami Attach(Observer) a Detach(Observer), pomocou ktorých sa ľubovoľný objekt spĺňajúci rozhranie Observer môže zaregistrovať. Pozorovaný objekt (Subject) udržuje zoznam všetkých svojich observerov a v prípade, že sa jeho stav zmení, notifikuje volaním Update() všetkých observerov. Situácia je znázornená v triednom diagrame na obrázku. V niektorých prípadoch je vhodné metóde Update() pridať aj argument - referenciu na objekt, ktorého stav sa zmenil. To potom umožní, aby sa observer zaregistroval u viacerých subjektov a využíval tú istú metódu Update(). V niektorých situáciách je vhodné, aby notifikácia nenastávala po každej čiastkovej zmene, ale až po ukončení postupnosti za sebou nasledujúcich zmien, preto treba pri implementácii Subjectu zvážiť, kedy a odkiaľ volať metódu notify(), aby bol návrh efektívny a aby nedošlo k notifikáciám v okamihoch, keď stav nie je konzistentný. Samostatnú pozornosť si vyžaduje rušenie subjektov a observerov. Observer, ktorý je rušený, by sa mal detach-núť zo všetkých subjektov, kde sa zaregistroval. Subject, ktorý je rušený, by mal upovedomiť všetkých observerov, aby u nich neostali visieť referencie na zrušený objekt. Notifikácia observerov môže obsahovať aj kompletnú informáciu o zmenenom stave (push model), alebo len minimum informácií, pričom observer si môže vyžiadať podrobnosti v prípade potreby (pull model). V prípade, že stav subjektu je členitý, observeri sa môžu zaregistrovať len na notifikácie o zmenách jednotlivých častí jeho stavu. Ak je sémantika notifikácií zložitá, je možné pre ňu vyhradiť samostatný objekt, ktorý podrobne definuje stratégiu notifikácií observerov (ChangeManager).


Obr. 67: Triedny diagram pre návrhový vzor Observer.

5.3.8. State
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

Návrhový vzor State je jednoduchý príklad na využitie polymorfizmu. Predstavme si, že nejaký komponent A vie spracovať nejakú požiadavku pričom na to využíva nejaký komponent B. Komponent A je trvácny a prijíma požiadavky vždy rovnakým spôsobom, ale v závislosti od toho, v akom kontexte sa systém práve nachádza, je potrebné na tú istú požiadavku reagovať raz jedným spôsobom, inokedy iným spôsobom. Komponent B, na ktorom sa požiadavka realizuje, sa teda v rozličných kontextoch správa inak. Preto vytvoríme rôzne verzie komponentu B (budú to rôzne podtriedy zastrešujúcej abstraktnej nadtriedy). V okamihu, keď dôjde ku zmene kontextu, tak objekt v roli komponentu B vymeníme - za inštanciu jeho sesterskej podtriedy.

Ako príklad si predstavme kresliaci editor, kde sa kurzor myši vie prepnúť medzi tromi rôznymi režimami - posúvací, editovanie detailov a pridávanie komentárov. Handler, ktorý spracováva udalosť klinutia alebo ťahania myšou (komponent A), deleguje spracovanie tejto udalosti príslušnému nástroju (komponent B), ktorý sa mení podľa výberu režimu používateľom.
Iný príklad predstavuje objekt, ktorý zabezpečuje spojenie cez TCP sockety. Toto spojenie môže byť z dôvodu šetrenia zdrojmi zdieľané medzi viacerými komponentami a môže sa v danom okamihu nachádzať v rozličnom stave - nevytvorené, nadviazané, uzavreté, ... Ak nový komponent požiada o otvorenie spojenia, akcia, ktorá sa v skutočnosti vykoná, závisí od toho, v akom stave sa spojenie práve vtedy nachádza. Pre každý možný stav TCP spojenia je vytvorená trieda. Využitím polymorfizmu sa pri pokuse o otvorenie spojenia zavolá správna metóda open(), namiesto toho, aby sme museli stav rozlišovať sériou podmienok testujúcich nejakú stavovú premennú. Situácia je znázornená na obrázku.


Obr. 68: Príklad využitia návrhového vzoru State.

5.3.9. Strategy
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Strategy je ďalší návrhový vzor založený na využití polymorfizmu a hoci jeho štruktúra je takmer identická ako pri návrhovom vzore State, plní odlišný účel, podobný ako pri návrhovom vzore Builder. V tomto prípade nie je cieľom vybudovanie štruktúrovaného objektu pomocou čiastkových operácií (ako pri vzore Builder), ale jednoducho abstrahovanie nad nejakým algoritmom, ktorý môže byť implementovaný rozličnou stratégiou. Jednoduchým príkladom môže byť abstraktná trieda Sorter (rola Strategy) s metódou sort() a jej podtriedy BubbleSorter, MinSorter, QuickSorter, MergeSorter (všekty sú v roli ConcreteStrategy). Niektoré triediace algoritmy zachovávajú poradie rovnakých prvkov, iné nezachovávajú. Príklad: utrieďme zoznam dvojíc (3,3), (1,4), (3,2), (2,1) podľa prvého prvku v dvojici. Algoritmus zachovávajúci poradie rovnakých prvkov musí vrátiť utriedený zoznam v poradí: (1,4), (2,1), (3,3), (3,2), hoci iný algoritmus, tiež korektne triediaci, ale nezachovávajúci poradie rovnakých prvkov môže vratiť zoznam v poradí: (1,4), (2,1), (3,2), (3,3). V určitom kontexte potrebujeme použiť napr. MinSorter, ktorý poradie zachová, hoci nie je taký rýchly ako QuickSorter, ktorý použijeme v kontexte, keď na zachovaní poradia nezáleží, ale naopak potrebujeme rýchlu odozvu.


Obr. 69: Štruktúra návrhového vzoru Strategy.

5.3.10. Template Method
Define a skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

V jednej zo zásad čistého kódu sa hovorí, že ak sa v našom zdrojovom kóde opakovane nachádzajú podobné časti, tak kód ešte nie je dostatočne čistý. Zrejme sme nenašli nejaký spôsob abstrakcie, ktorý dokáže spoločné časti podobných úsekov zjednodiť v abstraktnej podobe a vytvoriť dve špecializácie, ktoré budú obsahovať len to, čím sa navzájom od seba odlišujú. Spôsoby vytvárania takýchto abstrakcií sú veľmi rôznorodé a návrhový vzor Template Method je jeden z nich.

Myšlienka spočíva vo vytvorení spoločnej šablóny metódy v abstraktnej nadtriede (to je tá template method) a zadefinovanie abstraktných metód v tejto abstraktnej triede, ktoré budú špecializované v každej podtriede inak. Týmto pádom budú spoločné časti kódu uvedené len raz a vďaka polymorfizmu a generalizácii sa odlišné časti doplnia v závislosti na tom, na akej konkrétnej inštancii sa daná šablónová metóda zavolá.

Príklad, ktorého triedny diagram je zobrazený na obrázku, je o frameworku na vytváranie aplikácií s dokumentami. Každá špecifická aplikácia si vytvára vlastnú podtriedu odvodenú od frameworkovej triedy Application a definuje vlastný typ dokumentu odvodený od frameworkovej triedy Document. Frameworková trieda Application obsahuje už naprogramovanú šablónovú metódu OpenDocument(), ktorá vytvorí nový dokument a zaradí ho do zoznamu dokumentov príslušnej aplikácie. Táto metóda sa najskôr pokúsi vytvoriť novú inštanciu, do ktorej sa dáta dokumentu načítajú a ak sa to podarí, tak súbor s dokumentom otvorí a načíta ho do novo-vytvorenej inštancie. Na tieto jednotlivé kroky využíva metódy, ktoré si aplikácia zadefinuje prekrytím abstraktných metód frameworkovej triedy Application.


Obr. 70: Príklad využitia návrhového vzoru Template Method.

5.3.11. Visitor
Represent the operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.



Predstavme si stromovú adresárovú štruktúru súborov na disku, ktorá je načítaná v nejakom štruktúrovanom objekte v pamäti. Tento objekt dovoľuje prechádzať cez danú štruktúru univerzálnym spôsobom. Podľa typu položky zavolá rôznu metódu: v prípade, že položka je typu podadresár, zavolá metódu spracujPodadresar(), ak ide o spustiteľný súbor, zavolá spracujProgram() a inak zavolá spracujSubor(). Tieto metódy volá na nejakom objekte v roli Visitor, ktorý určuje, čo sa na jednotlivých položkách má robiť. Napr. ak naším cieľom je vypísať stromovú štruktúru na výstup, všetky metódy budú vypisovať názvy položiek, prípadne vypočítavať odsadenie podľa úrovne vnorenia do podadresárov. V prípade, že chceme len spočítať počet súborov v celej stromovej adresárovej štruktúre, metódy spracujProgram() a spracujSubor() budú zvyšovať interné počítadlo visitora.

Návrhový vzor Visitor teda umožňuje prechádzať položky nejakej zložitej štruktúry s tým, že operácie, ktoré sa nad jednotlivými typmi položiek majú vykonať, určí príslušná inštancia podtriedy spĺňajúcej rozhranie, ktoré je pre visitora pre daný typ štruktúrovaného objektu predpísané. Visitor má možnosť dané položky nielen čítať, ale ak je potrebné priamo do stromovej štruktúry pristupovať a upravovať ich. Mohli by sme povedať, že ide o trochu štruktúrovanejší iterátor.

Tento návrhový vzor sa typicky používa pri rôznych parseroch stromových alebo sekvenčných štruktúr - napr. pri parsovaní XML dokumentov v jazyku Java EE týmto spôsobom pracuje SAX parser, kde v roli visitora je ContentHandler.

Na obrázku je príklad využitia návrhového vzoru Visitor pri prechádzaní cez syntaktické prvky nejakého programu. Visitor má zadefinované metódy, ktorými spracováva rozličné syntaktické prvky - napr. jedna metóda spracováva príkaz priradenia (VisitAssignment), iná spracováva odkaz na nejakú premennú (VisitVariableRef). Program pozostáva z mnohých prvkov (Node), ktoré sú inštancie špecializácií triedy Node a každá z nich definuje metódu, ktorá má na starosti interagovanie s Visitorom správnym spôsobom - t.j. napr. ak určitý Node reprezentuje príkaz priradenia, tak visitora osloví vhodnou metódou VisitAssignment().


Obr. 71: Príklad využitia návrhového vzoru Visitor.

6. Integrácia aplikácií

S prudkým rozvojom informačných technológii v posledných dekádach 20. storočia nastalo nekoordinované nasadzovanie špecializovaných informačných systémov na rôzne čiastkové úlohy v mnohých organizáciách. Hoci aplikácie zjednodušili a zrýchlili prácu, čoskoro sa narazilo na problém: aplikácie navzájom nespolupracujú. Rovnaké údaje boli často uložené duplicitne vo viacerých systémoch, bežné procesy organizácie znamenali použitie viacerých systémov a viacnásobné vypĺňanie rovnakých dát, činnosti, ktoré by mohli byť plne automatizované, vyžadovali ručnú obsluhu, ktorá vstupy, výstupy a akcie jedného systému iba koordinovala so vstupmi, výstupmi a akciami ostatných systémov. Tento stav vo veľkej miere pretrváva dodnes a bude aktuálny vždy, pretože jednak vyvinúť obrovský systém, ktorý rieši všetky potreby organizácie, je priveľmi nákladné a ťažko realizovateľné a po druhé, všetko súvisí so všetkým, takže nejaký zmysel sa bude dať nájsť v prepájaní takmer všetkých aplikácií vždy. Naviac, pri efektívnom riadení organizácie si často na každý podproblém vyberáme najlepší dostupný nástroj, namiesto jedného veľkého univerzálneho riešenia, ktoré trpí nedostatkami v každej konkrétnej aplikácii. Iný príklad nutnosti integrácie aplikácií: dôjde k zlúčeniu dvoch organizácií (akvizícia) a pravidlá jednej firmy, ktorá používala iný softvér, zrazu začnú platiť cez celú spoločnosť.

Integrácia aplikácií teda znamená proces prepájania rozličných aplikácií tak, aby mohli vzájomne spolupracovať na definovanej funkčnosti. Výsledkom je integračné riešenie.


Obr. 72: Integračné riešenie.

Slovo integrácia ako také označuje proces začleňovania nejakej menšej jednotky do väčšieho celku. Poznáme známe príklady integrácie krajiny do Európskej Únie, alebo iných medzinárodných štruktúr, integrácia handicapovaných ľudí do bežnej spoločnosti, integrácia menšín do spoločnosti. Vo všetkých prípadoch vidíme spoločnú črtu: integrácia si vyžaduje úsilie jednak od menšej jednotky, ktorá sa integruje, ale podobne veľké úsilie sa vykonáva aj na strane celku, do ktorého sa jednotka integruje. Napríklad v prípade integrácie menšiny do spoločnosti bez úsilia väčšiny ide o asimiláciu, ktorej sa civilizovaná spoločnosť snaží vyhnúť, pretože potiera práva začleňovanej menšiny.

Prepájanie aplikácií je netriviálny proces, pretože často nejde len o obyčajný export a následný import do druhej aplikácie. Jednotlivé programy používajú rozličné dátové modely - napr. v jednom môže byť meno a priezvisko uložené zvlášť, druhý obsahuje len jeden atribút MenoPriezvisko. V jednom systéme môže atribút Adresa znamenať korešpondenčnú adresu kontaktnej osoby organizácie, v druhom môže znamenať oficiálnu adresu organizácie, s ktorou je zaregistrovaná na Štatistickom úrade SR. Rozdiely môžu spočívať napríklad aj vo formálnej zodpovednosti za správnosť evidovaných údajov, ktorá sa nesmie porušiť bez toho, aby sa nezmenili vnútorné predpisy organizácie.

Integrácia sa realizuje jednak úpravou existujúcich aplikácií (ak je to vôbec možné) alebo vytváraním nových komponentov, ktoré komunikujú s jednotlivými aplikáciami.

Kľúčovým pojmom, okolo ktorého sa točí celá integrácia aplikácií, je tzv. voľná väzba, v kontraste s pevnou väzbou. Rozlišujeme voľnú väzbu v čase návrhu a v čase behu.


Obr. 73: Voľná a pevná väzba v čase behu.

Voľná väzba v čase behu znamená, že integračné riešenie nevyžaduje, aby komunikujúce aplikácie boli v činnosti súčasne. Voľná väzba v čase návrhu nevyžaduje, aby prepojené systémy boli vyvíjané súčasne. Integračné riešenia s voľnou väzbou uprednostňujeme pred tými, ktoré vyžadujú pevnú väzbu, keďže umožňujú väčšiu flexibilitu.


Obr. 74: Voľná a pevná väzba v čase návrhu.

Integrácia aplikácií je problematika, ktorá by si zaslúžila aj samostatný kurz, aby sme do nej aspoň z časti nahliadli, zamerajme sa na klasifikáciu integrácie z troch rôznych hľadísk: klasifikácia podľa A) poskytovanej funkčnosti, B) spôsobu komunikácie s aplikáciami a C)vnútornej komunikácie v rámci integračného riešenia.

6.1 Klasifikácia integrácie podľa poskytovanej funkčnosti

Za integračné riešenie na nulovej úrovni by sme mohli považovať sekretárku, ktorá sedí za počítačom s viacerými aplikáciami a najčastejšie klávesy, ktoré používa sú ALT-Tab, CTRL-C a CTRL-V. Ak integračné riešenie poskytuje niečo viac, tak hovoríme o integrácii prostredníctvom portálu, o agregácii dátových entít, alebo o integrácii procesov.

Integrácia prostredníctvom portálu
Do všetkých aplikácií integračného riešenia sa používateľ prihlási na jeden raz. Okná všetkých aplikácií vidí naraz na obrazovke (alebo sa medzi nimi jednoducho prepína). V niektorých prípadoch sa informácie aj automaticky aktualizujú medzi jednotlivými aplikáciami. Typické technológie, ktoré v takomto prípade využívame sú adresárové služby - napr. prostredníctvom štandardu X.500. Prihlasovanie a aktualizácia používateľského profilu sa deje na jednom zdieľanom serveri, ktorý využívajú všetky aplikácie. Isto ste sa už stretli s možnosťou prihlásiť sa do nejakej aplikácie tretej strany pomocou vášho účtu pre aplikácie firmy Google (GMail a podobne).

Agregácia dátových entít
Toto riešenie ide ďalej a stará sa o vytvorenie jednotného pohľadu - dátového modelu, ktorý čerpá z dátových modelov jednotlivých aplikácií. Jednotlivé polia výsledného modelu sú namapované (s prípadnými úpravami po ceste) na novú dátovú entitu, ktorú definuje integračné riešenie. Nové aplikácie, ktoré do integračného riešenia pridávame, sa môžu odkazovať na tieto nové dátové entity, ktoré vznikli agregovaním (spájaním, zlučovaním) jednotlivých dátových entít. V tomto prípade ale integračné riešenie ešte samostatne nevykonáva žiadne aktivity.

Integrácia procesov
V tomto prípade integračné riešenie samostatne vykonáva interakcie medzi aplikáciami, aby zabezpečilo realizovanie stanovených požiadaviek. Napríklad vie vykonať mesačnú mzdovú uzávierku pre všetkých zamestnancov tak, že z rôznych systémov zistí potrebné informácie: koľko dní bol pracovník PN, na dovolenke a na pracovnej ceste, kedy nastúpil do zamestnania, aké sú aktuálne platné tabuľkové mzdy, aká je jeho aktuálna kvalifikácia, či je členom odborov, či má okrem bežnej mzdy príjem aj z nejakých projektových grantov, či si odkladá v druhom a treťom pilieri na dôchodok, atď. a na základe toho vyráta jeho mesačnú mzdu, na koľko stravných lístkov má nárok a aké sumy treba odviesť do rozličných poisťovní a tieto platby aj realizuje bez toho, aby mzdová učtáreň tieto údaje musela do systému vkladať: pracovnú dochádzku zadá sekretárka na jeho katedre do systému dochádzky, kvalifikáciu a odpracované roky vypočíta systém personalistického oddelenia, informácie o projektoch zadá centrum projektovej podpory, aktuálne tabuľkové mzdy sa vytiahnu zo systému ministerstva financií, podrobnosti o dôchodkoch prídu každý mesiac automatickou správou zo sociálnej poisťovne a o členstve v odboroch a aktuálnom odborárskom členskom odpovie informačný systém odborárov.

6.2 Klasifikácia integrácie podľa spôsobu komunikácie s aplikáciami

Na dosiahnutie spolupráce medzi aplikáciami musíme zabezpečiť, aby dokázali navzájom automaticky komunikovať, hoci pôvodne s komunikáciou takýmto spôsobom nepočítali (ak áno, tak integračné riešenie získame takmer "zadarmo" správnym nastavením konfiguračných súborov - čo je ideálny prípad). S aplikáciou môžeme automaticky komunikovať na troch rôznych úrovniach: A) na úrovni aplikačnej logiky, B) na úrovni perzistentných údajov, C) na úrovni používateľského rozhrania.

Komunikácia na úrovni aplikačnej logiky
Komunikácia na úrovni aplikačnej logiky znamená, že aplikácia poskytuje nejaký spôsob, akým sprístupňuje svoju funkcionalitu a dáta automatickým spôsobom - že už tak vopred bola naprogramovaná. Spôsobov existuje veľmi veľa, napríklad k aplikácii je pribalená dynamická knižnica a dokumentácia jej funkcií (API), webová aplikácia môže definovať REST-ovské URL adresy, ktoré reagujú požadovanými údajmi, akciami, aplikácia môže počúvať na nejakom TCP sockete a odpovedať na prijaté požiadavky, alebo aspoň obsahuje povel na vygenerovanie exportu alebo načítanie importovaných údajov vo formáte CSV, XML, alebo JSON.

Komunikácia na úrovni aplikačnej logiky je jednoznačne najlepší z uvedených troch prístupov, najmä preto, že je podporovaný priamo autormi aplikácie, takže je oveľa menšia pravdepodobnosť, že sa dopustíme nejakej chyby kvôli tomu, že nepoznáme vnútorné mechanizmy aplikácie. Pri vydaní novej verzie systému môžeme očakávať menšie zmeny a prípadnú podporu migrácie pre integrátorov ako je to v prípade používateľského rozhrania alebo databázy. Spravidla tým máme k dispozícii automatickú validáciu správnosti vstupných údajov a autorizácie (používateľ, ktorý by sa k určitým údajom nemal dostať sa k nim nedostane). Bežné systémy na úrovni aplikačnej logiky vyžadujú pevnú väzbu, avšak existujú aj systémy s automatickou odpoveďou cez e-mail, prípadne iné technológie s voľnou väzbou - napríklad Java Message Service (JMS). Hlavnou nevýhodou komunikácie na úrovni aplikačnej logiky je to, že často jednoducho nie je k dispozícii. Často nie sú k dispozícii ani zdrojové súbory aplikácie alebo spoločnosť, ktorá systém vyvinula, už neexistuje.

Komunikácia na úrovni perzistentných údajov
Takmer každá aplikácia ukladá svoje údaje do nejakej všeobecne známej a podporovanej databázy, ku ktorej po získaní prístupových údajov môže automaticky pristupovať aj integračné riešenie, obídením pôvodnej aplikácie. Na jednej strane je toto riešenie efektívne - dotazy optimalizuje databáza, môžeme prenášať veľké objemy dát, alebo robiť modifikácie priamo pomocou dotazovacieho jazyka, máme k dispozícii všetky údaje v databáze. Na druhej strane integrátori nemusia kompletne odhaliť dátový model a ľahko môžu porušiť integritu dát a pôvodnú aplikáciu tým aj celkom znefunkčniť. K tomu môže dojsť veľmi ľahko, ak by sme chceli integračné riešenie používať súčasne s pôvodnou aplikáciou, ktorá údaje môže dočasne odkladať do svojej lokálnej cache, alebo zamykať prístup k záznamom. Ďalej strácame automatickú validáciu vstupov - do databázy môžeme uložiť aj také údaje, ktoré pôvodný program ani nevie interpretovať, pokiaľ validácia nie je implementovaná priamo v databáze. Nie je tiež správne, že obchádzame systém prístupových oprávnení, lebo takto omylom môžeme dať prístup používateľom, ktorí by ho nemali mať (to je údajne napr. prípad pôvodnej verzie knižnice Fajr, alternatívneho prístupu k údajom univerzitného AISu), ktorý bol urobený práve tak, ako by sa integrácia aplikácií robiť nemala.

Komunikácia na úrovni používateľského rozhrania
Všetky aplikácie majú svoje používateľské rozhranie. Niektoré bežia na webe, takže vypĺňanie formulárov určených pre bežného používateľa môžeme nahradiť priamymi automatickými HTTP requestami typu POST, niektoré sa dajú ovládať z príkazového riadku (command line interface, CLI) a v najhoršom prípade sa dá nahrať aj makro (resp. vytvoriť jeho ekvivalent), ktoré za nás automaticky kliká na tlačidlá v dialógových oknách a vypĺňa editboxy. Výhodou je, že integračné riešenie takto nemôže urobiť nič viac ako bežný používateľ, takže je zabezpečená integrita údajov a validácia vstupov. Veľkou nevýhodou je nízka robustnosť - aj malá zmena používateľského rozhrania - napr. pri dodaní novej verzie spôsobí problémy. Neočakávaná situácia, ktorá zobrazí informatívne dialógové okno, alebo správu v príkazovom riadku tiež ľahko rozbije takéto integračné riešenie. Naviac údaje musíme aplikácii prezentovať a interpretovať ako používateľ, čiže napr. konvertovať vypísané pole reálnych čísel oddeľovaných čiarkami z textovej do binárnej podoby.

6.3 Klasifikácia integrácie podľa vnútornej komunikácie v rámci integračného riešenia

V tomto prípade sa zaoberáme vnútornou architektúrou integračného riešenia, ktorá môže využiť široké spektrum rozličných architektúr informačných systémov. Jeden z podstatných atribútov tejto architektúry ale je, či komunikácia v integračnom riešení prebieha A) synchrónne, alebo B) asynchrónne.

Synchrónna komunikácia
V prípade synchrónnej, čiže súčasnej, koordinovanej komunikácie (zo starej Gréčtiny: syn:spolu, chronos: časy), počítame s tým, že sa obe komunikujúce strany zapájajú do komunikácie v tom istom čase, čím vzniká pevná väzba. Využívajú sa tu technológie ako RPC (remote procedure call), RMI (remote method invocation), HTTP, CORBA (starší protokol na platformovo-nezávislú komunikáciu aplikácií), alebo SOAP (protokol pre výmenu štruktúrovanej informácie). Takéto aplikácie často využívajú všeobecný návrhový vzor SOA (Service-Oriented Architecture), a významnými parametrami takejto služby sú potom: priemerná očakávaná doba medzi dvoma výpadkami (mean time between failures), priemerná doba potrebná na opravu v prípade výpadku (mean time to repair/recovery). Takéto parametre sa nastavujú v dohode medzi poskytovateľom služby a klientom (SLA=service level agreement, dohoda o úrovni poskytovaných služieb).

Asynchrónna komunikácia
V opačnom prípade pripúšťame, že integračné riešenie sa postará o zabezpečenie spojenia a prenos informácií aj vtedy, keď komunikujúce strany nie sú činné v rovnakom čase. Získavame voľnú väzbu. Komunikácia sa väčšinou zabezpečuje posielaním správ cez komunikačné kanály, pričom môžeme využiť buď architektúru založenú na decentralizovaných dátovodoch a filtroch (výhodné z hľadiska dobrej modifikovateľnosti) alebo na centrálnom komponente, ktorý riadi komunikáciu cez všetky dátové kanály.

7. Anotácie

V tejto kapitole sa spoločne pozrime na jednu technológiu využívanú pri vývoji informačných systémov, ktorá získava na popularite: anotácie v zdrojových súboroch.

Stačí na naprogramovanie aplikácie poznať jeden programovací jazyk? V minulosti platilo, že celá aplikácia sa naprogramovala pomocou jedného jazyka a jednej technológie. Dnes to funguje zriedka. Aplikácia potrebuje ukladať údaje do externej databázy, ktorá má vlastný dotazovací jazyk. Aplikácia prezentuje informácie používateľovi na webovej stránke, vytvorenej v samostatnom prezentačnom hypertextovom jazyku. Aplikácia komunikuje s inými aplikáciami využívajúc kanály s platformovo-nezávislým protokolom. Vývojári navrhujú aplikácie a vytvárajú používateľské rozhranie a dokumentáciu, pričom sa automaticky generujú zdrojové kódy, alebo naopak.

Na zjednodušenie prepojenia programu s uvedenými (a mnohými ďalšími) službami a nástrojmi sa v zdrojových kódoch objavujú nejaké "značky", resp. komentáre v dohodnutom formáte, ktoré sú často nad rámec pôvodných vylastností programovacieho jazyka. Takéto značky v zdrojových kódoch nazývame anotácie. Sú inštrukciami pre externé nástroje alebo rozšírenia jazyka. Automaticky rozširujú funkcionalitu vytváraného programu.

Napríklad v programovacom jazyku Java poznáme anotácie vo forme dokumentačných komentárov, ktoré sa môžu umiestňovať pred definície identifikátorov (tried, metód, premenných...) a pomocou automatického nástroja na generovanie dokumentácie API (javadoc) z nich vygenerovať technickú dokumentáciu vo formáte HTML. Zdrojový kód metódy java.lang.System.lineSeparator() vyzerá takto:

    /**
     * Returns the system-dependent line separator string.  It always
     * returns the same value - the initial value of the {@linkplain
     * #getProperty(String) system property} {@code line.separator}.
     *
     * On UNIX systems, it returns {@code "\n"}; on Microsoft
     * Windows systems it returns {@code "\r\n"}.
     */
    public static String lineSeparator() {
        return lineSeparator;
    }

a takto vyzerá výsledná vygenerovaná HTML dokumentácia:


Ešte zaujímavejšie sú anotácie zapísané pomocou zavináča a nejakého identifikátora. Java samotná pozná takéto anotácie, napríklad anotácia @Override pred definíciou metódy spracuj(String hodnota) znamená, že táto metóda prekrýva rovnakú metódu nejakej svojej nadtriedy. Načo je to dobré? Jednak pri čítaní kódu programátor hneď vie, že v nadtriede existuje rovnaká metóda a nemusí to kontrolovať v zdrojovom kóde nadtriedy. Okrem toho: kompilátor program neskompiluje, ak sme sa náhodou pomýlili a v prekrývajúcej metóde použili argument typu String namiesto argumentu typu int, ktorý je v prekrývanej metóde v nadtriede. Bez tejto anotácie by bol program bez problémov skompilovaný, lenže volanie spracuj(6) by spôsobilo volanie metódy v nadtriede a možno by sme si to ani nikdy nevšimli, len program by robil niečo iné, ako má. Anotácia pomáha skontrolovať, že úmysel prekryť metódu nadtriedy sa naozaj podaril.

To ale stále nie je veľa, čo ešte @-anotácie dokážu? Veľmi veľa!

Príklad 1: automatické testovanie jednotkovými testami (JUnit).
Anotácia @Test (a skupina ďalších anotácií, ktoré zavádza JUnit), umožňuje napísať kód, ktorý nie je bežný program, ale obsahuje jednotkové testy určené na otestovanie nejakého iného nášho vytváraného programu. Vývojové prostredia (ako napr. Eclipse, Netbeans) potom umožňujú spustiť jednotkové testy k nášmu vytváranému kódu bez toho, aby sme si museli vyrábať vlastné testovacie skripty a v prípade zlyhania testov zobrazia podrobný protokol. Jedným kliknutím sa vieme preniesť na miesto v programe, kde test zlyhal. Príklad automatického JUnit testu:

import org.junit.*;
import static org.junit.Assert.*;

public class TestPolska
{
  static double eps = 0.0000000001;

  @Test
  public void zoZadania()
  {
     String ex = "div sub div add div mul 6 4 3 1 3 2 2";
     double v = Polska.vyhodnot(ex);
     assertTrue("prvy priklad zo zadania" , eps > Math.abs(0.5 - v));
  }

  @Test
  public void dalsie()
  {
     ex = "div div sub 10 7 add -5 7 div -1 -4";
     v = Polska.vyhodnot(ex);
     assertTrue("vysledok nesedi pre vstup '" + ex + "'", eps > Math.abs(6 - v));
  }
}

Príklad 2: Mapovanie objektov v pamäti na relačnú databázu.
Relačné databázy vznikli v čase, keď objektovo-orientované programovanie neexistovalo, resp. nepoužívalo sa.

Prečo sa volajú relačné databázy relačné? Pretože sú medzi tabuľkami vzťahy - relácie? Nie preto. Tabuľka ako taká je relácia. Spomeňme si z diskrétnej matematiky, čo je to relácia! Relácia R na množine A je podmnožinou karteziánskeho súčinu A x A. Relácia medzi množinami A a B bude pomnožinou karteziánskeho súčinu A x B. Takže tabuľka so zoznamom študentov s poliami meno:string, ročník:int, odbor:string je podmnožinou karteziánskeho súčinu string x int x string, čiže množina trojíc (meno, ročník, odbor), kde meno je string, ročník je int a odbor je string.

Postupne síce vznikli aj objektovo-orientované databázy, ale veľmi sa neuchytili. V praxi sa skôr používajú relačné databázy a namapovanie objektov na ich tabuľky. V Jave EE (Enterprise Edition) to môžeme urobiť takto:

package daba.db;

import java.io.Serializable;
import javax.persistence.*;

@Entity
@Table(name = "AISStudent")
public class Student implements Serializable {

    @Id
    private Long ID;

    @OneToOne(cascade = CascadeType.ALL) @MapsId("ID")
    private Person person;
    
    private String DIRECTION;
       
    public Person getPerson() { return person; }
    
    public static Student newStudent(String firstname, 
                                     String lastname, 
                                     long yearStarted,
                                     String direction)
    {
        Student newst = new Student();        
        newst.person = Person.newPerson(firstname, lastname, yearStarted);
        newst.DIRECTION = direction;
        return newst;
    }
    
    public Long getId() { return ID; }
    public void setId(Long id) { this.ID = id; }

    public String getDirection() { return DIRECTION; }       
    public void setDirection(String direction) { this.DIRECTION = direction; }

    // ...    
}

Anotácia @Entity robí z triedy Student automaticky triedu, ktorej inštancie (objekty) sa dajú ukladať do relačnej databázy ako záznam jednej tabuľky, rovnako opačne - objekt sa dá jedným príkazom inicializovať z nejakého záznamu uloženom v tabuľke. Anotácia @Table túto triedu mapuje na konkrétnu tabuľku v databáze (aj bez nej by však už bola namapovaná na tabuľku s rovnakým menom - čiže Student). Anotácia @Id určuje, že premenná ID zodpovedá primárnemu kľúču tabuľky a túto hodnotu bude generovať priamo databáza pri uložení nového záznamu, relácia @OneToOne v kombinácií s premennou person triedy Person (ktorá je tiež @Entity - a je namapovaná na inú tabuľku) umožňuje vytvoriť automatické prepojenie viacerých databázových tabuliek reláciou one - to - one, s tým, že vymazanie alebo vytvorenie záznamu v jednej tabuľke automaticky vymaže alebo vytvorí záznam aj v druhej tabuľke. Premenná DIRECTION je automaticky namapovaná na rovnomenný stĺpec v tabuľke AISStudent. V programe nám potom stačí napísať:

    objectToInsert = Student.newStudent("Janko", "Hraško", 2014, "AIN");
    entityManager.persist(objectToInsert);

alebo:

    Student s = (Student)entityManager.find(Student.class, personId);
    entityManager.remove(s);

na vytvorenie nového alebo vymazanie záznamu, ale hlavná výhoda spočíva v tom, že údaje načítané z databázy nemusíme nijak transformovať do našej internej reprezentácie dát v pamäti, ale sa načítavajú automaticky.

Príklad 3: Context and dependency injection - automatické aktualizovanie referencií s rozličnou platnosťou
Java EE je populárny a silný nástroj na tvorbu webových aplikácií, v ktorých serverovská časť je implementovaná v Jave a stránky, ktoré sa zobrazujú v klientskom webovom prehliadači, sú napísané pomocou jazyka JSF (Java Server Faces). Na rozdiel od tradičného modelu skriptovaných stránok v PHP, kde program v jazyku PHP generuje HTML kód zobrazovaný v prehliadači, JSF umožňuje prepojiť jednotlivé prvky webstránky (editboxy, checkboxy a podobne) s premennými nejakého objektu Javovského programu, ktorý beží na serveri a stará sa o spracovanie požiadaviek klienta. Takéto objekty, hovorí sa im "beany" - kávové fazuľky, môžu mať rozličnú životnosť a prepojenie na rozličné služby: niektoré existujú len po dobu spracovania jedného HTTP requestu, iné existujú počas celej session jedného konkrétneho používateľa, ďalšie sú spoločné pre celú aplikáciu - vytvárajú sa po nainštalovaní (deploy) aplikácie na server a existujú až po jej odinštalovanie (undeploy). Pomocou anotácie @Inject môžeme napríklad do beanu, ktorý má životnosť jedného HTTP requestu, "injectnúť" bean so životnosťou celej používateľovej session. Java EE sa stará o to, aby bola táto referencia jedného beanu na druhý vždy správne aktualizovaná:

import java.io.Serializable;
import javax.inject.Inject;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;

@Named
@SessionScoped
public class Guess 
{
   // ...	
}


@Named
@RequestScoped
public class Userguess implements Serializable
{   
    @Inject
    Guess guess;

    // ...
}	


Anotácia @Named zabezpečí, že na premenné zadefinované v bean-e Guess s platnosťou celej používateľovej session sa môžeme na JSF stránkach tejto aplikácie odkazovať pomocou Expression Language a do stránky priamo vkladať aktuálnu hodnotu z javového objektu, ktorá bude po vstupe od používateľa automaticky v javovom objekte na strane servera aktualizovaná:
Enter here: <h:inputText id="guessinput" value="#{guess.newguess}" />
a anotácia @Inject znamená, že z metód triedy Userguess môžeme priamo voľať metódy triedy Guess, cez premennú guess, napríklad: guess.restart(), pričom sa zavolajú na inštancii, ktorá patrí tej správnej používateľovej session, hoci aplikáciu naraz používa viacero používateľov a pre každého server automaticky udržuje jeho vlastný session bean.

Jazyk Java vývojárom dovoľuje vytvárať celkom nové anotácie s významom aký sa im hodí. Takto si vývojárske firmy môžu vytvoriť vlastné rozšírenia frameworkov a podstatne urýchliť a zjednodušiť vývoj aplikácií. Ak vás téma zaujala, pozrite si jednoduchú ukážku ako vytvárať vlastné anotácie: Creating Custom Annotations and Using Them.

8. Čistý kód

Tvorba zdrojového kódu (programu) je síce v niektorých prípadoch mechanická a priamočiara činnosť, často je to však veľmi náročný a tvorivý proces, pri ktorom dochádza k opakovaným vylepšeniam, úpravám, preskupeniam, reorganizácii a podobne. Vo všetkých týchto prípadoch na to, aby sme zapísali jeden riadok nového kódu musíme v priemere prečítať 10 riadkov existujúceho kódu. Ak bude náš kód napísaný zrozumiteľne a čitateľne (čisto), tak aj proces jeho tvorby sa zrýchli a hlavne - jeho životnosť vzrastie. Životnosť zdrojového kódu môžeme určiť ako dobu, po ktorej uplynutí už ďalšie úpravy nie sú možné bez toho, aby sa celý program neprepísal odznova, pretože program je už priveľmi komplikovaný. Čistota kódu nespočíva v nejakom jednom zázračnom pravidle, ale dosahuje sa poctivou disciplínou a vytrvalým procesom založeným na množstve drobných zásad. Formulovanie a pripomínanie si týchto zásad znovu a znovu má pre vývojárov veľký význam. Podujal sa na to autor knihy Clean code, Robert C. Martin a my z nej vyberáme aspoň niekoľko informácií.

8.1. Definície čistého kódu od popredných informatikov

Bjarne Stroustrup, autor jazyka C++: Chcem, aby môj kód bol elegantný a účinný. Logika by mala byť priamočiara, aby sa chyby nemali kde skrývať, s minimálnymi závislosťami, aby údržba bola jednoduchá, kompletné ošetrenie chýb v súlade s jasne formulovanou stratégiou a s výkonom blízkym optimu, aby ľudia neboli v pokušení zavádzať do kódu neporiadok pomocou svojvoľných optimalizácií. Čistý kód plní svoju funkciu dobre.

Grady Booch, autor známej metódy objektovo-orientovanej analýzy a návrhu: Čistý kód je jednoduchý a priamočiary. Čistý kód sa číta ako dobre napísaná próza. Čistý kód nikdy nezatemňuje zámer návrhára, ale je plný jasných a presvedčivých abstrakcií a priamych tokov riadenia.

David Thomas, pôvodný vedúci vývojového tímu nástroja Eclipse: Čistý kód je čitateľný a môže ho vylepšovať aj iný vývojár ako jeho pôvodný autor. Má jednotkové a akceptačné testy. Používa zmysluplné názvy. Umožňuje radšej jeden spôsob vykonania úlohy, ako viacero. Obsahuje minimálny počet závislostí, ktoré sú jasne definované. Používa API zrozumiteľne a v minimálnej miere. Kód by mal byť kultivovaný (s dokumentačnými komentármi), pretože všetky potrebné informácie sa nedajú vyjadriť len v samotnom kóde.

Michael Feathers, autor nástroja CPPUnit pre jednotkové testy jazyka C++: Mohol by som vymenovať všetky dobré vlastnosti, ktoré som si u čistého kódu všimol, ale jedna z nich je zastrešujúca a vedie ku všetkým ostatným. Čistý kód vyzerá vždy tak, ako keby ho písal niekto poriadny a starostlivý. Neexistuje nič samozrejmého, čo môžete urobiť, aby ste ho zlepšili. O všetkých týchto záležitostiach už autor kódu premýšľal a ak sa pokúsite uvažovať o nejakých vylepšeniach, dovedie vás to naspäť tam, kde práve ste. Oceňujete kód, ktorý vám niekto zanechal - niekto, kto bol v tomto odbore veľmi poriadny a skláňate sa pred ním.

Ward Cunningham, autor prvej Wiki: To, že pracujete s čistým kódom, spoznáte podľa toho, že každá procedúra, cez ktorú prechádzate sa ukáže byť tým, čo ste do značnej miery predpokladali. Kód môžete označiť za nádherný, keď to vyzerá tak, ako keby bol použitý programovací jazyk pre daný problém stvorený.

8.2. Vybrané zásady čistého kódu

1. krátke funkcie
Pri písaní textov, článkov, publikácií sa treba usilovať o krátke vety. Jedna veta by mala vyjadrovať iba jednu myšlienku. Analogia k vetám v texte sú pri písaní zdrojového kódu funkcie. Mali by byť krátke a vyjadrovať jednu myšlienku. Tento najzákladnejší princíp udržiavania prehľadného kódu použijeme vždy, keď je to možné. Vždy keď sa z nejakej funkcie dá vytiahnuť zmysluplná časť kódu von do samostatnej funkcie, tak to treba urobiť. Výsledkom sú funkcie, ktoré sú veľmi krátke - často obsahujú len tri riadky, nevnárajú sa viac ako o dve úrovne odsadenia (napr. vnorené cykly, podmienky).
2. funkcie robia jednu vec
3. funkcie pracujú na jednej úrovni abstrakcie
4. všetky identifikátory sú výstižné pomenované, mená ktoré jasne hovoria čo robia, na čo sú určené
5. funkcie nemajú viac ako 3 argumenty
6. vyhýbame sa výstupným argumentom funkcií
7. nepoužívame boolovský argument funkcie, ktorý určuje/prepína dve alternatívne činnosti
8. funkcie nemajú mať bočné efekty
9. funkcia by mala buď niečo robiť (command) alebo niečo zisťovať (query), ale nie oboje naraz
10. ak používame výnimky, pokúsime sa kód spracovávajúci chybu oddeliť do samostatnej funkcie
11. snažíme sa písať kód tak čisto, že komentáre v zdrojových kódoch nie sú potrebné
12. zakomentovaný a mŕtvy kód (t.j. taký, ktorý je v programe, ale nikdy nebeží) odstraňujeme čo najskôr
13. snažíme sa v jednom súbore používať iba jeden programovací jazyk
14. ak poznáme názov funkcie, jej telo nás nesmie prekvapiť - malo by obsahovať zhruba to, čo podľa názvu očakávame
15. dbáme na pokrytie všetkých aj hraničných prípadov vstupov
16. kedykoľvek objavíme duplicitu v kóde, snažíme sa spoločné veci vytiahnuť do spoločnej abstraktnej nadtriedy
17. snažíme sa vyhýbať kľúčovému slovu static (v Jave)
18. v kóde nepoužívame číselné konštanty ale nahradíme ich symbolickými
19. snažíme sa vyhnúť záporom v názvoch identifikátorov
20. pri používani automatických jednotkových testov si skontrolujeme aká veľká časť kódu je testami pokrytá.

9. Agilné metódy

Ako sme v úvode naznačili, tvorba informačných systémov je veľmi dynamický proces, kde zákazníci - zadávatelia často nevedia sformulovať svoje predstavy dostatočne presne a vývojári ich nevedia dostatočne zastúpiť, pretože dostatočne nerozumejú oblasti, pre ktorú informačný systém vyvíjajú.

Tento obrovský problém môžu prekonať vyššou flexibilitou a postupným približovaním sa a zlaďovaním svojich predstáv smerom k budovanému výsledku. Takto to riešia evolučné a inkrementálne modely vývoja informačných systémov. Prínosom je aj metóda prototypovania v oboch jej verziách.

Úplné odtrhnutie sa od rigidných postupov pri vývoji informačných systémov zavádzajú agilné metódy, ktoré samé o sebe ani nie sú samostatným plnohodnotným modelom vývoja IS, ako skôr súhrnom odporúčaní a princípov pre bezbolestnejší proces vývoja.

Medzi tieto princípy patrí: Princípy agilných metód si možno osvojiť aj len čiastočne, do určitej miery. Dokument "Manifesto agilného vývoja softvéru" (agilemanifesto.org), ktoré vydali poprední experti na informačné systémy, hovorí:
Ľudia a komunikácia sú viac než procesy a nástroje.
Funkčný softvér je viac než vyčerpávajúca dokumentácia.
Spolupráca so zákazníkom je viac než dojednávanie zmluvy.
Radšej reagovať na zmenu než sa držať plánu.

Aj keď časť napravo je dôležitá, viac si ceníme ľavú časť.
Pretavené do 12 princípov agilného vývoja manifesto uvádza:
Našou najvyššou prioritou je uspokojiť zákazníka skorým a sústavným dodávaním hodnotného softvéru.
Zmeny požiadaviek sú vítané dokonca aj v neskorých fázach vývoja. Agilné procesy dokážu pretaviť zmenu na konkurečnú výhodu zákazníka.
Dodávame funkčný softvér často, od niekoľkých týždňov po niekoľko mesiacov, s uprednostnením čo najkratších intervalov.
Ľudia z biznisu a vývojári musia denne spolupracovať počas celého projektu.
Postavte projekty na motivovaných ľuďoch. Poskytnite im prostredie, podporu a dôverujte im, že svoju úlohu splnia.
Najlepším spôsobom odovzdávania informácií vývojovému tímu a v tíme je osobný rozhovor.
Základným ukazovateľom napredovania je funkčný softvér.
Agilné procesy podporujú trvalo udržateľný rozvoj. Sponzori, vývojári a užívatelia by mali byť schopní trvalo udržať konštantné tempo.
Sústavný dôraz na technickú vyspelosť a kvalitný návrh podnecujú agilitu.
Jednoduchosť - umenie vykonať naozaj len to potrebné, je nevyhnutnosť.
Samoorganizované tímy vytvárajú najlepšie koncepty, požiadavky a návrhy riešení.
Tím v pravidelných intervaloch vyhodnocuje sám seba s cieľom byť efektívnejší a prispôsobuje tomu svoje správanie.
V praxi by dodržiavanie týchto zásad malo znamenať: Jedna z najpopulárnejších agilných metód vývoja softvéru je SCRUM, ktorá sama seba vychvaľuje takto: Na rozdiel od klasických rigidných metód vývoja softvéru nie je stanovené poradie v ktorom sa jednotlivé činnosti vykonávajú ako ukazuje nasledujúci obrázok.


Obr. 75: Pri vývoji metódou SCRUM sa vykonávajú všetky aktivity (označené na obrázku rôznymi farbami) naraz (na x-ovej osi je čas).

Nasledujúci obrázok zachytáva väčšinu podstatných čŕt metódy SCRUM: Product Backlog je zoznam aktuálne známych požiadaviek na systém, resp. úloh, ktoré tím musí splniť. Vývoj napreduje inkrementálne po cykloch, ktoré sa nazývajú šprinty (sprint) a trvajú väčšinou 2-4 týždne. Pred každým šprintom sa zorganizuje schôdza "Sprint Planning Meeting", kde sa z product backlogu vyberie skupina požiadaviek, ktoré chce tím stihnúť realizovať v nasledujúcom šprinte: tvoria spolu Sprint Backlog a počas trvania šprintu je sprint backlog zafixovaný, požiadavky v ňom sa nemenia. Položky v backlogu by mali byť formulované z uhla pohľadu "čo nové to prinesie zákazníkovi?".


Obr. 76: (Skoro) celý scrum v jednom obrázku.

Počas šprintu sa tímy stretávajú každých 24 hodín na krátkej 15-30 minútovej schôdzi - "Daily Scrum Meeting", kde každý zodpovedá na tri otázky: "Čo som urobil včera?", "Čo budem robiť dnes?", "Čo mi stojí v ceste?". Na konci každého šprintu sa organizuje schôdza "Sprint Review", kam sú pozvaní všetci stakeholderi, ktorí majú záujem a kde tím prezentuje výsledky práve uskutočneného šprintu. Výsledkom každého nového šprintu je nová verzia softvéru s novými črtami, ktorá je pripravená na dodanie. Po každom šprinte sa organizuje spoločenské podujatie alebo schôdza "Sprint Retrospective", kde sa vývojári majú možnosť neformálne porozprávať o procese vývoja, rozdelení práce a rolí akýchkoľvek ťažkostiach ktorým čelia, vymeniť si skúsenosti a nápady. Napríklad môže každý pomenovať, čo by chcel začať robiť, čo by chcel prestať robiť a v čom by chcel pokračovať (Start/Stop/Continue). Pre lepšiu orientáciu o množstve potrebnej a vykonanej práce (väčšinou udávanej v hodinách) si tým vytvára tzv. Burndown Charts.


Obr. 77: Scrum burndown chart.

V metóde SCRUM existujú tri základné role, ktorých význam je potrebné si dobre uvedomiť:
Obr. 78: Scrum - celkový prehľad.

10. Soft Skills

Okrem sady odborných poznatkov z informatiky musí úspešný člen vývojového tímu efektívne zvládať spoločenskú a tímovú komunikáciu, uvedomovať si svoju rolu v tíme a role ostatných, poznať silné stránky všetkých členov tímu a vedieť, čo od nich môže očakávať, mať predstavu o tom, ako funguje riadenie v spoločnosti, kde pracuje a ešte veľa ďalších schopností a zručností, ktoré sa niekedy označujú termínom "soft skills". Napriek tomu, že sa nerodí každý s prirodzenou charizmou, pri troche kontroly a sebaovládania sa každý môže rovnocenne podieľať na tímovej spolupráci a prispievať k nej svojím rovným dielom.

10.1. Spôsoby riadenia v spoločnosti

Každá spoločnosť má nejakú vnútornú firemnú kultúru - sadu písaných a nepísaných pravidiel, podľa ktorých funguje. Podľa najzákladnejšieho rozdelenia organizácie práce a riadenia firmy rozlišujeme spoločnosti s rôznym spôsobom riadenia:

Silné líniové riadenie, kde sú pracovníci začlenení do jednotlivých oddelení zameraných na konkrétny druh práce a úzko sa špecializujú. Napríklad tam môžeme nájsť oddelenie analytikov, ktorí komunikujú so zákazníkmi pri špecifikácii systémov, návrhárov, ktorí na základe špecifikácie vytvárajú návrh, programátorov ďalej rozdelených podľa rozličných platforiem, testerov, dokumentačné oddelenie, správcov, ekonomické oddelenie, oddelenie stykov z verejnosťou, oddelenie ľudských zdrojov a podobne. Ak spoločnosť začína riešiť nový projekt, na projekt vyčlenia potrebný počet analytikov, návrhárov, programátorov, testerov, správcov, atď., ktorí pracujú zo svojho oddelenia zaradeného do celkovej riadiacej štruktúry firmy, prípadne projekt posúvajú z oddelenia na oddelenie ako prechádza fázami vývoja.

Výhodou je jasné rozdelenie kompetencií a zodpovednosti, dosah na realizovateľnosť, jasný kariérny postup v organizácii, rýchla komunikácia. Pracovníci, ktorí sa venujú jednému typu úloh získavajú v danej oblasti bohatšie skúsenosti a môžu byť produktívnejší a efektívnejší - to si ale vyžaduje veľkú firmu s množstvom projektov.
Nevýhodou je centralizácia, ťažko sledovateľné náklady konkrétnych realizovaných úloh, veľké množstvo administratívnych pracovníkov, flexibilnosť, a zvádza k mocenskému prístupu k riadeniu.

Silné projektové riadenie, kde majú pracovníci priradenú svoju množinu schopností a zručností a sú zaraďovaní na jednotlivé projekty podľa potreby. Po zaradení na projekt podliehajú priamo vedúcemu projektu, ktorý už priamo podlieha vedeniu spoločnosti, bez toho, aby boli pracovníci zaradený v zložitej hierarchickej štruktúre. Pracovník môže zastávať rozličné úlohy a vykonávať v rozličných projektoch iné činnosti.

Výhodou je flexibilita pri rôznom type úloh v organizácii, sledovanie nákladov a zodpovedností, lepšia motivácia pracovníkov.
Nevýhodou je, že si vyžaduje vyššiu kvalitu manažérov, niekedy je dosah na členov tímu problémový, efektivita a spoľahlivosť je ohrozená, pretože tímy nie sú stabilné.

10.2. Základné postoje pri tímovej práci a v rozhodovaní/osobnostný profil

Teória o základných postojoch pri tímovej práci hovorí, že človek je kombináciou základných profilov:
  1. Orientácia na základy a istoty: ide o človeka, ktorý je dobrý rutinér, spoľahlivý, dochvilný, je každý deň v práci od 8 do 16 hodiny, má rád poriadok a jasne zadefinovanú prácu.
  2. Orientácia na výsledky: vysoko motivovaný jedinec, ktorý musí cítiť, že je produktívny, každý deň, týždeň, mesiac musí za sebou vidieť zodpovedajúci kus práce, hľadá spôsoby ako zefektívniť prácu seba i svojho tímu, motivujú ho dosiahnuté ciele, odmena a uznanie.
  3. Orientácia na rozvoj: človek, ktorého najviac baví objavovať nové, učiť sa, stále sa posúvať k novým obzorom, študovať a zlepšovať seba i svoje okolie, je ochotný venovať a obetovať veľa úsilia a zdrojov pre rozširovanie svojich vedomostí a schopností.
  4. Orientácia na spoluprácu: veľmi cenný člen kolektívu, ktorý dobre vychádza so všetkými jeho členmi, zmierňuje a rieši konflikty, dobre komunikuje a má radosť predovšetkým zo spoločného úspechu a spoločnej práce.

Obr. 79: Základné postoje pri tímovej práci - charakteristické vlastnosti a osobnostný profil.

Každý človek je v každom z uvedených štyroch smerov nejakým spôsobom rozvinutý - podľa toho na príslušnej osi zvolíme bod: čím viac smerom k rohu obdĺžnikového obrazca, tým viac je rozvinutý v príslušnom kvadrante. Pospájaním takto nájdených bodov vzniká zelený štvoruholník, ktorý tvorí osobnostný profil danej osoby.

10.3. Tímové role

Predstavme si skupinu ľudí, ktorej zadáme nejakú náročnú úlohu (napríklad skupina na brehu rieky Dunaj pri hrade Devín má za úlohu dostať sa na druhý breh do Rakúska) a budeme pozorovať, ako sa tejto úlohy chopia. V priebehu niekoľkých chvíľ sa v skupine vyprofilujú určité základné charakteristické triedy správania, ktoré by sme mohli rozdeliť na nasledujúce:
  1. Šéf (vedúci, koordinátor) - manažér
    • kľudný, dominantný, stabilný, uznávaný
    • koordinuje tím, vedie ho k spolupráci a k dosiahnutiu cieľov
    • v diskusii nedominuje, jeho príspevkom je položenie správnych otázok
    • jeho vedenie spočíva predovšetkým v sociálnej rovine, má osobné kúzlo a autoritu
  2. Navrhovateľ (režisér, konštruktér)
    • činorodý, impulzívny, dominantný, extrovertný
    • navrhuje a riadi práce v tíme
    • vyžaduje akciu, poháňa tím k vyššej produktivite
    • je spoločensky orientovaný, netrpezlivý, temperamentný
  3. Novátor (chrlič nápadov)
    • inteligentný, individualistický, dominantný, introvertný
    • prichádza s novými nápadmi a podnetmi, vyhľadáva problémy a originálnym spôsobom ich rieši
    • má veľkú predstavivosť a je zdrojom inšpirácie pre celý tím
    • zaujímajú ho len globálne náhľady, žiadne detaily
  4. Upozorňovateľ (overovateľ, rypák)
    • racionálny, stabilný, skeptický, inteligentný
    • hodnotí nápady, posudzuje riešenie, varuje pred chybami, hrá rolu diablovho advokáta
    • dokáže jasne a zrozumiteľne analyzovať a argumentovať
    • nie je príliš nadšený, ale vďaka tomu je najobjektívnejším členom tímu a je veľmi dôležitý
  5. Organizátor (ťahač)
    • svedomitý, disciplinovaný, výkonný, stabilný
    • stará sa, aby nápady a rozhodnutia boli transformovateľné do konkrétnych úloh a zaisťuje, aby boli realizované
    • pracuje systematicky, má rád pevné štruktúry
    • býva nepružný a potrebuje impulz - ak ho dostane, dotiahne veci do konca
  6. Objavovateľ (zháňač, vyhľadávač zdrojov)
    • spoločenský, čulý, priateľský, dominantný
    • zhromažďuje informácie a nápady, nadväzuje kontakty, získava podporu zvonku
    • najlepšie sa mu darí pod tlakom, rýchlo sa nadchne, ale nadšenie ho rýchlo opustí
    • je dobrý improvizátor
  7. Podporovateľ (hasič, strážca atmosféry)
    • citlivý, mierny, extrovertný, nedominantný
    • je priateľský, vie dobre vnímať a počúvať, tlmí konflikty, podporuje ostatných a stará sa o dobré vzťahy v tíme
    • rozvíja nápady, všíma si potreby a problémy ostatných
  8. Dokončovateľ (doťahovač)
    • tichý, starostlivý, úzkostlivý, introvertný
    • má rád jasné pokyny
    • stará sa o dodržiavanie poriadku a časových plánov
    • do detailov všetko kontroluje a dáva pozor, aby sa na nič nezabudlo
    • je starostlivý, občas až veľmi
    • nerád deleguje prácu na ostatných
Pochopiteľne ľudia nie sú vždy presne vyhranení v jednej konkrétnej roli, ale kombináciou niekoľkých viacerých.

11. Informačné systémy v štátnej správe

Zavádzanie informačných systémov do štátnej správy a verejných služieb je obrovská výzva, ktorá má svoje špecifiká - zadávateľom nie je súkromný zákazník, ktorý bude systém používať, ale štátni úradníci. Formulácie požiadaviek podliehajú politickým prioritám, ktoré sa s každou vládou mierne menia spolu s celkovou "firemnou kultúrou" riadenia krajiny a verejných projektov. Napriek tomu si všetci politici a zodpovední úradníci uvedomujú nevyhnutnosť informatizácie a zachovávajú aspoň čiastočnú kontinuitu. Asi najperspektívnejšie zákazky vznikajú v súlade s národnou stratégiou, ktorú nám dáva vypracovať Európska Únia.

Slovenská Republika vstúpila do Európskej Únie 1.mája 2004 a zapojila sa tak do finančných schém tejto inštitúcie. Tie sú pomerne komplikované a keďže sa naša krajina vzdala časti právomocí v prospech tejto nadnárodnej inštitúcie, je dobré si urobiť o nich aspoň krátky prehľad.

Financovanie EÚ sa deje v sedemročných tzv. programových obdobiach. Predchádzajúce programové obdobie trvalo v rokoch 2007-2013, ale v našom regióne dobieha dlhšie, vďaka výnimke, ktorú sme dostali vzhľadom na pomalé čerpanie prostriedkov vyhradených pre krajiny v našom regióne.

Ďalšie obdobie má trvať v rokoch 2014-2020.

Obrovský objem výdavkov tvoria štrukturálne a investičné fondy (predtým nazývané štrukturálne a kohézne), ktorých je 5 a viaceré sú zamerané na vyrovnávanie rozdielov medzi členskými krajinami. Rozdeľovanie týchto prostriedkov zväčša riadia národné vlády a agentúry:

Európsky fond regionálneho rozvoja (EFRR)
Európsky sociálny fond (ESF)
Kohézny fond (KF)
Európsky poľnohospodársky fond pre rozvoj vidieka (EPFRV)
Európsky námorný a rybársky fond (ENRF)


Najväčšie množstvo financií EÚ prúdi do poľnohospodárskych dotácií.

Okrem toho má EÚ rôzne priame výdavky a asi 800 grantových programov rôzneho rozsahu, pričom pre nám blízku oblasť výskumu a vzdelávania je relevantný najmä Rámcový program pre výskum a inovácie (HORIZON 2020, 80 miliárd Eur na celé obdobie 2014-2020). Mnohé z týchto programov riadi a prostriedky rozdeľuje priamo EÚ.

Jednotlivé krajiny si pre využívanie fondov formulujú svoje Operačné programy (OP), ktoré zodpovedajú ich špecifickým prioritám stanoveným v Národnom rozvojovom pláne (NRP) a financujú ich zo zdrojov zo štrukturálnych a kohéznych fondov. Operačné programy vyplývajú z konkrétnej špecifikácie v Národnom strategickom referenčnom rámci (NSRR), ktorý na celé programové obdobie vypracováva a schvaľuje národná vláda a potom po konzultáciách vlády s Európskou Komisiou (EK) a vyžiadaných úpravách ho definitívne schvaľuje EK.

Na Slovensku existovali v období 2007-2013 tieto OP:

1. Regionálny operačný program
2. Životné prostredie
3. Doprava
4. Informatizácia spoločnosti
5. Výskum a vývoj
6. Konkurencieschopnosť a hospodársky rast
7. Vzdelávanie
8. Zamestnanosť a sociálna inklúzia
9. Zdravotníctvo
10. Technická pomoc
11. Bratislavský kraj

Napokon sa dostávame k téme našej kapitoly, keďže 4. operačný program bol zameraný na informatizáciu spoločnosti (OPIS - operačný program informatizácia spoločnosti).

Financovanie cez OP podrobne definuje príslušný schválený dokument. OPIS určuje štyri prioritné osi:

1. ELEKTRONIZÁCIA VEREJNEJ SPRÁVY A ROZVOJ ELEKTRONICKÝCH SLUŽIEB
2. ROZVOJ PAMÄŤOVÝCH A FONDOVÝCH INŠTITÚCIÍ A OBNOVA ICH NÁRODNEJ INFRAŠTRUKTÚRY
3. ZVÝŠENIE PRÍSTUPNOSTI K ŠIROKOPÁSMOVÉMU INTERNETU
4. TECHNICKÁ POMOC


V operačnom programe sú k dispozícii obrovské prostriedky a nepochybne existuje potenciál na zlepšenie ich čerpania. Zoznam schválených projektov s výškou nenávratného finančného príspevku pre jednotlivé prioritné osi čitateľ nájde na webstránke Ministersva financií SR venovanej informatizácii spoločnosti, alebo priamo na stránkach operačného programu IS, linka na konkrétnu stránku: Schválené a neschválené žiadosti o nenávratný finančný príspevok projektov prioritnej osi 1 a 3, resp. Prijímatelia pomoci v 2. prioritnej osi.

Z projektov pre zaujímavosť vyberáme, na stránkach prioritných osí sú uvedené podrobnosti.

Os 1 a 3:

Elektronizácia služieb matriky, Ministerstvo vnútra SR
Elektronizácia služieb Sociálnej poisťovne, Sociálna poisťovňa
Elektronické služby Ministerstva práce, sociálnych vecí a rodiny SR na úseku výkonu správy štátne sociálne dávky, sociálna pomoc a pomoc v hmotnej núdzi, Ministerstvo práce, sociálnych vecí a rodiny SR
IS Registra fyzických osôb, Ministerstvo vnútra SR
Elektronické služby pre osvedčenie o evidencii vozidla, Ministerstvo vnútra SR
Dátové centrum obcí a miest, DataCentrum elektronizácie územnej samosprávy Slovenska
Elektronizácia služieb Mestského úradu v Žiline, Mesto Žilina


Os 2:

Digitálna galéria, Slovenská národná galéria
Digitálny pamiatkový fond, Pamiatkový úrad Slovenskej republiky
Dokumentačno-informačné centrum rómskej kultúry, Štátna vedecká knižnica v Prešove
Digitálna knižnica a digitálny archív, Slovenská národná knižnica
Digitálna audiovízia, Slovenský filmový ústav