Just when you thought it was safe to go ahead with microservices... along comes serverless
The Dark Souls* of code-wrangling
We all know, and have probably even coded, monolithic applications – software made of big old chunks of code. Supposedly these are giving way to microservices, smaller elements of functionality. But don't get too comfortable because it's time to shake things up again: now we have serverless.
The theory is to create single units of functionality that are developed in isolation of each other.
The promise is for an application that scales directly in line with demand. When a request is made to an HTTP endpoint, a very specific function is executed for handling exactly that request. Once complete, the compute resources are surrendered.
That's the promise, at least. Going serverless comes with a huge learning curve. You might be a solid practitioner of code, but serverless is on the extreme end of software engineering, automation, and architecture.
You've got some serious mental adjustment and relearning ahead of you.
Obviously, you can't just turn a monolith into a serverless application over night. In fact, going serverless comes with more considerations and has deeper implications than the "standard" rewrite.
A monolith comprises tightly coupled code while a serverless application is extremely decoupled. The code found in your Ruby on Rails or Django application, for example, will be hard to pull apart and make work as a bunch of HTTPS APIs. And while tools do exist to help, they aren't going to magically make this happen. Tools will help turn an existing application into a series of microservices, but ultimately you'll need to adjust how you think about the application's design and change your tactics when it comes to attacking software-design problems.
The equipment used in serverless operates very differently to your standard coding tools. A good example is the database. Most frameworks such as Rails and Django come with tools to migrate data between different versions, thus letting you perform actions such as adding a column in the database or introducing a new table.
Serverless has this too – only on a per-function basis. That is, each function should have its own database, so the tooling changes dramatically and becomes about the one function, not the whole application. You'll need a single tool for that function's specific database needs – maybe even something custom.
Keeping it continuous
One of the other hot topics right now is continuous integration and delivery (CI/CD). CI is the concept of repeatedly applying tests and checks against code as it's pushed to the central repository. Continuous delivery also reacts to changes to your code bases, but instead of testing the code, it deploys it.
Most monolithic applications have their own release processes that have been developed over time. They are often some custom script that gets executed manually during a release window. While CD isn't a thing for most monoliths, it does work for serverless – problem is, it's not as simple as just plug and play. Tools like Jenkins CI, Travis CI, CircleCI and Gitlab's own CI implementation need plenty of coaxing in the world of serverless.
Work needs to be done in areas such as being able to automatically unit, module, and integration test your code before reaching the CD stages. Unit testing is simple enough – provided you've mocked out your database and external services in the first place. Module tests are the same, but systems tests are more complex and require standing up temporary services to test everything truly works as expected. This is all before you've reached the CD stages.
Once you have reached the CD stages your tools have to be configured for this release candidate (version number, patch set, configuration and so on) and you have to be able to rollback a failed release. That means being able to A/B, or blue/green, a deployment to take into account that not everything goes to plan.
Again the tools are there to help with this, but they solve one problem and you've got to chain them all together to build a complete solution.
With serverless, you've also got so many connections to think about when writing a function that I bet most don't even consider contract testing that HTTPS API. How do you know you haven't broken the contract between your new release and everything that consumes the function's API?
Now, this problem exists in the world of monoliths too, but it's much easier to introduce spaghetti code, hacks, and bad practices to compensate. Serverless, however, can't afford that luxury. Every function is an isolated unit of business logic, and the API is like a legal contract between it and the outside world: break that contract and you'll upset a lot of people.
With a serverless application you're left having to do more extreme and pedantic levels of testing to get a CI/CD pipeline in place. This is one of the taxes that must be paid when everything is so loosely coupled.
So what are the options here? Should you just give up and forget about serverless? Yes and no.
If you have an established product or service you might be best served to start from scratch. There is so much to consider about the architecture, so much to test, a lot of components to wire together, and so many processes to put in place that forcing an older, enterprise monolith into a serverless architect will likely end in tears, wasted time, and money down the drain.
Rather, what you can – and should – do is slowly port your existing domain knowledge and customers across to a new platform. And while you're doing this, the old, trusty, money-making monolith keeps ticking over.
Bring in the clouds
Amazon Web Services (AWS) and Google Cloud Platform (GCP) also offer infrastructure that can support the serverless move.
GCP's Serverless catalogue is just as good and – in most cases – cheaper than AWS. Cloud Functions and Cloud Endpoints compete with Lambda and API Gateway and do just as good a job on rapid deployment of prototypes and production-ready web services. Cloud Functions is billed per GHz-second, a somewhat confusing way of saying for every GHz of compute used per second, and Cloud Endpoints is billed at $3 per month per 2M+ API requests handled. Keep below 2M requests and it's free. App Engine is another GCP offering aimed at a serverless deployment and per-usage based billing.
Outside these giants, there are plenty of tools. For example, Serverless Framework. It works well with several cloud providers and offers an incredibly powerful interface that can be extended to include additional functionality. In essence it's designed to abstract the APIs and interfaces used to provision cloud resources across multiple providers and make them accessible through a unified, singular configuration.
If you're a Python-only house, Zappa can be used to provision Python-based HTTP APIs in a matter of minutes. Apex is another open-source offering but only for AWS. At my last count, there are roughly 30 Serverless Framework solutions designed to help you deploy functions to the cloud.
With a good architect, the right service providers, the correct tools and an open mind, you can reimagine your software for serverless.
Just prepare for a long haul. ®
* For the grown-ups among us, Dark Souls is a notoriously difficult and popular Japanese action video game series. Journalists, who ironically aren't very good at games, have recently taken to calling particularly unforgiving titles "the Dark Souls of [insert genre]". So get out there and "git gud" at serverless.
We'll be covering Serverless, Cloud Native, FaaS and more at our Serverless Computing London Conference in November. Respond to our call for papers or buy blind bird tickets at the website here.