Abstraction in Elm: Introduce Local Functions

Matthew Buscemi
3 min readJan 16, 2018

--

Table of Contents

  1. Introduction
  2. One Expression to Rule Them All
  3. Introduce Comments
  4. Introduce Local Functions
  5. Utility-Based Modularization
  6. Domain-Based Modularization
  7. Wrappers and Generics for Everything
  8. Conclusion

Code

Discussion

This code demonstrates a refactor in which many portions of the monolithic expression have been reorganized into separate functions. We are no longer living in a world of a single mega-function, but rather many small functions that each serve a discrete purpose.

What effects have these changes had?

The first and most obvious effect is the obliteration of the duplication present in both of the previous code examples. If I want to change the duration of the fade effect in the oscillation, I can now change it in one place and the entire system is affected. If I want to add a third animation transition to the oscillation and have it affect all oscillations in the system, there is one place to do that.

But the removal of duplication is not the only positive effect. This code communicates its intent at least as well as the comment method. But, unlike the comment method, the intent is baked into the structure of the code. In order to change that intent, an engineer will have to restructure the code in some new way, and they will be beholden to the compiler.

In addition, all these new functions we’ve added come with names, and those names provide additional contextual clues. If an engineer starts to make a change that violates the intent, a good name can give them pause to reconsider their change’s effect on the system.

And finally, we have created a new situation in our case statement that wasn’t possible before. Look how small it is compared to previous incarnations. And not only is it smaller, but examine how it reads: statusBarColorStyle = colorOscillation GeneratingTests model.statusBarColorStyle. If I am coming to this code for the first time, and I see this line, I know immediately, after reading only five discrete symbols, that this code likely starts a color oscillation effect on the status bar, based on the current status of GeneratingTests. This was not possible with our previous code. In order to arrive at this same conclusion in previous examples, we had to carefully read eleven full lines of code and probably also compare those eleven lines to other parts of our system just to be sure.

There is one downside, and it is non-trivial. In order to find out the details of how the colorOscillation works, the engineer has to go searching for its definition.

By introducing this abstraction, we’ve made our intent both clear and resilient to accidental change, but at the cost of making some of the details of our system harder to find.

Analysis

Pros

  • The duplication has been eliminated.
  • It is clearer why the code is the way it is, and it is difficult to change the code behavior independently of this communication.
  • Relationships between different portions of code are clearer as well.

Cons

  • We have slightly obscured what the code does. This is because we have introduced a small amount of indirection. Upon seeing colorOscillation for the first time, an engineer must go searching for its definition in order to discover how it works.

Continue to Abstraction in Elm: Utility-Based Modularization.

--

--