Over time, I have learned that the promises of most new and shiny platforms are legitimate, but the downsides are rarely as well understood until you roll up your sleeves to build something with it.
I gained some first hand perspectives recently after building cloud functions for two new Sidekick features.
- When was I here? — Sidekick now allows you to turn back the clock and see when you last visited a particular restaurant or landmarks. E.g. you can ask Sidekick: when was the last time I visited CN Tower? If you have location history enabled in Google, you can also import those into Sidekick so you can go back in time. (released this week on iOS)
- Which route should I take? Google, Apple or Microsoft ? — Sidekick will compare routes generated by different providers so you always get the best results without needing to choose one app to use. (in Beta)
Both features were built using Google’s Cloud Functions. But the lessons learned are generic enough to AWS Lambda or Azure Functions users.
Upsides (are they real?)
- Zero installation to develop/test server side code? NO. Technically, you can write code using VSCode and directly deploy to the cloud, but the build/deploy/test/debug cycle would take too long (3+ minutes). I ended up spending time getting the emulators running locally, iterate locally, and then push to cloud for final verification.
- Auto scale? YES. To handle more users, you just need to watch your budget. (more on this later when the resource demand for handling one user requests changes.)
- Runtime isolation? YES. You can stop worrying about one request affecting the processing of another request as in traditional JEE or .NET server runtimes.
Downsides (don’t let these surprise you)
- Limits — Left, Right and Centre: They are, by definition, harmless until you exceed them. But there are LOTS of them; ranging from payload size, function counts, query string size, memory usage, storage usage, CPU time, frequency per region… the list goes on. It’s hard to keep them in your head so you can shape your solution to avoid running into brick walls. I ran into the 10Mb request size hard limit on Firebase CF and had to do some gymnastics to workaround it. See it for yourself: Limits for AWS Lambda, Azure Functions, Firebase CF, GCP. On top of the technical limits, you will also have to keep an eye on the billing limit when you exceed your cap on spending. Your function won’t run if it will exceed allocated budgets.
- The NodeJS execution environment (v8/v10 in Google, v10/v12 in AWS, v10/v12 in Azure) are not vanilla Node. Some popular node packages (e.g. formidable, BodyParser) could be incompatible with them. This is not a showstopper. There are usually alternatives, but it did take me quite some head-scratching to figure out why they don’t behave correctly in CF. And because CF is still young, there are not enough Q&A knowledge base in Stack Overflow yet. In addition, NodeJS release is happening very quickly these days, so documents do become obsolete quickly. (v14 as of June 2020)
- Configuration and tuning parameters are inside your code: Want keep-alives? Add it to your function’s property. Need more memory for handling your request. Yep, specify it in your environment JSON. Even though it’s serverless, it doesn’t mean you don’t have to study/understand the execution environment to use it correctly and efficiently.
Current State (June 2020)
For some scenarios, Cloud Function may be your only option (e.g. code that respond to cloud events such as new files uploaded to bucket, database triggers. So, it’s a good time to build up knowledge on how to do it right.
Having said that, for my bread-and-butter http request/response services, I am staying with my existing toolset and runtime. IMHO, cloud function’s zero-configuration promise is not worth the new headaches it introduces.
Hope this helps, and until next time.