I’m currently working with a team to make a new store finder for Well to help their customers and colleagues to use to find stores.
The team is a multi-skilled group, encompassing product design, User Experience testing and research, Web design and development. There’s people from http://well.co.uk, http://common-good.co/, http://www.ninesixty.co.uk/ and the company I work for http://infinityworks.com.
It’s been interesting and fun to work with the team.
For the technology, we had a choice, so to help us decide which direction to take, we agreed on some basic principles about what the tech should look like.
Fast to create
We want to be able to get things live quickly. We want to maximise time spent on writing features which improve the product, and minimise time spent on technical plumbing.
It’s not good enough to be quick at the start, but incur technical debt. We want to move onto other projects, and not need to carry out maintenance tasks like testing backups, server patching, manual checks etc. on past projects.
When a system breaks down, people generally have to immediately stop what they’re doing, fix it and then fix the underlying issue if they don’t want it to happen again. Unreliable systems require constant maintenance and distract teams from creating new things, always having to look after what they’ve already built.
Some systems attempt to create high reliability by increasing complexity. It sounds sensible on the surface - if one database server isn’t reliable on its own, add another and synchronise them. Unfortunately, this adds complexity, which means that attempts to improve resilience often fail more often than systems would without them, simply because there is more to go wrong.
Some systems which appear simple are not. It’s just that what you see abstracts the complexity from you.
Balancing it all
We decided to choose:
- Cloud infrastructure over in-house infrastructure - faster to provision, more flexible, less communication overhead and simple to provision.
- Cloud services over Infrastructure services. Faster to create and low maintenance since the provider does the work for us. Simple because the complexity is part of the service, or because the service has the complexity designed out.
Having had previous experience of working with Serverless architectures (serving a static React front-end from S3 and calling APIs via API Gateway and AWS Lambda), I thought that this style of architecture would meet our requirements, but with a few tweaks.
- Building up API Gateway to AWS Lambda request templates, cloud infrastructure and release pipelines with Terraform across multiple environments (dev, uat, production) was quite time consuming.
- React is great if everyone on the team knows it already. If not, then you probably don’t want your team to need to spend two weeks watching videos to make “Hello World”. It’s also not common for Web designers to know it, so it can make it hard to work together, despite JSX being quite pleasant to work with.
Based on my experience of React and Serverless architectures, I decided to use the Serverless Framework (https://serverless.com) - a tool that helps to build Serverless Architecture applications by abstracting away the differences between cloud providers. For AWS, it creates S3 buckets to store your Lambda functions, automatically handles code updates
serverless deploy and generates CloudFormation templates which connect all the pieces together.
My main reservations were that the abstraction makes it harder to understand what’s happened if it doesn’t work, but fortunately I haven’t found a problem yet. I was able to get something up and running really quickly, including handling multiple environments.
The hardest thing to deal with was that the Serverless Framework doesn’t automatically generate minimal privilege security policies for deploying, so I had to do a bit of trial and error to restrict the build server’s permissions.
I’ll go into a bit more technical detail in a future post.