\section{Stávající struktura systému}
\label{sec:navrh}

\secpreview{Tato část nabízí podrobný přehled jednotlivých vrstev uvedených
  výše v~oddílu~\ref{sec:vrstvy}.  Všímá si samotného návrhu a implementace
  jednotlivých vrstev (\ref{sec:prezentacni2}, \ref{sec:aplikacni2},
  \ref{sec:databazova2}) a odkrývá problémy, jež budou předmětem řešení práce
  (\ref{sec:navrhshrnuti}).}

\subsection{Prezentační vrstva}
\label{sec:prezentacni2}

Model na obrázku~\ref{fig:preslayer} přináší podrobný pohled na
\ientryb{prezentační vrstva}{prezentační vrstvu}.

\model{Prezentační vrstva}{preslayer}

Třídy odvozené z~\cl{Theme\_Base} představují konkrétní implementace různých
témat, jež definují grafický vzhled stránek (ikonky, písmo).  Třídy odvozené
z~\cl{Layout\_Base} představují jednotlivé typy rozvržení hlavních oblastí
stránky (nabídka, pracovní plocha).

Model ve skutečnosti bohužel není úplně přesný.  Třída \cl{Classic\_Ba\-se} má
v~reálné implementaci vždy pouze jediného potomka (třídu \cl{Layout}), jež má
tři implementace ve třech různých souborech, avšak díky vlastnostem
skriptovacích jazyků (PHP) nedochází ke kolizi jmen --- je vždy zaveden totiž
jen jeden soubor (podle uložených preferencí uživatele).  To umožňuje
aplikačnímu programátorovi dědit vždy od třídy \cl{Layout}, aniž by se staral o
to, jaký definiční soubor je ve skutečnosti zaveden pro její implementaci.

To není ideální řešení.  Vystoupí do popředí v~okamžiku, kdy se toto chování
navrhne bez použití dynamického zavádění definic tříd (což je vlastnost, jež by
neměla být obecně používána).

Pokud se nechám inspirovat Javou mohl bych dojít například k~modelu na
obrázku~\ref{fig:preslayernew}.

\model{Prezentační vrstva --- inspirace Javou}{preslayernew}

Odlišnost mezi modely je zřejmá, jak je vidět, \nientrya{třída
  \cl{Layout\_Ba\-se}} a její odvozeniny ve skutečnosti kombinují dvě rozdílné
funkčnosti (odpovědnosti) v~jednu, přičemž v~tomto případě je vhodnější, aby
byly oddělené:

\begin{enumerate}
\item Funkčnost \emph{co} má být zobrazeno.
\item Funkčnost \emph{jak} to má být zobrazeno.
\end{enumerate}

Jinými slovy, \cl{Layout\_Base} slouží jako kontejner pro prvky (\emph{co}) a
zároveň rozhoduje o umístění prvků (\emph{jak}).  Pokud však chceme
transparentně rozhodovat o rozmístění prvků, je mnohem lepší oddělit tyto dvě
odpovědnosti od sebe.

Na obrázku~\ref{fig:preslayernew} je vidět kontejner \cl{Page}, který (1) má
vazbu na aplikační objekty a (2) podle potřeby agreguje příslušný \cl{Layout},
jež řídí rozmístění prvků v~kontejneru.  Vzniká tak značně pochopitelnější
model z~těchto důvodů:

\begin{enumerate}
  
\item Je přehledný, logicky správnější a obecnější --- jde o uplatnění design
  patternu \nientrya{model\---view\---controller} (např.~\cite{javaprof},
  \cite{mvc} a \cite{mvcwiki}), blíže viz dále.

\item Je analogií k~modelu, jež používá řada grafických knihoven na různých
  platformách, viz například~\cite{gtk} či \cite{javaprof}, takže vývojáři jsou
  na něj zvyklí.

\end{enumerate}

