środa, 9 września 2015

Testowanie na podstawie ryzyka

Testowanie na podstawie ryzyka - co i jak dokładnie należy sprawdzić?


Czy przed codziennym wyjazdem do pracy sprawdzamy poziom oleju i płynu hamulcowego, czy w każdy piątek oddajemy samochód do warsztatu? Nie. Natomiast przed wyjazdem na trzytygodniową podróż gdzieś daleko całą rodziną, zwykle tak. Skąd ta różnica? Tłumaczy sią ją różnym w obu tych sytuacjach poziomem ryzyka (zagrożenia), któremu chcemy zapobiec, sprawdzając.

Po pierwsze, podczas trzytygodniowych wakacji znacznie wyższe są skutki (konsekwencje) ewentualnej awarii, niż podczas codziennej jazdy z domu do pracy. Na wakacjach zepsuty samochód to bardzo zdenerwowana rodzina, to strata cennych dni, to – być może – nieplanowany postój gdzieś z dala od cywilizacji, wreszcie – wyższe niż w domu koszty naprawy. Konsekwencje awarii w na trasie dom-praca, to koszt taksówki, lawety i naprawy w znajomym warsztacie: o wiele niej dotkliwe.

Po drugie, inne jest też w obu sytuacjach prawdopodobieństwo takiej awarii, bo na wakacjach jedziemy z większym obciążeniem, może w trudniejszych warunkach – na przykład przez Alpy – i poza tym dłużej. Jakkolwiek szacujemy niezawodność swego auta, - czy średnio jedna usterka na miesiąc, czy jedna na sto lat - to prawdopodobieństwo, że pojawi się podczas trzytygodniowej, intensywnej eksploatacji, jest znacznie większe, niż podczas jazdy godzinnej i kilkunastokilometrowej.

Podsumowując ten przykład, waga[1] ewentualnej awarii podczas wyjazdu urlopowego jest na tyle znaczna, że gotowi jesteśmy ponieść pewne koszty – czas i cenę sprawdzania – po to, aby obniżyć jej prawdopodobieństwo, natomiast w sytuacji codziennej, poświęcenie nawet minuty na sprawdzenie poziomu płynu do spłukiwania szyby, wydaje się zbyt wielką inwestycją.

Identycznie jest przy testowaniu systemów i oprogramowania. Dzisiaj wprawdzie termin „testowanie na podstawie ryzyka”[2] (ang. risk-based testing) nie jest tak modny, jak kilkanaście lat temu, kiedy referat na ten temat uzyskał odznaczenie „best paper award” na prestiżowej konferencji EuroSTAR[3], ale  fluktuacje mody nie zmieniają rzeczywistości: to ryzyko – funkcja konsekwencji i prawdopodobieństwa ewentualnej awarii – decyduje o tym, jak intensywnie i w jakim zakresie sprawdza się i testuje:


Rysunek 1. Zależność intensywności testowania od poziomu ryzyka

Powyższa zasada, wprawdzie ogólnikowa, pozwala na znacznie trafniejsze, niż ma to miejsce w wielu projektach IT, określenie pożądanej staranności i czasochłonności testowania. Przy negocjowaniu umów wdrożeniowych często do oszacowanej liczby osobodni, potrzebnych na stworzenie oprogramowania, dodaje się dwadzieścia procent na testowanie. Ten sposób, choć teoretycznie bezsensowny[4], w praktyce może dawać zaskakująco trafne wyniki, ale tylko pod warunkiem, że poprawnie szacuje się ryzyko. Jeśli produktem jest gra online, w której formułę wpisany jest ryzyko, że nowe funkcje nie zawsze funkcjonują całkiem poprawnie, i wyłapywanie takich bugów jest traktowane przez użytkowników jako element zabawy, wtedy 20%, to o wiele za dużo. Natomiast przy testowaniu oprogramowania rozrusznika serca, czy każdego innego systemu krytycznego dla bezpieczeństwa, nawet 100% bywa za mało.

Przykład

Projekt obejmował udostępnienie użytkownikom portalu banku trzech nowych funkcjonalności, określanych jako „A”, „B” i „C”. Na postawie wymagań, architekt i programiści oszacowali pracochłonność prac programistycznych jako odpowiednio 5, 12 i 17 osobodni, a w umowie uwzględniono dodatkowe 20% czasu na testy (20% z 34 dni, daje siedem dni[5]).

Co na ten temat mówi ISTQB?


W „Sylabusie poziomu podstawowego” ISTQB[6] termin „ryzyko” pojawia się wielokrotnie, bardzo ogólnikowo, w tym kontekście, że (a) testowanie nie usuwa zagrożeń, ale wykrywając je, umożliwia ich obniżenie; (b) że zakres testowania zależeć powinien do poziomu ryzyka.

W rozdziale 5-ym tego sylabusa „Ryzyko z testowanie”, podana jest definicja i przykłady ryzyka projektowego i ryzyka produktowego, oraz – bardzo skrótowo – zarysowane kroki zarządzania ryzykiem na poziomie całego projektu. Sylabus nie opisuje w żaden sposób konkretnie, co oznacza i jak stosować koncepcję testowania na podstawie ryzyka dla planowania i projektowania testów.

W „Sylabusie poziomu zaawansowanego” ISTQB[7] opis tematyki jest poszerzony, ale także dotyczy głównie zarządzania ryzkiem w projekcie i nie precyzuje, co ono oznacza konkretnie dla projektowania testów. Ponadto, wspomniane są tam, skądinąd intersujące, metody wykorzystywane zarówno w inżynierii wymagań, jak i projektowaniu systemów krytycznych dla bezpieczeństwa, takie jak FMEA i FTA[8], oraz ale z testowaniem nie mające bezpośredniego związku.

Szacowanie prawdopodobieństwa awarii


