F5 Kodkvalitet 151 Programutveckling sker i faser • Här: starkt förenklat version • Passar bara mindre projekt • Fem delmoment: – Fastställa och analysera förutsättningarna/kraven – Skapa en design – Implementera koden – Testning – Dokumentation OBS! Testning och dokumentation ska ske 152 parallellt med de övriga momenten. Livscykel, vidareutveckling och återanvändning Scenario 1: Nyproduktion av ett hus, som ska fungera som skola Scenario 2: Ombyggnation av ett modernt hus, byggt 2010 används som en förskola och ska fortsätta att användas som F-9 skola Scenario 3: Ombyggnation av ett gammal Kmärkt skola byggt 1870, till kontor Scenario 4: Åtgärda en skola som är klassat som ett sjukt hus. Skolan är bygg 1990. 153 Legacy code - ärvd kod Skriva kod som lever i flera generationer och varianter, som andra än du själv jobbar med. Ändra/jobba med kod som andra (eller du själv) har utvecklat, tex. » Bygga vidare Ny version » Kundanpassa » » Rätta fel 154 Legacy code - ärv kod Vad är viktigt då för att minimera kostnader och risker? Systemen/koden är lätt att förstå Lätt att testa det nya utan att ha sönder det gamla Samt Färdigheten att läsa och förstå andras system och kod, 155 dokumentation, etc. Livscykel, vidareutveckling och återanvändning Scenario 1: Nytt system som ska byggas från grunden Scenario 2: Utökning av funktionalitet i RSV system för folkbokföring som påbörjades 1985 Scenario 3: Anpassning ett system mot en helt ny kund, systemet utvecklat sedan 2010 Scenario 4: Jobba bort felrapporter som kommer in på mobiltelefonsystem, för att komma ut med en helt ny release. 156 Sträva efter kod som är… • kod som är bra, dvs, hög kodkvalitet • kod som är man kan stå för, för man kan garantera att den gör det den ska göra och inget annat, bra testad • kod som är beskriven på ett bra och tydligt sätt, dvs bra dokumenterad 157 Kodkvalitet Vad är god kodkvalitet? Vad är dålig kodkvalitet? Hur ”mäter vi kodkvalitet”? Vem bär ansvaret för kvalitet på koden? 158 Kodkvalitet Hur kan man jobba för att nå hög kvalité? Vems ansvar är det om en klass eller metod beter sig konstigt och orsakar fel? 159 Hur kan man jobba med kodkvalité? 1. Jobba strukturerat genom hela processen 160 Hur kan man jobba med kodkvalité? •Fokusera på kvalité och inte kvantitet – Bygg det ”viktigaste” först •Jobba tillsammans – Gemensamt ansvar en för alla alla för en – Kontinuerlig uppföljning av processen •Kod-granskning •Lätt att läsa, lätt att testa, förklara •Koden följer grundläggande kodprinciper •Koden, systemet är inte onödig svårt att förstå •Involvera testning i ett tidigt skede av processen 161 Hur kan man jobba med kodkvalité? •Tydlighet i förväntningar • Tydliga krav vad som ska systemet ska kunna göra • Tydliga definitioner när en funktion/del fungerar som den ska både i det lilla och i det stora • Tydliga definitioner på när det inte fungerar (undantag, fel, etc) •Bra design • System/klassdesign/metoddesign • Systemarkitektur, klasser, metoder, etc •Dokumenterad testning på många nivåer • Enhets, integrering, system,…acceptans-test • Hur ska man följa upp/garantera att koden fungerar även efter flera generationer • Mer om det senare 162 163 Johan Eliasson F6 Klass och metoddesign 165 Hur kan man jobba med kodkvalité? 1. Jobba strukturerat genom hela processen 166 Skapa en OO-design • Bestäm klasser, objekt och metoder som behövs – Vad finns redan? • Bestäm algoritmer för problemlösningen • I princip oberoende av programmeringsspråk – Diagram – Pseudokod • Designa för återanvändning? – Det är svårare att göra generella lösningar – Kan löna sig i framtiden – Återanvändning har varit en stor anledning till OOboomen 167 Implementation • När man kommer till detta steg så har man ”ritning klar”, det mesta av ”materialvalen är gjorda” • Översättning av design till källkod • Implementationen fokuserar på kod-detaljer • Alla viktiga beslut tas vid analys och design 168 Kodkonvention • Klasser påbörjas med stor bokstav (i övrigt små utom om flera ord då Inledande bokstav i övriga ord också görs stor) – AClass • Metoder/attribut inleds med liten bokstav (i övrigt små utom om flera ord då inledande bokstav i övriga ord också görs stor) – aMethod(), aVariable • Konstanter Bara stora bokstäver. Ord åtskiljs med _ – PI • Följer man dessa konventioner så kommer ens egna klasser att “se ut” som javas inbyggda. 169 Bra klasser är grunden • Bra namn som säger vad den gör eller är till för • Hanterar undantag och fel på ett bra sätt • Väldokumenterad –Vad den gör –Hur dess relation är till andra klasser –Publika metoder är dokumenterad • Minimera möjligheten att ändra tillstånden – använd setter och getters för att jobba med tillståndsförändring – tänk efter om det behövs setters, eller fungerar det utan • Undvik statiska attribut och metoder i så stor utsträckning det bara går 170 Bra klasser är grunden • Typer av klasser •Actor-classes •Utility-classes •Oförändliga klasser, • dvs man kan bara skapa objekt med värden och man har inga setters för att ändra tillståndet -String är en sådan klass • Inte för stora ansvar för en klass -> avspeglar sig i det publika ”interfacet” • Synligheten ligger på rätt nivå • Minska beroendet till andra klasser –Tex. undvik att lägga in metoder för utskrift i klasser försök att lägga dom så högt upp i klasshierarkin som det bara går helst i main-klassen. •System.out.println finns inte i alla miljöer… 171 Några olika typer av klasser •Actor-classes •Gör saker med objekten, ändrar tillstånd, har ett beteende, mm •Utility-classes •Ofta statiska klasser som inte jobbar med att förändra objekts tillstånd, –typ Math-klassen •Oföränderliga klasser •Klasser med ett fast tillstånd –Man kan bara skapa objekt med värden och man har inga setters för att ändra tillståndet 172 String är en sådan klass Vad kännetecknar en god klass • Med andra ord • En odelad, väldefinierad abstraktion • Coupling • Uppgiften kan beskrivas kort och tydlig • Namnet är en substantiv eller adjektiv som beskriver abstraktionen på ett adekvat sätt • Har ett koncist och sammanhängande gränssnitt •Cohesion • Har tillstånd och beteende 173 Coupling • Klasserna ska vara så oberoende som möjligt av varandra • Löst kopplade • Coupling mäter hur starkt klasserna är kopplade • Ju lösare klasserna är kopplade, desto – enklare är det att förstå en enstaka klass – enklare och förståeligare blir systemet som helhet • Klasserna med lös koppling kan lättare ändras utan att andra klasser påverkas ➨ Systemet blir lättare att ändra ➨ Dvs, Mera flexibilitet 174 UML: Klassrelationer svag koppling stark koppling 175 Klassdiagram Johan Eliasson Metoddesign •Konsistens när det gäller parametrar och namn –Följ en kodkonversion •Undvik sidoeffekter i metoder om det går , •beräknar och returnera ett värde •Undvik att förändra objekten som parametrarna refererar till, returnera ett nytt objekt om det är ”görbart” •Ibland använder man returvärdet för att säga något om beräkningen hur den gick, trots att metoden inte returnerar något riktigt värda •Exceptions så långt det går •jobba med undantag för att tala om att det har skett något som anroparen behöver veta för att hantera ev. 177 konstigheter Kategorier av metoder • Konstruktorer – Skapa instanser • Selektor (get-metod) – Returnerar information om objektets tillstånd • Mutator (set-metod) – Ändra objektets tillstånd • Annat – Gör någonting ➨ En metod ska tillhöra bara en kategori 178 Metoddesign •Java jobbar med ”Call-By-Value” på attributen, dvs värdet från anropssidan kopieras till attributen i metoden •Undvik att förändra värdet på de anropade attributen, speciellt när de är av referenstyp. •Vad händer på anropssidan om du ändrar på parametern/ attributet inne i en metod •använd final i attribut-listan för att göra det omöjligt att ändra attributen inne i metoden •Java kan inte förändra innehållet i variabeln som används för anropet •Java förändrar objektet som variabeln refererar till inne i en metod 179 package callByValue; import figures.Triangle; public class CallByValue { public static void main(String args[]){ int a = 42; System.out.println("a before someMethod(a): " + a); // a is copied and the copy is passed into the method someMethod(a); System.out.println("a after someMethod(a): " + a); } Triangle triangle = new Triangle(); System.out.println("triangle before triangleMethod(triangle): " + triangle); // triangle ref is copied and the copy is passed into the method triangleMethod(triangle); System.out.println("triangle after triangleMethod(triangle): " + triangle); public static void someMethod(int a){ a = 23; System.out.println("a within someMethod(a) after changing it: " + a); } public static void triangleMethod(Triangle triangle){ triangle.changeSize(10, 400); System.out.println("triangle within triangleMethod(triangle) after changing it: " + triangle); triangle = new Triangle(); System.out.println("a within triangleMethod(triangle) after created a new triagle: " + triangle); } 180 Cohesion • Varje metod ska vara “ansvarig” för bara en uppgift • Cohesion mäter huruvida en metod uppfyller detta krav • Ju mer en metod fokuserar på en enda uppgift, desto – enklare är det att finna ett bra namn – enklare och förståeligare blir koden • Metoder med stark samhörighet kan lättare ändras utan att andra metoder påverkas ➨ Det ska vara möjligt att beskriva en metod med en enkel mening med ett verb och ett objekt 181 Cohesion: Exempel 1 • Exempel 1: public void setNameAndAge (String name, int age); Bättre: public void setName (String name); public void setAge (int age); Exempel 2: /* Anropas en gång om året */ public void calculateHolidays(); { holidays += new Holidays(); age++; } Bättre: public void calculateHolidays(); public void incrementAge(); 182 Cohesion: Exempel 2 • Exempel 3: public void setFirstName (String name){ firstName = name; } public void setLastName (String name){ lastName = name; fullName = firstName + ”” + lastName; } Bättre: public void setFirstName (String name) { firstName = name; fullName = firstName + ”” + lastName; } public void setLastName (String name){ lastName = name; fullName = firstName + ”” + lastName; } 183 F6 Filer och IO 184 Input/ output Utströmmar från programmet Inströmmar till programmet 185 Input/output • Externa data kan tillhandahållas på många sätt i Java :” – Via GUI” – Läsas och skrivas direkt till och från tangentbord och bildskärm – Läsas och skrivas till och från filer – Läsas och skrivas till och från databaser – … • Java API tillhandahåller paketet java.io – Klasser som stöder input/output” – Klasser för att hantera när I/O-operationer går fel • Typfel • En fil som inte går att hitta/öppna • … 186 Filer • Filer kan användas för att lagra data permanent mellan programkörningar eller för utbyte an information mellan program. • Textfiler läsbara även för oss (med tex en texteditor) till skillnad från binära filer som lagrar datat mer som i datorns minne. 187 Skriva och läsa textfiler • Strömmarna betraktas som innehållande värden av typen char • Klasser som hanterar textfiler kallas readers och writers • Tre viktiga åtgärder – Öppna filen – Skriv/läs data – Stäng filen • Samtliga dessa kan misslyckas – Man måste förutse undantag! 188 Öppna/Skriva/Stänga • Skapa ett FileWriter objekt • En konstruktor tar filnamnet som parameter (String) FileWriter writer = new FileWriter(”testfil.txt”); • Skriv med metoden write() • Överlagrad, tex. med signaturen write(String str) writer.write("Första raden\n"); • Stäng filen med metoden close() writer.close(); //(Obs stäng ej System.in) 189 Läsa från filer • Scanner har en konstruktor som tar ett Fileobjekt som parameter • Alternativt kan man koppla ihop den med En Reader klass • File f=new File(“minfil.txt”); • Scanner in=new Scanner(f); //Kastar ett kontrollerat undantag • Scanner in2=new Scanner(new FileReader(“minfil.txt”)); • String str=in2.next(); • in2.close(); 190 Exempel import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class CopyBytes { public static void main(String[] args) throws IOException { FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream("xanadu.txt"); out = new FileOutputStream("outagain.txt"); int c; while ((c = in.read()) != -1) { out.write(c); } } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } 191 } Input/ output • Java I/O baseras på streams (strömmar) • En ström är en sekvens av bytes som flödar från en källa till ett mål • Fördefinierade standardströmmar: ström syfte System.in läsa input System.out skriva output System.err skriva fel enhet tangentbord bildskärm bildskärm datatyp InputStream PrintStream PrintStream • Standard strömmarna kan läggas om med System.setIn/Out/Err metoderna 192 InputStream • Inputströmmar är mera komplicerade • InputStream är en abstrakt klass • InputStream har väldigt begränsad mängd metoder för att hantera inläsning • System.in måste därför ofta ”kapslas in” i en mer specifik ström med de egenskaper man vill ha – Läsa in strängar – Läsa in heltal – Läsa in … • Vi kommer titta på några olika klasser vi kan använda till detta tex Scanner 193 Scanner • Osmidigt att läsa in en hel rad som sträng! Bättre med ett”ord” i taget. • Vad är ett ”ord”? • Tecknen måste grupperas till s.k. Tokens • Tidigare mycket eget jobb • Sedan Java 1.5 (5.0) finns klassen Scanner... • Man kopplar en scanner till en ström Scanner myScan = new Scanner(System.in); • Finns metoder för att läsa in heltal, flyttal, ord, rader etc. Se metoder i API:n – https://docs.oracle.com/javase/7/docs/api/java/util/ Scanner.html 194 Koppla ihop strömmar • För mer avancerat beteende kan de enkla strömmarna som läser/skriver från någon kopplas ihop med mer avancerade strömmar. • Ex: PrintWriter out=new PrintWriter(new FileWriter(“filnamn.txt”)); out.println(“hej”); out.close(); • Strömmar finns tex för buffring, hantera radnummer, komprimering och kryptering • https://docs.oracle.com/javase/7/docs/api/java/io/ PrintWriter.html 195 Exempel import import import import import java.io.FileReader; java.io.BufferedReader; java.io.IOException; java.util.Scanner; java.util.Locale; public class ScanSum { public static void main(String[] args) throws IOException { Scanner s = null; double sum = 0; try { s = new Scanner(new BufferedReader(new FileReader("usnumbers.txt"))); s.useLocale(Locale.US); while (s.hasNext()) { if (s.hasNextDouble()) { sum += s.nextDouble(); } else { s.next(); } } } finally { s.close(); } System.out.println(sum); } 196 } Object Serialization • Object serialization är ett sätt att spara ett objekts tillstånd (tex i en fil) så att vi sedan kan komma åt det. Även efter att programmet avslutats. • Object serialization åstadkoms mha Serializable interfacet och klasserna ObjectOutputStream och ObjectInputStream • writeObject metoden används för att serializera ett objekt • readObject används för att återskapa objektet 197 I/O Streams Input Streams Output Streams Data Streams Processing Streams Character Streams Byte Streams • • • • • • • Byte Streams handle I/O of raw binary data. Character Streams handle I/O of character data, automatically handling translation to and from the local character set. Buffered Streams optimize input and output by reducing the number of calls to the native API. Scanning and Formatting allows a program to read and write formatted text. I/O from the Command Line describes the Standard Streams and the Console object. Data Streams handle binary I/O of primitive data type and String values. Object Streams handle binary I/O of objects. 198