Ještě zpět k~obrázku~\ref{fig:preslayer}.  Zaujmout možná může i dědičnost
\cl{Layout\_Base} $\rightarrow$ \cl{Classic\_Base}, přičemž ze třídy
\cl{Layout\_Base} již není odvozena žádná jiná třída.  Jedná se o pozůstatek
nejranější implementace \tts{}u, který již nemá žádné opodstatnění.


\subsubsection{XML}
\label{sec:xml}

Dalším problémem prezentační vrstvy je neuspokojivé řešení XML exportů.

Nedávno byla v~\tts{}u implementována možnost XML výstupu a vstupu.  Než
přistoupím k~popisu problému s~XML výstupem, je na místě uvést, jak vůbec
probíhá generování HTML stránky (což byl donedávna jediný způsob presentace dat
pro klientskou aplikaci).

\paragraph{Generování stránky}

Jak vyplývá z~předchozího výkladu, o generování HTML stránky se starají třídy
odvozené z~\cl{Layout}.

Každá HTML stránka kterou klient zobrazí by měla být (ale nemusí) odvozena
z~třídy \cl{Layout}.  Díky tomu má vývojář zajištěny tyto \nientryb{služby
  prezentační vrstvy}{služby poskytované prezentační vrstvou}:

\begin{enumerate}
\item Natažení uživatelem vybraných stylů (a~vůbec zohlednění jeho nastavení
  týkající se vzhledu).
\item Zobrazení hlavní nabídky systému podle uživatelových oprávnění.
\item Zobrazeni vývojářem definovaných formulářů nebo HTML kódu v~oblasti
  pracovní plochy.  Toho je docíleno většinou přetížením několika příbuzných
  metod: \cl{Layout::prepare()}, \cl{Layout::navigate()} a
  \cl{Lay\-out::info()}.
\item Přístup ke kontextové nabídce (a~možnost její změny).
\item Přístup ke kontextové nápovědě (a~možnost její změny).
\item Přístup k~lokalizačním souborům (ať již globálním, či těch zavedených
  vývojářem).
\item Přístup k~mechanismu informování uživatele pomocí zpráv (například o
  výsledku databázové operace).
\end{enumerate}

A tyto \nientryb{služby aplikační vrstvy}{služby poskytované jádrem aplikace}:

\begin{enumerate}
\item Několik aktuálních objektů přístupných v~globálním jmenném prostoru
  (aktuální uživatel, spojení na aktuální databázi).
\item Ověření uživatele.
\item Zavedení užitečných knihoven funkcí.
\end{enumerate}

Pokud stránka není odvozena z~\cl{Layout} (jak naznačuji výše), musí (měl by)
si vše zajistit vývojář sám.  Při dobré znalosti systému k~tomu lze využít
určitých \uv{neveřejných} funkcí, ale rozhodně se nejedná o doporučovaný
postup.

\paragraph{XML}

A nyní zpět k~XML.  Při presentaci dat v~jiné než HTML podobě (XML, CSV, \dots)
nejsou prakticky služby poskytované prezentační vrstvou nutné --- buď by
prezentační vrstva měla tyto služby poskytovat v~modifikované podobě anebo
zcela jinak\footnote{Proč generovat nabídku aplikace pro CSV formát?  K~čemu je
  mi nabídka v~podobě HTML, když posílám PDF výstup?}.

Zároveň však služby poskytované jádrem aplikace jsou užitečné téměř vždy
(autorizace, přístup ke globálním objektům a ke knihovnám).

Řešení celého problému je prosté --- oddělit tyto dvě oblasti služeb
(prezentační a aplikační).

Bohužel, v~současné implementaci to sice je možné, ale rozhodně to není
pohodlné.

Současná praxe je taková, že například při generování XML výstupu se raději
odvodí třída z~\cl{Layout} (a~tím se pro každou XML stránku generuje například
zhola nepotřebná HTML nabídka aj.), než aby vývojář ručně zaváděl potřebné
knihovny.


\subsection{Aplikační vrstva}
\label{sec:aplikacni2}

\ientryb{aplikační vrstva}{Aplikační vrstva} je podrobněji zachycena na
obrázcích~\ref{fig:businesslayer}, \ref{fig:modulesbrief} a
\ref{fig:modulesbrief2}.

