Let’s explore why predictable programs are beneficial and how to increase predictability.

When writing code, one of the most important goals is to write it well.
The problem is that there is no objective standard that clearly defines what “well-written code” actually means.
However, we generally consider good code to be “easy to read,” “easy to maintain,” or “less prone to bugs.”
Put more simply, it is code that is less likely to cause problems.
So how can we reduce the likelihood of problems?
The answer is simple: we must write predictable code.
No reasonable developer intentionally writes problematic code.
Yet issues still occur because—even if the code was written by me (or our team)—we cannot always predict how it will behave.
Therefore, if we write predictable code, the probability of problems decreases, and the likelihood of writing “well-written code” increases.
Admittedly, this may sound idealistic or even unrealistic.
It is nearly impossible to make an entire app or website completely predictable.
However, if we narrow the scope and make each individual building block of the app predictable, then an application composed of those predictable pieces can realistically become predictable as a whole.
In this article, we will ultimately discuss how to make the building blocks of an app predictable. For now, let’s narrow the scope further and use a function as an example.
As we all know, a function is a block of logic that receives input (or none), performs some computation, and produces output (or none).
If we want to make a function predictable—or eliminate the factors that reduce its predictability—we can gradually turn it into a better, more predictable function.
To do that, we first need to understand what reduces a function’s predictability.
As mentioned above, a function performs “input → computation → output.”
The problem arises when elements outside of that input, computation, and output are involved, or when the function affects external elements. This is called a side effect.
For example, consider the following code:
const todos = [];
function addTodo(todo) {
todos.push(todo);
}
The addTodo function takes todo as input, performs the computation todos.push(todo);, and returns nothing.
It works correctly, but because it modifies an external variable todos, it creates a side effect.
Another example:
function getSomePostByUserId(userId) {
return fetch(`https://api.someapi.com/posts?userid=${userId}`).then((res) =>
res.json(),
);
}
getSomePostByUserId does not appear to affect external state, but it is influenced by external factors—the network.
The value it returns depends on whether fetch succeeds, and that success is outside the function’s control.
From these examples, we can conclude that a side effect occurs when a function affects external state or is affected by external state.
Another factor that reduces predictability is inconsistent output.
If a function does not return the same output for the same input, there is a high chance that side effects are involved.
For instance, if we fix userId = 1 and call getSomePostByUserId 100 times, some results may differ from others.
Returning to the main point, to write predictable code, we must minimize side effects.
(It would be ideal to eliminate them entirely, but that is nearly impossible in reality.)
A function without side effects is called a pure function, and this concept becomes the starting point of React.
Let’s summarize what we’ve discussed so far.
If we add just one more idea, we can begin talking about React.
Components—the building blocks of React—are functions.
Before explaining what a component is, let’s briefly describe React.
React is a library that helps you build UI in a declarative way. (Reference: React Official Docs - The library for web and native user interfaces)
When I first read that sentence, I did not understand it at all.
What does “declarative” mean? Why is it a library rather than a framework? I had many questions.
If I rephrase it in a way that was easier for me to understand:
“When a developer declares the desired UI (a view made of HTML + JS) using tools provided by React, React takes care of rendering it.”
More specifically, React uses a syntax called JSX.
It can be explained in complex terms, but simply put, it is “HTML that can use JS” or “a syntax that allows you to write HTML while leveraging JavaScript features.”
HTML allows us to draw structured markup in a declarative way.
Here again, the word “declarative” appears—but it becomes clear with an example:
<nav>
<h1>Logo</h1>
<ul>
<li>Nav Item 1</li>
<li>Nav Item 2</li>
<li>Nav Item 3</li>
</ul>
</nav>
We simply declare “this goes here, that goes there” using HTML tags, and when executed, the structure is rendered accordingly.
That is what declarative means. If you describe what you expect, it gets rendered without you giving step-by-step instructions.
What about JS? JavaScript can be viewed as a collection of tools that help solve complex problems using its syntax.
Returning to the React explanation, in the sentence “React is a library that helps you build UI in a declarative way,” the “build UI” part is achieved through JSX.
When we write JSX, React processes it internally and renders the UI.
Now, if we focus on the keyword “declarative,” the sentence becomes much clearer.
JSX is powerful—but a fundamental question remains:
How do we reuse this JSX? → This is where the concept of a component comes in.
A component is “a function that takes input and returns a UI description.”
The input is props, and the return value is JSX (= a UI description).
If the same props always produce the same JSX, then the component is a pure function.
export default function BookList({ books }) {
return (
<section>
<h2>Favorite Books</h2>
<ul>
{books.map((title) => (
<li key={title}>{title}</li>
))}
</ul>
</section>
);
}
books arraymap<section> ... </section>It does not modify external state, it does not make network requests, and the same books will always render the same UI.
In other words, it is a pure function without side effects, and therefore predictable.
A component is ultimately a function. For a function to be predictable, we must remember three principles: clear input and output, no unnecessary side effects, and a single responsibility.
First, a component’s input is props, and its output is JSX. If the same props are given, the same screen must always be rendered in order to trust the UI.
Second, if you execute code inside a component that affects the outside world—such as network requests or console logs—the output becomes unpredictable. The React team recommends isolating such side effects inside event handlers or Hooks (useEffect) to preserve “pure components.”
Third, dividing components into small, focused units makes testing and refactoring easier. A small function with a single responsibility is easier to test, and changes have limited impact on other parts of the system.
In short, if we treat components like pure functions, we can apply the predictability we learned from functions directly to the UI layer.
To summarize, React is “a library that helps you build predictable UIs by combining the declarative nature of HTML with JavaScript’s function and module systems.”
Ultimately, the React team’s goal is to make it easy to build applications composed entirely of predictable components.
Such applications are easier to read, easier to maintain, and less prone to bugs.
In the end, the starting point of building a “good web” experience is predictable code, and React is a tool that naturally brings that philosophy into the UI world.