Planując, projektując, wykonując i podejmując decyzję, czy można już zaryzykować zaprzestanie testowania, trzeba uwzględnić prawdopodobieństwo awarii – im jest ono wyższe, tym dokładniej warto sprawdzać.

Prawdopodobieństwo awarii zależy od dwóch czynników: możliwej obecności i rozkładu defektów (bugów), oraz tego, jak często i w jak sposób posługujemy się  programem (profilu użytkowania).

Prawdopodobieństwo defektów


Istnieje wprawdzie szereg czynników, zapewne skorelowanych z obecnością bugów w kodzie, ale wiedza na ten temat jest przypadkowa, anegdotyczna, a w najlepszym razie – niemożliwa do systematycznego zastosowania w praktyce. Przykładowo, wydaje się bardzo prawdopodobne, że jest bardzo silna dodatnia korelacja między toksycznymi relacjami w organizacji a liczbą i wagą popełnianych przez pracowników błędów, ale nie wynika z tego bynajmniej, aby godną polecenia w praktyce metodą projektowania testów była analiza kultury organizacji oraz dominujących w niej relacji między ludźmi!

Mimo powyższego zastrzeżenia, warto znać dobrze te czynniki, bo ta wiedza, jeśli ją posiadamy, pozwala – mimo niedostatków naukowej pewności – na znacznie większą skuteczność projektowania testów.
Złożoność oprogramowania
Im bardziej skomplikowany jest algorytm, realizowany przez oprogramowanie, tym większe prawdopodobieństwo  błędów i spowodowanych nimi defektów. Jak mierzyć komplikację algorytmów?

Po pierwsze, uwaga: przedmiotem pomiaru zwykle jest nie sam algorytm, a jego implementacja, o czym warto pamiętać – bywają programiści, zdolni w bardzo zawiły sposób zrealizować nawet najprostsze algorytmy.

Najlepiej znaną miarą złożoności algorytmu / kodu jest indeks McCabe[9]. Owszem, istnieją narzędzia, pozwalające na jego obliczanie, i firmy, których proces to uwzględnia (częściej jako wskazówkę, że zbyt zawiłą procedurę należy podzielić na mniejsze, niż jako wytyczną dla staranności testów), ale nieliczne. W praktyce, niepewnym, ale zadziwiająco trafnym źródłem wiedzy są subiektywne przekonania programistów. Jeśli testerzy mają do nich dostęp (jak w dobrym zespole Agile Scrum, realizującym zasadę „three amigos”[10]), pozwala to na znacznie lepszy dobór testów.

Uwaga: warto rozróżniać opinie o tym, że znany i określony algorytm jest zawiły, od brzmiących podobnie, ale mających dla testowania zupełnie inne konsekwencje[11], opinii o tym, że organizacyjny chaos nie pozwala jednoznacznie tego algorytmu poznać. Częstym tego przykładem jest nieznajomość w organizacji własnych reguł biznesowych (business rules).
Wielkość oprogramowania
Im większe[12] oprogramowanie, tym – niezależnie od jego złożoności – wzrasta oczywiście, przy niezmienionej gęstości defektów, ich liczba. W sensie technicznym nie istnieją jednak zależności, które mogłyby powodować także wzrost gęstości defektów w dużych programach, w porównaniu z mniejszymi, brak też więc podstaw do twierdzenia, aby duże programy należało w jakimś sensie testować staranniej, niż małe. Pośrednio, taka korelacja może się pojawić z tego powodu, że tworzenie dużego oprogramowania dokonywane jest zwykle w dużych projektach, gdzie problemy, spowodowane złą organizacją i niedojrzałymi procesami, lub czynnikami miękkimi (psychologia, dynami grupy), mogą wzrosnąć wykładniczo, co spowoduje większą częstość pomyłek i gęstość spowodowanych nimi defektów. Względnie częściej, niż w małych projektach, mogą pojawiać się defekty w interfejsach[13]. Są to jednak zależności na tyle ogólne, że trudno podać konkretną, jednoznaczną receptę na to, jak wziąć je pod uwagę projektując testy.
Znajomość technologii
Jeśli dziedzina, której dotyczy działanie tworzonego oprogramowania, oraz technologie wykorzystywane do jego implementacji (platforma sprzętowa, system operacyjny, wzorzec architektury, języki programowania, protokoły), są budowniczym dobrze znane, ryzyko pomyłek i spowodowanych nimi defektów jest na każdym poziomie niższe, w porównaniu z sytuacją, kiedy ta znajomość jest mniejsza. Brak wprawdzie dokładnych danych empirycznych, na ile poziom znajomości technologii przekłada się na wybory dokonywane przy określaniu strategii testowej, ale jako ogólną zasadę można przyjąć, że w projektach wykorzystujących nowe technologie należy na testowani przeznaczyć o około 1/3 więcej czasu / zasobów, niż w projektach używających technologii dobrze już wykonawcom znanych.
Wcześniejsze i późniejsze testowanie
Próbując oszacować właściwą staranność testów w jednej fazie projektów, należy koniecznie uwzględnić kontekst pozostałych poziomów testowania.

Przykład: chcąc określić, jak dużą staranność należy zachować podczas końcowych testów całego systemu w środowisku dostawcy, trzeba wziąć pod uwagę zarówno testy wykonywane wcześniej (testy jednostkowe programistów, testy komponentów, testy integracyjne interfejsów), jak i testy zaplanowane do wykonania później, na przykład testy akceptacyjne w środowisku docelowym. Zaniedbanie tej zasady może doprowadzić zarówno do testów niedostatecznych, jak i do zbędnego dublowania tych samych testów.

