LeTerzo

Code Health

A passionate agency with a battle-tested process for getting you results

This is another post in our Code Health series. A version of this post originally appeared in Google bathrooms worldwide as a Google Testing on the Toilet episode. You can download a printer-friendly version to display in your office.

by Cathal Weakliam

Loops are the standard way to process collections like arrays and lists. However, some loops implement the same patterns repeatedly, leading to duplicate code. Higher-order functions—functions that use other functions as inputs or outputs—can reduce duplication by providing a simpler way to express common operations with collections.

Consider these two loops in JavaScript that decide if every object in an array meets a condition:

let everyRequestValid = true; for (const request of requests) { if (!isValid(request)) { everyRequestValid = false; break; } } if (everyRequestValid) { // do something }let everyUserEligible = true; for (const user of users) { if (!isEligible(user)) { everyUserEligible = false; break; } } if (everyUserEligible) { // do something }

The high similarity between the two loops violates the Don’t Repeat Yourself principle and creates an unnecessary burden on readers and maintainers of the code.

To reduce the maintenance burden, use the every method to replace each loop with a single expression.  (In other languages every may have a different name, like all or allMatch).

if (requests.every(isValid)) { // do something }if (users.every(isEligible)) { // do something }

Processing collections with higher-order functions has several benefits:

  • It significantly reduces duplication by abstracting away the common looping code.
  • The resulting code is much shorter and simpler, with less opportunity for bugs.
  • A reader can quickly see the intent of the code as it is not obscured behind low-level control flow.

Two other common higher-order functions are map (apply a function to each element of a collection) and filter (select the elements of a collection that pass a predicate). While the exact syntax varies by language, here’s how they look in JavaScript (using an anonymous function as the argument):

// Double each value in `ints` const doubled = ints.map(n => n * 2);// Get only the even values in `ints` const evens = ints.filter(n => n % 2 === 0);

Just don’t overdo it! Don’t rewrite a loop with functions if it makes it harder to understand, or if it would be considered unidiomatic in your language (for example, in Python, list comprehensions are equivalent to map and filter but are usually preferred).