Ask HN: Does anyone else find the AWS Lambda developer experience frustrating?
I've been using AWS lambda a bit recently, mostly as a way to glue together various bits and pieces.
Maybe I'm doing this wrong but does anyone else find the experience to be really frustrating?
I can unit test bits of the code just fine, but at some point I always end up stuck in a slow feedback loop where I deploy the code, do some manual invoking, go and dig through the logs in CloudWatch, add another print statement in my lambda... and so on.
What I want is to run the lambdas locally, ideally more than one, and then exercise them with streams of test events (perhaps captured from a real environment). It would be quite cool if I could define BDD style tests around them too.
Anyone have any suggestions or share my frustrations?
I have heard localstack is quite good although I haven't given it a go yet. Would that work for me? I did try SAM but I was a bit underwhelmed and I don't want to use a separate IaC tool for these.
Alternatively, do other FaaS providers solve this problem?
Thanks for any help.
[+] [-] jiggawatts|5 years ago|reply
Programming in the 1960s to 80s was like this too. You'd develop some program in isolation, unable to properly run it. You "submit" it to the system, and it would be scheduled to run along with other workloads. You'd get a printout of the results back hours later, or even tomorrow. Rinse and repeat.
This work loop is incredibly inefficient, and was replaced by development that happened entirely locally on a workstation. This dramatically tightened the edit-compile-debug loop, down to seconds or at most minutes. Productivity skyrocketed, and most enterprises shifted the majority of their workload away from mainframes.
Now, in the 2020s, mainframes are back! They're just called "the cloud" now, but not much of their essential nature has changed other than the vendor name.
The cloud, just like mainframes:
- Does not provide all-local workstations. The only full-fidelity platform is the shared server.
- Is closed source. Only Amazon provides AWS. Only Microsoft provides Azure. Only Google provides GCP. You can't peer into their source code, it is all proprietary and even secret.
- Has a poor debugging experience. Shared platforms can't generally allow "invasive" debugging for security reasons. Their sheer size and complexity will mean that your visibility will always be limited. You'll never been able to get a stack trace that crosses into the internal calls of the platform services like S3 or Lambda. Contrast this with typical debugging where you can even trace into the OS kernel if you so choose.
- Are generally based on the "print the logs out" feedback mechanism, with all the usual issues of mainframes such as hours-long delays.
[+] [-] andreineculau|5 years ago|reply
When it comes to Lambdas, given the reasons above, there's only one thing that can improve the experience: PROXY. Before i went on parental leave i had the idea is creating a proxy lambda which can be configured with an IP and port number. That IP and port is for your local dev environment. This way, when developing you can instruct a live system to short-circuit and to proxy calls to a local lambda available om the respective port. Trigger end-to-end tests by invoking AWS services that will eventually call the proxy lambda, and then your local lambda with the same environment/context/input, reply with output which will reach the proxy lambda, which will output the same content forward.
[+] [-] iends|5 years ago|reply
In my own work with serverless I think about this a lot. In my day job, we built a new service and we pay AWS a few dollars per month to run. It would have cost us around $100 a month in AWS costs. However, the operational complexity is extremely high and we are also coupled to another service via Kinesis. For a billion dollar business, the trade off doesn't seem worth it.
I wonder how much of serverless is just AWS firing at Google (and Heroku, DO, etc) and other competitors. It certainly hasn't made my life as a developer easier. It's certainly much cheaper for some use cases but the complexity of the system goes up very quickly, and you're end up having to manage a lot of that complexity using an inferior tool like Cloud Formation (or Terraform).
[+] [-] orf|5 years ago|reply
It depends on what you mean by "serverless". Serverless webapps? Sure, maybe a fair bit. But the real killer feature of the Lambda service is that it's a universal extension mechanism for other AWS services. Want to run some shoddy virus scanning whenever an object is added to a bucket for compliance reasons? That's a lambda. Want to manipulate Firehose records before they are sent to the sink? That's a lambda. Want to execute some crazy Python function from an Athena SQL query? You guessed it. That's a lambda.
So when you say "It certainly hasn't made my life as a developer easier" it means you haven't needed to do these bespoke gluing together of stuff, because "being able to do this somehow" is infinitely easier than "not being able to do it at all because AWS hasn't exposed an API for this use case".
[+] [-] mattmanser|5 years ago|reply
Appropriate for a small amount of apps, but used inappropriately by a lot more for a while because it's the hot new thing.
[+] [-] rualca|5 years ago|reply
The complexity bogeyman is a red herring. What is software development if not a constant fight between increasing complexity and adding features, including making systems more robust and resilient and reliable?
Sure, you are free to claim that function-as-a-service paradigm is very complex because the code runs somewhere else, and you have to use a separate workflow than the one you're used to, and that you actually have to write unit tests to have some assurances that stuff does work as expected.
But what would be the alternative approach?
Would it be simpler to write a full-blown service that polls events and listens to message queues and launches background tasks? Obviously, no.
AWS Lambda is a fancy way to let developers develop event-driven systems by just writing tiny event handlers and plug in events. It's no rocket science. In terms of complexity, they pale in comparison with even the tiniest hello world windows GUI app, or even Qt. I'm terms of web services, they are a service where you just have to write the request controller bit after that runs after all auth things passed and request messages were parsed and validated. Considering this, isn't it unreasonable to talk about increasing complexity, when everything was made.far simpler than what it would otherwise be?
[+] [-] anfrank|5 years ago|reply
I often see ppl adopt one of two development patterns:
1. Locally mock all the services that your Lambda function uses. Like API Gateway, SNS, SQS, etc. This is hard to do. If you are using a tool that mocks a specific service (like API Gateway), you won't be able to test a Lambda that's invoked by a different service (like SNS). On the other hand a service like LocalStack, that tries to mock a whole suite of services, is slow and the mocked services can be out of date.
2. Or, you'll need to deploy your changes to test them. Each deployment can take at least a minute. And repeatedly deploying to test a change really slows down the feedback loop.
SST lets you develop your Lambda functions locally while connecting to others AWS services without needing to mock them locally. Behind the scene, the lambda requests are streamed to ur local, runs ur local function, response streamed back to Lambda. So you can iterate on ur function code without redeploying.
Think of your Lambda functions are Live Reloaded. You can see it in action here — https://youtu.be/hnTSTm5n11g
I’m the core maintainer of the project. And folks in our community are saying using SST feels like "working in the future" ;)
I'd love for you to give it a try. We are also a part of the YC W21.
[+] [-] davmar|5 years ago|reply
Also, this guide they put together is definitive: https://serverless-stack.com/#guide
Had I found that years ago, I would have saved SO MANY headaches. I've implemented local debugging (hell, and doesn't actually replicate AWS). I've followed the CloudWatch logs, just like you, painful.
The SST local debugging with lambda is the best way forward. Deploying micro services on seed.run is also the way forward.
[+] [-] tdfirth|5 years ago|reply
I'll check it out!
[+] [-] superchink|5 years ago|reply
[+] [-] windowshopping|5 years ago|reply
[+] [-] ufmace|5 years ago|reply
[+] [-] dragonwriter|5 years ago|reply
The purpose of the AWS Console, AFAICT, is:
(1) To be used by semi-technical ops and management types, and people doing tutorials, and
(2) To drive everyone else as quickly as possible to the APIs/CLIs/SDKs.
[+] [-] tdfirth|5 years ago|reply
If I'm honest, I do find AWS in general fairly high friction at times but it's way better than renting servers directly I think.
It's the only cloud provider I've really worked with to be honest though (other than a few experiments), maybe some others are much better in this regard?
[+] [-] picardo|5 years ago|reply
[+] [-] cpach|5 years ago|reply
I’ve been thinking a lot about AWS lately and it definitely seems to me like a modern take on what IBM did in the 80’s.
[+] [-] vangelis|5 years ago|reply
[+] [-] bamboozled|5 years ago|reply
[+] [-] StratusBen|5 years ago|reply
[+] [-] fookyong|5 years ago|reply
I run my lambdas locally with a single command: serverless offline
If the lambda has an http endpoint, it creates the endpoint at localhost/<endpoint> and I'm good to go, it even does live reloading as I edit my code.
If the lambda runs off AWS events, I can invoke the lambda locally with a command, and point it to a JSON file of a simulated AWS event. I get my local rails app to create these AWS event JSON files, so that I can test end to end locally. Works well for my purposes.
To deploy I just run: serverless deploy --stage production
Which sets up all the necessary additional services like API Gateway, cloudwatch etc.
I can't imagine using AWS lambda any other way.
[+] [-] innomatics|5 years ago|reply
AWS provides a docker image for emulating DynamoDB which works great for local dev and will commonly be paired with lambdas.
Another option I have used recently for implementing node web services is https://github.com/apex/up which also has a nice local dev experience.
[+] [-] tdfirth|5 years ago|reply
[+] [-] wharfjumper|5 years ago|reply
[+] [-] astashov|5 years ago|reply
It was surprisingly hard - the local development of lambdas is still very raw, documentation is scarce, and there are various small issues appearing here and there. I should probably write a blogpost about how to setup decent developer environment for AWS CDK and Lambdas, because there's not much on the Internet about it.
I set up the whole AWS infrastructure via AWS CDK. I have one TypeScript file, that creates a stack with lambdas, dynamodb tables, API gateways, S3 buckets, wires up the secrets manager, etc - all of that in 2 environments - dev and prod.
AWS CLI also can generate a Cloudformation YAML file from the CDK file (via `cdk synth`), which could be fed into SAM. So, I generate a `template.yaml` Cloudformation file this way, then run SAM like `sam local start-api`, and it runs exactly the same lambda locally, as in AWS, using that Cloudformation YAML file. SAM also supports live reload, so if you change any source files, it will automatically get those changes.
So, okay-ish developer experience for lambdas is possible. There're caveats though:
* I couldn't figure out how to use "nameless" Dynamodb tables (i.e. when CDK assigns the name to them automatically), because if I omit a table name in CDK template, then the local lambda and lambda in AWS assume different names for some reason.
* Locally, the binary outputs don't work. It ignores `isBase64Encoded` by some reason, and lambda just returns Base64 output, instead of binary.
* And the main problem - local lambdas are SLOW. It seems like it restarts some container or something under the hood on each API call, which adds 2-3 seconds to each API call. So, the calls that should be like 30ms, are actually 2 seconds now. This is super frustrating.
[+] [-] vinnymac|5 years ago|reply
Each use case is so unique, that it is likely difficult for them to account for every single situation where Lambdas are being used. Instead they opt for a generalized and non-specific documentation site, which results in docs I find practically useless.
I frequently find solutions to problems for AWS on someone's obscure blog, who after many days of suffering stumbled onto the answer, rather than finding anything of use directly from those who wrote the software.
Does a site exist where programmers can submit useful findings? Similar to stackoverflow, but rather than asking for questions, you just submit answers. I would think being able to search across such a crowdsourced utility would save programmers a ton of time.
[+] [-] mkl|5 years ago|reply
[+] [-] css|5 years ago|reply
I don't know why you need to deploy to test Lambda code; you can hit remote AWS stuff from local. The AWS SDK picks up your local config's IAM role the same way as it picks up the one granted to the Lambda itself. You don't need localstack for this, just an account in your AWS organization with the right role attached.
Packaging dependencies was a little weird to figure out, but the docs [0] are very good. A simple shell script can do the packaging work; its just a few lines to make the zip file.
[0]: https://docs.aws.amazon.com/lambda/latest/dg/python-package-...
[+] [-] msluyter|5 years ago|reply
https://github.com/jorgebastida/awslogs
It allows you to stream Cloudwatch logs from the command line, so you can grep them, save them to files, etc... (The web based Cloudwatch interface is terrible.)
Another suggestion is to try to modularize the core business logic in your lambda such that you separate the lambda-centric stuff from the rest of it. Obviously, though, if "the rest of it" is hitting other AWS services, you're going to hit the same testing roadblock.
Or you can try mocking, which may or may not provide much value for you. There's a python library for that, (moto), but it's not 100% up to date wrt AWS services/interfaces, last I had checked. Might be worth a try though.
https://github.com/spulec/moto
[+] [-] wharfjumper|5 years ago|reply
[+] [-] endgame|5 years ago|reply
1. If you are building APIs and using Lambda functions as targets from an API Gateway API, look into libraries like serverless-wsgi (Python) or wai-handler-hal (Haskell) that translate between API Gateway request/response payloads and some kind of ecosystem-native representation. Then as long as you're writing code where all state gets persisted outside of the request/response cycle, you can develop locally as if you were writing for a more normal deploy environment.
2. Look into the lambda runtime interface emulator ( https://github.com/aws/aws-lambda-runtime-interface-emulator... ). This lets you send invoke requests to a fake listener and locally test the lambda more easily. While the emulator is provided in the AWS container base images, you don't need to run it inside a container if you're deploying with zip files. (AWS-provided container images automatically enable the emulator if not running in a lambda runtime environment, and using docker for port remapping, which is nice but not at all required.)
3. Get really good at capturing all requests to external services, and mocking them out for local testing. Whether this is done with free monads, effect systems, or by routing everything through gateway classes will depend on your language and library choices.
[+] [-] dmlittle|5 years ago|reply
[1] https://github.com/lambci/docker-lambda
[+] [-] tdfirth|5 years ago|reply
As you say, it only does the 'host lambdas locally' bit though. If you wanted to do stuff like test the interactions between lambdas, or test them over HTTP (for lambdas that act as components in REST APIs), you'd need to build something yourself.
[+] [-] sonthonax|5 years ago|reply
AWS has Step Functions, which is a vaguely functional and declarative language for linking your lambdas together. It’s a bit verbose and annoying to write, but at least a it makes your lambada setup repeatable.
The state machine which actually runs your step functions is publicly available.
https://docs.aws.amazon.com/step-functions/latest/dg/sfn-loc...
[+] [-] coredog64|5 years ago|reply
[+] [-] _6pvr|5 years ago|reply
We have containers which unify local environment and production environment. In my opinion (and experience), there aren't any more efficient shared mediums to work with.
[+] [-] kaishiro|5 years ago|reply
However, in response to your specific pain point - after initializing a new functions project you can immediately run an 'npm run serve' and have local execution firing for any scaffolded endpoints. These - by default - will connect to a project associated RTDB/Firestore instance without the need for additional service account/IAM configuration.
I've always enjoyed that this was a part of the mainline dev flow - and it removes a huge barrier of entry for me (mostly mental) to spin up little toy projects or test endpoints whenever the thought crosses my mind.
[+] [-] unknown|5 years ago|reply
[deleted]
[+] [-] wussboy|5 years ago|reply
[+] [-] sharms|5 years ago|reply
[+] [-] tdfirth|5 years ago|reply
[+] [-] mozey|5 years ago|reply
In principle I try to avoid Amazon Web Services that lock me into the platform. So, for my dev stack I run a few other containers to give me the equivalent of the prod environment, RDS (MySQL or PostgreSQL), ES (OpenDistro), S3 (Minio), and SES https://github.com/mozey/aws-local
Dev is easy because I can test everything locally, and the resulting code should be portable to any other cloud.
Obviously this approach might not be feasible if you choose to use AWS that do not have equivalent self-hosted options.
[+] [-] i_v|5 years ago|reply
[1]: https://docs.aws.amazon.com/lambda/latest/dg/images-test.htm... [2]: https://github.com/aws/aws-lambda-runtime-interface-emulator
[+] [-] jmb12686|5 years ago|reply
[+] [-] rezonant|5 years ago|reply
[+] [-] reilly3000|5 years ago|reply
‘aws lambda invoke -e myevent.JSON’ goes a long ways, because you get the full response object back.
[+] [-] fifthofeight|5 years ago|reply
[+] [-] tdfirth|5 years ago|reply
Cosmotic's comment kind of confirms my suspicions to be honest.
[+] [-] anfrank|5 years ago|reply
I posted elsewhere in this thread but checkout SST (https://github.com/serverless-stack/serverless-stack), it lets’ you work on your Lambda functions live without having to mock AWS services locally. Here’s a short demo (https://youtu.be/hnTSTm5n11g)
[+] [-] cosmotic|5 years ago|reply
[+] [-] notsureaboutpg|5 years ago|reply
[deleted]