W praktyce, skutecznym sposobem na uwzględnienia testów wykonywanych na innych poziomach, i zsynchronizowania ich ze sobą pod względem staranności o zakresu, jest funkcja koordynatora testów (oczywiście, nie musi to być koniecznie osobna, pełnoetatowa rola – to zależy od wielkości projektu), mającego realne uprawnienia do narzucania innym podziału zadań.
Jakość wymagań
Zdaniem testowania jest sprawdzenie, czy budowany system zgodny jest ze zdefiniowanymi wymaganiami. Jednak w praktyce, ta podstawowa definicja często się nie sprawdza. Jeśli specyfikacja wymagań jest niewystarczająca, błędna, lub nieprecyzyjna, wówczas zadaniem testów jest także wykrycie, jakie naprawdę są potrzeby interesariuszy systemu, a do tego potrzeba więcej testów. Innymi słowy, gdy zaniedbanie inżynierii wymagań powoduje, że zadaniem testowania jest także – choćby w pewnym stopniu - pozyskiwanie i walidacja samych wymagań, wówczas trzeba zaprojektować znacznie obszerniejsze testy.
Ta zależność – im gorsze wymagania, tym obszerniejsze testy – nie zawsze się sprawdza. Nawet wtedy, gdy wymagania są niedostateczne i odpowiedzialność za ich zdefiniowanie i walidację spada na testerów, nie musi to być zrobione poprzez projektowanie większej liczny testów. Testerzy, pełniący w tym wypadku rolę inżynierów wymagań (analityków), mogą wymagania znajdować i sprawdzać także innymi metodami[14], niż poprzez projektowanie i wykonywanie testów produktu, lub jego komponentów.
W tym miejscu pojawia się ponownie pytanie, na które odpowiedzieliś[BB1] my już we wstępie do tej książki, jak zdefiniujemy czynność zwaną testowaniem. Czy przegląd dokumentacji, na przykład przegląd specyfikacji wymagań, to nie jest także forma testowania? Jeśli przyjąć taką, szerszą definicję testowania, wówczas opisywaną w tej sekcji zależność można określić inaczej: im mniej testowane były wymagania, tym więcej trzeba testować produkt, i odwrotnie.
Podejście do testowania, kładące nacisk na rolę testerów w pozyskiwaniu i walidacji wymaga[BB2] ń, jest tak zwane testowanie eksploracyjne.
Dojrzałość procesu
Przyjmijmy dla uproszczenie, że proces dojrzalszy, zgodnie z definicjami norm takich jak CMMI i SPICE[15], to taki, w którym stosuje się więcej procedur zapewnienia jakości, takich jak analiza biznesowa, inżynieria wymagań, projektowanie architektury, formalne przeglądy dokumentacji, systematyczne zarządzanie konfiguracją i zmianami. W procesie dojrzalszym relatywnie mniejszy udział w zapewnieniu jakości ma samo testowanie, więc – przy założeniu, że pozostałe czynniki są takie same – nie potrzeba w nim projektować tak wielu testów, jak w procesie mniej dojrzałym, bardziej chaotycznym.

W praktyce tę zależność może być trudno zaobserwować, bowiem z reguły im wyższe są wymagania jakości / niezawodności produktu IT, tym dojrzalszy stosuje się proces.
Znajomość i przestrzeganie zasad procesu
Im lepsza jest znajomość i stosowanie zasad procesu, tym mniejsze prawdopodobieństwo pomyłek i nieporozumień, a więc nie trzeba projektować tak wielu testów, mających na celu wykrycie ich skutków, czyli defektów.
Psychologia jednostki
Prawdopodobieństwo pomyłek i spowodowanych nimi bugów zależy od wielu czynników psychologicznych. Przykładowo, istnieją dobrze potwierdzone dane, pokazujące, że ludzie popełniają błędy znacznie częściej w stresie, w pośpiechu, w sytuacji, kiedy motywacja lękowa przeważa nad pozytywną.

W praktyce, trudno jednak brać te zależności pod uwagę w sposób systematyczny i rozbudowany, przystępując do projektowania testów.

Po pierwsze, gromadzenie tego rodzaju danych o współpracownikach jest zbyt czasochłonne, aby mogło się opłacać. Po drugie, jest byłoby często nieetyczne i niezgodne z prawem: choć prawdą jest, że pracownik, przeżywający poważne kłopoty rodzinne, zapewne myli się częściej, niż osoba spokojna i zadowolona, ale poddawanie pracowników badaniom, aby określić ich stan aktualny psychiczny, raczej nie jest dobrą receptą na organizację projektowania testów[16].

Między ludźmi istnieją duże różnice indywidualne. Działanie, pozytywnie motywujące jedną osobę, wobec innej osoby może być nieskuteczne lub wręcz przeciw-skuteczne, co jest kolejnym powodem, że uwzględnianie czynników psychologicznych przy projektowaniu testów nie jest podejściem, nadającym się do łatwego zastosowania w praktyce.

Choć opisane powyżej przyczyny powodują, że nie ma sensu próba systematycznego wyłożenia w podręczniku, sposobów uwzględniania czynników psychologicznych przy podejmowaniu decyzji o pożądanej staranności testów[17], to jednak umiejętność ich uwzględnienia w praktyce jest pożądana. Osoby dobrze znające się, pracujące dłuższy czas w jednej grupie, mające wysoką inteligencję emocjonalną, łatwiej biorą te czynniki pod uwagę, świadomie, lub podświadomie.
Dynamika grupowa
Podobnie jak psychologia jednostek, tak i zjawiska interpersonalne, społeczne, mają bez wątpienia duży wpływ na to, jak wysokie jest ryzyko pomyłek, nieporozumień i innych zjawisk, które mogą powodować błędy i wpływać na to, jak staranne testy trzeba projektować i wykonywać. Tak samo, jak rzecz ma się z aspektami psychologicznymi, mechanizmy tego wpływu są na tyle złożone, że odwoływanie się do nich w praktyce projektowania testów jest bezużyteczne. Oczywiście, literatura obfituje w anegdotyczne przypowieści[18], które znakomicie się czyta, a nawet dyskutuje, ale nie wynikają z nich żadne ogólne zasady, dające się przenieść w odmienne sytuacje projektowe.

