Writing

Refactoring: from strategy to interpreter pattern with Jest testing tool

Summary

My previous article extracted conditions into functions on simple cases. Harder situations are not solved by an extraction, and this one takes such a case: evaluating an expression like 1 + (6 + 5) * 8 while respecting associativity and operator precedence.

The first solution is the one everybody writes: an Expression class with an operator, a left operand and a right operand, and a switch to evaluate. It works, and it breaks the open/closed principle, since every new operator forces a change to the switch. Polymorphism fixes that: an abstract Expression, a ValueExpression for values, one OperatorExpression per operator, and a new operator becomes a new class that touches none of the others.

But polymorphism alone does not hold against a deeply nested expression. Hence the interpreter pattern, laid on top: a Lexer that splits the string into tokens, a Parser that reorders them by precedence with an algorithm inspired by merge sort, and an Interpreter that evaluates them with a stack. The strategy pattern has not gone; it still evaluates each operation through a Map of operators.

What made the whole journey possible were the Jest tests written first and updated at every step: no change is accepted unless they pass. The repository keeps one branch per step.

Key ideas

  • A switch in the evaluator breaks the open/closed principle: every new operator changes existing code.
  • Polymorphism, one class per operator, makes adding an operator trivial and removes the switch.
  • Faced with nested expressions, a lexer, a parser and an interpreter take over, and the strategy pattern stays beneath the interpreter.
  • Jest expectations, written first and updated at every step, are what make the refactoring verifiable.

Why I wrote this

In my previous article we had explored how to extract conditions into functions on simple, practical cases. More complicated situations are not solved by simple extractions.

Companion repositories