Just write components

18 months, 729 React components, 2134 modules and 165,915 lines of code into a project you get asked the question…

Are we scalable?

To which you respond candidly

Yes.

A quick question in response

How?

And finally the moment you’ve been waiting for

Just write components!

A quick double take

Wait? What?

It’s not madness… honest.

At Kalo, since we kicked off our front-end engineering efforts, we’ve been exploring the real world implications of new found tech, sharing our journey implementing new styling patterns, and have even been building tools to help us understand our application architecture better.

All of these journeys, and the many more undocumented journeys, have led us to formalise our founding front-end engineering principle of “just write components”, most notably in the name of scalability.

Scalability

Firstly, a quick recap on what we mean by “are we scalable?”. There’s this pretty solid definition of scalability from investopedia which I’ll call on here.

Scalability is a characteristic of a system, model or function that describes its capability to cope and perform under an increased or expanding workload. A system that scales well will be able to maintain or even increase its level of performance or efficiency when tested by larger operational demands.

So, “if I add more things, do all of those things remain effective?”.

There are two primary considerations when thinking “are we, as an engineering team, scalable?”.

  1. The first is “if we add more engineers do we at least retain our original working efficiency?”
  2. Secondly “if we write more code, does it continue to perform effectively?”

Sitting between these primary considerations are the mirroring angles “Given more code, can engineers retain their efficiency?” and “Given more engineers, will the code written continue to perform?”.

Interestingly, you’re always trying to tip the scales and allow fewer engineers to maintain more code since that just makes business ($$$) sense!

Taking all of this in to account, it should be understandable that our main objectives towards achieving scalability are:

  1. “To enable engineers to add code without affecting the efficiency of surrounding engineers”
  2. “To enable the writing of code which can be maintained efficiently by as few engineers as practically possible”.

What is a “component”?

Before we get to the practicalities of what “just write components” means it might first be helpful to ask ourselves what even is a “component” and which of its properties contribute towards our objectives and ultimately achieve scalability.

Out of interest I recently asked a non-engineer “what is a component?” — their response was “a smaller part of a larger system”. When asked to “describe all the components in a larger system” they responded with “they all look similar, independently they are unique in themselves, but together they share similarities”.

That last part is key. Looking at a component on its own it can be seen as unique however to reason about the larger system the definition moves to be similar.

If we look at this with an engineering perspective we can map the independent uniqueness of components as encapsulation and the similarities as the interface.

Encapsulation

To be encapsulated is pretty much to not expose any internals. The practicality of this is that components can be consumed with minimal understanding and are self-contained to the point they can do a (resource permitting) infinite amount of work.

This ultimately leads to allowing engineers to work with a high level of isolation whereby they avoid affecting other components (and in turn the larger system). The encapsulation also tends to provide very clear boundaries which can help promote code ownership where needed in a scaling team.

Consistent Interface

Having a consistent and predictable interface reduces the multitude of patterns and abstractions an engineer has to learn and understand. If n components each required a different pattern to consume it you’d have n patterns to learn. However with a unified approach you can reduce this to just the number of patterns.

Note here we talk about patterns more than the explicit API. Patterns can be learnt and parameters forgotten. Consider the Screwdriver. A million variations of screws and drivers but only one pattern — twist! Anyone could pick up any shape, brand or variation of a Screwdriver, match it with the appropriate screw and know how to use it.

Consider the Screwdriver. A million variations of screws and drivers but only one pattern — twist!

This unified interface should lead to engineers being able to consume more where they can re-use the patterns they’ve already learned. As Facebook shouts “learn once, write anywhere”.

Learn once, write anywhere.

React as an example

To try and materialise this all a bit more clearly I’ll give React as an example. Our entire codebase is written with React components at the heart. We’re at >700 components and not seeing any signs of slowing!

The React component paradigms drive you into a happy place where the two key properties of a component, encapsulation and consistent interface, are strongly in play. At this point picking up Component A should be mostly as trivial as Component B (providing you account for finding the right screw types!).

An example of a React paradigm at play here is the unidirectional flow of data which close to guarantees, providing you don’t abuse it, that you lean towards the same predictable APIs for consuming your components no matter the complexity. I.e. data values are passed in and callbacks can push new data values back up.

Ok, so “just write components”?!?

This should not be treated as an entirely literal expression (or command!). It is certainly not practical that you would ever build a considerably complex application without some other level of abstraction.

What this is however, is an identification of our components as the lowest common denominator of abstractions when building applications. In our case with encapsulation in play, you should now be able to take an engineer which understands your component model (in our case React) and they are instantly able to contribute to your application.

This generally leans towards another principle of “make 90% easy, 10% possible”.

90% easy, 10% possible

Returning to our objectives our true goal is to lower the barrier for an individual contributor to become effective while avoiding any negative external impact on the wider system — this is our definition of scalability!

Therefore…

Just write components!

Practicalities

As mentioned, you’re never going to be able to just write components. You need other abstractions to manage things such as routing, data management, notification handling etc. The more shallow and component-like we can consider these abstractions the smaller the learning surface area. A great example of this out in the React community would be the react-router v4 api and how it is influencing others. As Ryan Florence states, “Just Components™”.

As with anything abstraction related in programming we are always faced with a balance question (one which can easily be abused!) so for now just let common sense prevail while allowing for some experimentation! In practice we’ve gone heavy in on Components and Higher-order-components, but maybe different abstractions work for you!

Finally here’s a quick list of the other practicalities of this principle we’re tackling day-to-day here at Kalo:

  • Enabling everyone to work on any given component in isolation
  • Moving data dependencies alongside components (containerisation)
  • Localising routing definitions
  • Removing as much “global” consideration and minimising “contextual” awareness of components
  • Building a styleguide to ease discovery of components
  • Advancing recon to allow us to deep-dive into our application component hierarchy
  • Reducing the abstractions needed to build a “Kalo application”
  • Tidying up all those API utilities to provide a blessed subset
  • Formalising the common denominator patterns used in everyday front-end engineering
Go forth and just write components!

If you enjoyed this post, some of the approaches we introduced or are really passionate about tackling some of our or similar problems (you may even just fancy a chat! :) then feel free to reach out on twitter or if the time strikes you right check out our careers page!