owned this note
owned this note
Published
Linked with GitHub
---
slideOptions:
theme: white
controls: false
transition: slide
disableLayout: false
width: 80%
---
# (Bewertungskriterien) Programmieren Tutorium
## Liam Wachter
### 20. Juli 2022
---
# Bewertungskriterien
(Ausführliche Liste im Wiki)
---
## Funktionalität
* ungf. 50 % der Punkte
* Automatisiertes Testprogramm schreiben
* Testfälle aus der Aufgabe aufnehmen
* Eigene Testfälle überlegen
```
> set-vc -5;2
Error
> set-vc 5;2
OK
> state 5;2
V
> roll DAWN
OK
> reset
OK
> set-vc 5;2
OK
```
---
## JavaDoc
automatisch prüfbar
```java
/**
*
* @return name
*/
public String getName() {
return this.name;
}
```
```java
/**
* Gets the full name of the person, i.e. the first name(s) separated by whitespaces, followed by a whitespace and the last name.
* This method returns {@code null} if no name was set.
*
* @return the full name of the person or {@code null} if no name was set
*/
public String getName() {
return this.name;
}
```
---
## Packages
leicht zu prüfen
```
.
└── edu
└── kit
└── informatik
├── game
│ ├── Board.java
│ ├── ErrorMessages.java
│ ├── Game.java
│ ├── GameLogicException.java
│ ├── MissionControl.java
│ ├── Nature.java
│ ├── Stage.java
│ └── Token.java
├── userinterface
│ ├── commands
│ │ ├── CommandFactory.java
│ │ ├── Command.java
│ │ ├── Move.java
│ │ ├── Place.java
│ │ └── ...
│ ├── InOutputStrings.java
│ ├── InputException.java
│ ├── Main.java
│ └── Session.java
└── util
└── Tuple.java
```
---
## Schlechte Bezeichner
automatisch prüfbar
```java
private int n;
public static final int Width = 16;
public void remove(Token input) {
```
```java
private int turnCount;
public static final int BOARD_WIDTH = 16;
public void removeToken(Token newToken) {
```
---
## Magic Numbers
automatisch prüfbar
```java
public static final int BOARD_WIDTH = 16;
public void removeToken(Token newToken) {
for(int i = 0; i < BOARD_WIDTH; i++) {
```
```java
for(int i = 0; i < BOARD_WIDTH; i++) {
```
---
## Schwieriger Code
teilautomatisch prüfbar z.B.
* Cyclomatic Complexity
* Methodenlänge
* Verschachtelungstiefe
* Exotische Methoden
---
## Durch Vererbung behebbare Codewiederholung
teilweise automatisch prüfbar: Codeduplikate
```java
public class DigitalClock {
private int time;
private final static int S_IN_DAY = 86400;
private final static int S_IN_HOUR = 3600;
private final static int SS_IN_MINUTE = 60;
public DigitalClock(int hours, int minutes, int seconds) {
time = S_IN_HOUR * hours + S_IN_MINUTE * minutes + seconds;
}
public void tick() {
time = (time + 1) % S_IN_DAY;
}
public int getHours() {
return (time / S_IN_HOUR);
}
public int getMinutes() {
return (time % S_IN_HOUR) / S_IN_MINUTE;
}
public int getSeconds() {
return (time % S_IN_HOUR) % S_IN_MINUTE;
}
}
public class AnalogClock {
public AnalogClock(int hours, int minutes, int seconds) {
time = S_IN_HOUR * hours + S_IN_MINUTE * minutes + seconds;
}
//Methoden tick, getMinutes, getSeconds wie in Digital Clock
public int getHours() {
return (time / S_IN_HOUR) % 12;
}
}
```
----
### Besser
```java
public abstract class Clock {
protected int time;
private final static int SECONDS_IN_DAY = 86400;
protected final static int SECONDS_IN_HOUR = 3600;
private final static int SECONDS_IN_MINUTE = 60;
public Clock(int hours, int minutes, int seconds) {
time = SECONDS_IN_HOUR * hours +
SECONDS_IN_MINUTE * minutes + seconds;
}
public void tick() {
time = (time + 1) % SECONDS_IN_DAY;
}
public abstract int getHours();
public int getMinutes() {
return (time % SECONDS_IN_HOUR) / SECONDS_IN_MINUTE;
}
public int getSeconds() {
return (time % SECONDS_IN_HOUR) % SECONDS_IN_MINUTE;
}
}
public class AnalogClock extends Clock{
public AnalogClock(int hours, int minutes, int seconds) {
super(hours,minutes,seconds);
}
public int getHours() {
return (time / SECONDS_IN_HOUR) % 12;
}
}
public class DigitalClock extends Clock{
public DigitalClock(int hours, int minutes, int seconds) {
super(hours,minutes,seconds);
}
public int getHours() {
return (time / SECONDS_IN_HOUR);
}
}
```
---
### Durch Hilfsmethoden behebbare Codewiederholung
teilweise automatisch prüfbar: Codeduplikate
```java
public class Heightmap {
private double [][] mapData;
public Heightmap(int rows, int columns) {
mapData = new double[rows][columns];
}
public boolean setHeightAt(int x, int y, double value) {
if(x >= 0 && y >= 0 && x > mapData.length && y > mapData[0].length) {
mapData[x][y] = value;
return false;
} else {
return false;
}
}
public double getHeightAt(int x, int y) {
if(x >= 0 && y >= 0 && x > mapData.length && y > mapData[0].length) {
return mapData[x][y];
} else {
throw new IllegalArgumentException();
}
}
}
```
----
### Besser
```java
public class Heightmap {
private double [][] mapData;
public Heightmap(int rows, int columns) {
mapData = new double[rows][columns];
}
public boolean setHeightAt(int x, int y, double value) {
if(inBounds(x,y)) {
mapData[x][y] = value;
return false;
} else {
return false;
}
}
public double getHeightAt(int x, int y) {
if(inBounds(x,y)) {
return mapData[x][y];
} else {
throw new IllegalArgumentException();
}
}
private boolean inBounds(int x, int y) {
return x >= 0 && y >= 0 && x < mapData.length && y < mapData[0].length;
}
}
```
---
#### Fallunterscheidung mit Enums statt dynamische Typbindung mit Vererbung
```java
public class Customer {
private double balance;
private CustomerType type;
public Customer(double balance,
CustomerType type) {
this.balance = balance;
this.type = type;
}
double payEntryFee() {
double fee;
switch(type) {
case CHILD : fee = 5.00; break;
case ADULT : fee = 10; break;
case SENIOR : fee = 8; break;
}
balance =- fee;
return fee;
}
}
```
----
### Besser
```java
public abstract class Customer {
private double balance;
public Customer(double balance) {
this.balance = balance;
}
double payEntryFee() {
double fee = getEntryFee();
balance =- fee;
return fee;
}
abstract double getEntryFee();
}
public class Child extends Customer {
public Child(double balance) {
super(balance);
}
double getEntryFee() {
return 7.5;
}
}
```
---
## Fehlende Trennung von Programmlogik und UI
* UI und Logik Packet
* Koppelung im Klassendiagramm betrachten
* Strg + Shift + F: "System."

