\section{Úpravy aplikační vrstvy}
\label{sec:upravyaplikacni}

\secpreview{Tato část se věnuje změnám na úrovni aplikační vrstvy, jež byly
  představeny v~oddíle~\ref{sec:aplikacni2}.  Dále nabízí několik dalších
  postřehů k~implementaci základových tříd.}

Za největší problém \ientryb{aplikační vrstva}{aplikační vrstvy} bylo označeno
nevhodné použití dědičnosti (\ref{sec:dedicnost}), tj. odvození třídy
\cl{Tutos\_Module} ze třídy \cl{Tutos\_Base}.

Modely na obrázcích~\ref{fig:tutosbase} a~\ref{fig:tutosmodule} poskytují
detailnější pohled na tyto třídy.


\subsection{Třída \cl{Tutos\_Base}}
\label{sec:tutosbase}

\modelrot{Třída \cl{Tutos\_Base}}{tutosbase}

Na obrázku~\ref{fig:tutosbase} je možné nalézt tyto skupiny metod ve
\ientryb{třída \cl{Tutos\_Base}}{třídě \cl{Tutos\_Base}}:

\begin{itemize}
  
\item \emph{Databázové metody.}  To jsou metody, jež by určitým způsobem měly
  být přetíženy v~odvozených třídách --- každá třída ví sama nejlépe, které
  atributy a jak uložit do databáze.
  
  Některé se však nepřetěžují: \inlinecode{Tutos\_Base::save\_obj\_id()} a\\
  \inlinecode{Tutos\_Base::del\_obj\_id()}, nebo je to ve většině případů není
  nezbytné (např.~\inlinecode{Tutos\_Base::readHistory()})
  
\item \emph{XML metody.}  Těchto metod je použito pro podporu XML exportu
  (a~importu).
  
\item \emph{ACL metody.}  \ientrya{ACL} metody se používají pro kontrolu
  prováděných operací nad objektem.
  
\item \emph{Užitečné funkce.}  Jedná se o skupinu \uv{šikovných} operací, jež
  je dobré mít stále po ruce, jako například získání textové reprezentace
  objektu.

\end{itemize}

Všechny tyto metody se jistě vztahují právě k~hierarchii tříd odvozených
z~\cl{Tutos\_Base} a ač můžeme diskutovat o zlepšení návrhu (možná by stálo za
to uvažovat o rozdělení třídy kvůli jejímu rozsahu, viz dále), nelze označit
její předpis za nevhodný.

\subsection{Třída \cl{Tutos\_Module}}
\label{sec:tutosmodule}

\modelrot{Třída \cl{Tutos\_Module}}{tutosmodule}

Na obrázku~\ref{fig:tutosmodule} je společně se \ientryb{třída
  \cl{Tutos\_Mo\-du\-le}}{třídou \cl{Tutos\_Module}} zobrazena ještě třída
\cl{Modules}, která je s~touto třídou velmi úzce spjata.  Při pohledu na
operace obou tříd je možné říci, že až právě třída \cl{Modules} a její operace
dává třídě \cl{Tutos\_Module} její skutečný smysl.

Význam a funkce těchto tříd bude nejviditelnější z~příkladu.

\subsubsection{Tvorba vlastního modulu}
\label{sec:vlastni}

Pokud chceme rozšířit chování \tts{}u, je nejvhodnější udělat to skrze definici
vlastního modulu, než bezhlavou úpravou existujícího kódu.  Vývojář tak získá
řadu funkčnosti automaticky díky využití aplikačního rámce (application frame),
jež poskytují třídy \cl{Tutos\_Module} a \cl{Modules}.  Konkrétní přínosy jsou:

\begin{itemize}
  
\item Začlenění do ACL modulů --- jednotlivým uživatelům lze
  po\-vo\-lit/za\-ká\-zat využití modulu.
  
\item Automatické využití lokalizačních souborů poskytnutých společně
  s~modulem.

