More on this book
Community
Kindle Notes & Highlights
by
Sam Newman
Read between
November 1 - December 24, 2017
forgot. If your use of shared code ever leaks outside your service boundary, you have introduced a potential form of coupling.
My general rule of thumb: don’t violate DRY within a microservice, but be relaxed about violating DRY across all services.
The more logic that creeps into the client library, the more cohesion starts to break down, and you find yourself having to change multiple clients to roll out fixes to your server.
We need to embrace the idea that a microservice will encompass the lifecycle of our core domain entities,
The best way to reduce the impact of making breaking changes is to avoid making them in the first place.
REST, on the other hand, helps because changes to internal implementation detail are less likely to result in a change to the service interface.
This pattern — of implementing a reader able to ignore changes we don’t care
about — is what Martin Fowler calls a Tolerant Reader.
“Be conservative in what you do, be liberal in what you accept from others.”
Semantic versioning is a specification that allows just that.
When MINOR increments, new functionality has been added that should be backward compatible.
This versioning scheme allows us to pack a lot of information and expectations into just three fields.
if we want to release a breaking change, we deploy a new version of the service that exposes both the old and new versions of the endpoint.
blue/green deployments
The longer it takes for you to get consumers upgraded to the newer version and released, the more you should look to coexist different endpoints in the same microservice rather than coexist entirely different versions.
This pattern is sometimes referred to as backends for frontends (BFFs)
The business logic for the various capabilities these backends use should stay in the services themselves. These BFFs should only contain behavior specific to delivering a particular user experience.
“Build if it is unique to what you do, and can be considered a strategic asset; buy if your use of the tool isn’t that special.”
it might make more sense to change how your organization works rather than embark on complex customization.
even a minor-point upgrade in the underlying tool can break any customizations you have made.
Salesforce is especially troublesome in this regard.
Treat the CMS as a service whose role is to allow for the creation and retrieval of content.
The scope of such a tool typically starts small, but over time it becomes an increasingly important part of how your organization works. The problem is that the direction and choices made around this now-vital system are often made by the tool vendor itself, not by you.
identify the core concepts to our domain that the CRM system currently owned.
A useful pattern here is the Strangler Application Pattern
Avoid database integration at all costs. Understand the trade-offs between REST and RPC, but strongly consider REST as a good starting point for request/response integration. Prefer choreography over orchestration.
Avoid breaking changes and the need to version by understanding Postel’s Law and using tolerant readers. Think of user interfaces as compositional layers.
seam — that is, a portion of the code that can be treated in isolation and worked on without impacting the rest of the codebase.
we discussed previously, bounded contexts make excellent seams,
A great place to start is to use a tool like the freely available SchemaSpy, which can generate graphical representations of the relationships between tables.
The quickest way to address this is rather than having the code in finance reach into the line item table, we’ll expose the data via an API call in the catalog package that the finance code can call.
Typically concerns around performance are now raised. I have a fairly easy answer to those: how fast does your system need to
Sometimes making one thing slower in exchange for other things is the right thing to do, especially if slower is still perfectly acceptable.
But what about the foreign key relationship? Well, we lose this altogether. This becomes a constraint we need to now manage in our resulting services rather than in the database level.
What we actually have here is something you’ll see often — a domain concept that isn’t modeled in the code, and is in fact implicitly modeled in the database. Here,
I would actually recommend that you split out the schema but keep the service together before splitting the application code out into separate microservices,
eventual consistency. Rather than using a transactional boundary to ensure that the system is in a consistent state when the transaction completes, instead we accept that the system will get itself into a consistent state at some point in the future.
Another option is to reject the entire operation.
report back via the UI that the operation failed.
what happens if our compensating transaction fails?
allow some backend process to clean up the inconsistency later on.
Handling compensating transactions for each failure mode becomes quite challenging to comprehend, let alone implement.
When you encounter business operations that currently occur within a single transaction, ask yourself if they really need to. Can they happen in different, local transactions, and rely on the concept of eventual consistency?
If you do encounter state that really, really wants to be kept consistent, do everything you can to avoid splitting it up in the first place. Try really hard.
In a standard, monolithic service architecture, all our data is stored in one big database.
So a change in schema has to be carefully managed.
Second, we have limited options as to how the database can be optimized for either use case
Finally, the database options available to us have exploded recently.
To report across data from two or more systems, you need to make multiple calls to assemble this data.
You could resolve this by exposing batch APIs to make reporting easier.