A *magical* AWS serverless developer expertise

A common question developers bring up when wanting to develop serverless and cloud native applications is: what will the developer experience be like? It is an important question as a good developer experience with a quick feedback loop results in happier and more productive developers who are able to ship features rapidly. Since we’re building…

A *magical* AWS serverless developer expertise

A general inquire builders bring up when attempting to develop serverless and cloud native capabilities is: what’s going to the developer expertise be admire?
It’s some distance the biggest inquire as a lawful developer expertise with a short solutions loop results in happier and extra productive builders who are capable of ship functions mercurial.

Since we’re constructing Easy to be deliberately exiguous, a mighty developer expertise is a must.
We would like to be definite that that the few engineers that we discontinue rent can construct the most impact by turning in product functions like a flash while declaring a excessive wonderful.

We had the different to like how to resolve this subject in 2021 as Easy is built from scratch.
After we had been deciding our general tech stack, the expertise of constructing adjustments on a day-to-day basis performed a immense position within the likelihood-making, moreover to how we’ll have the flexibility to construct a winning alternate within the following 5 to 10 years with out eager to full foundational replatforms.
This meant being capable of lag our companies at scale at an inexpensive with out eager to have a full department factual taking a seek for after a homegrown infrastructure.

The rationale within the assist of these decisions positively requires its have separate post, however we ended up deciding to pass all-in on serverless and cloud native, fat-stack TypeScript, and utilizing AWS as our cloud supplier, in consequence of its maturity and recognition. We determined that utilizing proprietary AWS companies is an appropriate lock-in as there’s excessive cost gained in contrast to the likelihood of switching cloud companies.
I’ve positively viewed corporations utilize immense amounts of effort attempting to be cloud-agnostic, with out in truth realizing any tangible income from it.

What’s habitual about serverless pattern

There are some habitual components to constructing and attempting out serverless capabilities.
One of many foremost differences is that you simply discontinue up utilizing a range of cloud companies and purpose to dump as noteworthy responsibility to serverless solutions as which you might per chance perchance be like.

In the case of AWS Lambda which skill you typically discontinue up utilizing API Gateway, DynamoDB, SQS, SNS, S3, EventBridge, ElastiCache, and so forth. to construct your utility.
The usage of so many companies entails a range of configuration, permissions, and infrastructure that need to be developed, tested, and deployed.
When you completely point of curiosity on attempting out your lambda code then you’re skipping a immense allotment of your characteristic.
Examples which you might per chance perchance perchance also stumble upon whilst you don’t compare your infrastructure:

  • missing an S3 trigger to SQS or a Lambda feature
  • missing an EventBridge rule to route occasions to the true targets
  • missing a Lambda IAM position update to use a brand unusual AWS carrier
  • inaccurate CORS or authorizer configuration in API Gateway

One of many supreme inquiries to respond to is: when discontinue you might per chance perchance perchance even be attempting to wish to search out out about these errors?

  1. While writing and working your tests?
  2. While engaged on a characteristic and the developer manually attempting out their characteristic?
  3. In your Continuous Integration lag by blueprint of some E2E integration take a look at suite?
  4. In a shared deployed environment, a lot like dev or staging?
  5. Or within the worst case scenario: in production?

We determined to full it as soon as which you might per chance perchance be like: while writing and working tests.
What this skill is that the debate of “might per chance perchance also objective still you mock cloud dependencies or embody the cloud” became no longer in truth a inquire.
Having our Lambdas use AWS mocks or some localhost emulation still leaves loads to be desired when it comes to “will it in truth work” when deployed.
Gareth McCumskey’s Why native pattern for serverless is an anti-sample blog post captures the “emulate vs. use the cloud” debate moderately successfully, and I’d extremely counsel studying it.

The finest implication of constructing against the cloud is the need for cyber net access to successfully write code. While this might per chance perchance perchance be an unacceptable alternate-off to a pair of corporations or folk, for us as a some distance-off-first firm, we require cyber net access to communicate with our colleagues in consequence of this truth there might per chance perchance be very few situations when folk didn’t have network connectivity.

With the general precept that we are attempting to be constructing against the cloud and no longer attempting to construct a local developer expertise, we situation out evaluating a good deal of tools and technologies to search out out what works for us.

The 🌈 magical 🌈 stack

SpongeBob SquarePants drawing a rainbow with his hands
by blueprint of GIPHY

