Göm menyn

Projektbedömning

Oj, sidan är lång!

Det stämmer. Vi kan lätt sammanfatta stora delar som "ju högre kvalitet, desto högre betyg", men deltagarna brukar vilja veta så många detaljer som möjligt.

Så vad är syftet med projektbedömningen?

Syftet är delvis att examinera, delvis att hjälpa er lära er vad ni behöver veta för att skriva högkvalitativ kod. Kod som ni kan vara stolta över, som ni lättare kan utöka och ändra, som ni kan förstå ett år senare, och som andra kan förstå om de skulle ta över ert projekt.

Projekt som inte uppfyller kriterierna kommer att returneras för komplettering. Så gör vi även om det är uppenbart hur man skulle förbättra koden – för det är genom att göra man lär sig mest, inte genom att förklara hur man kunde ha gjort.

Vilka betyg kan man få, och när har man uppnått dem?

I TDDD78 ges betyg 3, 4, 5 eller komplettering. I 729A85 ges betyg G, VG eller komplettering.

Det finns vissa "hårda krav" för varje betygssteg (se nedan). I övrigt är projekt som tentor: Man kan aldrig veta exakt när man har lärt sig tillräckligt mycket för att få godkänt, eller när man har besvarat en fråga tillräckligt bra för att få full poäng. Man får helt enkelt jobba på till man tror man har klarat gränsen med rimlig marginal.

Det tar ett par timmar att bedöma och kommentera ett projekt, så man kan inte få reda på ett betyg i förväg. Men handledarna kan titta på projektet och ge tips, vilket knappast händer under en tenta. Utnyttja detta i god tid! Fråga gärna även andra gruppers handledare eller andra kursdeltagare om de har några minuter för att ge förslag och kommentarer.

Grundkrav: Automatisk kodinspektion

IntelliJ IDEA har stöd för över 600 "kodinspektioner" där utvecklingsmiljön automatiskt varnar för potentiella problem i programkoden. Fördelar:

  • Man kan få omedelbar återkoppling när som helst, och därmed lära sig snabbare.

  • Det blir färre kompletteringar, eftersom kvaliteten höjs innan inlämning.

  • Handledarna får mer tid till handledning och till icke-triviala kommentarer.

Alla projekt ska därför analyseras i IDEA, via Analyze|Inspect Code. Ni kan köra en annan miljö för utvecklingen, men koden ska ändå analyseras i IDEA före inlämning.

Om ni är osäkra på en varning: Läs den inbyggda förklaringen (klicka "more"), läs vår egen förklaring av varningar, fråga handledaren, och om inget av detta hjälper, fråga examinatorn.

Automatisk kodanalys kan så klart leda till falska varningar. Om man helt och hållet skulle undvika det skulle man också missa många väldigt värdefulla varningar. Därför kräver vi inte att alla projekt ska vara 100% fria från varningar. Däremot kräver vi att ni för varje varning:

  • Antingen fixar varningen så den försvinner,

  • eller kommenterar varningen i koden, nära själva varningen, och motiverar varför ni faktiskt har gjort rätt och varför man inte bör ändra koden just där. Kommentarer som "jag tycker inte det behövs" räcker inte och ger komplettering!

Arbetar ni inte på universitetets datorer behöver ni ladda ner kursens inspektionsprofil.

Kvalitetskrav

Många kriterier som vi är intresserade av är svåra att mäta och kvantifiera Vi kan till exempel inte ge ett strikt villkor för "hur läsbar" och "hur objektorienterad" koden ska vara. Här krävs istället en allmän bedömning av handledaren och examinatorn. Däremot kan vi förklara vilka kriterier som brukar kontrolleras. Diskussionen nedan är inte fullständig – tänk även på de allmänna kriterier för bra objektorientering som diskuterats på föreläsningarna.

För högre betyg ställs högre krav.

Objektorientering och Java

Programmera objektorienterat. Ta chansen att demonstrera att ni har lärt er begreppen som ingår i kursen och vet hur de ska användas. Detta är ju kursens mål! Om ett problem kan lösas på ett OO-sätt eller ett icke-OO-sätt ska ni använda OO-lösningen, om den inte är uppenbart sämre. Ni får gärna använda designmönster, om ni

Läsbarhet och struktur

