One takeaway from this: she didn’t arrive at this solution by banging out more tests or writing more code, generally. The solution resulted in less code, and it was superior.
The most powerful tool we have as developers is thinking.
One of my big beefs with seeing programming as little more than duct-taping a bunch of npm modules together is that the instinct for searching for an insight that greatly tames the problem gets nuked from the outset.
The journey here is tough but it is worth it.
I thought this was a really nice approach on the problem, and I’m glad I spent ten minutes hacking out my own solution before reading hers. If you haven’t seen this kata before, would you try an experiment before you read this article? You could go in blind or try the problem with the hint in my next paragraph and see if you arrive at a similar solution to hers.
Hint: look for type transitions in the problem.
Spoiler discussion: Looking at the final code and how she describes the key insight, I found myself wanting to talk about it in terms of type transitions. The additive rule is Fixnum -> String and the subtractive is String -> String, though there are aliases so this looks more like Fixnum -> AdditiveRoman -> SubtractiveRoman. It’s the nature of every insight that it looks obvious in retrospect, so it’s hard to say, but I believe someone walking into this problem treating the rules as type construction would also arrive at this same nice solution, in a way that’s a little more straightfoward than “write code for 20 years until you’re suspicious of every if and have the intuition to see what’s wrong”.
Fixnum -> String
String -> String
Fixnum -> AdditiveRoman -> SubtractiveRoman
I can’t decide if this version is ugly or not: https://gist.github.com/mmueller/abd3e4bf351d53188be422916b2441d3
I named the constant “BRUTE” because it is a sort of brute-force approach, but the logic is so straightforward using it.
Yes, I think that version is ugly. But you can make it not ugly by starting with a non-brute value map that contains only the single letters, then converting it into your current brute value map programmatically.
That would be taking the same approach as the author in splitting the work into two steps, one of which accounts for the second rule of Roman numerals. But you would be acting on the value map ahead of time instead of the number that was input. I kind of like that method more since you don’t temporarily have an invalid Roman number floating around.
My takeaway: “Try splitting transformations into two passes.” This will simplify the code and add maintainability, at the expense of performance.
I think that formulation is easier to spot applications for than “make everything the same” or “look for type transitions”. Though maybe that’s because my projects these days don’t use statically typed languages.