AWS Lambda Function Design Best Practice

When designing AWS Lambda’s, try to keep the side effects low. Think of your handler function having just 1 IO type. Just like a list can be typed as Array[string], try keeping just one IO type as well.

Function:

const handler = async event => {...}

Type:

Event -> IO[String]

I know this is hard. If your function does even just 2 things, like reading a file from S3, then writing it to Dynamo, that’s 2 IO events. Still, that’s just 3 possible responses: it worked, S3 failed, Dynamo failed.

You’ll be quite surprised at first how quickly “just 1 function” grows in complexity. If you’ve experienced “big ball of mud” or “big code base that has no friends”, you’ll get WHY you start so small on purpose.

AWS Lambda best practices encourages small, stateless functions. To say it more formally, they encourage small file size pure functions, with as little IO as possible.

It may be easier to co-locate code in 1 Lambda even if it creates more side effects for ease/speed reasons, which is ok.

If Python, use returns library with the IO marker for mypy.

JavaScript, return a Folktale v2 Result in a Promise.

TypeScript, use fp-ts with their IOEither (they’ll encourage a chain, but inside a Promise is ok).

Scala, ZIO has all kinds of IO types to choose from.