Pewne ogólne twierdzenia, takie jak – z jednej strony – „testowanie powinno być niezależne” (jak głoszą sylabusy ISTQB i wiele innych źródeł), lub – przeciwnie – że korzystniejsze jest podejście wspólnotowe, współodpowiedzialność (np. zasada „three amigos” w świecie zwolenników agile[19]), dają do myślenia, ale nie oferują żadnych niepodważalnych wzorców postepowania podczas projektowania przypadków testowych.
Kultura organizacji
Kolejny – po psychologii jednostki oraz psychologii społecznej i dynamice grupowej, temat równie ważny, co zbyt skomplikowany, by móc z niego wywieść jednoznaczne i konkretne zasady, dotyczące projektowania testów.

Ogólnie, kultura organizacji wpływa na postawy i stereotypy zachowania, dotyczące znaczenia jakości, sposobów zapewnienia jakości, oraz podejścia do spraw testowania i – szerzej – kontroli jakości. Jedna z wielu teorii kultury organizacji, Camerona i Quinna[20], następująco przedstawia cztery typowe rodzaje kultur organziacyjnych:


Rysunek 2. Cztery rodzaje kultury organizacji

W kulturze klanowej można spodziewać się braku (lub stłumienia) rywalizacji wewnętrznej, a więc także braku – występujących w niektórych organizacjach – konfliktów między zespołami programistów a zespołami testerów, co powinno sprzyjać starannemu doborowi testów, wspomagających tworzenie kodu i pracę programistów. Jednocześnie można też oczekiwać silnej lojalności wobec własnej organizacji, kosztem interesów klienta, co może powodować mniej staranne projektowanie testów negatywnych, mających za zadanie wykrycie trudnych do znalezienia bugów.

W adhokracji często występuje lekceważący stosunek zarówno do jakości, jak i do jej kontroli. Tworzenia spektakularnie nowatorskiej funkcjonalności jest postrzegane jako ważniejsze, niż niezawodność i brak błędów.

W kulturze rynkowej, dużą rolę przypisuje się potrzebom i kryteriom jakości klientów i użytkowników, kosztem mniej starannego uwzględniania jakości wewnętrznej, oraz niedostatecznego uwzględniania kryteriów technicznych przy projektowaniu testów. Można powiedzieć, że ta kultura będzie mieć skłonność do osiągania jakości zewnętrznej kosztem rosnącego długu technicznego[21].

W kulturze hierarchicznej występuje tendencja do stosowania standardowych rozwiązań, tak że projektowanie testów może być wykonywane w ten sam sposób, przy użyciu tych samych technik, niezależnie od innych czynników.

Powyższe twierdzenia są ogólnikowe, a ponadto nie sposób jest określić jednoznacznie wpływ czynnika tak wysokopoziomowego, jak kultura organizacyjna, na czynność tak wąską i konkretną, jak projektowanie testów. Niemniej, ogólna świadomość tego, że taki wpływ istnieje, pozwoli osobom projektującym testy lepiej unikać pułapek, wynikających z bezkrytycznego stosowania organizacyjnych przesądów i stereotypów.
Doświadczenie
Wpływ indywidualnego, grupowego lub branżowego doświadczenia na ocenę prawdopodobieństwa defektów, i tworzone na jego podstawie zasady projektowania testów, nie ulega wątpliwości.
Doświadczenie to bywa zbierane w formie zasad, publikowane i rozpowszechniane. Takimi heurystykami są, między innymi, wymienione w rozdziale pierwszym sylabusa podstawowego ISTQB: kumulowanie się błędów, paradoks pestycydów, oraz – punkt 4.5 tego sylabusa – testów „opierających się na intuicji, doświadczeniu oraz wiedzy na temat często spotykanych usterek”. 

Takie doświadczenie dotyczy między innymi czynników opisanych powyżej, jak i mnóstwa czynników lokalnych, specyficznych dla organizacji, produktu czy nawet konkretnego klienta. Autor tej książki spotkał się kiedyś z testem wielokrotnego przerywania jednej, określonej transakcji podczas jest wykonywania, robionym dlatego, że u klienta, na którego zamówienie powstała, kable od sieci leżały luzem na podłodze i bardzo często ktoś się o nie potykał, przerywając połączenie. Cały szereg takich doświadczeń, dających się przełożyć na zaskakujące dla osób niedoświadczonych testy, wiąże się z technologiami: językami programowania, strukturami baz danych, topologią sieci komputerowych. Doświadczony programista w jakimś języku, na przykład języku C, wie, lub wyczuwa, jakie typowe pomyłki popełniają inni programiści, i potrafi zaprojektować specjalne testy, aby znaleźć spowodowane nimi bugi.

W szczególności, taka wiedza z doświadczenia, będąca zestawem heurystyk, a nie algorytmów, jest stosowana podczas przeglądów kodu źródłowego.

Testowanie zabezpieczeń[22] także w dużym stopniu wykonywane jest prze pomocy takich nieprecyzyjnych zasad. W języku testerów zabezpieczeń nazywane bywa testowaniem penetracyjnym. W tej akurat dziedzinie, zmiany są tak częste, że aby uaktualniać swoje „doświadczenie”, specjaliści uczą się nieustannie.

Testowanie systemów krytycznych dla bezpieczeństwa[23] jest opisane w wielu branżowych standardach. Takie standardy są jakby zbiorem reguł, zgromadzonych na podstawie doświadczenia, w tym reguł określających sposoby projektowania testów i inne wymogi, które zaprojektowane testy muszą spełniać. Przykładowo, lotnicza norma DO-178B[24], określa wymagane poziomy testowego pokrycia kodu źródłowego, uzyskane podczas wykonywania zaprojektowanych testów.

