I’m regularly searching for ways to improve my workflow and simplify both the application’s architecture and its codebase. I look for open-source libraries to replace my hand-built modules, write a script to automate a common chore, introduce a new cloud service to reduce need for custom code, or make a common component more reusable for future projects.
But there are still several areas that I’m not happy with that burn a lot of my time. I’ll cover a few of these today.
Every month or so, I help one of my clients set up a Github repo for a new client project of theirs. It’s always for the back-end of a mobile/web app so there are a lot of commonalities in the architectures between most projects (e.g. a Lambda-backed API Gateway, Cognito, DynamoDB).
My current process goes something like this:
- Identify past project whose architecture most resembles that of the new project and clone it into a new root folder (this is usually the most recent project)
- Inside VSCode, find/replace all references to old project name with new project name
- Delete all code and config that were specific to old project (API routes, Lambda handlers, etc)
My main goals when setting up the repo are:
- To create an extensible structure that’s easily understandable for devs on the team (maps closely to the architecture and is well documented) and is somewhat consistent across different projects within my client’s organisation
- To stay as close as possible to standard industry conventions and best practices
I’m pretty happy with #1 and have evolved a folder structure that I’m reasonably happy with which takes advantage of the accumulated learnings from past projects (If this is something you’d like to learn more about, please hit reply and let me know).
Goal #2 is where my issue lies. “Best practice” is hard to define as the serverless space is still young and no pervasive convention akin to the Ruby on Rails or
create-react-app project structures has yet emerged as far as I’m aware. Folks such as Erez Rokah (
serverless-monorepo-app) and Eoin Shanaghy (
slic-starter) have released sample “starter repos” that are a great starting point.
Add in the fact that us developers are very opinionated with lots of areas of contention amongst languages and tooling, and it’s hard to see such a tool gaining widespread use. Even within the bounds of a fixed deployment framework (e.g. Serverless Framework), I’ve seen a wide range of different structures and conventions used.
The IAM system and its fine-grained permissions model is one of the biggest strengths of the AWS ecosystem, but also one of the biggest problem areas for developers. The AWS recommended best practice is to follow the least privilege principle when creating IAM roles. But to get this right can take time and I find often involves a slow process of trial and error.
Roles that I set up generally fall into 2 general categories: run-time or deploy-time.
Run-time roles are attached to resources such as Lambda functions and grant these resources permissions to perform operations on other AWS resources during the course of their execution. I find that run-time IAM roles are easy enough to define as I typically just need to inspect what AWS API calls my Lambda function is making and then add the equivalent permissions to my
iamRoleStatements section for that function in my serverless.yml file. This is almost always a 1:1 mapping of API call to IAM permission. My typical cycle to test this is to deploy my service and then run an acceptance test (e.g. that hits an API Gateway endpoint) and verify that it completes.
Deploy-time roles are attached to resources such as CodeBuild projects that are responsible for provisioning, updating configuration and tearing-down of AWS resources that make up my app. I find that deploy-time permissions are much slower to get right than run-time ones. This is for a few reasons:
- Unlike with runtime permissions around invoking API endpoints, provisioning a single resource type often requires multiple IAM permissions.
- Connecting different resources together (e.g. SNS topic subscriptions and Lambda triggers) requires further permissions
- For each “create” type permission, the equivalent tear-down/delete permission is required. This is in case CloudFormation attempts to rollback a failed deployment. Without this in place, a lot of manual resource configuration within the AWS Console can be required in order to “unstick” a CloudFormation stack that’s got into a bad state after attempting a rollback. This is particularly hard to test.
There are a few other parts of my workflow that I’m not totally happy with that I’ll cover in future emails, but I’ll leave it there for today.
What is your number one bugbear with your current serverless workflow? Hit reply and let me know. I’ll get back to you with any suggestions that I have that may help you. If I get enough responses, I’ll do a follow-up with the most common themes.
Other articles you might enjoy:
Free Email Course
How to transition your team to a serverless-first mindset
In this 5-day email course, you’ll learn:
- Lesson 1: Why serverless is inevitable
- Lesson 2: How to identify a candidate project for your first serverless application
- Lesson 3: How to compose the building blocks that AWS provides
- Lesson 4: Common mistakes to avoid when building your first serverless application
- Lesson 5: How to break ground on your first serverless project