Vývoj programů IB111 Základy programování Radek Pelánek 2017 1 / 47 Dnešní témata dokumentace testování dělení projektu do souborů volání programu z příkazové řádky styl, PEP8 případová studie – simulace sázení 2 / 47 Návrh a vývoj softwaru „softwarové inženýrství vývoj rozsáhlého softwaru nejen o zvládnutí „programování : specifikace, ujasnění požadavků návrh dokumentace testování integrace, údržba mnoho metodik celého procesu: vodopád, spirála, agilní přístupy, . . . 3 / 47 Dokumentace pro koho: pro sebe (při vývoji i později) pro ostatní jak: názvy (modulů, funkcí, proměnných) dokumentace funkcí, tříd, rozhraní komentáře v kódu 4 / 47 Dokumentace: obecné postřehy neaktuální dokumentace je často horší než žádná dokumentace sebe-dokumentující se kód – Nejlepší kód je takový, který se dokumentuje sám. (názvy funkcí, parametrů, dodržování konvencí, ...) u rozsáhlých projektů dokumentace nezbytnost psaní dobré dokumentace – trochu umění, nezbytnost empatie 5 / 47 Dokumentace v Pythonu dokumentační řetězec (docstring) první řetězec funkce (třídy, metody, modulu) konvenčně zapisován pomocí „trojitých uvozovek (povolují víceřádkové řetězce) def add(a, b): """Add two numbers and return the result.""" return a + b 6 / 47 Dokumentační řetězec víceřádkový def complex(real=0.0, imag=0.0): """Form a complex number. Keyword arguments: real -- the real part (default 0.0) imag -- the imaginary part (default 0.0) """ if imag == 0.0 and real == 0.0: return complex_zero ... 7 / 47 Dokumentační řetězce: ukázky """ This string, being the first statement in the file, will become the module’s docstring when the file is imported. """ class MyClass(object): """The class’s docstring""" def my_method(self): """The method’s docstring""" def my_function(): """The function’s docstring""" 8 / 47 Dokumentace vs. komentáře dokumentační řetězec co kód dělá, jak se používá (volá), ... brán v potaz při zpracování, dá se s ním dále pracovat: doc atribut, nástroje pro automatické zpracování, ... komentáře (#) jak kód funguje, jak se udržuje, ... při zpracování ignorovány 9 / 47 Testování: obecný postřeh Přístupy k testování: nevhodný: „přesvědčit se, že program je v pořádku vhodný: „najít chyby v kódu obecný kontext: „konfirmační zkreslení (confirmation bias) 10 / 47 Testování rozsáhlé téma: testování vs formální verifikace různé úrovně testování: unit, integration, component, system, ... různé styly testování: black box, white box, ... různé typy testování: regression, functional, usability, ... metodiky (test-driven development), automatizované nástroje unit testing (jednotkové testování) – testování samostatných „jednotek (např. funkce, metoda, třída) 11 / 47 Testování: dílčí tipy cíleně testujte okrajové podmínky, netypické příklady prázdný seznam (řetězec) záporná čísla, desetinná čísla pravoúhlý trojúhelník, rovnoběžné přímky přechodný rok „pokrytí kódu testem (code coverage) Jsou pomocí testu „vyzkoušeny všechny části kódu (funkce, příkazy, podmínky)? 12 / 47 Assert assert expression pokud expression není splněn, program „spadne (přesněji: je vyvolána výjimka, kterou lze odchytit) pomůcka pro ladění, testování užitečné zejména pro kontrolu „předpokladů příklad: faktoriál – vstup přirozené číslo 13 / 47 Refaktorování složitější kód nikdy nenapíšeme ideálně na poprvé refaktorování (code refactoring) – úprava kódu bez změny funkčnosti dobře napsané testy usnadňují refaktorování 14 / 47 Dělení projektu do souborů univerzální princip: velký projekt nechceme mít v jednom souboru důvody: jako dělení programu na funkce, o úroveň abstrakce výš 15 / 47 Dělení projektu do souborů jazykově specifické programovací jazyky se liší technickými požadavky i konvencemi hlavičkové soubory v C „hodně malých souborů v Javě terminologie: knihovny, moduly, balíčky, frameworky, ... 16 / 47 Terminologie v kontextu Pythonu pojmy s přesným významem: modul (module): soubor s příponou .py, funkce/třídy s příbuznou funkcionalitou balík (package): kolekce příbuzných modulů, společná inicializace, ... související pojmy používané volněji: knihovna (library) framework (framework) 17 / 47 Moduly v Pythonu modul poskytuje rozšiřující funkcionalitu zdroje modulů: standardní distribuce (např. math, turtle) separátní instalace (např. numpy, Image) vlastní implementace (základ: „.py soubor ve stejném adresáři ) použití: import module – následná volání module.function() import module as m from module import function from module import * (nedoporučeno) 18 / 47 Jmenné prostory jmenný prostor (namespace) ∼ mapování jmen na objekty jmenné prostory umožňují použití stejného jména v různých kontextech bez toho, aby to způsobilo problémy jmenné prostory mají funkce, moduly, třídy... moduly – tečková notace (podobně jako objekty) random.randint math.log 19 / 47 Proč nepoužívat „import * from X import * V malém programu nemusí vadit, ale ve větších projektech považováno za velmi špatnou praxi. „nepořádek v jmenném prostoru kolize, přepis překlepy se mohou chovat magicky složitější interpretace chybových hlášek Python Zen: Explicit is better than implicit. 20 / 47 Moduly – praktický příklad želví grafika, vykreslování obrázků do SVG (pro následnou manipulaci) mymath.py – trigonometrické funkce počítající ve stupních svg.py – generování SVG kódu, funkce typu: svg header(), svg line(), svg circle() manipulace s celkovým obrázkem (posun, rámeček), uložení do souboru turtle.py – třída reprezentující želvu, podpora pro více želv 21 / 47 Moduly – praktický příklad mymath.py svg.py turtle.py basic_shapes.pytrigonometry.py fractals.py další projekty run_turtle.py 22 / 47 Volání programu z příkazové řádky specifické pro programovací jazyky, příp. i operační systémy Python, Linuxové systémy: #!/usr/bin/python3 na prvním řádku chmod u+x filename.py 23 / 47 Volání programu z příkazové řádky pro rozlišení „importování a „volání : magická proměnná name funkce main (čistě konvence) def main(): # your code if __name__ == "__main__": main() 24 / 47 Volání programu z příkazové řádky argumenty z příkazové řádky: sys.argv ./myprogram.py test 4 knihovna argparse – sofistikovanější zpracování import sys print("Name of the program:", sys.argv[0]) print("Number of arguments:", len(sys.argv)) if len(sys.argv) > 1: print("The first argument:", sys.argv[1]) # Name of the program: myprogram.py # Number of arguments: 3 # The first argument: test 25 / 47 Styl psaní programů Při programování jde nejen o korektnost a efektivitu, ale i čitelnost a čistotu kódu: snadnost vývoje, testování údržba kódu spolupráce s ostatními (sám se sebou po půl roce) 26 / 47 Styl psaní programů obecná doporučení: nepoužívat copy&paste kód dekompozice na funkce rozumná jména proměnných, funkcí specifická doporučení (závisí na programovacím jazyce, příp. společnosti) – důležitá hlavně konzistence: odsazování bílá místa (mezery v rámci řádku) styl psaní víceslovných názvů 27 / 47 PEP8 – doporučení pro Python https://www.python.org/dev/peps/pep-0008/ výběr vybraných bodů obecný „duch doporučení celkem univerzální částečně však specifické pro Python (pojmenování, bílá místa, ...) 28 / 47 PEP8: Styl a konzistence konzistence (rostoucí důležitost) s doporučeními v rámci projektu v rámci modulu či funkce 29 / 47 PEP8: Odsazování a délka řádků standardní odsazení: 4 mezery nepoužívat tabulátor maximální délka řádku 79 znaků rady k zalomení dlouhých řádků 30 / 47 PEP8: Prázdné řádky oddělení funkcí a tříd: 2 prázdné řádky oddělení metod: 1 prázdný řádek uvnitř funkce: 1 prázdný řádek pro oddělení logických celků (výjimečně) 31 / 47 PEP8: Bílé znaky ve výrazech mezera za čárkou mezera kolem přiřazení a binárních operátorů zachování čitelnosti celkového výrazu ne okolo = v definici defaultní hodnoty argumentu nepoužívat přebytečné mezery uvnitř závorek 32 / 47 PEP8: Bílé znaky – příklady Ano: spam(ham[1], {eggs: 2}) Ne: spam( ham[ 1 ], { eggs: 2 } ) Ano: if x == 4: print x, y; x, y = y, x Ne: if x == 4 : print x , y ; x , y = y , x Yes: spam(1) No: spam (1) Yes: dct[’key’] = lst[index] No: dct [’key’] = lst [index] 33 / 47 PEP8: Bílé znaky – příklady Ano: x = 1 y = 2 long_variable = 3 Ne: x = 1 y = 2 long_variable = 3 34 / 47 PEP8: Bílé znaky – příklady Ano: i = i + 1 submitted += 1 x = x*2 - 1 hypot2 = x*x + y*y c = (a+b) * (a-b) Ne: i=i+1 submitted +=1 x = x * 2 - 1 hypot2 = x * x + y * y c = (a + b) * (a - b) 35 / 47 PEP8: Pojmenování – přehled stylů lowercase lower_case_with_underscores (snake_case) UPPERCASE UPPER_CASE_WITH_UNDERSCORES CapitalizedWords (CapWords, CamelCase, StudlyCaps) mixedCase Capitalized_Words_With_Underscores _single_leading_underscore single_trailing_underscore_ __double_leading_underscore __double_leading_and_trailing_underscore__ 36 / 47 PEP8: Pojmenování – základní doporučení proměnné, funkce, moduly: lowercase, příp. lower_case_with_underscores konstanty: UPPERCASE třídy: CapitalizedWords 37 / 47 Pojmenování: další rady jednopísmenné proměnné – jen lokální pomocné proměnné, nejlépe s konvenčním významem: n – počet prvků (např. délka seznamu) i, j – index v cyklu x, y – souřadnice nikdy nepoužívat: l, O, I (snadná záměna s jinými znaky) angličtina, ASCII kompatibilita 38 / 47 PEP8: Komentáře Komentář, který protiřečí kódu, je horší než žádný komentář. „inline komentáře používat výjimečně, nekomentovat zřejmé věci Ne: x = x + 1 # Increment x doporučení ke stylu psaní komentářů (# následované jednou mezerou) 39 / 47 PEP8: Import vždy na začátku souboru doporučené pořadí: standardní moduly, third-party, lokální absolutní raději než relativní 40 / 47 Vývoj programu: případová studie jednoduchý, ale ne triviální problém – simulace sázení ilustrace přístupu k programování návrh, rozmyšlení postupu postupný vývoj, prototypování, testování 41 / 47 Simulace sázení: problém, motivace Základní sázky 1:1 (panna/orel, férová mince) Strategie Martingale: základní sázka 1 po výhře dát základní sázku po prohře zdvojnásobit sázku 42 / 47 Martingale Reklama na Martingale Martingale je výborná strategie, vedoucí k zaručenému zisku! Tedy pokud jste nekonečně bohatí. . . Jak to dopadne reálně? 43 / 47 import random import pylab as plt fm = [] for j in range(100): b = 1000 s = 1 for i in range(100): if random.randint(0, 1) == 1: b += s s = min(1, b) else: b -= s s = min(2*s, b) fm.append(b) plt.hist(fm) plt.show() 44 / 47 Simulace sázení: škaredé řešení ukázka řešení s typickými chybami: nevhodné názvy proměnných copy&paste kód (při porovnání s jinou strategií) konstanty s nejasným významem absence funkcí proč špatné: nečitelné nevhodné k testování nejde snadno experimentovat nejde snadno zobecnit 45 / 47 Simulace sázení: základní návrh programu class Strategy – reprezentace strategie sázení, atributy budget, history, metoda make bet play – odehrání jedné série sázek get final budget stats – opakovaná simulace jedné strategie print stats, compare strategies – zobrazení výsledků ⇒ programování „na živo 46 / 47 Shrnutí Vývoj kvalitního softwaru je nejen o dobrém zvládnutí samotného programování. ⇓ navazující předměty příště: praktické tipy, přehled programovacích jazyků 47 / 47