\subsubsection{Dědičnost}
\label{sec:dedicnost}

Obrázek~\ref{fig:businesslayer} je značně zjednodušený model, kde chybí (až na
výjimky) asociace mezi třídami, kromě vazeb dědičnosti (což nahrazuji právě na
modelech vyobrazených na obrázcích~\ref{fig:modulesbrief} a
\ref{fig:modulesbrief2}).  Proč je zde vůbec model uveden v~takovéto podobě?
Slouží zde jako ilustrace toho, že:

\begin{enumerate}
\item \tts{} má skutečně mnoho aplikačních tříd.
\item Snaha zachytit je všechny na jednom modelu spolu se všemi jejich vazbami
  je nesmyslné.
\item Je z~něho patrná jedna chyba v~návrhu (právě ve vazbách dědičnosti),
  která by při jiném zobrazení nebyla tak zřejmá (viz níže).
\end{enumerate}

\model{Dědičnost}{businesslayer}

Jak si můžete na modelu s~dědičností povšimnout
(obrázek~\ref{fig:businesslayer}), množství tříd je odvozeno ze \ientryb{třída
  \cl{Tutos\_Mo\-du\-le}}{třídy \cl{Tutos\_Module}} a ta sama je odvozena ze
\ientryb{třída \cl{Tutos\_Base}}{třídy \cl{Tutos\_Base}}.

Pokud odpovědností \cl{Tutos\_Module} je definovat chování obecného rozšíření
\tts{}u, jaký smysl pro něj může mít zajišťování služeb perzistence, které
poskytuje třída \cl{Tutos\_Base}?  K~čemu ho ukládat do databáze?

Jde o chybu v~návrhu --- došlo ke sloučení dvou funkčností do jedné třídy
z~důvodu lenosti aplikačních programátorů, ač původní zamýšlené použití bylo
jiné:

Každé rozšíření \tts{}u by mělo být implementováno skrze
\cl{Tutos\_Mo\-du\-le}.  Díky tomu může jádro systému (representováno v~tomto
případě třídou \cl{Modules}) snadno určit základní vazby na systém, položky
nabídky, nápovědu, lokalizační soubory apod.  Není naprosto žádný důvod ukládat
tyto informace do databáze --- tyto informace jsou příliš proměnlivé a pro
každý modul jedinečné --- proto jsou buď definovány jako interní datové
struktury či uloženy v~externích datových souborech.

Stejně tak i každá perzistentní třída by měla dědit od společné třídy
\cl{Tutos\_Base}, díky čemuž získá databázové operace a přímý přístup
k~databázovým třídám, jež usnadní její práci s~databázi.

To, že došlo ke sjednocení těchto odlišných funkcionalit do jedné třídy, bylo
dáno řadou jednoduchých rozšíření (například \emph{správa poznámek}),
povětšinou operujících nad jednou databázovou tabulkou, do které se ukládají
datové atributy a jednou vazební databázovou tabulkou, v~níž se uchovávají
vazby na ostatní objekty systému\footnote{Systém generování a správa klíčů je
  v~\tts{}u dost ojedinělý a umožňuje jednou vazební tabulkou propojit několik
  typů objektů. Viz~\ref{sec:databazova2}.}

Při tvorbě nového rozšíření bylo nutné:

\begin{enumerate}
\item Implementovat vlastní třídy, které by prováděli požadované operace
  (odvozené od \cl{Tutos\_Base}).
\item Definovat jednu třídu rozšíření (odvozenou) od \cl{Tutos\_Module} a v~ní
  popsat závislosti na systému.
\end{enumerate}

Pro nově vznikající rozšíření to byla, podle mnohých, zbytečná práce: Proč
definovat dvě jednoduché třídy (a~vytvářet dva soubory) když by bylo možné
zkrátit a zpohodlnit dobu implementace dědičností?

