Declarative Programming And The Web

Advertisement

Like most web developers, I spend my days giving instructions to computers. These instructions generally involve some input (a request for a web page), some logic (get the right content from a database) and some output (send the content to the requesting browser). This process of telling a computer how to perform a task, such as generating a web page, is what we commonly call “programming,” but it’s only a subset of programming: imperative programming.

There’s another type of programming, declarative programming, that most web developers also use every day but don’t often recognize as programming. With declarative programming, we tell a computer what, not how. We describe the result we want, and the details of how to accomplish it are left to the language interpreter. This subtle shift in approach to programming has broad effects on how we build software, especially how we build the future web.

So, let’s take a moment to investigate declarative programming and the web we can build with it.

Hidden In Plain Sight

Declarative languages tend to fade into the background of programming, in part because they’re closer to how we naturally interact with people. If you’re talking with a friend and you want a sandwich, you don’t typically give your friend step-by-step instructions on how to make the sandwich. If you did, it would feel like programming your friend. Instead, you’re far more likely to talk about the result you want, such as “Please make me a sandwich” (or, perhaps, “Sudo make me a sandwich1”). If your friend is willing and able to follow this instruction, then they would translate the phrase “Make me a sandwich” into a series of steps, such as finding a loaf of bread, removing two slices, applying toppings, etc.

01-sandwich-opt

This type of result-focused instruction is how declarative programming works, by leaving the logic of how to implement requests to the system that is interpreting the language (for example, your friend). When we want an image in an HTML document, for example, we simply include an <img> tag, and then the system that interprets the HTML (typically, a browser) would handle all of the steps needed to display that image, such as fetching it from a server, determining where exactly to render it, decoding the binary data, scaling the image and rendering it to the screen. We don’t have to explain any of this, so we often forget that it’s all happening and that someone programmed both how it happens and how that complex process is derived from a simple <img>.

Another factor that makes declarative programming hard to see as programming on the web is that it “just works.” A lot of work went into making languages like HTML, CSS and SQL capable of providing enough clarity on what needs to be accomplished that the steps required to achieve a result can be determined without detailed instruction. But most web developers began using these declarative languages long after the hard work2 of building them was complete, so we just see them as normal and ordinary and just a natural part of the way the web works3.

When web developers do get involved in declarative programming before the interesting work is done, it’s typically while developing an API for a website. Most APIs are implemented via declarative programming. Rather than provide a way to give a website step-by-step instructions, APIs usually have a simple language that can be used to express the desired result. When we want to get some tweets from Twitter’s API, for example, we give a description of the tweets we want, such as “everything from @A_single_bear.” If the API is imperative, we would instead describe the specific steps we want Twitter to implement on our behalf, explaining how to load, format and return the tweets. Thankfully, the API hides all of that logic behind a simple declarative language, so we only need to describe what we want, not how to get it.

Two Paths Forward

Once we realize how widespread declarative programming languages are on the web, it’s hard to imagine the web without them. Hard, but not impossible. As JavaScript has grown to be ubiquitous, the tools we would need for an imperative-only web are easy to find. We could swap out HTML and CSS for rendering directly in JavaScript4. We could swap out SQL for a JavaScript-native database5 (or two6). And we could swap out calls to declarative web APIs with imperative calls to JavaScript functions, even across the gap between client and server7.

We could put all of this together and entirely stop using declarative languages on the web, even before we get into more advanced technologies heading in our direction, like asm.js8. We can, now, build the web equivalent of mainframes: large, powerful systems built not as a collection of disparate parts but as a cohesive whole. We can now JavaScript all the things9. We’ve tried this before, with technologies like Java and ActiveX. And some organizations, such as AOL, have even had success building a less messy web-like stack. The difference this time is that the technology available to build these “mainframes” is part of the open web stack, so that anyone can now make their own self-contained web-like stack.

An imperative-only JavaScript web is enticing if we understand the web as open technologies and connected documents. But if we expand our understanding of the web to include connected systems, then declarative programming is a key part of how we connect those systems. With that understanding, we should be heading in another direction. Rather building more complex systems by replacing declarative programming languages with imperative programming, we should be wrapping more and more of our imperative code in more and better declarative languages, so that we can build future complex systems on top of our current work. Rather than looking at JavaScript as the modern Java or C++, we should be treating it as the modern shell script, a powerful tool for connecting other tools.

