Choosing the right programming language is a lot like picking the right wine to accompany a meal: you need to understand how the food and drink complement each other, the occasion for which it’s being considered, and the preferences of your guests.
Let’s see how this concept applies to Azure Functions. They can be written in seven different languages that range from the objected-oriented C# and Java, to the functional F#, to the dynamically-typed JavaScript and Python, to the transpiled TypeScript, and finally, to the scripting power of PowerShell Core.
At first glance, it can seem like Microsoft added so many languages to its serverless platform to remain competitive with its main rival, AWS Lambda. And while that may be partially true, it’s not the whole story.
Almost any problem can be solved with any of the aforementioned languages. Some languages, though, are more suited to certain use cases. The choice of language isn’t so much a competition, but rather an exercise in evaluating whether a language is fit for purpose.
This article is broken up into two parts. It starts by looking at each of the languages in turn to figure out where they are best suited. The second part turns the first on its head by prescribing a high level process for selecting the right language every time.
Language Breakdown
C#
Let’s face it. For most .NET developers, C# is the go-to language to solve all. And in most cases, that reflex is probably right.
If you’re already running C#-based applications on Azure, be it in Service Fabric, containers, or anything else, it’s only logical to use the same language for your functions. Swapping parts across hosting platforms isn’t straight-forward, but it’s a whole lot easier when everything is written in the same programming language.
C# also happens to be the language with the lowest cold-starts on Azure Functions. Often times, cold start isn’t that big of a deal. But if you’re writing a publicly facing API, it probably has some requirements with regards to responsiveness. C# is the way to go in those cases.
Java
I’m not the best person to say when to use Java. I’ve barely written more than a few lines of Java in my career, and that was for an Android app. With that disclaimer out of the way, here goes anyway.
If you’re a Java shop running JVM workloads on Azure, then leveraging your existing knowledge will get you going with Azure Functions that much faster. Effectively, you’ll only need to deal with the learning curve that the serverless development model throws at you.
As it happens, Java suffers from some of the worst cold-start times on Azure Functions. For that reason, I don’t recommend using it to build HTTP APIs. But for background workers or event triggers, Java is by no means a bad choice.
JavaScript and TypeScript
TypeScript functions are transpiled to JavaScript before being deployed to Azure. For that reason, I decided to group JavaScript and TypeScript together, since they are one and the same to the functions runtime.
It’s very likely that you have a working knowledge of JavaScript already, being the lingua franca of web development. Writing JavaScript (or TypeScript) with NodeJs is a logical extension of your existing knowledge.
NodeJs is having an upsurge in popularity over the past five years. More and more developers are becoming familiar with it every day. So if you’re looking to hire developers, NodeJs should be an easy skill to find.
The lightweightedness of a NodeJs project makes it an ideal candidate for rapid prototyping and iterative development. Add in the type-security of TypeScript, the more-than-respectable cold start times, and there’s a strong argument to write most functions with NodeJs.
NodeJs is the most interesting language of the bunch if you’re interested in cross-cloud compatibility: it’s the only language supported on AWS, Azure and GCP. Porting your functions from one cloud to the other wouldn’t be trivial, but it also wouldn’t be infeasible.
F#
Many developers are curious about functional programming. We’ve all heard the selling points: it’s less error-prone, it has immutability baked-in, and makes concurrent programming that much simpler.
Still, there is a reluctance to take a dive off the deep-end with F#. In most cases, the hesitance is attributed to unfamiliarity. Committing to the development of an entire application in F# is risky when you aren’t sure of the outcome.
That’s where Azure Functions come in. Functions are typically small, do one thing, and can be quickly re-written. That makes them perfect candidates for trying F# in a low-risk, high-reward situation.
In short, Azure Functions might just be the perfect playground for exploring the possibilities of F# and functional programming.
Python
I’ve kept Python towards the end because it’s still in Preview, and therefore shouldn’t be used for production workloads. Regardless, there are some compelling reasons to use Python with Azure Functions.
Python is one of the go-to languages for data science work. Big players in the AI/ML space, such as TensorFlow, support Python as a first class citizen. The samples for Azure’s AI and ML frameworks are also in Python.
And while you might not be running TensorFlow in your functions, if you plan on doing any data science work, Python is the way to go.
PowerShell Core
PowerShell is also still in Preview. But it’s ability to automate IT operations make it hard to resist even at this early stage.
The real strength of running PowerShell functions, though, is the visibility that they bring with them. IT processes such as on-boarding, backup management, and security checks, can be turned into repeatable scripts that run automatically. The function ensures that the knowledge won’t be lost to turnover, and can be maintained by anyone through source control.
Make sure to read my full article about using PowerShell Core with serverless if you’re an IT worker looking to automate repetitive tasks.
Questions To Ask Yourself
As I researched the uses for each language within the functions runtime, I came across a few patterns that were at the core of making the right choice. Below is the process I’ve elaborated to select a language when writing a function from scratch.
Question #1: Is cold start time a factor?
In most cases, cold starts aren’t that big of a deal. Event-based triggers are unlikely to be time-sensitive. HTTP APIs can be very time-sensitive, but again, it depends on the use case.
On the other hand, every scenario is different, so if you are in a situation where cold start times are a factor, base yourself on hard numbers to make the first cut.
The best source for cold start information is Mikhail Shilkov’s detailed article from April 2018, with a follow-up posted just recently. Using his data as a starting point could eliminate almost 50% of the options right off the bat.
Of course, this is all assuming that you’re on the consumption plan, since it’s now possible to avoid cold starts entirely on the App Service plan, with Premium functions.
Question #2: Is the language appropriate for the problem space?
Some languages are better suited to solving certain sets of problems. We saw a few examples of that in the language breakdown, most notably for Python, PowerShell and F#.
Choosing the right language can make all the difference between a problem being easy to solve rather than struggling to get it done at all. Take some time to understand the strengths and weaknesses of the language, its development ecosystem, and its specialties before writing a single line of code.
Question #3: What’s Your Comfort Level With The Language?
Writing functions in a language you already know lets you focus exclusively on learning the serverless development model. And while there is nothing particularly difficult about it, dealing with its quirks is easier when you know the ins and outs of your chosen language.
Similarly, it’s easier to re-use code, create development standards, and simplify processes when a single language is used across all your applications in Azure. Every piece that you add to your development stack adds complexity, and complexity translates into time and money.
On the other hand, functions are great for familiarizing yourself with a new language. The stakes are low since you’re only committing to writing a small function in an unfamiliar language. If for some reason it doesn’t work out, it’s easy to re-write it in another, more familiar language.
Question #4: Is the language still in preview?
Lastly, if your functions are being used for mission-critical operations, it’s best to choose a language that is Generally Available rather than still in Preview.
Preview languages aren’t meant for production use. It’s unlikely that support for the language will disappear completely, but there could also be some hidden bugs that you only discover once you’re live in production.
All that being said, a Preview language could be perfectly fine for prototyping, testing, and proof of concepts. But then you’re stuck with something that may not be stable for a long time, so beware!
Final Thoughts
At the end of the day, the biggest factor in choosing a language for Azure Functions is familiarity. And that’s perfectly fine. But keep an open mind, since a function could be the perfect way to experiment with a new language.
Are you ready to start learning more about serverless? I’ve written over twenty five articles on developing with Azure Functions, including a visual guide to understand the basic concepts.