Göm menyn

Projektbedömning

Här diskuterar vi hur projekten bedöms. Läs detta i förväg för att vara medvetna om vad ni behöver tänka på under projektets gång!

Allmänt om projektbedömning

När du lämnar in ditt projekt kommer det att granskas i två omgångar, först av en handledare och sedan av examinatorn. Syftet med projektbedömningen är:

  • Att examinera dina kunskaper.

  • Att vara ett sista inlärningstillfälle där du får tips om vad du behöver tänka på.

Resultatet av bedömningen kan bli att:

  • Projektet blir godkänt. I TDDD78 och TDDE30 ges betyg 3-4-5. I 729A85 ges betyg G-VG.

    Du kan också plussa (höja betyget) vid senare inlämningstillfälle genom att fortsätta arbeta med samma projekt. Detta gäller garanterat under årets inlämningsmöjligheter, som visas på deadlinesidan. När nästa kursomgång börjar kan du behöva följa nya regler!

  • Projektet blir inte godkänt och behöver kompletteras vid senare inlämningstillfälle. Komplettering kan behövas även om det är uppenbart hur man skulle ändra koden – för det är genom att göra som man både lär sig mest och visar att man kan, inte genom att förklara hur man kunde ha gjort. Under årets inlämningstillfällen kan du fortsätta komplettera enligt årets regler. När nästa kursomgång börjar kan reglerna ändras.

Det tar minst ett par timmar att bedöma och kommentera ett projekt, så det är omöjligt för oss att ge en fullständig bedömning i förväg. Men i mån av tid kan handledarna titta på projektet och ge tips, vilket knappast händer under en tenta. Utnyttja detta i god tid! Fråga gärna även andra kursdeltagare om de har några minuter för att ge förslag och kommentarer.

Bedömningskriterier: Utökningar till Tetris

För att uppnå ett givet betyg i den här kursen behöver man visa upp kunskaper och färdigheter inom ett antal områden. Vår erfarenhet är att vissa av dessa områden kan vara svåra att få in i projektet. Vissa projekt leder till exempel inte på ett naturligt sätt till användning av felhantering (exceptions), och även om felhantering används någonstans kanske det inte testar just de aspekter som vi behöver examinera.

Därför har vi infört en betygsskillnad även i Tetrisuppgiften, där man behöver göra fler individuella uppgifter för att uppnå högre betyg än 3/G och därmed examineras med ytterligare djup och bredd.

Vi ger dock inte detta betyg i själva labbmomentet, delvis för att vi då skulle behöva ställa betydligt högre krav på all labbkod för att man skulle få ett av de högre betygen. Istället räknas dessa delar av Tetris in i momentet PRAx i LADOK, det som vi ibland slarvigt kallar "projektet". Det påverkar alltså det individuella projektbetyget och därmed betyget på hela kursen.

Bedömningskriterier: Programkod

Vi vill uppnå god objektorientering, bra användning av Java, och välskriven, välstrukturerad, lättläst och robust programkod.

Det går inte att i förväg ange exakt vad man måste göra för att uppnå en viss betygsnivå inom dessa områden. Detta beror dels på att vissa kriterier är svåra att mäta och kvantifiera, dels på att vissa "problem" kan kompenseras av att koden håller hög kvalitet i övrigt, och dels på att det inte går att göra en uttömmande lista på alla sätt man kan bryta mot de abstrakta principerna om bra programmering. "Hur objektorienterad" måste koden till exempel vara för betyg 3?

Här krävs istället en bedömning av handledaren och examinatorn, och ju högre betygsambition, desto högre krav ställs. Projektet är alltså som en tenta: 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 jobba på till man tror man har klarat gränsen med rimlig marginal.

