TL;DR: From a code aesthetic perspective, a combination of Hyperscript and CoffeeScript is an excellent way of writing beautiful React code.
React code is ugly. I’m not talking about any technical trait of the framework; I’m talking playing aesthetics, how the code looks on my screen, and the feelings it evokes.
Code aesthetics, in this sense, is not something developers are used to caring about. We have more important worries. Aesthetics are subjective, hard to measure and the benefits of chasing it are unclear. It is not often you’ll see a developer raising their hand and the midst of a Stand-up meeting to tell their peers they’re not pleased with how the code looks on their screen. And I’m not sure someone should, but I'm coming from a different perspective.
My considerations about React’s beauty started when working on a side-project. As most coders with coding as their profession and hobbies, the difference between work and leisure is simply defined by the amount of pleasure you take. Of course, we aim our careers at making both undistinguishable, and though sometimes they are, when they’re not, you still want at least your "coding for relaxation" hours to be as pleasant as possible.
Naturally, if, for some reason, React is unpleasant to me, and I want to spend time coding for pleasure, the obvious thing to do is to not use React. And I don’t, most of the time. But code, as we know, has a multifaceted perspective: you have code, the artifact, lines full of symbols you input to the computer, but you also have the result of your code, its output, the real-life implication of the ideas you expressed using a programming language. And I care, and I can derive equal or even greater pleasure from seeing my code interact with the real world.
The consequence is that sometimes, although I might find one programming language, or framework, or tool, unpleasant to see or use, it is the one I need to see my code taking the shape of something real in a reasonable time. Maybe this is due to some tooling, the big community creating things around it, or some other technical trait. Regardless of the reason, my coding-as-a-hobby time is scarce, and although I want it to be enjoyable, I also want to make the best of it, which means using things that do not always comply with my aesthetic standards. This is the case with React.
While reflecting on this topic one day, a question arose: Can I write React code that is aesthetically delightful while still keeping my productivity high? I know there are tremendously valuable answers to this question out there in the way of other programming languages and frameworks. All of those will have varying degrees of the same trade-offs, like how hard it is to learn, how much can I still benefit from the React ecosystem, how is the tooling around it, and so on. And all those trade-offs need to be measured differently depending on the project’s objective.
My answers to this question are more often than not something else that not React. But every once in a while, you compare every trade-off; you look at your project from different perspectives; you try to rethink the features you envisioned and the requirements you had; and still, at the end of the day, React will be your answer. With those cases in mind, I reframed the original question to: "how far can I go to make my React code more pleasing to view while still keeping it React code?"
"How far can I go to make my React code more pleasing to view while still keeping it React code?"
To start answering the question, I created a Create React App project with a simple React code as a reference. I wanted it to have at least a bit of real-lifeless but still be simple enough, so it wouldn't get in the way of testing different things. I chose the official React tutorial code, which you can find here: Tic Tac Toe.
Zooming on the simplest React component on that piece of code, the Square component, we see the following:
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
And this is the point where things get subjective: I find this code unpleasant. Again I’m not talking about the technical attributes of this code. When I say it is ugly, I’m trying to express a set of feelings it evokes in me, which are heavily based on my own experience of the world in general and programming specifically. It is from this perspective that I'll move on to say that the first problem that screams to me is JSX.
A lot has been discussed about JSX since its introduction, but I'll allow myself a quick consideration of it for the sake of elucidating my point. JSX is messy, but it is also a reality. It comes from a natural evolution of front-end technologies, which have since their beginning some form of XML language to define markup. What makes it different is that JSX usually lives inside your javascript code.
Making a rough comparison with spoken languages, JSX is as if the speakers of a particular language started using a whole set of words and expressions from other languages to express themselves. This frequently happens when a specific subject is innate to a given culture, for example. When people outside that culture, speakers of a different language, face that challenge of expressing ideas about that subject, they'll often lack the vocabulary to deal with it, recurring to the language spoken by those who "gave birth" to the topic as a way to solve it. Language purists soon get angry and point out how you could say those things without the need for imported words. But people would still use those words, and some of those words will eventually be incorporated into the official language. JSX was born from the need for Javascript speakers to express UI markup.
Following the language speakers' analogy, a few souls use the language for aesthetic purposes and a means of self-expression. It is generally the case for poets and literary writers. How do they look at foreign language words? Well, they’ll undoubtedly see them differently. Their perspective is analogous to my view here, as it looks at language from its power to express ideas while also considering it aesthetically. From this perspective, the use of JSX is unnecessary: it adds noise and does not contribute to the expression of the ideas it expresses.
All of this is to say my first step towards a more pleasant way of writing React was to get rid of JSX.
The no JSX version of the button component looks something like this:
const e = React.createElement;
function Square({ onClick, value }) {
return e('button', { className: 'square', onClick }, value);
}
The uniformity and conciseness of the code make for a substantial aesthetic improvement. And we can go further in the no-JSX road. I’m far from being the first person discussing JSX adoption. And hating it is probably as old as JSX itself. I bet the original team behind it had someone saying at least that it was unnecessary. You’ll find plenty of reading on reasons why JSX is terrible and the benefits of not using it. Gladly, you’ll also find technically sound alternatives to it. A prominent one is Hyperscript, which is recommended by the React team in their docs. It is a simple tool that helps you build hypertext using javascript. Its React version brings a more attractive API then createElement
gives us. I decided to try it out together with a tiny library of helpers called hyperscript-helpers
, and I found that those tools contribute to the code aesthetic quite nicely:
function Square({ onClick, value }) {
return button({ className: 'square', onClick }, value);
}
Replacing JSX is the Pareto principle applied to the beautification of React code. Little effort, excellent result. A move everyone should definitely make if they want prettier React code.
Moving on with exploring ways of prettifying your React code in the framework's realm, I found a dead-end. While there are design patterns and simple conventions I could explore, those require assessing their technical implications on a case-by-case basis, and I was just looking for something more general. So the next step would need to be in the Javascript layer.
JavaScript is an extremely flexible language, a quality well known as its double-edged sword. It is also something that can be explored from an aesthetic perspective. There are many different ways you can write valid code, with significant stylistic differences and a few technical implications. Many tools will help you customize and enforce the stylistic choices you make, and between those, there's one much of my liking: StandardJS. StandardJS is a tool for automating applying a collection of sensible coding style choices to your code. Of notable aesthetic implication between those choices is the exclusion of semicolons.
I find semicolons in JS code an unnecessary noise, and I'm happy taking the risks that come from not using them. After I incorporated StandardJS into my reference example, I was left with the following:
function Square ({ onClick, value }) {
return button({ className: 'square', onClick }, value)
}
Now in terms of javascript code, this was the best I could get. And looking back to what I had done so far, things were looking ok. The changes implemented were straightforward and could easily be integrated into my default side-project React setup. On the other hand, this was still aesthetically far from what I experienced in different languages. I've discussed the case for other languages already, and the point was I wanted to stick with React in a JS world. Unless there would be something that adds some sparkles of elegance to javascript while still being just like javascript, I’d be too far off the boundary I had set.
“Just like javascript.” While trying to stretch my creativity to look for different possibilities, this phrase made me travel back ten years in time. I was learning web development and had just come across Ruby on Rails. At the time, Rails used to ship with a different kind of JavaScript built-in, called CoffeeScript. CoffeeScript had a golden rule that said: “it is just JavaScript.” That being the case, CoffeeScript could fit my criteria, so I decided to see how things were going with the project and give it a try.
I knew that since ES5, a good set of CoffeeScript’s better features were incorporated into JS standards, so people technically had fewer reasons to adopt CoffeeScript. With the advent of transpilers, giving everyone the ability to seemingly use JS features that are not even standard yet, even developers who had to support older browsers could now benefit from the latest language features. This made CoffeeScript significantly less prevalent than it once was. But my interest was not technical. I wanted to find a pleasant aesthetic solution that allowed me to write React code that looks nice while still being JavaScript, with no need to learn a new language or framework.
Looking at the docs, CoffeeScript is close enough to JavaScript that I could neglect the learning curve, and it brings significant improvements to the code in terms of aesthetics. I had my doubts if it was still maintained, but it turns out it is. The latest release was done at the beginning of this year. Its latest major version incorporated new JS features and even supported JSX. So I decided to integrate it into my sample project. To do it, I had to eject my Create React App configuration so I could add a Webpack loader for CoffeeScript. Except for that, the conversion was pretty straightforward.
This is how the final code for the contrived Button component looked like at the end:
Square = ({ onClick, value }) ->
button ‘.square’, { onClick }, value
If you're curious about how the whole code looked like in the end, you can find it here. In terms of aesthetics, I see this code as a massive improvement to what I had first. The syntax is terse, and it looks clean.
A lot has been said about how the quest for beauty is a pursuit of less. I clearly subscribe to that. It turned out my beauty search was basically a search for writing an expressive piece of React code with less. The excellent improvement CoffeeScript brought - and other languages use - is attributing value to otherwise meaningless tokens. This realization seemed evident at the end, but it wasn't at the beginning. It served the purpose of reinforcing the power of less in general.
From a pragmatic perspective, at first glance, it seems that adopting such a style wouldn’t interfere with productivity. CoffeeScript has been out there for a while, and I expect it to have somewhat decent tooling. I had no surprises while building this quick experiment. There’s one thing that would be on my way from adopting it entirely, though: the ability to use it together with Typescript. I know how it could work, but I decided to stop the exploration at this point. Anyways, if you enjoyed the picture, would be interested in adopting a similar approach, and are curious about how it could work with Typescript, please let me know.
Thanks for reading.
Cover photo by Sincerely Media on Unsplash
Top comments (0)