This week I didn't have any mind-blowing revelations, but those are like unicorns, I'm fortunate when I come across them, but I know that it wont happen all the time. I did -through a colleague's PR comment- discover another Elixir function that will make my future life a little bit easier,
I was back in the world of custom validations, and they were getting more deeply nested than I liked, but I didn't see any way to make them more concise.
There's a lot going on here, but let's focus on the case statements that are being executed. With this particular validation the error shown to the user is the same in the case of all the
falses, in hindsight that's a clue that this could be cleaned up.
When it's all said and done I need to check if
net_revenue_shared. But the fields coming in are not in the exact same shape, and 0 != 0.00. I first have to explicitly check if the fields are zero, and if not, then check if
That logic would look something like this:
This is where
Enum.any?/2 comes into play, as it invokes the function for each item in the collection returning
true if at least one invocation returns
false otherwise. Basically both of those chunks of logic can be dropped into that function, and if either return true, the changeset would be returned, and if either return false the error would be returned. So, the refactor would look something like this:
rev_minus_cost == @zero_with_decimal && net_rev == @zero_with_decimal line is equivalent to:
rev_minus_cost == net_rev line covers this case:
But, as I write this Im seeing how this can be refactored further and not even use
Enum.any?/2! Basically, the problem I was originally having was how the data was coming in, versus the result of the mathematical logic. Again, it all came down to the fact that 0 != 0.00. But by rounding both the
total_group_costs result and
net_revenue_shared data to the hundredth place, I'm essentially normalizing the data, and it can be compared to itself directly, even if the logic result or field is
So, the result of that refactor is this:
Well, I have to say, this is pretty awesome. While revisiting past work to write about a function, I see a way to refactor that code even further while writing about it, and ultimately refactor it in a way that it doesn't even need the function that the post is highlighting. It's great that deeply nested logic can be cleaned up so efficiently with
Enum.any?/2 (along with the related function
Enum.all?/2), but I'm actually pretty happy that I was able to removed the need for it in this particular example.
This post is part of an ongoing This Week I Learned series. I welcome any critique, feedback, or suggestions in the comments.