Clean Code mit dem Linux sed-Befehl
Clean Code ist ein wichtiges Thema, das manchmal aufwändig und langweilig sein kann. So musste ich vor kurzem in circa 100 Klassen überflüssige Annotationen löschen 😒
Statt Eclipse nutzte ich die Linux-Shell und sed, um alle Dateien mit einem Befehl aufzuräumen.
Wie das genau geht, zeige ich euch hier.
Das Problem bzw. der dreckige Code
Die Modell-Klassen unserer Anwendung wurden früher zum Parsen von JSON in Java-Objekte und zum Schreiben per JPA in eine relationale Datenbank verwendet. Nach einem Redesign werden die Modell-Klassen nur noch zum Parsen von JSON Texten verwendet, so wie ich es z.B. hier zeige rest-json-apis-in-java-leicht-gemacht.html. Im Zuge des Redesigns wurde leider vergessen die nun ungenutzten JPA Annotationen in den Modell-Klassen zu entfernen. Konkret sehen alle Klassen ungefähr so aus:
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.OneToOne;
import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import lombok.Data;
@Entity
@Data
public class ProductPrice {
@Size(max = 150)
@Pattern(regexp = "^[\\d]*$")
private String id;
@Size(max = 150)
@Pattern(regexp = "^[A-Za-z]*$")
private String name;
@Enumerated(EnumType.STRING)
@Column(name = "price_type_string")
private PriceTypeEnum priceType;
@Valid
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
private Price price;
}
Sauberer Code bedeutet unter anderem, dass es keinen toten Code und damit auch keine ungenutzten bzw. toten Annotationen geben darf. Also legen wir los und machen folgendes:
- Zuerst löschen wir alle JPA Annotation:
@Entity, @Column, @OneToOne, @Enumerated - Danach löschen wir alle nicht mehr benötigten Imports:
import javax.persistence...
Dabei hilft uns Eclipse, indem es automatisch für uns alle Imports organisiert bzw. ungenutzte löscht. Tastenkürzel für "Organize Imports": strg + shift + O
import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class ProductPrice {
@Size(max = 150)
@Pattern(regexp = "^[\\d]*$")
private String id;
@Size(max = 150)
@Pattern(regexp = "^[A-Za-z]*$")
private String name;
private PriceTypeEnum priceType;
@Valid
private Price price;
}
Leider müssen wir jetzt noch 99 andere Modell-Klassen analog aufräumen 😲
Anmerkung: Wenn ihr euch für die übrig gebliebenen Annotationen interessiert,
schaut euch folgendes an:
- validation-with-spring.html für @Valid, @Size und @Pattern
- @Data ist eine Lombok Annotation und erzeugt für uns unter anderem automatisch Getter- und Setter-Methoden. Ich finde Lombok super, verweise hier aber auf die Lombok-Webseite: https://projectlombok.org/
Die Lösung mit dem Linux-Tool sed
Der Stream EDitor (sed) ist ein Unix-Tool zum Verarbeiten von Text-Datenströmen, siehe auch https://de.wikipedia.org/wiki/Sed_%28Unix%29.
- sed ist der Befehl zum Starten des Tools.
- /"@Entity"/d definiert, dass das Textpattern "@Entity" gesucht und gelöscht (d) werden soll.
- Dabei wird am Ende durch Angabe des relativen Pfades ./ProductPrice.java die zu verarbeitende Text-Datei definiert.
Mit sed habe ich die Möglichkeit in der Pfadangabe Wildcards (*) zu verwenden und somit alle Java-Dateien in einem bestimmten Verzeichnis (package) mit einem Befehl zu editieren:
Danach müssen noch die jetzt überflüssigen Imports gelöscht werden. Das geht sogar noch etwas einfacher, da sich die zu löschenden JPA Annotationen im selben Package befinden. Unser Befehl löscht die komplette Zeile, auch wenn sich noch andere Texte/Buchstaben in derselben Zeile befinden:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.OneToOne;
- \| ist das Zeichen, um diverse Text-Patterns OR zu verknüpfen. Jede Zeile die "@Entity" oder "@Column" oder ... enthält wird gelöscht. Backslash \ escaped dabei das OR Zeichen |, welches ohne vorgestellten Backslash als Teil des Textes interpretiert werden würde.
- Der eine Backslash am Ende der ersten Zeile entfernt den Zeilenumbruch in der Shell, da mein Befehl hier nicht in eine Zeile gepasst hat.
- Anstelle von @Entity\|@Enumerated könnte man auch nur @En angeben. Das hätte in der hier gezeigten Datei den gleichen Effekt, erhöht aber das Risiko in einer anderen Java-Datei benötigte Annotationen zu löschen, die mit "@En" anfangen. Ich empfehle beim Löschen möglichst lange und eindeutige Text-Patterns zu verwenden.
Git Bash verwenden, wenn kein Linux vorhanden ist
Git Bash ist ein für Windows kompiliertes Unix Paket, welches bash, ssh, cat, sed und viele weitere nützliche Unix Tools enthält.
und wird bei der Installation mit installiert. Alle hier gezeigten sed Befehle habe ich unter Windows in der Git Bash ausgeführt.
Fazit
sed --help
Buch mit weiteren Linux Kommandos |
Kommentare
Eclipse bietet dazu den "Replace..." Button in der "File Search" Funktion an.