There are a lot of programming languages–over 700, as Wikipedia lists them. And yet, we arguably don’t have nearly enough programming languages. Not since cloud upended the way applications get built.
Developers are moving away from managing physical servers to calling APIs that touch storage, compute, and networking resources. In turn, developers are trying to automate everything as code through static configurations, scripts, and files. Such automation would be easier if developers had programming languages that matched the task at hand, but they don’t. So, using a general purpose language like Java, a developer might invest thousands of lines of code to try to express business logic…and mostly fail.
To solve for this, we’re seeing companies like HashiCorp (HCL) and oso (Polar) release special-purpose declarative languages. Even at the risk of programming language proliferation, this feels like the right way forward: Purpose-built instead of general-purpose languages. However, we’re likely to see many of these programming languages rise and fall before we settle into a useful set of standard declarative languages.
Functional declarative programming languages: What’s old is new again
The irony is that the “novel” approach taken by special-purpose declarative languages really isn’t very novel. Years ago, programming languages split between functional (declarative) programming languages like Lisp and imperative programming languages like C. While the latter dominated for decades, functional declarative languages are making a comeback, said Jared Rosoff in an interview, a software executive who has built product at VMware, MongoDB, and more.
“Imperative languages were better suited to encoding business logic for apps,” Rosoff noted. “But in Infrastructure as Code [IoC], the world isn’t imperative. It’s rule-driven. And this world gets much easier when we change out the languages we use to program it.”
Even Polar, a declarative logic programming language specialized for making authorization decisions and tightly integrating with an application’s native language, really isn’t new. As Sam Scott, cofounder and CTO of oso, suggested in an interview, Polar has its roots in Prolog, which was developed way back in 1972, yet has the feel of imperative languages like Python. (Here’s an example of what Polar looks like.) This is important because it’s difficult to encode authorization logic in traditional, general-purpose programming languages. Doing so in a declarative language like Polar is more expressive and concise–think “tens of lines of code” instead of “thousands of lines of code.”
And yet, many will question whether creating new programming languages is the right approach. How many do we really need? The short answer is “more.” Here’s the longer answer.
Why can’t I just use [insert favorite programming language here]?
While we still use COBOL and other older programming languages, we also keep inventing new languages, each with its own advantages and disadvantages. For example, we have Rust and C++ for low-level, performance-sensitive systems programming (with Rust adding the benefit of safety); Python and R for machine learning, data manipulation, and more; and so on. Different tools for different needs.
But as we move into this Everything-as-Code world, why can’t we just keep using the same programming languages? After all, wouldn’t it be better to use the Ruby you know (with all its built-in tooling) rather than starting from scratch?
The answer is “no,” as Graham Neray, cofounder and CEO of oso, told me. Why? Because there is often a “mismatch between the language and the purpose.” These general-purpose, imperative languages “were designed for people to build apps and scripts from the ground up, as opposed to defining configurations, policies, etc.”
Further, mixing declarative tools with an imperative language doesn’t make things any easier to debug. Consider Pulumi, which bills itself as an “open source infrastructure-as-code SDK [that] enables you to create, deploy, and manage infrastructure on any cloud, using your favorite languages.” Sounds awesome, right?
The same problem crops up when trying to skirt the issue with data as config. This is a bit like using an existing language (Hey! I already know JSON…). As Scott explained, to make this approach work, a vendor typically needs to dress up the data format with conditions or custom rules (e.g., GitHub Actions) to make it work for the use case. Or maybe they use templating (e.g., Helm or how Ansible uses Jinja2). Plus, while the appeal often starts with the data format being human readable, the “files have a nasty habit of getting long and unwieldy,” he said, leading to posts like this and this and this and this.
This brings us back to declarative programming languages.
Declaring a purpose-built future for programming languages
Declarative languages like Polar and HCL are great for use cases like configuration because they allow you to just declare what you want the world to look like and not have to worry about what you need to do to make that happen. The downside is that it’s new: New learning curve, new need to build out an ecosystem of tools around it, etc. It’s still early for declarative programming languages, but that’s ok–it’s also still early for our Everything-as-Code world.
And while declarative programming languages aren’t perfect, they offer significant benefits over imperative programming languages, as iRobot’s Ben Kehoe called out. Over the next few years, I suspect we’ll see declarative programming languages proliferate, with the industry standardizing around those that do best at making themselves accessible to newbies through tooling and approachability (e.g., embracing a familiar syntax). If “developers are the new kingmakers,” it’s time for the declarative programming language designers to start crowning some new kings.
Disclosure: I work for AWS, but the views expressed herein are mine.