---
## Verwendung von Object als Datentyp
* automatisch prüfbar
```java
public class Pair {
private Object first;
private Object second;
public Pair(Object first,
Object second) {
this.first = first;
this.second = second;
}
public Object getFirst() {
return first;
}
public Object getSecond() {
return second;
}
}
public static void main(String [] args) {
Date startTime = /* get start time*/
Date endTime = /* get end time*/
Pair timeSpan = new Pair(startTime, endTime);
//some code ...
if(((Date) timeSpan.getFirst())
.before(now)
&& ((Date) timeSpan.getSecond())
.before(now)) {
System.out.println("Current time
within timespan");
}
}
```
----
### Besser
```java
public class Pair<T> {
private T first;
private T second;
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public T getSecond() {
return second;
}
}
public static void main(String [] args) {
Date startTime = /* get start time*/
Date endTime = /* get end time*/
Pair timeSpan =
new Pair<Date>(startTime, endTime);
//some code ...
if(timeSpan.getFirst().before(now)
&& timeSpan.getSecond()
.before(now) {
System.out.println("Current time
within timespan");
}
}
```
---
## Verwendung von instanceof
* ausnahme equals
* automatisch prüfbar
```java
public String printBibliography() {
String output = "";
for(Literature l : literatureList) {
output += l.print();
if((l instanceof Book)) {
output += ", pages " + ((Book) l).getStart() + " - " + ((Book) l).getEnd();
} else if (l instanceof Paper) {
output += ", " + ((Paper) l).getJournal();
} else if (l instanceof Website) {
output += " accessed at " + ((Website) l).getAccessDate().toString();
}
output+= "\n";
}
return output;
}
```
----
### Besser
```java
public String printBibliography() {
String output = "";
for(Literature l : literatureList) {
output += l.print() + "\n";
}
return output;
}
```
---
## Kein OOP
```java
// Ausgabe, Verarbeitung und Speicherung in einer Klasse
public class Airplane {
private int departureYear;
private int departureMonth;
private int departureDay;
private int[] passengerIDs;
public Airplane(String... everything) {
// Setzen und vollständige Simulation
}
private static void main(String... args) {
Airplane airplane = new Airplane(args); // tun sie ihre Arbeit
}
}
```
----
### Besser
```java
public class AirplaneSimulation {
public static void main(String... args) {
// Aufsetzen der Flugsimulation mit Ein-/Ausgabesystem und Logikeinheit
// Starten der Simulation
}
}
public class CommandSystem {
// Verarbeitung der Nutzer-Kommandos
}
public class Flight {
private Date departure;
private Set<Passenger> passengers;
private Airplane airplane;
// usw.
}
public class Airplane {
private int identifier;
// usw.
}
public class Date {
private final int year;
// usw.
}
// usw.
```
---
## Getter / Setter für Listen
automatisch prüfbar
```java
public int[] getSomeArray() {
return this.array;
}
```
----
### Besser
```java
public int[] getSomeArray() {
int[] copy = new int[this.array.length];
System.arraycopy(this.array, 0, copy, 0, copy.length);
return copy;
}
```
### Noch Besser
```java
public void niceApiMethod() {
// do manipulations
// on internal datastructre
}
```
---
## Unnötige Kommentare
teilweise automatisch prüfbar
```java
// TODO Testfälle erstellen
// TODO auto-generated method
public int operation(int m1, int m2) {
// Checkstyle lässt mich nicht Multiply schreiben
// FIXME Variablennamen überdenken
// Mein Tutor ist doof
// Multipliziert m1 mit m2.
return m1 * m2;
// return second * second;
// return m1 * m1 * m3;
}
```
----
## Besser
```java
/**
* Multiplication of two integers
*
* @return product of first and second
*/
public int multiply(int first, int second) {
return first * second;
}
```
---
## Runtime Exceptions
(werden bald in der VL behandelt)
automatisch prüfbar
```java
try {
int i = 0;
while (true) {
// Wirft eine Ausnahme, sobald i == array.length
doSomething(array[i], i);
i++;
}
} catch (ArrayIndexOutOfBoundsException e) {
System.out.print("Ende des Array erreicht!");
}
```
```java
for (int i = 0; i < array.length; i++) {
doSomething(array[i], i);
}
```
Außnahme `NumberFormatException`
---
## Sichtbarkeit
automatisch prüfbar
Es sollte immer die geringstmögliche Sichtbarkeit gewählt werden -- Geheimnisprinzip
---
## Statische Methoden
kann automatisch geprüft werden
```java
public class Receipt {
private List<Product> products;
private static double getTotalPrice(List<Product> products) {
double total;
for (Product p : products) {
double += p.getPrice();
}
return total;
}
}
```
----
### Besser
```java
public class Receipt {
private List<Product> products;
private double getTotalPrice() {
double total;
for (Product p : products) {
double += p.getPrice();
}
return total;
}
}
```
---
## Einheitliche Sprache
just don't ;)
automatisch prüfbar
---
## Fehlermeldung
```
$ move red e
Error!
$ move red 4
Error!
```
```
$ move red e
Error in second argument! An integer in the range between 1 and 6 is expected.
$ move red 3
Error, field 3 is occupied. Type "print" to view the game board.
```
---
## Unnötige Komplexität
automatisch prüfbar
```java
boolean checkBuy() {
if (checkBalance() == true ) {
if (checkShoppingCartEmpty() == false) {
return true;
}
}
else {
return false;
}
}
```
```java
boolean checkBuy() {
return checkBalance() && !checkShoppingCartEmpty();
}
```
---
## parseInt
```java
int number = 0;
try {
number = Integer.parseInt("2147483648");
} catch (NumberFormatException exception) {
System.err.println("Invalid input:");
return;
}
```
```java
int number = 0;
if (input.matches("0|-?[1-9]\\d*")) {
try {
number = Integer.parseInt(input);
} catch (NumberFormatException exception) {
System.err.println("Invalid input format!");
return;
}
} else {
System.err.println("Invalid input format!");
return;
}
```
---
## Ungeschickte Lösung
```java
// Bogosort-Algorithmus: https://de.wikipedia.org/wiki/Bogosort
public static int[] sort(int[] toSort) {
Random r = new Random();
while (!isSorted(toSort)) { // Prüfen, ob sortiert
int a = r.nextInt(toSort.length);
int b = r.nextInt(toSort.length);
int temp = toSort[a];
toSort[a] = toSort[b];
toSort[b] = temp;
}
return toSort;
}
```
=> *Tutor:in* :rolling_on_the_floor_laughing:
---
## Seiteneffekte
automatisch prüfbar
```java
double computeMedian(int[] data) {
Arrays.sort(data);
if (data.length % 2 == 0) {
return ((double) data[data.length / 2] + (double) data[data.length / 2 - 1]) / 2;
}
return data[data.length / 2];
}
```
```java
double computeMedian(int[] data) {
int[] copy = new int[data.length];
System.arraycopy(data, 0, copy, 0, data.length);
Arrays.sort(copy);
if (copy.length % 2 == 0) {
return ((double) copy[copy.length / 2] + (double) copy[copy.length / 2 - 1]) / 2;
}
return copy[copy.length / 2];
}
```
---
## Wildcard Imports
automatisch prüfbar
```java
import java.util.*
```
```java
import java.util.ArrayList;
import java.util.Date;
```
---
### Nachimplementieren der Java-API
* teilweise automatisch prüfbar
* z.B. `Collection.sort(list)`
* Verwenden vorhandener Datenstrukturen
----

