9. P-uppgift: granskning
Programmeringsteknik
Innehåll |
Granskning
Innan det färdiga programmet kan redovisas för en handledare ska det testas (granskas) av en kurskamrat. Vid testen ska din granskare kritiskt granska ditt program, testköra det och fylla i ett granskningsprotokoll. Denna granskning är ett obligatoriskt moment. (Varje kursdeltagare måste granska en uppgift, och alla uppgifter som ska redovisas måste granskas först.) Syftet med granskningen är att du genom att kritiskt granska en annans program ska få en ökad förståelse för hur man ska (och inte ska) programmera.
Här är granskningsprotokollet som ni ska fylla i. Förklaringar till de olika punkterna finns lite längre ned på den här sidan.
Namn _____________________________________ Födelsedag _______________ Uppgift __________________________________ Datum ____________________ Användarvänlighet __ Informativa utskrifter / lättbegripligt grafiskt gränssnitt __ Enkel inmatning Programmerarvänlighet __ Vettiga namn __ Kommentarer __ Konsekvent språk __ Konsekvent typografi __ Felhantering Strukturering __ Lämplig uppdelning i funktioner __ Lämplig uppdelning i klasser (ej oblogatoriskt) __ Temporära variabler så lokalt som möjligt __ Återanvändbara funktioner/klasser __ In- och utdata till funktioner __ Flexibelt/utbyggbart program __ Ingen kodupprepning __ Ingen hårdkodning Följande punkter är nödvändiga (måste alltid åtgärdas) __ Uppfyller kraven i lydelsen __ Detaljförståelse Granskare: _________________________________
Användarvänlighet
Informativa utskrifter
Programmet ska tala om för användaren vad programmet gör i varje steg och vad för inmatning som förväntas. Ett dåligt exempel kan se ut så här.
Ge tal1 : 26 och tal2 : 54 29 31 37 41 43 47 53
Man ska inte behöva titta i en manual eller ännu värre, i själva programkoden för att förstå vad som händer. Programmet måste vara självinstruerande.
Hej och välkommen till primtalsprogrammet. Programmet skriver ut alla primtal i ett intervall du definierar. Ange undre gränsen i intervallet: 26 Ange högre gränsen i intervallet: 54 De primtal som finns mellan 26 och 54 är: 29 31 37 41 43 47 53
Den senare varianten är mycket lättare att förstå när man kör programmet.
Enkel inmatning
Inmatningen ska inte vara onödigt krånglig.
... Vill du boka en biljett?ja Varifrån åker du? Arlanda Vart ska du åka? Kastrup Vilken månad ska du åka? Mars Vilken dag ska du åka? 25 Vill du boka returbiljett?ja Vilken månad ska du tillbaka? April Vilken dag ska du tillbaka? 5 Det går tyvärr inget flyg den 25 mars. Försök igen Vill du boka en biljett?ja Varifrån åker du? Arlanda Vart ska du åka? Kastrup Vilken månad ska du åka? Mars ...
Förutom att vara väldigt sen med att kläcka ur sig att det inte finns något flyg den önskade resdagen så verkar det inte finnas något sätt att boka en mängd biljetter. Att boka en klassresa med det systemet skulle vara väldigt enerverande.
Programmerarvänlighet
Vettiga namn
Programmet ska ha intuitiva namn på variablerna. För den som skrivit programmet är allt självklart, men inte för andra.
Nedanstående programkod är ganska svår att tyda
namn = 0 kalle = 0 while kalle < len(pelle): if pelle[kalle] > namn: namn = pelle[kalle] kalle = kalle + 1
Här följer samma kod med andra variabelnamn.
max = 0 i = 0 while i < len(lista): if lista[i] > max: max = lista[i] i = i + 1
Man ser nu lättare vad koden gör, nämligen sparar undan det högsta värdet i listan till variablen max. Fortfarande är inte namnet på listan optimalt. Vad för slags värden innehåller den? Är det löner, skottstatistik eller vad?
När det gäller en funktion eller metod brukar ett bra namn oftast vara ett verb som beskriver vad den gör eller vad den returnerar. Booleska funktioner (som returnerar True/False) bör ha ett namn som talar om hur läget är det fall den returnerar True.
Namnet på en klass kan vara ett substantiv som beskriver vad objektet representerar. Variabler och är också substantiv.
Att komma på bra namn kräver en del arbete!
Kommentarer
Alla klasser och funktioner måste kommenteras. Syftet med klassen/funktionen ska framgå. Det ska räcka att läsa kommentaren för att förstå hur en funktion ska användas (man ska inte behöva sätta sig in i hela koden).
För att kunna förstå och sätta sig in i hur en klass fungerar är det särskilt viktigt att man förklarar och kommenterar alla attribut (klassvariabler) som används i klassen.
In- och utdata till funktioner måste kommenteras. Det gäller både returvärden och parametrar. Om funktionen är en metod och den ändrar något attribut ska detta också kommenteras.
Kommentarerna ska inte förklara hur Python fungerar. Förutsättningen är att den som läser källkoden redan vet hur man programmerar. Kommentarer som förklarar t ex att en if-sats gör ett val och att en slinga upprepar något ska inte vara med vid redovisningen. Den som redovisar måste själv veta sådant utan anteckningar.
Konsekvent språk
Språkvalet ska vara konsekvent. Alla variabel-, klass- och funktionsnamn på ett språk. Alla kommentarer på ett språk. Det är OK att ha engelska variabel/metodnamn och kommentera på svenska. Undvik svengelska (sejva svenska språket).
Konsekvent typografi
Programmet ska ha en genomgående typografi. Namn som är sammansatta av flera ord kan t ex skrivas ihop genom att inleda varje nytt ord med stor bokstav, eller genom att skilja orden åt med understrykning. Variabel- och metodnamn brukar inledas med med liten bokstav och klasser med stor bokstav.
class EnBraKlass def enMetodSomTarTreParametrar(x, y, z)
Felhantering
Extrauppgiften för betyg C innehåller oftast felhantering, dvs att programmet kan hantera fel som kan uppstå. T ex kan det vara en slinga som upprepar inmatning tills korrekta värden kommer in. Ofta är den bästa lösningen att man skriver en funktion som tar hand om inläsningen.
Ange täljare: 1000 Ange nämnare: 0 Oj oj, nämnaren får inte vara noll. Försök igen. Ange nämnare: 10 1000 delat med 10 blir 100
Man kan också behöva lägga till särfall (exceptions) för att ta hand om fel som annars skulle ge felavbrott.
Strukturering
Lämplig uppdelning i klasser
Data som hör ihop (t ex namn, födelsedata och adressuppgifter för en person) kan samlas genom att dom får vara attribut i en klass. Funktioner som hör ihop kan bli metoder i en klass. Olika klasser för olika uppgifter.
Lämplig uppdelning i funktioner/metoder
Bäst är det med specialiserade funktioner som bara gör en sak.
def lasFranFilen(): filnamn = raw_input("Vad heter filen?") infil = open(filnamn,"r") lista = infil.readLines() lista2 = [] for element in lista: if type(element) == type(0): lista2.add(element) return lista2
Koden ovan gör flera saker; frågar efter en fil, läser in alla data från filen, stoppar in heltalen i en heltalsvektor och returnerar denna. Det vore bättre att dela upp dessa uppgifter på flera funktioner så att funktionsanropen blir:
namn = fragaFil() fildata = laesFranFil(filnamn) intresseantaTal = konvertera(fildata)
Programmet blir då mer flexibelt: Funktionen fragaFil kan skrivas om till ett grafiskt GUI där man klickar på rätt fil. Funktionen laesFranFil kan användas i andra sammanhang då man vill läsa från fil. Man kan skicka fildatat till en ny metod som kontrollerar data innan man anropar konvertera.
Temporära variabler så lokalt som möjligt
Se till att tillfälliga variabler skapas så lokalt som möjligt. En variabel som bara används inuti en slinga i en metod ska inte vara ett attribut i klassen, utan en lokal variabel i metoden.
Återanvändbara funktioner/klasser
En del uppgifter kan delas upp i klasser som går att återanvända i andra program. T ex kan en klass som representerar ett spelkort användas i olika kortspelsprogram.
Funktioner ska om möjligt vara skrivna så att dom går att använda i andra sammanhang. Ett knep är att se till att alla indata ges som parametrar. Ett annat är att specialisera funktionerna, så att varje funktion bara gör en liten del.
In- och utdata till funktioner
Var noga med in och utdata till funktionerna. En del funktioner som t.ex. bara skriver ut på skärmen kan vara parameterlösa och inte returnera något. Övriga funktioner bör ha alla indata som parametrar och utdata som returvärden.
Flexibelt/utbyggbart program
Skriv ditt program så att det lätt att utöka och bygga ut. Några exempel: I ett program som samlar data om pokemon ska man kunna lägga till fler pokemon utan att gå in och ändra i programmet. Om ett program läser in från fil ska det vara lätt att byta till en annan fil. Om man vill lägga till en beräkning så ska det vara enkelt att stoppa in en funktion för det, utan att behöva ändra på många ställen i programmet.
Ingen kodupprepning
Ett vanligt nybörjarfel när man programmerar är att använda taktiken klippa och klistra när samma sak ska göras på flera ställen i programmet. Detta leder dock till kod som är väldigt svår att underhålla. Om man ändrar på ett ställe måste man göra samma ändring på flera parallellställen. Det går i regel att skriva om koden till en funktion med parametrar och returvärde.
Ingen hårdkodning
Förekommer talet 5 på flera ställen i programmet? Om man behöver använda siffervärden kan dessa deklareras som konstanter.
ANTALSPELARE = 5; PI =3.14;
Följande punkter är nödvändiga (måste alltid åtgärdas för godkänt)
Uppfyller kraven i lydelsen
Programmet måste uppfylla kraven i P-uppgiftslydelsen. Det är inte tillåtet att förenkla uppgiften. Den som vill göra några förändringar måste förankra det med kursledaren först, och kunna visa en bekräftelse (ett ebrev t.ex.) på att kursledaren godkänt kravförändringar.
Detaljförståelse
Den som redovisar ska kunna redogöra för alla detaljer i koden, t ex vad variablerna innehåller, vad funktionerna gör och vad som skulle hända om handledaren tog bort en rad ur programmet.
Inlämningsuppgift 6
Hitta en studiekamrat som har kommit lika långt som du i kursen så att ni kan granska varandras program. Var inte för snäll när du går igenom programmet. Granskningen kan underkännas om du inte ens försökt kritisera programmet som du granskat. Och den som blir granskad är tacksam för alla fel du upptäcker, eftersom dom kan åtgärdas för redovisningen!
TODO