\item Jednoduchá instalace modulu do libovolné distribuce \tts{}u.
  
\item Podporu při tvorbě GUI, pokud vývojář užívá vlastních tříd odvozených ze
  základové třídy \cl{Layout} (doporučeno).

\end{itemize}

Při tvorbě vlastního modulu je možné postupovat podle několika málo
jednoduchých kroků.  Za předpokladu hotové aplikační logiky lze tvorbu nového
modulu v~současnosti shrnout takto:

\begin{enumerate}
  
\item \emph{Vytvoření konfiguračního souboru modulu}.  Úkoly konfiguračního
  souboru (podle konvence označovaného jako \inlinecode{mconfig}) jsou dva:

  \begin{enumerate}

  \item Přidat modul do globálních datových struktur \tts{}u --- konkrétně do
    několikrát zmiňované třídy \cl{Modules}.
    
  \item Definovat všechna globální nastavení nutná pro tento modul (globální
    proměnné, jimiž může uživatel měnit chování modulu, odkazy na knihovny
    třetích stran).

  \end{enumerate}
  
  Konfigurační soubor má pro jednoduché moduly typicky několik málo řádek
  zdrojového kódu (cca 30).
  
\item \emph{Definovat vlastní třídu odvozenou z~\cl{Tutos\_Module}.}  Vůbec
  není nutné definovat všechny metody rozhraní třídy \cl{Tutos\_Module} (ty
  nepřepsané nevykonávají žádný kód).  V~praxi se u jednoduchých modulů
  vyplatí:

  \begin{enumerate}
    
  \item Přetížit \cl{Tutos\_Module::getOverviewLink()}.  Tím může \tts{}
    generovat odkaz na hlavní HTML stránku našeho modulu.
    
  \item Přetížit další metody podle potřeby, například\\
    \cl{Tutos\_Module::getNewLink()}, jež napomáhá při generování kontextové
    nabídky \tts{}u.
    
  \item Definovat soukromé metody pro využití v~rámci modulu, vhodným
    kandidátem může být například metoda pro sestavení kontextové nabídky
    modulu (pokud se nemění) apod.

  \end{enumerate}
  
  Typicky jde opět o několik málo řádek zdrojového kódu (cca 50--100).
  
\item \emph{Vytvořit GUI našeho modulu.}  V~naprosté většině to znamená
  vytvořit HTML stránky, při jejichž tvorbě může značně pomoci odzvození ze
  společných základových tříd (\cl{Layout}).
  
  Zde pochopitelně množství nutného kódu záleží na propracovanosti rozhraní.
  Může být značné (rozsáhlé formuláře, složitá kontrola vstupních dat apod.).

\item \emph{Instalace.} Doporučuje se ukládat všechny soubory nového modulu do
  vlastního adresáře.  Pak stačí adresář překopírovat do kořenového adresáře
  instalace \tts{}u a zavést konfigurační soubor modulu (\inlinecode{mconfig})
  do globálního konfiguračního souboru.  Od tohoto okamžiku již lze nad modulem
  nastavovat oprávnění a používat jeho HTML stránky.

\end{enumerate}


\subsubsection{Odstranění dědičnosti}
\label{sec:odstraneni}

Z~tohoto krátkého příkladu a části~\ref{sec:tutosbase} je jistě patrné, že
třída \cl{Tutos\_Mo\-du\-le} a \cl{Tutos\_Ba\-se} mají velmi málo společného
--- jejich odpovědnosti jsou naprosto odlišné.

Zatímco instance \cl{Tutos\_Base} představuje perzistentní objekt systému a
stará se o jeho ukládání a načítání, XML representaci a obsluhuje s~ním spojené
oprávnění, instance třídy \cl{Tutos\_Module} představuje rozšíření \tts{}u a
její odpovědností je komunikovat s~jádrem systému (objektem třídy
\cl{Modules}).  Objekt třídy \cl{Tutos\_Module} nemá zájem o to být uložen
v~databázi, natož aby byl převoditelný do XML podoby.

