Serverless computing with Python

On Feb, 22nd I had the privilege of talking in front of the Barcelona Python Meetup regarding serverless computing (AKA FaaS) and the findings that I have been collecting over the past months while discussing with the technical teams of several online businesses with which I have been working. If you are interested, the slides can be found here.

Through the conversations held, I have realized that even though there is a generalized trust in the technology behind FaaS (almost nobody with whom I spoke to showed concern for its reliability), the size of the organization somehow dictates the main areas of concern when it is to be implemented. The smaller companies were more worried with the engineering aspects while the more enterprise-style organizations kept an eye on the more strategic facts such as being able to switch providers.

Provider independence

With FaaS, there is no such a thing as provider independence. Not only there is no standard API or uniform runtime support, but also the event-types a function can respond to depend on the Cloud Provider you use. If you are worried about this, if your business requirements include the capability to promptly migrate from one cloud provider to another, you are probably limiting yourself to using more conventional computing models such as IaaS.

With more realistic goals in mind, however, such as being able of a gradual transition between technology stacks, good architectural practices should be of great help.

Architecture comes to the rescue

As Bob Martin often says, databases and frameworks should be implementation details. I cannot see why this should not apply also to the fact of having our systems running on a specific FaaS provider or even to having them running on FaaS at all. A properly defined architecture that offers a clear separation of concerns will allow us to put the platform-specific details on the outer layers, where they cannot affect our business logic.

As we can see in the diagram above, by using Clean Architecture, Ports and Adapters or similar approaches, events get translated into calls to domain operations within the Controllers stratum.

What is the purpose of the serverless frameworks then?

Despite my initial expectations, I have found that toolkits like serverless or Claudia.js, offer mainly a set of tools to manage the release and other operational processes. However, there is very little abstraction they can provide and, as a result, they hardly have any influence in our code. As an interesting exception, Claudia.js offers a JavaScript API builder for AWS Lambda.

Bearing in mind that there are a number of tools that enable us to manage our infrastructure as code, like terraform, SaltStack or even AWS CloudFormation; should we add the aforementioned newcomers to our kit? Well, being aware of how difficult it is to create a software component like Terraform and the capabilities that it provides both for FaaS and IaaS environments, I would rather prefer that my organization invests in developing consistent skills in mature, flexible tools than in these serverless frameworks since, for the moment, I feel they are a little bit limited.

Complexity

The fact of using FaaS, per se, does not dramatically increase the complexity of a software system. However, incrementing the number of moving parts does. We need to be careful, therefore, not to have so many of them that we are blocked from understanding how our software behaves.

Also, at the moment, there are well-known techniques that help us to model microservices-based architectures that address the usual business problems. On the other hand, I am a little bit worried on how these techniques can be overused in a FaaS-only environment.

Python in the world of FaaS

Currently, Python runtimes are supported by AWS Lambda and Azure Functions but not by the Google version of the service. It is a pity the language support is not more widespread since, as you can see in the slide deck above, Python is very well suited to host our serverless subsystems. The __call__ magic method and the ability to extend functions via decorators have proven to me to be extremely useful.


class App(object):
  def __init__(insert_ctrl):
     self.insert_ctrl = insert_ctrl
     
  @tools.aws.json(body=True)
  def __call__(self, request, context):
     return {"statusCde": 200, body: {"status": "ok"}}
     
handler = App(InsertCtrl())

Take aways

  1. If you use FaaS, you should forget about 100% provider-neutral code.
  2. A good software architecture will make things much more manageable and portable.
  3. Python abstractions help a lot when working with FaaS (when there is provider support for the language). Particularly, the __call__ magic method and the decorators.
  4. Serverless frameworks are, in my opinion, not as mature as other infrastructure as code tools.

My conclusion: if you have a good engineering team that fully understands that there are no silver bullets in the software world, I do not see why you should not start experimenting with the FaaS model in controlled risk projects. To manage them, I would suggest that you use mature infrastructure as code software. In any case, I would take special care not to turn my system into a miriad of unmanaged functions that run on unexpected situations.