The serverless ‘Vuggy’ stack:
- Vue and TailwindCSS for our front-end, a static site deployed to AWS S3
- Go for our back-end, executed as AWS Lambda functions
- MariaDB (SQL) database on AWS RDS
Why we love this stack
It is a whole lot of fun
Go is such a beautiful, beautiful language. The power and elegance of Go allows us to build fast, scalable, reliable technology at rapid pace. Every time I build a package that passes tests, I feel the same as when my first merge sort compiled in C. That feeling of elegantly solving a little puzzle after being stumped. Using Go in our stack means I feel that way multiple times every single day.
Vue won our favour through it’s developer-friendly community and documentation. Vue mostly gets out of the way and lets us focus on our product. There is not very much we need to memorise in our head. Combined with Tailwind, it’s easy to design, build, and maintain all of our components.
It is simple and flexible
Simplicity is achieving our desired outcomes with the least input. Go and AWS are not the easiest tools to use, but they are relatively simple in that they don’t do much. They give the basic building blocks and full transparency in what happens to each bit and byte. It gives tremendous power to the programmer, and that makes us giddy.
Flexibility is the ability to adapt to our growing demands. Our first working prototype on this stack was mostly configured through AWS’ web console. The first devops processes were local basic bash scripts that used the AWS CLI. With four developers working on the code base, we moved the scripts to Bitbucket Pipelines for more automated and collaborative workflows. The shift from basic to more demanding requirements did not slow down our development velocity, and we have only scratched the surface of what our stack is capable of.
The above points relate mostly to the back-end. The front-end is no different. Vue and Tailwind have been the simplest and most flexible frameworks that we have found.
It is low-cost stack
In terms of computing resources, this stack has a light footprint. I like to develop on older computers and devices to make sure our users don’t suffer from performance issues. Sometimes my 4GB of RAM starts to suffer with Tailwind’s files ‘un-purged’ and Vue’s developer tools open, but otherwise it’s smooth sailing. Importantly, Go’s stellar cold-start performance on AWS Lambda helps avoid many of the pitfalls with other serverless services.
Our technology dollar costs are limited to our AWS services (S3, Lambda, API Gateway, NAT Gateway, RDS, Cognito, CloudFront). We are using enterprise-grade technology and can scale it up in seconds. Yet for all of this, our costs are less than A$100 per month.
Every design choice has its trade-offs. For now, we are happy to accept that our stack has:
- Slightly slower development feedback times for back-end development: after each change on the back-end, it usually takes about 15 seconds for the Go function to compile and update on Lambda before it can be tested.
- Lack of networking control: security groups on AWS are robust, but can be difficult to manage. Configuring routing tables can be annoying when you don’t have full system access to the hardware you are configuring.
- Lock-in: should we want to migrate to a different provider, we will have a lot of work on our hands. That said, Amazon’s adherence to open standards (e.g. API Gateway has supported OpenAPI 3.0 imports since 2018, whereas Google still does not support v3.0) means we only have a few hundred lines of Amazon-specific code, at most.
How we chose this stack
Our team had a broad background in software development that ranged from Assembly to Python and everything in between (e.g. C, Java, HTML/CSS, Ladder Logic, Android, GraphQL). We are not deep experts in any one area, but we understand how computers work.
We knew we would be living and breathing our code for years, so we tried several different architectures when launching small test products. We tried application frameworks (e.g. Firebase, AppSync) and loved how quickly you could spin up a working product. However, inevitably, on day 3 we would try to implement some simple feature that was impossibly hard. We were not alone, as there would be a GitHub issue with 250 comments expressing the same frustration.
We tried monolithic architectures and different combinations of hosting the application on servers. This worked great and was low-cost, but we could see future headaches affecting us: needing to be extra careful with security, scaling our services, and reducing latency for our global audience. All topics where Google, Amazon, or Microsoft are much better than us.
Much of the advice from our peers and coaches was to use a Node and React stack. The most common reason would that it would be easier to find help. Help in the form of the npm packages and in the form of developers. Moderns web developers may love a Node/React stack, but our primal brains just couldn’t adapt to feel anything but confusion when it came to all the packages and libraries and packages.
As for our database choice: we tried some really cool NoSQL databases and GraphQL queries. The data in our product is very structured, so a SQL database with REST endpoints match our needs perfectly. As for which SQL database, we stuck to an open-source technology that is familiar: MariaDB.
We are always evolving our tools at Meetric and we are sure there is a much better way to do what we are trying to do. We can’t wait to find out what it is.