Jediným společným prvkem je využití \ientrya{ACL}, avšak v~případě objektu
\cl{Tutos\_Module} jde o kvalitativně zcela odlišnou formu
oprávnění\footnote{Potvrzením této skutečnosti je i to, že se uchovává ve
  zvláštních tabulkách a interpretuje se jinak.} --- jde o oprávnění nad částí
funkčnosti celé aplikace (například nad \emph{správou kontaktů}), zatímco
v~případě \cl{Tutos\_Base} jde o oprávnění nad jedním perzistentním objektem
(například jedním konkrétním kontaktem).

Lze konstatovat, že požadavek na oddělení těchto tříd (tj.~zrušení třídy
\cl{Tutos\_Base} jakožto předka třídy \cl{Tutos\_Module}), je oprávněný.

Když už se měla použít dědičnost, byla by asi vhodnější vícenásobná dědičnost
(a~považovat ji za implementaci rozhraní).


\subsection[Další diskuze]{Další diskuze k~aplikační vrstvě}
\label{sec:dalsi}


\subsubsection{Zpracování vstupu uživatele}
\label{sec:zpracovani}

\paragraph{\tts{}}

Při zpracování vstupu se v~\tts{}u typicky provádí:

\begin{itemize}
  
\item Kontrola vstupních dat získaných z~formulářových polí.  Jde o běžné
  kontroly typu platné datum, rozsah čísla, \dots
  
\item Kontrola složitějších integritních omezení --- jsou oprávnění uživatele
  dostatečná?, existuje objekt, na který je odkazováno? je vstup uživatele
  jednoznačný?, je služba (SMTP například) k~dispozici?, \dots

\end{itemize}

U některých metod \cl{Tutos\_Module} je uvedeno, že nejsou příliš užívány (viz
obrázek~\ref{fig:tutosmodule}).  Jsou součástí třídy \cl{Tutos\_Module} od
prvotních návrhů systému a jejich cílem bylo pomoci vývojáři zaregistrovat data
získávaná z~formulářů a pomoci s~jejich automatickým zpracováním (kontrola
typů, základní operace --- získání referencí na objekty apod.).

Ukazuje se však, že každý formulář je příliš specifický a nelze (až na
nejjednodušší případy) tuto funkčnost nějak generalizovat pro kontrolu více
formulářů najednou, resp.~je nevhodné ji takto pojímat a umísťovat do třídy
\cl{Tutos\_Module}, blíže k~tomuto tématu viz
kapitola~\ref{sec:upravyprezentacni}.

Proto je většinou ponechána kontrola dat z~formulářů buď (1)~na úrovni
prezentační vrstvy, která, než nastaví hodnoty objektů z~formulářů, provede
kontrolu ve vlastním kódu, anebo (2)~přímo na aplikační třídě odvozené
z~\cl{Tutos\_Base}.

Ze složitějších kontrol je nejčastější:

\begin{enumerate}

\item \emph{Ověření nějakého oprávnění.} K~tomuto účelu velmi dobře slouží ACL
  metody třídy \cl{Tutos\_Base}.
  
\item \emph{Ověření nějaké aktuální hodnoty.}  Není určen žádný postup.
  
\item \emph{Ověření nějaké hodnoty na odkazovaném objektu.}  Je nutno získat
  odkazovaný objekt a pak na něm provést kontrolu jako výše.  Odkazovaný objekt
  lze v~\tts{}u nejsnáze získat pomocí funkce\\
  \inlinecode{Result::getObject()} anebo pomocí globální funkce
  \inlinecode{getObject()}.

\end{enumerate}

\paragraph{Obecný postup}

Obecným vhodným postupem vstupních kontrol uplatňovaným například
v~\cite{pyTWISTED} či~\cite{pyZOPE} je tento:

\begin{enumerate}
  
\item Ponechat kontrolu vstupních dat na prezentační úrovni.
  