Läsbarhet och struktur är viktigt eftersom programmering ofta går ut på att ändra existerande kod. Tid som läggs ner på att göra kod lättläst och välstrukturerad, och att dokumentera, är alltså inte bortslösad utan sparas in med råge i senare utvecklingsfaser. Slutmålet är därför inte bara att skapa ett program som åstadkommer rätt saker, utan att skapa ett program som gör på rätt sätt.

Exempel:

  1. Skriv välstrukturerad och modulär kod. Varje klass och metod ska t.ex. ha ett eget tydligt ansvarsområde, så att man lätt hittar i koden. Om en metod gör många olika saker är det ofta bra att bryta ut delar till egna metoder, så som vi har diskuterat på en föreläsning. Har du många klasser inom ett särskilt "område" (GUI, spelmekanik, ...) hör de kanske hemma i ett eget paket.

    Tänk på att minska klassernas kontrakt utåt: Undvik att göra medlemmar (fält och metoder) "public" i alltför hög grad.

  2. Undvik upprepningar. Projekt innehåller ofta kodsnuttar som upprepas, identiskt eller med små variationer. Upprepningarna kan ske inom en och samma metod, mellan metoder i samma klass, eller mellan olika klasser. Detta är problematiskt eftersom man får mer jobb att skriva, läsa och underhålla koden, och riskerar att ändringar inte genomförs konsekvent.

    Man kan ofta undvika detta genom hjälpmetoder (anropas flera gånger med olika parametrar), abstrakta hjälpklasser (samlar gemensam implementation inom en arvshierarki), eller liknande. Vet du inte hur du ska göra: Fråga innan du lämnar in!

    IDEA kan hjälpa till att hitta vissa former av duplicerad kod: Analyze | Locate Duplicates. Detta ersätter inte en egen kontroll! IDEA kan också hjälpa till att dela upp i delmetoder (markera kod, Refactor | Extract | Method).

  3. Skriv självförklarande kod, så långt det går. Detta är så klart ingen universallösning, men bra kod kan faktiskt göra ganska många kommentarer överflödiga. Då minskar också risken att man glömmer uppdatera en kommentar när koden ändras.

    • Hitta informativa och rättvisande namn, så minskar behovet av dokumentation. Exempel:
      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;

      En metod som flyttar alla fiender i ett spel kan gärna heta moveEnemies(), medan update() visserligen stämmer men inte är så informativt. En lista över uppkopplingar i en FTP-klient kan heta connections eller kanske currentConnections, medan c inte är informativt och windows är helt missvisande, även om varje uppkoppling har ett eget fönster på skärmen.

    • Använd fler namn, så behövs mindre dokumentation. Använd t.ex. namngivna konstanter eller enum-värden istället för "magiska konstanter" i koden. Exempel:

      // 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);
      } 

      Inför vi en namngiven konstant blir 52/53 självdokumenterande. Vi kan använda en lokal konstant (deklarerad final), eller deklarera konstanten i klassen (till exempel private final static int DECK_SIZE = 52;). Då blir det också enkelt att ändra värdet vid behov (här kunde man annars ändra alla "52" men glömma "53").

      // Shuffle the deck
      final int deckSize = 52;
      for (int i = 1; i <= deckSize; i++) {
          deck.swap(i, i + randomInt(deckSize+1-i) - 1;
      }
      

  4. Dokumentera där det behövs. Namngivning hjälper, men ofta behövs också kommentarer och annan dokumentation. Tänk på att handledaren och examinatorn ska läsa genom hela projektet!

    • Övergripande dokumentation av programmets struktur är viktig. Detta 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..."

    • Skriv också en beskrivande Javadoc-kommentar för varje klass – detta är ett krav! Javadoc kan även behövas för många fält eller metoder, men i vissa fall (t.ex. enkla getters/setters) är koden i sig själv så tydlig att kommentarer inte behövs.

      Fråga er själva: Om någon annan deltagare skulle sätta sig in i er kod, skulle de omedelbart förstå den?

    • Kod som är svår att förstå ska man först försöka förenkla. Ofta behövs ändå dokumentation och kommentarer, även efter rimliga förenklingar.

    • Det som behöver dokumenteras ska dokumenteras lagom mycket och på rätt nivå. Skriv t.ex. 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.

    • Kommentera inte det uppenbara, det man ser direkt genom att läsa en enda rad kod:

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

Robusthet

Var robust. Hantera till exempel eventuella fel som kan uppstå på ett bra sätt, särskilt när det gäller problem som direkt kan triggas av en användare.

Omfattning

Omfattningen ska motsvara projekttiden på runt 80 timmar/person. Omfattningen innebär inte bara "kodvolym" utan beror mycket på komplexitet, variation, och så vidare. Detta kriterium är av naturen mycket svårt att specificera närmare. Vad vi kan säga i förväg är:

  • Vi kan så klart inte godkänna ett projekt som ser ut att motsvara 25 timmars arbete – men hög kvalitet och bra användning av OO kan ändå till en viss del väga upp en mindre omfattning.

  • Projekt som är tillräckligt omfattande för 3/G brukar rent statistiskt ha minst 800 rader kod (exklusive tomrader, kommentarer osv). Många projekt från de senaste åren var flera gånger större.

    Detta betyder inte att vi bedömer omfattning efter antal kodrader!. Vi tar också hänsyn till komplexitet och variation. Men den kod som har uppfyllt dessa kriterier har oftast också blivit minst 800 rader lång.

  • Smart är bättre än långt. En smart och effektiv lösning är oftast bättre än en lång. Ineffektiv kod, t.ex. upprepningar av nästan identisk kod, har ofta lett till komplettering.

  • Vår rekommendation: Fokusera på kvalitet, funktionalitet och att utnyttja era 80(+80) timmar väl. Om ni funderar över projektets omfattning, diskutera med handledaren i god tid.

Ytterligare villkor för godkänt, 4, VG, 5

Villkoren nedan är mer specifika och måste uppfyllas för att ett projekt ska få det önskade betyget – annars komplettering eller lägre betyg (som kan plussas).

Kodkrav för godkänt betyg (3/G)

  • Lägg alla klasser i namngivna paket! Använd också rätt namngivningsstandard, t.ex. "se.liu.ida.fffee123.tddd78.project.gameboard".

  • Följ den vedertagna namngivningsstandarden som vi har diskuterat. Detta hjälper oss att snabbare förstå varandras kod. IDEA bör klaga om ni bryter mot standarden.

  • Ta bort död kod, dvs. klasser, metoder eller fält som aldrig används. 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.

  • Vid varje användning av static-fält eller Singleton måste man motivera via kommentarer: Varför är det viktigt att informationen bara kan lagras en gång, i ett globalt tillstånd? (Se diskussionen om static och Singleton i föreläsningsanteckningarna!)

  • Fel får inte ignoreras.. Om man inte kan återhämta sig från en exception på korrekt sätt måste man ta hand om problemet. För betyg 3/G är det acceptabelt att hantera fel som inte kan "fixas" genom att skriva ut en enkel stacktrace och avsluta programmet – då undviker man i alla fall många farliga följdfel.

  • Upprepad / repetitiv kod accepteras i mycket små mängder. Större mängd upprepningar kan ge komplettering, även för betyg 3/G. Se även "undvik upprepningar" ovan.

  • Sammanhörande uppräkningsbara "värden" ska modelleras med enum-konstanter, inte heltal eller strängar (exempel: mode = NORMAL, INVISIBLE, GHOST). Se föreläsningsanteckningarna för diskussion och motivering.

Kodkrav för betyg 4

  • Villkoren för godkänt projekt ska uppfyllas.

  • Fel (exceptions) ska hanteras korrekt. Detta innebär bland annat att de ska fångas på rätt plats, att man inte får "fånga och ignorera / glömma bort" felen, att man ska tänka på följdfel, och att man vid behov ska ge rimliga felmeddelanden. Programmet ska inte avslutas om man istället kan återhämta sig och fortsätta.

  • Javas stöd för resurser ska användas om ni behöver läsa in filer (bilder, ljud, banor, inställningar osv.) som tillhör och "levereras med" programmet. På det sättet undviker vi att behöva ange var filerna finns i en specifik installation, och filerna kan hämtas även om hela programmet råkar vara packat i en JAR-fil (liknande ZIP-fil). Om ni även skriver till en fil behöver ni inte använda resurser för den filen, eftersom ni i så fall ändå måste veta var filen är placerad.

  • Varje klass ska kommenteras med en övergripande Javadoc-kommentar som beskriver klassen (syfte, användning, relation till andra klasser, ...). Kommentarerna ska vara tillräckligt informativa för att man ska kunna få en rimlig förståelse för klasserna helt utan att läsa någon programkod! Javadoc-formatet beskrivs i en kursbok du har valt, eller t.ex. i Oracles egen dokumentation. Självklart kan även andra kommentarer behövas.

Kodkrav för betyg 5 / VG

  • Villkoren för betyg 4 ska uppfyllas.

  • Logga alla fel (exceptions) med hjälp av Javas loggningssystem (java.util.logging) tillsammans med rimliga felmeddelanden.

  • Hårdkoda inte sådan information som man kan vilja utöka eller ändra utan att skriva mer programkod eller kompilera om programmet. Sådana data måste läsas in från fil (med hjälp av resurser) snarare än att hårdkodas i programmet. Exempel på detta är definitioner av nivåer i ett spel, där varje nivå kanske innehåller en karta och ett antal andra parametrar för nivån. Ett annat exempel är definitioner av instrument i en mjukvarubaserad synthesizer. Vissa former av information kan med fördel lagras i property-filer som läses in med hjälp av resurser. Fråga om ni är osäkra.

  • Tangentbordsstyrning. Se till att ha "mnemonics" (understrukna bokstäver) i alla menyer, om ni använder menyer. Använd key bindings via InputMaps eller menyernas setAccelerator()-metod för att lägga in tangentbordskombinationer (shortcuts) för lämpliga kommandon, som Alt-F4 för att avsluta.

  • Använd assertions så som vi har beskrivit dem under föreläsningarna för att fånga upp olika typer av programmeringsfel. Användning på 1-2 platser i koden räcker inte, men man behöver inte heller använda dem för att till exempel testa alla parametrar till alla metoder. Använd dem där det verkar rimligt och beskriv hur ni har tänkt.

  • Upprepad / repetitiv kod bedöms hårdare för betyg 5.

Projektbeskrivning

Projektbeskrivning: Sammanfattning

Den slutliga projektbeskrivningen innehåller flera avsnitt som ska testa er förståelse av olika aspekter hos objektorienterad programmering. Hur mycket ni behöver ta upp i varje avsnitt beror på det betyg ni siktar på. Vi sammanfattar här och fortsätter sedan med mer detaljer.

Krav Betyg 3/G Betyg 4 Betyg VG Betyg 5

Visa förståelse för objektorientering genom att i projektbeskrivningen förklara hur ni har använt ett antal olika typiska egenskaper hos just OO-språk, och hur man hade kunnat göra i språk utan dessa egenskaper.

2 st 3 st 3 st 4 st

Visa insikt i programdesign, hur man tänker när man strukturerar sina program, genom att dokumentera ett visst antal designbeslut.

2 beslut 4 beslut 6 beslut 8 beslut

Visa förståelse för hur UML-diagram kan användas genom att inkludera ett visst antal diagram i förklaringarna av projektets struktur.

1 diagram 2 diagram 3 diagram 4 diagram

Ge oss tillräckligt med information! Se detta som tentafrågor där ni försöker ge tillräckligt med information för att verkligen visa upp breda och djupa kunskaper.

För att minska risken för komplettering får ni gärna lämna in ett eller två extra "svar" i varje avsnitt. Siktar ni på femma kan ni t.ex. beskriva 9-10 designbeslut istället för 8, så att ni har en liten marginal om något av dem inte skulle bli "godkänt".

Typiska egenskaper hos objektorienterade språk

Vi vill examinera en djupare förståelse för de objektorienterade begrepp vi har infört i den här kursen. I koden syns bara slutresultatet – i projektbeskrivningen får ni visa hur ni kom fram till detta och demonstrera att ni verkligen har förstått. För varje betygsnivå ska ni därför beskriva hur ni har använt ett visst antal olika typiska egenskaper hos just objektorienterade språk.

Icke-typiska egenskaper är t.ex. datatyper, enum-konstanter och serialisering av datastrukturer, som finns i olika former i många icke-OO-språk. Typiska egenskaper hos OO-språk inkluderar dessa (fråga gärna examinatorn om ni har egna förslag):

  • Användandet av gränssnitt (interface) för att representera abstrakta datatyper som har flera konkreta implementationer.

  • Abstrakta klasser för att specificera gemensam funktionalitet hos en uppsättning klasser.

  • Implementationsärvning, där en klass ärver metodimplementationer och fält från en annan (och lägger till egen kod alternativt "modifierar" existerande metoder via overriding). Här menar vi ärvning från en konkret superklass, för att skilja det från punkten ovan.

  • Sen/dynamisk bindning inom en typhierarki, för att anropa "rätt" implementation av en metod utan att känna till objektets verkliga typ.

  • Konstruktorer för att initialisera objekt.

I projektbeskrivningen finns en numrerad lista där ni kan lägga till en punkt för varje egenskap ni vill diskutera. Där beskriver ni tydligt:

  • Vilken egenskap det gäller.

  • Exempel på hur ni använt den, och var. Ange exakta namn på klasser och metoder så att det lätt går att hitta exemplet/exemplen, och beskriv vad ni har åstadkommit genom att använda egenskapen (vilket "problem" ni ville lösa).

  • Hur ni kunde ha löst detta (på ett rimligt sätt!) utan objektorientering, ifall ni hade använt ett språk där den aktuella egenskapen inte var tillgänglig.

  • Hur lösningarna skiljer sig åt. Vad vinner (eller förlorar) ni på att använda använda den objektorienterade finessen istället för att lösa det på något annat sätt? Eller är lösningarna kanske likvärdiga, även om de ytligt ser olika ut? Här ska ni alltså jämföra med en någorlunda rimlig alternativ lösning, som man faktiskt kunde ha använt om man ville lösa samma "problem" i ett icke objektorienterat språk.

Designbeslut

När man har flera rimliga alternativ för hur programmet ska designas och struktureras, och väljer ett av alternativen, tar man ett designbeslut. För varje betygsnivå ska ni beskriva ett antal designbeslut ni har tagit. Anledningen är både att ni ska visa oss hur ni har tänkt (som en tentafråga) och att ni själva ska fundera och reflektera över era val.
Många studenter har kommenterat att de har lärt sig mycket på att tänka genom dessa beslut!

Dokumentera detta under projektets gång – annars glömmer man lätt!

Vad är INTE ett designbeslut? Att man väljer int istället för long för ett visst fält är snarare ett "kodningsbeslut" – vi är intresserade av design på en lite högre nivå. Sådant som ska göras enligt projektkraven är inte (gruppens) designbeslut, t.ex. att de flesta fält ska vara privata. Det behöver också finnas alternativa lösningar som är så rimliga att beslutet inte blir helt trivialt och uppenbart. Att man använder konstruktorer för att man i sitt projekt inte har någon som helst användning av factory-mönstret är ett alltför trivialt beslut. Att dela upp koden i flera klasser är också ett uppenbart beslut i ett projekt av denna storlek.

I projektbeskrivningen finns en numrerad lista där ni kan lägga till en punkt för varje beslut ni vill diskutera. Detta ska vara andra lösningar än de som räknades upp under "användning av objektorientering"! I listan beskriver ni tydligt:

  • Vad ni ville åstadkomma.

  • Hur ni gjorde detta. Namnge klasser och metoder som är inblandade.

  • En rimlig alternativ lösning som ni kunde ha använt istället.

  • Varför den lösning ni valde var bättre än alternativet. (I vissa fall kanske ni inser att den lösning ni valde till slut blev sämre än alternativet – beskriv då varför.)

Är ni osäkra får ni gärna fråga handledarna, som i första hand kommer att bedöma projektspecifikationerna.

UML-diagram

För varje betygsnivå ska den slutliga projektbeskrivningen innehålla minst ett visst antal UML-diagram. Dessa kan t.ex. göras i IDEA.

Varje diagram ska illustrera en specifik "intressant" aspekt av projektstrukturen och åtföljas av en beskrivning enligt instruktionerna i mallen. Metoder och fält ska bara finnas med i diagrammen om de är relevanta och diskuteras i texten (undvik dem om ni bara vill illustrera klasstrukturen).


Sidansvarig: Jonas Kvarnström
Senast uppdaterad: 2017-02-27