Kā es iemācījos mīlēt TDD

07.07.2010

Vakar es uzstājos ikgadējā Latvijas testēšanas konferencē ar prezentāciju “How I Learned To Stop Worrying and Love Test Driven Development” jeb kā es iemācījos pārtraukt uztraukties un sākt mīlēt testu virzītu izstrādi. Tā kā auditorijai patika gan slaidi (kurus pašrocīgi zīmēju uz iPad), gan arī izraisījās diskusija par saturu, tad es šeit pārpublicēju prezentācijas kopsavilkumu.

Spējajā programmatūras izstrādē (Agile software development) testēšana nav tikai “testētāja” loma, kā tas ir bijis tradicionāli, bet gan funkcija, ko jāveic jebkuram projekta dalībniekam. Testu virzīta izstrāde (Test Driven Development, TDD) ir viena no galvenajām spējās programmatūras izstrādēs praksēm, kas tiek rekomendēta programmatūras izstrādātājiem ikdienas darbā.

TDD ideja ir ļoti vienkārša. Pirms sākt jaunas funkcionalitātes izstrādi (jauna procedūra, funkcija, metode) vispirms jūs izdomājiet, kā jūs vēlētos, lai šī jaunā programmatūras vienība strādātu – uz kādiem ievaddatiem jūs sagaidat kādus rezultātus. Un šī sagaidītā funkcionalitāte tiek aprakstīta ar automatizētu vienībtestu, kas to pārbauda. Un sākotnēji izpildot šo testu tam vajadzētu beigties neveiksmīgi, jo mums šī funkcionalitāte vēl nav izstrādāta. Tikai tad mēs sākam rakstīt programmatūras kodu, lai šo funkcionalitāti realizētu un tas tiek darīts vienkāršākajā veidā, līdz tiek panākts ka izveidotais vienībtests beidzas veiksmīgi. Un pēc tam tiek pārbaudīts, ka arī visi iepriekšējie testi izpildas veiksmīgi, lai varētu pārliecināties, ka neesam neko “salauzuši”. Veicot šādu inkrementālu izstrādi ik pa laikam tiek konstatēts, ka būtu nepieciešams uzlabot esošās programmatūras iekšējo struktūru jeb dizainu. Tad tiek veikta “refaktorēšana” – programmatūras koda struktūras jeb dizaina uzlabošana, bet netiek mainīta sagaidītā funkcionalitāte. Un to, ka netiek mainīta funkcionalitāte, var pārbaudīt izpildot visus automatizētos vienībtestus.

Šī pieeja izklausās vienkārša un loģiska un tā tiek popularizēta no Agile “guru” puses, bet realitātē šo pieeju diemžēl praktizē tikai ļoti maza programmētāju daļa. Kādēļ tas tā ir?

Tādēļ ka cilvēki pēc dabas ir slinki un vienmēr mēģina atrast iemeslus, kādēļ neko nemainīt. Šeit ir pāris tipiskie argumenti, kādēļ “tas mūsu gadījumā nestrādās”:

  • “Būs nepieciešams divreiz vairāk laika, lai uzrakstītu gan kodu, gan testus.”
  • “Mums nav laika rakstīt vienībtestus, jo termiņi jau bija vakardien.”
  • “Mums ir liels esošās programmatūras kods, ko mēs uzturam, mēs nevaram tagad uzrakstīt testus visam esošajam kodam.”
  • “Mūsu esošā programmatūra ir tā uzrakstīta, ka to nevar viegli notestēt ar automatizētiem vienībtestiem.”
  • “Mūsu klients / vadība / vēl kaut kas neļauj programmētājiem veikt refaktorēšanu, visu laiku tiek prasīta tikai jauna funkcionalitāte.”
  • “Es vienā blogā izlasīju, ka TDD īstenībā nekādus ieguvumus nedod.”