Men vi kan ändå göra en hel del för att konkretisera de abstrakta kraven.

  1. Vi ska bryta ner önskemålen i mer konkreta aspekter av programmering och programkod. Detta ser du i "underrubrikerna" nedan.

  2. Vi kan ibland ange en uppsättning specifika krav som projektet ska uppfylla, där man normalt får komplettering om man bryter mot kravet även om projektet i övrigt håller hög kvalitet. Ibland finns det också specifika skillnader i sådana krav mellan olika betygssteg. Detta beskriver vi i rutor som denna:

    Rubrik
    • Betyg 3/G: ...

    • Betyg 4/VG/5: ...

  3. Vi har sammanställt ett antal specifika, konkreta exempel på bra och mindre bra programmering. Siffrorna nedan refererar till olika avsnitt på den sidan. Detta kan ses som en kondensering av tusentals sidor tänkbart kursmaterial till en mindre mängd konkreta tips som fokuserar just på det som brukar kunna ge problem i kursens projekt.

Avsnitt 1. Undvik fel som kan upptäckas automatiskt

En hel del potentiella problem i programkod kan upptäckas automatiskt, genom algoritmer som analyserar koden. IDEA kan göra detta åt dig. Följ instruktionerna.

Inspektera koden med korrekt profil och åtgärda eller motivera varningar enligt instruktionerna. Annars kan du få komplettering utan att handledaren går genom projektet. Att granska ett projekt med många inspektionsvarningar är slöseri med tid. IDEA kan givetvis ha fel i sina inspektioner. Som det står i instruktionerna ska man då ge en tydlig motivering till varför man anser att IDEA har fel och varför koden inte bör ändras. Detta ingår i examinationen och kan i princip ses som en tentafråga. Att inte kommentera kvarlämnade varningar, eller enbart kommentera att "jag tycker inte det behövs" eller att "IDEA har fel" utan vidare motivering, ger normalt komplettering!

2020-05-15: I den inlämnade koden får du numera använda @SuppressWarnings eller //noinspection för att undertrycka (suppress) inspektionsvarningar; se Suppress inspections (inte "disable inspections", då detta stänger av hela inspektionen så att du inte ser var du behöver skriva motiveringar).

Detta ersätter inte behovet av motiverande kommentarer för att förklara varför en varning var ogiltig och skulle undertryckas! Granskningssystemet har nu lärt sig att hitta även undertryckta varningar, och dessa kommer att visas för granskaren med extra information om att denna varning var avstängd – detta visar oss att du tyckte varningen var ogiltig, men du behöver fortfarande förklara varför.

Avsnitt 2, 3, 4, 5. Skriv förståelig kod

Läsbarhet är viktigt eftersom programmering ofta går ut på att utöka och ä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.

Olika aspekter av detta har diskuterats under flera olika föreläsningar. På exempelsidan diskuteras detta också i flera olika sektioner:

  • [2] Allmän kodstruktur och organisation, t.ex. indelning av kod i metoder, klasser och paket.

  • [3] Kortfattad och koncis kod, som ger många exempel på hur man kan undvika upprepningar (identiska eller med variationer). Undvik Write Everything Twice – följ Don't Repeat Yourself!

  • [4] Självförklarande kod, som handlar om att göra koden lättare att läsa genom att det är uppenbart vad den gör, istället för att man kommenterar vad den gör. Till exempel är bra namngivning, och att man inför namngivna begrepp, viktigt.

  • [5] Dokumentation och kommentarer, i lagom mängd, som diskuterar hur man skriver de kommentarer som behövs även när många aspekter av koden är självförklarande.

Paketstruktur
  • Betyg 3/G: Ange alltid ett paket för din kod.

  • Betyg 4/VG/5: Dela upp projektet i lämpliga delpaket. Om det inte går att hitta lämpliga grupperingar kan det hända att projektet inte har tillräcklig omfattning, att för mycket kod ligger i en och samma klass, eller att projektstrukturen behöver justeras. Det kan också hända att projektet verkligen inte lämpar sig för uppdelning, men det är ovanligt.