Podle~\cite{cppprof} jde o ukázkové špatné použití dědičnosti.  Nevhodnost
tohoto postupu je například patrná i z~rozšíření \cl{Invoice} či \cl{Bug},
které pak definují ještě další třídy odvozené pouze z~\cl{Tutos\_Base}.


\subsubsection{Asociace}
\label{sec:asociace}

\modelrot{Asociace}{modulesbrief}

\model{Asociace --- \cl{Projects} $\leftrightarrow$ \cl{Contacts}}
{modulesbrief2}

\nientryb{objektový model asociaci}{Model s~asociacemi} je zachycen na dvou
obrázcích --- \ref{fig:modulesbrief} a \ref{fig:modulesbrief2}.
Obrázek~\ref{fig:modulesbrief2} doplňuje obrázek~\ref{fig:modulesbrief} o vazby
mezi podsystémy \cl{Projects} $\leftrightarrow$ \cl{Contacts}.

Na obrázeku~\ref{fig:modulesbrief} jsou vidět hlavní uskupení tříd a jejich
vztahy.  Oproti obrázku~\ref{fig:businesslayer} jsem si dovolil zanedbat
některé třídy a rozčlenil jsem třídy z~jádra \tts{}u do
podsystémů\footnote{Podotýkám, že \emph{pravým} podsystémem (modulem) nemusí
  být vždy nutně to, co je odvozeno od třídy \cl{Tutos\_Module} a naopak.}.

Aby model byl přehledný, nezachytil jsem do něj tyto vztahy, jež je snadné si
domyslet (platí i pro obrázek~\ref{fig:modulesbrief2}):

\begin{enumerate}
  
\item \emph{Tvůrce} --- každá perzistentní třída je asociována s~třídou
  \cl{User}.  Instance této asociace (link) mezi perzistentním objektem a
  objektem třídy \cl{User} udává tvůrce objektu (tento link je neměnný).
  
\item \emph{Vlastník} --- každá perzistentní třída je asociována s~třídou
  \cl{User}.  Link mezi perzistentním objektem a objektem třídy \cl{User} udává
  aktuálního vlastníka objektu (tento link lze měnit), tj. lze předat
  vlastnictví a s~ním související práva nad objektem.
  
\item Každá perzistentní třída je potomkem třídy
  \cl{Tutos\_Base}\footnote{Některé navíc, poněkud nešťastně, i potomkem
    \cl{Tutos\_Module} viz výše.}.

\end{enumerate}

Implementace asociací \emph{tvůrce} a \emph{vlastník} je úzce spjata
s~generováním identifikátorů pro objekty --- blíže viz~\ref{sec:databazova2}
--- na tomto místě pouze poznamenám, že každý objekt je vybaven jedinečným
identifikátorem v~rámci celého systému, takže teoreticky lze skutečně propojit
linkem libovolný objekt s~libovolným jiným objektem.  V~praxi však samozřejmě
existují vazby, jež systém nepodporuje, tj. neumožňuje je zadat a zobrazit
prostřednictvím uživatelského rozhraní a nelze je uložit do databáze.

Z~tohoto tvrzení též nepřímo vyplývá jeden fakt.  Vazby mezi třídami, jež jsou
zachyceny na obrázku~\ref{fig:modulesbrief}, jsou pouze ty \uv{doporučené}, tak
jak bylo původně zamýšleno, aby systém pracoval.  Během vývoje \tts{}u došlo
k~různým rozšířením, které sice vzájemné reference v~systému značně komplikují,
ale uživatelům poskytují velký komfort a jsou známkou jisté jedinečnosti
systému.  Mezi vazby, jež na obrázku~\ref{fig:modulesbrief} zachyceny nejsou,
patří například asociace, umožňující:

\begin{enumerate}
\item Propojit \cl{Tutos\_File} přímo ke třídě \cl{User}.
\item Sledovat \cl{Timetrack} (odpracované hodiny) pro \cl{Team}
  (obrázek~\ref{fig:modulesbrief2}).
\item Přidat \cl{Task} (úlohu) přímo k~uživateli
\end{enumerate}