Ja jūs kaut ko nemākat, tad jums vispirms tas ir jāiemācas un tikai tad var sākt izteikt pamatotus spriedumus par to. Un jārēķinās ar to, ka mācīšanās paņem kādu laiku un jūs nebūsiet produktīvi uzreiz pirmajā dienā (arī ja jūs sevi agrāk uzskatījāt par augstas klases programmētāju, tad tik un tā pirmajā dienā jūs būsiet TDD iesācējs). Un lai kaut ko iemācītos, vispirms to vajag darīt burtiski “kā grāmatā” un tikai pēc tam var sākt eksperimentēt un pielāgot (nevis sākt ar attieksmi, ka “mums tas neder”). Un attiecībā par TDD ir pieejamas gan labas grāmatas, gan arī labi demo “screencasts” (piemēram, kā to darīt Java vai Ruby gadījumā), kas palīdz iemācīties un saprast labākās TDD prakses.

Tad, kad es šādā veidā iemācījos TDD, tad es arī sāku daudz labāk pamanīt TDD ieguvumus:

  • Lai piegādātu kvalitatīvu strādājošu programmatūru, tad līdz šim vienīgais izgudrotais veids, kā par to pārliecināties, ir testēšana. Tādēļ “netestēšana” nekad nedrīkstētu būt kā alternatīva.
  • TDD gadījumā mazāk tiek veikta atkļūdošana (debugging). Tispiski programmētāji pavada daudz laika uz atkļūdošanu, bet pēc tam kad ir panākts, ka programmatūra strādā, tad viss atkļūdošanas laikā uzrakstītais pagaidu kods tiek “izmests miskastē”. TDD gadījumā šīs atkļūdošanas kods tiek saglabāts kā vienībtesti, kas tiek automātiski izpildīti arī nākotnē, lai pārliecinātos, ka vēlāk netiek atkārtota tā pati kļūda.
  • Mazāk laika tiek patērēts uz to, lai identificētu, kurā vietā ir kļūda. TDD daudz efektīvāk palīdz atklāt tās kļūdas, kuras rodas mazu izmaiņu blakusefektu gadījumā, kuri ar manuālo testēšanu netiek identificēti (jo neviens neiedomājas, ka tur varētu būt problēma), bet automātiskie vienībtesti, kas vienmēr tiek izpildīti visi, to var atklāt.
  • TDD var un vajag izmantot arī kļūdu labošanā – atklājot kādu jaunu kļūdu vispirms tiek uzrakstīts vienībtests, kas atkārto šo kļūdu un tikai pēc tam tiek labots kods, lai atrisinātu problēmu. Šī pieeja arī noder, lai sāktu izmantot TDD esošas programmatūras uzturēšanā un jaunu izmaiņu izstrādē – sākt rakstīt testus tām vietām, kur rodas kļūdas, vai kur tiek veiktas izmaiņas.
  • Iemācoties TDD jūs saprotiet, ka tā ir projektēšanas / dizaina aktivitāte, kurai automātiskie testi ir kā papildus ieguvums. Jūs vienmēr vispirms padomājat, kāds ir funkcijas vai metodes vai moduļa nolūks un kā jūs to izmantosiet un kā jūs to testēsiet pirms jūs sākat kodēšanu, kā rezultātā TDD uzlabos jūs koda dizainu un uzturamību.
  • TDD rezultātā jūs iegūsiet arī mazāku koda apjomu, kas dara tikai to, kas patlaban nepieciešams. Un jo mazāks ir koda apjoms, jo mazāk tur būs kļūdas un jo vieglāk to būs mainīt un papildināt.
  • TDD ļauj veikt pastāvīgu refaktorēšanu un programmētājiem nevajag prasīt atļauju veikt refaktorēšanu. Ja programmas kods pastāvīgi tiks mainīts un uzlabots, tad tas visu laiku būs gatavs izmaiņām un jūs nenonāksiet līdz situācijai, kad mazu izmaiņu veikšanai būs nepieciešams ieguldīt ļoti lielu darbu dēļ tā, ka refaktorēšana tika visu laiku atlikta.
  • TDD mērķis ir visu laiku uzturēt programmatūru bez zināmām kļūdām – ja visi testi izpildās veiksmīgi, tad mums nav zināmu kļūdu. Ja tiek konstatēta jauna kļūda, tad tā ir jāatrisina vispirms, pirms tiek veikta jaunas funkcionalitātes izstrāde.