Död kod
  • Betyg 3/G/4/VG/5: Ta bort död kod, det vill säga kod som aldrig kan anropas och därmed inte kan testas eller demonstreras ordentligt.

Repetitiv kod

Genom att abstrahera, parameterisera och generalisera kan man på kortare tid skriva kortare, mer lättläst och mer utökningsbar kod utan onödiga upprepningar. Detta är alltså viktigt av många anledningar.

  • Betyg 3/G: Upprepad / repetitiv kod accepteras i små mängder. Alltför repetitiv och ineffektiv kod ger ofta komplettering, även när det inte gäller "exakt" upprepning. Gå genom all din kod och undersök om det finns något du tycker borde kunna uttryckas effektivare, kod där det känns som om du inte borde ha behövt skriva så mycket som du gjorde. Antagligen behövde du inte det!

  • Betyg 4/VG/5: Upprepad / repetitiv kod bedöms hårdare.

  • Detta är en vanlig källa till komplettering eller betygssänkning!

Dokumentation och kommentarer
  • Betyg 3/G: Projektrapportens implementationsavsnitt måste ge en bra översikt över programmet, typiskt på 3–6 sidor (givet att det mesta är text). Detta är en del av examinationen som delvis ersätter en tenta.

    Koden måste också vara tillräckligt lättförståelig. Första steget är alltid att skriva självförklarande kod, men oftast krävs också en del kommentarer, både när det gäller varför man gör något och hur man gör det.

    Med detta sagt vill vi också säga att vi har sett extremt stora variationer i hur man kommenterar sina projekt. Vissa kommenterar alldeles för lite, medan andra ligger mycket över våra krav. Meningen är inte att varje fält, metod och kodstycke ska ha den perfekta och fullständiga beskrivningen, utan man behöver arbeta tillräckligt med kommentarerna för att den som läser koden ska få tillräckligt med information så man klart och tydligt förstår vad som händer och varför.

  • Betyg 4/VG/5: 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.

    Dessutom ska alla eventuella publika fält Javadoc-dokumenteras ordentligt. (Sådana fält ska normalt undvikas.)

Avsnitt 6. Korrekt objektorientering

Programmera objektorienterat. Ta chansen att demonstrera att du har lärt dig 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 du använda OO-lösningen, om den inte är uppenbart sämre.

Använd också objektorientering på korrekt sätt. Vissa aspekter av korrekt användning av objektorientering diskuteras under [6] Korrekt objektorientering.

Globala variabler och Singleton
  • Betyg 3/G/4/VG/5: Undvik globala variabler (icke-konstanta static-fält) och Singleton-mönstret. I undantagsfall kan detta vara den bästa lösningen, men det är mycket vanligare att det leder till komplettering.

Avsnitt 7. Korrekt användning av ärvning, polymorfism

Typhierarkier, ärvning och polymorfism är kraftfulla verktyg, men de ska inte användas till allt, och det finns ett antal fallgropar som har diskuterats under kursens gång. Några viktiga aspekter diskuteras vidare under [7] Ärvning, polymorfism med mera.

Avsnitt 8. Korrekt inkapsling / synlighet

Vi har diskuterat hur man kan göra medlemmar privata eller "skyddade" (protected) för att till exempel gömma implementationsdetaljer. Under [8] Inkapsling och synlighet påminner vi om några saker att tänka på.

Avsnitt 9. Korrekt användning av typer

Under [9] Korrekt användning av typer påminner vi om några aspekter av användning av typer, bland annat vad gäller generics (generiska typer som List<E>) och wrappertyper (objekt som lagrar enstaka primitiva värden, som Integer och Boolean).

Avsnitt 10. Felhantering och robusthet

Skriv robusta program. 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. Vanliga misstag och fallgropar visas under [10] Felhantering och robusthet.

Resurshantering

När man läser in resurser via t.ex. ClassLoader.getSystemResource() kan det hända att de saknas. Man får då null tillbaka, vilket kan leda till NullPointerException senare i koden.