So what does our magical AWS serverless developer expertise seek for admire? At a excessive stage the following construct up the predominant components:

  • Each developer has their very have personal AWS fable
  • AWS CDK to develop our infrastructure and Serverless Stack (SST) to procure a truly speedy solutions loop
  • Writing considerably extra integration tests than unit tests
  • Stout-stack TypeScript

Adopting these technologies and practices yields a dazzling colorful developer expertise.

Internal most AWS accounts

When going fat serverless, each and every developer having their very have personal sandbox AWS fable is a must.
As previously talked about, to construct most functions it’s no longer enough to jot down the code, there’s a range of infrastructure that need to be developed, modified, and tested.
Having personal AWS accounts lets in each and every developer to experiment and develop with out impacting every other engineer or a shared environment admire pattern or staging.
Mixed with our solid infrastructure as code use, this lets in each person to have their clone of the production environment.

That you just might per chance perchance perchance perchance be thinking: isn’t that pricey?
Obtained’t we be paying heaps of of bucks to AWS? Nope—no longer with serverless solutions!
The genuinely serverless solutions are all pay per usage, so if your AWS fable has zero process, shall we embrace thru the evening and weekend when engineers aren’t working, then you acquired’t pay a dime.
There are a pair of exceptions to this, a lot like S3 storage, DynamoDB storage, RDS storage, Route53 hosted zone, and so forth. charges, however they’re inclined to be minimal.

To illustrate, Easy’s January bill for our 7 developer accounts became a full of $150—pennies in contrast to the developer lag we succeed in by each person having their clone of production.
On occasion, the supreme cost for every and every developer is our relational database: Amazon Aurora Serverless v1 PostgreSQL.
It robotically scales up when it receives requests at some stage in pattern and the general system down to zero after 30 minutes of instruct of no process.

Screenshot of AWS bill for 7 developer accounts
The total bill for every and every developer fable’s AWS usage.
Breakdown of one AWS account’s usage
Breakdown of my AWS fable’s usage
(Uncover: the excessive CloudWatch charges are in consequence of evaluating observability tools and platforms in January)


With all of our functions considerably reckoning on cloud belongings, having our infrastructure defined as code and version managed is a laborious requirement.
We on the muse looked at tools admire Terraform, Pulumi, Serverless Framework, AWS SAM, however they either required us to be taught unusual programming or templating languages, or the developer expertise of the fat characteristic lifecycle wasn’t up to our expectations.

Support in March 2021, we stumbled upon Serverless Stack (SST) when it became still version 0.9.11.
What sold us today became their reside lambda reloading characteristic and being built on AWS CDK. SST and AWS CDK lend a hand TypeScript natively, so it successfully fits into our fullstack TypeScript favor.

Are residing lambda pattern allowed us to jot down our Lambda code and have our integration tests lag utilizing reside AWS companies with a 2-3 second solutions loop. SST replaces your lambda with a shim that proxies down all Lambda invocations by blueprint of Websockets to your native developer machine, which will invoke other AWS companies and returns with a response. The native runtime uses the AWS Lambda execution position’s permissions to construct AWS API calls to actual companies, so we had been moderately assured that the switch would work when deployed to production.
Overall this meant that we caught infrastructure components extremely like a flash in contrast to mocking or emulation.

Live lambda development architecture overview
Are residing lambda pattern architecture overview. (Source: docs.serverless-stack.com)

The implication of this setup is that we are capable of discontinue obliging fat-stack pattern with out problems.
We can point our React frontend utility to a non-public AWS fable’s deployed API Gateway URL and switch both the frontend and backend on the identical time with both codebases reside reloading.
On condition that the full lot is deployed and utilizing the identical AWS companies that the production environment uses, our frontend utility entirely works with out wanting workarounds.

While it became quite dangerous to exercise to construct our backend stack on a (on the moment) slightly unknown utility, we knew that we had the AWS CDK bound hatch. If we ever stumble upon one thing that SST doesn’t lend a hand or we don’t admire, lets as an different use a truly inclined AWS CDK achieve. This gave us the most efficient stability between an unparalleled developer expertise by SST with the maturity, characteristic richness, and first celebration lend a hand of AWS CDK.

Serverless Stack also has some unparalleled functions admire:

  • Losing damage components into your Lambda code and debugging for your native IDE. Right here is helped by the --develop-timeout flag which increases all Lambda timeouts to 15 minutes. When you’re drawn to this take a look at out the docs or this video.
  • Detecting infrastructure adjustments and prompting you to deploy them, i.e. getting as conclude to reside reload as which you might per chance perchance be like. Deployments still take quite of time because it’s Cloudformation below the hood.
  • A net based essentially based fully console (SST Console) to visualize your stacks, Lambdas, S3 buckets, moreover to the flexibility to replay person Lambda occasions.
  • Auto-exporting eradicated Cloudformation stack outputs: we bumped into this plenty of situations earlier than and it became a disaster as we in most cases seen too unhurried.
  • An ever-rising library of constructs

