The importance of elegance
About a week ago, Rich Harris posted a brutal takedown of Web Components, and parts of it really stayed with me. Rich is — among a host of other inventions — the creator of Svelte, a futuristic compiled frontend framework, and a lot of his post is about comparing Web Components to Svelte. I agree with all his points but the comparison between frameworks is the part that interested me the most. Let’s look at how Rich has implemented a simple “add these inputs” type of interaction as a Web Component:
class Adder extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
this.shadowRoot.innerHTML = `
<input type="number">
<input type="number">
<p></p>
`;
this.inputs = this.shadowRoot.querySelectorAll("input");
this.p = this.shadowRoot.querySelector("p");
this.update();
this.inputs[0].addEventListener("input", e => {
this.a = +e.target.value;
});
this.inputs[1].addEventListener("input", e => {
this.b = +e.target.value;
});
}
static get observedAttributes() {
return ["a", "b"];
}
get a() {
return +this.getAttribute("a");
}
set a(value) {
this.setAttribute("a", value);
}
get b() {
return +this.getAttribute("b");
}
set b(value) {
this.setAttribute("b", value);
}
attributeChangedCallback() {
this.update();
}
update() {
this.inputs[0].value = this.a;
this.inputs[1].value = this.b;
this.p.textContent = `${this.a} + ${this.b} = ${this.a + this.b}`;
}
}
customElements.define("my-adder", Adder);
This is a simple and fair example. Not many implementation details to argue about. You type numbers into the boxes, and the text content automatically updates to show their sum.
Errr… gonomics?
Now, if you were to look at this Web Component from a purely theoretical standpoint, it’d be hard to find fault with it. We’re being explicit everywhere, our functions are small and testable, there’s standardization in the form of observedAttributes, we’re using the DOM API… I mean, there’s nothing obviously wrong here, and for some reason I picture the Computer Science crowd standing around in a solemn circle, nodding approvingly in white lab coats (although I also imagine a few of them muttering about adding static types to it).
But come on. This is no way to live.
Reading through that code example I had some nasty flashbacks to writing C# and Java. It felt exactly like that. People with thick glasses had done some static analysis or applied Dijkstra’s algorithm or whatever and then decided that yes, THIS is how you talk to a computer: you laboriously and methodically describe the things you want done in discrete little chunks, write interfaces and getters and setters for them, and probably reams upon reams of XML configuration, and when you’re done you’re expected to pepper everything with Javadoc and send it to QA. Eughhh. But Rich shows us a better way:
<script>
export let a;
export let b;
</script>
<input type="number" bind:value="{a}" />
<input type="number" bind:value="{b}" />
<p>{a} + {b} = {a + b}</p>
That’s the Svelte component doing the exact same thing as our example above. These nine lines have just returned the rosy pink color to my cheeks. They underscore the importance of elegance in code. Not only for our collective sanity, but for the sake of our codebase. If code is explicit and testable but hard to read and follow, then we’ve lost our most important property along the way. Code is first and foremost designed to be read by humans, not computers. Turning source code into CPU instructions is the compiler’s job, not mine, and Rich has done a wonderful job illustrating how your choice of framework can turn a cumbersome chore into a reactive programming dream.
Your gut is the arbiter of truth
I don’t think anyone has ever set out to design a production language that’s hard to read (although I think I see Perl sulking in a corner over there) or overly verbose. They all have different stated goals, whether they be memory safety, beginner friendliness, or programmer portability. You can certainly write applications in all of them, and those applications will have different properties, and we all get to argue on message boards and be angry at one another because we feel insulted and threatened by someone else’s choice of tech. Hooray. You can write anything in anything, really.
But will you be happy doing it? Will your team be productive? Can you stomach maintaining that codebase for years and years to come?
I think these points are inextricable. And I think you should relentlessly KonMari your languages and frameworks: ask yourself, does this spark joy? If not, thank it, and send it on its way. The more you do it, the more you’ll learn to trust the feeling, and you’ll be happier and more productive for it.
Comments