Modulárne a viacvrstvové informačné systémy

V propagačných materiáloch sa pojmy „modulárny“ a „viacvrstvový“ používajú iba málokedy, prípadne len akosi mimochodom. Pritom bez týchto dvoch vlastností by nemal byť žiaden väčší informačný systém.

Modulárny softvér je taký, ktorý sa skladá z takzvaných modulov. To sú relatívne nezávislé časti kódu, vykonávajúce len presne vymedzenú oblasť činností. Moduly môžu medzi sebou komunikovať len pomocou presne určených rozhraní. Viacvrstvový systém používa na komunikáciu s okolím niekoľko úrovní, pričom každá z nich komunikuje len so svojimi najbližšími (pre pochopenie viď príklad).

Modulárnosť možno znázorniť na príklade informačného systému s nasledovnými funkciami (inšpirovali sme sa jedným naším skutočným produktom):
  1. Správa textových dokumentov, pridávanie popisov, zoraďovanie a výpisy podľa určených kritérií
  2. Fulltextové vyhľadávanie v uložených dokumentoch
  3. Pridávanie textov z článkov na internete
  4. Publikovanie článkov vo forme vhodnej pre tlač

Každá z týchto činností je sama o sebe značne náročná. Ak vám stačia iba niektoré z nich (napríklad nepotrebujete pridávanie z internetu ani publikovanie), v prípade integrovaného produktu by ste ich museli kúpiť tak či tak. Ak by ale tieto funkcie boli implementované ako moduly, stačilo by vám zaplatiť len za to, čo potrebujete. Navyše tým o nič neprídete, keďže v prípade potreby sa ďalšie moduly dajú doplniť bez problémov.

Jedným z typických príkladov viacvrstvového prístupu je ukladanie dát na disk cez súborový systém. Keď zadáte príkaz na otvorenie súboru „dokument.txt“, prebieha približne (a veľmi zjednodušene) takýto proces:
  1. Operačný systém na základe vášho príkazu zostaví požiadavku pre modul prístupu na diskové jednotky.
  2. Modul prístupu zistí, aký súborový systém je použitý a podľa toho zavolá príslušný ovládač.
  3. Ovládač súborového systému pomocou volaní modulu hardvérovej abstrakcie získa potrebné údaje (najprv priradí zadanému názvu súboru jeho adresu a následne ho postupne načíta).
  4. Modul hardvérovej abstrakcie zistí, z akého zariadenia sa má čítať (disketová jednotka, pevný disk, CD-ROM, a podobne) a zavolá príslušný ovládač.
  5. Ovládač zariadenia preloží požiadavku do tvaru, ktorému príslušné zariadenie rozumie, a pošle mu ju.

Vďaka abstrakčným vrstvám nemusíte pri otváraní súboru ani tušiť, ako je vlastne na disku uložený, či nebodaj poznať presné adresy. Vám stačí zadať názov súboru a o všetko ostatné už bude postarané automaticky.

Používanie modulov prináša množstvo výhod, ktoré sú tým citeľnejšie, čím rozsiahlejší je vytváraný informačný systém. V prvom rade umožňuje nezávislý vývoj rôznych častí kódu, zmeny či nebodaj úplné prepracovanie jedného modulu nijako neovplyvnia tie ostatné. Vďaka tomu môžu byť potrebné operácie implementované skôr bez toho, aby to sťažilo vývoj tých ostatných. Na každom module môže nezávisle pracovať iná skupina programátorov. Chyby v jednom module neovplyvnia funkčnosť ostatných modulov (maximálne im môžu chýbať jeho výstupy). V kóde rozdelenom na moduly sa dajú chyby oveľa ľahšie nájsť i odstrániť. Situácia bežná pri monolitických systémoch, keď oprava jednej chyby spôsobí inú chybu, je pri modulárnej štruktúre oveľa zriedkavejšia.

Viacvrstvový prístup je v prvom rade investíciou do budúcnosti. Umožňuje jednoduchú a rýchlu zmenu či doplnenie nových rozhraní. Ako sme videli na príklade ukladania na disk, ak chceme použiť nové zariadenie či súborový systém, nemusíme prepisovať nič v samotnom jadre operačného systému ani v ostatných programoch, ktoré používame. Stačí pridať príslušné ovládače a je to. Po nejakom čase používania informačného systému sa takmer vždy stane, že niektorá jeho časť prestane byť postačujúca. Napríklad použitý databázový systém už nezvláda také množstvo dát. Ak bola aplikácia napísaná „priamo naň“, neostáva vám nič iné, než ju celú nechať prerobiť; to znamená nielen vysoké výdavky, ale aj vysokú pravdepodobnosť nových chýb. V prípade, že používa abstrakčné vrstvy, stačí iba doplniť príslušný ovládač a žiadne zmeny v aplikácii netreba.

Použitie abstrakčných vrstiev má však aj okamžitý pozitívny efekt: oveľa ľahšie sa v ňom dajú nájsť a opraviť chyby.

Prakticky jedinou významnou nevýhodou použitia modulárnej štruktúry a viacvrstvového prístupu je dlhší počiatočný vývoj. Spôsobuje to nutnosť návrhu a implementácie obslužného kódu pre moduly, ktorý bude zabezpečovať komunikáciu medzi nimi a možnosť pridávania podľa potreby.