\item Definovat třídu pro každý formulář (tedy nikoli jednu třídu pro všechny
  formuláře, jak je to zamýšleno v \cl{Tutos\_Module}), u které bude:

  \begin{enumerate}
    
  \item Vhodným způsobem definována
    \nientryc{invarianta}{invarianta}{Invarianta je vlastnost objektu, která ho
      udržuje v~dobře definovaném stavu, viz např.~\cite{cppprof}.}.

  \item Jednotným způsobem zajištěno informování o vzniklých problémech.

  \end{enumerate}

\end{enumerate}

Toto oddělení odpovědností kontroly vstupních dat od jejich použití na
aplikační úrovni navíc přináší jednak (1)~vhodný způsob, jak skrze relaci
(session) předávat informace o zadaných hodnotách a zároveň jejich chybách u
bezstavového protokolu HTTP (vše zůstává pohromadě a je přenášeno minimální
množství informace), a~jednak (2)~dále snižuje závislost mezi vrstvami
aplikace, viz též kapitola~\ref{sec:upravyprezentacni}.

Při použití v~jazyku jako PHP vystupují napovrch ještě další výhody:

\begin{itemize}
  
\item Bezproblémová typová konverze (to je velmi nepříjemné při zpracování HTML
  formulářů v~Javě).
  
\item Podpora datových typů jako je asociativní pole na úrovni jazyka.  To
  v~mnoha případech znamená, že není nutno definovat zvláštní třídu --- hodnoty
  z~formulářů HTTP lze velmi snadno a s~veškerým komfortem uchovat právě
  v~asociativním poli.  Zbývá pouze stanoveni invarianty.

\end{itemize}

S~novou verzí PHP (verze 5) přichází podpora výjimek a bylo by škoda jich
nevyužít.  Pokud se komunita vývojářů rozhodne k~využití výjimek, bude stejně
nutno přepsat nějaké části systému a není důvod významněji nezměnit i ošetření
vstupních dat.


\subsubsection{Rozdělení třídy \cl{Tutos\_Base}}
\label{sec:rozdeleni}

Třída \cl{Tutos\_Base} je velmi rozsáhlá.  Nabízí se otázka, zda ji nerozdělit
do více tříd.  její metody lze rozdělit takto (převzato
z~části~\ref{sec:tutosbase}):

\begin{itemize}
\item \emph{Databázové metody.}
\item \emph{XML metody.}
\item \emph{ACL metody.}
\item \emph{Užitečné funkce.}
\end{itemize}

\emph{Databázové metody} tvoří základ třídy.

\emph{XML metody} jsou vhodným kandidátem na vyloučení ze dvou důvodů:

\begin{enumerate}
  
\item Ne všechny odvozené třídy je přetěžují (tj.~používají).  U některých je
  XML export delegován na jiné třídy --- typicky tam, kde je vztah agregace.
  Příkladem může být faktura \cl{Invoice} a položka faktury \cl{Invoice\_Pos}.
  
\item Jde o obecnou vlastnost, která nemusí být pouze doménou tříd odvozených
  od \cl{Tutos\_Base}.

\end{enumerate}

Volání \emph{ACL metod} je z~hlediska designu delegováno na třídu \cl{Acl}.
V~kódu je třída \cl{Acl} implementována pomocí několika bitových masek a ACL
metody operují přímo nad těmito maskami.  Není vhodné vyloučit --- není kam.

U \emph{užitečných funkcí} by bylo potřeba postupovat funkci od funkce
(například na získání textové representace objektu lze též nahlížet jako na
obecnou vlastnost, již lze realizovat rozhraním), avšak přímo se nabízí otázka,
jakou výhodu to přinese?  Odpověď je prostá --- žádnou.

Z~předkládaných faktů je možné doporučit oddělení XML metod.  Tato skutečnost
získá na významu v~kapitole~\ref{sec:upravyprezentacni}.


\subsection{Dopady na systém}
\label{sec:aplikacnidopady}

