Refactoring Towards Pure Functions

In one of my articles a commenter wrote that he was "in general, refactoring towards pure functions". Now, usually the word "towards" does not lend itself to bold statements, but I grew fond of the expression because it expresses precisely a couple of things that I rarely read or hear about. Black and white thinking Before I get into specifics, this article has a message: black-and-white thinking about paradigms is costing us code quality. In other words forcing a paradigm onto a varied set of problems will over- or underengineering the required solutions. As I wrote in my previous article Do you need classes in JS/TS?, when you have state to persist between calls and it's not trivial to manage that, using a class (or an equivalent object + scope combo) is the right way. It's akin to serving your dish with the appropriate cutlery (note that in JavaScript people can eat with their hands regardless of your attempts to neatly tuck things away - see also "monkey patching"). I maintain that even in a mostly functional codebase, if you encounter this particular problem, you're better off using a class than creating convoluted functional workarounds. That's why I like the term "refactoring towards pure functions"! We try to convert everything into a pure function, but if that results in something awkward or it just complicates the code, we keep what we have - or even rewrite it in OO-style! Spotting a Useless Class With the mindset of turning everything into pure functions, I began finding patterns of useless classes - ones that just complicate things without leveraging what a class could offer. Here is my simple algorithm to spot and remove such classes, hopefully resulting in a cleaner code base! A class Without Methods If a class has no methods then, it's just you a POD (plain-old-data) structure. You can simply use your everyday JS object: {} (of course you should define its type in TypeScript). class Person { constructor(firstName: string, lastName: string, occupation: string) { this.firstName = firstName; this.lastName = lastName; this.occupation = occupation; } // we have no methods here } const onePerson = new Person('Edward', 'Elric', 'Alchemist'); // Instead, simply: type SimplerPerson = { firstName: string; lastName: string; occupation: string; } const otherPerson: SimplerPerson = { firstName: 'Alphonse', lastName: 'Elric', occupation: 'Alchemist' }; // Notice that the second solution is more descriptive! // If you make a mistake and pass "Alchemist" to "firstName", // seeing the label "firstName" will alert you or the reviewer // that something is off. (You might have a special case where you may want to use a class for relying on instanceof, but I can provide an alternative for that in TypeScript - would you rise up for the challenge in the comments?

Apr 11, 2025 - 12:12
 0
Refactoring Towards Pure Functions

In one of my articles a commenter wrote that he was "in general, refactoring towards pure functions". Now, usually the word "towards" does not lend itself to bold statements, but I grew fond of the expression because it expresses precisely a couple of things that I rarely read or hear about.

Black and white thinking

Before I get into specifics, this article has a message: black-and-white thinking about paradigms is costing us code quality. In other words forcing a paradigm onto a varied set of problems will over- or underengineering the required solutions.

As I wrote in my previous article Do you need classes in JS/TS?, when you have state to persist between calls and it's not trivial to manage that, using a class (or an equivalent object + scope combo) is the right way. It's akin to serving your dish with the appropriate cutlery (note that in JavaScript people can eat with their hands regardless of your attempts to neatly tuck things away - see also "monkey patching").

I maintain that even in a mostly functional codebase, if you encounter this particular problem, you're better off using a class than creating convoluted functional workarounds.

That's why I like the term "refactoring towards pure functions"! We try to convert everything into a pure function, but if that results in something awkward or it just complicates the code, we keep what we have - or even rewrite it in OO-style!

Spotting a Useless Class

With the mindset of turning everything into pure functions, I began finding patterns of useless classes - ones that just complicate things without leveraging what a class could offer.

Here is my simple algorithm to spot and remove such classes, hopefully resulting in a cleaner code base!

A class Without Methods

If a class has no methods then, it's just you a POD (plain-old-data) structure. You can simply use your everyday JS object: {} (of course you should define its type in TypeScript).

class Person {
  constructor(firstName: string, lastName: string, occupation: string) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.occupation = occupation;
  }

  // we have no methods here
}

const onePerson = new Person('Edward', 'Elric', 'Alchemist');

// Instead, simply:
type SimplerPerson = {
  firstName: string;
  lastName: string;
  occupation: string;
}

const otherPerson: SimplerPerson = {
  firstName: 'Alphonse',
  lastName: 'Elric',
  occupation: 'Alchemist'
};

// Notice that the second solution is more descriptive!
// If you make a mistake and pass "Alchemist" to "firstName",
// seeing the label "firstName" will alert you or the reviewer
// that something is off.

(You might have a special case where you may want to use a class for relying on instanceof, but I can provide an alternative for that in TypeScript - would you rise up for the challenge in the comments?