Pokusit se zobrazit vše najednou by jistě nikam nevedlo, navíc, pro samotné
úvahy, jak je systém navržen to není podstatné, stačí si uvědomit, že toto
vzájemné odkazování je možné a vědět, jak ho implementovat, což je mimo jiné
probíráno v~oddílu~\ref{sec:databazova2}.

\paragraph{Podsystémy}

Na obrázku~\ref{fig:modulesbrief} jsou zachyceny 3 hlavní podsystémy:

\begin{enumerate}
\item \cl{Projects}.  Tento podsystém obsahuje vše, co souvisí s~projekty a
  jejich řízením.
   
  Projekt (\cl{Product}) může být hierarchicky rozčleněn do úkolů (\cl{Task}),
  které mohou být ještě dále děleny na podúkoly.  Mezi projekty mohou být vazby
  časové následnosti.
  
  Zavedením projektu u zákazníka vzniká instalace (\cl{Installation}).  Ta může
  (stejně jako projekt) obsahovat chyby (\cl{Bug}).  K~projektům, úkolům či
  instalacím se mohou vázat doprovodné soubory (\cl{Tutos\_File}).

\item \cl{Contacts}.  Tento podsystém spravuje kontakty (fyzické
  (\cl{Tutos\_Add\-ress}) i právnické (\cl{Company}) osoby).
  
  Právnické osoby mohou být rozděleny na jednotlivá oddělení
  (\cl{De\-part\-ment}).
  
  Všechny kontakty mají nějakou adresu (sídlo, místo bydliště =
  \cl{Lo\-ca\-tion}).
  
  Fyzické osoby často pracují v~nějaké společnosti (či jejím oddělení).
  Společnosti mohou být kategorizovány do skupin (\cl{Group}).

\item \cl{Calendar}.  Součástí jádra systému je i plánování času.  Schůzky
  mohou být napojeny na projekt a mohou zainteresovat nějaký kontakt.
  
  Speciálním případem schůzky je opakovaná (pravidelná) schůzka
  (\cl{Re\-cur\-rent\_Appoint\-ment}).

\end{enumerate}

\paragraph{Vazby \cl{Projects} $\leftrightarrow$ \cl{Contacts}}

Modul \cl{Projects} je velmi úzce napojen na modul \cl{Contacts}.  Vzniká mezi
nimi mnoho vazeb, jež vesměs vyjadřují, kdo má za co odpovědnost, viz
obrázek~\ref{fig:modulesbrief2}.

Typicky je kardinalita vazeb \inlinecode{m:n}.  Pokud se odpovědnost týká
uživatele systému (typicky pracovníka firmy), jsou s~vazbou spojeny i
odpracované hodiny (\cl{Timetrack}).


\subsection{Databázová vrstva}
\label{sec:databazova2}

Jak je vidět z~obrázku~\ref{fig:dblayer} a z~návrhu \inlinecode{java.sql.*}
(např.~\cite{javaprof}), tři třídy \ientryb{databázová vrstva}{databázové
  vrstvy} \tts{}u skutečně kombinují několik funkčností, jež jsou v~Javě
implementovány v~řadě tříd a rozhraní.

\modelrot{Databázová vrstva}{dblayer}

Následující tabulka (převzata z~části~\ref{sec:databazova}) to elegantně
shrnuje:

\begin{center}
  \begin{tabular}{l@{ : }l}
    Tutos\_DB & Driver, Connection, DatabaseMetaData, Statement \\
    Query & Statement, PreparedStatement \\
    Result & ResultSet, ResultSetMetaData
  \end{tabular}
\end{center}

Toto databázové rozhraní provází \tts{} již od jeho prvních verzí.  Když si
uvědomíme, kdy \tts{} vznikal (oddíl~\ref{sec:historie}), je to na tehdejší
dobu a PHP skutečně dobrá databázová abstrakce.

Databázová vrstva navíc poskytuje 2 ne zcela typické funkce:

\begin{enumerate}
  
