bild
Skolan för
elektroteknik
och datavetenskap

Granskningsprotokoll förklaringar

Uppfyller kraven i uppgiften

Programmet måste uppfylla kraven i uppgiftslydelsen. Det är inte tillåtet att förenkla uppgiften.

Användarvänlighet

Informativa utskrifter

Programmet ska tala om för användaren vad programmet gör i varje steg och vilken inmatningen 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 själva programkoden, för att förstå vad som händer. Att köra programmet måste vara självinstruerande.

    Hej och välkommen till primtalsprogrammet. Programmet
    skriver ut alla primtal i ett intervall du definierar. 

    Ange lägre 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

Det senare exemplet är mycket lättare att förstå när man kör programmet.

Enkel inmatning

Anmärk på programmet om inmatningen 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 frustrerande.

Programmerarvänlighet

Vettiga namn

Programmet ska ha intuitiva namn på klasser, metoder och variabler. För den som skrivit programmet är allt ofta självklart, men inte för den som granskar.

Nedanstående programkod är ganska svår att tyda

    int namn = 0;
    for (int kalle = 0; kalle < pelle.length; kalle++) {
        if (pelle[kalle] > namn) {
            namn = pelle[kalle];
        }
    }

Här följer samma kod med andra namn på identifierarna.

    int max = 0;
    for (int i = 0; i < vektor.length; i++) {
        if (vektor[i] > max) {
            max = vektor[i];
        }
    }

Man ser nu lättare vad koden gör. Fortfarande är det inte optimalt bra namn på vektorn. Vad för slags värden innehåller den? Är det löner, skottstatistik eller vad? Dessutom kan man i det här fallet göra koden tydligare med en "for each"-sats:

    for (int n: vektor)

Bra namn på metoder är oftast verb som beskriver vad metoder gör. Klasser och variabler är ofta substantiv som beskriver vad klassen/variabeln är. Det krävs ofta mycket jobb för att komma på riktigt bra namn.

Kommentarer

Alla klasser, instansvariabler och metoder måste kommenteras. Berätta syftet med klassen/instansvariabeln. Det ska räcka att läsa kommentar och metodhuvud för att förstå hur en metod ska användas; man ska alltså inte behöva titta i koden.

In och utdata till metoder måste kommenteras. Det gäller både returvärden och parametrar.

Kommentarer ska inte förklara hur Java fungerar. Förutsättningen är att den som läser källkoden redan vet hur man programmerar.

Konsekvent språk

Var konsekvent i ditt språkval: alla identifierare ska vara på ett språk, alla kommentarer på ett språk. Det är OK att ha engelska identifierare och kommentera på svenska. Undvik svengelska (sejva svenska språket).

Konsekvent formattering

Skriv ihop ord genom att inleda med stor bokstav, därefter små. Variabel- och metodnamn inleds med med liten bokstav och klasser inleds med stor bokstav.

    class EnBraKlass
    class EnTillBraKlass

    void enMetodSomTarTreParametrar(int x, int y, int z)
    int ettHeltal

Felhantering

Det krävs att programmet kan hantera fel som uppstår. Ibland kan man behövs en slinga, t.ex. vid inmatning för att programmet ska kunna gå vidare.

    Ange täljare: 1000
    Ange nämnare: 0
       Oj då, nämnare får inte vara noll. Försök igen.
    Ange nämnare: 10

    1000 delat med 10 blir 100.

Strukturering

Lämplig uppdelning i klasser

Undvik att ha all kod i en enda klass. Försök ha en klass för varje sak i programmet.

Lämplig uppdelning av metoder

Sträva efter att ha definiera metoder som bara gör en sak.

    int [] lasFranFil() throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("Vad heter filen?");
        String filnamn = in.readLine();
        in = new BufferedReader(new FileReader(filnamn));
        List list = new ArrayList();
        String row = in.readLine();
        while (row != null) {
            list.add(row);
            row = in.readLine();
        }
        int [] vek = new int [list.size()];
        for (int i = 0; i < list.size(); i++) {
            vek [i] = Integer.parseInt((String) list.get(i));
        }
        return vek;
    }

Koden ovan gör flera saker; frågar efter en fil, läser data från filen, gör om datat till heltal, stoppar in heltalen i en heltalsvektor och returnerar denna. Det är bättre att dela upp dessa uppgifter på flera metoder så att metodanropen blir:

    String filNamn = frågaFil();
    String [] fildata = läsFrånFil(filnamn);
    int [] intressantaTal = konvertera(fildata);

Programmet blir mer flexibelt. Metoden frågaFil kan skrivas om till ett grafiskt GUI där man klickar på rätt fil. Metoden läsFranFil 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

Deklarera tillfälliga variabler så lokalt som möjligt. Det är ett grovt fel att ha loop-variabler som instansvariabler. I koden nedan antas in vara en instansvariabel av typen BufferedReader initierad att läsa från tangentbordet.

    List lasFranFil() throws IOException {
        in = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("Vad heter filen?");
        String filnamn = in.readLine();
        in = new BufferedReader(new FileReader(filnamn));
        row = in.readLine();
        while (row != null) {
            list.add(row);
            row = in.readLine();
        }
	return list;
    }

Notera att metoden sätter om instansvariabel in att peka på en ny BufferedReader som läser från fil. Övriga metoder som använder in kommer att påverkas. Även om programmet fungerar ändå (ingen annan metod använder in) kan man få allvarliga problem om man försöker utöka programmet. Även row och list verkar vara deklarerade som instansvariabler helt i onödan.

Återanvändbara metoder/klasser

Ibland kan man dela upp programmet i klasser som kan återanvändas i andra program.

Specialicerade metoder kan man använda i andra sammanhang. Jämför med avsnittet om metoder ovan.

In- och utdata till metoder

Var noga med in och utdata till metoderna. En del metoder som t.ex. bara skriver ut på skärmen kan vara parameterlösa void-metoder. Övriga metoder har in- och utdata.

Flexibelt/utbyggbart program

Skriv ditt program så att det är lätt att modifiera och bygga ut.

Ingen kodupprepning

Ett vanligt nybörjarfel när man programmerar är att använda taktiken klippa och klistra. Det 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. Använd istället en metod som gör jobbet.

Ingen hårdkodning

Undvik att hårdkoda värden. Om du behöver använda siffervärden kan du deklarera dessa som konstanter.

    final static int ANTAL_SPELARE = 4;
    final static double E = 2.718281828;
Copyright © Sidansvarig: Stefan Nilsson <snilsson@nada.kth.se>
Uppdaterad 2012-10-15