sealed interface Rechnung
  permits InterneVerechnung, ExternVersandt {}
record ExternVersandt(Kunde kunde, double wert)
  implements Rechnung {}
record InterneVerechnung(String abteilung, double wert)
  implements Rechnung {}Heavy use of preview features!



Data is Data and nothing but the data
Strict separation between data and logic
like functional programming

sealed interface Rechnung
  permits InterneVerechnung, ExternVersandt {}
record ExternVersandt(Kunde kunde, double wert)
  implements Rechnung {}
record InterneVerechnung(String abteilung, double wert)
  implements Rechnung {}// omitted interface Kunde and record Businesskunde
record Privatkunde(String name, List<String> mail)
  implements Kunde {
    Privatkunde {
        Objects.requireNonNull(name);
        mail = List.copyOf(mail);
    }
}static double calculateMwSt(Kunde kunde, double wert) {
  if (kunde instanceof Privatkunde)
    return calculateMwSt((Privatkunde) kunde, wert);
  else if (kunde instanceof Businesskunde)
    return calculateMwSt((Businesskunde) kunde, wert);
  else
    throw new IllegalArgumentException(/* */);
}
static double calculateMwSt(Privatkunde p, double wert) {
  return wert * 0.1d;
}
static double calculateMwSt(Businesskunde b, double wert) {
  return b.isVorsteuerAbzugsberechtigt() ? 0d : wert * 0.1d;
}static double calculateMwSt(Kunde kunde, double wert) {
  if (kunde instanceof Privatkunde) {
    return wert * 0.1d;
  } else if (kunde instanceof Businesskunde b) {
    if (b.isVorsteuerAbzugsberechtigt()) return 0.0d;
    else return wert * 0.1d;
  } else {
    throw new IllegalArgumentException(/* */);
  }
}static double calculateMwSt(Kunde kunde, double wert) {
  return switch (kunde) {
    case Privatkunde p -> wert * 0.1d;
    case Businesskunde b
      when b.isVorsteuerAbzugsberechtigt() -> 0.0d;
    case Businesskunde b -> wert * 0.1d;
  };
}static double calculateMwSt(Kunde kunde, double wert) {
  return switch (kunde) {
    case Privatkunde p -> wert * 0.1d;
    case Businesskunde(String n, var m, var noMwSt)
      when noMwSt -> 0.0d;
    case Businesskunde b -> wert * 0.1d;
  };
}static double calculateMwSt(Kunde kunde, double wert) {
  return switch (kunde) {
    case Privatkunde _ -> wert * 0.1d;
    case Businesskunde(_, _, var noMwSt) when noMwSt -> 0.0d;
    case Businesskunde _ -> wert * 0.1d;
  };
}static String produceInvoiceText(
        Kunde kunde, double wert, double mwst) {
  return FMT. """
    Hallo \{
      switch (kunde) {
        case Privatkunde(String name, _) -> name;
        case Businesskunde(var name, _, _) -> name;
      } },
    Bitte senden Sie uns den Rechnungsbetrag in Höhe von \
    %.2f\{ wert }€ plus %.2f\{ mwst }€ MwSt \
    %2.f\{ wert + mwst }.
    Mit freundlichen Grüßen
    Merlin Bögershausen
    """ ;
}@Test
void invoiceValue100() {
  var customer = new Privatkunde("test", "test@dummy.de");
  var actualMwSt = MwStRechner.calculateMwSt(customer, 100d);
  assertThat(actualMwSt).isEqualTo(10d);
}6 Test to rule them all
@Path("/invoice")
public class InvoiceResource {
  @Inject KundenRepository kundenRepo;
  @Inject MailService mailService;
  @GET
  public void sendInvoice(long kundeID, double wert) {
    var kunde = kundenRepo.findById(kundeID);
    var mwst = MwStRechner.calculateMwSt(kunde, wert);
    var text = InvoiceFormatter.
        produceInvoiceText(kunde, wert, mwst);
    mailService.sendMail(kunde, text);
  }
}For every te am there are different trade-offs:
Readability - learn and use
Duplication - not always bad
Testability - no brain needed
Performance - don’t guess, measure!
Micro steps and huge gain for small disruption.

svstudioart on Freepik
creativeart on Freepik
ImageFreepik
Image from Freepik