Just att man får null tillbaka behöver inte uttryckligen hanteras genom att man lägger till en egen test av returvärdet, eftersom det i så fall beror på felaktiga resursnamn eller problem med själva installationen av programmet. Det är att jämföra med att klassfiler saknas i installationen, vilket vi inte heller har separat felhantering för.

Om bildhanteringsmetoder som ImageIO.read() kastar vanliga exceptions som faktiskt fångas, t.ex. IOException, ska detta inte ignoreras utan hanteras i catch-satserna på korrekt sätt. Det är bara den egna testen av om ClassLoader.getSystemResource(...) == null som får hoppas över!

För inläsning av bilder som är resurser får detta korrekta sätt t.ex. vara att ett felmeddelande ges till användaren och att programmet sedan avslutas, då detta återigen beror på att programmet i sig själv är felaktigt. (Läser man in bilder som inte är resurser, t.ex. bilder som användaren har angivit, ska man inte bara avsluta utan hantera felet genom att meddela användaren och t.ex. ge en möjlighet att välja en annan bild.)

Felhantering

Med "upptäckta fel" menar vi dels undantag (exceptions) som fångas efter att de uppstår i egen kod eller andras kodbibliotek, dels andra typer av fel som man upptäcker på andra sätt, t.ex. genom att man själv kontrollerar om användaren ger felaktig input eller om en metod signalerar fel genom att returnera null.

  • Betyg 3/G: Upptäckta fel får inte bara ignoreras.

    Om ett fel beror på användarens input, t.ex. att användaren har matat in felaktig information i en dialogruta, valt en fil som inte kan öppnas eller har styrt en spelare utanför skärmen, ska det hanteras genom att användaren får en ny chans att ge korrekt input.

    I övriga fall är det önskvärt att fel hanteras korrekt enligt kraven för betyg 4 nedan, men acceptabelt (för betyg 3/G) att helt enkelt skriva ut en stacktrace och avsluta programmet. Då demonstrerar du att du vet var felen kan uppstå och var de borde hanteras, och undviker många farliga följdfel.

    Att ignorera fel och fortsätta är inte acceptabelt för betyg 3/G.

  • Betyg 4/VG: Upptäckta fel ska hanteras korrekt. Detta innebär bland annat att fel ska hanteras på rätt plats, att man inte får "fånga och ignorera / glömma bort" felen, att man ska tänka på potentiella följdfel (om jag fångar felet här och fortsätter, vad händer då?), och att man vid behov ska ge rimliga felmeddelanden till användaren. Läs vidare i de specifika tipsen!

    Om det är helt orimligt att programmet ska kunna fortsätta köra efter felet, är det acceptabelt att helt enkelt skriva ut en stacktrace och avsluta programmet. I övrigt ska fel hanteras enligt bästa förmåga.

  • Betyg 5: Exceptions som fångas ska dessutom loggas med hjälp av Javas loggningssystem (java.util.logging), tillsammans med rimliga felmeddelanden. Loggning ska ske till en loggfil med hjälp av klassen FileHandler.

    Då detta bara gäller betyg 5 får man själv läsa på i dokumentationen för att lära sig hur loggning fungerar.

11. Korrekta designmönster

Att använda [11] Designmönster i projektet är inget krav, och vi granskar dem inte heller. Vi vill ändå varna för ett designmönster som ibland leder till modelleringsproblem i projekten.

Varning: MVC-mönstret (Model/View/Controller) är ofta för komplicerat att applicera på projekten. Detta mönster användes i Tetris, där vi helt separerade datamodellen (Board) från grafisk visning. Detta var relativt enkelt då Tetris har en enkel modell. Skriver man till exempel ett spel med många olika spelare och andra entiteter som ska visas på skärmen, kan det vara bättre (i ett mindre projekt som detta) att hoppa över MVC och låta varje sådan klass ha hand om både modell och grafisk visning. Med andra ord, att låta Player både hålla reda på var spelaren är, hur många liv den har, och hur den ska se ut och kanske animeras. Annars är det lätt att man får en alltför centraliserad lösning med en enda utritningsklass som ska känna till hur allt ska se ut, vilket istället bryter mot decentraliseringsprinciper.

