DEV Community

Charles Allison for AWS Community Builders

Posted on • Originally published at soprinye.com

Beyond Lambda Functions: Mastering Serverless Development

Photo by Buse Doga Ay on Unsplash

Introduction

AWS Lambda service is a critical component of serverless applications. It is one of the compute services for FaaS on AWS. When you deploy your functions to the cloud, AWS Lambda service is responsible for the execution. Knowing how to write and deploy functions is but a small percentage of what is required to build scalable serverless applications on AWS; it is a critical part not the only part. It is important to get ideas that can help when developing serverless applications.
This article contains some of the lessons learned in my 5 years of writing serverless applications that go beyond just knowing about AWS Lambda.
Let's dive right in!

Use Diagrams as a Guide

Diagrams have been a great tool for software engineers for a long time and it did not change with serverless development. I've worked with engineering teams that start working on large-scale systems without a simple diagram and what you hear is: "As you use the application you will get to know what it does and what happens when request 'x' is made". Maybe because of some requirements or something I'm not aware of, there is no simple documentation of the system's architecture. I have used diagrams in most of my large-scale architectures and they have been helpful. Some reasons for having a diagram as a guide include:

Sample Serverless Architecture

Birds-eye view of required components

In developing micro-services, it's safe to say that the unit of deployment is a service - a service is self-contained and has all the required functions it needs to carry out its operation. For serverless APIs, the unit of deployment is a function. Yes!, a function. However, in most, if not all cases, this function is not the only piece of your API. The function may need to read or write data from a data store, interact with data in an SQS queue or EventBridge, and many other components. The fact is there are a lot of moving parts that need to be effectively coordinated. With a diagram, you can see those parts and how they interact with each other to bring a feature to life.

Similar component concerns

The cloud offers similar products to achieving a result, of course with subtle differences and it is important to pick the right service given the right context to enable us to achieve our goal efficiently. After a system has been designed, with a diagram, you can quickly and easily depict if a service in use is the most efficient given the context of the requirement - you must however understand how each service operates in detail and avoid assumptions. Sometimes, you may have designed your architecture based on some limited requirement or even on assumptions. It is also possible that some parts of the system were rushed to quickly come up with a POC - that is fine. Having your solution in a diagram helps you understand what changes need to be done and how they affect the overall architectural solution. Diagrams also help in cases where there's a change to the requirement; it becomes easy to spot the service that should be replaced if needed and where.

Review solution across development life cycle

Software development is likened to the Civil Engineering discipline where in most cases, a building plan is drawn before actual construction begins. If this happens, then having a diagram allows you the opportunity to have your thoughts on paper(on screen) which effectively helps you review your solutions before implementation. There could be a better solution than what you originally documented. Let me also advocate that the software architecture diagram be seen as a "living document" in the sense that, it could change or be updated as the actual development progresses. This happens as you learn more about a domain or realise a better service for the job. Hence, you do not need a 100% complete diagram before you commence development. Having a visual representation of your solution, helps you make adjustments even faster as you implement your solution.

Faster development experience

I have noticed I go faster if I have a diagram that I can refer to as I implement a solution. This can be likened to goal setting and working backwards to implement the goal. It gives a feeling of having done it before. When you know the requirements and have documented the necessary services required to fulfil them, it's only a matter of your knowledge of the implementation. You really can go faster with a prepared diagram versus having to plan, think and develop almost simultaneously. It is useful here to remember that your code is not the solution - it is only an implementation of a solution.

Understand details of a service

It is typical in software engineering to start with a "hello world" type example when trying to learn a technology. It is ok and I am not against it - it's ok to get started with an example of how to use a service; it helps you quickly see requirements as well as simple outputs. However, to get the best and customise to your requirements, you will need more than a hello-world type experience. To become really good at using a service, you need to get practical with the service with as many use cases as you need to. Some of the ways to get started with a service include reviewing the documentation and reading an in-depth blog or an open-source repository with examples. However, please note that while those ways of learning are really good, they could focus on certain aspects of services, not the full capabilities. For example, it's general knowledge that Single Table Design in DynamoDB is very good. However, may not be suitable for all types of operations. Articles, blog posts, etc. have a focus - to get you to see a few things. Aside from all these, a progressive hands-on on the service is by far the best way to get a very good understanding of how the service operates, including its limitations - this helps you decide when to pick 'service a' over 'service b' when solving your requirements challenge.