SST’s Slack neighborhood has also been very necessary at any time when we encountered components, had questions, or characteristic requests. Frank, Jay, Dax, and the neighborhood are repeatedly delighted to assist. I’d extremely counsel giving SST a attempt because it’s laborious to search out anything that works so successfully.

Checking out

Early on we had an ambition of getting fat self assurance in our take a look at suite.
If our CI goes inexperienced then it also can objective still be protected to deploy that switch to production—which is precisely what we discontinue on merge to the foremost branch.
To full this we determined to point of curiosity our attempting out efforts on a mighty integration take a look at suite in set of unit attempting out person lambda capabilities or exiguous code blocks.
This might per chance perchance also objective seem admire atrocious observe or going against the outdated attempting out pyramid.
But when we stumble upon step-switch innovation, a lot like serverless, it’s most essential to inquire reward practices to hunt for if those practices still construct sense.

To be fully determined: we discontinue write unit tests the place it’s some distance luminous.
The place we now have got some alternate common sense or calculation then we discontinue write an exhaustive unit take a look at suite.
An instance is our core customer instruct machine having a unit take a look at for all which you might per chance perchance be like states and instruct transitions.
But unit attempting out things admire SQL queries, AWS API calls, or our GraphQL requests is for sure off the table because it yields itsy-bitsy actual-world assurance.
What you discontinue up attempting out is a range of implementation detail and declaring excessive wonderful mocks or emulation is a range of effort that’s no longer gradually value it.

To place it in numbers, our fresh take a look at suite ratio is set 30% unit tests and 70% integration take a look at situations.

2 unit tests. 0 integration tests pic.twitter.com/V2Z9F4G1sJ

— DEV Neighborhood 👩‍💻👨‍💻 (@ThePracticalDev) January 14, 2016

Our integration tests are designed and written in a mode whereby they’ll be reasonably speedy and take a look at for behaviour and no longer for implementation. What this skill is that we strive to lead determined of asserting on interior implementation most necessary components, such because the info kept in DynamoDB or RDS. As a replacement we point of curiosity on verifying externally (from the Lambda’s point of imprint) viewed behaviour, a lot like API responses or occasions being published. For our occasions, we blueprint the road at attempting out completely that an match has been published and no longer asserting all downstream shoppers. We write separate integration tests for every and every user. It also requires us to retain practical domain boundaries in our code to be definite that that each and every domain might per chance perchance also furthermore be tested independently.

Integration testing architecture
Integration take a look at boundaries

This strategy of writing tests also has the finest thing about being capable of be lag against shared environments. We presently have a fat integration take a look at suite working against our pattern environment on post-deploy merge to predominant and on a time table to detect flaky tests. There’s nothing stopping us from also working these staunch identical tests in our production environment as successfully. In idea, lets delete 100% of our code, rewrite all of our Lambdas in Delphi and as long as our integration take a look at suite passes lets ship it to production. (Uncover: we’ve but to accomplish that and don’t realizing on it anytime soon).

A conventional GraphQL API integration take a look at for a inquire or mutation roughly does the following:

  1. Demand a user from a pool of authenticated users (we bumped into some quotas and limits with our id supplier)
  2. Compose a brand unusual workspace so as that there’s a orderly instruct
  3. Direct up the instruct for the take a look at, a lot like create a customer, send a chat message, and so forth.
  4. Form the GraphQL inquire
  5. Verbalize the GraphQL response
  6. In the case of mutations: grunt any occasions that should always were published