Odstranění nevhodné dědičnosti ze systému bude znamenat:

\begin{itemize}

\item Jednodušší úpravu kódu tříd, kterých se týká --- rozdělení definic do
  více souborů (z~jednoho definičního souboru získám dva).
  
\item Úpravu ostatních souborů systému, jež tyto třídy používají.
  
  Mělo by se jednat o minimální úpravy, protože díky automatickému zavádění
  modulů pomocí \cl{Modules::loadmodules()}, je zajištěno nahrání i závislých
  modulů (pokud jsou správně definovány při tvorbě modulu).

\end{itemize}

Dále byly diskutovány drobné úpravy ostatních tříd:

\begin{itemize}

\item U třídy \cl{Tutos\_Base} bylo navrženo oddělení XML metod.
  
  Tam, kde si objekty odvozené z~\cl{Tutos\_Base} budou muset ponechat
  schopnost generování XML výstupu, bude možné využít vícenásobného dědění
  (a~pohlížet na něj jakožto na implementaci rozhraní).
  
  To se bude týkat minimální úpravy zdrojových souborů tříd odvozených od
  \cl{Tutos\_Base} (počet těchto tříd: přes~30).

\item Zrušení nepodstatných metod třídy \cl{Tutos\_Module}.
  
  To nebude mít na systém nejmenší dopad.

\end{itemize}

A zároveň byl navržen jeden radikálnější zásah do kódu pro jednotné zpracování
uživatelského vstupu (\ref{sec:zpracovani}).  Ač by se jednalo o větší změnu,
bylo by možné ji provádět postupně (třeba jen u nových modulů), protože se
dotkne jen velmi specifických souborů, které nemají téměř žádné vazby na systém
--- to je možné díky povaze, jakým jsou zpracovávány HTML formuláře ve webových
aplikacích obecně.

Formulář je zpravidla spojen pevně se stránkou, která je odpovědná za jeho
zpracování (atribut \inlinecode{action} elementu \inlinecode{form}).  Tato
stránka většinou negeneruje žádný výstup určený uživateli.  Ať již je kontrola
vstupních údajů úspěšná či nikoli, klient je přesměrován na jinou HTML stránku
s~informacemi o proběhlé operaci, jež zároveň často plní i jinou funkci.  Tento
postup je nutný, aby se zabránilo obnovení těch stránek, které by mohlo
způsobit problémy, například těch, kde je vkládán objekt do databáze.

\begin{itemize}
  
\item Zhruba platí: jedna třída = jeden formulář = jeden obslužný kód.
  
  To znamená změnu přibližně 30 souborů, které mohou být měněny postupně.
  
  Změny informačních stránek není nutné uvažovat --- informování uživatele
  pomocí různých zpráv je již jednotně řešeno v~bázových třídách uživatelského
  rozhraní (viz~\ref{sec:xml}).

\item Zároveň dojde k~jednoznačnému přesunu odpovědnosti do prezentační vrstvy
  (a~tím k~vzájemnému zvýšení nezávislosti vrstev).
  
\end{itemize}

Obecně lze dále doporučit více využívat relaci (session).  Tím dojde ke
zmenšení množství předávaných informací mezi klientem a serverem (budou
uchovávány přímo na serveru) a zároveň bude možné předávané informace lépe
strukturovat (seznamy, asociativní pole, objekty), což je při výměně informací
přes protokol HTTP nemožné.


\subsection{Shrnutí}
\label{sec:aplikacnishrnuti}

Z~úprav aplikační vrstvy je nejpodstatnější oprava špatně použité dědičnosti
(viz~\ref{sec:dedicnost} a~\ref{sec:tutosmodule}), která si vyžádá pouze malé
změny v~kódu.

Ostatní navrhované úpravy nejsou nijak kritické a není nutné je implementovat,
popř.~je možné je implementovat postupně.  Jedná se především o drobné změny
v~bázových třídách a transparentnější ošetření chyb (oddíl~\ref{sec:dalsi}).