By defining the implementation details in the language itself, declarative programming allows imperative languages such as JavaScript, PHP and Ruby to use the results as steps in more complex behaviors. This has the advantage of making a behavior available to a variety of languages, including languages that don’t exist yet, and it also gives us a solid foundation on which to build higher. While we could build our own document-rendering system in JavaScript or Python, we don’t need to because HTML has already solved that problem. And we can reuse that solution in any imperative language, freeing us to solve new, larger problems. JavaScript can draw an image on a canvas and place it into a document with HTML. Your friend can make you a sandwich and a fresh lemonade. But we’ll get to this future web only by valuing declarative programming as an approach worth maintaining, now that it’s no longer the only option.

Declarative First

When we start building a tool on the web, we often jump right into making it do what we want it to do. A declarative-first approach would instead start with defining a language to succinctly describe the results we want. Before we build a new JavaScript library for building sandwiches (or, of course, another10), let’s consider how we might describe the results in a declarative programming language. One option would look something like {"bread": "rye", "cheese": "cheddar"}, while another would look more like <sandwich><cheddar /><rye /></sandwich>. There are many choices to make when designing a declarative language, from high-level format choices (JSON? XML? YAML?) to details of data structure (is cheese an attribute of a sandwich entity or an entity in the sandwich’s toppings list?). Making these decisions early could improve the organization of your later imperative implementation. And in the long run, the declarative language might prove to be more important than the amazing sandwich-making implementation, because a declarative language can be used far beyond an individual implementation.

02-sandwich-opt

We can see some of the advantages of a declarative-first approach in public projects that have taken both approaches. For example, three years ago the Sunlight Foundation started working on a project to make it easier for people to contact members of the US Congress. They began with a Ruby app to automate the submission of contact forms, Formageddon11. This year, they launched a new declarative-first effort toward the same goal, the Contact Congress12 project, starting with a declarative language that describes contact forms13.

The activity14 graphs15 and timelines of the two projects make it clear which approach won out, but the benefits of the declarative approach go beyond the direct results. The YAML files produced by the declarative approach can be used to build apps like Formageddon, but they can also be used for other purposes, ones not even intended by their creators. For example, you could build an app to analyze the descriptions of contact forms to see which topics members of Congress expect to hear about from their constituents.

Successful declarative programming is in some ways more challenging than imperative programming. It requires clear descriptions, but also requires knowing enough about imperative implementation to know what needs describing. You can’t just tell an app where a form is and expect a valid submission, nor can you say <greatwebsite> to a browser and get what you want. But if you’re up for the challenge, the rewards of a declarative-first approach are also greater. Declarative languages often outlive their imperative implementations.

Try starting your next web project with declarative programming. See what languages you can find that already describe what you’re making, and write your own simple languages when you can’t find anything. Once you have a declarative definition of what you want to make, build it with an interpreter of those languages. You’ll probably end up making something more useful than you would have with an imperative-first approach to the same problem, and you’ll improve your imperative approach in the process.

(al, ml)

Footnotes

  1. 1 http://xkcd.com/149/
  2. 2 http://www.w3.org/2005/10/Process-20051014/tr
  3. 3 https://www.goodreads.com/quotes/39828-i-ve-come-up-with-a-set-of-rules-that-describe
  4. 4 http://vps2.etotheipiplusone.com:30176/redmine/projects/emscripten-qt/wiki
  5. 5 http://www.taffydb.com/
  6. 6 https://github.com/kripken/sql.js
  7. 7 https://www.meteor.com/
  8. 8 http://asmjs.org/
  9. 9 http://www.quickmeme.com/img/8d/8d30a19413145512ad5a05c46ec0da545df5ed79e113fcf076dc03c7514eb631.jpg
  10. 10 https://github.com/sudo-js/make-me-a-sandwich
  11. 11 https://github.com/sunlightlabs/formageddon
  12. 12 https://github.com/unitedstates/contact-congress/
  13. 13 https://github.com/unitedstates/contact-congress/blob/master/documentation/schema.md
  14. 14 https://github.com/sunlightlabs/formageddon/graphs/code-frequency
  15. 15 https://github.com/unitedstates/contact-congress/graphs/code-frequency

↑ Back to topShare on Twitter

Scott Reynen has been making web for nearly 20 years. He is currently VP of Technology at Aten Design Group, where develops websites for cause-driven organizations such as the World Resources Institute, Colorado Public Radio, and Stanford University. He is an active member of the Drupal community, and the wider web community.

Advertising

Note: Our rating-system has caused errors, so it's disabled at the moment. It will be back the moment the problem has been resolved. We're very sorry. Happy Holidays!

  1. 1

    Great article. Although the content borders on a manifesto (one that I would support btw), your examples go against the grain of trendy development. With W3C Web Components picking up momentum, I hope a balance will return to web development and we realize the benefit of declarative programming in other areas outside of the web (e.g. IoT devices).

  2. 2

    I’m not sure I understand. From your statements, isn’t everything except writing pure assembly (if that), “declarative programming”?

    • 3

      Not really. I’m guessing you’re asking that because everything above assembly is in some way abstracted from the detailed implementation. But while abstraction is one of the primary advantages of declarative programming, not all abstraction is declarative. Declarative programming is a specific type of abstraction that happens to be exceptionally reusable.

      In retrospect, the “please make me a sandwich” metaphor wasn’t a great choice, because that doesn’t actually become declarative until we strip out the instruction. A fully declarative form of that would look more like {sandwich: {state: “made”, owner: “me”}}, which describes the result, not the process. In declarative programming, I don’t care if you make me a sandwich or you buy me a sandwich someone else made or you build a sandwich-making robot and give me its output. The sandwich just needs to somehow end up made and in my hands to satisfy the declaration.

  3. 4

    “Sudo make me a sandwich” made my day

  4. 5

    This is brilliant work. Great article, great perspective, and great way to represent data by type without worrying about style. Excellent steps toward a healthy separation between design and data/content. Thank you for this!

  5. 6

    Hi Scott..nice and informative article. I am not a technical person but from your article I have clearly understood the difference between two. And before I forget to mention, I really liked the example you took..and yes of course the image too…”Sudo make me a sandwich”..:)

  6. 8

    Chathura Asanga Kulasinghe

    July 31, 2014 9:46 am

    Great article, indeed!!!

  7. 9

    Great read and some good links.
    Thx!

  8. 10

    Joe Wojciechowski

    July 31, 2014 2:40 pm

    Back in my early days, when I was on the path of becoming a UX Designer, I took a C++ course. Needles to say I decided to focus on design and not programming.

  9. 12

    I’m lost, but I have stopped at the title Declarative First. I agree, if you focus on how you store your data it can be accessed by anything – but I would also argue that this is in fact how 99.999999% of developers already create services. It’s as if you only have experience of writing templates for pre-built systems and assume that is how the world works, which I am sure is not the case.

    What I find interesting is that a lot of people are still creating what they consider to be an API after they have finished their application, which is baffling because they’re going to be re-writing calls they were already making just for other people to use them when if they’d started there the work is done.

    Now, I’m going to finish your article and see what more I can learn.

  10. 13

    Great article, I accept with the Declarative Programming and it depends on how you save your data. Great article

  11. 14

    ‘Declarative’ is opposite of ‘Imperative’ – so you do not give description/prescription of operation which you want to do. I think it is not bed definition, because ‘high level abstraction’ or ‘functional’ or ‘domain specific’ are not really good definitions, however they give some intuitional understanding;)
    I think wiki give good info about declarative:
    http://en.wikipedia.org/wiki/Declarative_programming
    Xml and Xslt is a good example I think, as well as Prolog (logic programming). ‘Goal programming’ have simmilar set of meaning, I think.
    Btw. Do You guys think declarative/functional/goal is a future for programming?

  12. 15

    I’m sorry, but I struggled to understand the point of this article. A few examples comparing declarative and imperative programming would have helped.

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top