---
# System prepended metadata

title: (Bewertungskriterien) Programmieren Tutorium

---

---
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."

![](https://i.imgur.com/JEZ21it.png)


---

## 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

----

![](https://i.imgur.com/TAo4amH.png)
<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