12. Körbara program

Projektet ska resultera i ett färdigt program som kan "levereras" för enkel installation och körning på någon annans dator – till exempel hos handledaren som ska testa inlämningen. Detta ställer ytterligare krav på programmet, som diskuteras under [12] Körbara program.

Inläsning av data och bilder
  • Betyg 3/G: Projektets filer får läsas in via vanlig filhantering. Detta gäller alltså filer som finns med projektet från början, t.ex. bilder och spelbanor.

  • Betyg 4, VG, 5: Javas stöd för resurser ska användas om du behöver läsa in filer (bilder, ljud, banor, inställningar osv.) som tillhör och "levereras med" programmet. Använd alltså ClassLoader.getSystemResource() och använd inte vanlig filhantering. På det sättet undviker man 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 du även skriver till en fil behöver du inte använda resurser för den filen, eftersom du i så fall ändå måste veta var filen är placerad.

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 tittar på bredd och djup, komplexitet och variation. Men den kod som har uppfyllt dessa kriterier har oftast också blivit minst 800 rader lång, och kod som är betydligt kortare har väldigt sällan uppfyllt kriterierna, även om det teoretiskt kan hända.

  • Om ni har börjat med strukturen från Tetris (rutnät eller andra sådana aspekter) har ni fått en del "till skänks", kodmässigt och/eller tankemässigt. Då kan det krävas att ni går längre eller djupare i den kod och den struktur som faktiskt är ny för projektet.

  • 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 du funderar över projektets omfattning, diskutera med en erfaren handledare i god tid.

Bedömningskriterier: Projektrapport

Den slutliga projektrapporten skrivs i andra halvan av den mall vi har tillhandahållit (och den inledande projektplanen behålls i inlämningen). Mallen ska så klart användas och ska innehålla all den information som vi har begärt genom mallens instruktioner.

Projektrapportens kvalitet inverkar också till viss del på bedömningen av projektet – har ni gjort ett bra jobb med att beskriva implementationen? Det mesta av detta går som vanligt inte att kvantifiera: Går det att förstå hur implementationen fungerar? Går det att förstå strukturen? En aspekt kan vi dock ge siffror på:

UML-diagram i implementationsbeskrivningen
  • För betyg 3/G ska man ha minst 1 UML-diagram i implementationsbeskrivningen i rapporten.

  • Betyg 4: Minst 2 diagram

  • Betyg VG (filfak): Minst 3 diagram

  • Betyg 5: Minst 4 diagram

Dessa diagram ska då användas på ett rimligt sätt för att illustrera olika aspekter av ert projekt. Det betyder att man inte tar med ett gigantiskt klassdiagram som visar ärvningsrelationer mellan alla klasser i hela projektet. Istället går man från andra hållet: När man vill beskriva en specifik aspekt av implementationen, t.ex. en viss hierarki av klasser och gränssnitt som man har skapat, skapar man också ett UML-diagram som gör det lättare att förstå det man har beskrivit.

Klassdiagram som visar hierarkier är bara en av flera möjligheter. Man kan också använda UML för att visa t.ex. komposition (objekt av typ X "har" objekt av typ Y) och mycket annat.

UML-diagram kan med fördel skapas i IDEA och klistras in i dokumentet. Man kan välja att börja med ett tomt diagram och manuellt välja vilka klasser som tas med (tryck SPACE), eller att börja med ett större diagram och ta bort det som inte önskas (högerklick, "delete").

Bedömningskriterier: Inlämning

Vid inlämning ska du följa alla inlämningsinstruktioner. Annars kan din inlämning återlämnas utan granskning.


Sidansvarig: Jonas Kvarnström
Senast uppdaterad: 2020-05-15