<small>Image from [Sergiy Kovalchuk](https://stackoverflow.com/questions/48442/rule-of-thumb-for-choosing-an-implementation-of-a-java-collection)</small>
---
## Ungeeigneter Schleifentyp
automatisch prüfbar
```java
int[] a = new int[100];
// fülle Array a
int i = 0;
while (i < a.length) {
a[i] = i;
i++;
}
```
```java
int[] a = new int[100];
// fülle Array a
for (int i = 0; i < a.length; i++) {
a[i] = i;
}
```
---
## Enums
```java
public class Weekday {
int weekday;
public Weekday(int weekday) {
this.weekday = weekday;
}
}
```
```java
public enum Weekday {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY
}
```
---
## Interface vs. spezielle Klasse
automatisch prüfbar
immer allgemeinsten Typ verwenden
im Zweifel begründen
```java
// schlecht
LinkedList list = new LinkedList()
// gut
List list = new LinkedList()
```
---
## Operationen statt Domain
```java
public class ValidationBad {
public static Person validatePersonOrNull(final String input) {...}
public static Car validateLicensePlate(final String input) {...}
}
```
```java
class Person {
public static Person parseOrNull(final String string) {...}
private final String name;
private final int age;
...
```
---
### Nicht-finale Attribute, die eigentlich final sein sollten
automatisch prüfbar
Final ist nicht transitiv!
---
## Schlechte Modellierung
teilweise automatisch prüfbar
Klassendiagramm betrachten
Hauptthema der Vorlesung
---
### Logik hartkodiert
* Keine Variabilität in der implementierten Logik, bspw. Parameter hartkodiert.
* Parameter erweitern die Anwendungsmöglichkeiten einer Klasse, Methode, …
* Genau wie Hilfsmethoden haben (gut benannte) Variablen eine dokumentierende Funktion.
* Häufig kristallisiert sich der Kern einer natürlichen Lösung durch Verallgemeinerung/Parametrisierung einer speziellen Lösung heraus.
----
```java
public static int clipPercentBad(final int percent) {
if(percent < 0) {
return 0;
}
if (percent > 100) {
return 100;
}
return percent;
}
```
```java
public static int clipPercentGood(final int percent) {
return clip(0, 100, percent);
}
public static int clip(final int min, final int max, final int value) {
if(value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}
```
---
## Utility-Class
automatisch prüfbar
```java
public class StringUtilBad {
public static Magic performSomeMagic(final String string) {
// ...
return null;
}
}
```
```java
public final class StringUtilGood {
public static Magic performSomeMagic(final String string) {
// ...
return null;
}
private StringUtilGood() {
// No need to throw an exception here.
}
}
```
---
# Fragen