New book: Recipes for Decoupling

Posted on by Matthias Noback

My new book Recipes for Decoupling is 100% complete and available now!

And now some other news related to this book.

A little background information

My new book is based on two things: 20 years of experience with (mostly framework) coupling issues in legacy code, and the hypothesis that PHPStan, the automated static analysis tool for PHP, can help us keep our code decoupled. Decoupling often means we want to use a dependency, but don't want to couple our code too tightly to it. The process of decoupling often involves some kind of rule, like "don't use Container::get()", but we don't want to focus on this rule all the time, or explain it to new members of the team. Instead, we want a tool that shows you an error when you don't follow the rule. Such an error will break the build of the project and prevent you from ever coupling to a dependency in this specific way again.

The Architecture & Decoupling bundle

Although the book counts 300 pages, it doesn't cover too much theory, and shows a lot of practical code samples instead. You'll learn useful techniques to decouple your code in meaningful ways from frameworks and libraries. Many of these techniques, or recipes, would eventually lead to the discovery of design patterns. In fact, if you already know patterns like Aggregate, or Application Service, you'll quickly recognize them in this book. But this book focuses not on the patterns, but on the question: what's a meaningful way to decouple from the dependencies of my project?

Architecture & Decoupling bundle

Because I still think that it will be interesting to learn about both - using refactoring techniques and static analysis rules to stay decoupled, as well as using design patterns to establish a good architecture for your web applications - I also set up a bundle, providing a nice discount if you buy both "Advanced Web Application Architecture" and "Recipes for Decoupling": the Architecture & Decoupling Bundle.

PHPStan custom rules repository

In "Recipes for Decoupling" we use PHPStan to establish strict rules regarding the use of third-party code or to prevent certain structures in code. We develop these rules step by step and with steadily increasing levels of complexity, but it may be useful to take a look at the end result. For this purpose I've set up a public GitHub repository with the final version of each rule and the corresponding tests:

Interview with Leanpub

If you want to hear more about Leanpub and my experience with book writing on their platform, check out the Frontmatter interview I had with Len Epp recently.

The book

The most important bit: the book. Recipes for Decoupling is 100% done now and available via Leanpub. I will later distribute a paper version via Lulu, but this will take a few more weeks at least.

PHP book frameworks decoupling Symfony Laravel Laminas
Comments
This website uses MailComments: you can send your comments to this post by email. Read more about MailComments, including suggestions for writing your comments (in HTML or Markdown).
Matt Gatner
Hello Matthias! Really enjoying the book. I’ve reached the chapter on ORMs and was very excited for the model decoupling… only to find out the solution was UUIDs.I have already re-read https://matthiasnoback.nl/2018/05/when-and-where-to-determine-the-id-of-an-entity, which makes sense in the context of new code  But decoupling an existing application (at least in my case) involves a lot of existing code and infrastructure - including databases with auto-incrementing primary keys and lots of foreign keys referencing these.Reading through the comments from that other blog post it seems that the solution for decoupling while maintaining auto-incrementing keys falls into one of two categories:* “stand in” IDs that are lazy-assigned in a transaction or swapped for an integer value* double-infrastructure calls, to fetch the “next ID” and then save the actual object
Both have pitfalls that seem immediately apparent, so I would like to hear if you have any suggestions for this sticky position?
Matthias Noback

Hi Matt, Thanks for you comment! In a legacy situation where we couldn't even add another column for the UUID, I have applied the following solution:

  1. Call to repository interface nextId(), which returns a value object that wraps an integer. The infrastructure implementation just did a MAX(id) + 1, because the database had to keep using an auto-incrementing ID.

  2. Pass the ID value object to the entity so it would use it, and it would end up in the id column.

This worked fine, because there were almost no concurrent updates, so there would be no clashes between different processes trying to insert a record with that same ID. Since we used the Aggregate pattern and we would wrap the changes in a database transaction as well, we would never have inconsistent data. The worst that could happen was that the transaction was rolled back. The user would then just re-do the same action.

If there had been a concurrency issue, we could have improved this process:

  1. We could introduce an actual sequence, that would actually reserve the generated ID for the requesting party.

  2. We could retry the same command, re-doing the changes but with a newly generated ID.

I hope this is helpful in some way!

Matt Gatner

Back to this 😅 how do you handle getting then next ID for child entities? If I have PurchaseOrder::addLine() I am stuck either: a) creating the Line outside the aggregate; the purchase order service already has the repository so can probably handle this with PurchaseOrderRepository::nextLineId(). Or, b) fetching the next ID for the Line from within the aggregate, which means the aggregate has its own repository as a dependency; seems unwise.

Matt Gatner

Thank you, very helpful. I had imagined updating the AUTO_INCREMENT value manually on the table (to deal with concurrency, which is definitely a consideration) but I actually like the “just increment and retry” solution a lot! MAX(id)+1 should cover 99% of cases (and from the read replica) and the collision becomes just a single additional command. I appreciate the response!

Matt Gatner
Enjoying the book immensely! There are some pretty big upcoming changes in v5 of PHP-Parser that will affect PHPStan (https://github.com/phpstan/phpstan/issues/7943) and thus Rector. Do you know if this will change the examples in your custom rules written throughout the book?
Matthias Noback

Thanks, Matt!

Good point about the breaking changes. I don't think many examples will break. I only thought of one example with Twig that uses ArrayItem, so that probably needs an update. Anyway, I'll make sure to publish an updated version of the book when the new major version of PHPStan lands.