Feilsøking og avlusing Frode Eika Sandnes If it ain't broke don t fix it! Ronald Reagan If we can t fix it, it ain t broke Lr. Col Walter Weir 1
Hva er på innsiden av den svarte boksen? Bygge opp en generell modell Hva skyldes kreft? Vi foretar observasjoner Vi stiller en rekke spørsmål Utfører eksperimenter Prøve å koble cause and effect 2
Stille diagnose for spesifikke tilfeller Hva er galt med denne pasienten? Vi utfører tester Sammenlikner resultatene med modellen vår Stille diagnose i et annet domene Hva er galt med bilen? 3
Feilsøking: Feilsøking Observasjon: et system virker ikke som forventet Aktivitet: finne ut hvorfor feilen oppstår Avlusing (debugging) Samme som feilsøking, men i tillegg gjør man et inngrep i systemet med hensikt å utbedre feilen. Feilsøking vs testing Testing: Utgangspunkt: systemet virker Hensikt: etablere trygget for at systemet faktisk er korrekt: Antagelse: hvis feil ikke finnes igjennom testing er sannsynligheten for feil mindre Feilsøking: Utgangspunkt: et system med kjente feil Hensikt: lokalisere feilen slik at den kan korrigeres Deretter bruke testing for å bevise korrekthet 4
Testing Testing viser KUN tilstedeværelsen av feil. Feil som ikke fanges av en test forblir uoppdagede. Typer av debugging Hacking Vi fikler med systemet til det ser ut til å virke Fristende på kort sikt, kan gjøres hurtig Introduserer flere feil på lang sikt Krever høyt erfaringsnivå og talent Systematisk Vi går metodisk til verk Krever mer innsats på kort sikt Introduserer færre feil Sparer tid på lang sikt Kan utføres med mindre erfaring og innsikt i systemet Forebyggende tiltak Unngå feil i første omgang 5
Typer av debugging Manuell Vi legger inn testekode i systemet for å stille diagnose Tidkrevende for enkle debugging oppgaver Fleksibilitet: kan brukes til å finne alle typer feil. Krever ikke kjennskap til vertkøyet Verktøyorientert Verktøy benyttes til å automatisk inspisere status i et kjørende program Effektivt lite innsats for å starte debuggingsaktiviteten Ikke alle feil kan effektivt lokaliseres med verkøy Må kjenne verktøyet Automatisk Detekterer feil og rapporterer Kombinasjon Kombinere bruk av manuell kode og verktøy Observasjon En feil er vanligvis basert på en observasjon der resultatet (output) ikke er som forventet. En observasjon er også knyttet opp mot En input (hva fikk systemet inn, for å få svaret ut). Systemets tilstand (over tid) Observatørens forståelse av systemets funksjonalitet En feilrapport bør så fullstendig som mulig slik at man kan gjenskape et fullstendig bilde av systemets tilstand da feilen oppstod. 6
Feil Repeterbare feil: Mest vanlig Feil bør være repeterbare Ikke-repeterbare feil (intermittent errors): Veldig uvanlig (men kan skje) Tegn på annen feilkilde og/eller ukomplett forståelse av systemet Unngå og baser debugging på rapporter om feil som ikke kan repeteres. Typer av systemkomponenter White box: Fullt innsyn i og tilgang til koden Gray box: Delvis innsyn i og tilgang til koden Black box: Ingen kunnskap og tilgang til koden 7
Feilsøkingsprosessen Et system skal bestå av en rekke sammenkoblede delsystemer Informasjon flyter igjennom systemet Identifisere hvor feilen oppstår input output Feilsøkingsprosessen Forstå systemet Kontrollert input, forventet output fra de forskjellige delsystemet Hvis input til et delsystem er feil, vil også output fra systemet blir feil Alle delsystemer som er avhengig av et feilaktig delsystem vil også oppføre seg som om de har feil, selv om de ikke har det. Fokuser derfor på delsystemet hvor feilen først oppstår først, deretter se på hele systemet samlet igjen. Del og hersk (divide and conquer) Gå ovenfra og ned i abstraksjonsnivå 8
System og abstraksjonsnivå Cluster av maskiner (tjeneste) En maskin, eller spesiell maskinvare ( box ) Et program eller prosess på en maskin En komponent i et program Et objekt En metode, funksjon eller prosedyre En blokk med kode Et statement 9
Manuell debugging Kikkehull inn i systemet Kjent som printf debugging. Legge print-setninger inn i koden på utvalgte steder i koden Vet hvor man er Vet at kode er eksekvert Kan inspisere tilstanden til variabler Kan kontrollert modifisere variabler og hendelsesforløp I java: System.out.println( Inne i VanskeligModul ); System.out.println( variablel a er +a); Problem: Må huske å fjerne koden (eller kommentere ut) etter at problemet er løst Utskrift ikke synlig hvis ikke outputbuffer er flush et (pass på) Assertions Vanlig i C++ Legge inn sjekker i koden som er enten sanne eller usanne Brukes bla til å sjekke pre-og post conditions for funksjoner (kravspesifikasjon) Hvis ikke testen evaluerer som forbenter stoppes programmet og feilmelding vises. 10
Rammeverk for logging log4j Erstatning for print-setninger Slipper å fjerne kode etterpå testkoden kan fungere som dokumentasjon Konfigurere hvor detaljert ting skal logges Produksjon, delvis utskrift, full utskrift Eksempel log4j: logger.debug( Innholdet i a er +a); logger.info( Nå er vi i vanskelig modul"); logger.warn( Dette ser skummelt ut"); logger.error("her er det noe galt ); logger.fatal("her er det krise"); Se apache.org for mer info om log4j. 0 [main] INFO App - Entering application. 48 [main] DEBUG MinModul Innholdet i a er 4 510 [main] INFO App - Exiting application. Verktøy Tracer Symbols debugger Grafisk debugger (anbefales, JBuilder) Gå igjennom koden steg for steg Frem et steg (next) Gå inn i metodekall (step into) Gå til et sted (run to) Stopppunkter (breakpoints) Kikke på variabler (watches) Modifisere variabler Kan ikke brukes på alle problemer som for eksempel sanntidssystemer (real-time systems) hvor den absolutte tiden er en viktig faktor. Profiler (mer om det senere) 11
Automatisk debugging Boundschecker (minne allokering C/C++) Exception handling Try (et eller annet) Catch (hvis det ikke gikk så ) Andre forebyggende verktøy Editorer og IDE (integrated development environment) Syntax highlighting, stavefeil Viser oss når vi gjør opplagte gale ting, som for eksempel glemmer en parantes eller semikolon Automatisk indentering Versjonskontroll Jo flere kokker jo mer søl Holde styr på forskjellige versjoner av kode utviklet av flere utviklere Mer om dette i systemmeringsfaget 12
Ikke skyld på andre Det er ofte fristende å tro at en feil skyldes av en annen komponent i systemet. Vanligvis er det en selv som er skyld i feilen Kompilering, feilmeldinger og følgefeil i java Ofte er det overveldende mange feil (100 vis) Fristende å begynne med den siste viste feilmelding, men ikke gjør det! Start alltid med den første feilmeldingen og jobb deg fremover. Ofte kan en feil lede til mange følgefeil. Kompilatoren prøver nemlig å gjette hva du gjorde feil og jobbe seg videre igjennom programmet For hver grunnfeil man fikser blir man kvitt mange følgefeil. Ofte kan man bli kvitt 20 feilmeldinger ved å fikse kun et problem Ta WARNINGS (advarsler) alvorlig. Selv om programmet virker så er det en grunn til at du har fått advarsler. 13
Kravspesifikasjon og acceptance testing Kravspesifikasjonen definerer hva systemet skal gjøre. Hvis systemet avviker fra kravspesifikasjonen har vi en feil. Acceptance test tester alle kravene i kravspesifikasjonen. Når systemet passerer acceptance testen er produktet ferdig. Veldig viktig for leverandør og definere en god kravspesifikasjon og acceptance test. Forebyggelse Gode Pprogrammeringsspråk Programmeringsvettregler 14
Effekt av programmeringsspråk 100 90 80 70 % tid debugging 60 50 40 30 20 10 0 assembler basic C Pascal Java programmeringsspråk Forebyggelse Programmeringsvettregler og god praksis Gjør ting enkelt KISS keep it simple stupid!!! Lån, tyveri og gjenbruk er bra Latskap er bra Sanitet og ryddighet God struktur 15
Inndeling i moduler Del opp i moduler moduler Lav kobling Høy coersion Oppdeling av kode Tommelfingerregel: en metode etc skal ikke være lenger enn en skjermfull (ca 25 linjer med kode). Unntak: lange case-switch blokker. Del opp: hvis det blir for langt Hvis en programfil blir for lang, del den opp i flere logiske biter 16
Kommentarer Ikke kommenter opplagte ting Kommenter spesielle ting Formatering av koden Formater alltid toden Bruk indentering Gjør koden vakker Vær konsekvent Ikke vær redd for å bruke mellomrom mellom linjer Ikke ha linjer på mer enn 80 tegn 17
Praksis med paranteser Lukk en parantes så fort du åpner en parantes, deretter kan du fylle inn innholdet etterpå. Mennesker greier ikke å holde styr på hvor mange paranteser som er åpnet eller lukket. Plaser krøllparanteser på samme nivå, slik at det er lett å se hvor en kodeblokk begynner og hvor den slutter. Bruk alltid krøllparanteser rundt en ny kodeblokk, selv om den kun består av et utrykk. Den kan fort vokse til å bestå av flere uttrykk. Følg vanlig praksis og idiomer Følg alltid konvensjon når du gjør vanlige ting. Da skjønner både du selv og andre hva du har gjort. For eksempel for looper for (i=0;i<n;i++) { } Lesing av filer etc 18
If setninger Sammenlikning av konstant og variabel, plasser konstanten først, deretter variablen if (4 == antall) Og ikke if (antall == 4) Pass på forskjellen mellom = og == Metoder Hver metode bør kun gjøre en ting Kortere metoder er lettere å forstå Restrukturer koden hvis parameterlisten er for lang (tegn på dårlig struktur) Deklarer variablene når du trenger dem Deklarer nye variabler i stedet for gjenbruk av gamle ubrukte variabler 19
Klasse, metode og variabelnavn Bruk fornuftige og beskrivende navn Bruk navn du kan uttale Unngå forkortelser Typer gir god basis for variabelnavn Vær konsekvent Hold deg til konvensjoner Klasser (definisjoner) alltid stor forbokstav Variabler (instanser) alltid liten forbokstav Gode navn er ikke nødvendigvis lange Stjel navn fra eksterne kilder Bruk positivt ladede ord (spesielt for booleans) Bruk pakker (navnrom) slik at du kan bruke de samme navnene i forskjellige sammenhenger Vær villig til å bytte ut et dårlig navn Variabler Unngå globale variabler Ikke gi andre direkte tilgang til en klasses variabler Ta deg tid til å lake aksessmetoder, dvs getter og setter metoder Sett alltid innholdet i en variabel før bruk 20
Sjekk input verdier Sjekk alltid input fra sub-systemer og brukere Får du de verdiene du faktisk tror? Gjør brukerne det de skal? Fang alltid avvik (excpetions) eller kast de videre. Dette ser spesielt når programmet jobber mot andre sub-systemer, som for eksempel eksterne databaser og lignende 21