Göm menyn

TDDC69 Objektorienterad prog. och Java

Krav på programkod


Den programkod du lämnar in för varje uppgift måste givetvis stämma med beskrivningen i uppgiftstexten och vara fullt fungerande. Dessutom måste den uppfylla följande krav. Läs dem i förväg, kontrollera att du följer dem under programmeringens gång, och dubbelkolla när du ska lämna in varje labb. Kraven är inte ett onödigt extraarbete som ger mindre tid åt den roliga kodningen, utan ett steg på vägen till att bli en bättre programmerare!

Läsbarhet och dokumentation

Det är viktigt att all programkod är lättläst och väldokumenterad. En anledning är att man i ett större programmeringsprojekt ofta måste återkomma till kod som skrivits tidigare: Man kan behöva fixa buggar, ett program kan behöva utökas med ny funktionalitet, eller man behöver helt enkelt förstå t.ex. hur en metod ska anropas för att kunna använda den i en annan del av programmet. För ett program som ska användas och utvecklas under en längre tid spenderas oftast mycket mer tid på detta än på att skriva programkoden den första gången! Tiden som läggs ner på att göra kod lättläst och att dokumentera är inte bortslösad utan sparas in med råge i senare faser av utvecklingen. Detta innebär bland annat att ni ska göra följande.

  • Använd informativa och rättvisande namn. En metod som är tänkt att flytta alla fiender i ett spel kan gärna heta moveEnemies(), medan update() inte är så informativt. En lista som lagrar alla uppkopplingar i en FTP-klient kan heta connections eller kanske currentConnections, medan c inte är informativt och windows är missvisande, även om varje uppkoppling har ett eget fönster på skärmen. Att kalla listan allConnectionsThatAreOpenRightNow är nog att gå ett par steg för långt.

    Se också till att faktiskt använda namn: Namngivna konstanter eller enum-typer är mycket bättre än "magiska konstanter" i koden. Det är lättare att förstå "if (state == State.RUNNING)" än "if (state == 14)"...

    Precis som med andra kodproblem kan missvisande eller svårförståeliga namn leda till en omedelbar retur för komplettering! Detta gäller även om namnen är kommenterade, eftersom kommentarerna bara ges vid deklarationen men namnet är missvisande varje gång det används.

  • Var enhetlig och konsekvent. Detta gäller kodstil såväl som namngivning. Att göra i princip samma sak på helt olika sätt i olika delar av koden kan vara förvirrande, liksom att kalla x-positionen x i en klass och xpos i en annan. Blanda inte språk (namngivning på kombinerad svenska och engelska).

  • Följ namngivningsstandarden. Java har en vedertagen namngivningsstandard som ska följas. Detta hjälper Java-programmerare att läsa varandras kod och snabbare förstå vad en identifierare refererar till.

    Till exempel skrivs klassnamn med inledande versal på varje "delord" (String, ArrayList, NullPointerException). Variabelnamn, parameternamn och metodnamn följer en liknande regel men inleds med en gemen (size, addElement, codePointCount). Understrykning används enbart som ordseparator i statiska konstanter, i kombination med versaler (public final static int MATRIX_WIDTH = 20).

  • Dokumentera lagom mycket och på rätt nivå. Ett vanligt fel är att man kommenterar på helt fel nivå, t.ex. genom att kommentera steg för steg vad koden gör. Detta är oftast redundant eftersom man lätt kan förstå det själv. Exempel:

      windows.add(myNewWindow); // Add the new window to the list

    Några riktlinjer för dokumentation:

    • Den viktigaste dokumentationen för en programmerare är ofta på en övergripande nivå. Denna dokumentation kan med fördel skrivas i ett separat dokument eftersom man ofta behöver läsa den för att överhuvudtaget veta vilka klasser man är intresserad av, om den ens är relaterad till en specifik klass. För projektet finns det plats för detta i projektbeskrivningen.

      Ett par förkortade exempel på vad som kan passa in här: "Alla rörliga objekt på skärmen är subklasser till Mover. Vill man ha flygfunktionalitet kan man ärva från Flier istället, eftersom detta har inbyggda funktioner för att landa. Varje rörligt objekt har en egen bakgrundstråd och rör sig individuellt med synkronisering via... /alternativt/ Vi använder en centraliserad spelloop som med jämna mellanrum anropar samtliga rörliga objekts uppdateringsmetod så de kan röra sig ett steg. Objekt som vill uppdateras mer sällan kan ange detta genom..."

    • Även i koden kan en del kommentarer behövas. Men istället för att omedelbart kommentera, försök först att skriva koden så dess betydelse är uppenbar. Detta är så klart ingen universallösning, men bra kod kan faktiskt relativt ofta göra kommentarer överflödiga. Då slår man två flugor i en smäll eftersom detta gör även övrig kod mer lättläst – och man minskar risken att man glömmer uppdatera en kommentar när koden ändras.

      Exempel 1:
      int i = 10; // Number of pixels to move for each step

      Förbättrad namngivning (som också gör det lättare att förstå vad som händer på alla ställen som faktiskt använder variabeln):
      int pixelsPerStep = 10;

      Exempel 2: Blanda en kortlek
      // Shuffle the deck (standard decks have 52 cards)
      for (int i = 1; i <= 52; i++) {
          // 53 is the deck size + 1
          deck.swap(i, i + randomInt(53-i) - 1;
      }

      Med en variabel till blir 52/53 självdokumenterande:
      final int deckSize = 52;
      // Shuffle the deck
      for (int i = 1; i <= deckSize; i++) {
          deck.swap(i, i + randomInt(decksize+1-i) - 1;
      }

      Med en separat metod har man givit ett namn till vad loopen gör (detta ska så klart göras med viss måtta):
      final int deckSize = 52;
      shuffle(deck, deckSize);
      ...
      private void shuffle(Deck deck, int deckSize) {
          for (int i = 1; i <= deckSize; i++) {
              deck.swap(i, i + randomInt(decksize+1-i) - 1;
          }
      }

    • Skriv gärna kodkommentarer som förklarar varför koden gör något, när det inte är uppenbart. Denna typ av kommentarer är ofta svårare att ersätta med lättläst kod.

Vissa aspekter av läsbarhet kan moderna utvecklingsmiljöer automatiskt fixa:

  • Den Java-kod du skriver måste följa de kodnings- och indenteringskonventioner som finns för Java. Till exempel ska satser separeras med radbrytningar (inte flera satser per rad).

    Detta krav är relativt enkelt att följa eftersom moderna utvecklingsmiljöer kan hjälpa till att formatera om kod så att de flesta konventionerna uppfylls. IDEA: Högerklicka katalog, välj "Reformat code...".

Struktur för klasser och paket

Strukturera klasserna enligt standarden:

  • Klasser i Java sorteras in i paket. Varje paket har ett namn, t.ex. paketet java.lang som innehåller grundläggande klasser som t.ex. String och Object. För att underlätta att skapa globalt unika paketnamn finns en standard där man inleder paketnamnet med sitt domännamn baklänges och därefter fortsätter med en identifierare inom domänen. För er del kan ett paketnamn till exempel vara "se.liu.ida.fffee123.tddc69.project.gameboard": Domän, studentkontonamn, kurs, uppgift (projektet), och ett delpaket inom projektet. Notera särskilt att det är bra att lägga olika relaterade delar av projektet i egna paket!

  • Skriv alltid varje Java-klass i en egen källkodsfil. Detta är en allmän konvention för Java och gör det lätt (även för kompilatorn) att hitta klasserna i programmet genom att leta bland källkodsfilerna (eftersom de har samma namn). Om man lägger flera klasser i samma fil blir det svårare att få en överblick över vilka klasser som finns i programmet. Undantaget är nästlade klasser, som definieras inuti en annan klass och därmed måste vara i samma fil.

Att gömma information

  • Förmågan att gömma information genom att använda privata instansvariabler är en viktig aspekt av objektorienterade språk som Java, bland annat för att det möjliggör senare förändringar av implementationen av datalagring i en viss klass utan hänsyn till andra klasser som använder dessa data direkt. Därför ska instansvariabler (fält) normalt vara private.

    Som så många andra regler har denna regel undantag, främst vad gäller enklare datalagringsklasser som t.ex. Rectangle i Java. Vid varje instansvariabel som inte är private måste det dock dokumenteras noga varför detta är ett bättre alternativ.

  • När det gäller metoder måste ni tänka efter vilka som bör vara private, protected respektive public. Metoder som bara borde användas "internt" inom en klass ska till exempel vara privata.

Ingen "onödig" kod

  • Vid projektinlämning ser vi ofta kod som upprepas flera gånger, i samma klass eller i olika klasser, identiskt eller med vissa parametrar ändrade. Detta ska undvikas, eftersom det ger mer kod för både er och oss att förstå, mer kod att underhålla i framtiden, mer jobb när förändringar ska ske (och måste göras på många olika platser i koden), och så vidare. Till exempel:
    • Om en viss metod gör (mer eller mindre) samma sak flera gånger, ska den koden troligen brytas ut till en ny metod så att man istället kan anropa den metoden flera gånger. Om vissa värden skiljer sig (en gång loopar man över lista A, en gång över lista B) kan man ofta skicka med detta värde som parameter till metoden.

    • Om två relaterade klasser (i samma arvshierarki) har samma eller liknande metoder, kan detta kanske ersättas av en gemensam metod i en gemensam superklass.

    IDEA kan hjälpa till att hitta vissa former av duplicerad kod: Analyze | Locate Duplicates. Detta ersätter inte en egen kontroll av labben eller projektet!

  • Död kod (klasser, metoder eller fält som aldrig används) får inte finnas med i en inlämning. Undantaget är om det finns kod som inte är färdig, men där ni ändå vill visa att ni har kommit en bit på vägen. Sådan kod måste vara väl avgränsad och det måste framgå tydligt vilka delar (hela klasser eller metoder) som inte används och varför.


Sidansvarig: Jonas Kvarnström
Senast uppdaterad: 2012-08-30