convey('create remark mutation', () => {
  it('might per chance perchance also objective still create an argument', async () => {
    const testWorkspace = await testData.newWorkspace();
    const ctx = await testData.testAggregateContext({ testWorkspace });
    const issueType = await issueAggregate.createIssueType(ctx, {
      publicName:  'Flee of the mill components',
    const customer = await customerAggregate.createCustomer(ctx, factories.newCustomer());

    const res = await testWorkspace.owner.graphqlClient.demand(CREATE_ISSUE_GQL_MUTATION, {
      input:  { issueTypeId:  issueType.id, customerId:  customer.id },

      createIssue:  {
        remark:  {
          id:  jestExpecters.isId('i'),
          issueType:  { id:  issueType.id },
          customer:  { id:  customer.id },
          set:  IssueStatus.Open,
          issueKey:  'I-1',
        error:  null,

    await testEvents.expectEvents(testWorkspace, [
        actor: testWorkspace.owner,
        payload: {
          eventType: 'domain.issue.issue_created',
          version: 1,
          issue: res.createIssue.issue,

A conventional EventBridge match listener integration take a look at would:

  1. Direct up any required instruct (that is extremely dependent on the staunch Lambda)
  2. Publish an EventBridge match onto a bus
  3. Wait and demand the side effects, which might per chance perchance be:
    1. Every other EventBridge match being published
    2. Direct in a datastore being updated (i.e. in DynamoDB, RDS, S3)

When you’ve ever written any integration take a look at attempt to be screaming for your head: working all this might per chance perchance also objective still be so uninteresting!
They’re positively slower than unit tests, however no longer unbearably uninteresting.
For the reason that total companies we use are serverless, and we be definite that our integration tests have 0 shared instruct we’re capable of working all of our tests in parallel.
We haven’t long gone to this level of optimisation, however shall we embrace our CI with a parallelism of 40 runs 656 take a look at situations across 110 take a look at suites in quite below 2 minutes exhaustively integration attempting out each and every corner of our utility.

Integration testing architecture
Integration take a look at suite results from our CI

Integration take a look at flakiness is but every other thing we actively kind out by working our tests on a time table at some stage within the work week.
If we ever procure a take a look at failure, we jump on the remark and video display down the root explanation for it.
This also spirited rethinking and restructuring how we take a look at definite things, admire GraphQL subscriptions, in a mode which is mighty and reputable.

We completely factual dipped our toes into our integration attempting out setup, this subject is for sure righteous of its have post.
That acknowledged, given that our API is a key allotment of our product, having each and every GraphQL inquire and mutation integration tested is important.
We reflect the alternate-off of getting a rather slower take a look at suite and a noteworthy greater self assurance that the characteristic or switch will work precisely is value it.

Stout-stack TypeScript

While utilizing fat-stack TypeScript isn’t strictly important to have a immense developer expertise on AWS, it in truth makes our group noteworthy extra positive. The ability to pass between the frontend, backend, and infrastructure code with out having to be taught a definite language is efficacious to each and every member of the group.

You continue to must be taught the AWS companies when constructing backend code, however that is natural when working with anything. You likewise must cherish CSS / HTML to develop frontend net capabilities. With SST and CDK in TypeScript, after you’ve realized what AWS companies you’d are attempting to use the TypeScript kinds and the editor’s autocomplete e book you in defining the lawful infrastructure.

We have most of our backend codebase in a single monorepo and use a handful of libraries a lot like pnpm, zod, lawful-delusion, swc to construct our code even better to work with, however extra on that in a future post!

Striking it all together

So what does this seek for admire in observe? Let’s take a seek for at what making a switch looks admire:

On this instance we created a workspace in Easy by blueprint of our core GraphQL API. This verified that E2E the API call works:

  • User fetched a superior JWT from our id supplier
  • AWS API Gateway handled the GraphQL demand and verified the validity of the JWT
  • The GraphQL Lambda created a brand unusual workspace in our Aurora Serverless PostgreSQL database and published an match to EventBridge
    • This verified that the Lambda has the lawful IAM permissions to be taught/write from PostgreSQL and submit to EventBridge
  • A winning response became returned to the client


Combining these technologies and practices skill we are capable of point of curiosity on transport functions:

  • In isolation with out impacting other engineers in consequence of each person having their very have AWS fable.
  • With a short solutions loop utilizing reside AWS companies gleaming that this will work when deployed, in consequence of SST and reside lambda pattern
  • With out problems develop serverless infrastructure with CDK
  • Beget excessive self assurance in correctness, in consequence of our integration attempting out
  • Not having to be taught a definite programming or templating language when switching between frontend, backend and infrastructure.

Might well perchance it be better? There’s positively room for inform, however I reflect that is already moderately 🌈 magical 🌈!
When you might per chance perchance perchance also objective have any questions or know of suggestions we are capable of construct our stack even better, procure in contact with us on Twitter at @builtwithplain or me at @akoskrivachy.

When you’re drawn to working with our 🌈 magical 🌈 tech stack take a look at out our fresh opening on Easy’s Jobs net page.

Read More

Ava Chan

Ava Chan

I'm a researcher at Utokyo :) and a big fan of Ava MaxBio: About: