Last week I came across a block of code during a code review that had a hint of code smell, and although I didn't have an immediate solution, it looked like something worth digging into. The goal was to add a field to a schema, but it needed to be added in a particular place in the schema. This meant that in the migration a handful of fields needed to be temporarily renamed, reordered, then renamed one last time back to their original name. This is the block of code that caught my attention (with the data generalized):
The repeating of the logic with only the values changing could be simplified, but what was throwing me a bit was that there are two different collections of data that need to be looped over synchronously. It's not uncommon to execute an
Enum.map/! inside an
Enum.each, or vice versa, or other combinations of that nature; but that wouldn't work here.
After looking at the docs, the very last function seemed like it would work for this situation,
Enum.zip/2. It takes two collections and converts them to one list of tuples, which can then be looped over. Using that function, the block of code above can be refactored to this:
Enum.zip/2 converts those two collections into this:
The tuple syntax looks a bit odd, as far as I can tell it is because both values are atoms. But, they are in fact tuples and because of this they can be treated as key/value pairs and looped over in the
Enum.each to rename the fields in the
It may not look like a huge improvement, but in the code review there were something like twelve fields to be renamed, so in that case it was worth the refactor. This also isn't the first case where I felt a problem might be solved by looping over two collections of data synchronously, so finding this solution was definitely time well spent.
This post is part of an ongoing This Week I Learned series. I welcome any critique, feedback, or suggestions in the comments.