1

someone gave me example about how to refactor if-else code.

function doSomething(a) {
    if (a === 'x') {
        doX();
    } else if (x === 'y') {
        doY();
    } else {
        doZ();
    }
}

it should refactored to:

function doSomething(a) {
    var lookup = {x: doX, y: doY}, def = doZ;
    (lookup[a] || def)();
}

but I said it is a bad example. the first piece of code is sample enough. I think it is ok to have those if-else. The second piece of code is not as clear as the first one.

then he gave me another example:

function rank(score) {
    var star
    if (score > 89) {
        star = 9
    } else if (score > 74 && score < 90) {
        star = 8
    } else if (score > 59 && score < 75) {
        star = 7
    } else if (score > 44 && score < 60) {
        star = 6
    } else if (score > 29 && score < 45) {
        star = 5
    } else if (score >10 && score < 30) {
        star = 4
    } else if (score > 8 && score < 11) {
        star = 3
    } else if (score > 6 && score < 9) {
        star = 2
    } else if (score < 7) {
        star = 1
    }
    return star
}  

I still though it is accepted. it is not big or complicated. easy to know what is doing. I will code like this just remove the condition after &&. I don't like to write so much if-else like this, but I cannot find a better way.

I asked he how to refacot it, he gave me the code he refactored.

function rank(score) {
    var ranges = {
        9: [90: Infinity],
        8: [75, 90],
        7: [60, 75],
        6: [45, 60],
        5: [30, 45],
        4: [11, 30],
        3: [9, 11],
        2: [7, 9],
        1: [-Infinity, 7]
    }
    var count = _.findKey(ranges, function(range) {
        return range[0] <= score && score < range[1]
    })
    return count >>> 0
}

I think the code refactored is more complicated then the origin code, easy to make mistake. and I don't like to use a hash map to refactor the if-else.

he said I should read some article about functional programming. they don't have if-else. they use pattern-matching and guard. I know litte about Scala and Haskell. I think pattern-matching just like switch statment. just more powerful.

I coped a piece of Haskell code from wiki:

describeLetter :: Char -> String
describeLetter c
   | c >= 'a' && c <= 'z' = "Lower case"
   | c >= 'A' && c <= 'Z' = "Upper case"
   | otherwise            = "Not an ASCII letter"

If I use Haskell to write this logic, I will write it like this, and I think it is similar to the origin code, not the code refactored by him.

My question is which code is better, the origin one or refactored one? why? or there is any other way to refactor this code?

Is it a good practice to use hash map to refactor if-else?

Thanks for your ansower!

level55
  • 89
  • 7
  • 1
    BTW: that condition does not make any sense: **else if (score < 74 && score < 90)** Anything that is **< 74** will be **< 90** – B001ᛦ Nov 27 '15 at 10:01
  • 1
    @bub sorry, I will fix it. Thanks! – level55 Nov 27 '15 at 10:02
  • 1
    Make sure to `===` for your equivalency comparisons. –  Nov 27 '15 at 10:05
  • 1
    @Shinobi881 ok, I will change it. Thanks! – level55 Nov 27 '15 at 10:06
  • 5
    The question is heavily opinion based, I'd say even off-topic. I'd use a hash map or an array if there would be more than two elses ... – Teemu Nov 27 '15 at 10:08
  • It you can understand what's happening go with the refactored examples as final code. "Make it work, make it right, make it fast!". Your more functional refactors should have more expressive variable names. –  Nov 27 '15 at 10:11
  • Btw, it should be just `(lookup[a] || def)();` – Bergi Nov 27 '15 at 10:27
  • Just saying, `score < 89` is still wrong. So much for "easy to make mistake". – Bergi Nov 27 '15 at 10:31
  • @Bergi yes, I known, this piece of code come from a book. I just keep the same. I will change it. do you think hash maps is a good way? – level55 Nov 27 '15 at 10:33
  • @level55: yes, they're much clearer than lines of if-elses. Also, given that they're a *structure* (not code), they can be trivially manipulated, shared, stored, loaded etc. – Bergi Nov 27 '15 at 10:35
  • In Haskell I'd probably write `rank score = 1 + maybe 8 (findIndex ( – Bergi Nov 27 '15 at 10:39
  • @bergi so you mean I should make the structure like a configuration. the convert it to the rule. it is ok even if the rule is complicated. just make the configuration is readable. – level55 Nov 27 '15 at 10:51
  • @Bergi, but if I use a structure, like the example, if I make a mistake in the configuration, 4: [11, 22, 30], it would not make a compile a error or runtime error. – level55 Nov 27 '15 at 10:55
  • Yes, exactly, like a configuration. Do you expect the `rank` intervals to change or expand, the `doSomething` to do more? Then make those changes easy, without requiring to change the logic. Keep it small and dry. (More important than if vs array would be to reduce the non-overlapping intervals to only one border, like in my Haskell snippet). Admittedly, keep it reasonable - if the rules are getting complicated, don't make the [configuration evaluation more complex than the rules themselves](https://en.wikipedia.org/wiki/Greenspun's_tenth_rule). – Bergi Nov 27 '15 at 10:58
  • Since when does Haskell (and other "functional" languages) not have conditionals ("if-else")? – molbdnilo Nov 27 '15 at 13:44
  • @molbdnilo I just repeated what my friend said. – level55 Nov 27 '15 at 15:44
  • @Bergi I love your solution with Haskell. I think this is also could be used in js. – level55 Nov 30 '15 at 02:28

2 Answers2

0

I think the answer will depend on your situation.

If you're working on your own, pick the style you're more comfortable working with; after all, you are the one that's going to be (re-)reading your code — you need to be able to understand it fairly easily. I'd say if you can train yourself to understand hash maps at a glance, go for it, it'll save those precious taps on the keyboard.

If you're working in a professional environment, you have to understand that this code is not 'yours'. This code is going to be read by your colleagues and probably a number of your successors as well. You need to make sure your code is as readable and coherent as possible — if those extra 1-2 lines of code here and there make the entire program more readable, it's worth the investment. There's nothing worse than inheriting code from people that try to be 'too smart' when writing and end up with complex clumps of code that are barely readable, even by the author.

You'll also have to take into consideration the preference of your colleagues as well, perhaps there's even a guide to dictate how to write out these situations in code. In those cases, you should pick the preferred style opted for by the team — sometimes that may be the less readable version, but continuity will help ensure legibility as well.

Chris Davis
  • 423
  • 2
  • 10
0

All of this code for "refactoring", you just need to use switch, switch is faster than if else and most probably by all the other obscure code above.

more here - > Javascript switch vs. if...else if...else

P.S this is my personal opinion

Community
  • 1
  • 1
Vitaliy Terziev
  • 5,298
  • 3
  • 15
  • 24
  • What makes you think that "*switch is faster than if else*"? And why do you think that speed is the incitement for the refactoring? – Bergi Nov 27 '15 at 10:25
  • @Bergi i added a comment in my answer, and if not speed then why? All of the other code is ridiculously obscure and error prone. – Vitaliy Terziev Nov 27 '15 at 11:03
  • Well, all of the answers (and even the linked articles) there basically boil down to "performance is mixed because of different optimisations". None of the two is a clear winner. So if not for speed, then why? Because of readability and maintainability of course, as every refactoring! The refactored code is much more clear and concise. – Bergi Nov 27 '15 at 11:26
  • @Bergi you are correct indeed, if were me i would bet on switch, i am not agree only that the second doSomething is more readable than the first one for example. I will add personal opinion in my answer, i had some exp with simple canvas snake with switch vs else and the memory was reduced just a little bit. – Vitaliy Terziev Nov 27 '15 at 11:31