Stejně jako živý organismus a většina přírodních jevů i softwarové projekty žijí svým životem, který začíná z prázdnoty, pokračuje prudkým růstem v dětství, vstoupí do dlouhého období dospělosti a pak následuje sestup, který téměř připomíná senilitu. [Jones89]
Na rozdíl od dítěte se software nestává moudřejším a schopnějším. Bohužel zjevně stárne a chřadne. [Lyons81]
V životním cyklu programového díla představuje údržba závěrečnou část. Často bývá podceňována, přestože představuje zhruba 80% času v životě programu. V této etapě se nejvíce zhodnotí úsilí věnované specifikaci, návrhu a dokumentaci programového díla, tj. činnostem, které nejsou přímo programováním jako takovým.
Na konci 70. let odhadl B.W.Boem, že zhruba 50% času programátorů představuje čas strávený údržbou existujících produktů. V roce 1990 pak bylo odhadnuto, že na světě je používáno více jak 100 miliard řádek zdrojového kódu. Nejméně 80% z tohoto množství tvoří nestrukturované, vyspravované a špatně dokumentované programy. Udržet tento software v chodu spotřebovává enormní materiální a lidské kapacity: chyby je nutno opravovat a systémy je nutno přizpůsobovat měnícím se podmínkám. Softwarová údržba je definována v IEEE Std 729 (1983) jako:
Modifikace softwarového produktu po jeho předání za účelem opravy chyb, zlepšení výkonnosti nebo dalších atributů, nebo přizpůsobení změněnému prostředí.
Softwarová údržba se tedy neomezuje pouze na opravu latentních chyb. Nejčastější rozlišení zahrnuje 4 druhy údržbových prací:
Na obr. 1 je uvedeno rozložení jednotlivých aktivit.
Obrázek 1: Podíly údržbových prací
Ačkoliv je uvedený graf založen na datech ze 70. let, poslední studie ukazují, že situace se nemění k lepšímu. S narůstajícím objemem instalovaného softwaru podíl údržby k ostatním pracem vzrůstá a vzájemný poměr údržbových aktivit se nemění.
Změny jak okolí systému, tak uživatelských požadavků jsou nevyhnutelné. Software modeluje část reality a realita se mění. Software se tedy musí vyvíjet. Velké procento z toho, co nazýváme údržbou, je ve skutečnosti vývoj.
Profesionální přístup k údržbě software respektuje následující aspekty:
D. Parnas vyprávěl kdysi následující anekdotu:
Letadlo je vybaveno 2 výškoměry, jejichž hodnoty jsou snímány a dále zpracovány (zobrazeny) počítačem. Původní kód pro zobrazení měl tvar
IF not-read1(V1) GOTO DEF1;
display(V1); GOTO C;
DEF1: IF not-read2(V2) GOTO DEF2;
display(V2); GOTO C;
DEF2: display(3000);Protože se ztratila dokumentace, byl nekomentovaný kód restrukturalizován do tvaru
if read-meter1(V1)
then display(V1)
else if read-meter2(V2)
then display(V2)
else display(3000)
endif;Protože ani teď nebyla objasněna záhadná hodnota "3000", byl nalezen programátor - autor. Ten vysvětlil, že nevěděl, co při poruše obou výškoměrů zobrazit, a tak se zeptal pilota, jaká je jeho průměrná letová výška. Softwaroví údržbáři se snažili na základě tohoto vysvětlení celou záležitost napravit - zobrazit na displeji výstražný nápis "STOUPEJTE !". To se jim však nepodařilo prosadit, neboť ve výcvikových manuálech již byla na trvalo zakotvena instrukce: Pokud displej ukazuje 3000 déle jak 1 sekundu, STOUPEJTE !
Tato historka ilustruje hlavní problémy údržby existujících programů. Za hlavní příčiny problematické údržby jsou považovány:
Označení nestrukturovaný kód zde souhrnně označuje všechny špatně navržené/kódované systémy. Projevuje se mnoha symptomy: použití "goto", dlouhé procedury, špatné a nekonzistentní pojmenování, vysoká složitost modulů, slabá koheze a silné propojení, nedosažitelný kód, velká hloubka vnoření "if-then-else" atd.
Velké SW systémy jsou (v případě úspěšného dokončení) dlouho používány. Změny vynucené praktickým používáním zvyšují v čase entropii systému. Výchozí struktury degradují a vzrůstá vnitřní složitost. Systém se stane neudržovatelný a bylo by nejlépe jej nahradit zcela novým systémem. To však nelze z mnoha důvodů jednoduše realizovat - nahradit osvědčený systém s mnoha sice nepříjemnými, ale známými nedostatky novým neověřeným systémem? Riziko je příliš velké!2
Vývoj nového systému je buď příliš nákladný, nebo bude obsahovat příliš mnoho chyb, nebo již nikdo nedokáže zformulovat původní požadavky. Obvykle se všechny 3 negativní faktory uplatní současně. Vzrůstá tedy snaha o "recyklování" existujícího SW, o jeho úpravu do strukturované, lépe udržovatelné podoby.
Nedostatek znalostí aplikační oblasti je všeobecným jevem, se kterým se potýká vývoj softwaru. Tento nedostatek se dále stupňuje během údržby. Jediným spolehlivým zdrojem poznatků o aplikační oblasti bývá obvykle pouze vlastní zdrojový text programu. Dobře míněné zásahy do nedostatečně pochopené aplikace mohou mít nepředvídatelné následky a dále stupňují nároky na údržbu.
Chybějící nebo neúplná dokumentace samozřejmě přispívá k problémům údržby. Nejvážnějším problémem je však především neaktuální dokumentace, tj. dokumentace, jejíž údaje jsou v rozporu se skutečností. Zkušení programátoři dokumentaci nevěří! Díky napjatým termínům během vývoje se kvalita dokumentace zhoršuje. I při dodržení stanovených pravidel však může mít dokumentace dále uvedené nedostatky:
Samo slovo "údržba" má negativní zabarvení. Údržba je považována za druhořadou práci. Nemá v sobě intelektuální výzvu a odměnování. V organizaci jsou údržbou pověřováni nově přijatí, nezkušení nebo méně zdatní pracovníci.
Ve skutečnosti je údržba velmi obtížná práce. Zahrnuje podstatně širší spektrum činností, než musí provádět většina vývojových pracovníků. Udržované programy, které napsali jiní lidé, je třeba pochopit, správně zdokumentovat jejich činnost, restrukturalizovat, opravovat atd. Toto je obvykle nutné provádět ve značném časovém stresu. Údržbář musí být chytřejší a zručnější, než vývojář! Řádně fungující oddělení údržby je pro firmu životně důležité.
Zpětné inženýrství je definováno jako proces analýzy předmětného systému s cílem identifikovat komponenty systému a jejich vzájemné vazby a/nebo vytvořit reprezentaci systému v jiné formě nebo na vyšší úrovni abstrakce.
Podle uvedené definice se zpětné inženýrství zabývá pouze inspekcí systému. Změny v systému a jeho restrukturalizace do této oblasti nespadají. V definici jsou zmíněny dvě kvalitativně odlišné reprezentace systému vytvořené zpětným inženýrstvím. Jedná se o obnovení návrhu4 a obnovení dokumentace5.
Obnovení dokumentace má za úkol odvodit sémanticky ekvivalentní popis na stejné úrovni abstrakce. Obnovení návrhu odvozuje sémanticky ekvivalentní popis na vyšší úrovni abstrakce.
Zpětné inženýrství je však často používáno během změn původního systému. V tomto kontextu se rozlišují dva druhy činností - restrukturalizace a reinženýrství6. Zde je vhodné poznamenat, že v literatuře bývají názvy reverse engineering a reengineering často zaměňovány.
Restrukturalizace se zabývá transformací systému z jedné reprezentace do jiné, na stejné úrovni abstrakce. Funkce systému se při restrukturalizaci nemění. Za restrukturalizaci je považováno i nové naprogramování modulu poté, co byl revidován návrh. S restrukturalizací se v posledních letech setkáme jako s činností, jejímž cílem je konvertovat existující software do podoby, kdy je složen ze znovupoužitelných modulů. Náklady vložené do této činnosti se nevrátí pouze v úsporách při údržbě, ale i při tvorbě nových systémů.
Reinženýrství (někdy nazývané renovace) provádí zásahy a změny do reálného systému nebo do dokumentů na příslušné úrovni abstrakce. Pokud je renovace prováděna na vyšších úrovních (např. v požadavcích nebo na úrovni návrhu), pak samozřejmě následuje přímé inženýrství7, které změny šíří do nižších úrovní.
Jestliže předáte nestrukturovaný, nemodulární nepořádek některému ze systémů, které řeší restrukturalizaci, obdržíte v nejlepším případě strukturovaný, nemodulární nepořádek. [Wendel86]
Zpětné inženýrství se většinou neomezí pouze na obnovení dokumentace. Často nás bude zajímat, proč jsou určité záležitosti řešeny určitým způsobem, jaký je význam zkoumaného fragmentu kódu apod. Musíme proto znát, jaké pracovní postupy používají programátoři při údržbě, jakým způsobem studují text programu. Studie údržbových aktivit ukázaly, že
Při přímém inženýrství obvykle postupujeme od vyšších úrovní abstrakce k nižším úrovním implementací. Během tohoto procesu se ztrácí informace8. Jestliže chceme projít opačným směrem k vyšší hladině abstrakce, musíme ztracenou informaci rekonstruovat. Východiskem pro rekonstrukci je především poslední zachovalý (a doufejme že platný) zdrojový kód programu.
Programátoři používají při zkoumání kódu různé zdroje informací. Je-li např. k dispozici návrhová dokumentace, pak lze odhalit něco o struktuře systému. V nejčastějším případě je však zdrojový kód jediným spolehlivým zdrojem informace.
Zkušení programátoři vědí, že text programu se skládá převážně ze stereotypně používaných, jednoduchých sledů instrukcí a že v několika místech jsou soustředěny skutečné lahůdky - "know-how" algoritmy. Při zpětném inženýrství je snaha eliminovat nejprve ploché, nezajímavé úseky programu a izolovat podstatné části programu. Úspěšnost tohoto procesu je přímo úměrná zkušenostem a teoretickým znalostem luštitele kódu.
Při systematickém přístupu je postupně vytvářeno celkové porozumění systému systematickým studiem programu "shora-dolů". Systematický přístup formuluje kauzální vztahy mezi jednotlivými komponentami systému.
Pokud je naše porozumění systému založeno jen na lokálních informacích, pak změny mohou vyvolat párací efekt. V takovém případě jsou změny lokálně korektní, ale vytvářejí nové problémy na jiných, nepředvídatelných místech.
Při poznávání systému potřebujeme i jiný druh informací - vnější informace. Porovnejme 2 fragmenty kódu, které řeší shodnou úlohu:
procedure A(var x: w); begin b(y, n1); b(x, n2); m(w,[x]); y:=x; r(p[x]) end; procedure Zmen_Okno(var nove_okno: okno); begin Okraj(stavajici_okno, bez_zvyrazneni); Okraj(nove_okno, zvyrazneni); Premisti_kurzor(O[nove_okno]); stavajici_okno:=nove_okno; obnov(proces[nove_okno]) end; |
Druhý fragment obsahuje jistý druh vnější informace, zachycené ve zvolených jménech identifikátorů. Čím méně je takovýchto, z hlediska funkce programu druhotných, informací k dispozici, tím obtížněji se odhaduje smysl činnosti jednotlivých fragmentů a programu jako celku.
Přímým důsledkem výše zmíněných skutečností je to, že:
Automatická rekonstrukce návrhu ze zdrojového textu programu je neproveditelná !
Proces pochopení systému při zpětném inženýrství lze podpořit některými nástroji. Jsou to
Tyto nástroje podporují nejen zpětné inženýrství, ale údržbu obecně. Nástroje pro restrukturalizaci mají velkou cenu i v jednoduché podobě. Pokud reformátování usnadní čtení programu, pak usnadní i pochopení jeho funkce.
Samozřejmě, i možnosti restrukturalizace jsou omezené. Restrukturalizace rozhodně nedokáže transformovat špatně navržený systém na dobrý. Většinu změn - vylepšení systému a odstranění chyb - je stále nutné řešit manuálně.
Efektivní údržbu lze zajistit tehdy, pokud se řídíme při jejím provádění podrobně a striktně zpracovanými postupy. To se týká nejen implementace všech schválených změn, ale také postupu, jakým jsou návrhy na změny řešeny. J. Martin doporučuje použít dobře dokumentovaný proces řízení změn během údržby.
Uvedené kroky jsou základem modelu údržby, ve kterém je každá změnová žádost řádně prověřena, a pokud je schválena, je implementována disciplinovaným pracovním postupem včetně příslušných úprav dokumentace.
Podstatou toho přístupu je to, že v sadě dokumentace je nejprve nalezen dokument na nejvyšší úrovni, do které zasahuje změna. Po úpravě příslušného dokumentu jsou odvozené změny promítány do dokumentů na nižších úrovních. Změna se šíří shora-dolů.
Realita je samozřejmě odlišná. Často se setkáme s modelem rychlé opravy. Nezbytná změna je provedena ve zdrojovém kódu, poté je systém znovu přeložen a vytvořena nová verze. Na závěr a případně až po několika úpravách jsou změny přeneseny do dokumentace (pokud ovšem čas dovolí).
V tomto pracovním postupu změny překrývají předchozí změny a struktura systému degraduje velmi rychle. Vzhledem k rostoucí složitosti systému a nekonzistenci dokumentace je následná údržba stále obtížnější. Samozřejmě, jsou situace, kdy se nevyhneme rychlým opravám systému. Takovýto styl údržby je však nutné minimalizovat a problémům předcházet plánovanou preventivní údržbou. Mimo vyhledávání a předvídání nových úprav je úkolem preventivní údržby opravit strukturální škody napáchané při dřívějších rychlých opravách.
Změny v softwaru mění jeho strukturu. Jedině souběžným a cílevědomým uplatněním postupů pro zajištění kvality můžeme omezit negativní vliv údržby na produkt. Pokud známe faktory kvality softwaru, které ovlivňují rozsah a náklady údržby, pak na základě měření a vyhodnocení můžeme přijmout preventivní opatření. Příkladem může být rozhodnutí, zda změnu, jejíž implementace do stávajícího systému výrazně zhorší kvalitativní parametry, není (s ohledem na budoucí údržbu) lépe řešit nákladnějším způsobem, např. přepracováním větší části systému.
V současné době se již uplatňují postupy SQA9 během návrhu. Je však nezbytné, aby se principy sledování a zajištění kvality staly nedílnou součástí procesu údržby. Implementace změn vyžaduje stejně důkladnou kontrolu kvality jako návrh.
1 | Znalci Murphyho zákonů vědí, že každá změna je k horšímu.
... zpět do textu |
2 | V době psaní tohoto textu slyšel autor zprávu
o očekávaných potížích při řízení letového provozu v USA.
SW/HW systémy staré více jak 20 let se nikdo neodvažuje zaměnit
za nové a při řešení běžných letových situací se dispečeři
stále častěji spoléhají na modlitby.
... zpět do textu |
3 | design rationale
... zpět do textu |
4 | design recovery
... zpět do textu |
5 | redocumentation
... zpět do textu |
6 | reengineering
... zpět do textu |
7 | forward engineering
... zpět do textu |
8 | Znalost detailu neznamená automaticky hlubší poznání systému. Při
implementaci se téměř vždy ztratí informace, proč bylo zvoleno právě
toto řešení detailu a jaký je význam detailu v celku.
... zpět do textu |
9 | Software Quality Assurance
... zpět do textu |