Achievements
Table of Contents
- 1. About This page
- 2. A: Abstraktion
- 3. B: Arv
- 4. C: Planering
- 5. D: Dokumentation
- 6. E: Genericitet
- 7. F: Imperativ Programmering
- 8. G: Inkapsling
- 9. H: Objekt, identitet och struktur
- 10. I: Metodik
- 11. J: Minneshantering
- 12. K: Modularisering
- 13. M: Pekare
- 14. N: Pragmatics
- 15. O: Profilering och Optimering
- 16. P: Kodgranskning
- 17. Q: Testning
- 18. TODO R–V: Verktyg
- 19. TODO X: Kommunikation
- 20. TODO Y: Mjukvaruutveckling / Programvaruteknik
- 20.1. Y64: Använd en namngiven utvecklingsprocess och reflektera över utkomsten G3 Report
- 20.2. Y65: Skriv konsekvent bra kod G3 Report
- 20.3. Y66: Tillämpa kodgranskning löpande G3 Report
- 20.4. Y67: Delta aktivt i ett programmeringsprojekt G3 Report
- 20.5. TODO Y68: Redovisa en fungerande projektuppgift G3 Report
- 20.6. Y69: Tillämpa regressionstestning under projektet G3 Report
- 21. TODO Z: Inlämningsuppgifter (Inluppar)
Did you know that you can collapse () and expand () entire sections of these pages? Try clicking a heading! Try “scrolling” to content deep down in a page by collapsing preceeding sections.
Found a bug? Select the fauly text and hit C-x to start a GitHub issue.
1 About This page
This page gathers all the achievements on the course for your perusal. Read about what each achievement corresponds here. Some are marked TODO, meaning they are being somewhat reworked for 2018. When they are finalised, the TODO marker will disappear.
You will use the AUPortal to select goals for demonstration and track your own progress. Starting in 2018, the AUPortal points back to this page for information about each achievement. I am testing gathering all achievement on a single page to facilitate searching – I’m eager to get feedback on this design choice. An alternative would be to gather all Abstraction achievements on one page, all Inheritance achievements, on another etc.
Each achievement is tagged to reflect its grade level and demonstration form – mirroring information in the AU Portal:
Tag | Meaning |
---|---|
G3 | Achievement is mandatory for grade 3 |
G4 | Achievement is mandatory for grade 4 |
G5 | Achievement is mandatory for grade 5 |
Lab | Achievement is demonstrated during lab sessions |
Special | See instructions for demonstration in the achievement text |
Report | Achievement is demonstrated as part of the project report |
2 A: Abstraktion
2.1 A1: Procedurell abstraktion G3 Lab
Tillämpa procedurell abstraktion på ett konsekvent sätt för att öka läsbarheten och undvika upprepningar.
Abstraktion är en av de viktigaste programmeringsprinciperna. Vi vet att djupt, djupt nere under huven är allt bara ettor och nollor (redan detta är en abstraktion!), men ovanpå dessa har vi byggt lager på lager av abstraktioner som låter oss tala om program t.ex. i termer av struktar och procedurer.
Procedurell abstraktion handlar om att separera användande från implementation. Varje procedur utför – idealiskt – en enda, välspecificerad funktion, t.ex. en viss beräkning, en förändring av programmets tillstånd, uppdaterar en datastruktur, stänger en fil, etc.
En väldöpt procedur (funktion) t.ex. open_file_for_reading()
ger
en tydlig beskrivning av vad den gör, men hur den gör det –
dess implementation – är inkapslad och inte synlig utifrån.
Använder den systemanropet fopen()
eller någon annan funktion?
Det skall vi strunta i! Det är inte1 inte något vi skall behöva bry oss om, och dessutom
något som kan komma att ändras, eller skilja sig beroende på
vilken dator jag kör programmet på.
Ta som tumregel att varje procedur skall kunna beskrivas enkelt och kortfattat. En procedur vars beteende inte går att beskrivas enkelt och kortfattat skall förmodligen brytas upp i flera mindre procedurer.
I ett nötskal handlar procedurell abstraktion alltså om att kapsla in alla “conceptual units of behaviour” i en procedur. En procedur är ungefär detsamma som en funktion och många programspråk (t.ex. C) gör ingen skilland på dem.
2.1.1 Exempel
Proceduren ritaEnCirkel(int radie, koordinat center)
utför
beräkningar och tänder individuella pixlar på en skärm, men i och
med att dessa rutiner kapslats in i en procedur med ett vettigt
namn, där indata är uttryckt i termer av koordinater och radie har
vi abstraherat bort dessa detaljer, och det blir möjligt att rita
cirklar tills korna kommer hem utan att förstå hur själva
implementationen ser ut.
Väl utförd abstraktion döljer detaljer och låter oss fokusera på färre koncept i taget.
2.1.2 Redovisning
Du bör ha en klar uppfattning om bland annat:
- Varför det är vettigt att identifiera liknande mönster i koden och extrahera dem och kapsla in dem i en enda procedur som kan anropas istället för upprepningarna?
- Abstraktioner kan “läcka”. Vad betyder det och vad får det för konsekvenser?
- Vad är skillnaderna mellan “control abstraction” (ex. if-satsen är en abstraktion) och “data abstraction” (ex. en lista är en abstraktion)? Du kan läsa om dessa koncept på t.ex. http://en.wikipedia.org/wiki/Abstraction_(computer_science).
- Ge exempel på procedurell abstraktion i ditt program! Kritisera den! Kan den förbättras?
- Vad är den kortfattade beskrivningen av vad funktionerna gör?
- Ger namnen på funktionerna en bra ledning om vad funktionerna gör?
- Finns det exempel på läckande abstraktioner, dvs. där den som anropar funktionen måste känna till hur funktionen faktiskt är implementerad för att fungera, eller förutsätter en viss implementation?
- Låt \(f_1\), \(f_2\) och \(f_3\) vara funktioner. \(f_1\) och \(f_2\) är delar av samma bibliotek och \(f_2\) använder \(f_3\) i sin implementation. Skiljer sig nivån av abstraktion mellan dessa på något sätt? Hur?
Är abstraktion möjlig utan inkapsling? (Bonusfråga)
Report a bug on this achievement? Please place an issue on GitHub.
2.2 A2: Objektorienterad abstraktion G3 Lab
Tillämpa objektorienterad abstraktion för att dölja implementationsdetaljer bakom väldefinierade gränssnitt.
I samband med redovisning bör du kunna förklara skillnaden/likheterna mellan procedurell abstraktion och objektorienterad abstraktion.
Vad innebär egentligen objekt-orienterad programmering? En ledning är att OOP är ett synsätt snarare än speciella nyckelord eller konstruktioner i ett programspråk.
Report a bug on this achievement? Please place an issue on GitHub.
2.3 A3: Informationsgömning G4 Lab
Demonstrera förståelse för designprincipen informationsgömning i
ett C-program med hjälp av .c
och .h
-filer.
Informationsgömning på engelska översätts till “information
hiding”. En viktig insikt här är att informationsgömning är en
princip som är programspråksagnostisk och inte knuten till några
speciella nyckelord. I Haskell kunde ni uppnå informationsgömning
med hjälp av moduler som bara exporterade en del av sitt
gränssnitt. Samma princip fungerar i C, men då är gränssnitt och
implementation separerade i .h
respektive .c
-fil.
Relatera gärna till koncept från Java, som gränssnitt respektive implementation.
Report a bug on this achievement? Please place an issue on GitHub.
2.4 A8: Gränssnitt G4 Lab
Visa hur man kan separera gränssnitt från implementation med hjälp av Java-interfaces.
Separation av gränssnitt från implementation är viktigt för att möjliggöra interna förändringar av implementationen utan att externa klienter behöver t.ex. kompileras om.
Javas interface
-konstruktion är ett förtingligat gränssitt som
kan knytas till en klass som implementerar det. Ett interface
kan ses som ett kontrakt och implementationen av ett interface
kan ses som ett löfte att uppfylla kontraktet. En klass som
implementerar ett interface
måste åtminstone nominellt uppfylla
detta kontrakt.
Detta mål handlar inte bara om att förstå principen för hur man gör en separation av detta slag utan också varför. Det sistnämnda bör guida det praktiska användandet och kan med fördel förklaras vid en redovisning.
Report a bug on this achievement? Please place an issue on GitHub.
3 B: Arv
3.1 B4: Arv och subtypspolymorfism G3 Lab
Make use of inheritance, overriding and super calls in a program that leverages subtype polymorfism.
3.1.1 Metodspecialisering (aka overriding)
Metodspecialisering avser när en subklass tillhandahåller en mer
specifik implementation av en metod än sin superklass. Ponera
klasserna Egendom
och Hus
där Hus
ärver av Egendom
. Man
kan tänka sig att det finns en metod skatt()
för Egendom
som
beräknar en viss grundskatt baserat på något givet värde, men att
Hus
tillhandahåller en egen implementation av skatt()
som är
mer specifik för just hus, t.ex. gör vissa avdrag etc. som
gäller specifikt för hus. Man kan tänka sig att den mer specifika
skatt()
-metoden anropar den mer generella för återanvändning
(räkna ut grundskatten).
Polymorfism är möjligheten att behandla olika typer av värden
genom ett gemensamt gränssnitt eller möjligheten att applicera en
funktion på flera olika typer av värden. Det finns många olika
typer av polymorfism – studera detta begrepp vidare! I Haskell
stötte ni på polymorfism till exempel i signaturen till map :: (a
-> b) -> [a] -> [b]
– map
tar en funktion från a
till b
ch en lista av a
:n och beräknar en lista av b
:n, och fungerar
likadant oavsett vilka typer man använder istället för a
och
b
.
Subtypspolymorfism avser polymorfism mellan subtyper, t.ex. Hus
och Egendom
ovan och husets möjlighet att uppträda/bli behandlat
som en generell form av egendom. (Javas dynamiska bindning gör här
att huset ändå bibehåller sitt specifika beteende.)
3.1.2 Inheritance in relation to subtype polymorphism
Inheritance facilitates (or even allows) the modularisation of
definitions, which can be very useful even if a class hierarchy
never branches out (meaning that no class has more than one
subclass). Imagine a class hierarchy with classes \(A\), \(B\) and
\(C\), such that \(A\) is a superclass of \(B\), and \(B\) is a superclass
of \(C\). The implementation of a behaviour \(b\) might be split over
\(A\), \(B\) and \(C\) through three separate, overriding,
implementations of a method \(m\). Thus, \(m\) is defined in \(A\), \(B\)
and \(C\) such that a subclass’ \(m\) overrides all its superclasses’
\(m\)’s. Through the use of super calls, \(C\)’s \(m\) may call \(B\)’s
\(m\). This effectively means that a specialised method can reuse or
extend a more general method in a super class. This was already
referenced above: “It is possible that the more specific
calculateTax()
” method calls the more general method for reuse,
e.g., to calculate basic tax.“
This allows us to distribute the specification of a behaviour over
multiple source locations in a way that may facilitate software
development and software evolution when used correctly. For
example, in the above example it is immediately clear from the
code that house taxation can be understood as a clean extension to
property taxation. This might be even more useful if Property
has several subclasses each subject to its own specific tax laws
as it allows reuse (because of the modular description) of the
basic property tax laws, making each delta small. In the case
where the variation in taxation is greater, we might implement
taxation as several methods working together, which allows a more
fine-grained overriding in subclasses. Be careful to not create
too unwieldy programs where the logic is hard to follow due to the
implicit (possibility of) branching in dynamic dispatch.
Overriding for its own sake shall be avoided.
If you find inheritance interesting, Tobias recommends a recent paper by Black, Bruce and Noble on the The Essence of Inheritance which he enjoyed immensely, especially Andrew’s presentation. Here is a(nother) recording of this presentation from WadlerFest.
Report a bug on this achievement? Please place an issue on GitHub.
3.2 B5: Liskov’s Substitution Principle G3 Lab
Demonstrate understanding of Liskov’s substitution principle by relating it to how you have used it in your implementations of the assignments or project.
Let \(C\) and \(D\) be classes, and \(P\) be a program that uses instance of class \(C\).
Liskov’s substitution principle (LSP) states that if \(D\) is a subtype of \(C\), then we should be able to change $C$-objects for $D$-objects in \(P\) without altering any desirable property of the program.
What does that mean?
In particular, from active use in your implementations, you must demonstrate understanding of the following concepts:
- The difference between subclass and subtype
- The concept of overriding
- The concept of overloading
- Understand the rule of covariance and contravariance with respect to method parameters and returns in relation to overriding, and how it relates to weakening preconditions and strengthening postconditions
- How the semantics of Java corresponds or deviates with the LSP
Bonus: is LSP the only possible definition of subtype?
Relate LSP to object-oriented reuse and/or software evolution and/or maintenance.
3.2.1 Incomplete Background (see lectures for complete coverage)
Överlagring (overloading) av operatorer, funktioner, metoder och
konstruktorer i Java sker när de har samma namn, men olika typer
på sina inparametrar, d.v.s. de har olika signatur. Ett
klassiskt exempel på överlagring är +
-operatorn som fungerar
olika beroende på typer: "1" + "2"
konkatenerar två strängar
(resultatet blir strängen "12"
), medan 1 + 2
adderar två
heltalsliteraler (resultatet blir heltalet 3
). C stöder inte
överlagring alls. Många statiskt otypade programspråk stöder
överlagring med avseende på antalet parametrar2
Specialisering (overriding) av metoder och konstruktorer sker
när en subklass tillhandahåller en konstruktor med kompatibel
signatur (detta avser regler för hur typer på returer och
parametrar får ändras – se kovarians och kontravarians). En
skillnad mellan metodspecialisering och konstuktorspecialisering i
Java är att i fallet konstruktorer måste åtminstone en konstruktor
anropas per klass i en klasshierarki, d.v.s. om klassen Hus
är
en subklass till Egendom
måste alla konstruktorer i Hus
anropa
en konstruktor i Egendom
(givet att en sådan finns). Notera att
ett sådant anrop måste stå först i konstruktorn eftersom objekt
initieras i stigande specialiseringsordning, d.v.s. mest generella
klass först (alla delar som hör till Object
), sedan näst mest
generella (Egendom
i föreliggande exempel) och sist det mest
specifika (här Hus
).
Report a bug on this achievement? Please place an issue on GitHub.
3.3 B6: Genomskärande åtaganden och arv G4 Lab
Förklara hur arv har använts i ett program för att separera genomskärande åtaganden.
Fördjupa dig i konceptet “genomskärande åtaganden.”
Genomskärande åtaganden är en försvenskning av begreppet Cross-cutting concerns. Ett åtagande är här något som (en del av) programmet måste göra, “ett stycke funktionalitet” slarvigt uttryckt, som kan vara “direkt” (beräkna \(X\)) eller “indirekt” (logga händelse under beräkning av \(X\) så att programmets beteende kan följas vid en krasch).
Separation av åtaganden (eng. separation of concerns) handlar om att inte blanda (eng. tangle) de olika implementationerna av olika funktionalitet. Om man t.ex. vill ändra på hur den ovan nämnda loggningen går till skall man inte behöva blanda in implementationen av beräkningen av \(X\).
Överkurs för den intresserade: Jämför med aspektorienterad programmering!
Report a bug on this achievement? Please place an issue on GitHub.
4 C: Planering
4.1 C7: Planering och uppföljning G3 Special
Planering och uppföljning är en viktig aspekt av kursen – programutveckling är ofta svårt på grund av osäkerhet och svårigheter att uppskatta tidsåtgång. Lättrörliga processer, som den som vi använder för att driva kursen, är ett sätt att motverka detta genom kontinuerlig uppföljning och en feedbackloop som visar om man underskattar eller överskattar tid.
Kurswebben beskriver den process som du skall använda, som är löst baserad på Scrum och personal Kanban.
Varje sprint skall du lägga upp en plan:
- Vilken inlämningsuppgift skall du göra
- Vilka mål skall du ta inom ramarna för den uppgiften
- Hur många mål du borde ta för att komma i mål med kursen
Dessa tre beslut kan hänga ihop. Till exempel kanske du saknar ett visst mål på nivå 4 som gör att det känns vettigare att göra en specifik uppgift – eller inte.
I början när du sitter med uppgiften är det som minst tydligt för dig exakt vilka mål som är lämpliga att redovisa. Du kanske ser 3 stycken men din plan säger att du skall nå 6. Det blir viktigt att du bevakar detta – går tillbaka till målbeskrivningarna, kanske sitter kvar med en gammal uppgift och kollar om den inte kan tänkas redovisa något.
Genom att göra en plan – X mål klar på Y tid – och bevaka hur det går (fortare eller långsammare än X/Y?) kan du få en känsla för hur du ligger till hela tiden.
Detta mål examineras genom inlämning av en komplett burndown chart efter fas 2. Den skall innehålla samtliga sprintar, det uppsatta målet, idealet, utfallet och hur du har planerat om. Du kan med fördel använda kursens spreadsheet för burndown charts. Om du skickar en länk till ditt spreadsheet, glöm inte att göra den publik så att den går att komma åt! Om du har planerat varje program får du gärna inkludera den planeringen också!
Skicka ditt burndown chart på epost till Gustaf enligt följande instruktioner:
- Ämnesraden skall vara
[IOOPM] C7
. Den första raden i mejlet skall vara ditt användarnamn till unix-systemet på formenfornamn.efternamn.NNNN
. Eftersom vi kommer ta emot mellan 100 och 150 mejl är det viktigt att det går lätt att hitta rätt mejl snabbt. - Tillsammans med din burndown-chart, skriv en kort beskrivning så att det går att förstå det utan att du står brevid och förklarar.
- Skriv också om hur du upplever att jobba på detta sätt, vad som är svårt och vad du får ut av det. Var ärlig! Om du bara tycker det har varit ett hinder, skriv det. Det viktiga är att du uttrycker en åsikt i frågan!
Report a bug on this achievement? Please place an issue on GitHub.
5 D: Dokumentation
5.1 D9: Dokumentation G3 Lab
Dokumentera icke-triviala modulers gränssnitt så att någon utomstående kan programmera mot dem.
Bra dokumentation är av största vikt vid utveckling. Vid en kort kurs som denna är det svårt att uppleva nyttan med dokumentation som man själv skriver eftersom det inte hinner gå tillräckligt lång tid under kursen för att sådant man utvecklat skall falla tillräckligt i glömska. (Ta gärna fram någon gammal inlämningsuppgift i Haskell från PKD och försök följa logiken och ändra i den.)
- Det är svårt att balansera mängden dokumentation som krävs för att beskriva något. Vem vänder man sig till? Vad kan man förvänta sig hos den som läser? Vad vill denne åstadkomma?
- Vad är en bra balans mellan för lite information och för mycket? Vad är en lämplig detaljnivå?
- Hur mycket av den interna implementationen bör man beskriva? Varför?
- Hur beskriver man komplexa och tvetydiga processer?
I funktionella språk som Haskell är pre- och postvillkor bra sätt att dokumentera förväntningar och löften på ett sätt som inte exponerar onödiga detaljer. Javaprogram har i regel tonvis med sido-effekter – vad får det för konsekvens för pre- och postvillkor?
Report a bug on this achievement? Please place an issue on GitHub.
6 E: Genericitet
6.1 E10: Implementera genericitet genom void-pekare G3 Lab
Använd void-pekare i C-program för att uppnå genericitet på ett relevant sätt, t.ex. en datasamling som kan lagra godtyckligt data
Det är inte en bra idé att ha kopior av kod med någon liten förändring, t.ex. en separat implementation av en heltalslista och en flyttalslista. Den underliggande logiken är densamma, och hittar man ett fel i en kopierad del måste man komma ihåg att ändra på samma ställe i alla kopior, etc.
I C använder man s.k. void
-pekare för att göra en datastruktur
generell, t.ex. gå från en lista av heltal till en lista som kan
hålla godtyckligt data. Detta är ett extremt vanligt C-idiom som
även förekommer i C:s standardbibliotek. En void
-pekare är en
pekare till en minnesplats med okänt innehåll, dvs. C-kompilatorn
vet inte vad som finns där och hur man skall använda minnet, eller
hur stort det är. Visa att du behärskar dessa idom och förstår
deras konsekvenser genom att använda dem på ett lämpligt sätt i
ett program.
Vid redovisning, börja med att förklara vad genericitet är och varför det kan vara bra i vissa sammanhang.
Report a bug on this achievement? Please place an issue on GitHub.
6.2 E11: Parametrisk polymorfism och typsäkerhet G3 Lab
Använd parametrisk polymorfism för ökad “statisk typsäkerhet” vid interaktion med Javas standardbibliotek.
Typsäkerhet avser att ett värde alltid används på tillåtet sätt,
t.ex. att en bit minne som råkar hålla en baseballspelare med ett
heltal för skostorlek på bytes 8–11 används på detta sätt. C är
inte ett typsäkert språk vilket tillåter oss att t.ex. spara
strängen "Hej"
på skostorlekens plats, och sedan läsa
dessa fyra bytes som en (abnorm) sko. Java är ett typsäkert
språk, och priset man betalar för detta är kontroller under
programmets körning som orsakar undantag om en operation skulle
leda till ett typfel.
Ponera en lista i Java där elementpekarna är av typen Object
. En
sådan lista kan innehålla vad data som helst, men vanligt är att
man är intresserad av en lista av basebollspelare etc.
Javas stöd för parametrisk polymorfism (även kallat generics) tillåter oss att skapa datastrukturer parametriserade över typer; parametrar vilka måste instantieras vid användande av strukturerna. Javas standardbibliotek formligen kryllar av klasser med typparametrar. Typparametrarna tillåter oss att uttrycka i kod att “detta är en lista av hermeliner” vilket medger möjligheten att signalera kompileringsfel om man försöker smyga in katt ibland hermelinerna.
Visa att du förstår konceptet parametrisk polymorfism och hur det kan användas för att flytta fel från körning (undantag) till kompilering (kompileringsfel).
Report a bug on this achievement? Please place an issue on GitHub.
6.3 E12: Designa med parametrisk polymorfism G4 Lab
Designa med parametrisk polymorfism för att göra relevanta delar av ett program mer generellt.
Vid designen av en eller flera klasser – dra nytta av parametrisk polymorfism för att slippa ange en typ vid definitionen (detta är en äppellåda) och istället ange den vid användandet av lådan (detta är en låda, som i detta fall råkar innehålla enbart äpplen).
En informell guldstjärna utgår för användanden som inte är samlingsklasser (collections).
Report a bug on this achievement? Please place an issue on GitHub.
7 F: Imperativ Programmering
7.1 F13: Iteration vs. rekursion G3 Lab
Visa en översättning mellan en rekursiv och en iterativ lösning av samma problem samt diskutera för- och nackdelar med sido-effekter.
Är någon av lösningarna bättre (vad betyder bättre?)? I så fall, varför skulle man någonsin vilja använda den andra lösningen?
Tänkvärt: Alla iterativa lösningar kan beskrivas med rekursion men gäller det omvända? Ibland ger rekursion en “historik” över vilken väg genom en datastruktur man tagit som försvinner vid en naiv översättning till iteration.
Rekursiva datastrukturer som t.ex. träd är bra för att demonstrera detta.
Report a bug on this achievement? Please place an issue on GitHub.
7.2 F14: Svansrekursion G4 Lab
(Eng. tail recursion)
Använd svansrekursion för rekursiva funktioner med potentiellt stort djup.
Svansrekursion är rekusion där varje rekursivt anrop kommer som det sista funktionen gör. Beakta följande, icke-svansrekursiva funktion:
int sum(int *numbers[], int num_siz) { if (num_siz > 0) { int rest = sum(numbers+1, num_siz-1); return *numbers + rest; } else { return 0; } }
int%20sum%28int%20%2Anumbers%5B%5D%2C%20int%20num_siz%29%0A%7B%0A%20%20if%20%28num_siz%20%3E%200%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20int%20rest%20%3D%20sum%28numbers%2B1%2C%20num_siz-1%29%3B%0A%20%20%20%20%20%20return%20%2Anumbers%20%2B%20rest%3B%0A%20%20%20%20%7D%0A%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20return%200%3B%0A%20%20%20%20%7D%0A%7D%0A
I detta fall används stacken som en temporär lagringsplats för alla temporära resultat. Vi kan skriva om funktionen på detta svansrekursiva vis:
int sum(int *numbers[], int num_siz, int acc) { if (num_siz > 0) { return sum(numbers+1, num_siz-1, acc + *numbers); } else { return acc; } }
int%20sum%28int%20%2Anumbers%5B%5D%2C%20int%20num_siz%2C%20int%20acc%29%0A%7B%0A%20%20if%20%28num_siz%20%3E%200%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20return%20sum%28numbers%2B1%2C%20num_siz-1%2C%20acc%20%2B%20%2Anumbers%29%3B%0A%20%20%20%20%7D%0A%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20return%20acc%3B%0A%20%20%20%20%7D%0A%7D%0A
I detta fall behövs ingen stack för att lagra tempoära värden (varför?) och som en konsekvens av detta kan en bra kompilator skriva om funktionen så att den kan köra i konstant minnesutrymme (mer eller mindre tranformera koden till en loop).
Kan en/din C-kompilator göra så-kallad “tail call-optimisation”? Under vilka omständigheter? Hur kan du pröva det?
Om din kompilator inte garanterar att svansrekursion transformeras till loopar – kan det vara problematiskt? Hur?
För att bli godkänd på detta mål måste du även visa hur du skriver om en rekursiv funktion på svansrekursivt vis.
Report a bug on this achievement? Please place an issue on GitHub.
8 G: Inkapsling
8.1 G15: Aliasering G3 Lab
Använd kopiering eller liknande för att undvika aliaseringsproblem i ett C- eller Javaprogram.
Aliaseringsproblem uppstår då pekare oavsiktligt pekar ut samma objekt/data så att en förändring via en pekare blir synlig via en annan pekare på ett överraskande sätt. I C är ett klassiskt exempel på aliaseringsproblem inläsning av strängar i en buffer som skrivs över vid varje ny inläsning. (Ett bra sätt att angripa detta mål är att vara vaksam på när du drabbas av denna bugg och använd det för att redovisa målet.)
Aliasering innebär att data kan delas mellan objekt. Detta är kraftfullt (en förändring via en pekare blir synlig för alla andra som har en pekare till samma data) men också väldigt farligt (en förändring via en pekare…) om man är slarvig med vad som delas och inte. Problematiskt är att kod som delar data och kod som inte delar data är identisk. T.ex. ett cirkelobjekt som har en pekare till ett punktobjekt som representerar dess center flyttas om dess centerpunkt flyttas. Om många punkter skapas på samma koordinat kan det vara effektivt att de delar denna punkt, men om de skall flytta sig individuellt uppstår problem om de inte har separata kopior av punkten.
Nu följer några tankar kring ägarskap, d.v.s., vilka objekt som hör till vilka andra objekt. Ett objekts (denna term omfattar även C-struktar) representation är de “subobjekt” som bygger upp ett sammansatta objekt. En länkad listas representation innehåller t.ex. dess länkobjekt eftersom dessa ägs av listan, men inte listdatat eftersom det inte är en del av själva listobjektet.
Representationsläckage är ett exempel på ett aliaseringsproblem och uppstår när subobjekt är synliga utanför det objekt till vilket de konceptuellt tillhör. Om man t.ex. kunde få ett handtag till en länk i en sorterad länkad lista utanför listan kan man göra borttagningar eller insättningar som förstör listans sorteringsordning.
Det är vanligt att subobjekt flyttas mellan objekt och byter ägare, eller skapas utanför objektet och flyttas in i det vid initiering. Mainstreamprogramspråk saknar dock koncept för ägarskap vilket kan leda till representationsläckage om man inte är aktsam.
Report a bug on this achievement? Please place an issue on GitHub.
8.2 G16: Namn-baserad inkapsling G3 Lab
Använd åtkomstmodifierare för att styra synligheten hos variabler och metoder.
Styr åtkomst till både privata metoder och data på ett lämpligt sätt och motivera användandet. Resonera också kring varför namnbaserad inkapsling inte är ett garanterat skydd mot aliasering.
Använd:
public
private
protected
eller motivera varför inte- package protection (saknar nyckelord)
Vad är Javas standard för inkapsling? Är det vettigt? Varför/varför inte?
Report a bug on this achievement? Please place an issue on GitHub.
8.3 G17: Nästlade och inre klasser G4 Lab
Använd nästlade och inre klasser för att kapsla in privata beståndsdelar i ett sammansatt objekt.
Notera den syntaktiskt subtila men relativt viktiga skillnaden mellan inre och nästlade klasser. Ett annat namn på sammansatta objekt är aggregat.
Inre och nästlade klasser är ett viktigt sätt att definiera objekt som består av komplicerade aggregat av flera objekttyper, men där man vill skydda/dölja de ingående delarna utifrån.
Report a bug on this achievement? Please place an issue on GitHub.
9 H: Objekt, identitet och struktur
9.1 H18: Jämförelsemetoden equals()
G5 Lab
Implementera stöd för strukturell likhet med hjälp av equals()
i
Java.
I Java-program används metoden equals()
för att jämföra två
godtyckliga objekt oavsett typ. Denna metod bör uppfylla ett antal
regler:
a.equals(b) == true
implicerarb.equals(a) == true
a.equals(b) == false
implicerarb.equals(a) == false
- Signaturen för
equals()
skall varaObject -> boolean
Man kan diskutera om equals()
-metoden bör förlita sig på
föränderligt tillstånd eller ej. Ett problem med detta är att två
objekt som är lika enligt equals()
senare kan ändras till att
inte vara lika längre, vilket kan leda till problem om man
förlitar sig på den “redan uträknade likheten” senare i
programmet.
Hur “lika” definieras kan vara olika – ibland används begreppet identisk för att avse att A och B är samma objekt; ibland används konceptet strukturellt lika eller ekvivalenta för att avse att A och B är två olika objekt men som ändå i enligt den gällande formen av likhet kan anses vara “utbytbara”, t.ex. A och B är två olika kakburkar som innehåller samma kaka.
Överkurs: tänk på relationen mellan equals()
och
hashcode()
och fundera över varför man ofta bör definiera en
hashcode()
-metod om man också definierar en equals()
-metod.
Report a bug on this achievement? Please place an issue on GitHub.
9.2 H19: Skillnaden mellan identitet och ekvivalens G3 Lab
Demonstrera förståelse för skillnaden mellan identitet och ekvivalens genom att demonstrera implementationer av båda koncepten och motivera valet av definition av likhet.
Vad menas med att två objekt/värden är identiska? Vad menas med att två objekt/värden är ekvivalenta? Hur implementerar man det ena och det andra?
Report a bug on this achievement? Please place an issue on GitHub.
9.3 H20: Värdeöverföring G3 Lab
Redovisa förståelse för skillnaden mellan värdesemantik och referenssemantik med hjälp av ett kodexempel.
Slå upp termerna, pröva gärna även engelska: “value semantics” respektive “reference semantics”. Se även parameteröverföring.
När använder man vilken typ av värdeöverföring? Fungerar C och Java annorlunda? Finns det fördelar/nackdelar med hur C och Java fungerar?
Report a bug on this achievement? Please place an issue on GitHub.
9.4 H21: Abstrakta klasser, metoder och interface G5 Lab
Redovisa förståelse för abstrakta klasser och metoder, samt deras relation till Java-interface.
Beakta bland annat:
- Hur skiljer de sig?
- Hur är de lika?
- När används de och vad har de för konsekvenser på programmen i vilka de används?
- Varför är multipelt arv mellan interface tillåtet och väldefinierat medan multipelt implementationsarv inte är det? (I Java, alltså.)
Report a bug on this achievement? Please place an issue on GitHub.
10 I: Metodik
10.1 I22: Defensiv programmering G3 Lab
Förklara innebörden av, och tillämpa på ett konsekvent sätt, defensiv programmering i ett program.
Studera konceptet defensiv programmering. Vid tillämpning, använd checklistan som finns i kursmaterialet och fundera på hur man kan kritisera den.
Report a bug on this achievement? Please place an issue on GitHub.
10.2 I23: Undantagshantering G3 Lab
Fånga på lämpliga platser och hantera på ett lämpligt sätt kontrollerade och okontrollerade (relevanta) undantag i ett program.
Fundera över vad som är en lämplig plats och hur man på ett
lämpligt sätt hanterar ett fel. Är det t.ex. någonsin relevant att
fånga ett NullPointerException
? Vilka fel kan t.ex. hanteras
utan att programmet snarare borde följa principen “crash, don’t
trash”?
För att bli godkänd måste du kunna
- kasta och fånga undantag,
- kunna resonera kring lämpligheten av varför undantag fångas där de görs, och vad som lämpligen ska hända när detta sker, samt
- förstå skillnaden mellan kontrollerade och okontrollerade undantag.
Report a bug on this achievement? Please place an issue on GitHub.
10.3 I24: Olika metoder för felhantering G4 Lab
Ett generellt problem i systemutveckling är hur fel skall hanteras. Ofta uppstår felen i en del av programmet där det inte är lämpligt att hantera dem; t.ex. ett fel som uppstår djupt nere i ett bibliotek på grund av felaktigt indata från en annan modul, som rimligen är den plats som skulle kunna “åtgärda detta problem”. Ibland måste ett fel propageras hela vägen upp till användaren som måste åtgärda problemet, eller göra ett val mellan olika sätt att hantera den uppkomna situationen, och i andra fall kan man bara ignorera/undertrycka problemet. Tyvärr kan det vara så att samma fel hanteras på olika sätt i olika program, så det är ibland svårt eller omöjligt att bygga in åtgärder direkt där felet uppstår, speciellt om man skriver ett bibliotek eller kod som skall kunna återanvändas.
Hur relaterar ovanstående till följande koncept:
- Crash don’t trash
- Defensiv programmering
- Undantagshantering (till exempel i Java)
- Hur fel hanteras i C med errno
Ge exempel på hur dessa koncept använts i dina olika inlämningsuppgifter, och vad konsekvensen av att byta mellan dem i ett program skulle bli.
Report a bug on this achievement? Please place an issue on GitHub.
10.4 I25: Egendefinierade undantag G4 Lab
Utöver föregående mål, demonstrera fördjupad förståelse för undantagshantering i Java genom att kasta existerande och egendefinierade kontrollerade och okontrollerade undantag i ett program.
Demonstrera med relevanta undantag, gärna i ett program du redan har skrivit under en tidigare sprint.
Report a bug on this achievement? Please place an issue on GitHub.
11 J: Minneshantering
11.1 J26: Allokering på stacken vs. på heapen G3 Lab
Demonstrera förståelse för skillnaden mellan allokering på stacken och allokering på heapen med hjälp av ett C-program.
Läs C: addendum om stack & heap
Pröva gärna också att t.ex. jämföra prestanda mellan ett program som allokerar mycket på stacken med ett som allokerar mycket på heapen (t.ex. genom att skriva om nedanstående rekursiva fibonacci-program där samtliga heltal mallokeras på heapen). Vad får det för effekt på uträkningens prestanda?
#include<stdio.h> #include<stdlib.h> int *heap_int(int i) { int *result = malloc(sizeof(int)); *result = i; return result; } int *fib(int *n) { if (*n == 0) { return heap_int(0); } else { if (*n == 1) { return heap_int(1); } else { return heap_int(*fib(heap_int(*n-1)) + *fib(heap_int(*n-2))); } } } // OBSERVERA! // Detta program läcker minne som ett såll -- det frigör inte några allokerade pekare int main(int argc, char **argv) { if (argc < 2) { puts("Usage: ./fib-rec 5"); } else { int *n = heap_int(atoi(*(argv+1))); printf("fib(%d) = %d\n", *n, *fib(n)); } return 0; }
%23include%3Cstdio.h%3E%0A%23include%3Cstdlib.h%3E%0A%0Aint%20%2Aheap_int%28int%20i%29%0A%7B%0A%20%20int%20%2Aresult%20%3D%20malloc%28sizeof%28int%29%29%3B%0A%20%20%2Aresult%20%3D%20i%3B%0A%20%20return%20result%3B%0A%7D%0A%0Aint%20%2Afib%28int%20%2An%29%0A%7B%0A%20%20if%20%28%2An%20%3D%3D%200%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20return%20heap_int%280%29%3B%0A%20%20%20%20%7D%0A%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20if%20%28%2An%20%3D%3D%201%29%0A%20%20%7B%0A%20%20%20%20return%20heap_int%281%29%3B%0A%20%20%7D%0A%20%20%20%20%20%20else%0A%20%20%7B%0A%20%20%20%20return%20heap_int%28%2Afib%28heap_int%28%2An-1%29%29%20%2B%20%2Afib%28heap_int%28%2An-2%29%29%29%3B%0A%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2F%20OBSERVERA%21%0A%2F%2F%20Detta%20program%20l%C3%A4cker%20minne%20som%20ett%20s%C3%A5ll%20--%20det%20frig%C3%B6r%20inte%20n%C3%A5gra%20allokerade%20pekare%0Aint%20main%28int%20argc%2C%20char%20%2A%2Aargv%29%0A%7B%0A%20%20if%20%28argc%20%3C%202%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20puts%28%22Usage%3A%20.%2Ffib-rec%205%22%29%3B%0A%20%20%20%20%7D%0A%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20int%20%2An%20%3D%20heap_int%28atoi%28%2A%28argv%2B1%29%29%29%3B%0A%20%20%20%20%20%20printf%28%22fib%28%25d%29%20%3D%20%25d%5Cn%22%2C%20%2An%2C%20%2Afib%28n%29%29%3B%0A%20%20%20%20%7D%0A%20%20return%200%3B%0A%7D%0A
Report a bug on this achievement? Please place an issue on GitHub.
11.2 J27: Manuell minneshantering G3 Lab
Demonstrera förståelse för minneshantering i C genom att skriva ett program med dynamiska strukturer som är fritt från minnesläckage och argumentera för varför det är så (och verifiera med valgrind).
Redovisa bland annat för:
- Hur uppstår minnesläckage?
- Vilken del av ett program ansvarar för att frigöra minne?
- När avgör man att en bit allokerat minne är “färdiganvänt” och går att frigöra?
- Vad kan hända om ett allokerat utrymme frigörs “för tidigt”?
- på vilket sätt hjälper valgrind dig att undvika minnesläckage?
Report a bug on this achievement? Please place an issue on GitHub.
11.3 J28: Manuell vs. automatisk minneshantering G4 Lab
Förklara skillnaden mellan C:s manuella minneshantering och hur Java hanterar minne och beskriv för ett lämpligt Java-program när minne allokeras och frigörs.
Redovisa bland annat för:
- När är ett objekt att betrakta som skräp som kan städas bort?
- När städas skräp bort?
- Hur kan jag som programmerare ta reda på när ett visst objekt städats bort?
- Finns det någon typ av minnesfel som jag kan få i C med pekare som jag inte kan få med referenser i Java?
- När allokeras minne och hur tar Java reda på hur många bytes ett visst objekt kräver?
- Hur tar jag som programmerare reda på hur många bytes ett visst objekt kräver?
Javas automatiska skräpsamlare kan konfigureras på många sätt, så tänk dig för varenda gång du säger “så här fungerar Javas GC”.
Bonus: hur fungerar “weak references”? Hur relaterar de till pekare?
Report a bug on this achievement? Please place an issue on GitHub.
11.4 J29: Jämför två metoder för automatisk skräpsamling G5 Special
Lämpliga metoder avser t.ex.:
- olika former av mark-sweep GC
- reference counting
- generational GC
Beskriv övergripande hur de valda metoderna fungerar. Diskutera deras för- och nackdelar. Lämpliga aspekter att beakta för en jämförelse omfattar bland annat följande koncept:
- throughput
- latency
- jitter
11.4.1 Redovisning
Detta mål har varit populärt att redovisa i form av en essä (X59) tidigare år. (Det går också bra att göra genom en diskussion med Tobias på ett labbpass.)
Report a bug on this achievement? Please place an issue on GitHub.
12 K: Modularisering
12.1 K30: Gränssnitt mellan moduler G3 Lab
Specificera tydliga gränssnitt mellan moduler i ett program som bör brytas ned i flera moduler (och implementera).
Börja med att förklara vad modularisering är och varför det är viktigt!
Att dela upp ett program i mindre beståndsdelar är i regel att föredra framför ett monolitiskt program. En anledning till detta är att det underlättar parallellutveckling – dvs. flera programmerare kan vara inblandade i ett projekt samtidigt och jobba på olika delar och därigenom förkorta utvecklingtiden (och öka kvaliteten).
Naturligtvis duger det inte med att göra vilken uppdelning som helst! Man bör beakta vad som är en naturlig uppdelning; ett program som modellerar ett brädspel kanske kan delas upp i en modul för spelets logik (hur pjäserna interagerar med brädet och varandra) och en modul för spelets grafik. Genom att separera logiken från grafiken underlättar man också för ett framtida utbytande av spelets grafik.
Pröva din modulariseringsstrategi genom att implementera ett program och notera vilka förändringar du måste göra när din insikt i programmet fördjupas.
Report a bug on this achievement? Please place an issue on GitHub.
12.2 K31: Coupling & cohesion G4 Lab
Givet ett icke-trivialt program uppdelat i moduler som i ovanstående mål, resonera kring begreppen coupling och cohesion för några av modulerna.
Termerna “low coupling” och “high cohesion” beskriver två egenskaper som krävs för att ett program skall anses välmodulariserat. Med low coupling avses att två moduler endast skall vara löst sammanknutna, så att det är möjligt att byta ut en av dem utan att göra några egentliga förändringar i den andra. Med high cohesion avses att alla delar som finns i en modul skall ha en “hög grad av samhörighet”, dvs. att alla delar av modulen avser samma aspekt av programmet. (Varför?)
Termerna ovan är enkla att beskriva separat från faktisk kod, men för att förstå dem måste du kunna relatera dem till din egen kod, beskriva coupling mellan moduler, cohesion inom moduler, och eventuellt göra motiverade förändringar i den tidigare designen.
Report a bug on this achievement? Please place an issue on GitHub.
12.3 K32: Separation of concerns G5 Lab
Utveckla resonemanget i K31 med en diskussion om separation of concerns och hur detta har uppnåtts (alt. kan/inte kan) i programmet i fråga.
Undersök termen/begreppet “separation of concerns” (leta bland annat men inte enbart i litteraturen om aspekt-orienterad programmering). Vad betyder detta begrepp? Relatera det till diskussionen om coupling och cohesion i föregående mål.
Report a bug on this achievement? Please place an issue on GitHub.
13 M: Pekare
13.1 M36: C:s array-notation och pekararitmetik G3 Lab
Arrayer i C är i regel inget mer än en behändig notation för pekararitmetik. Demonstrera att du förstår likheterna mellan pekare till konsekutiva minnesblock av element av en typ, och arrayer i C i ett i övrigt vettigt program.
Tips: Argumentvektorn till main
-funktionen.
Report a bug on this achievement? Please place an issue on GitHub.
13.2 M37: Använda pekare för att skapa länkade strukturer G3 Lab
En länkad struktur är en struktur uppbygd av separat-allokerade objekt som pekar till varandra, t.ex. en länkad lista eller ett träd. Länkade strukturer växer och krymper dynamiskt, dvs. deras storlek varierar med körning och under körning och kräver i regel minnesallokering på heapen.
Report a bug on this achievement? Please place an issue on GitHub.
13.3 M38: Värdeöverföring via pekare G3 Lab
Använd pekare till stackvariabler för värdeöverföring mellan funktionsanrop.
Läs C: addendum om stack & heap som finns bland extramaterialet.
Referenssemantik och värdesemantik tas upp redan i kom-igång-uppgiften.
Report a bug on this achievement? Please place an issue on GitHub.
13.4 M39: Pekare till pekare G4 Lab
Använd pekare till pekare (dubbelpekare) på ett lämpligt sätt i ett program.
En pekare till en pekare är en väldigt kraftfull mekanism som kan vara förvirrande ibland (t.ex. att man blandar ihop vad de olika pekarna pekar på).
Tips: iteratorer till datasamlingar som ger möjlighet att länka in och länka ur.
Argumentvektorn i main
-funktionen är visserligen en pekare till
en pekare, men skall inte användas för demonstration här.
Report a bug on this achievement? Please place an issue on GitHub.
14 N: Pragmatics
14.1 N40: Kompilering, länkning och interpretering G3 Lab
Demonstrera på lämpligt sätt förståelse för termerna kompilering, länkning, interpretering och JIT-kompilering och hur dessa används i C och Java.
Fundera över skillnaderna mellan länkning i C och Java och när länkning sker.
Ledning: med hjälp av enkla prestandamätningar kan man mäta tiden för JIT-kompilering och även dess inverkan på prestanda hos kod efter att den kompilerats.
Report a bug on this achievement? Please place an issue on GitHub.
14.2 TODO N41: Bindning G4 Lab
Förklara statisk och dynamisk bindning och exemplifiera med programkod.
- Hur påverkas möjligheten att återanvända kod?
- Blir det enklare/svårare att resonera om vad kod gör med statisk/dynamisk bindning?
- Finns det en prestandaaspekt? Är den relevant?
- Hur binder C?
- Hur binder Java?
Report a bug on this achievement? Please place an issue on GitHub.
15 O: Profilering och Optimering
15.1 TODO O42: Profilering och optimering 1/3 G3 Lab
Använda profileringsverktyg för att visa var ett redan skrivet program tillbringar mest tid.
Observera att dessa mål passar särskilt bra under projektet.
“Premature optimisation is the root of all evil” är ett citat från Donald Knuth. Ett delmål i denna kurs är att lära sig att använda tillämpliga verktyg för att förstå ett programs beteende under körning med avseende på prestanda, dvs. efter att programmet är implementerat ta fram det data som sedan krävs för att göra en faktisk optimering.
Lämpligen tar du fram vilka delar av programmet som tar längst tid att köra respektive körs flest gånger. Några frågor att besvara:
- Vad är lämplig granularitetsnivå på “delarna” som nämns ovan – och varför?
- Hur tar du fram detta data?
- Hur vet du att datat är “rätt”?
- Hur kan du använda datat?
Observera att det är dumt att profilera ett grafiskt program typ lagerhanteraren eftersom 99% av körtiden är väntan på I/O. Däremot kan man profilera delar av lagerhanteraren. Ta insättning i det binära sökträdet som ett exempel. Skriv ett litet program som använder samma binära sökträd och gör 1 miljon insättning av varor i databasen och sedan 1 miljon sökningar. Det är mer intressant att profilera.
15.1.1 Profilera ett C-program
Man kan använda verktyget gprof
för att mäta körtiden hos ett
C-program. Det finns flera tutorials på näten, t.ex. denna:
http://www.thegeekstuff.com/2012/08/gprof-tutorial/.
15.1.2 Profilera ett Java-program
15.2 O43: Profilering och optimering 2/3 G4 Lab
Med ledning resultatet från föregående mål, optimera programmet på ett förtjänstfullt sätt.
Observera att dessa mål passar särskilt bra under projektet.
Optimera programmet med hjälp av profilen ovan, motivera ansatsen och demonstrera och förklara prestanda-ökningen med hjälp av en ny profil för det optimerade programmet
I nödfall kan man bli godkänd på detta mål trots att man inte kan jaga fram en prestandaökning om den optimering man gjort (som visat sig vara en “falsk optimering”) intuitivt verkar vara en optimering.
Observera att det är dumt att optimera ett grafiskt program typ lagerhanteraren. Däremot kan man optimera delar av lagerhanteraren. Ta binärträdsbalanseringen som ett exempel. Den går kanske att göra bättre utan att först skriva ned hela trädet i en array?
Sedan får man demonstrera uppdateringen kanske genom att göra 1 miljon insättning av varor i databasen och göra 1 miljon sökningar med de olika sorteringsimplementationerna och jämföra.
Report a bug on this achievement? Please place an issue on GitHub.
15.3 O44: Profilering och optimering 3/3 G5 Lab
Samma som mål de två ovanstående målen, men beakta också minnesanvändning.
Observera att dessa mål passar särskilt bra under projektet.
Beakta inte enbart exekveringstid och frekvens, men minnesåtgången för strukturer och funktioner/metoder och – möjligen ännu viktiga – hur åtkomst till minnet sker. Kanske finns det någon samband mellan lång exekveringstid och suboptimalt minnesanvändande?
Kan man minska exekveringstiden genom att ändra hur minnet används?
Report a bug on this achievement? Please place an issue on GitHub.
16 P: Kodgranskning
16.1 TODO P45: Gör en informell kodgranskning under fas 1 G3 Lab
Gör en informell kodgranskning på ett program utvecklat av ett annat kodpar i samma grupp (det får inte finnas några överlappningar i medlemmar mellan granskande par och par som blir granskat). Syftet med en kodgranskning är att hitta defekter och förbättra kodens kvalitet. Följ ett kodgranskningsprotokoll och ta anteckningar.
Ge synpunkter på koden genom GitHubs issue tracker som finns för varje repo, eller genom att kommentera enskilda rader. Se till att använda en särskild version av programmet så att ni kan hitta tillbaka till just den vid redovisning, och för att undvika att programmet ändras samtidigt som ni gör granskningen.
Ute i arbetslivet gör man detta av flera anledningar:
- Kvalitetssäkring
- Utvecklare blir modigare när man delar ansvar för korrekthet
- När man vet att någon måste läsa koden skriver man ofta bättre kod
- Man sprider kunskap om vad som händer i projektet till fler
Det är en viktig färdighet att kunna kritisera någons kod utan att kritisera personen (och likaså att ta kritik!). Vidare blir man också ansvarig för koden som man OK:ar vilket gör att man måste vara noggrann och inte luras att tro att målet är att säga “vilken bra kod” till de man granskar.
16.1.1 Redovisning
Du redovisar detta under en labb genom att visa upp ditt kodgranskningsprotokoll och issue log. Ha koden tillgänglig för frågor från examinatorn. Minns att det är du som skall driva redovisningarna, inte examinatorn.
Report a bug on this achievement? Please place an issue on GitHub.
16.2 P46: Gör en informell kodgranskning under fas 2 G3 Lab
Gör en informell kodgranskning på ett program utvecklat av ett annat kodpar i samma grupp (det får inte finnas några överlappningar i medlemmar mellan granskande par och par som blir granskat). Syftet med en kodgranskning är att hitta defekter och förbättra kodens kvalitet. Följ ett kodgranskningsprotokoll och ta anteckningar.
Ge synpunkter på koden genom GitHubs issue tracker som finns för varje repo, eller genom att kommentera enskilda rader. Se till att använda en särskild version av programmet så att ni kan hitta tillbaka till just den vid redovisning, och för att undvika att programmet ändras samtidigt som ni gör granskningen.
Ute i arbetslivet gör man detta av flera anledningar:
- Kvalitetssäkring
- Utvecklare blir modigare när man delar ansvar för korrekthet
- När man vet att någon måste läsa koden skriver man ofta bättre kod
- Man sprider kunskap om vad som händer i projektet till fler
Det är en viktig färdighet att kunna kritisera någons kod utan att kritisera personen (och likaså att ta kritik!). Vidare blir man också ansvarig för koden som man OK:ar vilket gör att man måste vara noggrann och inte luras att tro att målet är att säga “vilken bra kod” till de man granskar.
16.2.1 Redovisning
Du redovisar detta under en labb genom att visa upp ditt kodgranskningsprotokoll och issue log. Ha koden tillgänglig för frågor från examinatorn. Minns att det är du som skall driva redovisningarna, inte examinatorn.
Report a bug on this achievement? Please place an issue on GitHub.
16.3 P47: Åtgärda defekter efter en kodgranskning G4 Lab
In addition to the previous goal, make a pull request with changes and cooperate with the owners of the receiving code base until the pull request has been successfully merged. Note that it is the code of the other team that should be improved.
If the code you were reviewing in the previous goal was next to perfect, maybe the improvements here will be restricted to catching spelling errors in comments. In most cases, however, there are some real issues. For example:
- Repeated logic that can be broken out and moved to functions of their own
- Functions that should be private aren’t private
- Behaviour that does not correspond to its description in comments
- Code that could segfault under certain circumstances
- Tests miss important corner cases (compare with your own!)
- Code that miscalculates or otherwise misbehaves under certain circumstances
How much work to do is an interesting question. Sadly, the answer isn’t so easy to give. The goal of this exercise is to practise proposing fixes to errors and communicating them through the proper channels which in this case is GitHub.
If you feel that you need support in knowing when enough is enough, then here are guidelines:
For each thing that you find, rate its severity on a scale \(1--3\). There is no objective scale, so here are some examples.
Severity | Example |
---|---|
1 | Improving description in a comment |
1 | Fixing spelling errors in a comment |
1 | Improving names of variables in a function (or name of a function) |
2 | Finding a DRY violation and solving it (e.g., through extracting functions) |
2 | Hardening correct code by e.g., adding initialisation, braces, etc. in a function |
2 | Moving a structs, adding static annotations in a file, etc. |
3 | Improving tests by additional cases for an important test |
3 | Finding and fixing bugs in a function |
Ideally, the sum of the severity of your fixes should total at least 10. State the severity for each issue you file and prepare to motivate it to a TA if questioned.
Report a bug on this achievement? Please place an issue on GitHub.
16.4 P48: Stäm av ett program mot en refactoringkatalog G5 Lab
Enkla refactoringmönster avser t.ex. namnändringar, och att flytta tillstånd och/eller beteenden från en plats till en annan. Både Netbeans och Eclipse har inbyggt stöd för refactoring. En bra utgångpunkt för att lära sig om refactoring är http://refactoring.com.
Finns det några “bad smells” i det program som ni just har granskat? Vilka då? Vad är lämpliga ändringar? Föreslå dem via GitHubs issue tracker på samma sätt som tidigare. Nämn gärna det refactoringmönster som ändringarna brukar!
Notera: Ni behöver självklart inte stämma av programmet mot hela katalogen.
Report a bug on this achievement? Please place an issue on GitHub.
17 Q: Testning
17.1 Q49: Enhetstestning G3 Lab
Ta fram lämpliga enhetstester, motivera dem, och förklara vad testerna visar.
Det står dig fritt fram att använda Cunit, JUnit, eller motsvarande. Detta kan redovisas både under projektet eller tidigare. Ett tips är att börja skriva tester från sprint 2 eftersom tester tenderar att förkorta utvecklingstiden så fort man blivit varm i kläderna med språket man programmerar i.
Enhetstester fokuserar på enskilda funktioner och metoder. Ett bra enhetstest kan köras helt automatiserat, är läsbart och prövar endast en enda logisk funktion/koncept. Enhetstester har flera funktioner, bl.a. gränssnittsdokumentation genom exempel, stöd vid debuggning av kod genom dokumentation av felaktiga indata, och i testdriven utveckling (TDD) skrivs testerna före koden de skall testa för att bena ut specifikationer och sätta fingret på oklarheter.
Report a bug on this achievement? Please place an issue on GitHub.
17.2 Q50: Mät och resonera kring testkvalitet G4 Lab
Hur vet man att de test man har är “bra”? Hur vet man vad testen egentligen testar? Använd ett lämpligt verktyg för att t.ex. mäta code coverage, d.v.s. hur stor del av koden som faktiskt testas av testen. Vilka andra kvalitetsmått på tester finns? Måste man testa sina tester? Måste man testa testernas tester? Blir inte detta en oändlig regression?
Använd t.ex. Gcov för att mäta code coverage för era tester.
Report a bug on this achievement? Please place an issue on GitHub.
17.3 TODO Q51: Andra verktyg för felsökning G5 Report
Använd Findbugs på ett eller flera av de Javaprogram som du har utvecklat under kursen och studera resultatet. Hittar du buggar i programmet? Får du s.k. “false positives”, alltså rapporter om fel som inte är fel i praktiken?
Använd också American Fuzzy Lop, en fuzzer, t.ex. på din lagerhanterare, för att hitta gränsfall som du inte har tänkt på.
Redovisa genom att diskutera ditt resultat med Tobias, Elias
eller Stephan.
Report a bug on this achievement? Please place an issue on GitHub.
18 TODO R–V: Verktyg
18.1 R52: Debuggning med GDB G3 Lab
Avser att kunna använda GDB (eller lldb) för att stega genom ett C-programs exekvering och sätta breakpoints (ex. b, c, s, n), skriva ut variablers värden, en backtrace, navigera en backtrace med up/down. Redovisa genom att återskapa ett förlopp från en skarp buggjakt med de relevanta stegen och förklara buggen.
Du kan lämpligen redovisa detta i samband med att du får ett svårfunnet segfault!
Report a bug on this achievement? Please place an issue on GitHub.
18.2 S53: Extrahera dokumentation ur kod G3 Lab
Använda doxygen eller JavaDoc för att extrahera kommentarer från kod till lämplig API-dokumentation.
Endast lämpligt att demonstrera i ett större program med flera moduler där gränssnitten behövts dokumenteras. När du demonstrerar, visa också att du kan lägga till, ändra etc. i informationen och generera ny dokumentation, samt visa på både välmotiverat kortfattade och utförliga hjälpavsnitt i dokumentationen.
Du kan bara redovisa detta mål på kod från sista C-uppgiften, sista Java-uppgiften eller projektet.
Report a bug on this achievement? Please place an issue on GitHub.
18.3 T55: Använda Emacs för editering G3 Lab
Avser förmåg att använda Emacs utan mus för att navigera och editera text, öppna filer, bläddra mellan och hantera buffrar, använda kill & yank och mark-stacken.
Du är klar att redovisa detta mål när du känner att du löser problem tack vare Emacs och inte trots Emacs.
Installera Emacs på din dator hemma om du inte redan har Emacs där tills ditt muskelminne har memorerat alla viktiga kommandon.
18.3.1 Varför har vi detta mål?
Av flera goda skäl, men inte som ett statement eller som en rekommendation för resten av ditt liv.
18.3.2 Jag dör om jag inte får använda vim!
Då är det ok. Men vim alltså. Emacs eller vim effektivt sett.
Report a bug on this achievement? Please place an issue on GitHub.
18.4 T56: Konfigurera Emacs för programmering G4 Lab
Utöver föregående mål, dra nytta av Emacs inbyggda stöd för programmering.
Avser stöd för kompilering och felsökning, textkomplettering el. snippets, samt användande av tags eller motsvarande för att navigera kod.
Några startpunkter att titta på:
- C/C++ Development Environment for Emacs
- https://tuhdo.github.io/c-ide.html
- Emacs: What’s the Best Setup for Coding
- http://ergoemacs.org/emacs/emacs_whats_best_setup_for_xyz.html
Report a bug on this achievement? Please place an issue on GitHub.
18.5 U57: Byggverktyget Make G3 Lab
Många program har komplicerade byggberoenden – för att kunna
bygga prg
måste vi länka a
och b
, och för att kunna länka
dem måste vi bygga dem. För att bygga a
kanske vi måste länka
c
och d
etc.
Programmet make
är ett utmärkt verktyg för att hantera
byggberoenden. Titta i Shaws bok för en minimal intro till
make
. Det finns också en svensk lathund om make i
kursmaterialet. Make gås också igenom på föreläsning.
Du bör använda make
från dag ett på kursen! Det är nämligen en
vanlig källa till fel att man kompilerar ett program utan att
kompilera om alla dess delar, etc.
Du bör inte redovisa detta mål förrän tidigast i sprint 2 – eller varför inte under projektet?
För att redovisa målet måste du bland annat redovisa just beroenden, eftersom det är det som make löser. Det betyder att ha byggregler som beror av varandra. T.ex. om \(A\) är beroende av \(B\), vi ändrar \(A\) men inte \(B\) så skall bara \(A\) kompileras om, inte \(B\).
Report a bug on this achievement? Please place an issue on GitHub.
18.6 V58: Grundläggande terminalkommandon G3 Lab
Att kunna navigera i terminalen är grundläggande som utvecklare. Det är standard att behöva logga in på maskiner på andra sidan jorden och kolla i loggar, starta om tjänster, etc. Drift och utveckling hänger samman, och det är sällan man har fönstersystem att tillgå (och ändå mer sällan som det vore vettigt att använda dem).
_Detta mål kan du inte redovisa vid kursens början. Observera att detta mål skiljer sig genom att det innehåller en uppgift som du skall använda för att redovisa._
18.6.1 Du bör kunna använda följande:
man
,apropos
,whatis
cd
ls
mkdir
,rmdir
grep
find
xargs
&&
&
- C-z, C-c och C-d (ung. suspend, abort och quit)
fg
bg
cut
tr
uniq
cp
- omdirigering, pipes och miljövariabler.
18.6.2 Titta också gärna på verktyg som
ack
tmux
awk
sed
zsh
ps
top
,htop
curl
ssh
,scp
- shell scripting
TIPS! Om du väntar till projektet med att redovisa detta mål kommer det gå per automatik. Givet förstås att du inte har undvikit terminalen fram till dess…
Filen http://wrigstad.com/ioopm/v58.zip innehåller ett antal
kataloger och filer i samma format som jag får era kodprov.
Lösningar som funkar med nedanstående exempel kommer nog att funka
mot innehållet i v58.zip
.
v58.zip
ser ut ungefär så här:
(genererad med hjälp av kommandot tree)
. ├── elica842 │ ├── uppgift1 │ │ └── passed.txt │ └── uppgift2 │ └── missing.txt └── writo649 ├── uppgift1 │ └── passed.txt └── uppgift2 └── fail.txt
I denna struktur finns det en katalog som motsvarar en person,
t.ex. writo649
, och under denna en katalog för varje uppgift som
innehåller de inlämnade filerna, samt resultatet av rättningen.
Utifrån exemplet ovan kan vi se att writo649
klarade av uppgift 1
men inte uppgift 2; elica842
klarade av uppgift 1 och för uppgift
2 finns inga uppgifter: den har inte lämnats in (missing.txt).
(Det kan finnas andra filer med vilka andra namn som helst, de är
utelämnade i exemplet ovan.)
Uppgiften består i att ta fram:
- En fil
a.txt
som innehåller alla godkända på uppgift 1 - En fil
b.txt
som innehåller alla godkända på uppgift 2 - En fil
c.txt
som innehåller namn och epostadress för alla ia.txt
ochb.txt
Varje uppgift bör lösas med ett kommando i terminalen. Notera att
uppgift 3 kan bygga på att filerna a.txt
och b.txt
redan finns.
Facit från exemplet ovan:
a.txt elica842 writo649 b.txt <tom fil> d.txt Elias Castegren elias.castegren@it.uu.se Tobias Wrigstad tobias.wrigstad@it.uu.se
(det är inte petnoga med tabbar, etc.)
För att konvertera t.ex. writo649
till ett namn och en
epostadress kan du använda kommandot “student” som finns på våra
Linux-system: /it/sw/misc/bin/student
.
Lämpliga kommandon för denna uppgift är:
find
xargs
grep
uniq
cut
ellerawk
cat
|
>
<
man
för att läsa på om ovanstående
Använd gärna tree
för att se trädstrukturen.
18.6.3 Ledning
Varje kommando spottar ut radorienterad text. Arbetsflöden skapas
genom att kommandon “pipe:as ihop”, kommand1 | kommando2 där all
output från kommando1 blir input till kommando2. Diverse
hjälpprogram används för att “massera texten” t.ex. om kommando1
listar A,B,C,D,E och vi vill ha C kan vi använda t.ex. cut -d , -f 3
för att säga “tolka detta som fält separerade av , och ta fält 3”.
Ett år stötte jag (Tobias) på en student på kursen som hade blandat ihop ^C och ^Z och som därför hade 50+ instanser av lagerhanteraren igång eftersom han, varje gång han trodde att han slog ihjäl programmet med ^Z, bara hade pausat det.
Det löste vi geschwint så här:
ps aux | grep ~whoami~ | grep ./lagret | cut -b 10-14 | xargs kill (1) (2) (3) (4) (5)
Steg (1) tar fram en lista över processer:
root 27002 0.0 0.0 175880 15736 ? Ss dec05 0:00 ... foobar 27005 0.0 0.1 199584 18480 ? S dec05 0:00 ... foobar 27007 0.0 0.1 309656 32528 ? S dec05 0:01 ./lagret root 27110 0.0 0.0 4496 780 ? S 09:45 0:00 ... foobar 27111 0.3 0.0 92592 10912 ? S 09:45 1:41 ...
… som skickas till steg (2) som filtrerar (grep:ar) fram alla
rader som matchar resultatet av whoami
(foobar ovan). Resultatet:
foobar 27005 0.0 0.1 199584 18480 ? S dec05 0:00 ... foobar 27007 0.0 0.1 309656 32528 ? S dec05 0:01 ./lagret foobar 27111 0.3 0.0 92592 10912 ? S 09:45 1:41 ...
… som skickas till steg (3) som filtrerar ytterligare:
foobar 27007 0.0 0.1 309656 32528 ? S dec05 0:01 ./lagret
… som skickas till steg (4) som tar fram numret på processerna:
27007
… som skickas till steg (5) som för vart och ett av numren som
trillar in (i detta fall endast ett) kör “kill <numret>”. Alltså,
kommandot ps aux | grep whoami
| grep ./lagret | cut -b 10-14 |
xargs kill utför slutligen
kill 27007
… vilket i det skarpa läget förra året blev över 50 anrop till kill, och alla lagerprogram stoppades.
Pröva gärna själv, men ersätt kill
med echo
för att inte slå
ihjäl något program!
18.6.4 Om programmet student inte finns/inte fungerar
Skapa en fil student.sh
med följande innehåll:
#!/bin/sh finger $1 | head -n 1 | awk -F: '{ print $3 }' | cut -c 2-
Gör den exekverbar:
chmod a+x student.sh
Gör klart uppgiften men använd student.sh
istället för student
Report a bug on this achievement? Please place an issue on GitHub.
19 TODO X: Kommunikation
19.1 X59: Essä G4 Special
Redovisa ett mål på nivå 4 eller 5 skriftligt genom en essä.
Skriftlig framställning är en viktig del av samtliga kurser på universitetet. Det är oerhört viktigt och användbart att kunna lägga upp en text eller ett resonemang, och veta hur man skall rikta sig till en specifik målgrupp.
Inte alla mål på nivå 4/5 är kanske lämpliga att redovisa via en essä (t.ex. inte labbhandledningen). Om du är osäker, hör med Elias eller Tobias först. Det är tillåtet att redovisa fler en ett mål (max 3) om de kan redovisas med en sammanhängande historia. Se till att få detta godkänt i förväg! Uppsatsen blir förstås längre i detta fall och maxlängdkravet nedan gäller ej.
Betrakta formkrav och språkliga krav som lika viktiga som ämneskraven. Du får skriva på svenska eller engelska. De språkliga kraven är lika höga oavsett språk.
Här är några tips:
- För mycket text på en sida utan rubriker blir ogenomträngligt och osexigt
- Tänk alltid igenom vad ditt syfte är och vad du vill förmedla till läsaren (vad skall läsaren ta med sig)
- Fråga för varje “kapitel” eller stycke vad de har för relation till det ovan nämnda budskapet – om det är oklart kan man fråga sig om det är motiverat att ha kvar
- En text skrivs eller läses sällan linjärt
- 66-72 tecken per rad är en optimal radlängd för ögat att följa
- Hur du formger din text är också en del av budskapet och hjälper till att driva hem poängerna
- Slarvfel och stavfel får dig tråkigt nog att framstå som oseriös och dum
- Använd verktyg (t.ex. M-x
flyspell
i Emacs) men förstå deras begränsningar - Använd textverktyg som gör det enkelt att göra förändringar i layout utan för mycket handpåläggning
- “Bara för att du har skrivit det är det inte en bra idé att ha det kvar i texten”
- När man granskar en text skall man läsa den både “nära” (hur skall den här meningen vara) och “på avstånd” (kanske poängen blir tydligare om man ändrar ordningen på kapitel 1 och 2)
- Be alltid någon annan läsa igenom texten och förklara för dig vad det faktiskt står i den
- Uppsala Universitet ger dig som student tillgång till professionell skrivhjälp, även för en uppgift som denna
- Du skall berätta en story och storyn hjälper läsaren att förstå och knyta samman allt.
- Bara för att du gjorde \(X\) före \(Y\) behöver de inte komma i den ordningen i texten, även om det antyder att du gjorde dem i omvänd ordning
Fundera över vad för slags ton man bör hålla i en essä, hur man klara av att vara saklig utan att bli tråkig, och fundera över vilken din stil är.
Det stilistiska är alltid viktigt, oavsett om man skriver ett sms eller en avhandling. Nedanstående briljanta citat kan förhoppningsvis både skänka glädje och inspirera:
This sentence has five words. Here are five more words. Five-word sentences are fine. But several together become monotonous. Listen to what is happening. The writing is getting boring. The sound of it drones. It's like a stuck record. The ear demands some variety. Now listen. I vary the sentence length, and I create music. Music. The writing sings. It has a pleasant rhythm, a lilt, a harmony. I use short sentences. And I use sentences of medium length. And sometimes, when I am certain the reader is rested, I will engage him with a sentence of considerable length, a sentence that burns with energy and builds with all the impetus of a crescendo, the roll of the drums, the crash of the cymbals-sounds that say listen to this, it is important. -- Gary Provost
En begränsning är att essän skall vara på ca 7500 tecken. Längre är inte bättre, men det man skriver måste vara av en viss volym för att tillräckligt intressanta frågeställningar om skriftlig framställning skall uppkomma.
19.1.1 Inlämning
Du lämnar in genom att skicka en genererad PDF från LaTeX-källkod till Tobias, samt en länk till en katalog i ditt repo där källan finns. Kommentarer kommer antingen direkt i PDF:en eller som issues i GitHub, beroende på omständigheterna.
19.1.2 Examination
Examinationen av essän sker i form av små seminariegrupper där alla läser och kommenterar på varandras essäer. Mer information om detta anslås senare under kursen.
Report a bug on this achievement? Please place an issue on GitHub.
19.2 TODO X60: Välstrukturerad presentation 1/2 G3 Special
Under 2018 examineras detta som en del av projektets slutpresentation. Varje person blir alltså individuellt godkänd eller ej på seminariets presentation i och med detta mål. Om man schabblar bort presentationen, eller inte är närvarande får man ett extra redovisningstillfälle, efter att kursen är klar, förmodligen 1-2 månader senare.
Muntlig framställning är lika viktig som skriftlig. En presentation kan lätt bli tråkig om den som talar är oengagerad, och en talares nervositet smittar av sig på åhörarna som då tänker på allt annat än budskapet. Att läsa innantill från ett papper är döden, även om den text man skrivit är fantastisk. Man måste göra den levande!
En talare som glider in i oväntade kläder eller har ett “tick” drar lätt uppmärksamheten till detta istället för till sitt budskap. Det kan vara en bra idé att undvika läderbyxorna (för någon definition av läderbyxor) och om det inte går, själv berätta varför man måste ha dem på sig just idag, så åhöraren får det ur sitt system.
En presentation har på samma sätt som en skriven text ett budskap och man måste vara noga med hur man lägger upp presentationen för att vara säker på att åhöraren kan följa med. Det blir ännu viktigare att berätta vad man skall säga, och sammanfatta hela tiden vad man har sagt.
Bilder är bra, speciellt om man tänker sig att de skall användas som studiematerial senare, men de kan lätt göra presentationen stelbent och inflexibel.
Som ämne skall du välja något som du själv är passionerad kring. (Vi har sett allt från Counter Strike-taktiker till hur man gör för att få gratis öl på nationerna.) Presentationen skall ta 7 minuter och vi räknar med ca 3 minuters muntlig feedback.
Fundera över vad för slags presentation du skall ge. Kolla t.ex. här för inspiration och vägledning.
Fundera över vad du tycker är svårt med en presentation och fokusera på det. Tycker du att det är svårt att berätta en sammanhängande historia – jobba med det. Är det svåra att stå inför folk – jobba med det.
Några tips:
- Ha inte för mycket text på varje bild
- Bilder kan vara bärare av mycket information, men kräver stor eftertanke vid skapandet
- Använd animationer etc. sparsamt
- Undvik att backa eller på annat sätt hoppa fram och tillbaka i presentationen
- Det är viktigt att vara engagerad – om du skall prata om något måste du övertyga dig själv om att det är spännande, för varför skulle man annars lyssna på dig?
- Be inte om ursäkt
- Lyssna på dig själv – säger du “ehm…” mellan varje mening eller “alltså” i början av varje mening? Går det att arbeta bort?
Du kommer att presentera både inför andra studenter och lärare. Anmälan till presentationstillfällen kommer ut i Piazza. Dessa tillfällen kommer att vara parallella med uppföljningsmöten eller lektioner.
Report a bug on this achievement? Please place an issue on GitHub.
19.3 TODO X61: Välstrukturerad presentation 2/2 G4 Special
Under 2018 examineras ej detta mål, dvs. X61 krävs inte för betygen 4 eller 5 på kursen.
Håll en välstrukturerad presentation om ett mål på kursen.
Se föregående presentationsmål för ytterligare instruktioner.
Du skall ha ett tydligt mål med din presentation: du vill lära ut X, etc. Något som åhörarna i efterhand kan ta ställning till om du har lyckats med eller inte och kan använda som utgångspunkt för återkopplingen på din presentation.
Som ämne skall du välja något mål på kursen. En lämplig längd på presentationen är 15 minuter.
Fundera över vad för slags presentation du skall ge. Kolla t.ex. här för inspiration och vägledning.
Fundera över vad du tycker är svårt med en presentation och fokusera på det. Tycker du att det är svårt att berätta en sammanhängande historia – jobba med det. Är det svåra att stå inför folk – jobba med det.
På första bilden av din presentation, ange:
- Målet med din presentation
- Vad du aktivt försöker träna på (t.ex. inte vara nervös)
Om du inte använder bilder kan du bara berätta det.
Här bedömer vi två saker:
- Din förmåga att presentera (bl.a. uppfylla det mål som du själv satt)
- Innehållet för det mål som du presenterar
Du kan bli godkänd på båda mål individuellt, alltså presentationen i sig och målet som var ämnet för presentationen. Det betyder att om du gör ett bra jobb har du möjlighet att bocka av två mål här.
Presentationerna kommer att gå till på samma sätt som i föregående mål, dvs. du presenterar både inför andra studenter och lärare. För att anmäla dig för en presentation, skicka ett mail till Gustaf. Tider för presentationer hanteras på mail i takt med att anmälningar kommer in.
Report a bug on this achievement? Please place an issue on GitHub.
19.4 X62: Kommunikation 1:1 G5 Special
Visa förmåga att förmedla kunskap genom att handleda ett pass.
Att hålla en presentation utan förberedelser är vanligt – jämför t.ex. med “elevator pitch” eller när någon frågar om något som man känner till. Vid labbhandledning är det vanligt att man måste berätta om olika koncept etc.
Även om man inte kan en viss aspekt av kursen bör man kunna hjälpa någon med en diskussion, både lyssna och tala.
Redovisning sker med hjälp av ordinarie labassar som bitvis följer med dig och lyssnar på dina förklaringar etc. till andra. Obeservera att du inte får ta redovisningar.
Ett bra sätt att förbereda sig är att sätta sig in i labassens roll genom att titta på hur (särskilt de seniora) labassarna gör.
Om du vill redovisa detta mål, maila till Gustaf.
Det blir lätt fullt i slutet av kursen, så hör av dig i tid!
Report a bug on this achievement? Please place an issue on GitHub.
19.5 TODO X63: Kommuniktion 1:M G3 Special
Samtala avslappnat med andra gruppmedlemmar. Ditt ansvar för gruppen. Gruppens ansvar för dig.
Detta mål omfattar sex fysiska möten under kursens gång. Varje möte skall dokumenteras med en gemensam rapport. Se detaljerade instruktioner här.
Report a bug on this achievement? Please place an issue on GitHub.
20 TODO Y: Mjukvaruutveckling / Programvaruteknik
20.1 Y64: Använd en namngiven utvecklingsprocess och reflektera över utkomsten G3 Report
Redovisning sker genom en gemensam (för alla medlemmar i projektet) skriftlig beskrivning av den valda processen (på hög nivå) samt en reflektion över dess styrkor och svagheter i projektrapporten. Om ni skulle starta om projektet imorgon – vad skulle ni behålla och vad skulle ni göra annorlunda (och hur)?
Visa också upp projektets burndown chart för samtliga sprintar.
Några frågor att starta med:
- Vilken process valdes? Varför?
- Hur följdes processen?
- Hur fungerade processen?
- Var antalet sprintar lämpligt?
- Var längden på sprintarna bra?
- Var planeringen optimistisk/pessimistisk/bra?
- Låg planeringen på en lagom detaljnivå?
- Kunde man se tendenser till att över- eller underskatta vissa tasks?
- Tidsfördelning?
Report a bug on this achievement? Please place an issue on GitHub.
20.2 Y65: Skriv konsekvent bra kod G3 Report
Under kursens gång har kodkvalitet beaktats åtskilliga gånger. Under projektet skall ni skriva kod av hög kvalitet! Vad betyder det? (Läsbarhet? Underhållsbarhet? Prestanda? Korrekthet? Testbarhet? Etc…) Hur har det tagit sig uttryck i ert system? Vad har det fått för konsekvenser?
Hur har ni sett till att koden är läsbar för alla i teamet? (Notera att läsbarhet är mycket mer än bara formattering och var måsvingarna sitter…)
Använd gärna ett verktyg (t.ex. astyle för att automatiskt formattera kod på ett enhetligt sätt.
20.2.1 Ni får använda någon av följande kodstandarder
Det går bra att välja en annan om man har en bra och utförlig motivation och får OK i förväg.
För en längre text om läsbarhet, se The Art of Readable Code.
Observera att högkvalitativ kod inte är detsamma som att följa en kodstandard.
Report a bug on this achievement? Please place an issue on GitHub.
20.3 Y66: Tillämpa kodgranskning löpande G3 Report
Tidigare under kursen har ni tillämpad kodgranskning på helt nya program som inte skrivit. Under projektet får ni äntligen tillfälle att tillämpa kodgranskning på ett liknande sätt som används ute i verkligheten: istället för helt ny kod får ni ofta titta på kod som fixar något i existerande kod, eller bygger vidare på existerande kod som ni känner till.
I projektet arbetar ni med branches eller forks från master. Ni kan ha branches i ert delade repo, eller personliga (privata) forks i era egna privata repon. Innan något commitas till master skall ni granska koden – alltså någon som inte skrev koden skall läsa igenom den och trycka på mergeknappen.
Ute i arbetslivet gör man detta av flera anledningar:
- Kvalitetssäkring
- Utvecklare blir modigare när man delar ansvar för korrekthet
- När man vet att någon måste läsa koden skriver man ofta bättre kod
- Man sprider kunskap om vad som händer i projektet till fler
Redovisa i projektrapporten hur denna typ av kodgranskining har fungerat och relatera till den typ som gjordes under tidigare faser, som var mindre disciplinerad och inte rörde er egen kod.
Om ni skulle starta om projektet imorgon – vad skulle ni behålla och vad skulle ni göra annorlunda (och hur)?
Det är frivilligt att använda kodgranskningsprotokoll här.
Report a bug on this achievement? Please place an issue on GitHub.
20.4 Y67: Delta aktivt i ett programmeringsprojekt G3 Report
Delta aktivt och reflektera över ditt deltagande. Fokusera på projektet, inte på produkten (även om produkten kan helt negligeras).
Redovisning sker genom en skriftlig personlig (enskild) reflektion som inkluderas i projektrapporten.
Fundera bl.a. på:
- How do I function in a team? Where are my strengths and weaknesses?
- How should I try to adapt the way I work to work better in a team?
- What motivates me? What demotivates me? How do I stay motivated in a project?
- How good am I at estimating how long a task will take? What is the process that produce my estimations?
- What role do I want to play in a team?
- Hur fungerar du i ett team? Faller du in i ett särskilt mönster, eller tar du återkommande en särskild roll?
- Får du ut något av att jobba i en grupp, eller jobbar du helst ensam?
- Jämför hur mycket du lärt dig under projektarbetet kontra kursens övriga delar, och fundera över hur du bäst lär dig saker.
- Hur har det gått att logga arbetstid?
- “Biggest fail” och “biggest win”, dvs. det största problem som du stötte på och det smartaste eller bästa du gjorde.
Report a bug on this achievement? Please place an issue on GitHub.
20.5 TODO Y68: Redovisa en fungerande projektuppgift G3 Report
Se övriga Y-mål som alla hör till projektet!
Utöver att vara ett seriöst försök att implementera specifikationen fullständigt, modulo “frivilliga utökningar” skall ert program:
- fungera på avsedda plattformar
- inte göra odokumenterade eller omotiverade avsteg från specifikationen
- vara fritt från minnesläckage (verifieras t.ex. med valgrind)
- inte krascha vid körning med valid indata
- skydda sig från felaktig indata på lämpligt sätt och i lämplig utsträckning
- inte behöva kompileras om när indata ändras
- ha ett lämpligt förhållningssätt till NIH och DRY
Ytterligare icke-funktionella krav är att:
- kodens indentering lyfter fram kontrollflödet
- ingen “machokodning” (t.ex. omotiverade oneliners)
- återkommande logik är utbruten och inkapslad i funktioner
- namn på filer, variabler, funktioner, etc. skall hjälpa läsaren att förstå deras innebörd, och beteende (t.ex. vilka värden som är rimliga, eller vad man kan förvänta sig från ett funktionsanrop)
- har tydligt dokumenterade gränssnitt som går att förstå utan att läsa koden och helst är formaterade med Doxygen eller JavaDoc
- programmet går att bygga och testa med en makefil
- programmet har enhetstester för alla viktiga funktioner
- som inte bara skrevs efter att programmet var klart “för att ha tester”
- som använder cunit
- där varje test prövar en sak, och flera tester görs ej i samma testfunktion
- konsekvent tillämpa en kodstandard
- ha en vettig git log
- överensstämma med aktiviteter på Trello
Lämna in detta program genom att skriva i readme.md
-filen i
roten på gruppens GitHub-repo vilken commit som var
inlämningen, alltså:
20.5.1 TODO Tagga projektuppgiften med …
20.6 Y69: Tillämpa regressionstestning under projektet G3 Report
Regressionstester är till för att fånga buggar och fel som uppstått i system efter förändringar. Det är inte helt ovanligt att gamla buggar återuppstår (kanske i ny skepnad) i och med att nya vägar skapats genom programmet. Om man har 100 tester och skall göra en förändring i ett program, börjar vi med att skapa en baseline genom att köra de 100 testerna och ser hur många/vilka som passerar. Efter förändringen gör vi samma och jämför.
Ta fram en uppsättning regressionstester för en del av ett
program, motivera dem, och förklara vad testerna visar. (Ett test
är inte ett test om det inte är automatiserat, minst make test
.)
En uppsättning regressionstester är ingenting man tar fram på en eftermiddag, utan de växer fram gradvis över tid. Vi kan t.ex. tänka oss att alla tester i den första sprinten under projektet är regressionstester. Att hantera och administrera regressionstester handlar inte bara om att ta fram nya tester vid behov (vilka?) utan också om ta bort tester (varför och när – kanske aldrig kommer upp under projektet).
Regressionstestning är viktigt för underhåll av kod eller vidareutveckling av en stor kodbas där effekterna av en förändring är svåra och kostsamma att spåra “manuellt”. Om man har en uppsättning regressionstester kan man köra dessa mellan förändringar för att se om förändringarna fått tester att misslyckas (alternativt börja fungera).
Regressionstester kan ha många olika format, bl.a. existerande enhetstest eller integrationstest, såväl som testfall skapade i samband med buggrapporter och buggfixar. I stora system kan regressionstesterna lätt bli svårhanterligt många.
Integrationstestning är konsten att ta olika moduler och visa att de fungerar tillsammans. Integrationstestning är separat från enhetstestning som försöker visa funktioner i enskilda moduler, och kan också vara betydligt mer komplicerat än enhetstestning eftersom det kan vara svårt att koppla samman moduler eller påvisa i vilken modul ett fel uppstår.
Report a bug on this achievement? Please place an issue on GitHub.
21 TODO Z: Inlämningsuppgifter (Inluppar)
21.1 DONE Z100: Inlupp 1 G3 Lab
21.1.1 Redovisa förståelse för grundläggande imperativ programmering i C
Detta mål är knutet till den första inlämningsuppgiften. Tekniskt sett är detta inte ett mål på samma sätt som de vanliga målen, men vi undviker ytterligare ett system för bokhållning om vi gör detta till ett mål.
För att vara färdig med inlämningsuppgiften skall du ha utfört alla steg i uppgiftsbeskrivningen förutom de som uttryckligen är frivilliga.
Programmet skall:
- Använda för uppgiften lämpliga abstraktioner
- “Skydda sig” från fel (du skall kunna förklara hur fel hanteras, och motivera valet av mekanism/strategi)
- Dokumentera alla publika gränssnittsfunktioner så att en annan programmerare skulle kunna använda implementationen
- Använda korrekt namngivning (t.ex.
ioopm_
) - Vara indenterat på ett sådant sätt att kontrollflödet är synligt
- Ha relevanta enhetstester som kan köras automatiskt
- Kunna byggas med make eller liknande verktyg
- Inte ha minnesläckage eller använda oinitierat minne
- Inte krascha vid körning med valid indata
- Inga ha några globala variabler
- Inga magiska nummer (t.ex. 128 står överallt i koden)
- Ingen “machokodning” (t.ex. omotiverade oneliners)
- Återkommande logik är utbruten och inkapslad i funktioner
- Namn på filer, variabler, funktioner, etc. skall hjälpa läsaren att förstå deras innebörd, och beteende (t.ex. vilka värden som är rimliga, eller vad man kan förvänta sig från ett funktionsanrop)
Inlämningsinstruktioner finns i uppgiftstexten!
Report a bug on this achievement? Please place an issue on GitHub.
21.2 DONE Z101: Inlupp 2 G3 Lab
21.2.1 Redovisa förståelse för grundläggande imperativ programmering i C
Detta mål är knutet till den första inlämningsuppgiften. Tekniskt sett är detta inte ett mål på samma sätt som de vanliga målen, men vi undviker ytterligare ett system för bokhållning om vi gör detta till ett mål.
För att vara färdig med inlämningsuppgiften skall du ha utfört alla steg i uppgiftsbeskrivningen förutom de som uttryckligen är frivilliga.
Programmet skall:
- Använda för uppgiften lämpliga abstraktioner
- “Skydda sig” från fel (du skall kunna förklara hur fel hanteras, och motivera valet av mekanism/strategi)
- Dokumentera alla publika gränssnittsfunktioner så att en annan programmerare skulle kunna använda implementationen
- Använda korrekt namngivning (t.ex.
ioopm_
) - Vara indenterat på ett sådant sätt att kontrollflödet är synligt
- Ha relevanta enhetstester som kan köras automatiskt
- Kunna byggas med make eller liknande verktyg
- Inte ha minnesläckage eller använda oinitierat minne
- Inte krascha vid körning med valid indata
- Inga ha några globala variabler
- Inga magiska nummer (t.ex. 128 står överallt i koden)
- Ingen “machokodning” (t.ex. omotiverade oneliners)
- Återkommande logik är utbruten och inkapslad i funktioner
- Namn på filer, variabler, funktioner, etc. skall hjälpa läsaren att förstå deras innebörd, och beteende (t.ex. vilka värden som är rimliga, eller vad man kan förvänta sig från ett funktionsanrop)
Inlämningsinstruktioner finns i uppgiftstexten!
Report a bug on this achievement? Please place an issue on GitHub.
21.3 TODO Z103: Inlupp 3 G3 Lab
21.3.1 Redovisa förståelse för grundläggande objektorienterad programmering i Java
Detta är det första Java-program som skrivs på kursen. Precis som i början av C-fasen ställer vi inte några höga krav på att man skall skriva idiomatiskt korrekt Java redan här, utan fokus ligger på att få ett fungerande program som:
- inte kraschar vid körning med valid indata
- skyddar sig från felaktig indata på lämpligt sätt och i lämplig utsträckning
- inte behöva kompileras om när indata ändras
- inte ha en massa halvtomma arrayer utan använda länkade strukturer för minneseffektivitet
- ha ett lämpligt förhållningssätt till NIH och DRY
Ytterligare icke-funktionella krav är
- inga globala variabler
- inga magiska nummer (t.ex. 128 står överallt i koden)
- kodens indentering lyfter fram kontrollflödet
- ingen “machokodning” (t.ex. omotiverade oneliners)
- återkommande logik är utbruten och inkapslad i egna metoder eller klasser
- namn på filer, variabler, funktioner, etc. skall hjälpa läsaren att förstå deras innebörd, och beteende (t.ex. vilka värden som är rimliga, eller vad man kan förvänta sig från ett funktionsanrop)
- har tydligt dokumenterade gränssnitt som går att förstå utan att läsa koden och helst är formaterade med Doxygen eller JavaDoc
- programmet går att bygga och testa med en makefil (
make all
ochmake test
)
Inlämningsinstruktioner finns i uppgiftstexten!
Report a bug on this achievement? Please place an issue on GitHub.
21.4 TODO Z104: Inlupp 4 G3 Lab
21.4.1 Redovisa förståelse för objektorienterad programmering i Java
Detta är det andra Java-program som skrivs på kursen. Precis som senare i C-fasen ställer vi högre krav på idiomatiskt korrekt Java än för föregående program. Förutom att programmet skall fungera korrekt skall det som vanligt:
- inte kraschar vid körning med valid indata
- skyddar sig från felaktig indata på lämpligt sätt och i lämplig utsträckning
- inte behöva kompileras om när indata ändras
- ha ett lämpligt förhållningssätt till NIH och DRY
Med icke-idiomatisk Java avses för enkelhets skull:
- följ Javas namngivningsstandard (
camelCasing
, Klasser/Interface har stor begynnelsebokstav, metoder liten begynnelsebokstav) - endast en klass per fil, förutom inre och nästlade klasser
equals()
-metoder skall vara symmetriska(a.equals(b) == b.equals(a))
- använd
public static final
för konstanter eller enums
Ytterligare icke-funktionella krav är
- inga globala variabler
- inga magiska nummer (t.ex. 128 står överallt i koden)
- kodens indentering lyfter fram kontrollflödet
- ingen “machokodning” (t.ex. omotiverade oneliners)
- återkommande logik är utbruten och inkapslad i egna metoder eller klasser
- namn på filer, variabler, funktioner, etc. skall hjälpa läsaren att förstå deras innebörd, och beteende (t.ex. vilka värden som är rimliga, eller vad man kan förvänta sig från ett funktionsanrop)
- har tydligt dokumenterade gränssnitt som går att förstå utan att läsa koden och helst är formaterade med Doxygen eller JavaDoc
- programmet går att bygga och testa med en makefil (
make all
ochmake test
) - programmet har enhetstester för alla viktiga metoder
- som inte bara skrevs efter att programmet var klart “för att ha tester”
- som använder junit
- där varje test prövar en sak, och flera tester görs ej i samma testfunktion
Vidare måste en annan grupp ha granskat uppgiften innan den kan bli helt godkänd (jämlikt P45).
Ändring 2016: meningen “Vidare måste en annan grupp ha granskat uppgiften innan den kan bli helt godkänd (jämlikt P45).” ersätts av “Vidare vore det väldigt trevligt, stimulerande för djuplärningen, och kanske också positivt för programmets kvalitet, om en annan grupp har granskat uppgiften innan den redovisas (jämlikt P45).”
Inlämningsinstruktioner finns i uppgiftstexten!
Report a bug on this achievement? Please place an issue on GitHub.
Questions about stuff on these pages? Use our Piazza forum.
Want to report a bug? Please place an issue here. Pull requests are graciously accepted (hint, hint).
Nerd fact: These pages are generated using org-mode in Emacs, a modified ReadTheOrg template, and a bunch of scripts.
Ended up here randomly? These are the pages for a one-semester course at 67% speed on imperative and object-oriented programming at the department of Information Technology at Uppsala University, ran by Tobias Wrigstad.