Un visu šo ieguvumu rezultātā es esmu konstatējis, ka īstenībā TDD izstrāde (ja to iemācās darīt pareizi) ir ātrāka nekā tradicionālā daļēji automatizētā, daļēji manuālā testēšana pēc tam, kad programmatūra ir izstrādāta. Kā arī kopējais patērētais laiks, lai sasniegtu kvalitatīvu rezultātu, ir mazāks.

Protams, TDD nav sudraba lode un neaizstāj visus testēšanas veidus. TDD ir efektīvs, lai notestētu, ka uz noteiktiem ievaddatiem un precīzi definēti rezultāti. Bet attiecībā uz lietotāju interfeisu ir svarīgi, vai lietotāja interfeiss labi izskatās, vai ir pareizās proporcijas un krāsu palete, vai tas ir pietiekoši vienkāršs un saprotams no lietojamības viedokļa. Uz šo aspektu testēšanu vajag izmantot cilvēkus ar atbilstošām lietojamības kritēriju testēšanas iemaņām. Bet nevajag izmantot cilvēkus kā testēšanas robotus, kas caur lietotāju interfeisu mēģina notestēt to, ko daudz efektīvāk var izdarīt ar vienībtestiem vai integrācijas testiem atbilstošā zemākā līmenī.

Programmētājiem nepatīk manuālā testēšana un “čeklistu” aizpildīšana, programmētājiem patīk kodēt. Tādēļ arī vajag palīdzēt programmētājiem iemācīt, ka testēšana ar kodēšanas palīdzību ir tikpat interesanta, kā cita veida kodēšana 🙂


Rekomendācijas programmētāju kvalifikācijas darbiem

14.06.2009

Šajā nedēļā piedalījos Latvijas Universitātes Datorikas fakultātes programmētāju kvalifikācijas darbu vērtēšanas komisijā – gan recenzēju daudzus darbus, gan arī klausījos un vērtēju klātienē vēl vairāk darbus. Kā jau katru gadu man nepatika vairākas tendences, kas bija sastopamas daudzos darbos, tādēļ gribēju šeit izkratīt sirdi un padalīties ar rekomendācijām, kā vajadzētu labāk rakstīt šos darbus, lai saņemtu labu vērtējumu no manis kā potenciālā vērtētāja 🙂

Strādājošs, kvalitatīvs un uzturams programmatūras kods ir primārais mērķis

Kā vienu no pirmajām lietām gribēju uzsvērt šo Agile principu, jo programmēšanas kvalifikācijas darbos galvenais mērķis ir parādīt, ka autors spēj radīt kvalitatīvu programmatūru. Tādēļ:

  • Strukturējiet programmatūru saprotamos funkcionālajos moduļos.
  • Sadaliet katru moduli nelielās funkcijās vai metodēs – nekādā ziņā viena funkcija vai metode nedrīkst būt pa daudzām lappusēm. Jo tās būs īsākas un saprotamākas, jo labāk.
  • Komentāros rakstiet, kāpēc jūs kaut ko dariet, nevis vēlreiz atkārtojiet to, kas redzams kodā.
  • Sadaliet biznesa loģiku un attēlošanas loģiku dažādos moduļos (sliktākie piemēri bija, kad vienā failā ir gan PHP, gan SQL, gan HTML, gan Javascript kods sajaukts vienā lielā putrā).
  • DRY (Don’t Repeat Yourself) princips – ja kāds kods bieži tiek ar copy-paste dublēts, tad tas nozīmēt, ka šo loģiku vajag izdalīt kādā kopējā funkcijā vai metodē, lai izvairītos no koda dublēšanas.

Vienkārša, saprotama un vajadzīga dokumentācija