Podsumowując, w poszczególnych branżach, a nawet firmach, mogą istnieć użyteczne zbiory testów lub zasad projektowania testów, zgormadzonych na podstawie doświadczenia. Próba ich rozszerzenia natrafia jednak na trudności. Nie negując znaczenia zbioru prawdziwych, częściowo prawdziwych lub niekiedy nieprawdziwych zasad testerskiego folkloru, wątpię, czy ich szczegółowe opisywanie i wyliczanie przyczyni się do rzeczywiście lepszej jakości  testów, projektowanych przez czytelników.

Niemniej, jak każda dziedzina wiedzy nieprecyzyjna, pozwalająca na dość dowolne głoszenie pewnych doświadczeń jako rzekomo uniwersalnych zasad, testowanie według doświadczenia jest opisane bardzo obszernie. Samo nazewnictwo jest rozbudowane: od testowania na podstawie doświadczenia (ang. „experience-based testing”), poprzez domyślanie się błędów („error guessing”), testowaniem na podstawie intuicji. Te pojęcia bywają też mylone, lub błędnie utożsamiane, z testowaniem losowym, testowaniem ad-hoc, lub tak zwnym testowaniem eksploracyjnym (opisane gdzie indziej w tej książce).
Czynniki prawdopodobieństwa defektów - podsumowanie

Rysunek 3. Podsumowanie: od czego zależy prawdopodobieństwo błędów i defektów

Skłonność do zachowania szczególnej ostrożności tam, gdzie wcześniej doświadczyliśmy kłopotów i niepowodzeń, jest wbudowana w ludzką psychikę, jest częścią naszego genetycznego wyposażenia. Tak samo, tam, gdzie nic złego wcześniej nie zdarzyło się, mamy skłonność do lekceważenia zagrożeń. Pod tym względem, testowanie na podstawie doświadczenia, jest czymś oczywistym i naturalnym.

Jak każdy mechanizm ludzkiej psychiki, także i ten jest bezwzględnie skuteczny ewolucyjnie, to znaczy, osobniki mające taki sposób funkcjonowania z większym prawdopodobieństwem zdołały przekazać swoje geny dalej. Nie oznacza to jednak, że takie działanie jest słuszne w każdej sytuacji, ani, że sprawdza się w środowisku, które nie miało i nie ma wpływu na ewolucyjne wybory – środowisku projektów IT.

Opis, jakie psychiczne mechanizmy mogą obniżać jakość ludzkich wyborów i decyzji, jest przedmiotem setek prac i naukowych, i popularnych z zakresu psychologii, i mija się z celem ich streszczanie w książce zajmującej się projektowaniem testów. Niemniej, należy zdawać sobie sprawę, że intuicja, każąca nam sprawdzać starannie to, co budzi nasz lęk, a pomijać kontrolowanie tego, co wydaje się niegroźne, może być zarówno bardzo trafna, jak i najzupełniej błędna. W uproszczeniu i pół-żartem, ludzką intuicję można określić jako paranoiczną: boimy się bardziej niż trzeba, i często nie tych rzeczy, których należy się bać, ale w zamian, nasze lęki bywają wyrazem realnych zagrożeń, z których na poziomie świadomości nie do końca sobie zdajemy sprawę[25]

Dlatego przy projektowaniu testów, warto zarówno doświadczenie oraz intuicję, jak i metody formalne, algorytmiczne, aby zminimalizować – nawet kosztem pewnego nadmiaru testów – ryzyko przeoczenia zagrożeń awariami.

Profil użytkowania oprogramowania


Prawdopodobieństwo awarii zależy nie tylko od częstości defektów, ale w równym stopniu od sposobu i częstości używania. Urządzenie, którego nigdy nie bierze się do ręki, nigdy nie może zawieść, choćby było przeżarte rdzą na wylot. Posługując się nie do końca sprawnym urządzeniem tyko z rzadka, mamy większą szansę, że nie zawiedzie, niż wtedy, kiedy posługujemy się nim często i intensywnie.

Aby użyć przykładu powszechnie zrozumiałego, można tę zależność określić jako prawdopodobieństwo, że istniejący ewentualnie defekt wyjdzie na jaw podczas użytkowania. Dlatego właśnie przed podróżą autem przez Alpy do Chorwacji wzrasta nasza gotowość poniesienia niedogodności i kosztów kontrolnej wizyty w warsztacie (czyli staranniejszego testowania), bowiem intuicyjnie widzimy, że bardziej wymagające warunki jazdy – góry, autostrada, obciążenie, zmęczenie kierowcy – poddadzą auto bardziej wymagającej próbie, która z większym prawdopodobieństwem ujawni defekty, na co dzień ukryte.

Celem testów jest zmniejszenie prawdopodobieństwa awarii w działaniu operacyjnym. Paradoksalnie, najskuteczniej realizuje się ten cel poprzez działania, mające cel przeciwny – maksymalizowania prawdopodobieństwa awarii podczas testowania, ale wyłącznie wtedy, gdy taka awaria ma szansę pojawić się także w działaniu operacyjnym, rzeczywistym. Najczęstszą przyczyną nieskutecznych, choć intensywnych testów jest to, że testuje się w inny sposób, niż systemem posługują się użytkownicy.
Sposoby pozyskiwania wiedzy o profilach użytkowania
Istnieje szereg metod, od intuicyjnych po formalne, określenia, w jaki sposób systemem posługują się użytkownicy.

Logi użytkowania. Gdy system, który ma być testowany, zastępuje inny system o podobnej funkcjonalności, można – jeśli są dostępne – wykorzystać logi, zawierające dane o tym, jak używano stary system. W szczególności, nawet jeśli nowy system ma umożliwić automatyzację zadań, dotąd wykonywanych ręcznie, można przyjąć założenie, że sposób posługiwania się nimi będzie podobny[26].

