Since lesson 1.4.4, the Kladde has had a contract for its store, IKladdeStore, and two implementations since then: the JSON file for the program and the store in memory for the tests. In this lesson a third one joins them, with EF Core and SQL Server. After that you change a single line in Kladde.Web, and the Kladde works with the database. The endpoints don’t notice, and the tests from module 2.3 keep running without you changing a line in them.

That it works so easily is no accident. It’s the reward for a decision you made in K1: The core decides what it needs from the store, and it doesn’t know a single one of them.

Ports and adapters

The Kladde is built on a pattern called ports and adapters (also hexagonal architecture):

  • A port is a contract that the core defines because it needs something from outside. IKladdeStore is such a port: “Load everything, save everything, and reject whatever clashes with a simultaneous change.” It lives in Kladde.Core.
  • An adapter implements a port with a particular technology. JsonKladdeStore in Kladde.Files with a file, InMemoryKladdeStore in Kladde.Core with a list, and now EfKladdeStore in Kladde.Data with SQL Server.

The dependencies all point inward:

Kladde.Web ──────► Kladde.Core ◄────── Kladde.Data (EF Core, SQL Server)
    │                  ▲
    │                  └────────────── Kladde.Files (JSON)
    └──► Kladde.Data   (only to put everything together in Program.cs)

Kladde.Core references nothing. Kladde.Data knows the core; the core doesn’t know Kladde.Data. Kladde.Web knows both, but only in one place that really matters, Program.cs, where everything is put together (lesson 2.3.3). The endpoints get an IKladdeStore and don’t know which one. Whoever swaps the store later changes one line in Program.cs, not twenty endpoints.

The Kladde makes one deliberate exception: ContactDirectory from lesson 2.4.9 reads directly with EF Core, and a page or an endpoint may use it. Reading for a display needs no rule of the model, and a search in SQL is exactly what the port can’t do. Changing, on the other hand, always goes through KladdeBook and therefore through the port.