Daudzos darbos sliktu kodu centās kompensēt ar lieliem dokumentācijas blāķiem, kas manā vērtējumā darbu var tikai pasliktināt.

  • Labāk dokumentāciju rakstiet īsāku un saprotamāku, nevis garu un nesaprotamu.
  • Izvairieties no triviālu lietu skaidrošanas un liekvārdības, bet neaizmirstiet paskaidrot lietas, kas ir specifiskas jūsu darbam.
  • Arī dokumentācijai ir jābūt DRY – nekopējiet vienus un tos pašus aprakstus uz dažādām dokumentācijas vietām.
  • Nemāniet lasītāju, ka vispirms uzrakstījāt visu prasību specifikāciju dokumentu, pēc tam projektējuma aprakstu un tikai tad kodējāt. Ūdenskrituma metode nav vienīgā pieeja – tā ir novecojusi un mūsdienās parasti nepiemērota pieeja. Droši izmantojiet un aprakstiet iteratīvās / inkrementālās / spējās izstrādes pieejas, ja tas ir patiesais veids, kā esat veidojuši savu darbu.

Testējiet ar kodu nevis ar dokumentāciju

Daudziem liekas, ka labākais veids, kā pārliecināt lasītāju, ka viņi ir dikti labi testējuši, ir saproducēt lielu testēšanas dokumentāciju. Bet, manuprāt, liela un sarežģīta testēšanas dokumentācija apliecina tikai to, ka šie testi netika bieži izpildīti.

  • Ļoti rekomendēju apgūt jūsu izvēlētās programmēšanas valodas atbilstošo automatīzēto vienībtestēšanas ietvaru. Automatizēti un regulāri izpildīti vienībtesti vienmēr būs labāki nekā gari un manuāli izpildāmi testi.
  • Primāri testējiet jūsu darba svarīgāko un potenciāli riskantāko funkcionalitāti, nevis rakstiet daudzus vienkāršus (piemēram, lauku obligātuma pārbaudes) testus.

Drošība

  • “Paroļu šifrēšana” nav vienīgā drošības problēma un/vai prasība.
  • Ja jūsu programmā ir dažādi lietotāji ar dažādām tiesībām, tad pieejas tiesības ir vienas no primārajām drošības prasībām, kas arī ir jātestē.
  • Pirms veidojiet “web” bāzētu sistēmu, iepazīstieties ar biežākajām drošības problēmām “web” bāzētajās sistēmās – sāciet ar SQL injekcijas problēmām.

Konfigurāciju pārvaldība

  • Mūsdienās veikt programmatūras koda pārvaldību tikai ar failu rezerves kopēšanas palīdzību profesionālam programmētājam vairs nebūtu pieļaujams.
  • Apgūstiet un lietojiet atbilstošus versiju kontroles rīkus, piemēram, Subversion, Git vai citus. Versiju kontroles rīki ir vieni no programmētāju pamatrīkiem.

Darbietilpības novērtēšana

  • Darbietilpības novērtēšana ir paredzēta, lai prognozētu potenciālo darbietilpību pirms jūs esat sākuši programmēt sistēmu. Darbietilpības novērtēšana nav paredzēta, lai pamatotu komisijai, ka jūs tiešām esat veltījuši 3 mēnešus darba izstrādei.
  • Neizmantojiet sarežģītas COCOMO novērtēšanas metodes, ja jums nav skaidrs, ko tās prognozē un ja jums rezultāti sanāk pavisam savādāki nekā faktiski patērētais darbs. Un netaisnojieties ar to, ka “COCOMO paredzēts lieliem projektiem” – lielie projekti nav nekas tāds briesmīgs, kuros pēkšņi visas vienkāršās lietas ir jātaisa piecreiz sarežģītāk.
  • Ja jūs izmantojat iteratīvo / spējo (Agile) pieeju pieeju, tad izmantojiet atbilstošas spējās novērtēšanas tehnikas.

Ceru, ka šīs manas rekomendācijas studenti nākamreiz “uzgooglēs” un ņems tās vērā kvalifikācijas darba izstrādē 🙂


Uzstājos BibCamp 2

07.11.2008