Obserwacja. W celu poznania sposobu, w jaki użytkownicy będą korzystać z systemu, mającego wspierać ich działania, można obserwować ich obecną pracę. W szczególności, może to być obserwacja uczestnicząca, gdzie w celu poznania sposobu pracy użytkownika, tester podejmuje tę samą pracę[27].

Zwykle, takie działania podejmuje się nie specjalnie pod kątem uzyskania informacji potrzebnej do testowania, a w ramach procedury pozyskiwania wymagań. Oczywiście, jeśli wymagania są dzięki temu dokładniejsze i lepsze, pozwala to również na trafniejsze projektowanie testów.

Domyślanie się. Najbardziej zawodna, i zarazem najpopularniejsza metoda pozyskiwania przez testerów wiedzy  na temat sposobów posługiwania się systemem przez jego użytkowników. Ma szansę powodzenia, jeśli rola użytkownika jest standardowa, lub znana testerowi. W przeciwnym razie, albo takie podejście ma małe szanse powodzenia, albo wymaga czasochłonnej eksploracji (nazwa od: testowanie eksploracyjne), w celu zdobycia potrzebnej wiedzy. Jeśli dziedzina zastosowania testowanego programu jest testerowi zupełnie nieznana, testy projektowane w ten sposób będą niewiele lepsze, od testów wybranych najzupełniej przypadkowo (losowo).

Modelowanie scenariuszy. Tradycyjne podejście do opisywania wymagań, to tworzenie listy funkcji i właściwości projektowanego systemu. Coraz częściej zastępuje się je, lub uzupełnia podejściem scenariuszowym, czyli opisywaniem raczej ciągów czynności, wykonywanych podczas wykorzystywania systemu, niż pojedynczych kroków / funkcji, wykonywanych w trakcie takiego ciągu. Przykłady takich form opisu, to przypadki użycia (use cases), zalecane przez metodyki agile opowieści użytkowników (user stories), diagramy BPMN. Z punktu widzenia projektowania testów, taki opis wymagań ma tę zaletę, że identyfikuje właśnie typowe ścieżki zastosowania, którymi będą się poruszać użytkownicy testowanych programów. To wskazuje na przewidywaną intensywność takich działań, zależną od liczby danego rodzaju użytkowników oraz wagi i częstości użycia poszczególnych scenariuszy, co wskazuje do pewnego stopnia, pożądaną, względną intensywność i staranność ich testowania.
Profil użytkowania, a konsekwencje
Dla ułatwienia, przyjmuje się często, że prawdopodobieństwo awarii i jej konsekwencje, to są niezależne zmienne. Jeśli skutkiem awarii jest wyłącznie konieczność kliknięcia na przycisk „OK” na oknie z informacją o drobnej awarii, to przyjmujemy, że konsekwencje takiej awarii są mniejsze, niż wtedy, gdy jej skutkiem jest konieczność mozolnego i wielogodzinnego odtworzenia danych z kopii zapasowej.

To założenie nie jest do końca prawdziwe. Po pierwsze, jeśli mierzyć czasem, to awaria, której skutkiem są dwie minuty dodatkowej pracy, jeśli wystąpi na różnych stanowiskach pracy łącznie 720 razy, dorówna dotkliwością jednorazowej awarii, której usuwanie trwa 24 roboczo-godziny, czyli całe trzy dni. Czyli drobne, ale częste awarie, mają skutki porównywalne do awarii cięższych, ale rzadszych.

Po drugie, trzeba wziąć pod uwagę skutki psychologiczne takich drobnych awarii. W swoich eksperymentach[28], Radosław Hofman pokazał istotne w tej sytuacji, psychologiczne czynniki. Jeden z nich można nazwać „czynnikiem narzekania”. Dwie równoważne grupy, testujące – niezależnie od siebie – to samo oprogramowanie i znajdujące w nim prawie dokładnie te same defekty, miały pod koniec eksperymentu zupełnie różne opinie na temat testowanej aplikacji: bardzo dobrą i bardzo złą. Obie grupy różniły się wyłącznie tym, jaki subiektywne i bardzo emocjonalne opinie wygaszali uczestniczący w pracy, współpracownicy eksperymentatora. Widać tutaj wyraźnie psychospołeczny mechanizm, w jaki częstotliwość występowania awarii może się przekształcić w subiektywne opinie o jej wadze.

Prawdopodobieństwo awarii a testy – podsumowanie


Rysunek 4. Od czego zależy prawdopodobieństwo awarii

Im większe jest prawdopodobieństwo awarii danej funkcji, czy niespełnienia danej charakterystyki, tym staranniej warto ją testować, przy założeniu, że pozostałe zmienne (konsekwencje awarii oraz skuteczność testów) są jednakowe.
Główną trudnością przy wykorzystaniu tego w praktyce, jest brak oszacowań ilościowych wymienionych czynników. Dlatego poniżej zamieszczam tabelę, która wprawdzie nie stwarza – z punktu widzenia akademickiego – żadnej nowej wiedzy, nie odkrywa nieznanych wcześniej zależności, ale znakomicie ułatwia posługiwanie się zależnościami już znanymi.


Rysunek 5. Tabela – narzędzie od oszacowania prawdopodobieństwa awarii

Wskazania:


15-20 punktów – testowanie (projektowanie i jedno wykonanie[29]) 15% - 20% czasu przeznaczonego w tej fazie na czynności konstrukcyjne oraz integrację. Testy pobieżne, głównie akceptacyjne.

21 – 30 punktów - na testowanie należy przeznaczyć co najmniej 30% czasu przeznaczonego w tej fazie na czynności konstrukcyjne oraz integrację. Testy nie tylko akceptacyjne, ale ukierunkowane także na próby złamania oprogramowania.

30 – 45 punków – poważna sprawa, skuteczne testowanie

