The Software Development Lifecycle standardizes the way an application is built, tested, and deployed. A consistent and reliable lifecycle allows for faster development by reducing friction and increasing visibility of how developers and their applications work.
Over my years of building and managing Serverless projects, I’ve created some guidelines to give our projects the best chance of success. This blog post isn’t a particularly lengthy one, but the points are potent even in small doses.
Building cloud resources using an Infrastructure as Code framework allows developers to standardize cloud-native services they need to deploy for their applications. This allows environment variables to be used in order to enforce proper staging practices and secure code secrets. These services can then be deployed and promoted in an automated CI/CD pipeline, either natively through the cloud provider or using an external service such as GitHub or GitLab.
“Move your development environment towards the cloud, do not try to move the cloud down to your dev environment.” - Ben Kehoe
What to do:
- Define resources using an Infrastructure as Code framework such as CloudFormation which creates CloudFormation Stacks which can be monitored.
- Have builds automated by a CI/CD pipeline using resources like CodeBuild & CodePipeline.
- Enforce environment variables and staging practices.
At Trek10, we trend towards using SAM, SAM CLI and the native AWS tooling for CI/CD. In fact, we even publish and maintain the official reference deployment for AWS Serverless Enterprise CI/CD.
While developing for Lambda, Unit tests should be built within the function as if they were in a microservice application. Integration tests should cover the various boundaries and connections between services to ensure data is passed along the entire workflow.
“Think through the parts of your application that are mission-critical and author your tests to ensure the reliable operation (and integration) of those functions. Productive tests are ones that catch regressions, evaluate expected behavior, and become part of software documentation.” - Paul Chin Jr.
What to do:
- Integration Tests between applications to ensure complete end-to-end transmission.
- Automate Smoke Tests to validate build viability.
- Use Mock Data for test cases to increase code coverage.
The key to good deployment practice is using predictable environments to have as much confidence as possible what factors are required to make an application work well and securely and where that will fail.
“Use at least an account per environment. You can even separate more fine-grained than that. AWS Organizations and IAM role assumptions make this manageable.” - Alex DeBrie
What to do:
- Instead Parameterize Lambda Functions with Environment Variables and Secret Managers
- Automate deployment using available AWS resources
- Use strategic, consistent tagging to attach metadata to applicable resources
- Use Compliance Tooling such as CloudSploit to enforce Tagging Requirements
When a Lambda is updated, either directly through the AWS Console, through a change in CloudFormation Stack, or through an API call, it happens independently of other deployed services, including other Lambdas within the same CloudFormation stack. When a Lambda is updated through the console, the code is updated via an auto-save. All other associated configurations, such as maximum runtime, must be saved on command.
At Trek10, we highly recommend that code is only ever updated via IaC utilities like CloudFormation or SAM. Once you venture down the path of pushing meaningful updates via the console, it is only a matter of time until non-trivial downtime or other loss will occur.
Don't give in the the temptations the point-and-click experience of the console offers in terms of ease and short-term speed over the safety of Infrastructure as Code. The path back to the light is dark and full of terrors (and outages). - Jared Short
What to do:
- Ensure tests are updated for any code changes... your CI pipeline is green, right?
- Any changes to configurations should also update infrastructure monitoring. No muting alarms and "we'll fix that latter".
- Any finalized changes done in the console should be translated into Infrastructure as Code. No "manual just this one time".
While we haven't covered every stage of the development, seeing how the lifecycle works with cloud functions like Lambda can make it easier to onboard other services in a standardized, well-designed way.
Once the basics of deployment are planned out, a team can have a broader picture of how to operationalize the serverless application with monitoring and metrics.
If you want to dig in deeper, I highly suggest you take at our breakdown of how AWS builds and deploys a real-world serverless application!