Tā kā mūsu kompānija bija viens no galvenajiem organizatoriem BibCamp 2 “nekonferencei bibliotekāriem”, tad organizētāji palūdza mani piedalīties un kaut ko noprezentēt. Tā kā runāt par man tuvām lietām man patīk :), tad es pieteicos uz veselām trīs prezentācijām.

Tālāk redzami slaidi no manām prezentācijām:

Web 2.0

Web lietojamība

Spējā jeb Agile pieeja

Galvenais “izaicinājums” bija noprezentēt šīs tehnoloģiskās tēmas pēc iespējas ne-tehnoloģiskākā veidā. Kopumā izdevās samērā veiksmīgi, jo auditorijai bija daudz jautājumu. Vislielākā interese bija par web lietojamību, jo šīs idejas var izmantot jebkuršs arī vienkāršu web lapu veidošanā.

Kopumā iespaids par BibCamp palika labs un noteikti rekomendēju arī citās jomās sākt organizēt šāda veida “nekonferences”. Par citiem BibCamp 2 iespaidiem var izlasīt Jāņa un Kristapa blogos.


Iemācieties plānot bez elektronisko rīku palīdzības

23.04.2008

Jau vairāk kā gadu esmu kļuvis par spējās programmatūras izstrādes (agile software development) pieeju pārliecinātu piekritēju un popularizēju to gan kolēģiem, gan klientiem. Un sanāk diezgan veiksmīgi 🙂

Viena no “agile” vērtībām ir “Individuals and interactions over processes and tools” – projektā iesaistītie cilvēki un viņu sadarbība ir svarīgāka nekā kādi formāli definēti procesi un tehnoloģiski rīki. Par šo tēmu bieži nākas runāt uzsākot kāda projekta pārveidi “agile” virzienā.

Viena no biežākajām tēmām ir par to, kādus rīkus izmantot projekta darbu plānošanā. Mēs esam pieraduši, ka darbu plānošana un kontrole notiek ar kādu rīku palīdzību – ar MS Project plāniem, ar Excelī sarakstītiem darbu sarakstiem vai arī ar vēl kādu komplicētāku rīku. Un tāpēc tiek uzdots jautājums, ar kādu rīku vislabāk vajadzētu plānot un kontrolēt “agile” projektus.

taskboard.png

Un mana atbilde uz to ir tāda, ka varbūt nemaz nevajag nekādus tehnoloģiskus rīkus. Ja projekta komanda ikdienā atrodas kopā vienā telpā, tad daudz efektīvāki var būt “manuālie” plānošanas rīki – papīra lapiņas un siena, kur šīs lapiņas var novietot:

  • papīra lapiņas neuzspiež obligātu informācijas struktūru, kā rezultātā tiek pierakstīts tikai tas, kas patiešām ir būtiski
  • papīra lapiņas var bez sirdsapziņas pārmetumiem izmest miskastē tad, kad redzmas, kad kādu darbu vajag pārformulēt savādāk vai sadalīt sīkākos darbos
  • plānošanas procesā papīra lapiņas daudz uzskatāmāk var novietot uz galda un kopīgi pārvietot, grupēt, sadalīt pa prioritātēm
  • papīra lapiņas dod veicamajiem darbiem “fiziskas esamības” efektu – tas vairs nav tikai ieraksts kaut kādā kaut kur noslēptā failā
  • papīra lapiņas pie sienas sagrupētas pēc darbu izpildes statusa ir vienmēr redzamas visiem projekta dalībniekiem un visi ir lietas kursā par patreizējo projekta darbu statusu – ir mazāka vajadzība pēc garlaicīgajām projekta statusa sanāksmēm, kur jāatskaitās par paveikto.

Un ja tiešām vēlāk tomēr būs nepieciešami elektroniski plānošanas rīki (kas var būt nepieciešams, ja visa projekta komanda regulāri neatrodas kopā vienā telpā), tad vispirms izmēģinot “manuālās” plānošanas metodes būs iegūta labāka sapratne par to, kādu elektronisko rīku vajadzētu izmantot un kādā veidā izmantot.

Tāds netipisks e-lietu raksts, kurā rekomendēju dažreiz atteikties no e-rīkiem 🙂