What you could learn from ‘Building Microservices’ by Sam Newman (2015, 250 pages)
When electricity replaced steam as the mean of power in factories, there was initially little improvement in productivity. Factory owners just replaced their centralised steam engine, with a single electrical generator. Only factories when factories moved away from a centralised generator, to separate generators for each machine, where they able to operate machine independently, move machines around and scale to solve bottlenecks.
The fundamental lesson is that for new technology to make a difference changes are often required elsewhere in the organisation.
Microservices are a (relatively) new way to construct software. Instead of a single application (monolith) which serves multiple functions, a microservice approach breaks down functionality into individual and separate services, in separate bundles of code.
As with all architectural choices, microservices have advantages and disadvantages.
- Faster to deploy, as services can be deployed independently, with less risk and coordination
- Faster to update, as each service stands along they can be refactored separately
- Better performance, as you can use the best language and databases for each service
- Easier to scale, as you can easily upgrade the service which is struggling
- Greater resilience, a microservices fail gracefully rather than catastrophically, i.e., when one service is down the rest stills works
- Organisation alignment, as micro service can easily be owned by a single team so responsibility is clear
- Harder to monitor, as monitoring is needed for each service and business logic will fall across multiple services (requiring additional measures such as a correlation IDs)
- Harder to diagnose failures, as multiple services interact a problem could be anywhere
- More to learn, the higher number of languages and databases means that engineers need to upskill which takes time to onboard and time to move between teams
- More expensive, the higher number of languages and databases means more licences
To get the most out of microservices, there are several principles and top-tips which can really help.
Microservices fundamental principles:
- Loosely coupled — change to one service must not impact any other service
- High cohesive — all related behaviour should sit together so that if those behaviours need to be changed it is only changed in one place
There are two main archetypes of microservice:
- Request response. A service basically says ‘do this’ then ‘give me an answer’
- Event-based (or pub-sub). A service says ‘this happened’ and then your service decides what to do
Other top tips for microservices:
Limit the number of different calls types to a service, to avoid performance issues as these ‘chatty communications; can lead to type coupling
Standardise what happens between the boxes (services), but be liberal about what happens within these boxes
Postel’s law (robustness principle) states “be conservative with what you do, be liberal in what you accept from others”
Build vs buy. Build if it unique to you and is a strategic advantage, otherwise, buy
Use a separate database for each service and avoid database integrations at all costs
Have single CI build per microservice, and one microservice per host (use an orchestration framework like docker)
Consider having four environments (which would each bear closer resemblance to Production). Configurations that change per environment should be kept to a minimum:
- Slow tests
- Performance testing
Testing, optimise for fast feedback
- Unit tests cover (Google ‘small tests’) a specific function. Have lots of these tests
- Service test (Google ‘medium tests’. Stub/mock databases and other services to make sure they remain fast
- End-to-end test (Google ‘medium tests’). Try to avoid these in favour of consumer-driven contracts (consider using Pact)
- track inbound response time at a bare minimum, then error rates, then application-level metrics
- Track responses of all downstream responses, bare minimum being response time and error tracking
- Standardise how and where metrics are collected
- Log into a standard location, in a standard format
- Standardise the use of correlation IDs
When changing the calls to a service, create a new endpoint and run the new call to the new service, while running the old endpoint in parallel. If everything works, then migrate all traffic and remove the old endpoint (try not to build a new service)
- Do you check into mainline once per day?
- Do you have a suite of tests to validate your changes?
- When the build is broken is it the No1priority for the team to fix
- Separate fast and slow test, run fast tests on each build (fail builds if tests fail) and run slow tests daily (overnight)
- Consider baking your service into an image (e.g., AWS AMIs), which will make your servers immutable
Bulkheads prevent failures from cascading across the system. Place bulkheads
Circuit breakers prevent down services from being overloaded. After a certain number of downstream request have failed, the circuit breaker is triggered. All further request fail fast for a given period of time, then a few requests are sent to see if the downstream service si will down
Mean time to repair is more appropriate in microservices, that mean time between failures
Don’t Repeat Yourself (DRY) applies to knowledge and behaviour (not code). This principle should be strongly applied within services, but more relaxed across all services.
- Do not write your own crypto, use standard
- Authentication — confirming someone says who they say they are
- Authorisation — confirm that an authenticated person can do what they have asked to do
Building Microservices is the best technical book for Product Managers I read this year. Read this book to understand the architecture behind modern software. You can buy ‘Building Microservices’ from Amazon UK here.
Originally published at getting better every day.