Donnerstag, Dezember 07, 2017

FlagArguments. Gut oder Böse?

Heute die Frage: Wie soll man mit Flag-Parametern umgehen? Flag-Parameter sind boolesche Methodenparameter, die die Ausführung einer Methode steuern. Dazu am besten gleich anschaulich ein Beispiel (Hier handelt es sich um eine fiktive Customer-Care-Relationship Anwendung. Kunden werden unterteilt in ‘Normalos’ und ‘Premium’ Kunden. Vorschläge von Premium Kunden landen in einer sogenannten Premium-Ablage. Normalos landen halt in der Normalo-Ablage):

public class ProposalServiceWithExtraParam {
    public void createProposal(Person person, boolean premiumCustomer) {
        Proposal proposal = new Proposal(person);
        if (premiumCustomer) {
            premiumQueue.add(proposal);
        } else {
            normalQueue.add(proposal);
        }
    }
}

Alternativ könnte man vielleicht auf den Extraparameter verzichten und dem API Benutzer eine weitere Methode zur Verfügung stellen?

public class ProposalServiceWithExtraMethod {
    public void createProposal(Person person) {
        Proposal proposal = new Proposal(person);
        premiumQueue.add(proposal);
    }

    public void createPremiumCustomerProposal(Person person) {
        Proposal proposal = new Proposal(person);
        normalQueue.add(proposal);
}

Jetzt geht es um die Frage, was ist besser? Extraparameter? Extramethode? Rein aus Gründen der Lesbarkeit ist die sprechende Variante mit der Extramethode, der Variante mit dem Extraparameter vorzuziehen.

Der Code, der diese API benutzen würde, könnte dann vermutlich folgendermaßen aussehen. Hier mit dem Extraparameter:

PersonService personService = ...; // Service für das Finden von Personen
CustomerService customerService = ...; // Service zur Beurteilung von Kunden
ProposalServiceWithExtraParam proposalService = new ProposalServiceWithExtraParam();
Person person = personService.findPerson(4711);

proposalService.createProposal(person, customerService.isPremiumCostumer(person));

Und jetzt mit der Extramethode:

ProposalServiceWithExtraMethod proposalService = new ProposalServiceWithExtraMethod();
Person person = personService.findPerson(4711);

if (customerService.isPremiumCostumer(person)) {
    proposalService.createPremiumCustomerProposal(person);
} else {
    proposalService.createProposal(person);
}

Bleiben wir bei dem Beispiel oben, könnte man vielleicht die kompaktere Variante mit dem Extraparameter vorziehen. Uneindeutiger wird die Sache in dem folgenden Beispiel:

ProposalServiceWithExtraParam proposalService = new ProposalServiceWithExtraParam();
Person person = personService.findPerson(4711);

proposalService.createProposal(person, customerService.bougthItems(person) > 10);

In diesem Fall wird der Premium-Status durch die Anzahl der gekauften Produkte ermittelt. Ist dieser größer als 10, wird ein Premium-Proposal erstellt. Jetzt ist es nicht mehr ganz so offensichtlich, was mit dem dritten Parameter gemeint ist. Umformuliert mit einem if-then-else und unter Verwendung der Extramethode erhält man folgenden Code:

ProposalServiceWithExtraMethod proposalService = new ProposalServiceWithExtraMethod();
Person person = personService.findPerson(4711);

if (customerService.bougthItems(person) > 10) {
    proposalService.createPremiumCustomerProposal(person);
} else {
    proposalService.createProposal(person);
}

Möglicherweise ist hier die Schreibweise mit der Extramethode für den Leser besser zu verstehen. Interessanterweise ist dieses Problem in anderen Sprachen nicht so dringend. In Javascript z.B. könnte man ein Parameterobjekt übergeben:

proposalService.createProposal({
    person: person,
    premiumCustomer: customerService.bougthItems(person) > 10
});

In Groovy können die Parameter ebenfalls benannt werden:

proposalService.createProposal(
    person: person,
    premiumCustomer: customerService.bougthItems(person) > 10
)

Ein klarer Vorteil für alle Sprachen, die benannte Methodenparameter erlauben.

Zu dem Thema haben sich einige Größen bereits Gedanken gemacht:

AssertJ und java.util.List

AssertJ hat eine praktische Möglichkeit, Listen in JUnit Tests abzuprüfen. Insbesondere, wenn in der Liste komplexe Objekte abgelegt sind, s...