Adopt EDA Early - For Efficient Scaling needs

One of the frequently talked about features of Lambda is that; it scales according to the number of requests. This means that a new instance of your lambda function is created to handle requests as they come in especially if a previous instance is "still busy". It is true that lambda scales. However, understanding its limitations is key to its efficient use and mitigation of unexpected behaviours.

Lambda does not scale infinitely, it has certain limits relating to the region of deployment and the number of functions that can be executed per time. Lambda's concurrency limit causes requests to be throttled when the limit is reached. Therefore, to build efficient systems with efficient scaling capabilities, you need to consider Event-Driven Architectures. It is very easy to postpone learning about EDAs in Serverless Architecture to a later time but I recommend that it is brought forward because it is very important and fundamental to your learning and understanding as a serverless developer and in developing efficient and scalable serverless architectures.

Two very fundamental aspects of EDAs are Queues and EventBuses. Fundamental knowledge of Amazon SQS and Amazon EventBridge can help you build efficient and scalable solutions.

What does that framework do? You may need to isolate it's orchestration

Frameworks help develop serverless applications because they provide some level of abstraction and structure as to how the application is written coupled with the ease of deployment.

Having developed several serverless applications using frameworks like AWS SAM and Serverless Framework, it is important to note that some aspects of the service or component are automated for the engineer. A good example is when AWS SAM or Serverless Framework automatically creates one of the critical components in the serverless API: the API Gateway.

In creating a custom API Gateway resource, the following resources are needed: RestApi, Resource, Stage, Method, Deployment and if you are using a custom domain, you will need both a BasePathMapping and DomainName resource.

In the SAM snippet below, just by specifying the Api type in the event source of the function, AWS SAM automatically creates those components for you - (talk about making your life easy) - and after deployment is done, you're greeted with a nicely formatted API Gateway URL with which you can access your APIs. A similar orchestration happens with the Serverless Framework.

CheckoutFunction:
Type: AWS::Serverless::Function
Properties:
  Handler: src/Checkout/index.handler
  Description: Performs order checkout
  MemorySize: 128
  Events:
    Api:
      Type: Api
      Properties:
        Path: /checkout
          Method: POST
Enter fullscreen mode Exit fullscreen mode

This is useful as necessary - however, there will be times when you will need to orchestrate an API Gateway - hence, will need to define custom resources as listed above. This means you will need to know how to build an API Gateway resource just like the framework does so that you can decompose, isolate and build up as necessary. The lesson here is defaults are good, however, custom resources will need more than defaults.

Get Comfortable with IaC - Infrastructure as Code

I've been involved in projects where some resources like custom domain names are created via the AWS console. You soon find out that as the project progresses, such resources created become a breaking point for a smooth CI/CD process because they have been manually created and it is possible to forget that such resources were created (this happens a lot with S3 buckets).

IaC becomes critical when you work in a multi-account setup and you have to deploy services or environments across accounts in an efficient way - most times, offloaded to a CI/CD process - which is the best practice.

It is possible to become overly focused on functions. However, Infrastructure as Code is critical to your success in developing serverless applications. This includes defining resources like Buckets, Queues, Event Bridges, and others using code that can be checked into source control and integrated with a CI/CD process for an efficient and fast integration and deployment loop. This ensures consistency across environments, as multi-accounts are becoming common. You need to get comfortable with IaC.

Summary

This article shares insight from my journey in developing Serverless Applications on AWS. It looks beyond Lambda functions as the focus of Serverless Applications and shares ideas that I can help an engineer become better at building serverless applications including using flow diagrams for architecture visualisation, understanding the limitations of Lambda and the need for event-drive architectures. It also talks about understanding cloud service detail to make the right judgement as to what service to incorporate in architecture, with a note on the usefulness of IaC.

Some common tools used include:

  • Diagramming
  • Lucid Chart
  • Draw.io
  • ExcaliDraw

IaC/Frameworks

  • Pulumi
  • Terraform
  • AWS CDK
  • AWS SAM
  • Serverless Framework

I hope this helps. Let me know your thoughts in the comment section.

Top comments (0)