markhildreth

markhildreth

Domain Modeling Made Functional questions

@swlaschin

Written in the persistence chapter under the section “Writing to a relational database”, that “we convert our domain object to a DTO and then execute an insert or update command.” I have a few questions on this.

1.) This doesn’t really seem to handle deletes. How would you recommend handle a command which deletes the root aggregate (and presumably all of its “children”)? Would the DTO just end up being a “null” which the persistence mechanism takes to mean “delete it all”?

2.) More troublesome, how would the aggregate root not be deleted but a child be deleted (e.g., removing an order line from an order).

Would we need to “mark” the line as deleted in our aggregate in order to know during persistence that it should be deleted? That seems like it would complicate the model for reasons of persistence.

Or perhaps our persistence logic deletes all order lines in the DB with IDs that are not in the order line DTO array?

Or maybe we retrieve the current state of the database as a DTO, do a diff with the DTO created as a result of our command

3.) In both of these questions (and specifically the second), there is the problem of concurrent transactions affecting the same aggregate. Are we essentially forced to use serializable transactions or record locking if we want to ensure that two transactions are not stepping on each others toes? Or is there another strategy here (besides strategies like event sourcing).

Thanks

First Post!

swlaschin

swlaschin

Author of Domain Modeling Made Functional

Thanks for the questions!

  1. Deletes generally just need an entity id, not a DTO. For a compound object like an Order, if the database supports it, I would set up a cascade delete. Otherwise you could query for the subobjects and explicitly delete them. In both cases I would hide all this logic inside the infrastructure component (API call wrapper) rather than exposing it to the domain logic.

  2. Removing a line from an Order would be treated as an Update from the domain’s point of view. It depends whether you want to expose the logic to the domain layer. If you want to hide it, I would pass in the modified DTO without the line and then, inside the infrastructure component (the API call wrapper), figure out which lines are missing (delete), which lines are added (insert), and which lines are changed (update). This approach means that ANY updates to the aggregate root (additions, subtractions, etc) are handled the same way, using the same infrastructure method. More complicated, but it keeps the domain logic simple.

  3. The problem of concurrent changes to the same aggregate is not specific to any particular design method and there are standard approaches you can use. If you have independent processes updating the database, you can use pessimistic concurrency (locks, transactions) or optimistic concurrency (versioning, timestamps). If everything is handled by one server (e.g. when doing microservices), then you can represent each aggregate root with an agent, and changes to the object are queued up and serialized that way. Or, yes, you can use event sourcing :slight_smile:

Hope this helps!

Where Next?

Popular Pragmatic Bookshelf topics Top

jimmykiang
This test is broken right out of the box… — FAIL: TestAgent (7.82s) agent_test.go:77: Error Trace: agent_test.go:77 agent_test.go:...
New
edruder
I thought that there might be interest in using the book with Rails 6.1 and Ruby 2.7.2. I’ll note what I needed to do differently here. ...
New
lirux
Hi Jamis, I think there’s an issue with a test on chapter 6. I own the ebook, version P1.0 Feb. 2019. This test doesn’t pass for me: ...
New
hgkjshegfskef
The test is as follows: Scenario: Intersecting a scaled sphere with a ray Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) And s ← sphere...
New
digitalbias
Title: Build a Weather Station with Elixir and Nerves: Problem connecting to Postgres with Grafana on (page 64) If you follow the defau...
New
tkhobbes
After some hassle, I was able to finally run bin/setup, now I have started the rails server but I get this error message right when I vis...
New
redconfetti
Docker-Machine became part of the Docker Toolbox, which was deprecated in 2020, long after Docker Desktop supported Docker Engine nativel...
New
gorkaio
root_layout: {PentoWeb.LayoutView, :root}, This results in the following following error: no “root” html template defined for PentoWeb...
New
davetron5000
Hello faithful readers! If you have tried to follow along in the book, you are asked to start up the dev environment via dx/build and ar...
New
dachristenson
I’ve got to the end of Ch. 11, and the app runs, with all tabs displaying what they should – at first. After switching around between St...
New

Other popular topics Top

Devtalk
Reading something? Working on something? Planning something? Changing jobs even!? If you’re up for sharing, please let us know what you’...
1063 23050 405
New
PragmaticBookshelf
Andy and Dave wrote this influential, classic book to help their clients create better software and rediscover the joy of coding. Almost ...
New
PragmaticBookshelf
Free and open source software is the default choice for the technologies that run our world, and it’s built and maintained by people like...
New
ohm
Which, if any, games do you play? On what platform? I just bought (and completed) Minecraft Dungeons for my Nintendo Switch. Other than ...
New
siddhant3030
I’m thinking of buying a monitor that I can rotate to use as a vertical monitor? Also, I want to know if someone is using it for program...
New
AstonJ
There’s a whole world of custom keycaps out there that I didn’t know existed! Check out all of our Keycaps threads here: https://forum....
New
AstonJ
In case anyone else is wondering why Ruby 3 doesn’t show when you do asdf list-all ruby :man_facepalming: do this first: asdf plugin-upd...
New
PragmaticBookshelf
Learn different ways of writing concurrent code in Elixir and increase your application's performance, without sacrificing scalability or...
New
New
AstonJ
If you’re getting errors like this: psql: error: connection to server on socket “/tmp/.s.PGSQL.5432” failed: No such file or directory ...
New

Sub Categories: