With all of the new features, it’s only natural to want to reach for the most powerful tool for any given task. Is that the best policy, though?
More often than not, it’s problematic. In fact, the creators of the web thought about this eventuality. Tim Berners-Lee and Noah Mendelsohn wrote a document called “The Rule of Least Power” (RLP) in 2006.
When designing computer systems, one is often faced with a choice between using a more or less powerful language for publishing information, for expressing constraints, or for solving some problem. This finding explores tradeoffs relating the choice of language to reusability of information. The ‘Rule of Least Power’ suggests choosing the least powerful language suitable for a given purpose.
Why the language of least power?
It might seem like the W3C wants to torture web developers. Why suggest a developer not use the strongest tool for the job?
Berners-Lee and Mendelsohn proposed that power and flexibility are inversely related. As power grows, the ability to analyze the output shrinks.
They viewed the future of the web as something built from reusable pieces. Many devices and applications could read the data, use it and combine it in multiple ways.
Information published on the Web can be flexibly combined with other information, read by a broad range of software tools, and browsed by human users of the Web.
In other words, the web is a world of endless remixes.
This is something that should appeal to our modern sensibilities. Modularity over integration. Components over pages.
What does this mean for a modern developer?
The state of Rule of Least Power in modern web development
In some cases, the Rule of Least Power is at play in modern web development. Concepts like modularity, components and packages are all modern structures. They’re also key concepts of a reusable web like Berners-Lee and Mendelsohn discussed.
With that, you might think we’re in line with this philosophy. I see a startling amount of modern “best practices” that seem at odds with this philosophy, though.
Don’t believe me?
I’d like to present three scenarios. Each scenario will be increasingly controversial.
Scenario 1: Describing data for your application
When you want to describe data for your application, how and where should you create it?
Here are your options: create variables on the fly in your functional code or create a data object.
Let’s look at how we create data as you need it in your functional code.
In this example, we build our data inside our function with variable declarations and then immediately use the data:
In this example, we have functioning code. It would get the job done. Would our data be reusable, though? No. That data would forever live in that function.
Instead, we create a data object. This could be the result of a RESTful endpoint, a GraphQL call or just a flat data file.
This data object represents the same data but is endlessly analyzable and reusable:
This is an example of what the RLP calls “Scalable language families.”
It brings the benefits of a declarative language and matches it with the power benefits of JS.
Most developers will agree with this setup. Data in a data layer in JSON; application written in a powerful programming language.
This separation of concerns opens all of these doors.
That’s the least controversial scenario. Let’s step up to a newer, slightly more controversial example.
Scenario 2: Servers
Just like we should seek the least powerful mechanism to contain our data, we should seek the least powerful server to deliver our application or site to our users.
In this case, I’m not referring to RAM and processor. I mean, we should use the server with the least complexity of software.
In the days of the emerging web, servers were any computer connected to the Internet serving HTML pages. Simple.
As the need for more dynamic content became greater, so did our server needs. We now needed a database. We needed programming languages to access, manipulate and store the data. In the end, though, this all ended up serving HTML documents to the browser (if we ignore the dark times of Flash and Java applets).
There’s a grand experiment playing out right now. There’s a modern static site movement. I’m a strong advocate of this movement.
Static sites used to mean putting a bunch of index.html files on a server. That was never the friendliest methodology for developers. Now we get all of our modern conveniences and a great static output. We’ve moved the complexity from the server to the development environment.
Keep in mind, you can still use your programming language of choice. You just use it locally, build the files and publish to a server with no scripting languages.
Why this way?
- Since it’s just HTML being served, this gives us lightning fast downloads
- It gives us fewer security holes since there’s no database or scripting language
- It makes our application highly portable and reusable — finding incredibly cheap hosting for static files is very simple
When static sites aren’t quite enough
This approach becomes more problematic when you need a server to process something. Whether this is a place to securely store API keys, process a form or accept payments.
That’s where “serverless” functions come in. It’s a bit of a misnomer, but these functions are rented time on someone else’s server. It tends to be a low-cost, low-maintenance resource to provide this sort of functionality.
The future of your application
If you’re currently managing your own server for your application, by all means, keep that server. There’s rarely a point in a major refactor when things are currently working. You may be able to start taking advantage of this potential future already.
If you treat your server as a series of endpoints instead of a machine meant to serve the entire application, you can harness the power of static sites with your current setup. If you’re able to decouple your back-end logic from your front-end presentation layer, you can gain the advantages I mentioned above without starting completely over.
If you’re starting from scratch, it’s definitely worth looking into a “serverless” architecture. By utilizing principals from the Rule of Least Power, we gain portability and flexibility — not to mention lower costs, higher speeds and happier front-end developers.
This scenario will become less controversial over the next few years as the tools get increasingly stronger.
My next scenario has become quite a hot topic in the past two years.
Scenario 3: The Holy Trinity of web development
Traditional web development goes a little something like this:
- Server gets a request
- Server language handles the request and pieces together HTML which it sends to the browser
- The browser loves this
- It creates the DOM and then lets CSS and JS run wild with those DOM elements
- CSS styles them
- JS makes them interactive
- Beautiful, interactive pages happen!
Newer, more “modern” takes on web development often look something more like this:
- Server gets a request
- Sends the absolute LEAST amount of markup it can (a <head> and possibly one <div> in the <body>)
- JS takes over, creates the DOM, styles the DOM, makes the DOM interactive
- Beautiful, interactive pages happen!
These sites and apps are always amazing. They feel great to use.
Surely with their prominence and slick interactions and great usability, they have to be the way to go!
If we refer back to the Rule of Least Power, though, we realize very quickly that this method violates it.
If we look at the Holy Trinity of web development — HTML, CSS and JS — it’s easy to see the hierarchy of power. HTML is a declarative, semantic language. This means there is no programmatic power, and its tags each describe a type of data. CSS is also declarative. It has more power than HTML, but just enough to do its job.
JS is a programming language. It can be used to do small things or incredibly large, complex things. It is easily the most powerful of the three languages.
In the second workflow, we’ve used the most powerful language available to do all of the work.
Why is this a problem?
Since the DOM is created by JS, by default the data is less analyzable. HTML creates an analyzable tree of data. This data can be consumed by any number of applications.
- The browser can convert it to the DOM
- Google’s bots can effortlessly crawl it
- Screen readers can read it
- In the future, voice assistants may be able to read it
If you ask yourself that, you’re already ahead of a lot of developers.
If you’re worried about these things, you should look into testing. If you thought testing against the last two versions of browsers was tough, this should not sound exciting to you.
Think about “Markup-First Development.”
In that case, you can still think Markup First. Make sure your app prerenders. There are services, frameworks and hosts that can all do this for you with minimal effort. Write in your favorite framework — be it Vue, Angular, React, etc. — and then serve server-rendered AND browser-rendered content.
This solves a major aspect of the problem. You now have HTML on the page. The browser and other applications have something they can easily consume. It’s not enough to just render HTML to the browser, however. Your markup should be well thought out and semantically correct.
Be aware of your tags. Not everything is a <div> or a <span>.
Be aware of your nesting. Not everything needs endlessly nested elements. This is exactly why React released “Fragments” in v16.2.0.
In the end, don’t assume one HTML tag is equal to another. If you architect your markup with as much thought as you put into your application logic, you’ll create something that is highly reusable. The easier for other applications to consume your data, the better for ALL your end users.
At the end of the day, the Rule of Least Power is about creating clean code.
By using the least powerful language to get the job done, we get the least-complex, most portable future-proofed code that we can.
When you build your next website keep RLP in the back of your mind. Your future self may thank you for it.
Plug: LogRocket, a DVR for web apps
LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.