Mendelova zemědělská a lesnická univerzita v Brně Provozně ekonomická fakulta
Analýza a návrh systému pro řízení dopravní společnosti Diplomová práce
Vedoucí práce: doc. Ing. Ivana Rábová, Ph.D.
Bc. Jan Beránek
Brno, 2008
2
Chtěl bych na tomto místě poděkovat paní doc. Ing. Ivaně Rábové, Ph.D. za pomoc a odborné vedení při zpracování této práce. Dále děkuji za podporu všem svým kolegům z firmy Unis Computers, spol. s r. o., z Oddělení vývoje a implementace. Bez jejich pomoci by nemohla tato práce vzniknout.
4
Prohlašuji, že jsem tuto bakalářskou práci zpracoval samostatně s použitím literatury, kterou uvádím v seznamu.
V Brně dne 19. května 2008
....................................................
6
7
Abstract Beránek, J. Analysis and Design of Public Transport Company Management System. Diploma thesis. Brno, 2008 This text describes the development of the module for public transport timetables management and modifications, which is the part of the complex business information system Prytanis. Firstly, there are mentioned methods and possibilities of developing such systems, starting with a system analysis, then a system design and implementation. In the next part there follows the description of the designed and developed module Timetables, and especially all fundamental steps in its development cycle, whereas the module, as well as the whole system, is both designed and programmed by an object-oriented approach, using the modelling language UML.
Abstrakt Beránek, J. Analýza a návrh systému pro řízení dopravní společnosti. Diplomová práce. Brno, 2008 Práce popisuje vývoj modulu správy a editace jízdních řádů komplexního podnikového informačního systému Prytanis. Nejprve jsou obecně uvedeny metody a možnosti vývoje takového systému, a to od analýzy přes návrh až po implementaci. Poté následuje popis navrženého a sestaveného modulu Jízdní řády, a zejména všech zásadních kroků v jeho vývojovém cyklu, přičemž modul, stejně jako celý systém, je navržen i naprogramován objektově orientovaným přístupem, za využití modelovacího jazyka UML.
8
9
OBSAH
Obsah 1 Úvod do problematiky
11
2 Cíl práce
13
3 Literární přehled
15
4 Současný stav problematiky 17 4.1 Informační systém Prytanis . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 4.2 Další možnosti vedení jízdních řádů . . . . . . . . . . . . . . . . . . . . . . . 20 4.3 Možnosti počítačové optimalizace hromadné linkové dopravy . . . . . . . . 21 5 Ekonomické zhodnocení 23 5.1 Informační systém dopravního podniku . . . . . . . . . . . . . . . . . . . . . 23 5.2 Ekonomické dopady komputerizace procesů . . . . . . . . . . . . . . . . . . 23 6 Teoretická studie 6.1 Životní cyklus softwaru . 6.2 Úvodní studie . . . . . . . 6.3 Analýza . . . . . . . . . . 6.4 Návrh . . . . . . . . . . . 6.5 Implementace a testování 6.6 Kritika modelování . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
7 Metodika práce
. . . . . .
. . . . . .
. . . . . .
. . . . . .
27 27 28 31 39 57 60 63
8 Tvorba modulu Jízdní řády 65 8.1 Úvodní studie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 8.2 Analýza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 8.3 Návrh a implementace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 9 Diskuze
79
10 Závěr
81
11 Literatura
83
Přílohy
87
A Původní informační systém Prytanis
89
B Model business procesů v subsystému správy jízdních řádů linek
93
C Analytické modely a dokumenty
95
D Návrh a implementace aplikace
109
E Rozsáhlé diagramy na volně vložených listech
129
10
OBSAH
1
1
ÚVOD DO PROBLEMATIKY
11
Úvod do problematiky
Již od počátku vývoje lidské společnosti začala být zřejmá potřeba cestování a dopravy. Veřejnou dopravu je možné v historii vystopovat nejdříve jako dopravu po vodě, ve formě přívozů. Tento motiv lze sledovat již v řecké mytologii, když zemřelí byli ve starém Řecku pohřbíváni s drobnou mincí pod jazykem, aby mohli na cestě do říše mrtvých zaplatit převozníku Cháronovi. Veřejná hromadná doprava se objevuje až později. Pomineme-li lodě, tak jako prostředky hromadné dopravy lze prvně označit dostavníky, které jezdily po pevných trasách z města do města, od hostince k hostinci. Rozkvět hromadné dopravy osob, tak jak ji známe dnes, pak začíná s železniční dopravou. První železnice pro osobní dopravu, tažená koňmi, byla zavedena ve Velké Británii v roce 1803 mezi městy Wandsworth a Croydon, a se zavedením parního pohonu pak začíná období rozvoje hromadné dopravy v pravém slova smyslu. Zvyšování počtu možných dopravních prostředků, počtu linek a četnosti jejich spojů klade také větší nároky na cestujícího těmito dopravními prostředky. V dobách dostavníků, kdy každým městem projížděla zpravidla jen jedna „linkaÿ, stačilo vědět, který den v týdnu do města přibližně přijíždí a kam pokračuje dále, a obdobné to bylo ještě i v době prvních železnic. V současné době je toto naprosto nedostačující. Kvůli potřebě zaznamenat průběh linek, jejich jednotlivých spojů a časů jejich odjezdů z jednotlivých zastávek začaly být již kolem poloviny 19. století vydávány jízdní řády. S průběhem času a měnícími se technickými podmínkami a postupy se měnil i způsob jejich zpracování, od nahodile psaného seznamu spojů a odjezdů po dnešních několik v podstatě standardizovaných formátů. V mnoha civilizovaných zemích je navíc formát jízdních řádů legislativně upraven, a stejně tak je tomu i v České republice (388/2000 Sb.). Převrat do oboru plánování přepravy a jízdních řádů, ostatně stejně tak jako do téměř všech ostatních oborů lidské činnosti, přinesl masový rozvoj informační a komunikační techniky. Komputerizace celého procesu správy jízdních řádů linek, která ve svém důsledku umožňuje zoptimalizovat a tím i zlevnit podnikové procesy uvnitř firem, je dnes snahou ve všech dopravních podnicích. Proto i já jsem si jako téma diplomové práce vybral počítačové zpracování jízdních řádů.
12
1
ÚVOD DO PROBLEMATIKY
2
2
CÍL PRÁCE
13
Cíl práce
Využití počítačů při hromadném uchování a zpracování dat může mít zásadní význam při optimalizaci a zefektivnění podnikových procesů, což je v současné době jeden pilířů rozvoje podniku. Největšího významu v této snaze dosahují podnikové informační systémy. Informační systém je souhrn metod, lidí a technických prostředků zabezpečujících informační procesy. Každý z těchto faktorů je podstatný; zanedbáním kteréhokoliv z nich klesá užitná funkce celého systému. Programové vybavení je jednou z těchto složek, a jak již bylo uvedeno, pouze za použití co možná nejlepšího softwaru může firma dosáhnout nejlepších výsledků. Podnik ho může získat různými způsoby, mezi něž patří vývoj vlastními silami, nákup softwaru vyrobeného na zakázku nebo nákup a uzpůsobení typového softwaru. Uvádí se, že pro menší a střední podniky bývá zpravidla nejvhodnější nákup typového softwaru, protože ostatní alternativy příliš zatěžují rozpočet podniku. Proto je poptávka po těchto systémech značná. V posledních dvaceti letech vzniklo množství firem zabývajících se vývojem typových informačních systémů, které vyvíjejí jednotlivé softwarové produkty zaměřené na podporu různých oborů podnikání svých zákazníků. Jednou z takových firem je i Unis Computers, spol. s r. o. Jde o firmu, která již od roku 1991 vyvíjí komplexní podnikový informační systém Prytanis pro podniky se zaměřením na dopravu a spedici. Zahrnuje větší množství modulů, které pokrývají většinu činností a aktivit těchto podniků, od ekonomických aplikací (banka, pokladna, pohledávky, fakturace), přes základní společné části (zakázky, personalistika, docházka) až po moduly a aplikace zaměřené ryze na dopravu (evidence a údržba vozidel, spedice, záznamy o provozu vozidel nákladní dopravy). Někteří ze zákazníků kromě toho také provozují veřejnou osobní dopravu, a to jak pravidelnou, tak i nepravidelnou (zájezdy). Pravidelná linková osobní doprava v současné situaci není informačním systémem Prytanis dostatečně pokryta, což vede tyto zákazníky k tomu, že využívají dílčích řešení konkurenčních aplikací ryze pro správu jízdních řádů linek. Tato situace je zřejmě neuspokojivá, a to nejen pro firmu Unis Computers, spol. s r. o., ale i pro její zákazníky, protože používají dva softwarové produkty od různých výrobců, a možnost integrace obou systémů je značně obtížná. Z toho důvodu jsem byl v rámci své pracovní činnosti ve firmě Unis Computers, spol. s r. o. pověřen vývojem tohoto modulu Jízdní řády. Cílem diplomové práce je tedy navrhnout a naprogramovat aplikaci pro správu a zadávání jízdních řádů linek jako součást podnikového informačního systému Prytanis.
14
2
CÍL PRÁCE
3
3
LITERÁRNÍ PŘEHLED
15
Literární přehled
Při každé činnosti odborného rázu je třeba před samotnou prací nejprve získat všechny potřebné poznatky. Nejvhodnějším způsobem se pak jeví studium již publikované literatury. Při vývoji počítačových aplikací komputerizujících určitou oblast lidského konání se využijí poznatky ze dvou oblastí: z problémové domény, pro kterou je aplikace určena, a z oblasti týkající se vývoje aplikací obecně. Proto i já rozděluji literární prameny do dvou skupin: na publikace zabývající se hromadnou dopravou, jízdními řády a jejich zpracováním a na zdroje týkající se analýzy, návrhu a implementace aplikací. Dnešní podoba jízdních řádů je do značné podoby standardizovaná a každý zadávaný údaj má svůj význam. Pokud aplikace nebude respektovat to, jak jsou jízdní řády linek tvořeny a používány, nebude pro zákazníky použitelná a nemá proto naději na úspěch. Kvůli získání těchto znalostí z problémové domény je důležité studium pramenů z první skupiny (týkajících se linek a jízdních řádů). V České republice je jediná fakulta zabývající se dopravou. Je to Dopravní fakulta Jana Pernera, patřící pod Univerzitu Pardubice. Tato fakulta pak pro své studenty vydává skripta a publikace. Jako stěžejní dílo, obsahující základní pojmy a definice z této oblasti, je skriptum Osobní doprava (Vonka a kol., 2001). Jiné veřejně dostupné knižní zdroje o linkách, spojích a jízdních řádech silniční dopravy prakticky neexistují. Naštěstí existují i online zdroje. Avšak o této problematice se ani na Internetu nevyskytuje mnoho informací, jediným uceleným materiálem je článek v české Wikipedii. Většinu informací z této oblasti jsem proto čerpal konzultacemi se zákazníky a lidmi, kteří v dopravě pracují. Zásadním zdrojem pro zpracování jízdních řádů je také Vyhláška Ministerstva dopravy a spojů, o jízdních řádech veřejné linkové osobní dopravy (388/2000 Sb.), která legislativně upravuje podobu jízdních řádů. Obsahuje taxativní výčet údajů, které musí být na jednotlivých typech jízdních řádů uvedené. Druhou skupinu zdrojů tedy tvoří materiály pokrývající celý průběh vývoje aplikací. V první řadě je potřeba zmínit publikaci Podnikové procesy (Řepa, 2007) týkající se analýzy a modelování podnikových procesů obecně. Mezi potřebné zdroje patří také publikace zabývající se modelováním v jazyce UML. V dnešní době je jich již na trhu i v češtině větší množství, lze uvést např. knihu Myslíme v jazyku UML (Schmuller, 2000) nebo UML a unifikovaný proces vývoje aplikací (Arlow a Neustadt, 2007), další desítky podobných knih existují v angličtině. Vynikajícím zdrojem je publikace Objektové modelování a UML v praxi 2000 (Kraval, 2001), která obsahuje spoustu autorových zkušeností a doporučení pro vývoj aplikací. Co se UML týče, poměrně dobře jsou jeho diagramy a jejich užití popsány i v uživatelské příručce k modelovacímu nástroji Enterprise Architect (Sparx Systems, 2008). Stejně tak je i velice důležité při tvorbě systému dobře znát programovací jazyk, v kterém je systém vyvíjen. Vzhledem k tomu, že je celý systém Prytanis tvořen v programovacím jazyce C# pro platformu Microsoft .NET, výborně poslouží publikace zabývající se jazykem C#, jako třeba C# 2005. Velká kniha řešení (Bayer, 2007) nebo C# 2005. Programujeme profesionálně (Nagel, 2007). Z online zdrojů lze jako velice dobrý zhodnotit seriál o programování v jazyce C# na serveru Živě.cz (Puš, 2008). Neocenitelným pomocníkem při praktickém programování je pak samozřejmě dokumentace k programovacímu jazyku, zde konkrétně k jazyku C# a platformě Microsoft .NET (Microsoft Corporation, 2008).
16
3
LITERÁRNÍ PŘEHLED
Při výčtu zdrojů nelze samozřejmě zapomenout na manuál k databázovému systému Ingres, který je používaný pro uchovávání dat (Ingres Corporation, 2006). S návrhem aplikace souvisí použití návrhových vzorů, což jsou obecná znovupoužitelná řešení běžných problémů a situací. Stěžejním dílem v této oblasti je kniha Design Patterns (Gamma a kol., 1995). Zajímavé myšlenky a nápady lze nalézt také v knize Implementation Patterns (Beck, 2008). Také na Internetu je k nalezení mnoho článků a dalších zdrojů týkajících se návrhových vzorů a dalších moderních vývojových trendů, zajímavé články jsou uvedené např. na blogu René Steina (Stein, 2008). Pro vývojáře softwaru ale nemusí být zajímavé a užitečné pouze příručky ke konkrétnímu programovacímu jazyku či modelovacímu nástroji. Mám na mysli další publikace sloužící spíše k sebevzdělávání programátora, obsahující doporučení a postřehy vedoucí k lepšímu kódu a produktivitě vůbec. Do této kategorie spadají velice zajímavé knihy Co programátory ve škole neučí (Paleta, 2003) nebo Programátor pragmatik (Hunt a Thomas, 2007). V této práci je zmíněno větší množství dalších témat, na jejichž podrobné popsání zde bohužel nezbývá prostor. V textu zabývajícím se každým z těchto témat jsou proto uvedeny odkazy na odbornou literaturu (většinou články ve sbornících a odborných časopisech), kde se lze dočíst více. V neposlední řadě je pak třeba zmínit i knihu LATEX pro začátečníky (Rybička, 2003), která mi velice pomohla s formální a typografickou úpravou práce.
4
SOUČASNÝ STAV PROBLEMATIKY
4
17
Současný stav problematiky
V této části práce se pokusím shrnout současný stav problematiky, tak aby na jeho základě bylo možné navrhnout aplikaci co nejlépe splňující požadavky na ni kladené.
4.1
Informační systém Prytanis
Firma Unis Computers, spol. s r. o. už od roku 1991 vyvíjí informační systém Prytanis jako informační systém pro středně velké podniky se zaměřením na dopravu a spedici, zajišťující jejich kompletní provoz z hlediska provozního, ekonomického i řídícího. V té době začal vznikat informační systém běžící na textovém režimu na unixových serverech, založený na relačním DBMS Ingres, psaný v programovacím jazyce Ingres 4GL. Vývoj v programovacím jazyce Ingres 4GL Pro lepší představu krátce shrnu prostředky, kterými byl původní systém Prytanis vytvářen. Programovací jazyk Ingres 4GL byl vyvinut koncem osmdesátých let, se svým vývojovým prostředím Vision, někdy známým také jako Ingres ABF (Application by Forms), umožňuje tvorbu aplikací využívajících relační databázi s uživatelským rozhraním na textovém režimu. (Na ukázku je na obrázku 12 na stránce 89 hlavní editační okno pro zadání jízdního řádu linky, a na obrázku 13 je formulář pro opravu zastávky.) Vývojové prostředí obsahuje i vizuální editor pro navržení designu obrazovek (tj. umístění ovládacích prvků). Výkonný kód je psán v jazyce Ingres 4GL a představuje reakce na události – při události inicializace formuláře je naplněn daty, lze zadávat reakce na opuštění polí, stisk různých kláves apod. Kód obsluhující formulář je tedy vlastně rozdělen do bloků obsluhující jednotlivé události, jde tedy o ryze událostní programování. Programovací jazyk Ingres 4GL samotný je typický 4GL jazyk podporující strukturovaný přístup k programování. Velice dobře spolupracuje s databází, databázové příkazy se píší přímo do zdrojového kódu. Používá datové typy databázového systému Ingres (např. VARCHAR, INTEGER). Lze vytvářet datový typ záznam podle řádku tabulky, podobně jako např. v Oracle PL/SQL, pracovat s kurzory, poli proměnných apod. Ukázka kódu formuláře je v příloze A (jde o kód formuláře pro zadání dat o převážených pohonných hmotách z modulu Spedice). Zajímavá je ale samotná práce vývojového prostředí. Vývojové prostředí totiž neukládá sestavy, formuláře a celkově vše, co programátor při vytváření aplikace zadává, do souborů jako ostatní vývojové prostředí běžných programovacích jazyků1 , ale přímo do 1 V běžných vývojových prostředích, kde existuje vizuální nástroj (tzv. designer ) na vytvoření uživatelského rozhraní (Visual Studio, NetBeans, . . . ), práce probíhá tak, že programátor na formulář rozmístí ovládací prvky (textové pole, rozbalovací seznamy, tlačítka apod.), a designer podle toho na pozadí tvoří kód, kde jsou deklarace, vytvoření instancí těchto jednotlivých ovládacích prvků, nastavení jejich vlastností apod. Tento vygenerovaný kód se automaticky umístí do metody Init() formuláře, která se např. volá z jeho konstruktoru, nebo na podobné umístění, takže při spuštění tohoto formuláře jsou tyto ovládací prvky vytvořeny a nastaveny. Programátor tedy sice tvoří uživatelské rozhraní ve vizuálním nástroji, ale výstupem této práce je běžný zdrojový kód umístěný v souborech, který se nijak neliší od toho, který píše programátor ručně. Naopak, při dostatečných znalostech ovládacích prvků v programovacím jazyce lze vytvořit uživatelské rozhraní zcela v kódu, tj. napsat ručně kód, který jinak generuje designer, a v mnoha případech je dokonce tento výsledný kód lepší (i když jeho vytvoření samozřejmě trvá podstatně déle).
18
4
SOUČASNÝ STAV PROBLEMATIKY
databáze, do připravených struktur. Až při sestavení produkční verze jsou z těchto databázových tabulek data o formulářích, i všechen kód, získán a sestaven do spustitelného binárního kódu. Zhodnocení funkční stránky původního systému Prytanis Informační systém Prytanis dosáhl v průběhu let značné obliby u zákazníků. Vlivem jejich požadavků a námětů se za přibližně 15 let rozrostl tak, že dosahoval značné velikosti a komplikovanosti. Obsahuje desítky modulů a aplikací, které pokrývají všechny provozní, ekonomické a řídící procesy podniku. Systém je zřetelně zaměřený na podniky zabývající se dopravou a spedicí. Kvůli požadavkům zákazníků, kteří provozují i osobní linkovou dopravu, vznikla v původním systému Prytanis i aplikace Jízdní řády. Zatímco funkčně byl celý systém velmi kvaltní a propracovaný (firma Unis Computers, spol. s r. o. na něj získala i osvědčení kvality podle ISO 9001), jeho architektura, a zejména uživatelské rozhraní (pouze na textovém režimu) začalo být postupně jeho problémem. Zatímco v některých případech bylo možné architekturu systému vnímat jako výhodu2 , obecně začal původní systém ztrácet právě kvůli uživatelskému rozhraní. Jedním z modulů, který byl tímto nejvíce postižen, byly právě Jízdní řády, zejména když v posledních letech vznikly desktopové aplikace s grafickým uživatelským rozhraním, které umožňovaly jízdní řády zadávat. S přechodem konkurenčních aplikací na grafické uživatelské rozhraní většina zákazníků firmy Unis Computers, spol. s r. o., používající informační systém Prytanis, přestala modul Jízdní řády systému využívat a přešla na používání těchto konkurenčních aplikací (bude o nich pojednáno dále), a je třeba uznat, že práce s těmito aplikacemi je podstatně příjemnější než s původním systémem Prytanis. K dnešnímu dni už by se dali tedy zákazníci používající k vedení jízdních řádů linek modul informačního systému Prytanis spočítat na prstech jedné ruky. Ohledně funkční stránky ale nebyly nikdy na tento modul závažnější stížnosti. Je koncipován jako nástroj pro správu a editaci jízdních řádů linek, základní funkci tedy tvoří zadávání linek (tj. založení/oprava linky, přidání/oprava zastávek, spojů, a časů odjezdů spojů z jednotlivých zastávek). K linkám se evidují licence. Linka může být v systému ve více nezávislých variantách (protože s průběhem času se linky mění, a to nejen časy odjezdů spojů, ale i trasa linky). Se splatněním (označením varianty za platnou) se vytvoří v modulu Turnusy turnusové příkazy. Na modul jízdní řády dále navazují moduly Rentabilita osobní dopravy a ZPVOD (Záznamy o provozu vozidel osobní dopravy). Modul Jízdní řády je tedy do značné míry integrován v celém podnikovém systému.3 Při svém návrhu jsem do jisté míry vzal jako základ právě tento původní systém. 2
Původní systém Prytanis běžel na unixovém serveru. Uživatelé se k němu připojovali přes terminál, používajíce protokol ssh. To má oproti klasickým „windowsovýmÿ formulářovým systémům zřejmou výhodu, že není potřeba nic instalovat. Pro administrátora v podniku používajícím původní systém Prytanis stačí při zakoupení nového počítače nainstalovat a nakonfigurovat terminál (Putty nebo Arctel), a to je vše. Naopak moderní desktopové aplikace fungují zpravidla jako tlustý klient, tzn. že veškerá business logika je umístěna na každém klientovi zvlášť, takže je potřeba takovou aplikaci instalovat. Ještě více tato výhoda vynikne při upgradu aplikace – u původního Prytanisu stačilo nahradit binární soubory na serveru, a všichni uživatelé, když se na server připojí, tak je budou používat; u klasických tlustých klientů je potřeba nahrát upgrade na každý počítač. Další výhodou byla nezávislost na platformě počítače (terminálu), na kterém uživatel pracoval – stačilo, pokud měl aplikaci podporující protokol ssh. 3 Integrace ale není zcela dokončená, jsou zde zbytečné nedostatky – např. dopravní podniky a jejich pobočky se zadávají zvlášť a nejsou nijak propojené na systémový číselník obchodních partnerů.
4.1
Informační systém Prytanis
19
První grafická verze systému Prytanis v jazyce OpenROAD Jak již bylo výše uvedeno, s tím, jak běžel čas, začal původní informační systém Prytanis ztrácet v průběhu let popularitu kvůli primitivnímu uživatelskému rozhraní. Proto v roce 2003 začal ve firmě Unis Computers, spol. s r. o. vývoj nové verze systému Prytanis s grafickým uživatelským rozhraním. Pro vývoj byla zvolena technologie OpenROAD (zkratka pro Open Rapid Object Application Development), což je objektově orientovaná grafická nástavba na Ingres 4GL. Technologie je typově podobná původnímu Ingres 4GL. Znovu obsahuje designer, kde programátor vytvoří formuláře (mající již podobu běžných formulářů a dialogových oken systému Windows), a na jednotlivé události ovládacích prvků (stisknutí tlačítka, opuštění pole, kliknutí myší) reaguje kódem v jazyce OpenROAD 4GL, který je podobný původnímu jazyku Ingres 4GL, s podporou objektově orientovaného programování. Znovu je při vývoji vše uloženo v databázovém systému a až při kompilaci je teprve vše převedeno do souborů, na rozdíl od původního Ingres 4GL ne přímo do strojového kódu, ale do mezikódu (nazývaného image), který je pak interpretován běhovým prostředím, které musí být na cílovém počítači nainstalováno. Tím je zajištěna nezávislost na platformě/operačním systému. Nová verze systému Prytanis vznikala jako tlustý klient, ale technologie podporovala i architekturu tenkého klienta s aplikačním serverem. V roce 2005 se začalo i s přepisováním původní aplikace Jízdní řády do nového GUI. Bohužel se však nikdy k žádné spustitelné verzi jízdních řádů nedošlo. V roce 2006 totiž firma Computer Associates v rámci celkové restrukturalizace své činnosti výrazně změnila podmínky licencování technologie OpenROAD. Bez toho, abych zde uváděl podrobnosti, došlo by k tomu, že při použití nového licenčního modelu na Ingres a OpenROAD by se výsledný systém Prytanis musel zdražil natolik, že by si ho žádný ze zákazníků nekoupil. Proto byl po zvážení všech následků vývoj v OpenROADu zastaven a odepsán. Nicméně z této fáze se dochovaly návrhy Jízdních řádů, které jsem také při analýze a návrhu nového modulu využil. Se zpětným ohlédnutím lze dnes říct, že bylo dobře, že se dnes dále ve vývoji v OpenROADu nepokračuje. Až při práci s prostředím .NET se poznalo, v čem všem je OpenROAD chudší. Zaprvé nejde o plně objektově orientovaný jazyk – např. nepodporuje konstruktory a destruktory, statické členy tříd, neumožňuje použít rozhraní (interface) ani jinak rozšířit jednoduchou dědičnost, apod. Je stoprocentně databázově závislý (na RDBMS Ingres). A v neposlední řadě jde o jednoznačně okrajovou technologii (na internetu k němu nejsou v podstatě žádné fóra, diskuze ani podobné zdroje řešení obvyklých problémů, uvolněné zdrojové kódy ani komponenty apod.), což také činí vývoj obtížným. Prytanis na platformě Microsoft .NET Od roku 2006 začal tedy vývoj nové, plně grafické verze systému v prostředí .NET, přičemž je použito know-how získané během 15 let vývoje původního systému systému. Vzhledem k tomu, že se během doby do značné míry změnily i metody vývoje software, přistoupilo se při vytváření tohoto „nového Prytanisuÿ ke kompletní analýze a návrhu aplikace v modelovacím jazyce UML (při vývoji v OpenROADu se totiž kvůli podobnosti jazyků pouze přepsalo uživatelské rozhraní). Nový systém je navrhován v třívrstvé architektuře (uživatelské rozhraní, business logika a databázová vrstva), je psaný v jazyce C# (pro Microsoft .NET runtime) pro
20
4
SOUČASNÝ STAV PROBLEMATIKY
RDBMS Ingres, nicméně architektura je navrhovaná s ohledem na to, aby byl systém co možno nejvíce databázově nezávislý (takže při požadavku některého zákazníka na jiný databázový systém stačí přepsat menší část databázové vrstvy). Vedení firmy vynaložilo při vývoji tohoto nového systému značné investice i do nákupu externích vývojových komponent, např. DXperience Enterprise (který obsahuje řešení eXpress Persistent Objects pro mapování business objektů do relační databáze, sadu ovládacích prvků pro uživatelské rozhraní Xtra Editors nebo nástroj pro tvorbu reportů Xtra Reports). V této práci navrhovaná aplikace Jízdní řády má být jednou ze součástí právě tohoto systému.
4.2
Další možnosti vedení jízdních řádů
Vedení jízdních řádů linek silničním dopravy v informačním systému Prytanis není pro dopravní podniky jedinou možností. Na trhu existují další aplikace, které toto umožňují. Vzhledem k tomu, že jde o velice specifickou oblast, je ale tvorba softwaru s tímto zaměřením doménou specializovaných firem. Pokud navíc odhlédnu od nástrojů pro jízdní řády linek drážní dopravy4 , tak lze uvést jen několik systémů a aplikací, které se dopravním podnikům na českém/regionálním trhu nabízejí. (Neuvádím zde původní informační systém Prytanis na textovém režimu, který je stále v některých firmách používán. Jeho popis a zhodnocení byly provedeny výše.) V současnosti zřejmě nejpoužívanější aplikací pro vedení jízdních řádů linek silniční dopravy je balík WinADO od slovenské firmy EM Test. Ačkoliv původně šlo pouze o doplňkový software pro systém vybavení cestujících v MHD a pravidelné autobusové dopravě, sloužící k zadání dat pro práci systému, postupně se vyvinul v poměrně komplexní a pěkně řešený systém, který už je na elektronických strojcích a čtečkách karet nezávislý a lze ho používat pouze pro správu a editaci jízdních řádů linek. Kromě modulu Linky (který je jeho základní částí a odpovídá aplikaci, kterou zde v této práci navrhuji) obsahuje i moduly Turnusy, Přehledy stazek (ZPVOD) a Vozidla a jejich údržba a dokonce i účetnictví a personalistiku. Je tedy možné výlučně pomocí tohoto systému zajistit komputerizaci všech základních procesů dopravního podniku. Uživatelské rozhraní je plně grafické, a navíc poměrně dobře a přehledně zpracované, a dá se říct, že je to zřejmě nejvýznamnější konkurent informačního systému Prytanis z pohledu firem zabývajících se pravidelnou osobní dopravou. Další aplikací sloužící ke správě jízdních řádů je USV-C od firmy Mikroelektronika Vysoké Mýto. I tento je navržen jako software pro zadání dat potřebných pro elektronické strojky a další elektronické vybavení autobusů MHD. Na rozdíl od výše popisovaného systému WinADO se ale nerozvinul do podoby komplexního podnikového systému, vedou se zde pouze linky a ceníky a další různé informace potřebné pro elektronické prvky v MHD (parametry pro hlásič, nápisy pro tabla v autobusech, nastavení strojků pro tisk jízdenek). 4
Jídzní řády silniční a drážní dopravy je nutné důsledně odlišovat. Jízdní řády železniční dopravy a jejich obsah jsou totiž upraveny jiným legislativním, opatřením, a to § 55 dopravního řádu drah (173/1995 Sb.). Vedení linek železniční dopravy musí navíc řešit další problémy, se kterými se silniční doprava nepotýká. Zejména jde o propustnost jednotlivých dopravních cest, kapacita každé této cesty je dána počtem kolejí, a je třeba zajistit, aby po každé koleji jel v jednom časovém okamžiku jen jeden vlak; toto není u silniční dopravy třeba řešit. Při konsrukci jízdních řádů železniční dopravy se proto tvoří kompletní grafikon, a aplikace sloužící k vedení jízdních řádů linek železniční dopravy jsou značně složitější.
4.3
Možnosti počítačové optimalizace hromadné linkové dopravy
21
Uživatelské rozhraní je sice grafické, v podobě formulářové aplikace, ale není již tak dobře zpracované jako ve WinADO. Pro komplexní zajištění procesů v dopravním podniku je tedy USV-C nedostačující. Praxe ale ukazuje, že většina dopravních podniků má tuto aplikaci zakoupenou a používá ji k zadávání dat a ovládání elektronických komponent ve vozech MHD. Pro samotné zadávání a editaci linek pak používají jiné systémy (např. IS Prytanis), a v nich vytvořené linky a jejich jízdní řády pak naimportují do USV-C. Proto i jednou z funkcí nově navrhovaného modulu Jízdní řády systému Prytanis musí být výměna dat (export a import) s aplikací USV-C. Poměrně uceleným systémem řízení přepravní činnosti dopravních podniků je systém Skeleton od olomoucké firmy FS Software. Obsahuje modul pro tvorbu linek a jejich jízdních řádů (nabízí i grafikony a možnosti optimalizace jízdních řádů), a další moduly pro sledování Turnusů, provozu a údržby vozidel apod. Neobsahuje ale žádný ekonomický/účetní modul, slouží výhradně pro komputerizaci dopravy, takže firmy jej využívající musí používat i jiný systém pro ekonomiku a účetnictví. Brněnská firma Chaps, která mimo jiné vede Celostátní informační systém o jízdních řádech veřejné osobní linkové dopravy, vydává vlastní specializovanou aplikaci pro tvorbu jízdních řádů SOCRET. Její funkčnost je omezená jen na vedení jízdních řádů linek (a potřebných číselníků – zastávek, typů vozů apod.), neřeší již další agendu dopravních podniků, jako třeba turnusy nebo stazky (ZPVOD). Výhodou je ale velice dobrá spolupráce s Celostátním informačním systémem.5
4.3
Možnosti počítačové optimalizace hromadné linkové dopravy
Editací a správou jízdních řádů, o které jsem v této práci až doposud psal, bylo myšleno ruční zadávání jízdních řádů linek, tj. pracovník zodpovědný za plánování přepravy ručně sestaví linky, trasy jednotlivých spojů a časy jejich odjezdů z jednotlivých zastávek na linkách. Při pohledu na problematiku by ale čtenáře mohl napadnout druhý přístup ke tvorbě jízdních řádů, a to jejich vyhodnocení jakožto řešení úlohy matematického programování. Na tomto principu staví mimo jiné i optimalizační systém Kastor, vyvinutý na Žilinské univerzitě v Žilině (Palúch a Majer, 2007). Základní úlohy optimalizace hromadné linkové dopravy V rámci optimalizace hromadné linkové dopravy osob lze vysledovat několik na sebe navazujících optimalizačních úloh. Základním podkladem pro všechny tyto metody je analýza proudů cestujících, které jsou nejlépe vyjádřeny tzv. OD-maticí (z anglického Origin-Destination Matrix ). První poměrně náročnou úlohou je pak již samožné získání této matice. Kromě metody úplného manuálního sběru dat o všech cestujících na linkách, který je velmi finančně náročný6 , existuje větší množství matematicko-statistických po5
Povinností každé firmy provozující veřejnou osobní linkovou dopravu je předávat aktuálně platné jízdní řády svých linek do Celostátního informačního systému o jízdních řádech veřejné osobní linkové dopravy. Jedním z požadavků na aplikace pro vedení jízdních řádů je proto i export dat právě do tohoto systému. Tato funkčnost bude tedy i součástí modulu, který zde v této práci navrhuji. 6 Uvádí se, že jeden den dopravního průzkumu ve městě se 100 000 obyvateli vyjde řádově na milion korun.
22
4
SOUČASNÝ STAV PROBLEMATIKY
stupů sloužících k získání OD-matice a modelování pohybu cestujících obecně, více lze nalézt v odborné publikaci věnované tomuto tématu (Abrahamsson, 1998). Druhou úlohou v pořadí, poté, co jsou stanoveny proudy cestujících, je návrh systému linek. Uvádí se, že pro městskou dopravu je vhodná řídší síť linek s menšími rozestupy spojů, zatímco pro příměstskou dopravu spíše topograficky hustší síť linek s méně spoji. Obecně jde o úlohu řešitelnou pomocí matematického programování, v současnosti se nejvíce uplatňuje přístup, kdy člověk – dopravní inženýr – navrhne více variant pokrytí území sítí linek, a počítač z nich podle optimalizačních kritérií (zpravidla OD-matice) vyhodnotí nejlepší možnost. Jakmile jsou navrženy linky, přichází další optimalizační úloha, kterou je návrh časových poloh spojů. Zde je třeba brát v úvahu nerovnoměrnosti požadavků cestujících na přepravu (ranní a odpolední špička). Optimalizační algoritmus musí řešit koordinaci spojů různých linek na společných úsecích tak, aby se tyto pokud možno pravidelně střídaly7 , a koordinaci v přepravním uzle, která má za cíl, aby cestující čekali na přestup co možná nejkratší dobu. V řadě poslední úlohou je pak optimalizace oběhu vozidel a osádek, tj. turnusů. Jde o poměrně komplikovaný problém, který se zpravidla řeší postupně (nejprve se rozvrhnou oběhy vozidel, což lze převést na klasický přiřazovací problém, a poté se pro vypočítané turnusy vozidel navrhnou vhodné směny řidičů). Toto řešení má ale tu potíž, že se řidiči na vozidlech velice často střídají. Pokusy o řešení obou dílčích částí současně vedou pak na natolik složitý problém, že doposud nebyl uspokojivě vyřešen. Výsledky optimalizace a jejich využití Z předcházejícího výkladu je doufám zcela zřejmé, že naivní představa, že by po zadání proudů cestujících bylo možné počítačově vygenerovat jízdní řády linek a turnusy vozidel a řidičů, je zcela nereálná. Ačkoliv se čistě teoreticky jedná o úlohy řešitelné matematickým programováním, přenos výsledků z teoretické do praktické roviny je natolik komplikovaný, že jde spíše o zajímavou vysokoškolskou úlohu, a v reálných dopravních podnicích se z provedených pokusů o optimalizace využilo dost málo. Při zadávání optimalizačních úloh je totiž třeba pracovat s tolika obtížně kvantifikovatelnými proměnnými, že samotné sestavení logicky správného matematického modelu bývá zpravidla neřešitelným problémem. Do řešení je třeba zahrnout spoustu veličin, často externího rázu (např. pokud je v regionu železnice, tak bývá většina cestujících přepravována po ní a autobusy by měly sloužit spíše jen jako návoz). Praxe ukazuje, že dopravní podniky zpravidla jdou „cestou nejmenšího odporuÿ, nejsou ochotné „překopatÿ celou síť linek a jízdní řády mění jen v nejmenším možném rozsahu, jen pokud to konkrétně vyžaduje změna proudů cestujících. Optimalizace hromadné linkové dopravy tedy zůstává pouze zajímavou úlohou na akademické úrovni. Ani jedna z konkurenčních komerčních aplikací, které jsem zmiňoval v předchozí části, také žádné metody počítačové optimalizace nepodporuje, a ani žádný ze zákazníků firmy, s kterým byla tato problematika konzultována, o nic podobného nemá zájem. Proto se ani já v návrhu modulu Jízdní řády informačního systému Prytanis možnostmi počítačové optimalizace jízdních řádů linek hromadné dopravy nebudu zabývat. 7 Jde o úlohu známou jako Žilinský problém, který vede na úlohu optimalizace rozmisťování mnohoúhelníků po kružnicích.
5
EKONOMICKÉ ZHODNOCENÍ
5
23
Ekonomické zhodnocení
Pochopitelně, dopravní podniky se nesnaží o co nejlepší počítačovou podporu svých procesů bezúčelně a investice do svého programového vybavení, stejně tak jako všechny ostatní investice obecně, realizují jen pokud od nich očekávají ekonomický zisk.8 V této kapitole se tedy pokusím ekonomicky zhodnotit dopady komputerizace řídících procesů v dopravní společnosti.
5.1
Informační systém dopravního podniku
Dopravní podniky jsou právní formou i organizací podobné všem ostatním podnikům v národním hospodářství a motivem jejich existence je tedy zisk. Proto by i jejich informační systém měl obsahovat manažerské aplikace zabývající se rentabilitou jednotlivých činností a analytickými a predikčními modely. Co se ale od většiny ostatních podniků liší, jsou nižší vrstvy informačního systému v pyramidové hierarchii jeho globální architektury. Vzhledem k tomu, že hlavní náplní činnosti je doprava osob, tak i aplikace na úrovni operativního a taktického řízení jsou výrazně orientovány tímto směrem.9 Základní aplikací je správa jízdních řádů linek. Na jízdní řády linek navazuje organizace turnusů vozidel a řidičů, a sestavení denního přepravního plánu. Ten slouží jako podklad pro stazky (záznamy o provozu vozidel osobní dopravy), informace z nich se pak používají pro výpočet mzdy řidičů. Kromě jízdních řádů vstupuje do turnusů také naplánovaná nepravidelná osobní doprava (např. zájezdy). Nezbytnou agendou je evidence vozidel a záznamy o jejich údržbě. K vozidlům se vedou hospodářské listy vozidel, kde se evidují náklady na vozidlo, jeho spotřeba a další ekonomické charakteristiky. Na jízdní řády dále navazuje rezervační a předprodejní modul. Většina jízdenek ale zpravidla není prodaná v předprodeji, ale až přímo ve vozidle. Proto musí informační systém dopravní společnosti spolupracovat s elektronickými strojky nejen ve směru exportu údajů o spojích a zastávkách do strojků, ale i importu údajů o prodaném jízdném ze strojků do systému. V manažerské nástavbě systému by pak měla být aplikace hodnotící rentabilitu dopravy na úrovni jednotlivých linek a jejich spojů. Kromě toho obsahuje informační systém dopravního podniku i moduly nezbytné pro všechny firmy, jako je účetnictví, personalistika, banka a pokladny, evidence majektu a další.
5.2
Ekonomické dopady komputerizace procesů
Cílem fungování dopravního podniku (nebo spíše jeho vlastníků) je maximalizace jeho zisku. Zvýšení zisku lze obecně dosáhnout buď zvýšením výnosů, a nebo snížením nákladů. Určení cen ale nebývá ve výhradní kompetenci dopravních podniků, dost často 8
Ekonomický zisk je rozdíl mezi celkovými výnosy a ekonomickými náklady. Do ekonomických nákladů se kromě explicitních (účetně vyjádřených) nákladů započítávají i náklady ušlé příležitosti (tj. výnosy, které by bylo možné dosáhnout, kdyby byly prostředky investovány do jiné nejvýhodnější alternativy) (Macáková, 2002). Zjednodušeně lze tedy říct, že investice přináší ekonomický zisk tehdy, když všechny ostatní alternativy investice vedou k horšímu účetnímu zisku než tato. 9 Neuvádím v tomto zhodnocení běžné kancelářské aplikace a podobný software, který je k nalezení v každém podniku, a ekonomiku podniku nijak zásadně neovlivňuje.
24
5
EKONOMICKÉ ZHODNOCENÍ
(zejména u městské hromadné dopravy) dochází k tomu, že ceny jízdného jsou výsledkem vyjednávání se správou města, popř. územní samosprávné jednotky. Tuto pozici má vedení města z toho důvodu, že zpravidla městskou hromadnou dopravu dotuje ze svého rozpočtu. Množství přepravovaných cestujících se v čase vyvíjí, od roku 1990 došlo k poklesu poptávky po veřejné hromadné dopravě o 50 % (Pavelčík, 2003), zatímco výrazně vzrostl stupeň automobilizace (počet osobních aut na 1000 obyvatel). Tento trend ale spíše souvisí s celospolečenskými změnami; poptávka po dopravě realizované dopravním podnikem je do značné míry cenově neelastická, a nelze očekávat, že by ji dopravní podniky mohly výrazně zvýšit svou cenovou politikou (možná spíše kvalitou služeb – lepší organizací dopravy např. při přestupech, vhodným vedením linek apod.). Je tedy zřejmé, že možnosti dopravních podniků zvýšit své výnosy jsou značně omezené. Pokud má tedy dopravní podnik zvyšovat svůj zisk, jeho hlavním nástrojem bude minimalizace nákladů. Té lze poměrně efektivně dosáhnout optimalizací podnikových procesů, při níž může hrát zásadní roli podpora řízení těchto procesů vhodným informačním systémem. Optimalizace pak navíc může i pomoci zlepšit kvalitu poskytovaných služeb. Je pochopitelné, že nejlepších hospodářských výsledků dosáhne dopravní podnik tehdy, když používá informační systém co nejlépe podporující jeho podnikové procesy. Pokud bychom uvažovali případ, kdy některá z v předchozí části uvedených aplikací není pokryta programovým vybavením, tak jde o poměrně zásadní narušení možnosti koncepčního řízení dopravního podniku. Těžko si lze například představit případ, kdy by turnusy byly plánovány a vedeny „na papířeÿ, protože v dobře koncipovaném systému jsou zdrojem pro další aplikace sloužící ke komplexnímu řízení činnosti podniku. Je třeba uvést, že tato situace se již v dnešní době v podstatě nevyskytuje, dopravní podniky už mají všechny své zásadní agendy pokryty odpovídajícím programovým vybavením. Co je ale zásadním a často rozhodujícím faktorem úspěšnosti používání informačního systému a počítačové podpory řízení podniků celkově, je integrace jednotlivých částí informačního systému. Situace, kdy např. k vedení jízdních řádů je používána jedna aplikace, a pro předprodej jízdenek jiná, která s první není integrovaná, představuje poměrně značné obtíže, protože nutí uživatele ručně zadávat údaje, které jsou již obsažené v bázi dat jiné aplikace. Dezintegrace jednotlivých aplikací informačního systému je závažným problémem při zavádění informačních systémů, a to nejen v oblasti dopravních podniků. Jedině dobře integrovaným systémem lze zajistit hladký průběh řídících procesů v podniku, tak že data zadaná v jedné dílčí aplikaci se projeví i v jiných aplikacích na jiné úrovni řízení, což přispívá k dobré synchronizaci podnikových procesů, a tím v důsledku i k úsporám jejich nákladů a času. Lze říct, že tento problém je poměrně častý, protože existuje málo systémů umožňujících softwarové pokrytí všech činností dopravního podniku. V současné době by se v českých dopravních podnicích daly rozlišit tři situace: • Všechny význačné procesy dopravního podniku jsou pokryté jedním integrovaným informačním systémem, obvykle od jednoho dodavatele. Toto je z ekonomického hlediska nejvhodnější situace, protože nevznikají zbytečné problémy při souběžném používání více heterogenních systémů (např. již zmíněná duplicita zadávání dat). Příkladem systému pokrývajícího všechny činnosti dopravního podniku je právě informační systém Prytanis, a nebo WinADO od firmy EM Test.
5.2
Ekonomické dopady komputerizace procesů
25
• Dopravní podnik používá jeden systém pro řízení dopravní činnosti, a druhý pro běžnou ekonomickou agendu. I tato situace je poměrně uspokojivá, protože hlavní je integrace v rámci aplikací pro řízení dopravní činnosti (např. výše uvedená spolupráce jízdních řádů s předprodejním systémem). Nicméně tyto dva systémy musí být nějakým způsobem integrovány, protože například údaje z aplikace vozidla a jejich údržba se musí promítnout do evidence dlouhodobého majetku, nebo stazky do mezd a personalistiky. Jde o poměrně častý případ, příkladem systému pro řížení dopravní činnosti může být v předchozí kapitole popsaný systém Skeleton, a pro běžné ekonomické aplikace společné pro většinu podniků lze použít v podstatě libovolný z běžných komerčních ekonomických softwarových balíků (např. Money S5 ), se kterým se podaří vyřešit ingegraci. • Dopravní podnik používá větší množství heterogenních aplikací a systémů. Toto je jednoznačně nejhorší varianta, protože čím více aplikací je do podpory procesů dopravní společnosti zapojeno, tím obtížnější je jejich vzájemná integrace. Jednoznačným problémem je duplicita dat, navíc může docházet k problémům, když se v jedné aplikaci něco založí a v jiné se neprovede následující krok logicky odpovídající průběhu podnikového procesu (např. v jedné aplikaci je zadán turnus vozidla, v jiné nejsou po jeho odjetí do hospodářského listu daného vozidla zadané jeho ujeté kilometry a spotřebované pohonné hmoty).
26
5
EKONOMICKÉ ZHODNOCENÍ
6
TEORETICKÁ STUDIE
6
27
Teoretická studie
Samotný vývoj programového vybavení je poměrně náročnou disciplínou lidského konání, kde je možné vysledovat více názorů na optimální metody a postupy. V této kapitole naznačím postupy a metodiky, které jsem při tvorbě své práce využil. Uvádím zde jednak infromace a názory z odborné literatury – nejvýznamnějším zdrojem je publikace Objektové modelování a UML v praxi 2000 (Kraval, 2001), která se jako zdroj prolíná většinou sekcí této kapitoly – a jednak poznatky a zkušenosti získané mnou či mými spolupracovníky během vývojového procesu ve firmě Unis Computers, spol. s r. o.
6.1
Životní cyklus softwaru
Životní cyklus softwaru (nebo také Proces vývoje softwaru) je podle Wikipedie posloupnost kroků vedoucí k vytvoření kompletního softwarového díla. Různé metodiky10 uvádějí rúzné fáze vývoje, nicméně pokud by měl být proveden souhrn, tak se všechny přibližně shodují při tvorbě aplikace objektově orientovaným způsobem na těchto krocích (budou podrobně popsány v další části této práce): 1. Úvodní studie – jde o specifikaci požadavků na budoucí systém. Často bývá prováděno modelování podnikových procesů, protože komputerizace identifikovaných procesů zpravidla tvoří požadavky na systém. Proces jako takový je souhrn kroků vedoucí k nějakému cíli, pokud je procesů (a tedy i cílů) více, bývá někdy vhodné sestavit i model cílů, aby byly identifikovány hlavní a vedlejší cíle a vztahy mezi nimi. Výstupem této fáze je tedy seznam požadavků na systém. 2. Analýza – v této fázi jde hlavně o to, postihnout podstatu problémů a jejich řešení na úrovni problémové domény. Zejména tedy jde o řešení nezávislé na konkrétním implementačním prostředí. Základním a zásadním výstupem této fáze je use-case model, dále je to konceptuální model tříd a kde je třeba, tak další analytické modely UML (sekvenční diagram, stavový diagram). Jsou také vytvořeny test-casy pro pozdější testování scénářů podle specifikace. 3. Návrh (design) – navazuje na analýzu. Zde již jde o návrh realizace systému v konkrétním implementačním prostředí; v popisech se již (na rozdíl od analýzy) objevují pojmy z implementace (tabulka, sloupec). Základním modelem fáze návrhu je model tříd, který navazuje na konceptuální model vytvořený v analýze. Dále můžou být vytvořeny další modely týkající se konkrétní implementace, jako komponentní model, nebo deployment model. Designér také identifikuje a navrhne test-casy, jednak pro testy technologie (zátěž, kritické body systému, rychlost), a pokud jsou používány jednotkové testy, tak i pro funkční testování (protože až designer identifikuje jednotlivé metody tříd/objektů a jejich funkce, tj. výstupy odpovídající daným vstupům). 10
Asi by bylo na místě, když zde vysvětlím pojmy metodologie, metodika a metoda, protože bývají poměrně často zaměňovány, a to i v odborné literatuře. Metodologie je souhrn definovaných principů a speciálních pojmů, používaných pro orientaci v dané oblasti, v podstatě se jedná o vědu zabývající se studiem způsobů řešení problémů a hledání odpovědí. Naproti tomu metodika představuje konkrétní souhrn doporučených pravidel a postupů vedoucích k dosažení cíle. Součástí metodiky jsou pak jednotlivé metody, které jsou nasazeny pro řešení jednotlivých dílčích problémů (Konečný, 2007). Nepřesnosti v používání těchto pojmů v českých odborných textech pramení z nesprávného překladu z angličtiny. Slovo metodika totiž obvykle odpovídá anglickému methodology, zatímco českému metodologie odpovídá anglické metamethodology.
28
6
TEORETICKÁ STUDIE
4. Implementace a testování – jde o sestavení kódu podle specifikace předchozích fází, součástí je i testování: jednak jednotkové testy v průběhu implementace, a poté testy scénářů, uživatelského rozhraní, integrační a další, mající za cíl verifikaci sestaveného modulu, po skončení jeho kódování 5. Dokumentace, nasazení, zkušební a ostrý provoz – závěrečné fáze životního cyklu softwaru. Tyto závěrečné fáze jsou ale již mimo hlavní záběr mé práce, a proto je nebudu v dalším textu dále popisovat. Iterativní a inkrementální metoda vývoje Jde o moderní způsob vývoje, která se snaží odstranit nevýhody vodopádové metody vývoje. Podstatou je provedení návrhu a implenentace v jedné iteraci na jedné relativně malé části systému, zatímco kompletní návrh ještě není zdaleka dokončený. Poté se začne s další iterací, tj. návrh a naprogramování další části systému, a takto se složením všech iterací postupně získá celý systém. Iterace se týkají zejména návrhu a implementace, popř. částečně i analýzy. Naopak je zcela zřejmé, že kompletní úvodní studii je nutné provést před započetím dalšího vývoje, protože specifikace požadavků na tvořený systém je základem, bez kterého nelze ve vývojovém procesu pokračovat. Analýza může probíhat iterativně a inkrementálně, s jednou vyjímkou. Use case model by měl být kompletně sestavený a všechny případy užití aspoň hrubě popsané najednou, a pokud možno co nejdříve (to znamená ihned po hotové specifikaci požadavků, tj. na začátku fáze analýzy). Úplnost use-case modelu má zásadní význam při jeho použití v projektovém řízení. Jde totiž o první úplný popis systému. V okamžiku, když vedoucí projektu má v ruce kompletní sestavený use-case model, má vlastně seznam všeho, co bude potřeba navrhnout a naprogramovat. Díky tomu může reálně odhadnout rozsah prací, časovou a finanční náročnost, a plánovat rozvržení pracovníků. V opačném případě není možné v podstatě vývoj strategicky řídit.11 Navíc je vhodné, aby sestavený model případů užití byl v případě vývoje software na zakázku použit jako příloha smlouvy, protože jedině tak se přesně definuje rozsah vytvářeného systému a zabrání se zvyšování požadavků zákazníka.
6.2
Úvodní studie
Jedná se o první fázi vývoje, jejímž cílem je zejména specifikace toho, co tvořený systém bude umět. Z tohoto hlediska bývá často konstruován Business Process Model, ve kterém se postihnou procesy v podniku; na jeho základě se zvolí ty, které bude nový systém podporovat, a takto pak vznikají funkční požadavky na systém. Tato fáze tvorby softwaru je pěkně charakterizována v článku o procesním modelování (Merunka, 2003). Modelování podnikových procesů Modelování podnikových procesů (Business Process Modelling) je postup sloužící k postihnutí všech činností, které jsou v daném podniku prováděny. Zejména jde o zachycení 11
Specifikace požadavků je sice základním dokumentem, ale sama o sobě není příliš podrobná, co se týče detailů, a proto k projektovému řízení nedostačující. Až teprve práce analytika odhalí v systému funkčnosti, které nejsou v požadavcích příliš popsány, protože je např. uživatelé považují za samozřejmé.
6.2
Úvodní studie
29
podstatných událostí na jedné straně a vstupů, výstupů a cílů procesů v podniku na straně druhé. Může být využit jako podklad pro specifikaci požadavků při vývoji softwaru, ale kromě toho bývají modelovány procesy v podnicích i za jinými účely – např. jako podklad pro jejich analýzu a reengeneering , a nebo jako nástroj pro vzdělávání zaměstnanců, aby si lépe uvědomili souvislosti mezi jednotlivými činnostmi podniku (Bider, 2003). K procesnímu modelování samotnému existuje několik přístupů, podle toho, k jakému účelu bude model použit. V dalším textu se budu zabývat pouze Eriksson-Spencerovou notací, protože pro specifikaci požadavků pro vývoj softwaru se mi zdá nejvhodnější důraz na události a vstupy a výstupy procesů.12 Jejími základními prvky jsou: • Proces – souhrn souvisejících aktivit, s určitým cílem, který má přesně definovaný počátek, konec, vstupy a výstupy. Procesy v procesním modelu můžou být později realizovány jedním nebo více případy užití systému. • Vstupy – vše, co ovlivňuje běh procesu. Vstupy lze dělit na dva typy: zdroje a informace. Zdroje představují všechny vstupy, které se průběhem procesu spotřebují (resp. už nikde dále v procesním modelu nevystupují), zatímco informace můžou být používané více procesy pro ovlivňování jejich průběhu, a to i opakovaně. Souhrnně jde o určité objekty, zpravidla o instance tříd v konceptuálním class modelu. • Události – zpravidla iniciují spuštění procesů. Událost sama bývá něčím vyvolána – obvykle aktorem. • Výstupy – jde o objekty, stejně jako vstupy. Výstupy jsou výsledky běhu procesu, ať již reálné objekty nebo informace, a mohou se uplatnit jako vstupy dalších procesů. • Cíl – každý proces by měl mít dobře definovaný cíl, je to důvod, proč se v podniku tento proces provádí. Rozdíl mezi výstupem a cílem je v tom, že zatímco výstup je konkrétní objekt nebo informace (která před během procesu neexistovala, popř. existovala v jiné podobě, z které byla transformována), cíl bývá spíše abstraktní formulace. Dobře si to lze představit na příkladu procesu Přijetí materiálu na sklad, jehož výstupem je uskladněný materiál, popř. kromě toho i dokument příjemka, zatímco jeho skutečným cílem může být např. udržení stavu materiálu na skladě v požadované výši. Více procesů může mít stejný cíl (např. stejný cíl jako v předchozím příkladě by měl i proces Objednání materiálu). Jak již bylo výše několikrát zmíněno, procesní model se konstruuje pouze z důvodu identifikace požadavků na systém, prostřednictvím pochopení fungování tohoto podniku. Je proto potřebné si uvědomit zásadní rozdíl mezi procesním modelem (a také modelem cílů, který bude popsán v další části práce), a všemi modely analýzy a návrhu, počínaje use-case modelem. Model podnikových procesů se většinou snaží postihnout všechny procesy, které v podniku (nebo jeho oddělení) probíhají, nezávisle na tom, jestli jsou již nějakým způsobem komputerizovány, a také bez ohledu na to, jestli budou nebo nebudou podporovány navrhovaným informačním systémem (v podstatě je to naopak, teprve z procesního modelu se vybírají požadavky na systém). Proto se nejedná o model infromačního systému, ale spíše o model podniku, obsahuje i procesy, které nebudou zahrnuty do systému, a jsou popisovány v kontextu, jak proces v podniku doopravdy probíhá. Oproti 12 Dobře známá a používaná notace BPMN je vhodná spíše pro reorganizaci podnikových procesů, protože klade důraz na souslednost a souvislosti jednotlivých procesů. Jednotlivé přístupy, jejich výhody a nevýhody a nejvhodnější využití jsou velice pěkně shrnuty v článku Choosing Approach to Business Process Modeling (Bider, 2003).
30
6
TEORETICKÁ STUDIE
Obr. 1: Ukázka jednotlivých prvků Eriksson-Spencerovy notace pro modelování podnikových procesů. Zdroj: The Business Process Model (Sparx, 2000).
tomu use-case model je model tvořeného systému, obsahuje jen případy užití, které budou systémem podporovány, a v popisu use-casu jde o to, jak bude systém při různých činnostech používán. Domněnka, že procesy v procesním modelu podniku a případy užití v use-case modelu navrhovaného informačního systému mají mezi sebou vztah 1 : 1, je tedy hrubou chybou v analýze. Procesní model navíc zpravidla nebývá příliš dopodrobna rozepsaný. Procesy lze sice dekomponovat, ale přílišná dekompozice nemusí být žádoucí, protože ve fázi specifikace požadavků jde hlavně o to požadavky identifikovat.13 Procesní model je ale rozhodně užitečný, jako jeho další přínos (kromě identifikace požadavků) lze uvést i velice brzkou identifikaci objektů problémové domény (vstupy a výstupy budou odpovídat třídám v modelu tříd). Model cílů Pokud se jedná o rozsáhlejší podniky, tak také počet v nich probíhajících procesů je vyšší. Tyto procesy mají různé cíle. Podstatné je to, že jednotlivé cíle těchto procesů mají mezi sebou určité vztahy, tvoří doslova hierarchickou strukturu. Teprve srovnáním vztahů mezi jednotlivými cíli lze zodpovědně rozpoznat vztahy mezi procesy. Modelování podnikových cílů není nutným krokem při vývoji informačního systému, ale může pomoci lépe porozumět jednotlivým procesům a jejich motivaci. Lze tak například zabránit situaci, kdy některé z cílů jsou natolik základní, že si na ně vedení firmy vzpomene, až když zjistí, že je vytvořený informační systém nepodporuje (Kueng a Kawalek, 1996). Diagram cílů, který je grafickým vyjádřením modelu cílů, zobrazuje cíle podniku, a vztahy mezi nimi. Základním vztahem mezi cíli je dekompozice, pomocí níž jsou hlavní podnikové cíle (např. dosažení zisku, udržení se na trhu) rozkládány na dílčí cíle (nízké náklady, zvýšení obratu). Dalším slabším vztahem mezi cíli je vztah contribution (do češtiny by ho šlo přeložit jako „příspívá kÿ), který umožňuje modelovat další slabší závislosti (např. nízké ceny služeb přispívají ke spokojenosti zákazníků). 13 Jako příklad lze uvést aplikaci Spedice informačního systému Prytanis, která v procesním modelu vyšla na deset až patnáct procesů, zatímco nakonec obsahovala kolem 130 use-casů. Je to způsobeno hrubostí procesního modelu – např. jako jeden proces byla označena Správa číselníků, ale vzhledem k rozsahu aplikace se nakonec objevilo ke třiceti číselníkům, které bylo třeba v aplikaci spravovat, což vyústilo na třicet případů užití.
6.3
Analýza
31
K modelování podnikových cílů byl vytvořen jazyk GRL (Goal-Oriented Requirments Language) (Liu a Yu, 2003). Pomocí jeho diagramů lze vyjádřit vzájemné vztahy mezi cíli a také vztahy mezi cíli a požadavky na systém. Vzhledem k tomu, že jde o poměrně rozsáhlou problematiku, která je vzhledem k zaměření této práce spíše okrajová, nezbývá mi než odkázat čtenáře na odbornou literaturu. Specifikace požadavků Specifikace požadavků je v podstatě hlavním výstupem celé fáze úvodní studie. Jde o formální dokument, jehož hlavním smyslem je, že slouží jako ujednání mezi vedením vývoje a zákazníky, ohledně toho, co bude obsahem aplikace (Berezin, 1999). Dokument je významný zejména z hlediska řízení projektu, protože jde o první hrubý soupis funkčností požadovaných po systému. Naopak svým určením ani rozsahem neodpovídá analytickým dokumentům, jako např. use-case modelu – jde pouze o souhrnný soupis požadavků, a právě prací analytika je rozebrat požadavky a na jejich základě navrhnout podrobnou specifikaci funkcionality tvořeného informačního systému. Požadavky na aplikaci se mohou dělit do několika skupin. Nejvýznamnější jsou funkční požadavky. Jde o funkce, které by měl tvořený informační systém podporovat, často odpovídají jednotlivým procesům naznačeným v procesním modelu (resp. funkčními požadavky je komputerizace těchto procesů). Pokud je prováděno modelování podnikových cílů, lze nalézt požadavky na systém podle jednotlivých podnikových cílů tak, že požadované funkce systému budou prostředky vedoucí k naplnění těchto cílů. Funkční požadavky tvoří obvykle nejrozsáhlejší část specifikace požadavků (Nuseibeh a Easterbrook, 2000). Další skupinou požadavků jsou nefunkční požadavky. Jde jednak o požadavky na použité technologie, jednak na specifické rysy uživatelského rozhraní aplikace. Další skupinou pak jsou obecné požadavky odpovídající standardu ISO/IEC 9126 (Botella a kol., 2007), kam náleží požadavky na použitelnost (snadnost obsluhy), výkonnost, spolehlivost (střední počet selhání za jednotku času, doba nutná k obnově), škálovatelnost, bezpečnost a rozšířitelnost (snadnost přidání dalších funkčností, se kterými v původním návrhu aplikace nebylo počítáno).
6.3
Analýza
Poté, co jsou specifikovány základní požadavky na systém, přichází na řadu analýza, jejímž cílem je podrobně popsat strukturu a chování navrhovaného systému na úrovni pojmů problémové domény. Zásadní pravidlo při systémové analýze je, že by systém měl být popsán bez ohledu na použité technologie a implementační prostředí, protože jedině tak lze dosáhnout znovupoužití výsledků analýzy (např. může být vytvořena jedna verze aplikace jako desktopová aplikace, tlustý klient, a druhá verze jako webová aplikace). Use-case model a jeho prvky Use-case model je základním a v moderním vývoji softwaru nezbytným modelem fáze analýzy. Jeho cílem je postihnout to, jak bude systém uživateli používán, tj. jaké funkcionality bude poskytovat a jak s ním budou uživatelé pracovat. Při modelování use-casů analytik vychází ze specifikace požadavků, která je formálně přijatým výstupem předchozí
32
6
TEORETICKÁ STUDIE
fáze (úvodní studie). Hlavní prací je pak jednáním se zákazníky – budoucími uživateli – podrobně popsat navrhovaný systém. Use-case model obsahuje dva základní typy elementů: use-casy a aktory. Use-case (česky případ užití) je základní jednotka funkčnosti poskytovaná systémem – jedna užitná činnost systému, která vede ke splnění určitého požadavku uživatele. Kompletní systém se pak dá vyjádřit jako souhrn většího množství případů užití – užitných činností, které poskytuje. Use-casy jsou z hlediska dalšího vývoje zásadní, protože tvoří kompletní popis systému, „knowledge baseÿ toho, jak bude systém pracovat. Aktor je externí subjekt, který systém používá (přesněji který předává systému určité vstupy nebo od něj přijímá jeho výstupy). Pojmově odpovídá terminátorům v data-flow diagramech Yourdonovy strukturované analýzy. Aktorem můžou být osoby používající systém, externí systémy spolupracující s ním, a také např. běh času (např. v případě dávkové úlohy volané ve stanovenou hodinu v noci).
Obr. 2: Ukázka prvků use-case diagramu.
Mezi jednotlivými elementy use-case modelu (use-casy a aktory) se modelují různé vazby. Jednou z častých vazeb je interakce include, která specifikuje, že jeden use-case obsahuje druhý, tj. tento druhý je nedílnou součástí prvního. Jako příklad lze uvést, že součástí use-casu Vytvoření nové objednávky bude Výběr odběratele z číselníku obchodních partnerů. Význam této dekompozice, a obecně všech interakcí mezi use-casy, je nalezení re-use co nejdříve v analýze. Dalším podobným vztahem je extends, který specifikuje volitelné rozšíření funkčnosti původního use-casu, pokud nastanou určité podmínky. Např. již zmiňovaný případ užití Vytvoření nové objednávky může být v případě, že vybraný odběratel má u podniku dluh (faktury po splatnosti), rozšířen use-casem Zobrazení závazků obchodního partnera po splatnosti. Místo (podmíněného) volání rozšiřujícího use-casu je nazýváno extension point. Vztahy extends a includes jsou realizací dost podobné (rozdíl je jen v povinnosti/volitelnosti volaného use-casu), pojmově odpovídají volání subrutiny a někdy není volba jednoho z nich zcela jednoznačná. Mezi use-casy může být i slabší vztah než přímé volání jednoho druhým. Typické je, že jeden use-case musí předcházet druhému (tj. aby šlo začít jeden, musel být předtím proveden jiný), ale takovýchto slabších vztahů lze najít větší množství, a slouží pouze jako upřesňující informace pro lepší pochopení používání aplikace, takže je není třeba modelovat všechny. (To ani není dobře možné, neboť téměř mezi každými dvěma use-casy by šlo nalézt určitý vztah). K modelování těchto slabších vztahů slouží vazba dependency s příslušným stereotypem, např. pro specifikaci toho, že jeden use-case předchází druhému, bývá používán stereotyp precedes (Holub, 2000). Poněkud kontroverzním vztahem v use-case modelu je generalizace/specializace, bude jí věnována následující podsekce práce.
6.3
Analýza
33
Aktoři se k use-casům připojují pomocí asociace, která označuje, že určitý aktor používá určitý případ užití. Lze zadat směr této interakce. V use-case modelu se používá ještě jeden element, kterým je package. Představuje skupinu souvisejících činností a používá se pouze při tvorbě use-case modelu systému hierarchickým rozkladem a k přehlednému sdružení souvisejících případů užití. Rozklad use-case modelu na package není jednoznačný (každý analytik zřejmě dojde k jiné hierachii balíků souvisejících činností), lze při něm využít procesy a jejich hierarchii z procesního modelu (Štolfa a Vondrák, 2003). Model případů užití je jeden z nejvýznamnějších modelů ve vývojovém procesu vůbec. Kromě toho, že slouží jako detailní popis navrhovaného systému, od kterého se odvíjí další fáze vývoje, bývá využíván při projektovém řízení (bylo popsáno výše), při jednání se zákazníky (jako příloha smlouvy definitivně specifikující zakázku – tvořený systém), a jako podklad pro tvorbu dokumentace a pro vytváření testovacích případů (ty budou popsány později v této kapitole). Podrobnější výčet s vysvětleními lze nalézt v publikaci Objektové modelování a UML v praxi 2000 (Kraval, 2001).14 Generalizace/specializace v use-case modelu Generalizace/specializace15 (v dalším textu budu používat zkrácený pojem gen-spec) je vztah buď mezi dvěma use-casy, nebo dvěma aktory, značící, že jeden je zvláštním případem (specializací) druhého. Gen-spec je poměrně silným prostředkem k dosažení re-use, přesto se ale názory na jeho použití v use-case modelu různí. Mezi use-casy se gen-spec používá k vyznačení toho, že use-case vychází z jiného, ale má nějaké specifické vlastnosti. V use-case modelu je problém s tím, že use-case bývá předkládán i budoucím uživatelům, tj. osobám bez hlubších znalostí softwarové analýzy, a má tedy být tvořen tak, aby pro jeho porozumění nebyly takové znalosti zapotřebí, zatímco vztah gen-spec je pro většinu takovýchto lidí poněkud hůře pochopitelný. Zatímco vztahy extend a include si každý snadno představí jako volání jedné funkcionality z druhé (nebo spíše volání jednoho dialogového okna z druhého), generalizace/specializace není zdaleka tak snadno uchopitelná, a její časté používání model případů užití značně znepřehledňuje. Gen-spec mezi aktory vyjadřuje, že jeden aktor je speciálním případem druhého (např. Vedoucí účetního oddělení je specializací obecného Účetního, oproti němu může mít zřejmě větší oprávnění k zásadním krokům v účetním modulu). Tento vztah je o něco lépe pochopitelný, zde jde hlavně o to, že modelování gen-spec mezi aktory je zcela zbytečné. Jako vysvětlení je třeba uvést, z jakého důvodu jsou aktoři do use-case modelu zařazováni. Narozdíl od use-casů, které představují samotný systém a jsou základem dalšího vývoje, aktoři se modelují jen kvůli nalezení use-casů. Pro analytika je totiž zprvu podstatně snažší dát dohromady seznam těch, kteří systém budou používat, a u každého z nich 14
Existují i další rozšíření možností využití modelu případů užití. Při plánování zabezpečení systému lze využít use-case model doplněný o misuse-casy (do češtiny by šlo přeložit jako případy zneužití), což slouží pro nalezení možných způsobů napadení systému (Buchanan, 2004). V takovémto modelu se navíc jako další aktor objevuje útočník, který iniciuje misuse-casy, jako např. u webové aplikace, která bude umožňovat zadávání příspěvků návštěvníků, bude takovýmto misuse-casem Vložení spamu jako příspěvku. Pak se používá i dependency se stereotypem prevents, která slouží k označení, který use-case slouží k zabránění kterému misuse-casu (např. Vedení IP blacklistu brání již zmíněnému Vložení spamu). 15 Tento vztah bývá někdy nazýván dědičnost, což je ale v use-case modelu, narozdíl od class modelu, nedává smysl.
34
6
TEORETICKÁ STUDIE
pak specifikovat činnosti, které se systémem budou provádět, než sestavit use-case model přímo. Do dalšího vývoje už ale aktoři nevstupují.16 Analýza vztahů mezi nimi tedy nemá žádný smysl. Dokumentace případů užití Grafickým vyjádřením use-case modelu je use-case diagram. Na rozdíl od ostatních modelů UML není ale hlavní význam use-case modelu v jeho grafickém vyjádření, ale v dokumentaci k jednotlivým use-casům. Ty totiž představují kompletní popis navrhovaného systému, a právě popis průběhu každé užitné činnosti systému tvoří hlavní obsah systému. Rozsah dokumentace případu užití se v názorech v různých odborných publikacích liší, ale víceméně všichni se shodují na těchto základních částech: názvu, podmínkách před spuštěním a po provedení, základním toku a rozšiřujících a alternativních tocích událostí. Existují i šablony pro mnohem podrobnější zápis, umožňující zadat další údaje o případu užití, více informací lze nalézt v článku Precise Use Cases (Gelperin, 2004). Nicméně rozsáhlejší a formální dokumentace use-casů nebývá některými autory doporučována, protože vede k zbytečnému podrobnému popisování intuitivních faktů a činností, a výsledné use-casy jsou podstatně delší a hůře čitelné (Gottesdiener, 2004). Zásadní částí popisu use-casu jsou toky událostí, které představují posloupnost kroků (interakcí uživatele a systému) vedoucí ke splnění cíle use-casu. Rozlišují se základní tok (bývá nazýván happy day), rozšiřující toky (podrobněji rozepisuje jednotlivé kroky základního toku) a alternativní toky (nastávají při odlišných podmínkách, než které předpokládá základní tok). K samotnému zapsání obsahu use-casů se nabízí více možností: • Použít strukturovanou šablonu, zpravidla ve formě dokumentu MS-Word. Na internetu je k dispozici velké množství různě formálních a podrobných šablon, tento přístup navíc umožňuje použít v popisu i formátování, díky kterému je dokumentace případu užití podstatně přehlednější, a také hypertextové odkazy pro udání souvisejících use-casů, velmi dobře lze popsat i návrh sestavy. Na druhou stranu nevýhodou je, že takový use-case zpravidla není nijak propojený s CASE nástrojem, v kterém je obsažený všechen ostatní obsah analýzy; použití formálních šablon navíc dost často vede k zaměření na formální stránku use-casu namísto obsahové. • Zadat obsah případu užití pouze neformálně, ve formě intuitivního popisu prostým textem, např. do poznámky (note) k use-casu v CASE nástroji. Výhoda je zřejmá – rychlost a snadnost takového zápisu, nevýhodou může být nepřesný popis nebo opomenutí některého důležitého faktu (k čemuž ale může dojít i při použití formální šablony). 16
Existuje jedna výjimka. Aktoři pojmově představují role v systému, i když pouze na konceptuální úrovni. Tím myslím, že zpravidla každý „lidskýÿ aktor odpovídá jedné roli v přístupových právech. Nelze to ale vzít za zásadu s tím, že mezi aktory v use-case modelu a rolemi v systému bude vztah 1 : 1. Jinak by se při pozdějším přidání další role do systému (bez jakékoliv změny funkčnosti systému) musel změnit i use-case model, protože by do něj byl přidán další aktor. Pokud by navíc šlo o systém, který se používá u více zákazníků, tak je pravděpodobné, že administrátoři u těchto zákazníků si budou vytvářet vlastní role, u každého zákazníka jiné. To by v důsledku znamenalo, že pro každý systém u každého zákazníka by musel existovat zvláštní use-case model, protože by v něm byli jiní aktoři. Aktoři tedy odpovídají rolím pouze intuitivně, takže při vkládání výchozích rolí uživatelů v systému se lze podívat do use-case modelu a doplnit role podle aktorů v něm.
6.3
Analýza
35
• Formální popis diagramy, popř. matematickou notací. Je sice nejjednoznačnější, ale nebývá doporučován zejména kvůli tomu, že dokumentace use-casů by měla být čitelná i lidmi mimo vývoj systému (např. budoucími uživateli). Nicméně formalizace use-case modelu může být užitečná pro jeho verifikaci a odstranění formálních chyb.17 • Zadat podrobný a strukturovaný popis v CASE nástroji, pokud to umožňuje. Příkladem takového nástroje je např. Enterprise Architect. K případu užití v něm lze zadat název, popis, podmínky před spuštěním, po ukončení a za běhu obecně, atributy v sestavě18 , toky19 a další spoustu užitečných údajů. Výhodou je, že kompletní analýza je v CASE nástroji; naopak nevýhodou je již zmíněná nepřehlednost. Scénáře a jejich testování Už ve fázi analýzy je žádoucí vytvářet testovací případy, a to pro navržené scénáře práce se systémem. Nejprve bude tedy potřebné vysvětlit pojem scénář use-casu. Scénář případu užití je jednou jeho instancí; jde o jednu kompletní cestu skrz toky případu užití (Heumann, 2001). Zatímco use-case je tedy obecný předpis, jak může být systém používán, a jeho toky představují základní průběh práce a možné odbočky z něj (jak systém zareaguje na nějakou situaci, která se základnímu toku vymyká), scénář je jedno kompletní použití případu užití – např. že uživatel začne hlavním tokem, zadá něco špatně, systém zareaguje alternativním tokem, uživatel chybný údaj opraví, a buď pokračuje v hlavním toku, nebo se znovu dostane do alternativního toku (buď stejného, pokud znovu zadal údaj špatně, nebo do jiného), atd. Scénářů tedy může být větší množství – jedním z nich je průchod základním tokem a skončení běhu případu užití, zatímco jiné mohou projít v různém pořadí různými alternativními toky, tak jak to povoluje logika používání aplikace. Scénář je tedy jeden kompletní průchod případem užití, od jeho spuštění, až po skončení, ať už normální, nebo abnormální. Tento rozdíl bývá chybně interpretován i v odborné literatuře, která poměrně často nerozlišuje mezi toky use-casu a jeho scénáři.20 Proč se zde tolik zabývám scénáři a jejich odlišením od toků? Je nesporné, že pro další návrh a programování aplikace jsou zásadní toky, protože ty obsahují postup práce systému za různých podmínek. Scénáře jsou ale základním podkladem pro návrh testovacích případů k testování analytické funkčnosti (tj. že se systém chová tak, jako je v analytických dokumentech specifikováno). Toky samotné nelze testovat (s výjimkou základního toku), protože se nejedná o činnosti s definovaným počátkem, podmínkami za začátku, a koncem a podmínkám při ukončení – alternativní toky představují pouze výsek části průběhu use-casu, který je ošetřením nějaké nestandardní situace. 17
Formální chybou v use-case modelu je např. circular reference mezi use-casy vazbou include. Vztah include znamená bezpodmínečné volání druhého use-casu, a pokud by ten zase zpětně volal původní, tak práce systému nidky neskončí. 18 Možnost zadání atributů use-casu není v Enterprise Architectu dostupná z žádné nabídky, ale lze na ně přejít tak, že se označí daný use-case, a stiskne se klávesa F9. Nicméně ve srovnání s možnostmi dokumentu s formátováním nejde o příliš přehledné řešení, např. neexistuje jednoduchý způsob, jak vyjádřit, že jde o sestavu typu master-detail (např. objednávka a její položky) – v EA nelze rozumně odlišit, které údaje se zadávají k objednávce (datum) a které k položce (počet kusů) 19 Ve skutečnosti jde o scénáře, tento nedostatek EA bude vysvětlen v další části práce. 20 Tento problém je i v Enterprise Architectu, který v dialogu pro zadání podrobností use-casu obsahuje pouze kartu Scenarios, která je podle své struktury vhodná pro zápis toků událostí use-casů. Pak ale není kam psát scénáře use-casů.
36
6
TEORETICKÁ STUDIE
Scénáře jsou naopak kompletní činnosti, které mají definovaná data či jiné podmínky pro své spuštění, průběh práce se systémem (zejména akce uživatele), a výsledek, ke kterému má dojít. Pak není problém sestavit ke scénáři testovací případ, který je jen podrobným rozepsáním všech podmínek, akcí uživatele a reakcí systému vedoucích k definovanému výsledku. Více se lze o této problematice dozvědět ve vynikajícím článku Generating Test Cases From Use Cases (Heumann, 2001). Testovací případy jsou podkladem pro testování analytické funkčnosti, které je pak prováděno ve fázi implementace a před nasazením (kde o něm také bude v této práci blíže pojednáno). Konceptuální class model Dalším výstupem analytické fáze kromě use-case modelu je konceptuální model tříd. Narozdíl od implementačního class modelu, jehož tvorba je hlavní částí fáze návrhu, cílem konceptuálního class modelu je pouze zachycení vztahů mezi existujícími pojmy problémové domény. Je objektově orientovanou obdobou diagramu známého jako Conceptual Schema, což je konceptuální ERD. Pojmy problémové domény jsou spojené jednoduchými vztahy (asociace, agregace/kompozice a dědičnost). V systému budou zpravidla zavedeny jako třídy v daném programovacím jazyce.21 Class model jako takový bude popsán v sekci práce zabývající se návrhem aplikace, proto nyní nebudu vysvětlovat jednotlivé pojmy, jejich vysvětlení lze nalézt v této části, popř. v publikacích, které jsou uvedeny v seznamu použité literatury. Třídy není nutné podrobně specifikovat co do atributů, metod, konstruktorů a pokročilých prvků objektově orientovaného návrhu, jako jsou rozhraní nebo indexery (to není ani dost dobře možné, má-li být zachována zásada, že analytické modely jsou nezávislé na použité technologii/implementačním prostředí, protože každý programovací jazyk nabízí jinou množinu těchto prvků), stačí zaznačit význačné atributy/metody. Není ani vhodné přílišné použití návrhových vzorů a dalších postupů, které patří do fáze návrhu; zde jde pouze o modelování existujících objektů problémové domény. Smysl tohoto modelu již byl jednou zmíněn: jednoznačně objasnit vztahy mezi pojmy. Use-case model samotný toto nedokáže, protože se zabývá pouze chováním systému – způsoby použití systému uživatelem. Pojmy problémové domény, zařazované do tohoto modelu, lze nalézt zejména v dokumentaci k use-casům, kdy je použita metoda známá jako nouns extraction (podstatná jména použitá v use-casech představují poměrně často instance tříd). Dalším zdrojem může být model podnikových procesů (v něm se objevující objekty – vstupy a výstupy procesů – jsou zpravidla také instance tříd). Objekty těchto tříd lze pak použít v dalších analytických modelech (sekvenční model, model spolupráce apod.) 21
Druhou možností jsou tzv. Adaptivní objektové informační systémy. Jejich princip spočívá v tom, že na rozdíl od běžných systémů je možné objektový model dynamicky měnit. Hierarchie pojmů a vztahů mezi nimi totiž není zavedena jako třídy, ale je uložena v databázi, a uživatelé mají zpravidla i nějaký nástroj na jeho změny, což jim umožňuje neomezeně nastavit strukturu a chování systému (Yoder, Balaguer a Johnson, 2001).
6.3
Analýza
37
Sekvenční model Sekvenční model je prvním modelem formálně a podrobně popisujícím chování systému (use-case model nebývá považován za formální model, protože chování zachycuje pouze volně slovním popisem). Sekvenční model se snaží zachytit interakce mezi jenotlivými objekty, ve fázi analýzy pouze z problémové domény. Objekty mají totiž podle teoretického vymezení objektově orientovaného programování schopnost spolupracovat s jinými objekty pomocí posílání zpráv, které v běžných programovacích jazycích odpovídá volání metod. Sekvenční diagram pak zachycuje chování systému jako souslednost interakcí (volání metod) jednotlivých objektů. Jeden diagram v sekvenčního modelu zpravidla odpovídá jednomu toku use-casu. Z toho plyne, že jde o značně podrobný model, a proto se nedoporučuje tvořit ho pro celý systém (pro všechny toky všech use-casů), ale pouze pro ty případy, kde je běh systému složitější či zadaný textovým popisem méně zřejmý. Zápis průběhu činnosti sekvenčním diagramem (jako souslednost interakcí mezi objekty) je totiž naprosto jednoznačný (příklad základního sekvenčního diagramu je na obrázku 3). Na druhou stranu, ani sekvenční diagram nelze použít ve všech situacích, jeho zásadním omezením je, že z řídících struktur zobrazuje pouze sekvenci, ale nelze v něm rozumně zadat selekci ani iteraci. Pokud se tedy v toku objevují komplexní větvení nebo cykly, není použití sekvenčního diagramu účelné, v tom případě je vhodnější použít diagram aktivit.22
Obr. 3: Ukázka jednoduchého sekvenčního diagramu.
V sekvenčním diagramu vystupují primárně objekty, a ne třídy (může být pouze uvedeno, instancemi kterých tříd tyto objekty jsou). Může být tedy vytvořen dříve než konceptuální class model, nebo souběžně s ním. Po dotvoření class modelu pak zpravidla 22
V UML 2.0 byl přidán element Combined Fragment, který do jisté míry umožňuje zachytit i větvení, cykly a ošetření výjimek (Bell, 2004), lze ale říct, že vyjádření těchto řídících struktur stále není příliš intuitivní nebo jednoduché, zvláště ve srovnání s diagramem aktivit. I přes toto rozšíření tedy zůstává sekvenční diagram primárně určený pro zachycení složitějších, ale sekvenčních činností, a pro činnosti se složitějším postupem se příliš nedoporučuje používat.
38
6
TEORETICKÁ STUDIE
není problém doplnit do sekvenčního modelu třídy. Naopak sekvenční model lze využít pro doplnění/ověření class modelu. Předávání zpráv mezi objekty představuje volání jejich metod, resp. metod tříd. Sekvenční model tímto umožňuje identifikovat význačné metody tříd (právě ty, které by měly být zachyceny v konceptuálním class modelu). Předávání zpráv mezi procesy (tj. volání jejich metod) navíc ukazuje zodpovědnost objektů za jednotlivé činnosti – některé činnosti provádí objekt sám, zatímco pro provedení jiných zavolá metodu jiného objektu. Naopak nezobrazuje příliš dobře samotnou strukturu systému, tj. vazby mezi třídami. Ty jsou mnohem lépe viditelné z class modelu. Další analytické modely Ačkoliv hlavní náplní fáze analýzy je tvorba use-case modelu, na jehož zpracování kvalita budoucího systému stojí a padá, a základní naznačení struktury systému konceptuálním class modelem, lze v této fázi mimo tyto dva modely a sekvenční model využít i další modely. Stejně jako sekvenční model jsou tyto další spíše volitelné, a jejich smysl rozhodně není v tom, že musí být tvořeny pro všechny části systému – každý z nich je vhodné využít v určitých případech, a je ho vhodné proto v této situaci vytvořit pouze pro tu část systému, které se to týká. Vzhledem k rozsahu práce není možné u těchto pomocných modelů zacházet příliš do podrobností, co do jejich prvků a vazeb mezi nimi, koneckonců to vše lze nalézt v materiálech věnovaných standardu UML a softwarové analýze obecně, například v publikaci UML a unifikovaný proces vývoje aplikací (Arlow a Neustadt, 2007). Spíše se proto pokusím u jednotlivých modelů naznačit jejich význam a vhodné použití. • Model spolupráce (z anglického Collaboration model ) je další prostředek k vyjádření kompetencí objektů tříd, co do vyjádření struktury interakcí přehlednější než sekvenční diagram. Na rozdíl od sekvenčního modelu zde ale chybí časový rozměr těchto interakcí, tj. ukazuje pouze, které objekty volají metody jiných, ale ne souslednost těchto volání23 . Je vzájemně převoditelný se sekvenčním modelem, a proto zpravidla nebývá příliš často používán, zejména pokud je již zaveden sekvenční model. • Statový model (anglicky Statechart) je doplňkovým modelem sloužícím k vyjádření možných stavů objektů a aktivit, které k dosažení těchto stavů vedou. Není povinným diagramem, a jeho hlavní smysl je podchytit možné přechody mezi jednotlivými stavy objektů, tam kde je výčet možných stavů objektu rozsáhlejší a je zájem tyto možné změny stavů sledovat. Přechody mezi stavy objektu se dějí za pomoci činností (aktivit) objektů (ty zde nejsou podrobněji sledovány, k jejich zachycení slouží Activity model ). Popisuje se také událost, která změnu stavu vyvolává, a další podmínky, při jejichž splnění dojde k vyvolání aktivity a následné změně stavu; stavový model je tedy plně deterministický. • Model aktivit (anglicky Activity model ) je inverzí stavového modelu. Zatímco ve stavovém modelu byla pozornost zaměřená na stavy objektů, a aktivity byly pouze brány jako prostředek pro změnu stavu, zde jsou naopak modelovány tyto aktivity. Model aktivit je jedním z nejúplnějších modelů chování systému, zachycuje všechny řídící 23 V některých zdrojích lze nalézt variantu, že pořadí předávání zpráv mezi objekty (tj. volání metod) je znázorněno tak, že zprávy jsou podle tohoto pořadí očíslovány. I tak je ale toto znázornění značně nepřehledné, a stejně jako v sekvenčním modelu přetrvává nemožnost znázornit jiné řídící struktury než sekvenci.
6.4
Návrh
39
struktury (sekvence, větvení i cykly), a může se vhodně použít pro vyjádření průběhu určité činnosti (např. toku use-casu) v situaci, kdy ještě nejsou vyřešené objekty a jejich kompetence (aktivity se v tomto diagramu uvádějí bez objektů, kterým patří), ale je již zřejmý průběh činnosti. Syntakticky je tento model totožný s modelem podnikových procesů, obrovský významový rozdíl je ale v tom, že jde o model tvořeného informačního systému, a proto modeluje pouze jeho aktivity (tj. aktivity probíhající v systému při jeho používání uživateli), zatímco procesní model zachycuje reálné aktivity v podniku.
6.4
Návrh
Fáze návrhu (anglicky Design) navazuje na výsledky analýzy, zejména na use-case model, v kterém je obsažený kompletní popis funkčnosti systému. Use-case model, obsahující případy užití a jejich toky, které zpravidla prošly interní a externí revizí a v této fázi jsou již odsouhlasené zákazníkem i vedením vývoje, představují v podstatě závazný dokument, na základě kterého budou probíhat veškeré další práce; tím se myslí to, že designer a poté i programátoři již sami nemohou měnit specifikované chování aplikace (pouze iniciovat změnu use-casu, který by pak musel být znovu schválen zákazníkem i vedením vývoje). Návrh realizace systému již bere v potaz konkrétní implementační prostředí, a cílem této fáze je vytvořit přesnou specifikaci tříd a jejich metod tak, aby podle ní mohl být tvořen zdrojový kód. Vrstvená architektura Jednou ze základních úloh ve fázi návrhu je stanovení architektury aplikace. Pro podnikové informační systémy a podobné komerční aplikace se v současné době nejčastěji používá vrstvená architektura, a to zejména vertikálně vrstvená. Vertikálně vrstvená architektura je návrh, u kterého jsou operace a funkce jedné vrstvy vystavěny nad operacemi a funkcemi vrstvy nižší. V průběhu historického vývoje se postupně rozvíjí vertikální rozvrstvení systémů. Nejjednodušším a nejstarším případem je jednovrstvá architektura, kdy všechny operace řeší monolitický systém. Později vznikl model dvouvrstvé architektury, kdy došlo k oddělení logiky uložení dat (databázová vrstva) od aplikační a prezentační vrstvy (Dvořák, 2006). V současné době nejpoužívanějším modelem je třívrstvá architektura, a bude proto dále uvažována i v této práci. Zde se informační systém skládá ze tří na sobě ležících vrstev (zde popsaných od nejnižší po nejvyšší). 1. Databázová vrstva obsahuje nástroje a rutiny pro obsluhu přístupu k datům, kontroluje jejich integritu a provádí jejich předzpracování. Zpravidla obsahuje systém pro řízení báze dat, a také aplikační rutiny pro ukládání/získávání objektů z báze dat, obsluhu transakcí a další součinnost s DBMS systémem, o nichž budu v dalším textu mluvit jako o DB vrsvě aplikace. 2. Aplikační vrstva tvoří samotné jádro aplikace, podle požadavků uživatele provádí veškeré transformace vstupních dat na výstupní. Obsahuje tedy veškerou logiku zpracování a uchování dat, proto bývá někdy nazývána vrstva business logiky (dále BL). V podstatě veškeré výsledky analýzy (use-casy i konceptuální class model) se promítnou právě do této vrstvy.
40
6
TEORETICKÁ STUDIE
3. Prezentační vrstva, někdy také nazývaná vrstva uživatelského rozhraní (dále UI ). Jejím smyslem je komunikace s uživatelem – příjem jeho vstupů a prezentace výstupů systému, v dnešní době obvykle na grafické úrovni (GUI).24 Podstatné je, že vyšší vrstva vidí a aktivně volá a používá jen bezprostředně nižší vrstvu, tj. ne žádnou dále nižší, a také nepoužívá žádnou vyšší, a to ani vrstvu bezprostředně nad ní. Pro nižší vrstvu představuje nad ní ležící vrstva pouze anonymního klienta, jehož metody přímo nevolá, a jediný způsob, jak mu předává data, je v návratových hodnotách svých subrutin. Iniciovat nějaké akce ve vyšší vrstvě může pouze tak, že vyvolá událost a v parametrech této události předá potřebná data (tuto událost si předtím musí nějaký objekt vyšší vrstvy zaregistrovat), popř. také tím, že při provádění některé své funkce vyhodí výjimku. Důvodem pro toto omezení je to, že vyšší vrstva musí logicky referencovat („vidětÿ) nižší vrstvu, aby mohla používat její třídy a jejich metody. Pokud by i nižší vrstva měla volat metody vyšší, musela by referencovat vyšší vrstvu. Tím by vznikl klasický problém s circular reference, a tyto dvě vrstvy by nešlo od sebe oddělit, a fungovaly by v podstatě jako jedna vrstva. Právě oddělitelnost a nahraditelnost jednotlivých vrstev je přitom hlavním smyslem vrstvení aplikace, a to zejména z těchto dvou důvodů: • Nahraditelnost jednotlivých vrstev – je možné bez problémů nahradit jednu implementaci vrstvy za jinou. Např. pokud se napíše UI vrstva jako formulářová aplikace pro Windows a je požadavek na webový front-end (internetový systém pro vkládání objednávek), pak oba dva mohou používat stejnou BL vrstvu (a tím i ostatní nižší vrstvy) a stačí pouze napsat prezentační logiku v ASP. Nebo lze za použití abstraktní DB vrstvy s interfacy dosáhnout nahraditelnost DB vrstvy, tak že výsledný systém může fungovat podle potřeby nad různými databázovými systémy. • Spravovatelnost aplikace – když se cokoliv změní v některé z vrstev, je nutné projít a opravit pouze tuto vrstvu aplikace a vrstvu ležící bezprostředně nad ní, ale je zajištěné, že žádné jiné vrstvy ne. Toto je velmi výhodné vzhledem k tomu, že nejčastěji se mění právě vrstva uživatelského rozhraní, zatímco DB vrstva aplikace zůstává prakticky neměnná (nepočítaje možné opravy v tělech jednotlivých metod, což ale zpravidla nevynucuje opravy ve vyšších vrstvách) Implementační class model Hlavním modelem fáze návrhu je implementační model tříd, který navazuje na konceptuální model tříd vytvořený v analýze, a rozšiřuje ho a rozvádí do podoby konkrétní implementace ve vybraném programovacím jazyce/vybrané technologii. Obecně se model tříd tvoří zpravidla pouze pro vrstvu business logiky, které je základní funkční částí systému. UI vrstva je specifikována návrhy formulářů uživatelského rozhraní, její modelování class diagramem nemá smysl, protože její tvorba spočívá v umisťování již připravených komponent – tříd – na formuláře. DB vrstva většinou neobsahuje složitější hierarchii tříd, ale pouze základní třídu představující databázové spojení a několik helper tříd pro pomocné operace. Základním elementem modelu tříd jsou třídy. Podle teorie objektově orientovaného programování třída určuje vlastnosti a chování svých instancí v systému. U tříd samot24 Pokud je použit návrhový vzor Model-View-Presenter, přibude další kvazi-vrstva mezi aplikační a prezentační vrstvu, aspekty tohoto řešení budou uvedeny dále v této sekci.
6.4
Návrh
41
ných se rozlišují jisté charakteristiky: třídy mohou být perzistentní (ukládané do nějakého datového úložiště, nejčastěji databáze) nebo transientní (dočasné); abstraktní třídy jsou takové, od kterých nemohou být přímo vytvořeny instance; třída může být také označena za generickou, tyto třídy shrnují funkčnost, která není specifická pro konkrétní datový typ25 . Lze sledovat další spoustu vlastností tříd, různé podle použitého programovacího jazyka (každý jazyk umožňuje u tříd a jejich operací zadávat jiné charaketristické vlastnosti). Kromě tříd se v class modelu mohou objevovat další elementy, v závislosti na použitém programovacím jazyce. Může jít např. o struktury, enumerace (výčtové typy), interfacy apod. Ukázka jednoduchého diagramu tříd je na obrázku č. 4.
Obr. 4: Ukázka jednoduchého diagramu tříd. K objednávce se zadává zákazník, a kromě toho také objednávka obsahuje seznam řádků (alespoň jeden), z nichž každý znamená objednání určitého množství určitého zboží.
Jednotlivé elementy modelu tříd mohou být spojeny různými vazbami, u některých lze určovat směr či násobnost. Jednou ze základních vazeb mezi třídami je běžná asociace.26 Představuje situaci, když si objekt třídy drží odkaz na jiný objekt, bez nějakého speciálního významu. Typickým příkladem asociace je výběr z číselníku, např. objednávka si drží odkaz na obchodního partnera – zákazníka, který si zboží objednal. Zvláštním případem asociace je asociační třída. Používá se tehdy, pokud je třeba ke vztahu mezi dvěma třídami udat další informace, často v případě vazeb mezi třídami s násobností M : N 27 nebo u asociací mezi více než dvěma instancemi. Pojmově odpovídá spojovací tabulce používané v ERD, tj. každá instance asociativní třídy si drží odkaz na jednu instanci každé třídy zapojené v asociaci. Asociační třída není povinný element, v tom smyslu, že dost často v modelu není označena jako asociativní třída s odpovídající syntaxí, ale místo toho zakreslí návrhář obyčejnou třídu, držící si příslušné běžné asociace na ostatní třídy. (Obě dvě možnosti znázornění jsou uvedeny na obrázku 5. Obě jsou 25
Generické programování je paradigma, které umožňuje další úroveň re-use zdrojového kódu, a to na úrovni algoritmické abstrakce (Musser a Stepanov, 1989). Využívá se u algoritmů/tříd, které nejsou závislé na použitém konkrétním datovém typu, typické využití je např. pro type-safe kontejnerové třídy, jako jsou lineární seznamy, zásobníky a stromy, kde struktury a použité algoritmy jsou shodné pro obsluhu kontejnerů všech typů objektů; další možností jsou různé iterátory a obecné třídící a vyhledávací algoritmy. První všeobecně používaná implementace generického programování jsou šablony a na nich vytvořená Standard Template Library v programovacím jazyce C++ (Stepanov a Lee, 1995). Dnes je generické programování zapracováno v mnoha programovacích jazycích, kromě C++ je nejznámější Java a C#. Více o generickém programování, a zejména o jeho implementaci v těchto třech programovacích jazycích lze nalézt v článku Generické programování v C++, Javě a C# (Virius, 2005) 26 Nepoužívám zde pojem asociace, protože asociace je obecnější vazba, a kromě běžné asociace je jako speciální případ asociace chápána i agregace a kompozice (Kraval, 2001). 27 Je třeba si uvědomit, že v samotném objektovém návrhu a programování, na rozdíl od ERD, je vazba M : N bez problémů realizovatelná. Problém ale může nastávat jednak, pokud má mít aplikace jako úložiště dat relační databázový systém, a také v situaci, kdy je potřeba evidovat k vazbě další informace nebo s ní provádět složitější operace a výběry.
42
6
TEORETICKÁ STUDIE
správné, tj. ve výsledném kódu i jinde budou obě realizovány stejně; varianta se syntaxí asociativní třídy je pouze přehlednější.)
Obr. 5: Dvě možnosti znázornění asociativní třídy: vlevo správná syntaxe podle UML – použití elementu Association class; vpravo intuitivní znázornění běžnými asociacemi. Obě řešení jsou správné a použitelné, a vedou na stejný kód třídy Employment.
Silnějšími vazbami mezi třídami jsou agregace a kompozice. Představují vztah master-detail, rozdíl mezi nimi je v tom, že u agregace může být daný prvek částí několika jiných prvků, zatímco u kompozice patří výhradně jedné instanci, která ho celkově ovládá (se smazáním masteru se smaže i detail). Agregace se vyskytuje hlavně v konceptuálním class modelu, v implementačním se již příliš nedoporučuje používat, protože vede na vazbu s násobností M : N (jeden celek má pochopitelně několik částí, a z definice agregace může jedna část náležet více prvkům), kterou je vhodnější rozepsat na spojení asociativní třídou. Naproti tomu kompozice je běžný vztah, odpovídá variantě, kdy master si drži kolekci prvků a každý prvek zpětný odkaz na master. Dalším typem vazby mezi třídami kromě asociace je gen-spec, které bývá v class modelu označována jako dědičnost. Vyjadřuje vztah, že určitá třída je specializací jiné, která je zase jejím zobecněním. Pomocí dědičnosti lze vytvářet komplexní hierarchie, je to např. obvyklé u ovládacích prvků uživatelského rozhraní, jako třeba ovládací prvky v MS .NET v namespace System.Windows.Forms, kde obyčejné textové pole (TextBox) je až na šesté úrovni hierarchie dědičnosti. Některé programovací jazyky (C++) podporují i vícenásobnou dědičnost, nicméně tento koncept se dnes považuje za problematický, (jedním ze známých problémů je tzv. Diamond Problem, viz obrázek č. 6), takže moderní objektově orientované jazyky (C#, Java) podporují pouze jednoduchou dědičnost. Prostředkem k emulování vícenásobné „dědičnostiÿ v těchto jazycích jsou potom rozhraní (interface). Jde o předpis metod a dalších veřejně viditelných členů, které musí implementovat každá třída, která chce rozhraní používat. V C# i v Javě může pak tedy třída mít jenom jednoho předka, ale může implementovat obecně libovolný počet interfaců. Vztah, že třída implementuje interface, se v class modelu znázorní pomocí vazby realize, která je sémantickou obdobou dědičnosti mezi třídami. Rozhraní samotná mohou také tvořit hierarchii generalizace/specializace, mezi nimi se použije vztah dědičnosti stejně jako mezi třídami. V současné době se ale složité vztahy dědičnosti mezi třídami příliš nedoporučují používat. Dědičnost je totiž statickým vztahem definovaným programátorem (resp. návrhářem aplikace), a je rigidní vzhledem ke změnám na objektech v hierarchii, navíc je značně obtížné navrhnout bázovou třídu tak, aby všechny její operace dávaly smysl pro všechny
6.4
Návrh
43
Obr. 6: Diamond Problem, nerozhodnutelná situace při použití vícenásobné dědičnosti. Máme-li objekt třídy Class4, a zavoláme nad ním metodu DoWork() (kterou sám neimplementuje), zavolá se implementace třídy Class2 nebo Class3? Různé programovací jazyky toto řeší různě, více o tomto problému se lze dočíst např. na Wikipedii.
možné typy jejích potomků. Proto se dnes doporučuje na vhodných místech použít spíše asociaci/kompozici.28 Návrh business tříd Stejně jako use-casy v analýze, i třídy a další elementy class modelu (struktury, rozhraní) mají svůj obsah. Obsahem tříd je v nejobecnějším smyslu jejich struktura a chování (resp. struktura a chování jejich instancí), přeloženo do terminologie objektově orientovaného programování, jde o atributy třídy a metody. Různé programovací jazyky umožňují třídám zadat další obsah, jako třeba vlastnosti, události a indexery v C#. Právě zejména specifikace obsahu jednotlivých tříd je úlohou designera (vztahy mezi jednotlivými třídami na hrubé úrovni už většinou odhalí analytik v rámci konceptuálního class modelu). Z hlediska funkčnosti aplikace mají zásadní roli perzistentní třídy vrstvy business logiky aplikace, někdy bývají nazývány business třídy. Tvoří hlavní strukturu evidovaných 28 Dědičnost bývá zdůrazňována i v mnoha publikacích pro začátečníky v objektově orientovaném programování. Jedním ze zmiňovaných příkladů jsou zaměstnanci – zaměstnanec může být buď placený od hodiny (dohoda o provedení práce) nebo měsíčně (podle pracovní smlouvy). Situace se jeví jako typický příklad použití dědičnosti, kde je bázová třída Zaměstnanec a její potomci jsou zaměstnanci s určitým způsobem odměňování. K zásadnímu problému ale dojde v okamžiku, kdy je potřeba změnit způsob odměňování daného zaměstnance (např. z hodinové mzdy na měsíční). V případě použití dědičnosti totiž sice lze vymazat zaměstnance jako celek, ale těžko lze změnit jeho typ. Ve skutečnosti jde o typický příklad nevhodného použití dědičnosti. Správný návrh je zde pomocí vztahu Party-Role: zaměstnanec má plat (kompozice s ordinalitou 1 : 1), který může být od hodiny, nebo měsíční. Mezi nimi je pak již použití dědičnosti vhodné, protože jak měsíční plat, tak i plat od hodiny jsou specializace obecného platu. Na rozdíl od předchozího řešení dědičností zaměstnanců není problémem změnit zaměstnanci plat z hodinového na měsíční, dojde pouze ke změně odkazovaného (resp. vlastněného) objektu (Corfield, 2004).
44
6
TEORETICKÁ STUDIE
údajů v systému, a jsou na ně také kladeny větší požadavky, např. schopnost perzistence (uchování svých dat v určité datové struktuře i po skončení práce systému), což se odrazí v jejich struktuře a chování. U všech položek tříd (datových polí, metod i dalších konstruktů) se zadávají specifikátory přístupu (nejčastěji public, protected a private), které určují, jestli je daný prvek dosažitelný i zvenčí třídy. Obecně (nejen u business tříd) se doporučuje, aby všechny fieldy29 byly označeny jako privátní, tj. že k nim nepůjde přistupovat odjinud než zevnitř z třídy. Souvisí to s jednou ze základních vlastností objektově orientovaného programování, kterou je to zapouzdření (encapsulation). Principem je to, že nelze zvenčí manipulovat s daty objektu (a tím nekontrolovaně měnit jeho vnitřní stav), pouze lze zavolat některou z jeho metod, která změnu stavu zapříčiní, někdy bývá tento princip nazýván konzistence vnitřních stavů objektu. Objekty tvoří rozsáhlé vzájemně propojené struktury. Někdy ale nebývá zdůrazňováno, že není vhodné přistupovat k zanořeným podobjektům přímo, a to ze dvou důvodů: • První z nich je spíše teoretický. Pokud se objekt skládá z vnořených podobjektů (navázaných pomocí kompozice), tak jeho tranizitivní stav je souhrn stavu jeho všech položek, a tedy i stavů jeho podobjektů. Změnou stavu vnořeného podobjektu se tedy přímo změní i stav hlavního objektu, aniž by mu byla předána zpráva (zavolána jeho odpovídající metoda).30 . • Praktický důvod se týká udržovatelnosti, tento princip je známý jako Law of Demeter.31 29
Zde dochází bohužel k nejednoznačnosti terminologie. Podle českého názvosloví obsahují třídy atributy a metody, atributy jsou jejich datové složky (struktura) a metody určují chování. Nicméně v prostředí Microsoft .NET lze k třídám a jejich obsahu zadávat popisné metainformace, jako např. že třída/operace je zastaralá ([Obsolete]) nebo že daný statický člen třídy je sdílený pouze v rámci jednoho vlákna ([ThreadStatic]). Anglická terminologie .NET tyto popisné údaje označuje jako attributes (nezbývá než česky přeložit jako atributy), zatímco datové složky tříd, které jsou podle české terminologie uváděny jako atributy, označuje jako fields (česky by se dalo přeložit jako pole, ale většinou se tento pojem v literatuře nepřekládá). Jako příklad lze uvést tuto deklaraci třídy: [Serializable] // atribut (informace, ze tridu lze serializovat) public class Osoba { private string jmeno; // field (datova polozka tridy) ... } Vzhledem k tomu, že v této práci potřebuji mluvit jak o datových složkách tříd (objektů), tak i o těchto metainformacím, musím se přidržet terminologie používané firmou Microsoft a označovat popisné metainformace tříd a jejich položek jako atributy a datové položky tříd jako fieldy, ač to na první pohled může působit nejasně. Proto se také budu ve zbytku práce, který je častěji svázán s implementací, snažit vyhnout odkazování na datové položky tříd jako na atributy. 30 Tento tranzitivní stav není tradičními technikami založenými na viditelnosti proměnných chráněn, lze totiž získat odkaz na instanci vnořeného podobjektu (tzv. alias) a pracovat s ním (volat jeho operace), nedbaje na to, že je součástí jiného objektu a tudíž jeho změnami se mění i stav jeho vlastníka (Theisen, 2000) 31 Princip zákona spočívá v tom, že je možné přistupovat k přímo drženým objektům a volat jejich metody, ale již ne „sáhnoutÿ přes ně na jejich podobjekty a přistupovat k nim (Lieberherr, Holland a Riel, 1988). V class modelu to znamená, že navržené metody nesmí pracovat s jinými objekty než těmi, na které si daná třída drží přímý odkaz, ve zdrojovém kódu, že ve výrazu nesmí být dvě tečky za sebou, resp. v C++ dva šipkové operátory (pokud se používá odkaz this, tak tři).
6.4
Návrh
45
Pokud je tedy potřeba přistupovat k hlouběji zanořeným objektům, je potřeba zavolat metodu přímo drženému objektu, který teprve sám zavolá danou metodu cílového. Nevýhodou této delegace je to, že pro 100% dodržení tohoto principu je nutné vytvářet velké množství jednoduchých wrapper metod, které pouze předají přijatou zprávu dalšímu objektu v hierarchii (resp. vyvolají jeho metodu). Proto se dnes jedná spíše o doporučení, jak postupovat v případech složité struktury vnořených podobjektů. Jak již bylo výše uvedeno, na business třídy jsou kladeny nároky z toho ohledu, že musí zajišťovat svoji perzistenci, tj. ukládání a získávání svých instancí z datového úložiště. Bez toho, abych zde popisoval jednotlivé optimalizační techniky objektově-relačního mapování (o kterých bude pojednáno v příslušné sekci této práce), lze říct, že použití metod a technik pro zajištění perzistence je mezi různými business třídami obdobné a zobecnitelné. Proto lze vhodným návrhem zajistit re-use této funkčnosti. Často používaným řešením je návrhový vzor Layer Supertype, který spočívá v odvozování všech business tříd od společného předka (nazvěme ho BusinessObjectBase). Tato společná bázová třída pak obsahuje společné funkcionality business tříd, příklad takového předka uvádí na svém blogu René Stein (Stein, 2008). Podobně je vhodné zavést i bázovou třídu pro kolekci business objektů, pokud možno generickou (BusinessCollectionBase
). Za pomoci těchto dvou bázových tříd lze v podstatě zobecnit veškerou funkcionalitu business tříd týkající se jejich perzistence, takže odvozené business třídy již nemusí řešit většinu těchto problémů samostatně. Návrhové vzory Návrhové vzory jsou obecně znovupoužitelná řešení běžných situací při návrhu softwaru. Pomáhají urychlit vývoj tím, že nabízí ověřená a dobře zdokumentovaná řešení, která lze zapojit do návrhu systému. Nejde tedy o komponenty, ale pouze o schématická řešení, která je v každém konkrétním případě třeba naimplementovat do dané situace. Obvykle představují vztahy mezi rozhraními a třídami, vyjádřené v class modelu. Jednotlivé elementy jsou pojaty pouze jako role, a při použití jsou do nich dosazeny konkrétní třídy, kterých se problém týká (jedná se o podobnou abstrakci, jako např. matematické vzorce). Jako příklad zde představím návrhový vzor Decorator. Jeho motivací je umožnění rozšiřování funkcionality třídy za běhu, jde o alternativu k používání dědičnosti. Využití je vhodné v těch případech, kdy může dojít k obecnému rozšiřování instancí třídy, přičemž všechny možnosti nelze definovat do překladu (nebo to není účelné). Koncept je znázorněn na class diagramu na obrázku 7. V tomto návrhovém vzoru jsou použity následující prvky: • Component – abstraktní třída nebo rozhraní společné pro všechny objekty, které mohou mít svoje data nebo chování dynamicky rozšiřitelné. • ConcreteComponent – třída reálného světa (může jich být i více), ke které budou přidávány další funkcionality. Formálně, metoda M objektu O může volat metody (předávat zprávy) jen těchto objektů: samotného objektu O (reprezentovaného ukazatelem this), objektů, které jsou jeho přímými součástmi (jeho fieldy), parametrů metody M a lokálních objektů vytvořených v kontextu metody M . Smyslem pravidla je to, že čím méně se v tělech jednotlivých metod objektu předpokládá o struktuře a chování jiných objektů (a vůbec o jejich existenci), tím snažší je pak změnit strukturu těchto objektů, protože pak nevyvolává nutnost změn mnoha jiných metod objektů, které s ním nemají přímou vazbu. Tím pak změna v jedné části systému nezpůsobí neočekávané problémy jinde skrz celý systém.
46
6
TEORETICKÁ STUDIE
Obr. 7: Schéma návrhového vzoru Decorator. V tomto příkladu jsou použité abstraktní třídy, prvek Component může být realizován i jako rozhraní (popř. i prvek Decorator).
• Decorator – abstraktní třída, společná pro všechny třídy s přídavnou funkcionalitou. Podstatný je odkaz na původní objekt, který je tímto Decoratorem (resp. jeho potomkem) rozšířen. Přitom navenek se Decorator projevuje stejně jako původní rozšiřovaný objekt a je za něj nahraditelný, to je zajištěno tím, že mají společného předka v hierarchii dědičnosti (resp. implementují společné rozhraní). Rozšiřovaný objekt je Decoratoru předán v jeho konstruktoru Decorator(Component comp). • FirstConcreteDecorator a SecondConcreteDecorator jsou konkrétní třídy s rozšířenou funkčností, implementují stejné metody, jako má základní komponenta, tím, že v tělech svých metod zpravidla volají dané metody této základní komponenty, ale mohou k nim přidávat vlastní funkčnost. Příklad z reálného světa může být agenda osobních údajů učitelů na VŠ. Každý učitel má základní osobní údaje, u některých se navíc evidují publikace, vyučované předměty, členství v orgánech, stáže a spousta dalších volitelných údajů. Třída Ucitel bude pak hrát roli konkrétní komponenty, tj. třídy, jejíž funkcionalita (resp. funkcionalita jejích instancí) bude dynamicky rozšiřována. Jednotlivé konkrétní Decoratory mohou být např. PublikaceUcitele, StazeUcitele apod. Přiklad chování, které se bude dynamicky měnit a rozšiřovat v závislosti na tom, které údaje jsou k učiteli zadány, může být vrácení textového popisu obsahujícího tyto všechny údaje (metoda string GetText()). Ukázkový zdrojový kód v C# lze nalézt v příloze D. Výhodou je to, že decoratory je možné skládat, tj. StazeDecorator je možné rozšířit dalším typem Decoratoru. Drobný problém by působilo to, že pak by se údaje o uživateli vypisovaly v nahodilém pořadí (resp. v pořadí podle toho, jak byly k instanci třídy Ucitel decoratory přidávány). Šlo by ho ale vyřešit např. tak, že metoda GetText() by nevracela řetězec, ale kolekci záznamů (např. Dictionary, číselná hodnota by představovala pořadí), a existovala by metoda (mohla by patřit třídě Component), která by z této kolekce vrátila příslušný řetězec.
6.4
Návrh
47
Návrhových vzorů existuje větší množství, člení se do několika skupin (vzory struktury, chování, tvorby objektů a další), zatímco některé se využijí v téměř každé aplikaci (např. Singleton), jiné jsou poměrně vzácné a použitelné na specifické situace (Muší váha). Dá se říct, že stále přibývají další vzory. Samozřejmě, cílem schopného designera není použít některý návrhový vzor v každé situaci, kdy je to jen trochu možné, a ohýbat kvůli tomu zbytek aplikace. Stejně jako u ostatních nástrojů pro tvorbu softwaru jde spíše o to, použít je ve vhodných případech, protože lze pomocí nich ušetřit značné množství práce. Další modely fáze návrhu Ve fázi návrhu se kromě class modelu využijí i jiné modely, zpravidla jako podpůrné nástroje pro specifikaci architektury systému. Jednak se používají analytické modely chování systému, v podrobnější formě. Jde o sekvenční model, model spolupráce, stavový model a model aktivit. Ve fázi designu jsou využitelné zejména k podrobné specifikaci chování jednotlivých tříd a jejich metod. Zde už jsou interakce mezi objekty – předávané zprávy – detailně navržené, takže jde spíše o ověření konzistence návrhu tříd s analytickým modelem. Druhým nejvýznamnějším modelem fáze návrhu po class modelu je Model komponent (z anglického Component Model ). Slouží ke znázornění vztahu mezi komponentami systému. Podle definice je komponenta uzavřená znovupoužitelná část systému, pomocí které se provádí fyzické členění systému (Kraval, 2001). Z technologického hlediska se zpravidla jedná o modul/knihovnu, např. COM komponentu, .NET assembly nebo Java Package (tj. JAR archív). Cílem zavádění rozdělení systému na komponenty je zvýšení přehlednosti a spravovatelnosti systému. Při návrhu komponent se vychází z class modelu systému. Třídy samotné v class modelu lze totiž sdružovat do balíků (element Package), které představují první návrh komponent (během návrhu může např. dojít k tomu, že se několik balíků sloučí a utvoří jednu komponentu, ale není to možné naopak, tedy obecně je package nejmenší nerozdělitelný prvek granulárního systému). Model komponent je syntakticky poměrně jednoduchý, jediným typem elementů jsou komponenty, z nichž některé jsou spojené vazbou dependency (ukazuje, která komponenta je závislá na jakých jiných). Rozsáhlejší systém se zpravidla člení na komponenty ve dvou rozměrech. Prvním z nich je struktura systému jako taková: obvykle existuje společné jádro, které obsahuje základní třídy a číselníky, další částí je ekonomika, kde lze zase rozlišit jádro ekonomického subsystému (společné třídy pro doklady, účetní období apod.), moduly Banka, Pokladna, Účetnictví, Správa DHM apod. Jde tedy o rozčlenění systému podle funkčnosti. Druhým rozměrem jsou vrstvy vrstvené archtektury. Zpravidla jak jádro, tak Banka, tak i Evidence DHM, i všechny další funkční moduly budou mít UI vrstvu a BL vrstvu, a pokud není centrálně vyřešená perzistence objektů, tak i DB vrstvu. Jak tedy samotná syntaxe modelu komponent je do značné míry jednoduchá, optimální návrh částí systému, tak aby se vyhnulo circular reference, je značně obtížná úloha. Jedním z postupů, jak toto rozdělení umožnit, je návrhový vzor Bridge. Pokud dojde k situaci, že jedna assembly potřebuje referencovat druhou, a druhá zase první, lze pomocí něj problém vyřešit tak, že do první assembly se dá interface, který druhá třída v druhé assembly implementuje. Druhá assembly pak může referencovat první, a první ji referencovat nepotřebuje, protože třída v druhé assembly je „schovanáÿ za dostupným
48
6
TEORETICKÁ STUDIE
interfacem. Příklad na kruhově propojené assemblies Config a Logging je na obrázku 8, řešení pomocí návrhového vzoru Bridge na obrázku 9.
Obr. 8: Mějme třídy Log a Config. Řekněme, že třída Log čte nastavení logování z konfigurace, proto musí „vidětÿ (mít odkaz) na třídu Config. Ale i naopak, pokud má být změna konfigurace zalogována, musí třída Config odkazovat na Log, aby mohla zavolat metodu pro zápis do logu. Třídy tedy odkazují na sebe navzájem, a pokud má být každá v jiné komponentě, pak i mezi kompnentami bude circular reference. Horní část představuje vzájemně závislé třídy, spodní kruhově závislé komponenty, svislá čára neúspěšný pokus o jejich oddělení.
Obr. 9: Pokud je vytvořen interface k jedné ze zúčastněných tříd (zde je to třída Log), je možné všechny závislosti vést jedním směrem. Pak i komponenty bude možné po svislé čáře oddělit, a assembly Logging bude referencovat assembly Configuration.
Posledním modelem UML použitelným ve fázi návrhu systému je model nasazení (Deployment Model ). Souvisí zejména s technologickou architekturou, zaměřuje se na jednotlivé hardwarové prvky (servery, osobní počítače), zejména na jejich typy, počty a vzájemné vztahy. Vzhledem k tomu, že hardwarová architektura systému je mimo hlavní zaměření mé práce, nebudu zde deployment model podrobněji popisovat.
6.4
Návrh
49
Specifikace testů Práce designera nekončí s navržením struktury systému, tj. jeho modelu tříd. Dalším výstupem fáze designu jsou předpisy pro testování. Aniž bych zde podrobněji rozebíral typy testů a jejich charakteristické vlastnosti (budou uvedeny dále v této práci v sekci Implementace), lze říct, že designer má vedle analytika hlavní zodpovědnost za plánování testování tvořeného systému. Vzhledem k tomu, že designer navrhuje detailní strukturu aplikace jako souhrn jednotlivých tříd a chování aplikace jako specifikaci funkcionality metod těchto tříd, je jeho zaměřením White Box Testing.32 Prvním typem testů, pro které designer tvoří specifikace, jsou testovací případy vnitřní funkčnosti, zpravidla realizované jednotkovými testy. Jde o ověření metod tříd (resp. dalších bloků kódu, jako např. konstruktorů, properties, indexerů apod.), zda pro všechny možné kombinace vstupů dávají požadované výstupy – tj. pro korektní vstupní hodnoty správné výstupy a pro chybné vstupy vyhodí správnou výjimku, popř. chybu ošetří jinak. Je třeba uvést, že designer zpravidla nepíše těla jednotkových testů v testovacím nástroji (např. NUnit), ale pouze specifikaci; testy samotné píše tester ve fázi implementace (doporučuje se před samotným aplikačním kódem). Druhou formou testování, které má na starosti designer, jsou testy technologie (anglický pojem je Performance Testing). Jde zejména o testování odezvy aplikace při kritických bodech systému, naplnění tabulek reálným množstvím dat a další podobné kvantifikovatelné charakteristiky, vesměs výkonového charakteru. Návrhový vzor Model-View-Presenter a re-use prezentační logiky Hlavním tématem, o kterém chci v této části práce pojednat, je návrhový vzor Model-View-Presenter. Jeho základním cílem je uvolnění vazby mezi UI a BL vrstvami aplikace, přitom při zachování možností jak volat z UI metody BL vrstvy (což je běžné a požadované), tak i z BL vrstvy volat metody UI. Řeší tedy obrovský nedostatek vrstvené architektury, a to, že v ní není možné přímo volat vyšší vrstvu z nižší vrstvy. Základem jeho práce je využití návrhového vzoru Bridge pro odstínění vazby mezi rozhraním komponent UI vrstvy a jejich implementací, schéma řešení je na obrázku 10. Jednotlivé elementy tohoto návrhového vzoru jsou tyto: • Model – jde o objekt/část objektu BL vrstvy, který obsahuje business kód. Stejně jako v běžné třívrstvé aplikaci, na požádání (zavolání jeho metody) provede nějakou akci a vrátí výsledky. • Presenter – stěžejní prvek návrhového vzoru, zajišťuje prezentační logiku, a přitom je obsažený v BL vrstvě aplikace. Při impulsu (zavolání své metody) uživatelským rozhraním (View) vyvolá odpovídající metodu business objektu (Model). Naopak při určité události v business objektu (změna hodnoty některé property, nebo 32
V odborné literatuře bývá někdy testování rozdělovány na Black Box Testing a White Box Testing. Black Box Testing má za cíl otestovat všechny možnosti užití systému uživateli, bez ohledu na to, jaká je vnitřní implementace těchto akcí. Typickým příkladem je testování scénářů use-casů, a jde o zodpovědnost analytika, který specifikuje, jak bude systém na konkrétní kroky uživatele reagovat. Naproti tomu White Box Testing (někdy lze najít také pojem Glass Box Testing) spočívá v testování z vnitřní perspektivy, z pohledu vývojáře, se znalostí vnitřní struktury, když jsou testovány jednotlivé metody a další elementy, co se týče správné funkčnosti a výkonnosti. Jde tedy o náplň práce designera, protože až ten zná konečnou vnitřní strukturu systému, a může tedy identifikovat jednotlivé metody a požadavky na ně (Microsoft Corporation, 2005).
50
6
TEORETICKÁ STUDIE
Obr. 10: Schéma návrhového vzoru Model-View-Presenter.
úspěšné/neúspěšné ukončení činnosti) zavolá metodu uživatelského rozhraní, předepsanou interfacem IView. K navázání konkrétního View k instanci třídy Presenter dojde zpravidla v konstruktoru, který má tvar public Presenter(IView view), a komponenta UI vrstvy, která ho vytvoří k ovládání své prezentační logiky, do jeho konstruktoru předá jako parametr odkaz na sebe this (tento postup bývá někdy nazýván Dependency Injection). • IView – interface představující rozraní komponenty UI vrstvy aplikace. Je součástí BL, jeho hlavním smyslem je odstínění závislosti tak, že nedojde ke kruhové referenci mezi UI a BL vrstvou aplikace. Odkrývá všechny metody a properties, které může Presenter volat a používat. • View1 a View2 – konkrétní prvky zajišťující interakci s uživatelem, např. může jít o potomky třídy Form z jmenného prostoru System.Windows.Forms. Implementují rozhraní IView a poté, co inicializují instanci presenteru (jeho konstruktoru předají odkaz na sebe), mají možnost účastnit se oboustranné interakce s BL vrstvou aplikace. Hlavní přínos je v tom, že prvek Presenter, tj. prezentační logika, je umístěná v BL vrstvě aplikace. To umožňuje její re-use i pro různé konkrétní uživatelské rozhraní. Pod pojmem prezentační logika si lze představit řízení chování uživatelského rozhraní, např. na formuláři editace pracovního poměru zaměstnance bude TextBox pro zadání hodinové mzdy zašedlý (disabled), pokud uživatel nezvolí, že je zaměstnanec placený od hodiny. Takovýchto akcí může být na uživatelském rozhraní větší množství a pokud se povede jejich řízení znovupoužít, lze o výraznou úsporu práce (jinak musí být pro každou variantu uživatelského rozhraní prezentační logika implementována znovu) (Martin a Martin, 2006). Dalším využitím tohoto návrhového vzoru je testování scénářů. Jde zřejmě o jediný jednoduchý prostředek, který umožňuje automatizaci testování prezentační logiky, tj. jaké výstupy dává aplikace uživateli a jak nakládá s jeho vstupy. K tomuto se používají tzv. mock-objekty, které stejně jako skutečné uživatelské rozhraní implementují metody pro komunikaci s presenterem, ale ve skutečnosti nevykonávají žádné akce na uživatelském rozhraní, ale pouze si např. logují volání svých metod (např. že presenter nastavil nějaké pole jako needitovatelné, do jiného pole něco doplnil po výběru v dalším poli apod.). Díky tomuto je možné zautomatizovat celé testy scénářů tak, že stačí nakonec zkontrolovat záznam mock-objektu, jestli bylo vše provedeno korektně.
6.4
Návrh
51
Nevýhoda je samozřejmě jednoznačná, a to je složitost návrhu a zvýšený objem psaného kódu, kdy je oproti klasické třívrstvé aplikaci třeba navíc napsat presenter a zahrnout do něj prezentační logiku, a rozepsat UI komponentu tak, aby implementovala rozhraní IView. Navíc je takováto architektura aplikace i poněkud méně průhledná a pochopitelná. Perzistence objektů v relační databázi Za běhu objektové aplikace jsou všechna přístupná data systému obsažená v objektech. U většiny běžných aplikací je ale potřebné zachovat data i po ukončení práce se systémem, tak aby se mohlo při příštím spuštění systému pokračovat v práci. Vyvstává tedy potřeba trvalého uložení perzistentních dat. Existuje pro to několik možností • Přímo v diskových souborech – zpočátku šlo o jedinou možnost, a i všechny dnešní pokročilejší možnosti (databázové systémy) ukládají ve svém důsledku data do souborů na disk. Přímé ukládání dat systému do diskových souborů ale přináší řadu nevýhod: problematická je práce s datovými soubory různých formátů, protože každý z nich je třeba parsovat jiným způsobem (tento problém je dnes již částečně vyřešen použitím ODBC driverů, které odstíní konkrétní uchování dat v souborech od funkcí přistupujícím k těmto datům); zřejmě nejvýznamnějším problémem použití souborů je ale zajištění integrity dat v nich, zvláště při přístupu více procesů k souborům. • Alternativní databázové architektury, může jít např. o objektové databáze 33 nebo XML databáze – jde ale spíše o experimentální řešení, jejich produkční využití v podnikových informačních systémech je vzácné. • Relační databázové systémy – z tohoto výčtu představují jednoznačně nejčastější volbu. Jejich specialitou je velmi podrobně propracované zajištění ACID konzistence databázových operací.34 Při použití relační databáze pro zajištění perzistence objektů slouží databáze jen jako úložiště dat, a přímo se s ní nepracuje (do databáze nezapisuje žádná jiná subrutina než metoda Save() daného objektu), zásadním principem objektově orientovaného programování je právě to, že nelze přistupovat k datům samotným, ale pouze předat danému objektu zprávu (zavolat jeho metodu), čímž lze jeho změnu vyvolat. Zajištění perzistence objektů v relační databázi bývá také někdy nazýváno objektově-relační mapování (Object-Relation Mapping). Základní metodou je přímé ruční mapování, kdy je třeba vytvořit v relační databázi struktury vhodné pro uložení business objektů, a naprogramovat mechanizmy pro načítání objektů a jejich ukládání. Kromě toho existuje i velké množství různě kvalitních nástrojů pro automatizaci O/R mapování, pro téměř všechny objektově orientované jazyky, např. technologie Hibernate (pro .NET verze NHibernate) nebo eXpress Persistent Objects. I tyto pokročilé nástroje ale vychází z přímého ručního mapování, pouze ho zobecňují a automatizují. 33 Ve slovním spojení objektové databáze bylo zbytečné používat množné číslo. Jedinou objektovou databází použitelnou v produkčním prostředí je DBMS Caché od firmy Intersystems. 34 Zkratka ACID představuje čtyři základní požadavky na konzistenci databázových transakcí: atomicitu, konzistenci dat, izolaci a trvalost (Herrington, 2003), v běžných relačních databázových systémech býva dosahována pomocí transakcí, i když existují i jiné koncepce pro zachování konzistence operací; více lze najít v článku The Transaction Concept (Gray, 1981).
52
6
TEORETICKÁ STUDIE
Ruční mapování tříd na ERD Ačkoliv datový model (graficky vyjádřený entitně-relačním diagramem) není součástí standardu UML (jde o jeden z modelů Yourdonovy strukturované analýzy), bývá ho vhodné vytvořit v situaci, kdy aplikace bude využívat pro perzistenci svých business objektů relační databázový systém. Na rozdíl od strukturované analýzy, kde je datový model zásadním modelem struktury systému, zde má význam pouze pomocného modelu fáze návrhu, určeného pro vytvoření vhodných datových struktur v relační databázi. Datový model (ERD) je strukturálním modelem, zobrazuje data a jejich vazby podobně jako model tříd. Datový model a class model jsou také do jisté míry převoditelné, a to zpravidla tím způsobem, že se na základě class modelu vytvoří ERD.35 Tabulky v ERD pojmově odpovídají business třídám class modelu, tj. perzistentním třídám v modelu BL vrstvy aplikace; a lze říct, že i perzistentním strukturám (struct), pokud jsou při návrhu použity. Rozdíl je ale ve vazbách mezi tabulkami v ERD a mezi třídami (strukturami) v class modelu. Zatímco datový model uznává pouze jeden typ vazby (tou je odkaz do jiné tabulky, v SQL reprezentovaný specifikací FOREIGN KEY), v class modelu existuje více možných vazeb mezi elementy (bylo o nich pojednáno dříve v této sekci práce). Příklad ERD vytvořeného z modelu tříd je uveden na obrázku 11.
Obr. 11: Příklad entitně-relačního diagramu odpovídajícího class diagramu objednávky (byl uveden dříve v této sekci, na obrázku 4 na stránce 41, v části věnované modelu tříd). Je zde použita Barkerova notace (tzv. Crow’s Foot notation) a datové typy RDBMS Oracle.
• •
• • •
35
Vztahy mezi elementy v class modelu se tedy do ERD převedou takto: Běžná asociace (odkaz do číselníku) – je totožná s cizím klíčem (FOREIGN KEY). Kompozice s násobností 1 : N (master-detail) – převede se na zpětnou asociaci, tj. detail obsahuje cizí klíč na master. Z tohoto důvodu je už i v class modelu vhodný u detailu (položky) zpětný odkaz na master (vlastníka položky). Kompozice s násobností 1 : 1 (perzistentní helper objekt) – poměrně vzácný případ, nejčastěji se řeší jednoduše cizím klíčem z masteru na helper objekt. Asociativní třída – pojmově totožná se spojovací tabulkou, obsahuje cizí klíč na každou třídu účastnící se asociace. Dědičnost (gen-spec) – existují tři možností mapování dědičnosti, jejich podrobnější popis lze nalézt např. v publikaci Objektové modelování a UML v praxi 2000 (Kraval, 2001). Každá má své výhody a nevýhody, existuje zde (stejně jako obecně v databázové teorii) nepřímá úměrnost mezi optimalizací na výkon a čistotou struktury, normalizovaností a optimalizací na konzistenci dat.
Modelovací nástroj Enterprise Architect dokonce obsahuje funkci na transformaci class modelu na datový model. Výsledek zpravidla není ihned použitelný a transformované ERD je třeba ručně upravit (zejména cizí klíče a řešení dědičnosti), ale i tak se jedná o nástroj do značné míry šetřící práci, zejména se takto lze vyhnout úmornému zadávání atributů tabulek.
6.4
Návrh
53
1. Základní způsob (1 : 1) – vytvoří se tabulky pro rodiče i všechny potomky, v tabulce předka jsou jeho atributy (společné pro všechny), v tabulkách potomků pouze atributy, které mají navíc oproti předkovi, a kromě toho má také každý potomek odkaz na předka. Jde o výchozí způsob, bez dodatečných úprav. Výhodou je jeho normalizovanost (dá se říct, že jde o nejčistší řešejí), nevýhodou je, že při potřebě nahrát instanci potomka se musí spojovat tabulky (protože vlastní atributy potomka jsou v jeho tabulce a společné atributy v tabulce předka). 2. Sloučení do jedné tabulky – atributy předka i všech potomků jsou v jedné obrovské tabulce, zpravidla se přidává další sloupec jako údaj o typu (třídě) záznamu. Tento způsob je jednoznačně optimalizován pro výkon, problém je s konzistencí dat – pro každý záznam mají význam jen určité sloupce, zatímco ostatní sloupce pro něj nemají smysluplnou hodnotu. Problematické je přidání dalšího potomka (vede k přidání sloupců do tabulky), hrozí náhodné zavlečení chyb do jiné oblasti systému (v jedné tabulce jsou data několika entit) a je problém s constrainty, protože v podstatě musí platit pro každý řádek jiné, podle jeho typu. 3. Úplné rozdělení – každý potomek má svou tabulku, v které jsou všechny jeho atributy (jak jeho vlastní, tak i zděděné po předkovi), předek (pokud je perzistentní) má také svou vlastní tabulku. Jde do jisté míry o kompromis, zvláštní problém je s vícenásobnou definicí stejných sloupců v každé tabulce potomka, což vede i k vícenásobné definici constraintů, triggerů a dalších objektů vázaných na sloupce. Pokročilé techniky optimalizace objektově-relačního mapování První z problémů, jejichž řešení bych zde chtěl zmínit, je zajištění integrity souběžných operací. Jde zejména o problém při souběžné editaci jednoho záznamu více procesy (typicky více uživateli) zároveň. Pokud tato situace totiž není nijak ošetřena, může dojít k tomu, že když první uloží data, druhý mu je přepíše, bez toho, aby to kterýkoliv z nich věděl. Existují tři základní způsoby řešení tohoto problému: • Pessimistic Concurrency – spočívá v zamykání dat, na tom principu, že jakmile je záznam načten (s příznakem, že je načítán pro editaci), je uzamčen a ostatní procesy k němu nemohou přistupovat, a to až do té doby, než vlastník zámku k záznamu zámek uvolní (typicky zapíše a potvrdí změněná data). Tedy už v okamžiku načtení dat může dojít k tomu, že systém vyhodí chybové hlášení a neumožní uživateli pokračovat. Jak už z názvu této techniky vyplývá, její typické použití je v případech, kdy se očekává, že může docházet k problémům se souběžnými operacemi.36 Na druhou stranu jde o implementačně náročnější řešení, které způsobuje overhead (kontrola locků, zamykání a jejich uvolňování při každé editaci) a má problémy se situací, kdy proces řádně neukončí session a tím pádem i neuvolní zámek (je třeba implementovat mechanizmus odstraňování zámků zamrzlých klientů). • Optimistic Concurrency – princip spočívá v tom, že se kontrolují problémy s konzistencí souběžných operací až v okamžiku zápisu dat. Typicky zjistí, jestli nějaký jiný proces nezměnil data v období mezi jejich načtením a pokusem o uložení, a v takovém případě dojde k chybě a data nemohou být uložena (.NET vyhodí výjimku 36 Tuto techniku například používá aplikace Microsoft Word, která v okamžiku, kdy už je soubor otevřen, umožní druhému uživateli otevřít soubor pouze pro čtení.
54
6
TEORETICKÁ STUDIE
DbConcurrencyException), a uživatel musí znovu načíst data a editaci zopakovat. Výhoda přístupu je je v jednoduchosti implementace a minimálním overheadu; zřejmá nevýhoda je v tom, že pro uživatele je toto řešení velice nepříjemné, protože stráví čas prací na editaci dat a až při uložení se dozví, že došlo k chybě a data je nutné nahrát znovu. Vhodné použití je v těch případech, kdy se kolize souběžných operací neočekávají, nebo nejde o rozsáhlá data se složitou editací (např. číselníky o sloupcích název a popis). Při uložení dat se nastaví timestamp uložení, který je při nahrání získán společně s ostatními daty, a při pokusu o uložení je porovnán timestamp nahraných dat s daty v databázi: pokud je v databázi jiný, je jasné, že se data změnila; podobně lze použít i číslo verze záznamu (při uložení se zvýší o 1). • „Last In Winsÿ – implicitní situace, kdy souběžné operace nejsou nijak ošetřeny. Potom poslední UPDATE přepíše všechny předchozí verze. Jde o nejhorší řešení, protože může dojít k přepsání dat (tj. k jejich ztrátě) bez toho, aby se to kterýkoliv uživatel dozvěděl. Existují optimalizace těchto řešení, např. u Optimistic Concurrency může dojít ke chybě, jen pokud oba dva procesy přepisují jeden atribut, ale ne už, pokud každý z nich zapisuje do jiných atributů (Basu a Rahman, 2006). Dalším problémem objektů při jejich uchování v relační databázi je, že objekty tvoří rozsáhlé do sebe zanořené struktury. Pokud by měl být při přístupu k objektu nahráván celý strom podobjektů, jednalo by se o obrovské zdržení. Jedno z řešení tohoto problému je využití návrhového vzoru Lazy Load. Jeho princip spočívá v tom, že jsou vnořené podobjekty z databáze dohrávány až v tom okamžiku, kdy je potřebné k nim přistupovat. Řešením, které představuje René Stein na svém blogu (Stein, 2008), je zavést dva mezistavy nahrání objektu (poněkud zjednodušuji, na jeho blogu je kompletní řešení se zdrojovým kódem): • Skeleton – objekt má pouze unikátní identifikátor (id ). Využítí je u objektů, na které nahrávaný objekt odkazuje pomocí běžné asociace. V tom případě je v jeho tabulce id odkazovaného objektu (např. v situaci, že objednávka má v class modelu běžnou asociaci na zákazníka, tak tabulka objednávky obsahuje id zákazníka). Na jednu stranu není vhodné, aby field objednávky – odkaz na zákazníka – byl nevyplněný (resp. null), protože při práci s objektem by se pak byly neudržitelné problémy (neustálé NullReferenceException). Na druhou stranu nemá rozhodně smysl nahrávat všechna data odkazovaného objektu, protože někdy nemusí být potřeba (např. při zobrazení přehledu objednávek), a už vůbec jeho vnořené podobjekty. Proto se objekt zákazník vytvoří pouze jako skeleton s jediným vytvořeným atributem id, a objekt samotný se nahraje až v okamžiku, kdy je potřeba získat některé jeho další data (např. jméno zákazníka). • Plochý objekt – v objektu jsou nahrané všechny jeho jednoduché atributy, které jsou obsažené v jeho databázové tabulce, ale nejsou nahrané jeho vnořené kolekce. Ty jsou nahrávány až v okamžiku, kdy je potřeba s nimi pracovat (resp. s jejich prvky). Typický příklad je, že v okamžiku zobrazení přehledu objednávek se nahrají všechny objednávky jen jako ploché objekty (tj. bez položek), a položky se dotáhnou k vybrané konkrétní objednávce až při příkazu na její zobrazení/editaci; pokud by měly být nahrány při zobrazení přehledu objednávek položky všech objednávek v přehledu, šlo by o značné zpomalení aplikace.
6.4
Návrh
55
Výhodou návrhového vzoru Lazy Load je, že se v konečném součtu nahraje mnohem méně dat (jen ty, které jsou skutečně potřebné pro práci uživatele se systémem); nevýhodou jsou časté, byť jednoduché, databázové dotazy, a také určitý overhead (je nutné sledovat a při přístupu ověřovat, které vnořené kolekce už jsou nahrané a které ještě ne). Posledním problémem, jehož řešení budu v této části práce uvádět, je vytvoření více instancí téhož objektu (lépe řečeno, více objektů obsahující data vzatá z jednoho řádku v databázi): v situaci, kdy k tomuto dojde, mohou nastat vážné problémy, zejména s konzistencí dat při ukládání, např. pokud jsou obě tyto instance změněny, a to každá jinak. Řešením je použití tzv. identitní mapy (návrhový vzor Identity Map). Identitní mapa funguje jako cache objektů, a udržuje si odkaz na všechny objekty, které jsou v systému nahrány. Pak při nahrání objektu se zkontroluje, jestli již tento objekt (objekt s daným id) není v identitní mapě, a pouze pokud není, tak se vytvoří jeho nová instance (a ihned se také vloží do identitní mapy). Samotná realizace identitní mapy je zpravidla jako dvourozměrná hešovací tabulka, jeden rozměr je podle typu (třídy) objektu, a pak podle id v rámci instancí téže třídy (Cochran, 2008). Hlavní příznivý důsledek použití je v tom, že každý objekt bude v systému pouze jednou, čímž se zamezí výše uvedeným problémům. Naopak, na rozdíl od populárního názoru, identitní mapa a cache objektů při O/R mapování obecně nepřináší jednoznačný výkonnostní přínos.37 Automatizace objektově-relačního mapování pomocí technologie eXpress Persistent Objects Balík eXpress Persistent Objects (dále XPO) je nástrojem k zajištění automatické perzistence business objektů. Tvoří vlastní DB vrstvu, kdy na pozadí aplikace běží Session, která je připojená k databázi a sama v okamžiku potřeby nahrává potřebný objekt z databáze; odpadá tedy potřeba psát DB vrstvu aplikace. XPO automaticky tvoří SQL dotaz, což vede k nezávislosti tvořené aplikace na použitém databázovém systému. Navázání business objektů na technologii XPO je založeno na návrhovém vzoru Layer Supertype, kdy perzistentní třídy musí dědit bázovou třídu XPObject (nebo jejího potomka). Tímto získávají schopnost automatické perzistence – metody pro nahrání a uložení objektu, a atribut OID (Object Identifier). Ve výchozím módu je toto v podstatě dostačující, protože XPO je poměrně autonomní a je schopné provádět DDL operace – pokud v databázi není tabulka se stejným jménem jako třída, vytvoří si ji, popř. si dokáže po změně struktury třídy změnit tabulku v databázi, tvoří spojovací tabulky pro vazbu s násobností M : N , vytváří si pomocné tabulky v případě složité dědičnosti, apod. Lze používat třídění, filtrování i agregační funkce, podobně jako při přímém psaní SQL dotazů. Tyto dotazy ale nejsou psány v jazyce SQL (jehož jednotlivé dialekty jsou databázově závislé), ale v objektovém kvazidotazovacím jazyce, který je jádrem XPO převáděn na SQL dotaz vhodný pro daný databázový systém. XPO umožňuje i používat 37 Důvodem je to, že cache má tendenci k zastarávání, a jediná správná a aktuální verze dat je v databázi. Pokud má být např. zobrazen seznam objektů, které splňují nějaká kritéria (např. zákazníků, kteří zadali v minulém měsící alespoň pět objednávek), je stále nutné poslat dotaz databázovému systému na pozadí aplikace, protože i když jsou určité záznamy v identitní mapě, není nijak zaručeno, že jsou to všechny, nebo naopak že se hodnoty záznamů v cache nezměnily. Určitý přínos může mít identitní mapa při nahrávání vnořených podobjektů, ale problém se zastaráváním dat v cache přetrvává, takže lze říct že hlavním smyslem identitní mapy je zabránění dvojího nahrání jednoho objektu. Více se lze dočíst ve výborném článku Why a Cache in an O/R Mapper Doesn’t Make it Fetch Data Faster (Bouma, 2006).
56
6
TEORETICKÁ STUDIE
transakce, a softwarově je emuluje i na databázových systémech, které je samy nepodporují (např. starší verze MySQL). Mapování tříd je do značné míry automatické, pro specifikaci konkrétního nastavení mapování se využívají atributy (jde o prvek deklarativního programování, např. atribut [Persistent("column_name")] pro specifikaci sloupce tabulky, v kterém je umístěna hodnota daného fieldu). Pro mapování dědičnosti je implicitně používán základní způsob (1 : 1), u konkrétních tříd lze nastavit i sloučení do jedné tabulky a úplné rozdělení. Při mapování dědičnosti XPO automaticky rozšiřuje databázové schéma. Výchozí mód XPO provádí většinu práce automaticky, bez možnosti snadného ovlivnění programátorem. To přináší i jisté problémy: • Defaultně jsou perzistentní veřejné členy – u klasické objektové aplikace (privátní fieldy, veřejné properties) je nutná úprava, kdy se properties označí jako neperzistentní a atributem [PersistentAlias("field")] se specifikuje odkaz na daný field. • Jsou požadovány určité názvy objektů v databázi (např. jména spojovacích tabulek), které nelze nijak nastavit – toto může působit problém zejména při napojení XPO na již existující aplikaci, kdy by bylo nutné tyto existující tabulky v databázi přejmenovat. • XPO samo provádí DDL příkazy, což vede v podstatě ke ztrátě kontroly nad strukturou báze dat, se všemi důsledky. Pokud databázi využívají i jiné aplikace (např. reportovací nástroj), které očekávají určitou strukturu databáze, tak změny prováděné XPO je učiní naprosto nefunkčními. Nelze provádět žádnou optimalizaci databáze, a obnovení databáze po havárii (nekorektním vypnutí) je značně problematické. Problémem je také náhodné zanesení chyby z kódu do databázového schématu. Proto je zřejmě vhodnější používat plně manuální režim. V tom případě je nutné namodelovat ERD podle modelu tříd a vytvořit v databázi příslušné struktury. Tímto lze dosáhnout větší flexibility řešení; na druhou stranu je třeba zajistit primární klíč a generování klíče nového objektu, a také ošetřit integritu souběžných operací. Řešení eXpress Persistent Objects je komerční, je placeno od počtu vývojářů (základní poplatek je 150 USD). Za další poplatek je možné dokoupit i zdrojové kódy balíku. Lze je zakoupit zvlášť, nebo jako součást balíku DXperience Enterprise, který kromě XPO obsahuje i reportovací nástroj a pěkně propracované ovládací prvky uživatelského rozhraní. Celá technologie je royalty free – tj. neplatí se žádné další poplatky za použití v konkrétních komerčních aplikacích, popř. za jejich prodané licence. Přínosem této technologie je jednoznačně ušetření práce při tvorbě aplikace (není nutné programovat DB vrstvu). Navíc aplikace založené na XPO dosahují i výkonnostně velice dobrých výsledků, protože přístup k datům je výrazně optimalizován (např. je použit návrhový vzor Lazy Load ). Další výhodou je databázová nezávislost aplikace.38 Více informací o této technologii lze získat např. na webových stránkách firmy Developer Express (Developer Express, 2008). 38
Tato databázová nezávislost je pochopitelně relativní. XPO podporuje v současné době dvanáct nejznámějších databázových systémů, ale pokud je třeba vytvořit aplikaci nad databází, kterou nepodporuje, nelze XPO v podstatě rozumně použít.
6.5
6.5
Implementace a testování
57
Implementace a testování
Tato fáze, někdy také nazývaná realizace informačního systému, spočívá v tvorbě spustitelného kódu aplikace (softwaru informačního systému). Tvoří ji dvě hlavní činnosti: kódování nových funkcionalit a oprava chyb, a testování aplikace v aktuálním stavu tvorby. Tvorba zdrojového kódu K samotnému programování informačního systému zde není příliš co dodávat. Vychází z návrhu, který podrobně specifikuje strukturu i chování aplikace, jako návrh tříd a specifikaci jejich metod.39 Nemá cenu v této části opisovat doporučení pro psaní kvalitního zdrojového kódu, jsou jim věnovány celé knihy, např. Co programátory ve škole neučí (Paleta, 2003). Lze zmínit jen pečlivé komentování, vhodné pojmenovávání proměnných, a nepoužívání nesrozumitelných konstrukcí, ani různých triků pro odhadované zvýšení výkonnosti aplikace. V poslední době jsou určitá doporučení pro psaní lepšího zdrojového kódu zahrnována pod pojem defenzívní programování (Hunt a Thomas, 2007), jejichž cílem je minimalizovat chyby, a také dosáhnout toho, že když už k chybě dojde, tak se projeví co nejdříve, protože v tom případě je mnohem snažší chybu nalézt a opravit. Mezi tyto techniky patří např. používání asercí pro vnitřní kontrolu hodnot proměnných, ošetření všech možných hodnot dat (např. každý příkaz switch by měl mít blok default, v kterém by měl minimálně vyhodit výjimku InvalidOperationException). Některé techniky souvisí již s návrhem aplikace, např. snížení komplexnosti a propojenosti kódu vhodným rozdělením do komponent a nepřistupováním k zanořeným objektům v jejich hierarchii přímo (tzv. Law of Demeter, byl popsán dříve). S tvorbou zdrojového kódu souvisí otázka jeho optimalizace, tj. zvýšení výkonu systému. Snahy o optimalizaci již při prvním psaní zdrojového kódu nejsou mnohdy příliš užitečné, zejména pokud se stráví spousta času s optimalizací jednotlivých dílčích funkcí před tím, než se projeví skutečná problémová místa (uživá se pojem bottleneck ). Optimalizace navíc většinou vede ke složitějšímu a méně přehlednému kódu. Výkonnost systému je převážně dána volbou technologií a postupů práce systému, k čemuž dochází ve fázi designu, a návrhem vhodných algoritmů a datových struktur. Výsledky optimalizace zdrojového kódu jednotlivých programových jednotek jsou pak oproti důsledkům vhodného/nevhodného návrhu minimální. Vhodný čas na optimalizaci kódu je tedy až poté, co se provede komplexní výkonností testování aplikace s reálným množstvím dat, pak teprve se odhalí všechna kritická místa a je třeba výkonnostní problémy opravit v kódu. 39
Není pochopitelně prakticky možné, aby návrh byl kompletní v tom smyslu, že bude obsahovat všechny metody všech tříd, takže programátor by už psal pouze jejich těla. Návrh musí obsahovat všechny třídy, a ty metody, na které jsou nějaké funkční požadavky; na druhou stranu během vývoje zřejmě bude docházet k tomu, že programátor rozepíše jednu navrženou metodu na volání dílčích privátních subrutin, apod. Pokud by se tomuto mělo zabránit, musel by se návrh provést do takové úrovně detailu, že by byla jeho časová náročnost v podstatě neudržitelná. Zásadou by ale mělo být, že veřejné členy tříd a jejich chování by se oproti návrhu neměly měnit, protože jejich změna by mohla vést ke změně spolupráce mezi objekty a nutnosti přepracování modelu tříd, a návrhu jako celku. Prostředkem k dosažení souladu class modelu s programovým kódem je tzv. reverse engineering. Jde o techniku, kdy ze zdrojového kódu je zpětně sestaven model tříd. Enterprise Architect podporuje synchronizaci modelu s kódem oběma směry – jednak jako vygenerování tříd z class modelu, a jednak i jako reverse engineering, tj. promítnutí zdrojového kódu do class modelu.
58
6
TEORETICKÁ STUDIE
Testování Testování softwaru je činnost, jejímž cílem je zhodnocení schopnosti aplikace nebo jeho části dosáhnout požadovaných výsledků (Pan, 1999). Samotné testování, tj. provádění testů a interpretace jejich výsledků, je nedílnou součástí tvorby zdrojového kódu systému ve fázi implementace. Specifikace testů (tj. požadované chování po zadaných vstupech) je ale tvořena již dříve, a to ve fázích analýzy a návrhu. Existuje více druhů testů, které se navzájem liší cílem a informacemi, které test o testované aplikaci vrací (Kaner, 2003). Mezi nejpoužívanější testy při vývoji informačních systémů patří: • Funkční testování – jedná se o testování průběhu každé funkce izolovaně. Jde o nejčastější testování, které lze zautomatizovat pomocí jednotkových testů. Programátor spustí tento test všech jednotlivých metod třídy při každém zásahu do programové jednotky, před vydáním stabilní verze apod. Pro každou funkci bývá psáno více testů: test s přijatelnými kombinacemi vstupů musí vrátit správný výsledek, testy s chybnými vstupními podmínkami musí správně ohlásit chybu (např. vyhodit výjimku) a korektně skončit. Výhodou je velice dobrá zautomatizovatelnost a také snadnost vyhodnocení; nevýhodou je to, že funkční test neodhalí jednak chyby při složitějších scénářích spolupráce různých metod více objektů, a také neodhalí chybu v návrhu, tj. nesoulad mezi specifikací chování aplikace (dokumentace use-casů) a skutečným chováním. • Testování scénářů – pokročilejší testování komplexních funkcí systému, zpravidla má vazbu na jeden scénář případu užití. Tyto testy se tvoří již ve fázi analýzy, a mají tedy přímý vztah k užitným činnostem systému pro uživatele (v podstatě se testuje, jestli každý konkrétní scénář použití systému uživatelem proběhne při daných vstupech korektně). Tyto testy jsou poměrně silné, protože odhalí všechny chyby oproti specifikaci.40 Automatizované testování scénářů ale není zdaleka tak jednoduché jako funkční testování, protože zpravidla spočívá v interakci UI vrstvy s uživatelem: – Je možné shrnout scénář na volání jedné funkce, které se předají všechny vstupy, jež by jinak postupně zadával uživatel. Tato funkce pak volá samotné výkonné metody objektů, a v okamžiku, když je třeba, aby do skutečného systému vložil údaj uživatel (např. zvolil možnost v dialogovém okně apod.), metoda použije údaj, který dostala jako parametr, a podle toho pokračuje v práci. Jde o jednoduché a poměrně dobře použitelné řešení; jeho nevýdou je ale, že neověří prezentační logiku skutečného uživatelského rozhraní. – Testování scénářů lze realizovat tak, že před spuštěným systémem bude sedět tester a testovat aplikaci (každý její scénář) ručně. Tento přístup je tedy zhruba totožný s testováním uživatelského rozhraní. Zřejmě nemá cenu zdůrazňovat, že jako prostředek k testování scénářů je značně problematický, protože otestovat všechny scénáře use-casu, se všemi možnými vstupy, je časově náročné a namáhavé. V důsledku tedy vede k tomu, že se testování scénářů spíše zanedbává, 40
Testování scénářů ale není nejvhodnějším prostředkem pro hledání jednoduchých chyb v tělech základních subrutin. Zde je vhodnější funkční testování, protože takovou chybu izoluje – při testu scénáře se pouze projeví, že po průběhu s danými vstupy systém vydal nekorektní výstup, ale ne již která konkrétní funkce chybu způsobila. Proto se nejprve doporučuje otestovat všechny programové jednotky zvlášť (funkční testování), a až v případě bezchybného průchodu provádět testování scénářů.
6.5
Implementace a testování
59
a pak může dojít k odklonu implementace od popisu práce systému stanoveného ve fázi analýzy. – Prostředkem, jak spojit automatizaci testování scénářů s otestováním skutečné prezentační logiky použité v aplikaci, je návrhový vzor Model-View-Presenter (byl popsán v sekci zabývající se návrhem, viz obrázek č. 10 na stránce 50). • Testy technologie – jejich cílem je zhodnocení výkonu systému, např. v kritických situacích, při naplnění reálným množstvím dat, apod. Díky nim lze nalézt problémová místa, která poté stojí za to optimalizovat. Jejich automatizace je snadná a vypovídací schopnost dobrá (pokud se obdobný výsledek projeví opakovaně při několika průbězích), ale odhalí pouze výkonnostní problémy, ne chyby ve funkčnosti systému. • Testování uživatelského rozhraní – předtím, než se vůbec dá systém k dispozici uživatelům, je třeba zhodnotit správnost a srozumitelnost uživatelského rozhraní. Provádí ho zpravidla tester, když ručně zkouší používat aplikaci a hodnotí použitelnost (usability) jednotlivých formulářů. • Uživatelské testy – provádí je potenciální uživatelé systému, aby se zjistil názor lidí mimo vývojový tým na řešení systému. Poznatky uživatelů jsou zásadní, protože právě uživatelé budou nakonec se systémem pracovat, a cílem vývojového týmu musí být jejich co nejvyšší spokojenost se systémem, protože spokojenost a pozitivní názory existujících uživatelů na systém jsou jednou z jeho nejlepších forem propagace.41 Existuje více typů těchto testů, např. Alpha Testing, Beta Testing a Acceptance testing. Je ale nutné připomenout, že z teoretického pohledu není testování plně uspokojivou technikou k zajištění kvality aplikací. Testováním nelze prokázat správnost určitého algoritmu. Není totiž zaručeno, že při testování chybného algoritmu test chybu objeví, neboť může totiž dojít k tomu, že nebyla testována situace, kdy se program chová chybně. Z principu pak otestování algoritmu pro všechny vstupní hodnoty není realizovatelné. Prokázat správnost sestaveného algoritmu je tedy možné pouze pomocí formálních matematických postupů (Backhouse, 2003). Jednotkové testy Jednotkové testy (volně přeloženo z anglického Unit Testing) jsou nástrojem k otestování nejmenších individuálních funkčních částí kódu, což jsou v objektově orientovaném programování metody tříd. Jednotkové testy jsou do značné míry automatizovatelné, pomocí nástrojů z rodiny xUnit, např. pro prostředí .NET je to balík NUnit. Jednotkové testování, které je typickým nástrojem funkčních testů, probíhá tak, že pro každou testovanou metodu se sestaví jedna nebo více testovacích metod, které zavolají testovanou s různými vstupními daty, a pomocí aserce ověří správný výsledek. Pokud se takto pokryjí všechny metody a properties, lze pak naráz provést test celé třídy. Pomocí tohoto mechanismu lze následně sestavit testy pro všechny třídy v aplikaci. Cílem jednotkových testů je jednoduchý mechanizmus ověření, že jednotlivé dílčí jednotky pracují správně, toto ověření programátor provádí zpravidla po každé změně aplikace. Lze říct, že k ověření jedné metody reálné třídy je zpravidla potřeba napsat několik testů (tj. testovacích metod). Důvodem je to, že v kódu metod aplikace jsou různé 41
V marketingové teorii se dnes hovoří o tzv. business democracy, kdy jsou firmy „řízenyÿ přáními a požadavky zákazníků, veškerá jejich činnost se zaměřuje na maxímální uspokojení těchto přání a požadavků (Foret, 2006).
60
6
TEORETICKÁ STUDIE
podmínky a větvení, a průběh práce metody závisí na vstupních hodnotách. Pro každou kombinaci vstupních hodnot, pro které je definované jiné chování metody, je tedy třeba napsat test. Navíc je potřebné otestovat i jak metoda reaguje na neplatné vstupní hodnoty. Uvádí se, že na každý řádek kódu aplikace připadá pro jeho solidní pokrytí testy asi 3–5 řádek testovacího kódu (např. v nástroji NUnit). Zatímco specifikaci testovacích případů pro jednotkové testy píše zpravidla designer, zdrojový kód testů je spíše prací testera (popř. programátora) ve fázi implementace. Doporučuje se ale, že testy by měly být naprogramované před samotným kódem aplikace (Miller, 2002). Na toto navazuje jedna z agilních metodik, nazývaná Test Driven Development. V jejím pojetí je celý vývoj řízen testy, ve fázi implementace se nejdříve vytvoří testy, pak se vytvoří co nejrychleji kód tak, aby všechny testy proběhly úspěšně, a poté se provádí refaktoring, dokud není řešení uspokojivé. Výhodou této metodiky je jednoznačná orientace na výstupy, tj. od každé metody se primárně požaduje, aby splňovala požadavky na ni kladené (vyjádřené ve formě testů). Naopak nevýhodou může být, že i přes následný refaktoring někdy není dosažena taková úroveň objektové čistoty a re-use obecně.
6.6
Kritika modelování
V předchozí části své práce hojně používám softwarové modelování v modelovacím jazyce UML, jako prostředek k naznačení postupu řešení uváděných problémů. Nyní je tedy na čase kriticky se zamyslet nad samotným modelováním informačních systémů v UML, tj. zejména nad jeho problémy. První, poněkud naivní kritikou modelování obecně je, že samotným modelováním se tvoří pouze pomocná schémata pro tvorbu systému, nikoliv informační systém jako takový. Sice lze tvrdit, že modelování tvořeného systému je základním krokem při plánování a rozmyšlení jeho vývoje a šetří čas, který by jinak byl zbytečně vynaložen, pokud by se chyby v porozumění požadavků zákazníka a špatně navržené architektuře systému měly projevit až v průběhu psaní zdrojového kódu, nicméně základním pravidlem, na které by se při modelování informačních systémů nemělo zapomínat, je, že cílem celé této námahy je naprogramovat vhodný software, a model je pouze prostředkem pro snažší dosažení tohoto cíle. Modelovací jazyk UML jako takový, ostatně stejně jako všechny standardizované nástroje pro návrh softwaru, vedou k formalizaci modelů. Toto lze někdy vnímat jako výhodu (formální postup zajistí, že se v průběhu práce na každém projektu provedou určité nezbytné činnosti a jejich výstupy se zaznamenají do stanovených modelů), avšak formálnost modelů lze do značné míry hodnotit i negativně, protože svádí k zaměření se analytiků/designerů místo na obsahovou správnost modelů na jejich formální správnost, tj. užití správné notace. Několik příkladů za všechny: • Vztahy include a extend v use-case modelu – tyto vztahy nejsou příliš dobře popsány a rozlišeny ani ve standardu UML, a při zavedeném chápání (include je povinné volání, zatímco extend nepovinné) nejsou ani zcela jednoznačně rozlišitelné. Nemá smysl, aby analytik dlouze rozmýšlel, který z nich použít, pokud je obsahová stránka jasná, tj. pokud ví, za jakých podmínek jeden use-case volá druhý, a zapíše to srozumitelně do dokumentace k use-case modelu. • Generalizace/specializace v use-case diagramu – tento problém jsem zmínil již v sekci věnované analýze, zjednodušeně jde o to, že ačkoliv jde o formálně správné vazby
6.6
Kritika modelování
61
(standard UML povoluje použít gen-spec jak mezi use-casy, tak i mezi aktory), obsahově jsou těžko pochopitelné či zbytečné. Pokud se analytik zaměří na formální stránku modelu, tak je schopen vytvořit model, který je formálně správný a jeho jediným problémem je, že není k pochopení. • Vztahy agregace/kompozice v class modelu – další ze vztahů, kde ani mezi odbornou veřejností nepanuje konsenzus ohledně jejich rozdílu a doporučeného použití. Není účelné dlouze přemýšlet nad použitím formálně správné vazby, pokud je jasná a zdokumentovaná povinnost a násobnost účastníků vazby. • Přiřazování aktorů k use-casům – v UML verzi 1.3 se používal k připojení aktora k jím používanému use-casu vztah use. V UML 2.1 se má používat asociace. Změna ve standardu byla provedena z důvodu odlišení sémantiky vazby use a asociace. Záleží ale z obsahové stránky na tom, která vazba je použita pro připojení aktora k use-casu? Znovu nemá smysl dbát na to, aby v této situaci byla použita formálně správná vazba. Snad nemá cenu zdůrazňovat, že hlavním cílem tvorby modelů informačních systémů je obsahová stránka těchto modelů, a formální správnost modelů je pouze prostředkem pro jejich lepší uchopení ostatními analytiky/designery. Pokud je ale model dobře pochopitelný a zdokumentovaný, tak ačkoliv používá formálně nesprávnou notaci, je přijatelný a nemá cenu ztrácet čas jeho opravami a snahami o správnost použití jeho elementů podle normy. Dalším problémem jazyka UML je jeho jednotná notace pro různé typy modelů, tj. pro analytické modely, návrhové modely i dokumentaci implementace. Přitom univerzálnost UML bývá často uváděno jako výhoda UML, protože modelovací jazyk používá užší množství modelů a jejich elementů. Problém je ale v tom, že kvůli této univerzálnosti může dojít k tomu, že jeden vývojář může interpretovat model vytvořený jiným vývojářem při uvažování jiných předpokladů jinak. Typické je to u class modelu, kde to, co jeden vývojář navrhl jako konceptuální diagram (s asociacemi znamenajícími pouze obecnou souvislost mezi objekty problémové domény), druhý vývojář může považovat za implementační class model, kde asociace znamenají ukazatele na odkazované objekty. S tímto souvisí i další problém jednotné notace konceptuálního a implementačního class modelu: v konceptuálním modelu jsou naznačené určité vztahy mezi entitami problémové domény, stejná notace ale svádí designera k tomu, že tyto vztahy přijme bez dalšího rozmýšlení jako vztahy mezi tvořenými třídami, zatímco mnohdy by bylo vhodnější určitý analytický vztah rozpracovat v návrhovém modelu jinak. Toto jsou pouze nejvýraznější nedostatky modelování informačních systémů, lze jich nalézt několik desítek (Simons a Graham, 1999). I přes tyto problémy lze ale říct, že modelování softwaru v UML je pozitivním procesem, který vede k vyšší kvalitě tvořených systémů. Pouze je potřeba si tyto nedostatky při vývoji uvědomit, aby nedošlo k tomu, že modelování systému a fáze analýzy a návrhu obecně, se ukáže jako kontraproduktivní.
62
6
TEORETICKÁ STUDIE
7
7
METODIKA PRÁCE
63
Metodika práce
V předchozí kapitole jsem se pokusil představit jednotlivé metody a techniky použitelné pro vývoj objektově orientované aplikace. Nyní je tedy na čase rozhodnout, které z nich nakonec při realizaci své práce použiji, a proč. Na začátek je nutné uvést, že vzhledem k tomu, že tvořený modul bude součástí podnikového informačního systému Prytanis, a je vyvíjen jako součást tohoto celého systému ve firmě Unis Computers, spol. s r. o., neměl jsem zcela neomezenou možnost zvolit metodiku vývoje a použité postupy a techniky, ale způsob řešení je do značné míry odvislý od celkového postupu tvorby informačního systému Prytanis a vývojového procesu ve firmě Unis Computers, spol. s r. o. obecně. Celý systém je tvořen jako software pro volný trh, tj. není daný jeden zákazník, který by řídil a rozhodoval o jeho vývoji, jako u vývoje software na zakázku, ale systém je tvořen interně, a poté bude prodáván všem zákazníkům, kteří o něj budou mít zájem. Z toho plyne i zásadní věc, že požadavky na systém mají interní charakter, a jsou zhruba specifikovány domain managerem (v případě aplikace Jítzní řády jde o vedoucího vývoje modulu Doprava). Tyto požadavky samozřejmě nejsou neměnné, v průběhu práce na první fázi vývoje (specifikace požadavků) jsem konzultoval názory na tvořenou aplikaci i s několika význačnými zákazníky, kteří o ni projevili zájem; výsledná specifikace je tedy souhrnem požadavků (názorů) vedoucího vývoje a konkrétních požadavků a připomínek zákazníků – budoucích uživatelů. Vzhledem k tomu, že už tedy jsou požadavky zhruba rozepsány, není nutné ve fázi specifikace požadavků trávit příliš mnoho času. V práci budu tvořit procesní model, ale spíše jako ověření konzistence existujících požadavků, aby se na některý zásadní komputerizovatelný proces nezapomnělo. Na druhou stranu nerozebírám model podnikových procesů příliš do hloubky, ani netvořím model cílů nebo další složitější podnikové modely, a i výsledná specifikace požadavků na systém má víceméně neformální charakter. Ve fázi analýzy bude vytvořen use-case model v celé své šíři, hlavně proto, že se jedná o esenciální model pro další vývoj, a nezbytná bude také kompletní dokumentace všech nalezených use-casů. Dále sestavím konceptuální class model; další analytické modely budu tvořit pouze v případě nutnosti (pokud se objeví složitější chování, těžko popsatelné dříve zmíněnými modely), a lze očekávat pouze výjimečné použití těchto doplňkových analytických modelů, v odůvodněných situacích. Dále se při vývoji aplikace Jízdní řády bude postupovat iterativní a inkrementální metodou vývoje, což znamená rozdělení dalšího vývoje aplikace na jednotlivé menší přírůstky, které budou realizovány postupně. Tato metoda je používána i ve vývoji celého podnikového informačního systému Prytanis na platformě .NET. Z návrhových modelů zcela jednoznačně využiji implementační class model, a to pro návrh struktury tříd BL vrstvy aplikace. Nemá příliš význam používat model komponent, protože aplikace Jízdní řády bude z hlediska částí systému tvořit jednu komponentu, pouze vertikálně strukturovatelnou (na BL vrstvu a UI vrstvu). Ve vhodných situacích budou využity návrhové vzory. K řešení perzistence business objektů je v celém tvořeném systému použita technologie eXpress Persistent Objects. Bude ale použita v plně manuálním režimu, kdy je třeba v databázi vytvořit příslušné datové struktury, a ručně nastavit, které třídy (a jejich
64
7
METODIKA PRÁCE
fieldy) se budou mapovat do kterých tabulek (a jejich atributů). Proto se z tohoto ohledu jeví nezbytné vytvoření entitně-relačního diagramu. Jak již bylo výše uvedeno, celý systém je tvořen v programovacím jazyce C#. K jeho funkčnímu white-box testování budou využity jednotkové testy, a k jejich automatizaci nástroj NUnit. Vzhledem k tomu, že se jedná o rozsáhlý systém, používá do značné míry interní aplikační framework. Jeho přínosem je jednoznačné ušetření práce při programování opakujících se činností; na druhou stranu zdrojový kód jednotlivých aplikací se tímto stává méně přehledný, a to zvláště pro čtenáře mimo vývoj ve firmě Unis Computers, spol. s r. o., protože ve větší míře obsahuje volání funkcí frameworku. Proto zřejmě nemá v této práci smysl uvádět kompletní zdrojový kód tvořeného modulu, a místo toho budou uvedeny pouze ukázky zdrojového kódu, a ukázky obrazovek vytvořeného systému.
8
TVORBA MODULU JÍZDNÍ ŘÁDY
8
65
Tvorba modulu Jízdní řády
Hlavním cílem mé práce je vytvoření modulu pro správu a editaci jízdních řádů informačního systému Prytanis. V této kapitole tedy popíši řešení problému, to jest jednotlivé dílčí modely vedoucí k sestavení požadovaného modulu, a ukázky zdrojového kódu a obrazovek systému.
8.1
Úvodní studie
Jak jsem již v kapitole 7 uvedl, celý systém (a tedy i tvořený modul) je vyvíjen pro volný trh. Základní požadavky na systém byly stanoveny interně ještě před tím, než jsem začal na modulu pracovat, proto tedy nemá cenu příliš podrobně zpracovávat modely a dokumenty této fáze. Jde spíše pouze o ověření konzistence, a případné doplnění požadavků. Základním modelem, který jsem v této fázi tvořil, je procesní model. Činnost dopravních podniků (pro které bude tvořený modul určen) zahrnuje větší množství procesů z několika oblastí. Základním zúžením pro potřeby této práce je zaměření se na dopravní činnost podniků, protože ostatní subsystémy (např. ekonomické procesy) jsou již uspokojivě pokryty jinými moduly informačního systému Prytanis, a ani pro potřeby této práce není účelné modelovat všechny procesy odehrávající se v dopravních podnicích. Dopravní činnost cílových podniků a softwarové požadavky na její komputerizaci již byly stručně naznačeny v kapitlole 5. Zde jsou tyto shrnuty do podoby Business Process Modelu, který je všeobecně uznávaným vyjádřením procesů podniku. Celý procesní model dopravní činnosti dopravních podniků je uveden na obrázku 30. Aniž bych zde opisoval tento diagram (a také to, co jsem již napsal v kapitole 5), lze tedy pouze shrnout, že správa jízdních řádů je základním procesem, na který navazuje většina dalších procesů v dopravních podnicích. To je pochopitelně logické, protože jen pokud jsou stanovené jízdní řády linek, lze plánovat přepravu, prodávat jízdenky a následně vyhodnocovat ekonomické charakteristiky vozidel a rentabilitu přepravy (neuvažuji zde nepravidelnou osobní dopravu, která je pro většinu běžných dopravních podniků jen doplňkovou činností). Model business procesů při správě jízdních řádů linek Celý procesní diagram dopravní činnosti typického dopravního podniku je uváděn spíše pro ilustraci. Cílem této práce je sestavit modul pro počítačovou podporu prvního z procesů, správy jízdních řádů. Pokud se tedy blíže podíváme na dílčí procesy spadající pod správu jízdních řádů (procesní model správy jízdních řádů je uveden na obrázku 14), lze identifikovat několik podnikových procesů. Prvním z nich je Správa zastávek, vzdáleností mezi nimi, značek termínových omezení a dalších znovupoužitelných elementů. Vyplývá z potřeby evidovat kromě samotných jízdních řádů ještě další údaje, které se při tvorbě jízdních řádů použijí. Typicky jsou to zastávky, jejichž seznam s podrobnějšími údaji je dobré vést zvlášť. Mezi údaje sledované u zastávek může patřit např. tarifní pásmo, do kterého zastávka náleží (jsou-li tarifní pásma používána), zda je zastávka na znamení, zda je bezbariérově přístupná (popř. je na ní WC), a další údaje, které se využijí zpravidla při tisku jízdního řádu linky, ale je vhodné je zadat obecně tak, aby nemusely být doplňovány k dané zastávce v každém jízdním řádu linky zvlášť.
66
8
TVORBA MODULU JÍZDNÍ ŘÁDY
Stejně tak je vhodné centrálně evidovat vzdálenosti zastávek, aby nedošlo k tomu, že na jednom jízdním řádu bude vzdálenost mezi dvěma zastávkami jiná než na jiném (samozřejmě, za předpokladu, že spoj jede po stejné trase). Dále je vhodné vést i seznam termínových omezení, aby se zajistilo jejich jednotné číslování napříč všemi jízdními řády linek42 , nebo seznam informativních poznámek pod jízdními řády. Zásadním procesem v této oblasti je Zadání a úpravy linky. Jeho cílem je tvořit a spravovat jízdní řády linek tak, aby se s nimi mohlo v podniku dále pracovat (tisknout je, plánovat podle nich turnusy vozidel a řidičů apod.) Jde o proces, jehož realizace informačním systémem bude zřejmě nejnáročnější. Na druhou stranu tvoří základ celého systému a jeho komputerizace je tedy zásadní a nezbytná. Poté, co je vytvořen jízdní řád linky, je třeba z něj získat tiskový výstup, zejména kvůli vydávání tištěných knižních jízdních řádů a kvůli výlepu jízdních řádů na označníky zastávek. Tohoto je dosaženo procesem Získání tištěného jízdního řádu. Lze pouze uvést, že existuje větší množství formátů tisku (např. pro knižní jízdní řády je třeba vytisknout jízdní řád v jiném formátu než pro výlep na jednotlivé zastávky), a stejně tak existuje větší množství technologických postupů, jak vytištěného jízdního řádu dosáhnout. Tak jako tisk linky způsobí výstup jízdního řádu v tištěné formě, tak proces Export linky slouží k převodu dat o lince do různých elektronických formátů potřebných pro přenos dat o lince do informačních systémů pro další zpracování. Může to být software pro obsluhu elektronických strojků (např. USV-C ), Celostátní informační systém jízdních řádů, nebo je někdy třeba získat výstup ve vhodném formátu pro umístění na webové stránky dopravního podniku. Další agendou navazující na linky je Sledování licencí k linkám. Důvodem je to, že provoz hromadné linkové silníční dopravy je legislativně omezen tak, že je možné provozovat pouze takové linky, na které vydá příslušný dopravní úřad licenci. Proto je tedy vhodné evidovat licence k jednotlivými linkám. Souhrn požadavků na tvořenou aplikaci Neformální seznam požadavků na aplikaci Jízdní řády (nejedná se o přesnou specifikaci, jaká bývá k vidění při vývoji software na zakázku) vychází ze sestaveného modelu podnikových procesů. Zásadní ale je také fakt, že tvořená aplikace bude součástí informačního systému Prytanis. Co se nefunkčních požadavků týče, jsou téměř 100% dány celým systémem. Jedná se zejména o použité technologie, způsob vývoje a testování, jednotný způsob ovládání aplikace a uživatelské rozhraní, apod. Specifické pro aplikaci jsou tedy v podstatě pouze funkční požadavky. Do funkčních požadavků zasahuje také fakt, že součástí původního systému Prytanis na textovém režimu byla aplikace pro správu a editaci jízdních řádů, a tato se dnes ještě 42
Termínová omezení jsou doplňujícími údaji evidovanými k jednotlivým spojům na lince, udávají konkrétní termíny, v kterých spoj jede/nejede, i když by podle základního omezení (všední dny/soboty/neděle a svátky) jet měl. Typickým termínovým omezením je Nejede 24. XII. a 31. XII. Na jízdních řádech se termínové omezení číslují od 10 do 79, používají se k tomu tzv. negativní značky (jsou to malá bílá čísla v černém poli). Podle vyhlášky (388/2000 Sb.) musí být na jízdním řádu jedné linky jedna negativní značka použita v jednom významu. Mezi jednotlivými jízdními řády toto platit nemusí, nicméně uznávaným doporučením je dodržovat jeden význam jedné negativní značky i v rámci jízdních řádů všech linek dopravního podniku, protože to zvyšuje přehlednost jízdních řádů.
8.2
Analýza
67
u několika zákazníků používá. Stejně tedy jak celý nový systém Prytanis se nemůže svou funkčností výrazně odchýlit od starého systému (a musí poskytovat kompatibilní podporu podnikovým procesům komputerizovaným původním systémem), tak i nově tvořená aplikace Jízdní řády musí být kompatibilní s modulem původního systému v tom smyslu, že musí být nastavitelná na takový způsob používání, jak dnes pracují zákazníci s původním modulem. Toto samozřejmě není absolutní, nová analýza aplikace je prováděna právě proto, aby byla znovu modelována funkční stránka systému, a funkcionality, které nejsou potřebné nebo nikdy pořádně nefungovaly, nebudou v nové aplikaci obsažené. Nicméně neměla by být vypuštěna žádná podstatná používaná funkčnost původního systému. Funkční požadavky na aplikaci by se tedy daly shrnout do následujícího výčtu: • Evidence zastávek a jejich vzdáleností (v původním systému byly nazývány Přejezdy) • Evidence poznámek, termínových omezení a dalších znovupoužitelných elementů • Zadání linky – přidání spojů, zastávek, zadání průběhu jednotlivých spojů, časů jejich odjezdů ze zastávek a vzdáleností mezi zastávkami • Udržování historie linek – varianty linek s časovou platností • Možnost přesunu starých variant linek do archívu linek, tak aby „nezaplevelovalyÿ hlavní přehled linek. • Import linky z datových formátů konkurenčních systémů pro správu linek a z Celostátního informačního systému • Správa licencí na linky • Export linek do různých datových formátů • Možnost vést na jedné databázi jízdní řády více dopravních podniků43 • Tisk linky v různých formátech • Možnost zadávání dalších údajů pro použití při tisku či exportu do jiných aplikací – např. přestupy na zastávce na spoji nebo tabulky MHD pro tisk Tyto spíše neformálně vyjádřené požadavky pak tvoří základní přehled funkčnosti aplikace, který bude dále rozpracován ve fázi analýzy.
8.2
Analýza
Poté, co byla hotová specifikace požadavků (a ta byla do značné míry hotová už v době, kdy jsem na aplikaci začal pracovat, naopak byla vlastně částečně mým zadáním při této práci), bylo načase zpracovat use-case model. Objevil jsem dva aktory používající aplikaci Jízdní řády: jedním z nich je administrátor aplikace, který má oprávnění k pokročilým funkcionalitám, jako je např. editace číselníků ovlivňujících chod aplikace (např. typy linek), a druhým běžný uživatel, který aplikaci nekonfiguruje, ale pouze běžným způsobem používá, tj. zadává zastávky, jízdní řády linek, licence k linkám apod. Při sestavování use-case modelu jsem tyto členil do balíků (packages), a to zejména podle jednotlivých podnikových procesů, jejichž komputerizaci budou tyto use-casy zajišťovat, a podle kategorií ve specifikaci požadavků. Nakonec jsem sestavil osm balíků, které dohromady obsahují 70 případů užití. 43 Tato možnost je implementována v původním modulu, a byla výslovně zákazníky požadována. V některých případech totiž nemá každý dopravní podnik zakoupený software pro zadávání a správu jízdních řádů, a tak se domluví s druhým dopravním podnikem a používají jeho software. Nejzajímavější na tom je, že většinu číselníků aplikace (mimo jiné zastávky, termínová omezení, poznámky, typy linek a přepravní systémy) mají společných.
68
8
TVORBA MODULU JÍZDNÍ ŘÁDY
Diagramy případů užití V této části se pokusím zhruba shrnout model případů užití, samotné diagramy jsou uvedené v příloze C. Prvním balíkem v use-case modelu je Místa, zastávky a přejezdy mezi nimi. Jde o první sadu funkcionalit, jejichž cílem je zejména zajištění práce s číselníkem zastávek a číselníkem přejezdů mezi zastávkami, use-case diagram je uveden na obrázku 15 na stránce 95. Základním případem užití je Založení nové zastávky a analogická Oprava zastávky v číselníku zastávek, které slouží k zadání údajů o jednotlivých zastávkách. Jde zejména o místní určení zastávky (obec a část obce), název zastávky a další různorodé údaje o zastávce, které jsou do jisté míry nastavitelné. V systému se poté evidují vzdálenosti mezi zastávkami, a to dokonce dvojí vzdálenosti: tarifní a skutečné. Skutečné vzdálenosti se používají pro evidenci, kolik km skutečně vozidlo ujelo, např. na v ZPVOD nebo pro výpočet silniční daně, a je možné je vyjádřit desitinným počtem kilometrů. Narozdíl od nich, tarifní vzdálenosti se používají při tisku na jízdní řády a pro výpočet jízdného, je-li počítáno podle km, a jde o celé číslo (měla by to být skutečná vzdálenost zaokrouhlená na celé kilometry). Co se týče vzdáleností mezi zastávkami, existuje také více modelů, jak může tato funkčnost pracovat: např. v původním systému Prytanis mohlo mezi dvěma zastávkami existovat více přejezdů, a nerozlišoval se směr; naproti tomu např. v aplikaci WinADO existuje mezi každými dvěma zastávkami nejvýše jeden přejezd, a přejezdy se zadávají pro každý směr zvlášť. Proto číselník přejezdů je navržen do značné míry jako konfigurovatelný administrátorem aplikace, který nastaví pro daný dopravní podnik nejvhodnější způsob používání přejezdů. Součástí tohoto balíku jsou v původním návrhu i číselníky krajů, okresů a obcí. Tyto budou pro aplikaci jízdní řády potřebné (např. u zastávky se zadává, do které obce náleží), ale přitom v současném stavu nebyly v systému navrženy.44 V důsledku ale budou součástí jádra systému, tedy v jiné komponentě, kterou bude komponenta jízdní řády používat. Druhou skupinou funkcionalit podobného ražení je package nazvaný Číselníky (viz obrázek 16). Jsou v něm obsažené různé editovatelné číselníky spadající pod aplikaci Jízdní řády, např. skupiny linek, číselník textů poznámek nebo termínových omezení nebo atributy zastávek na lince, některé z nich jsou editovatelné pouze administrátorem aplikace na dané instalaci. Zejména v tomto balíku se objevuje koncept obecných vlastností. Jde o to, že k lince se mohou v systému zadávat různé další doplňující informace, které mohou ale být u každého zákazníka různé, a navíc mohou být různé i u linek na jedné instalaci (u jednoho zákazníka), např. podle typu linky. Využijí se např. při spolupráci aplikace s jinými moduly nebo externími aplikacemi (např. Rezervační systém nebo Turnusy), nebo reprezentují specifické údaje, který nemají systémový význam (nereaguje se na ně v kódu), ale mají interní význam pro daného zákazníka, který je používá. Obdobně fungují i položky zastávek v číselníku zastávek, což jsou obecné a do jisté míry nastavitelné doplňující údaje zadávané k zastávce. K zastávce na lince (zastávce přiřazené na určité místo v lince) se zadávají atributy, podobného typu, které opět mohou být různé u jednotlivých zákazníků a různé i mezi zastávkami na lince (např. k první zastávce na lince se nebude zadávat, že je na znamení). 44
Současný stav byl takový, že se tyto jednotlivé údaje zadávaly k adrese pouze jako prostý text, bez nějakého výběru odkudkoliv. To je značně nevýhodné, mnohem lepší je hierarchie číselníků od státu až po obec, kdy každá nižší územní jednotka ví, do které vyšší náleží.
8.2
Analýza
69
Doufám, že z předchozího odstavce je zřetelně vidět analogická funkčnost. Nejde ale jen o aplikaci Jízdní řády, tento koncept lze nalézt v celém systému Prytanis, např. k obchodnímu partnerovi se zadávají jeho vlastnosti, k objednávce došlé v aplikaci Spedice doplňkové údaje k objednávce, apod. Re-use je tedy zcela zřejmé a také plánované, v systému existuje komponenta Obecné vlastnosti, která tuto funkčnost poskytuje (resp. jsou to dvě základní třídy DefiniceVlastnosti a HodnotaVlastnosti, class model bude uveden v části zabývající se analýzou), a která bude při implementaci použita i v aplikaci Jízdní řády. Nicméně zde ve fázi analýzy uvádím tyto funkčnosti zvlášť, a tedy lze říct že i duplicitně, a to z toho důvodu, že při analýze by neměly být brány v potaz otázky implementace, analýza je psaná z pohledu uživatele, a z jeho pohledu se jedná o nezávislé funkcionality. Package Linky, spoje a zastávky na lince (obrázek 17 na stránce 97) shrnuje vytvoření/základní editaci hlavičky linky, hlavičky spoje a hlavičky zastávky na lince.45 Linka je v systému pojatá jako matice Spoje × Zast´ avky, což odpovídá jejímu zobrazení na běžném vnitrostátním jízdním řádu, zde se tedy řeší pouze přidání/editace řádku této matice (zastávky na lince) a sloupce (spoje); samotné zadání časů odjezdů spojů z jednotlivých zastávek (tj. těla matice) je další funkcionalitou, obsaženou v balíku Hlavní editační okno. Package Hlavní editační okno (jeho diagram je uveden na obrázku 18) shrnuje práci se zadáním činností spojů na jednotlivých zastávkách linky, časů odjezdů spojů ze zastávek a vzdálenosti zastávek na jednotlivých spojích. Ačkoliv v use-case modelu se nejedná o příliš rozsáhlou oblast, při skutečné implementaci bude právě hlavní editační okno jednou z nejrozsáhlejších a nejobtížnějších částí, protože sdružuje poměrně značné množství možností zadání údajů a přitom musí být dobře pochopitelné a použitelné. Samozřejmostí jsou různé funkce pro kopii průběhu spoje, posun času, kopii kilometrovníků nebo rozpočítání časů podle zadané průměrné rychlosti spoje. Na tento balík navazuje package Přehled linek (obrázek 19), který obsahuje případy užití zabývající se prací uživatele s přehledem linek, tj. jednotlivé funkcionality z něj volané. Jde zejména o různé přečíslování linek, práci s archivem linek (jde o nástroj pro převedení dávno neplatných variant linek mimo hlavní část systému, aby bylo v hlavním přehledu linek pouze jejich únosné množství, a přitom se data starých variant linek neztratila). Do balíku Platnost a stavy linky (obrázek č. 20 na stránce 100) byly pak odděleny funkčnosti 45 Pro správu objektů všech tří těchto typů jsou psány případy užití trojmo, postupně pro přidání objektu, jeho opravu a smazání/zrušení. Tento způsob zápisu se objevuje i v některých dalších místech analýzy této aplikace (např. editace zastávek v číselníku). Re-use analýzy u této formy zápisu pak není zcela optimální. Existují různé názory na tento problém, souvisí s různými přístupy k rozsahu use-casu, a už jen k tomu, co vlastně ještě je use-case a co je jen rozšiřující/alternativní tok jiného use-casu. Zatímco někteří analytici pak považují přidání nového záznamu, opravu a smazání jen za jednotlivé alternativní toky jednoho use-casu, který nazývají editace, setkal jsem se i s přístupem, kdy bylo vyplnění každé části formuláře záznamu (např. jedné karty) modelováno jako jeden případ užití. Já ve své práci zachovávám víceméně kompromisní přístup, přidání/opravu/smazání rozlišuji u záznamů, kde je každá tato činnost i funkčně jiná (např. jsou v ní obsažené jiné validace, některé údaje jsou v případě opravy needitovatelné apod.), zatímco u jednoduchých číselníků je sdružuji do jednoho use-casu. Pokud mají být tyto tři činnosti s objektem modelovány zvlášť, existuje více řešení jejich namodelování. Jedním z nich je použít mezi nimi vztah gen-spec, kdy se vytvoří use-case Detail záznamu (odpovídá needitovatelnému zobrazení), na který se navážou společné funkčnosti, a případy užití pro přidání/opravu/smazání záznamu se na něj navážou jako jeho specializace. Použití gen-spec ale diagram případů užití poněkud znepřehledňuje, proto používám ne zcela čistý (ale přehlednější) způsob, když jeden z těchto případů užití popíši podrobně, včetně zobrazené sestavy (zpravidla přidání nebo detail), a ostatní popíši pouze zhruba, s odkazy v textu na příslušné toky podrobně popsaného use-casu.
70
8
TVORBA MODULU JÍZDNÍ ŘÁDY
týkající se stavů linek a práci s jejich platností (splatnění, ukončení platnosti apod.), protože tyto akce mají vazby mimo aplikaci Jízdní řády – pokud je varianta linky označená za platnou, promítají se všechny s ní prováděné akce do aplikace Turnusy, popř. i do Rezervačního a předprodejního systému či dalších modulů systému Prytanis. V sedmém balíku (package Doplňkové informace k linkám, na obrázku 21) se nacházejí případy užití zajišťující zadávání doplňkových údajů k linkám a spojům. Jde o údaje, které nejsou přímo nezbytné pro práci v systému, ale projeví se při různých exportech do datových formátů jiných aplikací nebo při spolupráci aplikace Jízdní řády s ostatními moduly systému. Je sem umístěno také zadání hodnot parametrů linky, položek zastávky v číselníku zastávek a atributů zastávky na lince, jejichž definice jsou zakresleny v balíku Číselníky. Posledním navrženým balíkem (tj. skupinou souvisejících případů užití) je Importy, exporty a tisky (na obrázku č. 22, stránce 102), v něm obsažené use-casy se týkají vstupu a výstupu dat do aplikace a zejména tiskového výstupu. Lze zde najít i číselníky související s tiskem, zejména Typy tisku a Formáty tisku. Rozdíl mezi nimi je v tom, že zatímco typ tisku specifikuje tištěné údaje a způsob jejich organizace, formát tisku určuje fyzické formátování tiskového výstupu (okraje, zvětšení/zmenšení, otočení apod.). Dokumentace případů užití Jak jsem již zmínil v části teoretické studie věnované use-casům, use-case model není úplný, pokud nejsou jednotlivé případy užití popsány a zdokumentovány, co do průběhu. Jde tedy o zachycení toků událostí use-casu. Pokud má však být zachován požadavek na přesný a jednoznačný popis use-casů, vede to k tomu, že dokumentace jednoho případu užití se může natáhnout na několik stránek dokumentu. Z tohoto důvodu neuvádím v této práci popisy všech sedmdesáti use-casů obsažených v analýze aplikace, ale pouze popis jednoho z nich na ukázku. Jako vhodný případ užití jsem zvolil Založení zastávky v číselníku zastávek, jehož dokumentace je uvedena v příloze C. Samotnou formální úpravu dokumentu je možno pro export z Enterprise Architectu poměrně dobře nakonfigurovat, takže lze dosáhnout i dobře čitelného strukturovaného výstupu ve formě tabulek; zde ukazuji pouze nejjednodušší formát s odrážkovými seznamy. Dokumentace k tomuto případu užití, jak byla zadána v Enterprise Architectu, obsahuje • Název use-casu • Stručný textový popis, aby každý, kdo případ use-case dostane do ruky, zhruba pochopil, o co v něm jde. Ve skutečnosti se jedná o textový element Note, který lze podle standardu UML zadávat ke všem elementům. • Omezení běhu use-casu a jiné externí okolnosti ovlivňující jeho průběh – např. oprávnění přihlášeného uživatele, popis konstant ovlivňujících běh use-casu apod. • Toky událostí – již v kapitole Teoretická studie jsem zmínil problém Enterprise Architectu, když nemá žádný nástroj pro zadání toků use-casů. K tomuto lze využít (a také využívám) záložku Scenarios na detailu use-casu, která je sice zřejmě původně určená pro scénáře, ale je dobře použitelná i pro evidenci toků daného use-casu. Toky mohou být základní, rozšiřující nebo alternativní, přičemž rozdíl mezi rozšiřujícím a alternativním tokem je poněkud subjektivní a nejednoznačný. V prezentovaném případu
8.2
Analýza
71
užití jsou tedy jeden základní tok a čtyři rozšiřující (v podstatě podrobněji rozepisují základní tok událostí). • Návrh sestavy, co se jednotlivých polí na formuláři týče, zejména jejich typu, povinnosti, výchozí hodnoty a stručného popisu významu pole a práce uživatele s ním. V Enterprise Architectu lze zadat pole pomocí volby Attributes nad označeným use-casem.46 Nicméně nelze snadno odlišit jednoduché pole od sloupců v tabulkách/seznamech, proto druhou možností zůstává zadání sestavy v běžném textovém procesoru, kde lze snadno a přehledně zadat všechny potřebné údaje o polích sestavy. Konceptuální class model Na obrázku 31 je navržen základní konceptuální model tříd aplikace jízdní řády. Pokusil jsem se celý model tříd vměstnat do jednoho diagramu za účelem komplexního vyjádření vztahů mezi jednotlivými pojmy, čímž ale bohužel došlo k jeho značnému rozsahu, takže jsem upustil od zobrazení všech atomických atributů a prezentuji na tomto diagramu pouze samotné pojmy a jejich vztahy (viz obrázek č. 31). Zde se tedy pokusím o stručný popis tohoto modelu, a tedy pojmů (tříd) v tvořeném systému. Samozřejmě je nutné připomenout, že skutečná implementace (tj. které z pojmů budou skutečně třídami podle tohoto návrhu, a které se naopak ještě rozpadnou na více tříd, které budou jejich funkčnost zajišťovat) je až otázkou fáze designu, analytický class model je spíše prvním popisem vztahů objektové problémové domény, který má pak být při návrhu využit jako podklad. Existuje číselník zastávek, jde o všechny zastávky znovupoužitelné v rámci všech linek systému. Zastávka leží v určité obci, která zase v další úrovni hierarchického členění územních jednotek (okres/kraj/stát). K zastávkám lze zadávat nástupiště, pokud je zájem je centrálně evidovat. V systému se dále evidují přejezdy mezi zastávkami, které specifikují vzdálenosti mezi dvěma zastávkami. Základním objektem celé aplikace je linka. Každá linka náleží k nějakému typu linky, pokud je zájem členit linky do skupin, tak i do libovolného počtu skupin linek. Každá linka obsahuje seznam zastávek na lince, ty se vybírají z číselníku zastávek, zastávka na lince si zejména drží informace o pořadí v rámci linky. K lince lze zadat vzdálenosti mezi jednotlivými zastávkami na ní (buď jako jeden z přejezdů z číselníku přejezdů, nebo jako konkrétní hodnoty jen pro tyto dvě zastávky na této lince, pokud je to nastavením systému povoleno). Kromě toho obsahuje linka i N spojů. Každý spoj ale nejede všemi zastávkami, spoje jezdí po různých trasách (za trasu berme průběh zastávek, kde spoj zastavuje/projíždí). Spoje se dělí na dva směry (tj. každý spoj si nese údaj o tom, jestli jede ve směru od první zastávky do poslední, nebo od poslední do první). Dále si spoj může nést informaci o vzdálenosti mezi svými každými dvěma zastávkami, pokud se vzdálenosti mezi zastávkami nezadávají již k lince jako celku. Každý spoj má údaje o tom, kdy jede, tj. své omezení, které mohou být jednak základní kalendářní (např. že jede v pracovní dny a soboty), a jednak termínové (např. 46
Je velice potřebné nějakým způsobem strukturovaně zaznamenat všechny položky, které uživatel na formuláři v průběhu jednoho případu užití zadá. Zadávání atributů – sestavy – k use-casům není prvek standardu UML, nicméně Enterprise Architect to umožňuje (těžko říct, zda to bylo záměrem jeho tvůrců) díky tomu, že v objektovém schématu UML modelu používaném Enterprise Architectem je seznam atributů elementu obsažený již v bázové třídě společné pro všechny UML elementy.
72
8
TVORBA MODULU JÍZDNÍ ŘÁDY
nejede 24. 12. a 31. 12.). Ke spoji se navíc zadává dopravní podnik a pobočka, která spoj zajišťuje (protože na jedné lince může spoje provozovat více různých dopravců). Údaj o činnosti (a času) jednoho spoje linky na jedné zastávce linky nese objekt zastávka na spoji, která pojmově odpovídá jednotlivým políčkům v matici jízdního řádu linky (spoje odpovídají záhlaví sloupců a zastávky na lince řádkům). Na každé zastávce na spoji se eviduje jednak činnost spoje (příjezd/odjezd/průjezd apod.), a jednak čas. Kromě toho se k zastávce na spoji zadává větší množství doplňkových údajů, jako například přestupy na jiné spoje či doplňkové poznámky pro export, lze zadat i konkrétní nástupiště, z kterého spoj ze zastávky odjíždí. K lince, spojům, zastávkám na lince i zastávkám na spoji lze zadávat poznámky. Jedná se o odborný termín, poznámky představují doplňkové údaje, které se tisknou pod samotný jízdní řád linky, často nesou nějakou dodatečnou informaci o objektu, ke kterému patří, bývají doplněny značkou (např. se může jednat o údaj, že spoj pokračuje jako jiná linka dále určitým směrem, nebo že na dané zastávce na spoji není možný nástup, ale pouze výstup). V systému je navržen číselník textů poznámek, odkud je možné je vybírat. Na typy linek se váží typy tisku a potažmo i formáty tisku, pro jednotlivé dopravní podniky, které používají systém pro správu linek, jsou pak definované šablony pro tisk. Kromě toho se na typ linky váže i výchozí přepravní systém, ale jde jen o výchozí hodnotu, ke konkrétním linkám, a dokonce i spojům v rámci linky, lze zadat jiný. Jak již bylo výše zmíněno, k některým objektům se zadávají další volitelné doplňující údaje, jako např. položky k zastávce, parametry k lince nebo atributy k zastávce na lince. V této fázi je ještě uvádím jako nezávislé pojmy, pouze s podobnou strukturou, ale v implementačním class modelu bude již znázorněno, že jsou všechny tři implementovány pomocí stejného mechanizmu Obecných vlastností. Popis class modelu, jak jsem ho tu nyní uvedl, je do značné míry hrubý a konceptuální, snahou zde bylo zejména představit základní pojmy a vztahy mezi nimi. Podrobná specifikace těchto jednotlivých pojmů i vztahů, které nebyly v tomto textu zmíněny, jsou součástí dokumentace k use-case modelu, a také k tomuto implementačnímu modelu tříd, ale pro její velký rozsah ji zde raději neuvádím. Použití dalších analytických modelů Jak jsem již psal výše, sekvenční diagram dokáže značně zpřehlednit složitější scénář interakce objektů. V prezentované analýze je ale většina toků/scénářů jednoduchých, neobsahují žádné složitější spolupráce objektů, většinu obsahu dokumentace případů užití pokrývají popisy, které údaje uživatel zadává, popř. odkud je vybírá, jaké jsou možné hodnoty a co se kontroluje/validuje, dynamické chování objektů je v těchto popisech v menšině, protože je zpravidla intuitivní. Dokumentace, tj. textový popis toho, co se v jeho průběhu děje, je tedy pro většinu jednoduchých use-casů dostačující. Nicméně několik use-casů v aplikaci vykazuje složitější scénáře spolupráce objektů, takže u nich byl sekvenční model sestaven, jde např. o kontrolu linky, přidání zastávky na linku nebo přidání spoje na linku (jeho sekvenční diagram je na ukázku na obrázku č. 23 v příloze C). V dalším textu popíši právě tento sekvenční model. Na počátku tohoto scénáře pracuje uživatel s uživatelským rozhraním (UI vrstva aplikace, v diagramu je označená jako GUI), které má přístup k editované lince, a ta si zase „držíÿ seznam zastávek na lince a seznam spojů. Když dá uživatel UI vrstvě příkaz
8.3
Návrh a implementace
73
k přidání spoje, zavolá tato metodu linky. Objekt linka nejprve provede ověření, jestli není stav linky platná, protože je určeno, že na platnou linku není možné přidávat spoje. V případě, že se skutečně jedná o platnou linku, je BL vrstvou, konkrétně linkou, vyhozena výjimka, kterou si UI chytí a ohlásí uživateli chybu47 , čímž případ užití končí, což je zřejmé z použití Combined Fragmentu break. Pokud není linka platná, je vytvořen nový spoj, a UI zobrazí uživateli formulář pro zadání údajů nově vytvářeného spoje. Uživatel tyto údaje postupně zadá (zde se jedná o spoustu jednoduchých sekvencí zpráv typu uživatel zadá hodnotu do formuláře, UI ji vloží do objektu, která se opakuje N -krát pro každý údaj ve formuláři, popř. s případnými validacemi těchto údajů), a dá příkaz k uložení nového spoje. Uživatelské rozhraní zavolá metodu Save() nad linkou, a ta inicializuje uložení nového spoje. Poté je potřeba vytvořit zastávky na tomto spoji (lze si to představit tak, že do tabulky představující jízdní řád přibyl nový spoj – tj. sloupec – a teď je třeba zadat činnosti tohoto spoje na všech zastávkách linky – tj. vyplnit pole ve sloupci tohoto spoje, ve všech řádcích představujících zastávky na lince). Proto je N -krát, pro každou zastávku na lince, zadána ke spoji jeho činnost na této zastávce na lince (resp. je vytvořen objekt zastávka na spoji, která tento údaj nese). Poté, co všechno úspěšně proběhne, vrátí linka uživatelskému rozhraní údaj o tom, že byla v pořádku uložena, a UI toto ohlásí uživateli. Užitečným modelem je také stavový model. Použil jsem ho pro naznačení stavů linky a jejích přechodů (viz obrázek č. 24). Rozlišuji zde čtyři stavy: běžnou neplatnou linku, platnou linku s otevřeným obdobím platnosti, platnou linku s uzavřenou platností (je zadáno, do kdy platí), a archivovanou linku. Stavy platná s otevřenou platností a platná s uzavřenou platností by bylo možné také vyjádřit jako dva dílčí stavy – součásti composite stavu platná. Jistě by bylo možné vytvořit i další pomocné analytické diagramy pro další entity systému. Je ale vhodné pomocí těchto pomocných analytických diagramů popisovat pouze scénáře a situace, kde je to nutné a kde by bez těchto modelů mohly nastat problémy s jejich pochopením. Modelovat i jednoduché a jednoznačné případy není účelné, protože tvorba těchto modelů pouze zdržuje a odvádí pozornost od návrhu a implementace samotného systému, a z ekonomického hlediska je tedy ztrátová.
8.3
Návrh a implementace
Ve fázi návrhu jde hlavně o postupné vytvoření class modelu systému. Podstatným faktem ale je, že při vývoji je používána iterativní a inkrementální metoda, takže systém je tvořen po menších přírůstcích. Důsledekem toho je, že implementační class model není vytvořen zaráz, ale je modelován postupně, po jednotlivých iteracích. Pořadí jednotlivých přírůstků, po kterých bude vývoj probíhat, přitom hrubě odpovídá balíkům v use-case modelu: 1. Číselník zastávek a přejezdů 2. Ostatní základní číselníky aplikace – číselník termínových omezení, textů poznámek, stavů linek, skupin linek apod. 47
Tato koncepce validací a ošetření chyb je použita v celé aplikaci Jízdní řády, stejně jako v celém systému Prytanis. Objekty BL vrstvy v případě, že dojde k chybě, vyhodí výjimku (v C# klauzule throw), kterou prvek UI vrstvy – zpravidla formulář – očekává a chytí ji (konstrukce try {...} catch {...} [finally {...}]), a nějak na ni zareaguje (většinou ohlásí chybu uživateli).
74
8
TVORBA MODULU JÍZDNÍ ŘÁDY
3. Zadání hlavičky linky, hlavičky spoje a nové zastávky na lince 4. Hlavní editační okno – činnosti a časy spojů na jednotlivých zastávkách na lince 5. Přehled linek, archiv, archivace, hromadné činnosti volané z přehledu – např. přečíslování linek 6. Platnost linek, splatnění, ukončení a otevření platnosti linky 7. Evidence licencí na linky 8. Doplňkové údaje k linkám, spojům a zastávkám – různé přestupy na zastávce na spoji, tabulky MHD, zvláštní kilometrovníky apod. 9. Nastavení tisku a tisk 10. Importy a exporty Z tohoto důvodu je class model tvořen postupně. Jako základ, před první iterací, je vzat konceptuální class model, s menšími úpravami (rozepsání zřejmých vztahů M : N ). Ukázky několika prvních výseků class modelu jsou uvedeny v příloze na konci této práce. Třídy jsou na diagramech vyvedeny v různých barvách, které mají svůj význam: béžová (výchozí) znamená navrhovanou (nenaimplementovanou) třídu, oranžová částečně hotovou (tj. třídu, na které se právě pracuje), a zelená zcela hotovou. Návrh modulu jako součásti systému Prytanis Celá aplikace Jízdní řády není osamoceným softwarovým dílem, ale je součástí rozsáhlého podnikového informačního systému. Je tedy logické, že není možné provést její návrh izolovaně, ale pouze v kontextu návrhu celého systému, a zajistit tímto spolupráci modulu se zbytkem systému Prytanis. Zejména jde o to, že se v class modelu aplikace Jízdní řády objevují třídy a další elementy z ostatních modulů a aplikací, zatímco třídy a elementy z Jízdních řádů zase mohou být používány v jiných částech systému (např. v plánované aplikaci Turnusy nebo Plán osobní dopravy). Aplikace Jízdní řády je přitom takového charakteru, že není příliš závislá na ostatních částech systému, ale přitom tvoří základ, na který bude nastavovaný subsystém pro řízení osobní dopravy (je to pěkně vidět i z procesního diagramu na obrázku 30). Lze tedy říct, že nevyužívá jednotlivé business subsystémy, ale pouze společné části, jádro systému, které využívají téměř všechny aplikace a moduly. Společné části systému pokrývají řadu činností, které by si samostatně stojící aplikace musela řešit sama. Lze zmínit autorizaci a oprávnění uživatelů (řeší společná komponenta Autorizace), logování (třída Log v komponentě Logovani) a práce s proměnnými/přepínači ovlivňujícími chování aplikace (komponenta Konstanty). Návrh business tříd je založen na návrhovém vzoru Layer Supertype. Všechny business třídy v tvořeném modulu, stejně jako ostatní business třídy v celém systému, jsou odvozené od společného předka, třídy BusinessObjectBase, která zejména zajišťuje jejich perzistenci, všechny vnořené kolekce (vztah master-detail ) jsou realizovány třídou BusinessCollectionBase či jejím potomkem. Důsledkem je pak značná automatizace načítání a ukládání dat do báze dat, protože řešení perzistence je založeno na použití technologie eXpress Persistent Objects (třída BusinessObjectBase dědí XPLiteObject a třída BusinessCollectionBase je specializací třídy XPCollection), podrobněji o těchto dvou bázových třídách pojednám v části Implentace. Základní třídy pro business objekty jsou umístěny v komponentě Base, ve které jsou kromě toho v její UI vrstvě základní třídy pro formuláře, od kterých jsou běžné aplikační
8.3
Návrh a implementace
75
formuláře odvozovány s tím cílem, že se dosáhne poměrně jednotného vzhledu a ovládání celého systému (konkrétně je to ViewForm pro seznam/přehled položek a DetailForm pro zobrazení/editaci jedné položky). V Jízdních řádech se navíc využijí business třídy společné pro celý systém a používané různými komponentami, např. Stat a Adresa umístěné ve společné komponentě Adresy nebo třídy ObchodniPartner a Stredisko (tj. pobočka obchodního partnera) z komponenty ObchodniPartneri. Poslední aplikací používanou komponentou, kterou bych zde chtěl zmínit, je komponenta ObecneVlastnosti, která zobecňuje zadávání doplňkových informací ve tvaru atribut-hodnota k objektům business tříd. Tyto se objevují i v jízdních řádech (položky zastávky, atributy zastávky na spoji nebo parametry linky) a kromě toho se tento koncept používá v celém systému (např. vlastnosti obchodního partnera, doplňkové údaje k objednávce ve spedici). Diagram tříd BL vrstvy obecných vlastností je uveden na obrázku č. 25. Dvě základní třídy jsou DefiniceVlastnosti (představuje definici atributu, ke kterému se zadává hodnota) a Vlastnost (drží hodnotu, a odkaz na definici atributu). V definici vlastnosti se nastaví, jakého typu je hodnota vlastnosti 1. Doslovná hodnota některého z běžných datových typů – např. číslo, řetězec nebo příznak (logická hodnota ano/ne) 2. Vazba do některého v systému existujícího číselníku 3. Výběr z několika předdefinovaných možností – tyto se defininují při zadání atributu, v modelu tříd to vypadá tak, že třída DefiniceVlastnosti obsahuje kolekci možných hodnot, což jsou instance agregované třídy HodnotaCiselniku (lze si představit, že tyto hodnoty tvoří jakýsi anonymní číselník možných hodnot použitý pouze u tohoto atributu) K obecným vlastnostem existuje také UI vrstva, která obsahuje grafický prvek pro práci s obecnými vlastnostmi, ve formě User controlu, který lze na formulářích objektů obsahujících obecné vlastnosti použít. Perzistence objektů a datový model Jak jsem již výše uvedl, celý systém Prytanis je primárně vyvíjen nad RDBMS Ingres. Vzhledem k tomu, že k perzistenci business objektů je použita technologie eXpress Persistent Objects, předpokládá se ale možnost nasazení i na jiných relačních databázových systémech, podle požadavků konkrétních zákazníků. Zatímco při přímém ručním O/R mapování je třeba jednak sestavit datový model aplikace (tj. entitně-relační diagram) a podle něj DDL příkazy pro vytvoření konkrétních datových struktur (např. CREATE TABLE), a jednak psát v jazyce SQL konkrétní příkazy na dotazování a modifikaci báze dat, zpravidla v DB vrstvě aplikace, při použití technologie XPO: • Jednoznačně odpadá potřeba psaní DML dotazů (příkazy INSERT, UPDATE a DELETE), protože vše se provádí automaticky, stačí nad příslušným objektem zavolat jeho metodu Save() pro uložení nového nebo změněného objektu. Výmaz se provádí analogicky voláním metody Delete().
76
8
TVORBA MODULU JÍZDNÍ ŘÁDY
• Dotazy na bázi dat se nepíší v jazyce SQL (a nejsou tedy závislé na použitém databázovém systému), ale jako volání objektových kvazidotazů48 , které jádro XPO (konkrétně třída Session) převádí na dotazy v SQL dialektu daného databázového stroje. • To, zda bude potřebné tvořit ERD a DDL skripty, závisí na nastavení módu XPO (konkrétně jde o nastavení property Session.AutoCreateOption). Při automatickém režimu toto není třeba, protože XPO tvoří v databází příslušné struktury samo, zatímco při plně manuálním režimu (nastavení AutoCreateOption.None) je potřeba namodelovat ERD a podle něj vytvořit v databázi tabulky, do kterých budou data ukládána. Ve vytvářeném informačním systému Prytanis v prostředí .NET se používá XPO v plně manuálním režimu. Při vývoji je tedy třeba sestavit i datový model a DDL skripty, které jsou samy o sobě databázově závislé. V dalším textu budu mluvit o ERD a DDL vytvořeném pro RDBMS Ingres, při použití systému nad jinými databázovými systémy by musely být skripty pro definici tabulek vytvořeny znovu, zpravidla hlavně kvůli odlišným názvům datových typů. Datový model (resp. jeho výseky – dílčí entitně-relační diagramy) vznikají ve fázi návrhu v těsné návaznosti na model tříd. Zpravidla tedy v každém přírůstku, když je vytvořen class model v něm použitých tříd, tak je vytvořen i odpovídající entitně-relační diagram a z něj sestaveny DDL příkazy. Několik ERD (k class diagramům aplikace) je jako ukázka uvedeno v příloze D. Ve všech tabulkách business tříd se vyskytují tři sloupce id, state a lock. Sloupec id představuje unikátní identifikátor objektu, který XPO při uložení nového objektu inkrementuje. V tabulkách se až na výjimky nemaže „natvrdoÿ přímo z databáze, ale objekty se pouze označí jako smazané (neaktivní). Toto udává sloupec state, který nabývá 1 (hodnota enumerace ObjState.Active) pro platné záznamy a 0 (ObjState.Inactive) pro smazané. Toto není výchozí chování XPO (XPO samo maže přímo z tabulek voláním DELETE), ale jde o úpravu v bázové třídě business objektů, používanou v systému Prytanis. Sloupec lock pak slouží pro zajištění integrity souběžných operací pomocí Optimistic Concurrency, kdy je při každém uložení objektu inkrementován o 1, a objekt díky tomu při svém ukládání pozná, zda nebyla mezitím provedena změna jeho dat v databázi (podrobněji je tato technika popsána v sekci týkající se O/R mapování). Zvláštní pozornost si zaslouží obecné třídy (a jejich tabulky) používané v aplikaci, ať již třída Souradnice pro správu GPS a jiných souřadnic zastávky a jejích nástupišť, nebo třída Vlastnost držící hodnotu jednotlivých doplňkových údajů objektů (např. položek zastávek nebo parametrů linek). Zde bylo potřebné rozhodnout, jestli se pro ně vytvoří zvláštní tabulky pro objekty pouze z aplikace Jízdní řády, nebo se použijí tabulky z já48
Např. dotaz
SELECT * FROM zastavky WHERE vyhledavaci_kod = :kod AND state = 1 se přepíše při použití nativního XPO dotazu takto (vezměme, že ObjState je enumerace, kde pojmenovaná hodnota Active odpovídá číselné hodnotě 1): Session.FindObject(new GroupOperator(GroupOperatorType.And, new BinaryOperator("VyhledavaciKod", kod), new BinaryOperator("State", ObjState.Active)));
8.3
Návrh a implementace
77
dra systému, zejména v souvislosti s očekávaným množstvím dat umístěných v těchto tabulkách. Hodnoty obecných vlastností jsou navržené tak, že mohou být uloženy centrálně ve společné tabulce, ale častěji se používá případ, kdy jsou při každém výskytu hodnoty vlastností ukládány do zvláštní tabulky (takže v jedné tabulce budou položky zastávek, v druhé parametry linky a v třetí třeba vlastnosti obchodního partnera z aplikace Obchodní partneři). Ukládání ve zvláštních tabulkách nakonec budu používat i zde v aplikaci Jízdní řády, a to zejména z důvodu množství dat (ke každé zastávce se už ve výchozí instalaci počítá s dvanácti položkami, které bude možné zadat, nehledě na to, že další bude moci libovolně přidávat administrátor aplikace u každého zákazníka). Implementace Poté, co je pro každý přírůstek sestaven class model a erd, a vytvořeny příslušné datové struktury (tabulky) v bázi dat, je možné přistoupit k samotné implementaci. Ta je při použití modelovacího nástroje Enterprise Architect usnadněna tím, že z modelu tříd je možné vygenerovat zdrojový kód tříd, tj. deklarace fieldů a hlavičky subrutin (metod, properties apod.), takže stačí pouze doplnit výkonný kód – těla subrutin. Výsledkem této práce je hotová business třída, jedna taková kratší třída je na ukázku vložena do přílohy D.49 Další, lze říct že ještě náročnější prací, je poté naprogramovat prezentační logiku, tj. formulář a interakci s uživatelem, kde se zhusta využívá událostního programování, tím způsobem, že systém reaguje na události, které uživatel svými akcemi vyvolává (např. kliknutí na tlačítko, zadání hodnoty do textového pole apod.). Sama tvorba formuláře detailu položky je poměrně zdlouhavá (na rozdíl od formuláře přehledu, který lze do značné míry zautomatizovat použitím předpřipravených komponent), nicméně díky použití bázových formulářů lze dosáhnout poměrně solidní jednoty vzhledu uživatelského rozhraní. Ukázka několika formulářů je v příloze D na stránce ??. Testování Nedílnou součástí vývoje je i průběžné testování, a to zejména moderními metodikami doporučené jednotkové testy, které je možné snadno zautomatizovat a lze je provést po každém zásahu do zdrojového kódu. Mnohdy se doporučuje vytvořit je celé podle specifikace designera před započetím psaní kódu, a i pokud ne, tak co nejdříve v průběhu kódování. 49
Původně jsem měl v úmyslu dát do přílohy třídu, v jejímž funkčním kódu se doopravdy něco provádí, např. jsem uvažoval o třídě Zastavka. Tato má ale ke dni psaní této části (1. května 2008) ke 1200 řádkům, takže vyšla na zhruba 25 stran příloh. Došel jsem k názoru, že je to přece jenom příliš; bohužel pokud má být zdrojový kód tříd v jazyce C# aspoň trochu přehledný, nelze ho zkrátit odebráním prázdných řádků či seskupením více příkazů na méně řádků – pak by sice zabral méně stránek přílohy, ale pro čtenáře by nebyl srozumitelný. Rozhodl jsem se tedy nakonec uvést jako příklad pouze jednoduchou business třídu s několika málo fieldy, která navíc ani neobsahuje žádné složitější funkčnosti, slouží víceméně pouze jako dataholder, tj. drží data náležející jednomu řádku databázové tabulky a obsahuje properties pro přístup k nim a metody pro jejich základní obsluhu a validaci. Nicméně její struktura je stejná jako u rozsáhlejších tříd s větším počtem metod konajících složitější funkce, např. si i na této třídě lze povšimnout použití deklarativních atributů [Persistent()] a [PersistentAlias()] nad fieldy a properties třídy.
78
8
TVORBA MODULU JÍZDNÍ ŘÁDY
Pokud je pro automatizaci testů v prostředí .NET použit nástron NUnit, lze dosáhnout pomocí atributů nad jednotlivými metodami testovací třídy poměrně snadno nastavení specifikace testů. Základním atributem je [TextFixture], který označuje třídu obsahující testovací metody, jednotlivé testovací metody jsou označovány atributem [Test], lze je členit do skupin použitím atributu [Category()] apod. Celkem obsahuje framework NUnit jedenáct takovýchto atributů pro deklarativní popis testu. Ukázka testovací třídy (zkrácená) pro otestování business třídy Nastupiste je uvedena v příloze D. Použití atributů pro nastavení testování bylo dlouhou dobu specifikem frameworku NUnit, ostatní testovací frameworky rodiny xUnit řešily nastavení testů pomocí dědičnosti a konvencí pro pojmenování (např. název testovacích metod musel začínat na „testÿ, metoda volaná před každým testem se musela jmenovat „SetUpÿ apod.), až v JUnit verze 4 je použit podobný přístup založený na popisných metainformacích o metodách, jako v NUnit. Tento přístup je obecně výhodnější, protože umožňuje větší variabilitu testovacích tříd a jejich metod, a přitom i přehlednější.
9
9
DISKUZE
79
Diskuze
Na závěr této práce by bylo vhodné ji kriticky zhodnotit, a to zejména v ní dosažené výsledky, ve srovnání s jinými alternativami, neboť, stejně jako v každé jiné oblasti lidského konání, se vždy nabízí více možností, jak daný problém pojmout a zpracovat. Poměrně rozsáhlá část této práce byla věnována teoretické studii, tj. shrnutí a zhodnocení již dosažených poznatků. Zhodnocení již dříve dosažených poznatků by pochopitelně měl být základ každé odborné práce. Analýza a návrh softwaru, a softwarové modelování obecně, se ale z odborného pohledu řadí spíše do skupiny empirických vědních oborů. Na rozdíl od exaktních věd (např. matematika), kdy se buď dané tvrzení dokáže a je tedy pravdivé, a nebo se prokáže, že pravdivé není, většina tvrzení a názorů v této oblasti má tedy spíše relativní charakter, jde spíše o doporučení, která v určitém kontextu jsou pochopitelná a logicky správná, zatímco v jiné situaci není příliš vhodné doslova se jich držet. S takovýmto náhledem je tedy nutné hodnotit většinu výroků a názorů v kapitole Teoretická studie. Koneckonců, v odborné literatuře se uvádí, že vývoj softwaru je neustálé rozhodování mezi různými alternativami, z nichž žádná není obecně lepší nebo horší, ale pro každou je nutné v dané situaci hodnotit klady a zápory jejího nasazení. S tímto souvisí fakt, že na vývoj softwaru existuje větší množství názorů, často i protichůdných, které však vzhledem k charakteru vědy není možné nijak zredukovat. Důsledkem tedy je, že kapitola Teoretická studie je poněkud obsažnější, přičemž nebylo možné ji rozumně zkrátit, aniž by byly vynechány zásadní poznatky a názory. Při čtení této práce se může zdát, že samotná praktická část, tj. řešení uvedeného problému, je ve srovnání s teoretickou studií poměrně krátké a neúplné. Důvodem je ale to, že část samotného obsahu práce – mnou dosažené poznatky a názory – uvádím v teoretické části práce, často jako hodnocení uvedených přístupů. Pokud by totiž měly být uvedeny zvlášť, ztratila by se určitá kontextová souvislost. Proto tedy v části Teoretická studie uvádím jednak informace a názory získané z odborné literatury, a jednak zkušenosti a poznatky získané mnou, popř. mými kolegy v rámci vývoje informačního systému Prytanis na platformě .NET, zatímco v části Tvorba modulu pak již uvádím pouze praktické aspekty řešení. Samotná praktická část se může zdát poměrně krátká na to, jak problém uvádím teoreticky. Tento fakt má ještě několik dalších vysvětlení. Jednak je samozřejmě potřebné uvést, že hlavní jádro praktické části, tj. modely systému, jsou uvedeny v příloze. Navíc ale v případě většiny modelů zůstávám pouze u jejich grafického zobrazení diagramy, neuvádím zde tedy kompletní dokumentaci modelů s popisy jednotlivých elementů. Toto je obzvláště výrazně vidět u use-case modelu, kdy jsem uvedl pouze kompletní use-case model (rozdělený pro přehlednost na několik diagramů) a na ukázku dokumentaci jednoho z navržených 70 případů užití. Důvodem je samozřejmě rozumný rozsah práce – např. samotná dokumentace všech případů užití vyjde v době psaní tohoto textu (19. května 2008) na 123 stran, což by bylo více než samotná diplomová práce bez příloh. V práci navíc až na výjimky neuvádím téměř žádný zdrojový kód aplikace, což může vyvolávat dojem, že jsem implementaci poněkud odbyl. Skutečným důvodem ale je, že nechci příliš zabředávat do zdrojového kódu aplikace, zejména z toho důvodu, že je velice rozsáhlý (jen ukázka jednoduché třídy Nastupiste vyšla na osm stran), a je závislý na řešení celého systému Prytanis, takže bez delšího popisu a komentáře stejně čtenáři sám o sobě nic neřekne. Doposud jsem mluvil o kódu business tříd v BL vrstvě aplikace;
80
9
DISKUZE
zdrojový kód UI vrstvy tvoří zvláštní kapitolu, a to v tom smyslu, že je ještě rozsáhlejší, a oproti kódu BL vrstvy pro čtenáře také méně srozumitelný a přínosný. Zjednodušeně řečeno, nelze čekat, že do této své práce vložím kompletní zdrojový kód aplikace Jízdní řády. Se zveřejňováním kompletní dokumentace a zdrojového kódu souvisí i otázka práv k softwarovému dílu, jímž aplikace Jízdní řády je. Systém jako takový je vyvíjen v rámci mé pracovní činnosti ve firmě Unis Computers, spol. s r. o., a tedy veškerá dokumentace i zdrojové kódy jsou z právního hlediska majetkem této společnosti. Systém není vyvíjen pod žádnou otevřenou licencí (např. GPL), ale zdrojové kódy jsou majetkem spoječnosti a jsou ve své podstatě tajné; i kdyby to bylo technicky možné (což jsem v předchozím odstavci zdůraznil, že není), nelze tedy očekávat, že do této práce dám kompletní dokumentaci všech modelů a zejména veškeré zdrojové kódy aplikace. Celou kompletní implementaci modulu se nepodařilo dokončit. Bohužel až při analýze (tvorbě use-case modelu) se ukázalo, kolik různých funkcionalit je od systému očekáváno, jednak vedoucím vývoje, a jednak potenciálními zákazníky, se kterými byla analýza konzultována. Use-case model se postupně rozrůstal od plánovaných 35 případů užití, které přibližně identifikoval vedoucí vývoje, když mi práci zadával, až po 70, některé požadavky různých zákazníků byly navíc značně rozmanité či místy protichůdné. Zapracovat vše do analýzy proto zabralo podstatně delší čas, než jsem zpočátku očekával (dá se říct, že se jedná o typickou chybu programátora/analytika podcenění složitosti problému). Samotný návrh a implementace je poté realizována inkrementální a iterativní metodou, což vede k tomu, že se aplikace vyvíjí postupně – místo aby byl systém vyvinut naráz jako celek, probíhá implementace po přírůstcích, když každý přírůstek je konzultován s budoucími uživateli a upravován, což sice zvýší dobu vývoje ve srovnání s první nějakým způsobem funkční verzí vyvinutou naráz, ale ve výsledku je software vyvinut rychleji a v lepší kvalitě díky tomu, že je dříve známá zpětná vazba na přírůstek. Z předchozího odstavce vyplývá, že není a ani nemůže být prezentována celá kompletní naprogramovaná aplikace. Ne že by to bylo zásadní a nezbytné. Cílem této práce je totiž zejména představit možnosti vývoje takovéto aplikace a předvést analýzu a návrh řešení, zatímco samotná implementace je již poněkud závislá na tvaru a struktuře celého vyvíjeného systému Prytanis, a nemá smysl ji tu celou prezentovat. Proto jsem přistoupil pouze k tomu, že vkládám několik ukázek (ukázka zdrojového kódu business třídy, ukázka třídy pro jednotkové testy apod.). Nicméně vývoj aplikace Jízdní řády touto prací nekončí, naopak implementace jednotlivých přírůstků bude pokračovat dále, tak aby jejím cílem bylo použitelné softwarové dílo odpovídající potřebám dopravních podniků při komputerizaci svých dopravních procesů. Poslední problém, který tu chci zmínit, znovu souvisí s tím, že tvořená aplikace bude součástí komplexního podnikového informačního systému. Kdo čekal, že součástí této práce bude CD s funkční aplikací (aspoň v tom stavu, v jakém je vytvořen), bude zřejmě zklamán. Důvodem je to, že aplikace neběží sama o sobě – ve skutečnosti se jedná pouze o několik DLL knihoven, které jsou volané společnými částmi systému, a které jsou na jiných společných knihovnách závislé. Ke spuštění je navíc potřeba databázový systém, na kterém budou uložena perzistentní data systému, a další poměrně složité nastavení serveru a klienta – to vše je dané tím, že informační systém Prytanis je kompletním řešením potřeb podniku, a je dodáván včetně instalace a zprovoznění techniky firmy Unis Computers, spol. s r. o., přičemž tato fáze nasazení systému je poměrně náročná a složitá.
10
10
ZÁVĚR
81
Závěr
Cílem této práce bylo navrhnout a sestavit aplikaci pro správu a zadávání jízdních řádů linek. Výsledkem je ověřená a odsouhlasená analýza a postupně, po přírůstcích přibývající spustitelná aplikace, začleněná do inforačního systému Prytanis. Podporuje, resp. v případě ještě nenaimplementovaných částí bude podporovat, všechny význačné procesy v souvislosti se správou linek a jejich jízdních řádů, přičemž analýza je kompletní, odsouhlasená a ověřená. Samozřejmě, hodnota aplikace není jen v ní samotné, ale zejména v celém řešení – informačním systému podporujícím zadávání jízdních řádů linek. Tak jako aplikace Jízdní řády ovlivní užitnou hodnotu ostatních modulů a aplikací systému Prytanis, tak i zpětně řešení těchto ostatních částí a jeho kvalita ovlivní použitelnost a hodnotu aplikace Jízdní řády. Proto není možné tuto aplikaci hodnotit pouze samostatně, ale lépe v kontextu celého informačního systému Prytanis. Vývoj této aplikace pochopitelně nebyl bezúčelný – jeho cílem bylo zvýšení užitné hodnoty celého informačního systému Prytanis. Jízdní řády jsou pouze první ze série aplikací sloužící ke komputerizaci podnikových procesů řízení osobní dopravy. Nelze tedy očekávat, že tato samotná aplikace přinese výraznou optimalizaci procesů v dopravním podniku. Až doplnění informačního systému Prytanis o další navazující aplikace povede ke kompexní a integrované komputerizaci těchto procesů a tedy i ke kýžené úspoře nákladů dopravních podniků. Tato aplikace ale k tomu pokládá dobrý základ tím, že je plně integrovaná s již existujícími částmi systému, a další moduly a aplikace na ni mohou navazovat.
82
10
ZÁVĚR
11
11
LITERATURA
83
Literatura
Abrahamsson, T. Estimation of Origin-Destination Matrices Using Traffic Counts – A Literature Survey [online]. Laxenburg (Rakousko) : International Institute for Applied System Analysis, 1998 [cit. 19. března 2008]. Interim Report IR-98-021. Dostupné na www: . Arlow, J., Neustadt, I. UML 2 a unifikovaný proces vývoje aplikací: Objektově orientovaná analýza a návrh prakticky. Přel. B. Kiszka. 2. uprav. vyd. Brno : Computer Press, 2007. 568 s. Přel. z UML 2 and the Unified Process: Practical Object-Oriented Analysis and Design. ISBN 80-251-1503-8. Backhouse, R. Program Construction. Calculating Implementations from Specifications. Chichester (Velká Británie) : John Wiley & Sons, 2003. 352 s. ISBN 0-470-84882-0. Basu, S., Rahman, S. M. Improving Optimistic Concurrency Control Using Hybrid Techniques of Snapshot Isolation And ROCC. In MICS 2006: Proceedings of the 39th Midwest Instruction and Computing Symposium. Mount Pleasant (Iowa, USA) : Iowa Wesleyan College, 2006. Bayer, J. C# 2005. Velká kniha řešení. Brno : Computer Press, 2007. 914 s. Edice Programování. ISBN 80-251-1620-4. Beck, K. Implementation Patterns. Harlow (Velká Británie) : Addison-Wesley, 2008. 157 s. Edice The Addison-Wesley Signature Series. ISBN 0-321-41309-1. Bell, D. UML’s Sequence Diagram [online]. Armonk (New York, USA) : IBM DeveloperWorks, 16. února 2004 [cit. 4. dubna 2008]. Dostupné na www: . Berezin, T. Writing a Software Requirements Document [online]. Berkeley (Kalifornie, USA) : University of California, 1999 [cit. 24. března 2008]. Dostupné na www: . Bider, I. Choosing Approach to Business Process Modeling – Practical Perspective [online]. Stockholm (Švédsko) : IbisSoft AB, 2003 [cit. 22. března 2008]. Dostupné na www: . Black Box and White Box Testing for Application Blocks [online]. Redmond (Washington, USA) : Microsoft Corporation, 2005 [cit. 8. dubna 2008]. Microsoft Patterns & Practices. Dostupné na www: . Botella, P. a kol. ISO/IEC 9126 in Practice: What Do We Need to Know? In Proceedings of First Software Measurement European Forum 2004. Milán (Itálie) : Instituto di Ricerca Internzionale, 2007. ISBN: 88-86674-33-3. Bouma, F. Why a Cache in an O/R Mapper Doesn’t Make it Fetch Data Faster. In Frans Bouma’s Blog [online]. Haag (Holandsko) : Frans Bouma, 31. srpna 2006 [cit. 12. dubna 2008]. Dostupné na www: . Buchanan, S. Misuse cases. In Afongen, Sam Buchanan’s weblog [online]. Saint Paul (Minnesota, USA) : Sam Buchanan, 2. prosince 2004 [cit. 30. března 2008]. Dostupné na www: .
84
11
LITERATURA
Cochran, M. C# Generic Identity Map – Creating an Object Pool for Multiple Object Types [online]. Boothwyn (Pennsylvania, USA) : C# Corner (vydává Mindcracker LLC), 27. ledna 2008 [cit. 12. dubna 2008]. Dostupné na www: . Corfield, S. A. The Pain of Inheritance. In An Architect’s View. ColdFusion, Software Design, Frameworks and more . . . [online]. Castro Valley (Kalifornie, USA) : Sean A. Corfield, 19. dubna 2004 [cit. 6. dubna 2008]. Dostupné na www: . Dvořák, J. Využití technologie AJAX v Univerzitním informačním systému. Bakalářská práce. Brno : Mendelova zemědělská a lesnická univerzita v Brně, 2006. 45 s. Enterprise Architect 7.0 User Guide [online]. Creswick (Austrálie) : Sparx Systems, 2008 [cit. 10. března 2008]. Dostupné na www: . Foret, M. Marketingová komunikace. Brno : Computer Press, 2006. 460 s. ISBN 80-251-1041-9. Gamma, E. a kol. Design Patterns: Elements of Reusable Object-Oriented Software. Harlow (Velká Británie) : Addison-Wesley, 1995. 416 s. ISBN 0-201-63361-2. Gelperin, D. Precise Use Cases. Methods and Tools, 2004, roč. 12, č. 1. ISSN 1023-4918. Gottesdiener, E. Use Cases: Best Practices [online]. Armonk (New York, USA) : IBM DeveloperWorks, 19. srpna 2004 [cit. 1. dubna 2008]. Dostupné na www: . Gray, J. The Transaction Concept: Virtues and Limitations. Cupertino (Kalifornie, USA) : Tandem Computers Incorporated, 1981. HP Laboratories Technical Report Tandem TR 81.3. Herrington, J. D. Have a Little Respect for SQL Databases [online]. Darien (Connecticut, USA) : DevX (vydává JupiterMedia Corporation), 8. října 2003 [cit. 10. dubna 2008]. Dostupné na www: . Heumann, J. Generating Test Cases From Use Cases. The Rational Edge. Červen 2001, roč. 2, č. 6, str. 48–58. Holub, A. OO Design Process: Use Cases, an Introduction [online]. Armonk (New York, USA) : IBM DeveloperWorks, 1. prosince 2000 [cit. 30. března 2008]. Dostupné na www: . Hunt, A., Thomas, D. Programátor pragmatik. Jak se stát lepším programátorem a vytvářet kvalitní software. Přel. I. Magera, L. Ptáček. 1. vyd. Brno : Computer Press, 2007. 266 s. Přel. z Pragmatic programmer. ISBN 80-251-1660-3. Ingres 2006. SQL Reference Guide [online]. Redwood City (Kalifornie, USA) : Ingres Corporation, 2006 [cit. 10. března 2008]. Dostupné na www: . Kaner, C. What Is a Good Test Case? In STAREAST 2003: Proceedings of the Software Testing Analysis and Review Conference, Orlando, May 12-16, 2003. Orlando (Florida, USA) : Software Quality Engineering, 2003. Konečný, V. Nástroje pro tvorbu IS. Elektronická studijní opora k předmětu Integrované informační systémy. Brno : Mendelova zemědělská a lesnická univerzita v Brně, 2007. Kap. 5, str. 60.
11
LITERATURA
85
Kraval, I. Objektové modelování a UML v praxi 2000. Valašské Klobouky : Objects Consulting, 2001. Kueng, P., Kawalek, P. Goal-Based Business Process Models: Creation and Evaluation. Business Process Management Journal, 1997, roč. 3, č. 1, str. 17–38. ISSN 1463-7154. Lieberherr, K., Holland, I., Riel, A. Object-Oriented Programming: An Objective Sense of Style. ACM SIGPLAN Notices, listopad 1988, roč. 23, č. 11, spec. vyd. ’OOPSLA 88 Conference Proceedings, str. 323–334. ISSN 0362-1340. Liu, L., Yu, E. Designing Information Systems in Social Context: A Goal and Scenario Modelling Approach. Information systems, 2003, roč. 29, č. 3. ISSN 0306-4379. Macáková, L. a kol. Mikroekonomie. Základní kurs. Slaný : Melantrium, 2002. 7. vydání. 271 s. ISBN 80-86175-20-0. Martin, R. C., Martin, M. Agile Principles, Patterns, and Practices in C#. Old Tappan (New Jersey, USA) : Prentice Hall, 2006. 732 s. ISBN 0-13-185725-8. Merunka, V. Procesní modelování jako důležitá část fáze získávání požadavků pro analýzu a návrh informačních systémů. Systémová integrace, 2/2003, srpen. ISSN 1210-9479. Miller, C. Six Rules of Unit Testing In The Desktop Fishbowl. tail -f /dev/mind > blog [online]. Sydney (Autstrálie) : Charles Miller, 2002 [cit. 13. dubna 2008]. Dostupné na www: . Musser, D. R., Stepanov, A. A. Generic Programming. In Gianni, P. ISSAC ’88. Proceedings of the 1988 International Symposium on Symbolic and Algebraic Computation, Rome, Italy, July 4-8, 1988. Berlín (Německo) : Springer Verlag, 1989. 554 s. Lecture Notes in Computer Science 358. ISBN 3-540-51084-2. Nagel, C. C# 2005. Programujeme profesionálně. Brno : Computer Press, 2007. 1400 s. ISBN 80-251-1181-4. .NET Framework Class Library [online]. Redmond (Washington, USA) : Microsoft Corporation, 2008 [cit. 10. března 2008]. Dostupné na www: . Nuseibeh, B., Easterbrook, S. Requirements Engineering: A Roadmap. In Finkelstein, A. C. W. The Future of Software Engineering. Proceedings of the 22nd International Conference on Software Engineering, ICSE’00. Limerick (Irsko) : ACM Press, 2000. ISBN 1-58113-253-0. Online Documentation for .NET Components and Libraries by Developer Express [online]. Las Vegas (Nevada, USA) : Developer Express, 2008 [cit. 16. března 2008]. Dostupné na www: . Paleta, P. Co programátory ve škole neučí aneb Softwarové inženýrství v reálné praxi. Brno : Computer Press, 2003. 360 s. ISBN 80-251-0073-1. Palúch, S., Majer, T. K optimalizácii mestskej a prímestskej pravidelnej osobnej dopravy. In Vysoká škola jako facilitátor rozvoje společnosti a regionu. 3. mezinárodní konference. Kunovice : Evropský polytechnický institut, 2007. 234 s. ISBN 80-7314-107-8. Pan, J. Software Testing [online]. Pittsburgh (Pennsylvania, USA) : Carnegie Mellon University, 1999 [cit. 13. dubna 2008] Dostupné na www: .
86
11
LITERATURA
Pavelčík, P. V. Vývoj dopravy v České republice od roku 1990. Fotografie J. Konečný. Průhledy: časopis o přírodě a lidech, 2003, roč. 3, č. 5-6. ISSN 1802-3932. Puš, P. Poznáváme C# a Microsoft .NET [online]. Brno : Živě.cz (vydává Computer Press), 2008 [cit. 10. března 2008]. Dostupné na www: . Rybička, J. LATEX pro začátečníky. Brno : Konvoj, 2003. 3. vydání. 240 s. ISBN 80-7302-049-1. Řepa, V. Podnikové procesy: procesní řízení a modelování. 2. vyd. Praha : Grada, 2007. 281 s. Edice Management v informační společnosti. ISBN 80-247-2252-6. Schmuller, J. Myslíme v jazyku UML. Praha : Grada Publishing, 2000. 359 s. Edice Knihovna programátora. ISBN 80-247-0029-8. Simons, A. J. H., Graham, I. 30 Things That Go Wrong in Object Modelling with UML 1.3. In Kilov, H., Rumpe, B., Simmonds, I. Behavioral Specifications of Businesses and Systems. Dordrecht (Holandsko) : Kluwer Academic Publishers, 1999. 328 s. The Kluwer International Series in Engineering and Computer Science Volume 523. ISBN 0-7923-8629-9. Sparx, G. The Business Process Model [online]. Creswick (Austrálie) : Sparx Systems, 2000 [cit. 23. března 2008]. Dostupné na www: <www.uml.co.il/WhitePapers/The_Business_Process_Model.pdf>. Stein, R. René Stein. Názory vzešlé z mesaliance humanitní skepse a technologického optimismu [online]. Bystřice u Benešova : René Stein, 10. ledna 2008 [cit. 10. března 2008]. Dostupné na www: . Stepanov, A. A., Lee, M. The Standard Template Library. Palo Alto (Kalifornie, USA) : Hewlett-Packard Company, 1995. HP Laboratories Technical Report 95-11(R.1). Štolfa, S., Vondrák, I. Strukturování use case diagramů pomocí byznys procesů. In Objekty 2003. Sborník konference OBJEKTY 2003. Ostrava : VŠB – Technická univerzita Ostrava, 2003. ISBN 80-248-0247-0. Theisen, D. Enhancing Encapsulation in OOP. A Practical Approach. Diplomová práce. Bonn (Německo) : Universität Bonn, 2000. 54 s. Virius, M. Generické programování v C++, Javě a C#. In Objekty 2005. Sborník příspěvků 10. ročníku konference. Ostrava : VŠB – Technická univerzita Ostrava, 2005. Ed. V. Snášel. 324 s. ISBN 80-248-0595-2. Vonka, J. a kol. Osobní doprava. Pardubice : Univerzita Pardubice, 2001. 170 s. ISBN 80-7194-320-7. Vyhláška Ministerstva dopravy č. 173/1995 Sb., kterou se vydává dopravní řád drah, ve znění pozdějších předpisů. Praha : Ministerstvo dopravy ČR, 1995. Vyhláška Ministerstva dopravy a spojů č. 388/2000 Sb., o jízdních řádech veřejné linkové osobní dopravy. Praha : Ministerstvo dopravy a spojů ČR, 2000. Yoder, J. W., Balaguer, F., Johnson, R. Architecture and Design of Adaptive Object-Models. ACM SIGPLAN Notices, prosinec 2001, roč. 36, č. 12, str. 50–60. ISSN 0362-1340.
Přílohy
88
11
LITERATURA
A
A
PŮVODNÍ INFORMAČNÍ SYSTÉM PRYTANIS
Původní informační systém Prytanis
Ukázky obrazovek původního systému Prytanis
Obr. 12: Hlavní editační okno jízdního řádu linky v původním systému Prytanis.
Obr. 13: Formulář pro opravu zastávky v číselníku zastávek v původním systému Prytanis.
89
90
A
PŮVODNÍ INFORMAČNÍ SYSTÉM PRYTANIS
Ukázka zdrojového kódu jazyka Ingres 4GL INITIALIZE (a_mode = CHAR(1) NOT NULL, id_mista_celni = INTEGER(4) NOT NULL) = DECLARE l_like = VARCHAR(100) NOT NULL; l_prompt = VARCHAR(1) NOT NULL; l_poc = INTEGER(1); IIint = INTEGER(4); IIint2 = INTEGER(4); IIrowcount = INTEGER(4); IIobjname = CHAR(32) NOT NULL; BEGIN /* inicializace formulare */ IF a_mode = ’B’ THEN /* prohlizeni bez moznosti editace */ SET_FORMS FORM (MODE = ’read’); f_nadpis = ’PROHLÍŽENÍ DOPLŇUJÍCÍCH ÚDAJŮ’; ELSE SET_FORMS FORM (MODE = ’update’); f_nadpis = ’OPRAVA DOPLŇUJÍCÍCH ÚDAJŮ’; ENDIF; /* v pripade opravy nebo detailu dotahneme informace o zbozi */ IF ifnull(zbozi_phm,’’) != ’’ then REPEATED SELECT :zbozi = popis FROM yyt_c_druhzboz WHERE druh_zbozi = :zbozi_phm; COMMIT WORK; ENDIF; IF ifnull(teplota,0)=0 THEN teplota = NULL; ENDIF; IF ifnull(teplota_staceni,0)=0 THEN teplota_staceni = NULL; ENDIF; END /* end initialize */ /* volani funkce pro vyber */ ’Výběr’ (VALIDATE = 0, ACTIVATE = 0, EXPLANATION = ’Zobrazí platné hodnoty daného pole’), KEY FRSKEY10 (VALIDATE = 0, ACTIVATE = 0) = BEGIN IF a_mode = ’B’ THEN CALLPROC beep(); message ’Nelze nic měnit, nacházíte se v prohlížení . . .’ WITH style=popup; ENDIF; IIint = -1; INQUIRE_FORMS FIELD ’’ (IIobjname = NAME, IIint2 = TABLE); IF (IIobjname = ’zbozi_phm’) THEN /* Vyber z ciselniku zbozi */
A
PŮVODNÍ INFORMAČNÍ SYSTÉM PRYTANIS
IIint = CALLFRAME look_up ( II_ROWS = 10; II_QUERY = SELECT DISTINCT druh_zbozi, popis FROM yyt_c_druhzboz ORDER BY druh_zbozi, popis; II_FIELD1 = ’druh_zbozi’; II_FIELD2 = ’popis’; II_TITLES = 1; II_FIELD_TITLE1 = ’Označení’; II_FIELD_TITLE2 = ’Název druhu zboľí’; druh_zbozi = BYREF(zbozi_phm), popis = BYREF(zbozi) ); ENDIF; IF (IIint < 0) THEN message ’V daném poli není definován výběr.’ WITH style = popup; ELSE COMMIT WORK; SET_FORMS FORM (CHANGE = 1); ENDIF; RESUME; END /* end vyber */ ’Konec’ (VALIDATE = 0, ACTIVATE = 0, EXPLANATION = ’Návrat k předešlé obrazovce’), KEY FRSKEY3 (VALIDATE = 0, ACTIVATE = 0) = BEGIN IF a_mode != ’B’ THEN validate; /* kontrola poctu fakturovanych litru */ IF ifnull(litry_fakturovane,0) != ifnull(litry,0) AND ifnull(litry_fakturovane,0) != ifnull(litry15,0) AND ifnull(litry_fakturovane,0) != ifnull(litry_staceni,0) AND ifnull(litry_fakturovane,0) != ifnull(litry15_staceni,0) THEN CALLPROC beep(); message ’Fakturované litry musí být stejné jako litry,’ +’ litry při 15 nebo litry stáčené!’ WITH style=popup; RESUME ENDIF; ENDIF; RETURN; END /* end skonceni */ AFTER FIELD ’zbozi_phm’ = BEGIN INQUIRE_FORMS FIELD ’’ (IIint = CHANGE); INQUIRE_FORMS FORM (IIobjname = MODE); IF (IIint = 1) AND (UPPERCASE(IIobjname) != ’QUERY’) THEN IF ifnull(zbozi_phm,’’)=’’ THEN zbozi = ’’; RESUME NEXT;
91
92
A
PŮVODNÍ INFORMAČNÍ SYSTÉM PRYTANIS
ENDIF; /* overeni, jestli je zadane zbozi v ciselniku zbozi */ REPEATED SELECT :zbozi = popis FROM yyt_c_druhzboz WHERE druh_zbozi = :zbozi_phm; inquire_ingres (IIrowcount = rowcount); COMMIT WORK; IF IIrowcount <= 0 THEN CALLPROC beep(); MESSAGE ’"’ + zbozi_phm + ’" není povolená hodnota tohoto’ + ’ pole (zvolte "Výběr").’ WITH style = popup; RESUME; ENDIF; ENDIF; RESUME NEXT; END /* end after field zbozi */
B
B
MODEL BUSINESS PROCESŮ V SUBSYSTÉMU SPRÁVY JÍZDNÍCH ŘÁDŮ LINEK
93
Model business procesů v subsystému správy jízdních řádů linek
Obr. 14: Model podnikových procesů týkajících se správy jízdních řádů linek.
94
B
MODEL BUSINESS PROCESŮ V SUBSYSTÉMU SPRÁVY JÍZDNÍCH ŘÁDŮ LINEK
C
C
ANALYTICKÉ MODELY A DOKUMENTY
95
Analytické modely a dokumenty
Diagramy případů užití aplikace
Obr. 15: Use-case diagram shrující případy užití související s evidencí zastávek a přejezdů mezi nimi. Jsou zde i případy užití pro správu číselníků krajů, okresů a obcí, ačkoliv nepatří do samotné aplikace Jízdní řády, bylo je nutné pro lepší práci se zastávkami navrhnout a naprogramovat.
96
C
ANALYTICKÉ MODELY A DOKUMENTY
Obr. 16: Use-casy patřící do package Správa číselníků. Jde o nejrůznější číselníky a nastavitelné údaje pro správné fungování aplikace, některé z nich jsou editovatelné pouze administrátorem aplikace, protože zásadně ovlivňují její funkčnost.
C
ANALYTICKÉ MODELY A DOKUMENTY
97
Obr. 17: Přehled případů užití souvisejících se základním založením linky, jejích spojů a zastávek.
98
C
ANALYTICKÉ MODELY A DOKUMENTY
Obr. 18: Hlavní editační okno aplikace (uživatel zde bude zadávat zejména časy odjezdů spojů ze zastávek) a případy užití volatelné z něj.
C
ANALYTICKÉ MODELY A DOKUMENTY
99
Obr. 19: Přehled linek a různé use-casy, které z něj lze spouštět (mimo funkčnosti související se stavy linek a platností linky, které jsou ve zvláštním balíku a jejich use-case diagram je uveden na obrázku 20).
100
C
ANALYTICKÉ MODELY A DOKUMENTY
Obr. 20: Use-case diagram funkčností související se stavy linek, a s jejich platností a jejími změnami.
C
ANALYTICKÉ MODELY A DOKUMENTY
101
Obr. 21: Případy užití správy a zadávání různých doplňkových údajů k linkám a spojům. Jsou zde (a ne v balíku Linky, spoje a zastávky na spoji ) proto, že se jedná o doplňkové údaje a dá se předpokládat, že při použití iterativní a inkrementální metody vývoje budou realizovány ve zvláštním přírůstku, později než založení linky, spoje a zastávky na lince a zadání základních údajů k nim.
102
C
ANALYTICKÉ MODELY A DOKUMENTY
Obr. 22: Use-case diagram shrnující činnosti týkající se tiskového výstupu jízdních řádů z aplikace, a exportů a importů dat.
C
ANALYTICKÉ MODELY A DOKUMENTY
103
Dokumentace případu užití Založení nové zastávky Stručný popis: V aplikaci Jízdní řády existuje číselník zastávek, který obsahuje všechny zastávky, které pak jsou použity v jízdních řádech jednotlivých linek. Zastávky jsou napojené na obecné místa/adresy. Každá zastávka má své unikátní číslo. Jsou dva typy zastávek: - NORMÁLNÍ - PŘEJEZDOVÉ (viz níže) Zastávka má číslo zastávky, je to unikátní identifikátor v systému. Kromě toho mají zastávky název a spoustu parametrů (jestli je na znamení, název pro tablo a další). Pojem PŘEJEZDOVÁ ZASTÁVKA – je to zastávka, která se nemůže objevit na trase spoje v jízdních řádech. Je určená pro přejezdy do turnusů. Např. autobus dojede na Zvonařku, vyžene cestující (tj. konec linky je Zvonařka,aut.nádr.), pak jede přejezd 1 km na parkoviště (zastávka Zvonařka,parkoviště). Je to už mimo linku a neveze lidi, ale ten přejezd musí mít v turnusu, aby věděl, co má dělat. Pak (třeba za 2 hodiny) se zase ten 1 km vrátí (na Zvonařka,aut.nádr.) a odjede na další linku. Takže Zvonařka, parkoviště není zastávka v žádném jízdním řádu, dokonce to není ani žádná zastávka (nemá označník, název, apod.), je to v podstatě jen nějaké učení místa. No a to přesně je PŘEJEZDOVÁ ZASTÁVKA. DŮLEŽITÁ POZNÁMKA: Oproti populárnímu názoru, že okresy byly v ČR zrušeny, OKRESY V ČESKÉ REPUBLICE NADÁLE EXISTUJÍ. K 31. 12. 2002 byly zrušeny pouze okresní úřady a jejich obecná působnost přenesena na obce s rozšířenou působností, ale spousta institucí specializované státní správy nadále členění na okresy používá (a mj. se mají používat i při specifikaci zastávek pro jízdní řády). OKRESY JSOU TEDY JAKO ÚZEMNÍ CELKY ZACHOVÁNY, ČLENĚNÍ ÚZEMÍ ČR DO OKRESŮ ZŮSTÁVÁ V PLATNOSTI TAK, JAK BYLY PŘED ROKEM 2002. Externí omezení ovlivňující běh: Tento případ užití může volat pouze přihlášený uživatel, neočekává se zvláštní úroveň oprávnění pro akci založení zastávky do číselníku zastávek. Toky událostí: • Základní 1. uživatel dá příkaz k založení nové zastávky 2. systém zobrazí formulář pro zadání nové zastávky 3. uživatel vyplní údaje o zastávce 4. uživatel dá příkaz k uložení nové zastávky 5. systém zkontroluje data a v případě, že jsou v pořádku, novou zastávku vloží do číselníku • Zadání obce – (Rozšiřující tok) Každá zastávka musí náležet právě do jedné obce, obec musí být u každé zastávky zadaná. Při jejím zadání má uživatel dvě možnosti: – vybrat obec z číselníku obcí. Pokud již v tomto okamžiku je zadaný stát, tak se budou hledat pouze obce z toho státu – ručně zadat novou obec. V tom případě se zobrazí formulář pro přidání nové obce.
104
C
ANALYTICKÉ MODELY A DOKUMENTY
Pole s obcí bude uživatelem needitovatelné (nebude moct opravit text v něm, akorát vybrat obec z číselníku). Na formuláři bude ještě jedno pole – POUŽITÝ NÁZEV OBCE, kam by se při výběru obce z číselníku doplnil ten název obce v číselníku, ale uživatel by ho mohl změnit (třeba když je ten název obce moc dlouhý, tak ho rozumně zkrátit, a tak), a tento text by se použil při sestavování názvu zastávky. Z toho důvodu pak není potřeba mít editovatelný název zastávky samotný (narozdíl od starého Prytanisu). • Sestavení názvu zastávky – (Rozšiřující tok) Název zastávky se skládá ze tří částí – název obce – např. Otrokovice, povinné (proto musí být u každé zastávky zadaná obec) – část obce/městská část, např. Kvítkovice – bližší určení, např. hřbitov Varianty názvu zastávky mohou být: – obec – např. Držková – obec,část obce – např. Hulín,Chrášťany – obec,část obce,bližší místo – např. Zlín,Kudlov,myslivna – obec„bližší místo – např. Fryšták„Žabárna (dvě čárky nejsou překlepem, ale naopak tam MUSÍ být) Pokud je zadána zastávka, která má shodné všechny tři části (obec, část obce a bližší určení), tak v tom případě systém při ukládání ohlásí varování, a uživatel bude muset uložení takovéto zastávky potvrdit (a nebo zvolí, že ji uložit nechce, a zůstane v editaci zastávky). Název zastávky není přímo ručně editovatelný, skládá se automaticky z údajů zadaných do tří nezávislých polí (použitý název obce, část obce, bližší určení). Zadává (resp. automaticky skládá) se pouze, pokud se jedná o normální zastávku (není zaškrtlé, že jde o přejezdovou zastávku). Naopak, pokud se jedná o přejezdovou zastávku, je povinný zkrácený název (v případě normální zastávky je jeho vyplnění volitelné), který vyplní uživatel ručně. Při zadávání použitého názvu obce, části obce a bližšího určení se v ani jednom z těchto polí nesmí objevit čárka (vedlo by to ke zmatku, protože čárkami se v názvu zastávky oddělují jednotlivé části). • Zadání nástupišť – (Rozšiřující tok) Pokud se skládá zastávka z více nástupišť (což obvykle skládá – běžná zastávka na vesnici má jedno nástupiště s označníkem na jedné straně silnice, a druhé na druhé straně silnice pro spoje, které jedou v tom opačném směru), a je zájem sledovat, na kterém staví konkrétní linky/spoje, lze u zastávky zadat seznam jejích nástupišť. U každého nástupiště se může zadat jeho číslo (bude se zobrazovat a tisknout), jeho popis (pro identifikaci, když např. nástupiště nejsou číslované), a jeho souřadnice (pokud nejsou zadané, tak se berou společné souřadnice zastávky, pokud ty zadané jsou). Musí být vždy zadané buď číslo, nebo popis nástupiště (nebo i oboje), tj. každé nástupiště musí být nějak identifikovatelné. Konstantou lze nastavit, jestli při zadávání nástupišť k lince/spoji se musí vybrat jedno z nástupišt zadaných zde k zastávce, nebo jestli lze zadat i nástupiště, které zde není zadané.
C
ANALYTICKÉ MODELY A DOKUMENTY
105
• Zadání položek zastávek – (Rozšiřující tok) K zastávce se zadávají i položky zastávek. Jsou to doplňkové údaje, používají se např. při exportu do jiných aplikací (název pro strojky Mikroelektronika, číslo zastávky pro celostátní informační systém). Berou se z číselníku položek zastávek, který je do jisté míry editovatelný administrátorem u zákazníka. Přímo v definici těchto položek se určí, jakého jsou typu, a jestli budou používané, popř. jestli budou povinné, a v jakém pořadí se budou zobrazovat. Identifikované alternativní toky událostí: (mimo zřejmé validace) 1. Uživatel ručně zadá číslo zastávky, a toto už má jiná zastávka v číselníku – při opuštění pole je číslo zastávky zvalidováno, pokud dojde k této chybě, objeví se mu informativní hláška a zastávka nepůjde uložit, dokud číslo neopraví. 2. Uživatel zadá obec (její název/kód), která se nevyskytuje v číselníku obcí – systém se uživatele zeptá, zda chce takovouto obec založit do číselníku obcí, pokud uživatel zvolí, že chce, je vyvolán formulář pro založení nové obce, kde uživatel vyplní údaje a uloží tuto obec; pokud zvolí, že tuto obec nechce založit, je zobrazeno informativní hlášení a zastávka v tomto stavu nepůjde uložit. 3. Nově vytvářená zastávka má stejnou obec, část obce a bližší místo jako jiná, již existující v číselníku zastávak – pokud toto systém při uložení zjistí, zeptá se uživatele, zda chce zastávku i přesto uložit, ten může buď zvolit, že chce, a v tom případě se i přes tento nedostatek zastávka uloží; pokud zvolí, že nechce, tak se neuloží a uživatel zůstane v otevřeném formuláři pro zadání zastávky 4. Při uložení nové dojde k chybě při validaci jednotlivých údajů – systém ohlásí uživateli, které údaje jsou nesprávně vyplněny, zastávka tedy není uložena, a uživatel je poté vrácen do formuláře pro zadání nové zastávky, kde nevalidní údaje opraví. 5. Jiná neočekávaná chyba při ukládání – systém ohlásí chybu a připad užití končí Sestava (údaje zadávané k zastávce): • Číslo zastávky (přirozené číslo, povinné, defaultně Číslo poslední zastávky + 1) – unikátní identifikační číslo zastávky mezi všemi zastávkami v aplikaci • Přejezdová zastávka (příznak, povinný, ale defaultně nenastavený) – jestli jde o normální, nebo přejezdovou zastávku. Přejezdová zastávka je zastávka, která se neobjevuje v jízdních řádech, ale jen v turnusech (blíže viz popis případu užití). • Stát (vazba do číselníku států, výchozí je přednastavený místní stát, který by měl být v systému nastavený konstantou) – stát se k zastávce neukládá, znamená akorát něco jako omezení výběru zastávky, aby se při výběru obce nenabízely obce všech možných států, protože by uživatel stejně číselník obcí skoro vždy podle státu filtroval. • Obec (vazba do číselníku obcí, povinná) – obec, ve které leží zastávka • Použitý název obce (text, povinný, doplní se název vybrané obce, tak jak je zadán v číselníku obcí, resp. zkrácený název, pokud je k obci zadán) – toto pole je tu kvůli tomu, že název obce může být poměrně dlouhý text, a uživatel třeba může chtít do názvu zastávky ho nějak zkrátit nebo jinak upravit, tak v tom případě ho zde v tomto poli změní. Do názvu zastávky se použije text z tohoto pole. Když uživatel vybere obec z číselníku obcí, tak se do tohoto pole doplní její název
106
C
ANALYTICKÉ MODELY A DOKUMENTY
• Okres/kraj (text, nelze měnit, jen pro čtení) – Když je vybrána obec, je vedle zobrazeno, do kterého okresu/kraje náleží, tuto inormaci nemůže uživatel měnit (leda tím, že vybere novou obec, která je v jiném okrese) • Část obce/městská část (text) • Bližší určení místa (text) – bližší určení zastávky v rámci obce a její části, např. obecní úřad, autobusové nádraží, rybník, hřbitov apod. • Název zastávky (text, nelze ho měnit, jen pro čtení) – generuje se ze tří fragmentů: použitého názvu obce, části obce a bližšího určení místa • Zkrácený název (kratší text, u přejezdových zastávek povinný, jinak ne) – zkrácený název se používá při zobrazení a tisku turnusů. V případě, že jde o přejezdovou zastávku, je povinný. U obyčejné zastávky může být vyplněn (normální zastávka se může v turnusech objevit, pokud se na ní začíná nebo končí nějaký spoj) – pokud je krátký název zadaný, použije se v turnusech, pokud není, použije se běžný název. • Název zastávky v místním jazyce (text) – pole je přístupné jen pokud leží obec v jiném státě, než je místní stát používaný v systému. • Vyhledávací kód (text o deseti znacích) – Uživatel může zadat vyhledávací kód, pomocí kterého bude snadno při zadávání dohledávat zastávku. Vyhledávací kód musí být mezi zastávkami unikátní (ale nemusí být, a zpravidla nebývá zadaný ke všem zastávkám) • Souřadnice GPS X, Souřadnice GPS Y, Souřadnice S-JTSK X, Souřadnice S-JTSK Y (nepovinná desitinná čísla) – souřadnice zastávky jako celku v jednotlivých souřadnicových systémech. Seznam položek zastávky: • Položka (text, jen pro čtení) – název položky, tak jak jej zadá administrátor/správce aplikace v číselníku položek zastávek. • Hodnota položky (druh závisí na definici položky, může se jednat o text, výběr z více možností nebo odkaz do existujícího číselníku, v definici lze také nastavit, zda je vyplnění položky povinné a jaká bude výchozí hodnota) – různé doplňující údaje, částečně definovatelné administrátorem aplikace Seznam nástupišť zastávky: • Číslo nástupiště (přirozené číslo, v případě, že nástupiště nejsou číslované, tak se toto pole nechá nevyplněné) • Označení (libovolný text, každé nástupiště u zastávky musí být označené buď textem, nebo číslem nástupiště) – označení nástupiště pro interní identifikaci v dopravním podniku (zpravidla se nikam netiskne), může se použít např. když nástupiště nejsou číslované • Souřadnice GPS X, Souřadnice GPS Y, Souřadnice S-JTSK X, Souřadnice S-JTSK Y (nepovinná desitinná čísla) – souřadnice konkrétního nástupiště v různých souřadnicových systémech
C
ANALYTICKÉ MODELY A DOKUMENTY
107
Ukázky dalších analytických modelů
Obr. 23: Sekvenční diagram modelující činnost Přidání spoje na linku. Zobrazuje zejména složitější interakce, jednoduché opakované sekvence (postupné vyplnění všech polí na formuláří) jsou zanedbány, resp. shrnuty jednou sekvencí zpráv Uživatel vyplňuje data do formuláře → SetValues().
108
C
ANALYTICKÉ MODELY A DOKUMENTY
Obr. 24: Stavový diagram znázorňuje stavy objektů třídy Linka a jejich možné přechody.
D
NÁVRH A IMPLEMENTACE APLIKACE
D
109
Návrh a implementace aplikace
Ukázka implementace návrhového vzoru Decorator // Component public abstract class UcitelComponent { // predpis pro metodu, ktera vrati textovy popis ucitele public abstract string GetText(); } // ConcreteComponent public class Ucitel : UcitelComponent { // private fields - jmeno a prijmeni // metoda vrati textove info o uciteli public override string GetText() { return string.Format("{0} {1}, na MZLU v Brně", this.jmeno, this.prijmeni); } } // Decorator public abstract class Decorator : UcitelComponent { // odkaz na instanci, kterou tento decorator bude rozsirovat private UcitelComponent component; // konstruktor - prevezme instanci, kterou bude rozsirovat public Decorator(UcitelComponent comp) { this.component = comp; } // predpis metody pro vraceni popisu public abstract override string GetText(); } // FirstConcreteDecorator public class StazeUcitele : Decorator { // field - seznam absolvovanych stazi // metoda vrati popis ucitele public override string GetText() { return string.Format("{0}\n{1}", this.component.GetText(), this.GetStazeText()); } // vrati souhrn informaci o stazich jako retezec private string GetStazeText()
110
D
{ // zretezime udaje o stazich } } // analogicky pro dalsi decoratory
NÁVRH A IMPLEMENTACE APLIKACE
D
NÁVRH A IMPLEMENTACE APLIKACE
111
Diagram tříd komponenty Obecné vlastnosti
Obr. 25: Class model zobrazuje třídy v BL vrstvě komponenty ObecneVlastnosti, slouží pro obecné popisné údaje formy atribut-hodnota.
112
D
NÁVRH A IMPLEMENTACE APLIKACE
Entitně-relační diagramy navazující na modely tříd aplikace
Obr. 26: Entitně-relační diagram zobrazuje tabulky odpovídající třídám z class diagramu na obrázku č. 32 na stránce 131.
D
NÁVRH A IMPLEMENTACE APLIKACE
113
Obr. 27: Entitně-relační diagram jednoduchých číselníků potřebných při zadávání linky, zastávek a spojů – např. termínová omezení, poznámky, stavy linek, skupiny linek apod.
114
D
NÁVRH A IMPLEMENTACE APLIKACE
Ukázka zdrojového kódu business třídy Nastupiste using using using using using
System; DevExpress.Xpo; UnisComp.Pry.Spol.Base.BL; UnisComp.Pry.Spol.Adresy.BL; System.Diagnostics;
namespace UnisComp.Pry.Doprava.JizdniRady.BL { [Persistent("dj_nastupiste")] public class Nastupiste : BusinessObjectBase { #region fields /// <summary> /// Jedinečné číslo nástupiště v seznamu nástupišť této zastávky /// [Persistent("cisloNastupiste")] private byte? cisloNastupiste; /// <summary> /// Popis pro interní identifikaci, /// např. když nástupiště nejsou číslované /// [Persistent("popis")] private string popis; /// <summary> /// Odkaz na master, ke kterému toto nástupiště patří /// [Persistent("zastavka"), Association("ZastavkaNastupiste")] private Zastavka zastavka; /// <summary> /// Agregovaný objekt shrující údaje o souřadnicích nástupiště /// [Persistent("souradnice")] private Souradnice souradnice; #endregion //end fields #region properties /// <summary> /// [GET,SET] Jedinečné číslo nástupiště v seznamu nástupišť /// této zastávky, nemusí být zadané (nástupiště se nemusí číslovat) /// [PersistentAlias("cisloNastupiste")] public byte? CisloNastupiste { get {
D
NÁVRH A IMPLEMENTACE APLIKACE
return this.cisloNastupiste; } set { // 0 se chape jako nezadane nastupiste if (value == 0) { value = null; } this.CheckEquals(this.cisloNastupiste, value); this.cisloNastupiste = value; } } /// <summary> /// [GET,SET] Slouzi k praci s cislem nastupiste jako s retezcem, /// napr. pro bindovani na formular /// [NonPersistent] public string CisloNastupisteJakoRetezec { get { return this.CisloNastupiste.HasValue ? this.CisloNastupiste.ToString() : string.Empty; } set { if (string.IsNullOrEmpty(value)) { // cislo zastavky neni zadane - osetreni prazdneho retezce this.CisloNastupiste = null; } else { // je zadane - zkusime ho prevest try { this.CisloNastupiste = byte.Parse(value); } catch (FormatException ex) { throw new ArgumentException(string.Format("EDJ00016::{0}", UnisComp.Pry.Doprava.JizdniRady.RS.Exceptions.EDJ0016), ex); } catch (OverflowException ex) { throw new ArgumentException(string.Format("EDJ00017::{0}", UnisComp.Pry.Doprava.JizdniRady.RS.Exceptions.EDJ0017Format( byte.MinValue, byte.MaxValue)), ex); } }
115
116
D
NÁVRH A IMPLEMENTACE APLIKACE
} } /// <summary> /// [GET,SET] Popis pro interní identifikaci, např. když nástupiště nejsou /// číslované /// [PersistentAlias("popis")] public string Popis { get { // osetreni null hodnoty - pokud je ve fieldu null, navenek to // vystupuje jako prazdny retezec return this.popis ?? string.Empty; } set { // osetreni prazdneho retezce if (value == string.Empty) { value = null; } this.CheckEquals(this.popis, value); this.popis = value; } } /// <summary> /// [GET] Agregovaný objekt shrující údaje o souřadnicích nástupiště /// [PersistentAlias("souradnice")] public Souradnice Souradnice { get { if (this.souradnice == null) { this.souradnice = new Souradnice(this.Session); } return this.souradnice; } } /// <summary> /// [GET] Odkaz na master, ke kterému toto nástupiště patří /// [PersistentAlias("zastavka")] public Zastavka Zastavka { get { return this.zastavka;
D
NÁVRH A IMPLEMENTACE APLIKACE
117
} } #region Override Properties /// <summary> /// Vrati true, pokud bylo nastupiste zmeneno /// public override bool IsDirty { get { // pokud je zmeneny samotny objekt, je to jasne if (base.IsDirty) { return true; } else { // jeste muzou byt taky zmenene souradnice if (this.souradnice == null) { // nic tam nebylo a uzivatel na ne nesahl return false; } else { // pokud uz tam byl a ted je zmeneny, tak je jednoznecne dirty, // a nebo pokud je ted vytvoreny a neni prazdny (treba tam uzivatel // neco zadal a pak to smazal) return this.souradnice.IsDirty || (this.souradnice.IsNew && !this.souradnice.IsEmpty); } } } } #endregion #endregion //end properties #region constructors #region Vychozi konstruktory /// <summary> /// Konstruktor /// public Nastupiste() : base() { // This constructor is used when an object is loaded from a persistent
118
D
NÁVRH A IMPLEMENTACE APLIKACE
// storage. Do not place any code here. } /// <summary> /// Konstruktor /// /// <param name="session"> public Nastupiste(Session session) : base(session) { // This constructor is used when an object is loaded from a persistent // storage. Do not place any code here. } #endregion /// <summary> /// Konstruktor vytvoří nové nástupiště patřící k dané zastávce /// /// <param name="zastavka">Zastávka, ke které bude nově vytvářené /// nástupiště náležet public Nastupiste(Zastavka zastavka) : this() { // validace if (zastavka == null) { throw new ArgumentException(string.Format("EDJ0007::{0}", UnisComp.Pry.Doprava.JizdniRady.RS.Exceptions.EDJ0007)); } this.zastavka = zastavka; } /// <summary> /// Konstruktor vytvoří nové nástupiště patřící k dané zastávce /// v zadané session /// /// <param name="zastavka">Zastávka, ke které bude nově vytvářené /// nástupiště náležet /// <param name="session"> public Nastupiste(Zastavka zastavka, Session session) : this(session) { // validace if (zastavka == null) { throw new ArgumentException(string.Format("EDJ0007::{0}", UnisComp.Pry.Doprava.JizdniRady.RS.Exceptions.EDJ0007)); } this.zastavka = zastavka;
D
NÁVRH A IMPLEMENTACE APLIKACE
} #endregion //end constructors #region Metody #region Override /// <sumary> /// Metoda, je provedena po konstrukci objektu /// public override void AfterConstruction() { base.AfterConstruction(); // Use this constructor when you want to create a new object. // Place here your initialization code. } /// <summary> /// Provede validaci objektu nastupiste /// public override void Validate() { // overeni, ze je zadany vnoreny objekt Souradnice Debug.Assert(this.Souradnice != null, "Vnoreny podobjekt souradnice je null kurna"); // zaznamy, ktere se budou mazat, nema cenu kontrolovat if (this.state != ObjState.Active) { return; } base.Validate(); // pokud neni zadane ani cislo nastupiste, ani popis, je to chyba if ((!this.CisloNastupiste.HasValue || this.CisloNastupiste == 0) && this.Popis == string.Empty) { throw new ArgumentException(string.Format("EDJ0008::{0}", UnisComp.Pry.Doprava.JizdniRady.RS.Exceptions.EDJ0008)); } } /// <summary> /// Ulozi objekt nastupiste /// public override void Save() { base.Save();
119
120
D
NÁVRH A IMPLEMENTACE APLIKACE
// zavolame ulozeni souradnic - nejsou agregovane // ale jenom pokud ma smysl je ukladat - a to pokud jsou dirty, // a nebo pokud jsou nove, a je tam neco zadane if (this.Souradnice.IsDirty || (this.Souradnice.IsNew && !this.Souradnice.IsEmpty)) { this.Souradnice.Save(); } } /// <summary> /// Vrati retezec o danem nastupisti /// /// public override string ToString() { // pokud je zadane cislo nastupiste, tak to bude hlavni obsah vypisu, // popr. i s oznacenim, pokud je zadane if (this.CisloNastupiste.HasValue && this.CisloNastupiste != 0) { return string.Format("Nástupiště č. {0}{1}", this.CisloNastupiste.ToString(), (this.Popis == string.Empty ? string.Empty : string.Format(" ({0})", this.Popis))); } else { // cislo neni zadane, tak vratime jenom oznaceni return this.Popis; } } /// <summary> /// Znovunacte objekt a jeho obsah /// /// <param name="forceAggregatesReload">True, pokud se maji nahrat i /// agregovane podobjekty, jinak false public override void Reload(bool forceAggregatesReload) { base.Reload(forceAggregatesReload); // reload souradnic - nejsou oznacene jako [Aggregated], ale vyznamove // jsou vlastnene timto nastupistem if (forceAggregatesReload) { this.Souradnice.Reload(); } } #endregion /// <summary>
D
NÁVRH A IMPLEMENTACE APLIKACE
121
/// Metoda vrati true, pokud dve predane nastupiste se shoduji bud v cisle, /// nebo pokud cislo neni zadane tak v popise, /// a pritom to jsou dve ruzne nastupiste /// /// <param name="prvni">Prvni z kontrolovanych nastupist /// <param name="druhe">Druhe z kontrolovanych nastupist /// Vrati true, pokud se dve ruzne nastupiste shoduji cislem, /// popr. popisem public static bool MajiShodnyObsah(Nastupiste prvni, Nastupiste druhe) { // pokud je to jedno stejne nastupiste (jedna instance), tak maji // samozrejme i stejny obsah if (prvni == druhe) { return true; } if (prvni.CisloNastupiste.HasValue && prvni.CisloNastupiste != 0 && druhe.CisloNastupiste.HasValue && druhe.CisloNastupiste != 0) { // pokud maji obe dve zadane nastupiste, tak pokud jsou obe dve // ty nastupiste shodne, vratime true, naopak pokud jsou teda // kazde jine, vratime false return (prvni.CisloNastupiste == druhe.CisloNastupiste); } else if ((!prvni.CisloNastupiste.HasValue || prvni.CisloNastupiste == 0) && (!druhe.CisloNastupiste.HasValue || druhe.CisloNastupiste == 0)) { // pokud ani jedno nema zadane cislo nastupiste, porovname popisy return string.Equals(prvni.Popis, druhe.Popis, StringComparison.InvariantCultureIgnoreCase); } else { // jedno ma zadane cislo a druhe ne, // takze kazdopadne nemaji shodny obsah return false; } } #endregion }//end class Nastupiste }//end namespace JizdniRady
122
D
Ukázky obrazovek nové aplikace Jízdní řády
Obr. 28: Formulář pro opravu zastávky v číselníku zastávek.
NÁVRH A IMPLEMENTACE APLIKACE
D
NÁVRH A IMPLEMENTACE APLIKACE
123
Obr. 29: Přehled zastávek, z kterého je možné volat funkce pro přidání nové, opravu či smazání zastávky.
124
D
NÁVRH A IMPLEMENTACE APLIKACE
Ukázka testovací třídy k otestování business třídy Nastupiste using using using using using using using
System; NUnit.Framework UnisComp.Pry.Spol.Base.DB; UnisComp.Pry.Spol.Autorizace.BL; UnisComp.Pry.Spol.Base.BL.Opravneni; UnisComp.Pry.Spol.Konstanty.BL; UnisComp.Pry.Doprava.JizdniRady.BL;
namespace UnisComp.Pry.Tests.Doprava.JizdniRady { [TestFixture] public class TestNastupiste { #region TextFixtureSetUp /// <summary> /// Metoda se zavola pred zacatkem testovani a nastavi pripojeni do /// databaze a overeni uzivatele, aby se dalo pracovat s databazi, kdyby /// bylo potreba /// [TestFixtureSetUp] public void Init() { // overeni uzivatele // nemuzete cekat ze do ukazky dam skutecny conncetionstring a // prihlasovaci udaje, jake jsou na serveru v Unis Computers OpravneniHelperGetter.Helper = OpravneniHelper.Instance; DbSession.ConnectionString = "ConnectionString"; Uzivatel.Authentize("username", "password"); // inicializace konstant KonstantyCache.Initialize(Session.DefaultSession); } #endregion TextFixtureSetUp #region Private Methods /// <summary> /// Metoda vytvori novou zastavku a vrati ji /// public Zastavka GetNovouZastavku() { // vezmeme prvni obec z ciselniku obci, jenom aby tam neco bylo Obec obec = Session.FindObject(new BinaryOperator("Id", 1)); if (obec == null) { throw new InvalidOperationException("V Db nejsou zadne obce");
D
NÁVRH A IMPLEMENTACE APLIKACE
} // vytvorime novou zastavku v te obci Zastavka retVal = new Zastavka(); retVal.Obec = obec; retVal.BlizsiMisto = "rest."; return retVal; } /// <summary> /// Metoda vytvori nove nastupiste, prida ho na zadanou zastavku /// a vrati ho /// public Nastupiste AddNastupisteNaZastavku(Zastavka zast) { Nastupiste retVal = new Nastupiste(zast); zast.Nastupiste.Add(retVal); return retVal; } #endregion Private Methods #region Tests #region Uvodni overeni korektniho vytvoreni zastavky a nastupiste [Test, Category("Uvodni overeni")] /// <summary> /// Nove vytvorena zastavka nema zadne nastupiste /// public void TestNovaZastavkaNemaZadneNastupiste() { Zastavka zast = this.GetNovouZastavku(); Assert.AreEqual(zast.Nastupiste.Count, 0); } [Test, Category("Uvodni overeni")] /// <summary> /// Test konstruktoru - je mu predana korektni zastavka /// public void TestNewNastupisteValid() { Zastavka zast = this.GetNovouZastavku(); // zkusime vytvorit nove nastupiste Nastupiste nast = new Nastupiste(zast); Assert.IsNotNull(nast); } [Test, Category("Uvodni overeni")] [ExpectedException(typeof(ArgumentException))]
125
126
D
NÁVRH A IMPLEMENTACE APLIKACE
/// <summary> /// Test konstruktoru, mel by vyhodit vyjimku, kdyz je predana null /// zastavka /// public void TestNewNastupisteNullZastavka() { // zkusime vytvorit nove nastupiste, predame null, melo by vyletet Nastupiste nast = new Nastupiste(null); } #endregion Category Uvodni Overeni #region Cislo zastavky [Test, Category("Cislo zastavky")] /// <summary> /// Priradi do cisla nastupiste prazdny retezec - melo by odpovidat /// nezadanemu cislu nastupiste, tj. null /// public void TestCisloNastupisteJakoRetezecEmpty() { // vytvorime nastupiste na dane zastavce Zastavka zast = this.GetNovouZastavku(); Nastupiste nast = this.AddNastupisteNaZastavku(zast); // predame mu prazdny retezec nast.CisloNastupisteJakoRetezec = string.Empty; Assert.IsNull(nast.CisloNastupiste); }
[Test, Category("Cislo zastavky")] /// <summary> /// Melo by se povest prevest v retezci zadane validni cislo nastupiste /// public void TestCisloNastupisteJakoRetezecValid() { // vytvorime nastupiste na dane zastavce Zastavka zast = this.GetNovouZastavku(); Nastupiste nast = this.AddNastupisteNaZastavku(zast); // predame mu cislo nastupiste v retezci nast.CisloNastupisteJakoRetezec = "3"; Assert.AreEqual(nast.CisloNastupiste, 3); } [Test, Category("Cislo zastavky")] [ExpectedException(typeof(ArgumentException))] /// <summary> /// Priradi do cisla nastupiste spatny retezec - treba kde jsou pismena, /// melo by to vyletet ///
D
NÁVRH A IMPLEMENTACE APLIKACE
public void TestCisloNastupisteJakoRetezecInvalidFormat() { // vytvorime nastupiste na dane zastavce Zastavka zast = this.GetNovouZastavku(); Nastupiste nast = this.AddNastupisteNaZastavku(zast); // predame mu chybny retezec nast.CisloNastupisteJakoRetezec = "kravicka"; }
[Test, Category("Cislo zastavky")] [ExpectedException(typeof(ArgumentException))] /// <summary> /// Priradi cislo vetsi nez je rozsah nastupist /// public void TestCisloNastupisteJakoRetezecTooBig() { // vytvorime nastupiste na dane zastavce Zastavka zast = this.GetNovouZastavku(); Nastupiste nast = this.AddNastupisteNaZastavku(zast); // predame mu moc velke cislo nast.CisloNastupisteJakoRetezec = "124273437"; } #endregion Category Cislo Zastavky /* Spousta dalsich testu */ #endregion Tests } }
127
128
D
NÁVRH A IMPLEMENTACE APLIKACE
E
Rozsáhlé diagramy na volně vložených listech
Model podnikových procesů dopravní činnosti Obr. 30: Model podnikových procesů dopravní činnosti podniku zabývajícího se hromadnou silniční linkovou dopravou v Eriksson-Spencerově notaci, na druhé straně této vložené stránky formátu A3. Plnou černou čarou je znázorněna hranice subsystému procesů zabývající se dopravní činností (např. proces Zpracování mezd zaměstnanců již nepatří do tohoto subsystému, ačkoliv spolupracuje s některými jeho procesy).
Konceptuální class model aplikace Jízdní řády Obr. 31: Konceptuální (někdy bývá také uváděn pojem analytický) model tříd aplikace Jízdní řády, na druhé straně této vložené stránky formátu A3. Jsou naznačené vztahy mezi všemi pojmy problémové domény, u kterých je navržena jejich komputerizace.
Diagramy implementačního modelu tříd Obr. 32: Diagram tříd znázorňující třídy mající souvislost se zastávkami a přejezdy, a vztahy mezi těmito třídami. Stejně jako v následujících diagramech jsou zobrazeny jen dostupné členy těchto tříd (tj. jsou skryty private fieldy a metody). Za povšimnutí stojí vytvoření přejezdu na neperzistentní třídě Vzdalenost (umožňuje re-use funkcí spojených se zadáváním tarifní a skutečné vzdálenosti, protože ta se zadává ještě i mezi zastávkami na lince a také mezi zastávkami na spoji), a delegace většiny funkčností třídy Prejezd na helper třídu (tato abstrakce byla vhodná z tohoto důvodu, že způsob používání a práce s přejezdy se do značné míry liší v závislosti na nastavení konstanty).
Obr. 33: Diagram tříd shrnující různé číselníky. Významnou roli tu zabírají zejména číselník termínových omezení a jím použité třídy a enumerace, a číselník poznámek a standardní poznámky.
Obr. 34: Třídy týkající se linky a zastávky na lince. Jak je vidět, většina tříd jsou perzistentní business třídy, založené na bázové třídě BusinessObjectBase.
Obr. 35: Poslední část základní struktury aplikace jízdní řády, v tomto diagramu je znázorněn kompletní vztah mezi třídami Linka, Spoj, ZastavkaNaLince a ZastavkaNaSpoji, které tvoří hlavní jádro aplikace a na které jsou navázány téměř všechny ostatní funkčnosti.