Z tohto dôvodu sa neoplatí tento spôsob používať pre jednoduché systémy. Ak napríklad potrebujete pridať na svoju stránku jednoduchú knihu návštev, nemá význam sa trápiť s abstrakciou a modulmi, pretože aj kompletné prerobenie takéhoto kódu je jednoduché a časovo nenáročné. Pri väčších systémoch je už použitie modulov a abstrakcie veľmi výhodné, niekedy dokonca až nevyhnutné.

Hoci minimálne 90 percent informačných systémov by malo byť modulárnych a viacvrstvových, existujú aj výnimky. Typickým príkladom sú systémy vyžadujúce prácu v reálnom čase (real-time), pri ktorých je rýchlosť a spoľahlivosť tak dôležitá, že sa oplatí zaplatiť vysoké náklady spojené s údržbou a aktualizáciami.

Pbatenghyngvbaf Lbh ner n bofreinag jro unpxre Vs Lbh jnag n wbo va bhe pbzcnal cyrnfr znvy gb gbhtuthl ng ci2p qbg fx Unir n avpr qnl
Šťastie je radosť bez ľutovania.
		-- Tolstoj
    function perr($msg, $level)
    {
        echo $msg;
    }

    function readcsv_get_entity($fh, $sep = ';')
    {
        $entity = array();
        $attr = '';
        $eoe = false;

        while((! feof($fh)) && (! $eoe))
        {
            $ch = fgetc($fh);
            switch($ch)
            {
                case "\r":
                    break;
                case "\n":
                    $eoe = true;
                case $sep:
                    array_push($entity, $attr);
                    $attr = '';
                    break;
                case '"':
                    $ch = '';
                    while((! feof($fh)) && $ch != '"')
                    {
                        $ch = fgetc($fh);
                        $attr .= $ch;
                    }
                    $attr = rtrim($attr, '"');
                    break;
                default:
                    $attr .= $ch;
            }
        }

        if(feof($fh) && ($entity || $attr))
        {
            array_push($entity, $attr);
        }
        elseif(feof($fh))
        {
            $entity = false;
        }

        return $entity;
    }

    function readcsv_parsecsv($filename)
    {
        $ret = false;
        $sep = ';';
        $line = '';
        $line_num = 0;
        $cells = array();
        $names = array();

        $fh = fopen($filename, 'r');
        if(! $fh)
        {
            perr('Failed to open file \''
                . $file . "'\n", 8);
        }
        else
        {
        $line = '';
        while(! feof($fh))
        {
        $entity = readcsv_get_entity($fh, $sep);

        if($entity)
        {
        if($line_num == 0)
        {
        foreach($entity as $name)
        {
            array_push($names, trim($name, '"'));
        }
        }
        else
        {
        foreach($entity as $index => $val)
        {
        if(isset($names[$index]))
        {
            $cells[$line_num][$names[$index]]
                = trim($val, '"');
        }
        else
        {
            array_push($cells[$line_num],
                trim($val, '"'));
        }                            
        }
        }
        $line_num ++;
        }
        }
        fclose($fh);
        }

        return $ret;
    }
        
    function perr($msg, $level)
    {
        echo $msg;
    }

    function readcsv_get_entity($fh, $sep = ';')
    {
        $entity = array();
        $attr = '';
        $eoe = false;

        while((! feof($fh)) && (! $eoe))
        {
            $ch = fgetc($fh);
            switch($ch)
            {
                case "\r":
                    break;
                case "\n":
                    $eoe = true;
                case $sep:
                    array_push($entity, $attr);
                    $attr = '';
                    break;
                case '"':
                    $ch = '';
                    while((! feof($fh)) && $ch != '"')
                    {
                        $ch = fgetc($fh);
                        $attr .= $ch;
                    }
                    $attr = rtrim($attr, '"');
                    break;
                default:
                    $attr .= $ch;
            }
        }

        if(feof($fh) && ($entity || $attr))
        {
            array_push($entity, $attr);
        }
        elseif(feof($fh))
        {
            $entity = false;
        }

        return $entity;
    }

    function readcsv_parsecsv($filename)
    {
        $ret = false;
        $sep = ';';
        $line = '';
        $line_num = 0;
        $cells = array();
        $names = array();

        $fh = fopen($filename, 'r');
        if(! $fh)
        {
            perr('Failed to open file \''
                . $file . "'\n", 8);
        }
        else
        {
        $line = '';
        while(! feof($fh))
        {
        $entity = readcsv_get_entity($fh, $sep);

        if($entity)
        {
        if($line_num == 0)
        {
        foreach($entity as $name)
        {
            array_push($names, trim($name, '"'));
        }
        }
        else
        {
        foreach($entity as $index => $val)
        {
        if(isset($names[$index]))
        {
            $cells[$line_num][$names[$index]]
                = trim($val, '"');
        }
        else
        {
            array_push($cells[$line_num],
                trim($val, '"'));
        }                            
        }
        }
        $line_num ++;
        }
        }
        fclose($fh);
        }

        return $ret;
    }