Die Tabelle zeigt eine gewisse Symmetrie. Denn es gibt Methodenpaare wie add und remove, addAll und removeAll etc. Die Methode remove-All scheint bei Map zu fehlen, denn diese Methode wäre das Gegenstück zu putAll. Map bietet außerdem die Methode entrySet und keySet, aber nicht die Methode valueSet. Diese Methode heißt korrekterweise values, weil die Mengeneigenschaften in diesem Fall nicht erfüllt werden kann.
Es ist wichtig, starke Begriffe in einer API zu etablieren und diese einheitlich wiederzuverwenden. Beispielsweise sollten Sie nicht Synonyme wie »delete« und »remove« innerhalb einer API beliebig mischen. Entscheiden Sie sich für einen Begriff und bleiben Sie dann dabei. Verwenden Sie Begriffe, die den Benutzern der API geläufig sind. Das Wort »erase« wäre zum Beispiel zu ungewöhnlich. Ein Java-Entwickler würde vermutlich für Dateioperationen nach »create« und »delete« als Erstes suchen. Bei Persistenzoperationen hingegen nach »insert« und »remove«.
Eine API ist intuitiv verständlich, wenn Entwickler den Clientcode der API ohne die Dokumentation lesen können. Das kann nur durch Vorwissen und sprechende Bezeichner funktionieren. Daher sollten Sie gezielt versuchen, Begriffe aus bekannten APIs wiederzuverwenden.
2.2.3Dokumentiert
Eine API sollte möglichst einfach zu benutzen sein. Gute Dokumentation ist für dieses Ziel unverzichtbar. Neben Erklärungen für einzelne Klassen, Methoden und Parameter sollten auch Beispiele in der Dokumentation vorhanden sein. Entwickler können durch Beispiele schnell eine API lernen und benutzen. Im Idealfall findet ein Entwickler ein passendes Beispiel, das mit wenigen Änderungen direkt wiederverwendet werden kann. Die Beispiele der Dokumentation zeigen, wie die API korrekt verwendet werden soll.
Gute Dokumentation kann zum Erfolg einer Technologie beitragen. Das Spring Framework hat beispielsweise eine sehr gute Dokumentation mit vielen sinnvollen Beispielen und Erklärungen. Dies war sicherlich ein Grund für die hohe Akzeptanz des Frameworks.
2.2.4Einprägsam und leicht zu lernen
Wie leicht oder schwer es ist, eine API zu lernen, hängt von vielen unterschiedlichen Faktoren ab. Eine konsistente, intuitiv verständliche und dokumentierte API ist sicherlich einfacher zu lernen als eine inkonsistente, unverständliche und undokumentierte. Die Anzahl der von einer API verwendeten Konzepte, die Wahl der Bezeichner und das individuelle Vorwissen der Benutzer haben ebenfalls großen Einfluss auf die Lernkurve.
APIs sind nur mit Mühe zu erlernen, wenn die Einstiegshürden sehr hoch gelegt werden. Dies ist dann der Fall, wenn viel Code für erste kleine Ergebnisse geschrieben werden muss. Nichts kann einen Benutzer mit Anfängerkenntnissen mehr einschüchtern. Das Webframework Vaadin bietet deswegen auf seiner Website ein Beispiel2 mit geringer Einstiegshürde und »sichtbaren« Ergebnissen:
public class MyUI extends UI {
protected void init(VaadinRequest request) {
TextField name = new TextField("Name");
Button greetButton = new Button("Greet");
greetButton.addClickListener(
e -> Notification.show("Hi " + name.getValue())
);
setContent(new VerticalLayout(name, greetButton));
}
}
Das Beispiel zeigt die Verwendung von Widgets – eine Besonderheit für Webframeworks. Dieses Beispiel hat den Vorteil, dass mit nur etwa 10 Zeilen Code ein erstes sichtbares Ergebnis entsteht. Das Beispiel kann man für weitere Experimente nutzen, um das Framework auszuprobieren.
2.2.5Lesbaren Code fördernd
APIs haben enormen Einfluss auf die Lesbarkeit des Clientcodes. Schauen wir uns dazu folgendes Beispiel an:
assertTrue(car.getExtras().contains(airconditioning));
assertEquals(2, car.getExtras().size());
Das Beispiel ist ein Auszug aus einem Unit Test. Die beiden Assertions prüfen, ob das Fahrzeug car eine Klimaanlage und insgesamt zwei Extras hat. Alternativ könnte der Unit Test auch mit dem FEST-Assert-Framework geschrieben werden:
assertThat(car.getExtras())
.hasSize(2)
.contains(airconditioning);
Dank des Fluent Interface, dessen Methodenketten zur Validierung des Testergebnisses stärker an eine natürliche Sprache angelehnt sind, ist der Code des zweiten Beispiels etwas verständlicher. Ein Fluent Interface ist eine Domain Specific Language (DSL), die durch die Anpassung an die Anforderungen ihrer Domäne viel ausdrucksstärker als eine universelle Programmiersprache ist. In Abschnitt 6.1 finden Sie weitere Informationen zu diesem Thema.
Bessere Lesbarkeit und Wartbarkeit von Unit Tests waren die Entwurfsziele des FEST-Assert-Frameworks. In diesem Zusammenhang könnte man noch viele andere Bibliotheken mit gleichem Zweck nennen: Das Spock Famework beispielsweise bietet eine kleine DSL zur übersichtlichen Strukturierung von Tests.
Ein Beispiel aus einem ganz anderen Aufgabengebiet ist die JPA Criteria API. Diese API dient zur Konstruktion von typsicheren Datenbankabfragen. Mit dem folgenden Java-Code wird eine Query gebaut und ausgeführt, um alle Order-Objekte mit mehr als einer Position zu selektieren:
EntityManager em = ...;
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Order> cq = builder
.createQuery(Order.class);
Root<Order> order = cq.from(Order.class);
order.join(Order_.positions);
cq.groupBy(order.get(Order_.id)).having(
builder.gt(builder.count(order), 1));
TypedQuery<Order> query = em.createQuery(cq);
List<Order> result = query.getResultList();
Übersichtlicher wird die Abfrage mit QueryDSL. Diese Bibliothek bietet ein Fluent Interface, mit dem verständliche Pfadausdrücke formuliert werden können.
EntityManager em = ...;
QOrder order = QOrder.order;
JPQLQuery query = new JPAQuery(em);
List<Order> list = query.from(order)
.where(order.positions.size().gt(1))
.list(order).getResults();
Entwickler verbringen mehr Zeit mit dem Lesen als mit dem Schreiben von Quellcode. Daher kann deren Produktivität durch gut lesbaren Quellcode bzw. einer leicht verständlichen API verbessert werden. Wie können APIs zu lesbarem Code führen?
Gute Namenskonventionen sind wichtig, denn sie unterstützen das Lesen und Erfassen des Quellcodes. Gut lesbarer Code enthält auch weniger Fehler, denn Fehler fallen dann schneller