W szczególności, powyższą tabelę można i warto zastosować do szacowania ilości pracy, którą planuje się włożyć w przygotowanie i wykonanie testów. Może być podstawą, czy argumentem, używanym podczas negocjowania kontraktu wdrożeniowego. Nagminnie stosowana podczas takich negocjacji  reguła dodawania na testy 20% czasu, potrzebnego - jak się wydaje - na napisanie oprogramowania, jest nie tylko merytorycznie bezsensowna, ale szkodliwa zarówno dla zamawiających, jak i wykonawców, ponieważ ten czas w rzeczywistości może się wahać między 5% a 200% czasu niezbędnego na pisanie i kompilowanie kodu.

Merytorycznie, jeszcze lepsza byłaby tabela uwzględniająca także konsekwencje awarii, oraz skuteczność testowania w redukowaniu ich prawdopodobieństwa, ale w kontekście organizacyjnym, byłoby ją trudniej zastosować. Przedstawiciele klienta oraz analitycy biznesowi najchętniej twierdzą, że wszystko jest ogromnie ważne, a twierdzenia dotyczące kosztów lub braku skuteczności testów mogą – nie bez racji – odczytać jako krytykę braku innych metod zapewnienia jakości. Skuteczniejsze więc będzie samo odwoływanie się do prawdopodobieństwa awarii.

Natomiast odwołując się do powyższej tabeli, można w ciągu dosłownie kilku minut uzyskać rezultat znacznie trafniejszy. Dodatkowa korzyść z tej tabeli, to przypomnienie o istnieniu i znaczeniu unaocznienie wymienionych w niej czynników. Podjąwszy decyzję o tym, ile i jak dokładnych testów się wykona, i zarezerwowawszy na nie środki w budżecie przedsięwzięcia, wielu kierowników i uczestników projektów zapomina, że oszczędności, drogi na skróty, czynione później gdzie indziej w projekcie, nie zostaną magicznie wykryte przez te zaplanowane testy, lecz spowodują albo potrzebę testów obszerniejszych, niż wstępnie planowane, albo – najczęściej – gorszą jakość dostarczonego produktu[30].

Szacowanie konsekwencji awarii


Konsekwencje awarii szacujemy w odniesieniu do działania operacyjnego, w środowisku produkcyjnym. Oczywiście, awarie powodują pewne koszty i konsekwencje także w warunkach testowych: coś – fragment platformy sprzętowej lub dane, może ulec zniszczeniu, test – być może czasochłonny – trzeba będzie powtórzyć, konieczna będzie ponowna konfiguracja systemu, wreszcie test blokujący, zakończony niepowodzeniem, powoduje, że dalsze testy nie mogą być wykonywane, dopóki defekt nie będzie usunięty. Te koszty jednak omawiamy bardziej szczegółowo w następnym rozdziale „Skuteczność testów w zapobieganiu awarii”. Jeśli konsekwencje awarii w wyniku testu są bardzo wysokie, jak w przypadku testowania na kosztownej platformie docelowej systemów wbudowanych, wówczas wartość testów, wykonywanych na danym poziomie, jako sposobu na zapobieganie awariom w działaniu operacyjnym, jest ograniczona. Przykładowo, loty próbne prototypów nowych modeli samolotów, choć oczywiście bardziej ryzykowne niż loty modeli będących już w produkcji masowej, rzadko kiedy kończą się katastrofami. Ponieważ koszty, zarówno materialne, jak i ludzkie, takich katastrof, są niedopuszczalnie wysokie, użyteczność testów jako metody ograniczania prawdopodobieństwa poważnych błędów konstrukcyjnych, jest mała – zamiast nich, stosuje się inne metody – staranne projektowanie, obliczenia, testy komponentów w tunelach aerodynamicznych itd.

Koszty awarii w działaniu operacyjnym nie zawsze są łatwe do oszacowania. Składa się na nie wiele czynników.

Koszty bezpośrednie – skutki awarii


Straty biznesowe, spowodowane awarią. Na przykład koszty przestoju, straty spowodowane niepoprawnymi transakcjami lub obliczeniami.

Wobec systemów wbudowanych, mogą to być również straty materialne: zniszczony sprzęt, towary, instalacje.

Wobec systemów krytycznych dla bezpieczeństwa, mogą to być straty, których zwykle nie szacuje się w pieniądzach: utrata zdrowia lub życia ludzi.

Awarie systemów biznesowych, zwłaszcza finansowych, obracających dużymi sumami pieniędzy, mogą być wielokrotnie wyższe, niż koszty zbudowania i zapewnienia jakości systemu, którego awaria je powoduje.

Wybór sposobów projektowania testów zależnie od wielkości ryzyka



Rysunek 6. Ryzyko a testy – w praktyce




[1] Waga ryzyka (niekorzystnego wydarzenia) jest funkcją jego konsekwencji oraz prawdopodobieństwa.

[2] Często używana, niegramatyczna forma to „testowanie w oparciu o ryzyko”.