\item \cl{Tutos\_DB::nextID()}, jež poskytuje nové volné ID, které může být
  použito pro nově vkládaný objekt.

\item \cl{Result::getObject()} --- tato funkce vybere z~databáze objekt na
  základě jeho jedinečného ID.

\end{enumerate}

Nezávislost na databázi je zajištěna dědičností.  Pro každou podporovanou
databázi (viz~\ref{sec:databazova}) je z~abstraktní třídy databázové vrstvy
(\cl{Tutos\_DB} a \cl{Result}) odvozena nová třída, jež příslušným způsobem
implementuje příslušné metody.

Třída \cl{Query} již není používána.  Sloužila ke konstrukci DDL (zřídka i DML)
SQL dotazů, které byly konstruovány i na základě metadat, jež si samotný systém
udržuje o databázi (názvy tabulek, typy sloupců apod.).  Nyní má význam pouze
během instalace \tts{}u, kdy tyto informace nemohou být zjištěny z~databáze, či
dodány vývojářem v~kódu.

Přestože je databázová vrstva navržena pro potřeby \tts{}u dobře, lze mít pár
výhrad:

\begin{enumerate}
  
\item Z osobní zkušenosti vychází největší výtka --- ve většině databázových
  abstrakcích se rozlišují (při běžné práci) tyto třídy (pro jejich označení
  použiji označení z~Javy):

  \begin{itemize}

  \item \cl{java.sql.Driver} --- přebírá parametry pro spojení a je schopna
    vytvořit spojení na databázi.

  \item \cl{java.sql.Connection} --- spojení na databázi.  Representuje
    databázi jako takovou, umožňuje nastavení řízení transakcí a skrze další
    třídy poskytuje pohodlný přístup k~datům v~ní uložených.

  \item \cl{java.sql.Statement} --- představuje SQL dotaz položený databázi.

  \item \cl{java.sql.ResultSet} --- představuje výsledek SQL dotazu.

  \end{itemize}
  
  Jak je vidět, v~\tts{}u sice jsou k~dispozici všechny tyto možnosti, ale
  nemusí být k~nalezení ve třídách, kde je na ně vývojář zvyklý.
  
\item S novými verzemi databází přicházejí nové vlastnosti těchto databází
  (zejména MySQL v~nových verzích).  Pokud chceme tyto nové vlastnosti využít,
  je nutno tyto vlastnosti implementovat (tj. je na vývojářích \tts{}u, aby
  zajistili dostupnost nové funkce) a to zabírá čas, jež může být využit lépe.

\end{enumerate}

Oba tyto nedostatky mohou být vyřešeny velmi prostě --- nahradit databázovou
vrstvu nějakou běžně užívanou komponentní knihovnou, jako
například~\cite{phpADODB} či~\cite{phpPEARDB}.


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

Po podrobnějším představení jednotlivých vrstev aplikace se již vynořily nějaké
nedostatky v~návrhu a implementaci.

Z~celkového pohledu nemám zásadnější výtky.  \tts{} je aplikace typu transakční
manažer a jako celek je implementován podle doporučených postupů.  Nicméně:

\begin{enumerate}
  
\item V prezentační vrstvě se objevuje problém ve špatném návrhu (dědičnost
  místo agregace), viz oddíl~\ref{sec:prezentacni2} a
  obrázek~\ref{fig:preslayernew}, a~špatně řešený výstup do jiných formátů
  (generování výstupní stránky není ideální), blíže viz~\ref{sec:xml}.
  
\item V aplikační vrstvě je nevhodně použitá dědičnost, z~důvodu lenosti
  vývojářů, viz oddíl~\ref{sec:dedicnost}.  Jinak není k~řešení samotné
  aplikační logiky žádných výtek.
  
\item V databázové vrstvě nejsou žádné větší nedostatky, avšak použití jiné
  (standardní) knihovny namísto vlastně udržovaného kódu by mohlo zlepšit a
  zprůhlednit vlastnosti databázové vrstvy.

\end{enumerate}
