Could this file be under a hundred lines?
7 minute read
... is a quote my team has heard from me, many times over. As a rule of thumb, I've found it helps accentuate good, quality code being written.
The qualities I'm looking for are readability, low cognitive load, and composition. Keeping files roughly under a hundred lines force you to confront each of these principles. You're made to think through the intent or the 'what'. While packaging up the actual or the 'how' into bite sized chunks.
What is the intent?
As an example, this is how the page.tsx file for the landing page of this website is structured
const Page = async () => (
<>
<LandingSection />
<div className="px-8 md:px-0 m-auto">
<InfoSection />
<div className="flex flex-col">
<ArticleSection />
<ProjectSection />
</div>
</div>
</>
);
The intent is clear. It is a screen/page. It has four sections.
How does 'x' work?
Great question! Click on the component/function/file you're interested in and get the 'how' there.
When we frame overall intent, we don't care about how it operates. That is the responsibility for the subcomponents (or functions).
Tell me more
Ultimately all code we write should be easy for the next person (or LLM) to understand, and extend. We should aim to keep context and cognitive load colocated and at the requisite level of depth.
For example, looking at a page/screen file as above. What you see is a 'declarative structure' for the screen. In similar scenarios you may find the structure as well as a call to any initially required data, or perhaps some wrapping of providers and state management. What you shouldn't see is the inner workings of any of these specific and discrete actions. What I mean by that can be summarised by the fact the query for article/project data isn't retrieved in the page file itself. Instead, as they pertain just to their own respective components, they are handled there.
Since React uses a declarative model to describe what it will do, this kind of composition is well suited to provide the correct level of responsibility.
However, this isn't React specific. If we instead focused on functions rather than UI the same principles apply. If we were to have a function that spans hundreds of lines it would create significant cognitive load. If we wanted to change one aspect of it, we'd need to first find where that is in code. Then be cognisant of the effect any change to have to the overall function. If we instead chunked the function down into grouped actions and responsibilities, we could have one overarching function which calls a few others. Inside of them we can garner the 'how', however the 'what' or the intent for the overarching function is clear.
Coming back to the page.tsx example
It's easy to quickly parse, coming in at only 12 lines. We can see four components each with the suffix 'Section', which implies their context and boundary. Each component is responsible for its own section, however the overall page is responsible for structuring the sections in the desired order. The page.tsx doesn't need to understand how the articles, or projects sections operate. It doesn't need to understand how data is retrieved, nor how they are presented. Not to say data shouldn't be retrieved or props passed down from this level, but if they are it should be because multiple sub-components here rely on it.
Importantly the cognitive load to parse the code and come to an understanding of its intent is minimal. If I wanted to extend the home page, this is the file I need to make a change to. If the change is relevant just to a section that already exists, I can go to that file instead.
The scenario we're wanting to avoid is coming to a page.tsx file which has too much happening. As an example, If I instead put each sections code into this file rather than their own, these meagre 12 lines will balloon in size. Even if it remains under our arbitrary ~100 line limit, it has now confused the logical boundary and composition we should aim for. As we've now mixed in the 'how' which increases our cognitive load.
In psuedo-code that could look something like
const Page = async () => {
// fetch the article/project data
const {loading, articles} = getArticles();
const {loading, projects} = getProjects();
return (
<>
{/* <LandingSection /> */}
<div>
// show columns on left/right of central image, hide when on mobile.
// show central image, increase size on mobile, decrease size for desktop.
</div>
<div className="px-8 md:px-0 m-auto">
{/* <InfoSection /> */}
<div>
// add divider to top and bottom of text section
// text section + two cta (calls to actions) to prompt posts/projects
</div>
<div className="flex flex-col">
{/* <ArticleSection articles={articles} /> */}
<div>
// retrieve articles, list them ordered by publish date, prompt more cta
</div>
{/* <ProjectSection projects={projects}/> */}
<div>
// retrieve projects, list them ordered by publish date, prompt more cta
</div>
</div>
</div>
</>
)
};
Which will take longer for the next developer to parse and understand. They're now having to understand the 'how' rather than the what. From the first enclosing div where there was just <LandingSection />, it now includes all of the 'how' for the landing instead.
If I wanted to make a change to the articles section, I could do it here. However, I would first need to find where the article UI is in this file. Then be cognisant of how changes will affect other aspects of this file. Furthermore, we lose out in some easy reusability we could add. The article and project sections are doing the exact same thing, however they have been re-written which isn't very DRY. We could group their responsibilities into one component, then extend that component to handle either type of data, posts or projects.
So we've lost readability, increased cognitive load, and missed composition amongst other principles.
Wrapping up
Not every file is best suited to under a hundred lines. There are valid reasons to go beyond that. Don't take this rule of thumb as gospel. However, you should use it to frame readability, cognitive load, and composition. The easier to read the code is, the easier it is to maintain, the easier it is to extend.
So, "could we bring this file under a hundred lines?"

