This is the start of a blog series called “Patterns of Service-Oriented Architecture”, which is based on my experience at Stitch Fix (the first post is up if you want to get right to it!). Over the last four years, we’ve gone from a team of two developers and one Rails app, to almost 80 developers managing 40+ applications. These applications are a mixture of user-facing and headless services. While our technical architecture isn’t perfect, we’ve had relatively few major problems. Part of the reason for that is that we’ve done a decent job of identifying and re-applying patterns to solve similar technical challenges.
You may be familiar with the so-called “Gang of Four” book, called Design Patterns: Elements of Reusable Object-Oriented Software. Although software patterns can be abused by blindly applying them, at their core, they are a great way to transfer knowledge about solving common problems.
There is also great value in a software team re-using patterns appropriately. They can often save time not having to re-think a technical solution from first principles, and they also make it easier for teams and their members to communicate and collaborate. Structures will look similar, allowing engineers to more easily work on a wide variety of projects. Higher-functioning teams can even ensconce their application of a pattern into re-usable code, increasing the benefits.
This blog series will cover several patterns that we use every day in our software. I’m certain these aren’t novel, and many could be documented in other places, so at worst, these posts can reaffirm the fitness of these patterns to real-world problems. We’re using all of them!
Format
I’m copying the format from the Gang of Four book, so each post will have these sections:
- Intent - What is the problem this pattern solves?
- Motivation - A longer, motivating example problem and a simple description of the pattern.
- Applicability - Situations in which this pattern might be useful (a pattern is not a replacement for good judgement).
- Structure - Specifically how does the pattern look or how might you implement it. I’ll try to avoid code if I can, so that we can better understand these patterns as concepts.
- Anti-Patterns/Gotchas - Common mistakes or hidden complexity when applying this pattern.
- See Also - Related patterns. Often, the application of a pattern means using another one in conjunction, however some patterns solve similar, but different problems.
Terms
There are a few terms I’ll try use that are hopefully intuitive, but in case they are not:
- Consumer - Code that calls into a remote service—it’s consuming that service.
- Database - Some sort of canonical data store.
- Durable - A property of a database regarding what happens to the data during a failure. A durable database is expected to keep data despite failures. Postgres is an example of a durable database. A database that lacks durability, such as memcache, requires special configuration and infrastructure to be made more durable.
- Message Queue or Message Bus - A messaging system such as RabbitMQ that supports publishing and subscribing to messages.
- Service - Code that exposes some sort of API to allow Consumers to do something.
Patterns
This list will be updated as more patterns are added.
- Asynchronous Transaction
- Background Job
- Database Transactions
- Denormalized Cache
- Idempotency Key
- Message Decorator - coming soon
- Parameterless Jobs - coming soon
- Sequenced Background Jobs - coming soon