What could you could learn from ‘Building Microservices’ by Sam Newman (2015, 250 pages)
When electricity replaced steam as the means 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 and solve bottlenecks easily, thus drastiacally increasing producvivirty.
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 apporach breaks down funcionality into individual and seperate services, in seperate bundles of code.
|Faster to deploy, as services can be deployed independently, with less risk and coordination||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)|
|Faster to update, as each service is stand along they can be refacroted seperately||Harder to diagnose failures, as multiple services interact a proble could be anywhere|
|Better performance, as you can use the best language and databases for each service||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|
|Easier to scale, as you can easily upgrade the service which is struggling||More expensive, the higher number of languages and databases means more liscences|
|Greater resilience, a microserices 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|
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 reponse. 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 microservcices:
- 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 should each more closely resemble 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)
- Continuous integration:
- 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
- Continuous deployment:
- 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 archetecture behind modern softwarre. You can buy ‘Building Microservices’ from Amazon UK here.