Úvaha - zápis programového kódu
Tento článek vznikl na základě příspěvku na konferenci pro excel vývojáře - Pandora jejiž jsem dlouholetým členem. Dotaz byl v celku jednoduchý a tazateli se dostalo uspokojivé odpovědi. Tazatel však vyjádřil údiv nad jedním technickým obratem, který použil jeden z odpovídajících. Konkrétně se jednalo o tento příkaz
Pom = Pom And (Cells(t, A) = Cells(t - 1, A))
Následně se vlakno rozrostlo o další nápady k řešení včetne diskuze jak napsat tento příkaz co nejsrozumitelněji. Také já sem přispěl se svým názorem do pověstného "mlýna" a dle zásluh sem byl řádně rozemlen od mého kamaráda Vladimíra Hajdovského, kterého si vážím a uznávám ho, jako člověka s bohatou programatorskou praxi a ochotou se o své zkušenosti podělit a pomoci ostatním. Nicméně, na daný problém mám jiný názor, který se pokusim objasnit tímto článkem.
Příspěvek o kterém se tady rozepíšu, mužete najít na již zmiňovaném serveru Pandora včetně jeho kompletního vývoje. Pokud dojdete až nakonec, zjistíte, že nejen Vladimír, ale i někteří ostatní členové tohoto skvělého fóra, jsou zmatení mým zápisem programového kódu.
Pokusím se osvětlit, proč to dělám takto a ne jinak a proč v tom spatřuji oproti jiným přístupum výhody. Předne bych chtěl podotknout, že nejsem žádný počítačový harcovník a ani své znalosti jsem nezískal na žádných školách a to co vím o VBA a programování je díky,
- Igorovi Schvarcovi
- Jiřímu Čihařovi
(oba právě z Pandory) a samozřejmě Johnovi Walkenbachovi a Pandoře a hlavně sebevzdělávání - což mě přivedlo až ke změně myšlení o zápisu programového kódu. Stalo se to asi před rokem a půl (jaro 2008), kdy jsem usoudil, že mě neuspokojuje nabídka knih o VBA na českém trhu a rozhodl jsem se pro nákup zahraniční literatury. Volba padla na knihu Professional Excel Development The definitive Guide for Developing Applications Using Microsft Excel and VBA (koukněte se na hodnocení uživatelů)
S nadsázkou lze říct, že mi tato kniha změnila kompletně pohled na psaní kódu pod VBA, je otázkou zda to bylo dobře nebo ne. Kniha je doslova nabita praktickými radami a vysvětlením jak psát programový kód + výsvětlení proč by se to takto měl psát. Snažím se některých doporučení držet a doufám, že je aplikuji správně. Body které zmíním pokrýva kapitola 3 této knihy
Není to tak, že bych slepě přebral vše co je tam napsáno, jednoduše jsem některé rady shledal velmi užitečnými a zkusil jsem je aplikovat v praxi.
Následuje výčet bodů, které považuji za základ (a berte to opravdu jako základ)
- psát kód tak, aby jej někdo jiný mohl snadno upravit
- nestydět se za (rozumně) dlouhé názvy promenných - ShapesCount namísto SpCnt atd.
- psát samovysvětlující kód
- vyvarovat se tzv. "magických" čísel v kódu pomocí konstant
- zapouzdřovat procedury a funkce tak ať jsou samostatně použitelné kdekoliv (ideální stav)
- jedna rutina by měla obsahovat max 200 řádků kódu, pro lepší přehlednost
- dodržovat pravidlo, že funkce vrací výsledek a nikdy nic neprovádí (daří se, jak kdy)
- používat minimálně globální proměnné, proměnné na úrovní modulu a nepředávat více jak 5 parametrů pří volání jiných rutin
- oddělovat logiku userformu od řídící vrstvy
Některé body se mi daří dodržovat více některé méně, ale snažím se...
Na již několikrát zmíněném dotazu v Pandoře se pokusím demonstrovat některé z těchto bodů.
Po různých modifikacích, byl návrh na řešení původního dotazu takový;
For A = 2 To 21
If Cells(t, A) <> Cells(t - 1, A) Then Pom = False: Exit For
Next A
Je to jasné a čitelné a každý kdo už chvílí programuje s VBA by neměl mít žádný problém s dekodováním co tento kousek kódu dělá.
Pojďme se podívat co jsem napsal já. Již nějaký čas pracuji v týmu s kolegou ze zahraničí, a již několikrát se nám oběma potvrdilo ono okřídlené "v jednoduchostí je síla". Ovšem tady ona "jednoduchost" neznamená napsat program na co nejméně řádku, ale naopak, udělat to jiným programátorům co nejjednoduší, aby nebylo nutné dlouho uvažovat proč je tento kód napsán takto a co vlastně dělá.
Mnou navržené řešení bylo následující (přepsáno do češtiny)
Const SLOUPEC_ZACATEK As Byte = 2
Const SLOUPEC_KONEC As Byte = 21
Dim bolNestejne As Boolean
Dim bytSloupec As Byte
bolNestejne = False
For bytSloupec = SLOUPEC_ZACATEK To SLOUPEC_KONEC
If Cells(t, bytSloupec).Value <> Cells(t - 1, bytSloupec).Value Then
bolNestejne = True
Exit For
End If
Next bytSloupec
O dost delší, že ....? Pojďme si to rozebrat (proměnnou "t" jsem přebral z původního řešení)
Prvních 5 řádků kódu původní návrh neobsahuje, ale já jsem je uvedl abych mohl vše lépe vysvětlit.
- je to delší, protože když chcete něco vysvětlit jednoduše obvykle to zabere více času než to napsat složiteji.A nikomu se nechce moc psát = bolí z toho prsty Měli byste psát kód tak, aby byl čitelný řádek po řádku bez toho aby se "čtenář" musel někde vracet.
- jsou tam delší názvy proměnných a použity konstanty Rozumně dlouhé jména proměnných mají usnadnit čtení kódu, všichni víme, že proměnná "x", "y", "A1", "A2" popř. "myobj" nic neřeknou, ale všichni jsme si tim prošli. Proměnná bytSloupec jasně říká co je jejím obsahem a jelikož používám maďarskou notaci (která už je prý zastaralá), tak víte o jaký typ jde = Byte
- Konstanty Od přečtení výše zmíněné knihy se snažím vyvarovat tzv. "magickým" číslům v kódu. Je to vcelku nepříjemné, když v kódu, který napsal někdo cizí před x lety narazíte na podmínku typu
- Kompletní verze příkazu vč. vlastnosti Value Ne vždy to takhle píšu, jak víte každá metoda ve VBA má svou výchozí vlastnost (Value, Text apod.) takže proč se tím zabývat? Jsou vlastně jen dva důvody. Ten první je ryze praktický, my jako VBA vyvojáři jsme 100% odkázaní na Microsoft a na jeho zvůli co pro nás udělá. Nikde není napsáno, že v další verzi Office nebudou tyto výchozí vlastnosti odstraněny nebo přejmenovány, tak jak to mají jazyky .NET (zrovna u vlastnosti Value objektu Cells to neplati) např. prvek Button ma jino výchozí vlastnost ve VBA (Value) a v .NET (Text). Druhý důvod je prozaičtější, kód může upravovat programátor, který nikdy s VBA nedělal a o nějakých výchozích vlastnostech nemá ani ponětí, protože jeho programovací jazyk tuto vlastnost nemá.
- Více řádkový If .. End If Opět platí, dá se to napsat na jeden řádek, ale ztrácíme přehlednost. Rychleji si všimneme samostaného řádku než dvojtečky na stejném řádku (toto je maličkost)
If lngPocitadlo = 17 Then
' neco
End If
Proč, zrovna 17?, kde všude je tato podmínka použita? co když to změním?
Něco podobného je i v původním navrženém kódu
For A = 2 To 21
Proč až sloupec 2 a proč to končí sloupcem 21, a je to vůbec sloupec? Samozřejmě lze použít komentář, ale už nedodržujeme podmínku o "samovysvětlujícím" kódu. Následná změna konstanty je jednoduchá a změny se promítnou všude. Není nic lepšího, než hledat ono "magické" číslo 17 a zjišťovat kde všude bylo použito. Konstanty byste měli psát velkými písmeny a slova oddělovat znakem "_" pro jednoznačné odlišení od proměnných a vestavěných konstant. Konstanty byste měli použit kdykoliv, kdy není jasné proč jste použili nějaké číslo.
To je k tomuto malému příkladu asi vše. Jak sami vidíte, je to delší o 3 řádky (bez deklarací), ale vyplatí se to. Samozřejmě tento malý a izolovaný kousek kódu Vám neukáže veškeré výhody tohoto přístupu, ale zkuste tyto rady použít ve větším projektu nejlépe ještě pro někoho jiného nebo při spolupráci v týmu a možná mi dáte za pravdu.
Ještě bych se rád zmínil o jednom příkazu o kterém si myslím, že jej ostatní berou se skřípějicími zuby. Moje oblibené Range a jeho ekvivalent Cells. Tak jako většina jsem psal příkazy, které vypadaly nějak takto.
Range("A" & radek)
Od nějakého času se mi tento příkaz přestal líbit, nejde o žádný racionální důvod jde prostě jen o sympatie a určitě už od nějakého roku 2005 píšu stejný příkaz takto
Cells(radek, "A")
nebo
Cells(radek, 1)
Jednoduše mi tento zápis přijde programatorský čistší než to samé s Range, ale pro běžného smrtelníka ztrácí na přehlednosti. Jak sem psal, jde vyloženě jen o sympatie a já už sem si na tolik zvyknul, že čtení tohoto příkazu mi nedělá sebemenší problém a tak namísto tohoto příkazu
Range("A" & PrvniRadek, "S" & PosledniRadek).Select
u mě uvidíte něco takového
Range(Cells(PrvniRadek, "A"), Cells(PosledniRadek, "S")).Select
Toliko k úvaze jak psát programový kód. Co se týče výše zmíněných bodů, osobně mám pocit, že stojí za to je dodržovat a pokud si knihu objednáte a přečtete celou, najdete v ní spousty dalších praktických informací do Vaše VBA života. Zároveň však neříkám, že budu takto psát kód do konce života, vše se vyvíjí a může se změnit. Pokud máte k článku nějaké připomínky, napište je do komentářů, budu velmi vděčný za diskuzi.
Komentáře
Přehled komentářů
Hola, i já tak nějak podobně zapisuji kód. I když se i na mě snáší kritika za dlouhé názvy...
chce to uvazovat v sirsich souvislostech
(Premek, 9. 3. 2011 10:50)
Samozrejme nedodrzuji vsechny pravidla -jsem liny, ale zrovna v tomto pripade bych o nejakem pravidle neuvazoval. Ber to jako priklad, aby to bylo srozumitelne tak mas nejlepsi, kdyz si udelas objekty ktere si pojmenujes a pak je predas objektu Range. kde zapis pak muze vypadat takto
Range(OblastZacatek, OblastKonec).Select
Pravidla mohou i vzbudit úsměv
(Archangel, 9. 3. 2011 7:56)
s velkou slávou nám popisuješ knihu o programování ze které si SÁM sobě stanovil pravidla, a ve stejném článku tyto pravidla porušuješ (Range x Cells)- srozumitelnost pro jiného.
Pobavilo mě to :-))
zápis kódu
(blekii68, 3. 8. 2020 4:03)