New Style

Data Oriented Java

Java Software Engineer

Line of Business Public

Merlin Bögershausen / @mboegie




Heavy use of preview features!

Data Oriented Programming?

Monolithic history

Monolith

Self-Contained Systems

SelfcontainedSystems

Even smaller, the ☁️

Data Orientation means

  • Data is Data and nothing but the data

  • Strict separation between data and logic

  • Invalid state is not representable

  • Nothing is Mutable

How to DOP

Analyze Domain

Domain

Model only valid state

BeispielKlasssenDiagramm

Write Domain

sealed interface Rechnung
  permits InterneVerechnung, ExternVersandt {}

record ExternVersandt(Kunde kunde, double wert)
  implements Rechnung {}

record InterneVerechnung(String abteilung, double wert)
  implements Rechnung {}

Write Domain

// omitted interface Kunde and record Businesskunde

record Privatkunde(String name, List<String> mail)
  implements Kunde {
    Privatkunde {
        Objects.requireNonNull(name);
        mail = List.copyOf(mail);
    }
}

Write Logic - OOP

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;
}

Instanceof Pattern

static double calculateMwSt(Kunde kunde, double wert) {
  if (kunde instanceof Privatkunde) {
    return wert * 0.1d;
  } else if (kunde instanceof Businesskunde b) {
      return b.isVorsteuerAbzugsberechtigt()
                ? 0.0d : wert * 0.1d;
  } else {
    throw new IllegalArgumentException(/* */);
  }
}

Switch Expression

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;
  };
}

Deconstruct

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;
  };
}

Ignore Parts

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;
  };
}

Real World

Testing

@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

Modules

modularization

Integrate in EE

@Path("/invoice")
public class InvoiceResource {
  @Inject KundenRepository kundenRepo;
  @Inject MailService mailService;
  @POST // parameter mapping omitted
  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);
  }
}

Final Thoughts

Make your own Opinion

tradeoffs meme

Make your own Opinion

  • Readability 👓 - learn and use 📚

  • Duplication 🖨️ - not always bad 🧀

  • Testability ✅ - no brain needed 🧟‍

  • Performance 🚴‍- don’t guess, measure! ⏲️

Try it!

Contact

Me

🐘 MBoegie@fosstodon.org //
𝚾 & 🦋 @MBoegi //
GitHub/MBoegers

See you!

Printen

Image Credits