[3]Risk Based Testing and Metrics”, Ståle Amland, EuroSTAR 1999 (http://amland.no/WordDocuments/EuroSTAR99Paper.doc).

[4] Ponieważ nie bierze pod uwagę czynności zapobiegania błędom,  takich jak staranne określenie wymagań oraz architektury systemu, ani tego, że wśród  czynności, zaliczanych do „programowania”, może przecież znajdować się wiele testowania: przeglądy kodu, analiza statyczna, testy jednostkowe, pomiary pokrycia testowego.

[5] Przy okazji, te liczby są wymownym przykładem, jak niedostateczne są przyjęte dość powszechnie w przemyśle IT oszacowania pracochłonności testowania. Programiści, wiedząc, że będzie wykonywane testowanie i usiłując dotrzymać termin, minimalizują testy, poprzestając niekiedy na samej kompilacji, połączeniu i próbnym uruchomieniu kodu. Wcześniej muszą zapoznać się z wymaganiami i zrozumieć je – i to samo muszą zrobić testerzy, choć zwykle dokładniej. Programista może przecież w razie potrzeby poprzestać na domysłach, licząc na to, że ewentualne nieporozumienie wyjdzie na jaw w testach właśnie.

Następnie, programiści piszą kod, a testerzy projektują testy. Ktokolwiek wykonywał obie te czynności, wie, że są one porównywalne, zależnie oczywiście od wymaganego od testów poziomu staranności. Nie zapominajmy, że testy trzeba potem jeszcze wykonać, ale przyjmijmy ugodowo, że jest to praca porównywalna z debugowaniem kodu, wykonywanym przez programistów. Wszystko wskazuje na podział 50-50 (w tym przykładzie, dwa razy 34 dni), więc dlaczego powszechnie przyjmuje się, że testowanie uda się wykonać w czasie czterokrotnie krótszym? Odpowiedź jest prosta: kod musi być napisany, podczas gdy skutki niedostatecznego testowania czasem uda się zamaskować, czasem przerzucić na użytkowników, a czasem po prostu ma się szczęście i mimo braku testów, awarie są nieliczne.

[8] FMEA (Failure Mode and Error Analysis).

[11] Jeśli znany algorytm jest skomplikowany, trzeba go poznać i precyzyjnie – także metodami formalnymi – projektować jego testy. Jeśli natomiast algorytm jest nieznany, testowanie powinno założyć eksploracyjny kapelusz i rzucić się w wir pozyskiwania (ściślej – zdobywania) wiedzy na temat rzeczywistych wymagań metodami niealgorytmicznymi, raczej sieciowo-interpersonalnie-psychologicznymi.

[12] Wielkość oprogramowania mierzy się liczbą linii kodu źródłowego (LOC), komponentów lub funkcji.

[13] Wymowne przykłady takich sytuacji, to tragiczne i kosztowne awarie promu kosmicznego „Challenger” 1986 oraz sondy „Mars Climate Orbiter” 199?, spowodowane defektami, które zaistniał w wyniku

[14] Metody pozyskiwania wymagań, to – w ogromnym skrócie – ankiety, wywiady, różne techniki kreatywne, np. burza mózgów, studiowanie dostępnej dokumentacji, prototypowanie, obserwacje lub obserwacje uczestniczące. Techniki walidacji wymagań, to różne przeglądy lub inspekcje, wywiady, analiza statyczna modeli wymagań.

[16] Tam, gdzie konsekwencje pomyłek mogą być szczególnie poważne, stosuje się jednak takie badania. To, co uważa się za absurd w odniesieniu do programisty czy analityka w projekcie IT, jest uzasadnione i akceptowane np. wobec pilotów samolotów pasażerskich.

[17] Sylabusy ISTQB różnym aspektom tak zwanej „psychologii testowania” poświęcają sporo miejsca. Także doświadczenie z wielu konferencji i seminariów wskazuje, że to tematyka popularna wśród osób zajmujących się testowaniem. Jednak nie jest to żadna wiedza naukowa, tylko „pop-psychologia”, zestaw interesujących anegdot, nie mających waloru ogólności – dlatego rezygnujemy z ich opisywania w tej książce.

[18] Typowe przykłady takich pozycji, to: „Lessons Learned in Software Testing” (Cem Kaner, James Bach, Bret Pettichord) - „Testing Computer Software” (Cem Kaner, Jack Falk, Hung Q. Nguyen) oraz „Agile Testing (Lisa Crispin, Janet Gregory).

[20] Kultura organizacyjna - diagnoza i zmiana (Cameron Kim S., Quinn Robert E.)

[21] Dług techniczny, na przykład opisany w „Dealing with Technical Debt in Agile Development Projects”, Harry M. Sneed

[22] Używam terminów „testowanie zabezpieczeń” lub „testowanie odporności” jako odpowiednika angielskiego „security testing”. Nagminnie stosowane „testowanie bezpieczeństwa” można pomylić z „testowaniem systemów krytycznych dla bezpieczeństwa” – ang. „safety testing”.

[23] Takich, których awaria może spowodować zranienie lub śmierć ludzi – a więc z reguły systemów wbudowanych, sterujących urządzaniami medycznymi, pojazdami, samolotami, oraz innymi nienezpiecznymi urządzeniami elektrycznymi, mechanicznymi i chemicznymi.

[24] Na przykład „Avionics Certification: A Complete Guide to DO-178 (Software), DO-254 (Hardware)”, Vance Hilderman, Tony Baghai, Len Buckwalter.

[25] Znakomitą, popularną pozycją ilustrującą działanie tych mechanizmów, jest książka „Błysk. Potęga przeczucia” Malcolma Gladwella.

[26] Może to być założenie błędne – czasem zmiana technologii, platformy czy nawet wyglądu urządzenia albo aplikacji, powoduje trudne do przewidzenia zmiany zachowań użytkowników.

[27] Ten sposób bywa też nazywany „praktykowaniem” – ang. apprenticeship.

[28] „Behavioral economics in software quality engineering”, Springer Verlag

[29] Podkreślmy – projektowanie i jedno wykonanie, nie wielokrotne testy regresji lub ponowne (potwierdzające, że bug został naprawiony). Tematyka uwzględnienia, przy planowaniu projektów, czasu potrzebnego na debugowanie, poprawianie błędów, testy ponowne i testy regresji jest ważna, ale wybiega daleko poza tematykę tej książki.

[30] Efekt ten jest opisany w tekstach Hansa Schaefera „O czym tester powinien pamiętać, nawet o północy”  (http://blogomotion.com/Victo2012/PL/Wiedza/co_tester_wiedziec_powinien.pdf) oraz „Testing as Co-dependent Behavior” Lee Copeland’a (http://www.stickyminds.com/article/when-helping-doesnt-help)







Brak komentarzy:

Prześlij komentarz