4/3/2022

Build fullstack AWS apps

#code#fullstack#cloud

What is serverless?

When we think of web applications we usally think of servers that are responsible for receiving HTTP requests, processing the request, running some business logic and finally returning a result. You are not only responsible for the business logic, but also the server infrastrucutre itself. There are a few issues with this:

  1. You are charged for keeping the server up even when you are not serving out any requests.
  2. You are responsible for uptime and maintenance of the server and all its resources.
  3. You are also responsible for applying the appropriate security updates to the server.
  4. As your usage scales we need to manage scaling up our server as well. And as a result manage scaling it down when we don’t have as much usage.

Having to deal with all this DevOps work can end up distracting you from the more important job of building and maintaining the actual app your users are paying for. Even when you are a large business and have a DevOps team, not being able to quickly deploy and test your code as a developer can slow things down. This is where serverless comes in

Serverless Computing

Serverless computing (or serverless for short), is a setup where the cloud provider (AWS, Azure, or Google Cloud) is responsible for executing a piece of code by allocating the server resources (so they manage all the server stuff mentioned above) based on real-time usage. You are only charged for the time your code is running. The code is typically run inside stateless containers that can be triggered by a variety of events including http requests, database events, queuing services, monitoring alerts, file uploads, scheduled events (cron jobs), etc. There are a number of serverless offerings such as:

  • AWS: AWS Lambda
  • Microsoft Azure: Azure Functions
  • Google Cloud: Cloud Functions

While serverless abstracts the underlying infrastructure away from the developer, servers are still involved in executing our functions.

Since your code is going to be executed as individual functions, there are a couple of things that we need to be aware of.

Microservices

The biggest change that we are faced with while transitioning to a serverless world is that your application needs to be architectured in the form of functions. You might be used to deploying your application as a app. But in the serverless world you are typically required to adopt a more microservice based architecture.

Stateless Functions

Your functions are typically run inside secure (almost) stateless containers. This means that once the code has finished running, the container will be shut down and a new will be spun up for the next event. You can not rely on the output of the function to still be there when the next event comes in, so make sure that each event can be handled individually. This also relates to the next topic.

Cold Starts

Since your functions are run inside a container that is brought up on demand to respond to an event, there is some latency associated with it. This is referred to as a Cold Start. Your container might be kept around for a little while after your function has completed execution. If another event is triggered during this time it responds far more quickly and this is typically known as a Warm Start.

The duration of cold starts depends on the implementation of the specific cloud provider and how your code has been written.

Aside from optimizing your functions, you can use simple tricks like a separate scheduled function to call your function every few minutes to keep it warm. Serverless Stack Framework (SST) has pre-built tools for this.

Serverless Stack Framework (SST)

Now, one of the most popular options for serverless apps is AWS. AWS offers a number of different services and tools which can be used together such as DynamoDB, Lambda Functions, S3 and Cognito.

Since these services run on AWS, it can be tricky to test and debug them locally. And a big part of building serverless applications, is being able to define your infrastructure as code. This means that we want our infrastructure to be created programmatically. We don’t want to have to click through the AWS Console to create our infrastructure each time.

To solve these issues we can use Serverless Stack Framework (SST).

SST makes it easy to build serverless applications by allowing developers to:

  • Define their infrastructure using AWS CDK
  • Test their applications live using Live Lambda Development
  • Set breakpoints and debug in Visual Studio Code
  • Deploy to multiple environments and regions
  • Use higher-level constructs designed specifically for serverless apps
  • Configure Lambda functions with JS and TS (using esbuild), Go, Python, C#, and F#

It does this by using AWS CDK.

AWS CDK Infrastructure

AWS CDK (Cloud Development Kit) allows you to use TypeScript, JavaScript, Java, .NET, and Python to create AWS infrastructure.

So for example, a CloudFormation template that creates our DynamoDB table would now look like.

Without code:

COPY- Resources:
-   NotesTable:
-     Type: AWS::DynamoDB::Table
-     Properties:
-       TableName: ${self:custom.tableName}
-       AttributeDefinitions:
-         - AttributeName: userId
-           AttributeType: S
-         - AttributeName: noteId
-           AttributeType: S
-       KeySchema:
-         - AttributeName: userId
-           KeyType: HASH
-         - AttributeName: noteId
-           KeyType: RANGE
-       BillingMode: PAY_PER_REQUEST

Defined as code:

+ const table = new dynamodb.Table(this, "notes", {
+   partitionKey: { name: 'userId', type: dynamodb.AttributeType.STRING },
+   sortKey: { name: 'noteId', type: dynamodb.AttributeType.STRING },
+   billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
+ });

The first thing to notice is that the resources are defined as class instances in JavaScript. That’s great because we are used to thinking in terms of objects in programming languages. And now we can do the same for our infrastructure. Second, we can reuse these objects. We can combine and compose them. So if you always find yourself creating the same set of resources, you can make that into a new class and reuse it!

CDK is truly, infrastructure as code.

Live Lambda Development

SST provides a cloud native local development environment that gives you instantaneous feedback on edits made in your Lambda function code. Changes are automatically detected, built, and live reloaded in under 10 milliseconds. And you can use breakpoints to debug your functions in your favorite IDE.

Live Lambda Development is an SST feature that allows you to debug and test your Lambda functions locally, while being invoked remotely by resources in AWS. It works by proxying requests from your AWS account to your local machine.

SST Console

The SST Console is a web based dashboard to manage your SST apps.

Alt text

The SST Console does a couple of things:

  • Display real-time logs from your Live Lambda Dev environment
  • Shows you all the deployed resources in your app
  • Allows you to invoke your functions and replay invocations

It also lets you explore resources you are using within your app. You can read more in documentation.

Conclusion

So, now that you have an idea what SST can do the question is: Should you use it? I believe that it is an invaluable tool when you want to go serverless. However, make sure that the app you are building actually benefits from this architecture. Don't overengineer your app just because it looks like everyone is doing it!