DEV Community

Discussion on: Keeping your code clean by sweeping out "if" statements

Collapse
 
khtony profile image
Breton F • Edited

Just for testing the if version would have been way more difficult to write without any added value.

Map is an interface meaning more flexibility. Yes a little more complex.

The map in the example is static but could be a dynamic configuration or comes from anywhere.

Yes it depends on the context. But this pattern is relevant. I like it

Collapse
 
tomazfernandes profile image
Tomaz Lemos

Hi Breton, thanks for your feedback!

Thread Thread
 
khtony profile image
Breton F

Thanks for sharing, I will read it..

Thread Thread
 
tomazfernandes profile image
Tomaz Lemos

I decided to rewrite that post based on your and other fellow DEV's feedback, if you'd care to read the new version I'd really appreciate!

dev.to/tomazlemos/let-s-talk-trade...

Collapse
 
tomazfernandes profile image
Tomaz Lemos

Hi Breton, those are some very good points, thanks!

I’m in need of some feedback on this other pattern, if you care to take a look I’d really like to hear your thoughts:

dev.to/tomazlemos/implementing-a-s...

Happy New Year!

Collapse
 
mindplay profile image
Rasmus Schultz

Just for testing the if version would have been way more difficult to write without any added value.

I'm not sure what you mean?

The test burden is the same - it has to cover every case.

If the map was somehow open to dependency injection, this would have been a different case, where you could inject a simpler map with mock values, leading to a simpler test case. But as it is now, the map is an implementation detail - your test needs to cover every supported case, so there's no difference in terms of testing. (Your test should not assume implementation details like a map or an if-else ladder, since these details could change; the subject of this post.)

Yes it depends on the context. But this pattern is relevant. I like it

I wasn't trying to say it isn't relevant or I didn't like it. 🙂

I'm just raising awareness of the limitations - when introducing an abstraction (whether it's one you design, or an existing one, in this case a map) there is always a trade-off in terms of flexibility.

Map is an interface meaning more flexibility.

Once you adopt an abstraction, you're limited to whatever that abstraction defines as being the responsibility, which means less flexibility.

Unless you have some other definition of flexibility.

But I think I was clear with my example on what I define as flexibility: the freedom to add another condition that doesn't conform to a precise pattern, in this case the map abstraction.

Of course, you could abstract further to cover use-cases with new conditions, but at that point you're taking on more complexity.

So you have to weigh the pros and cons. Introducing an abstraction is always less flexible and can always lead to more complexity - I think that's definitely demonstrated by the example I gave here.

And the author agrees with me:

Your point is a valid one, in that the map version is a lot less flexible than using ifs.

Again, that doesn't mean this pattern isn't relevant. It doesn't mean I don't like it. It just means you shouldn't make decisions like these without understanding the trade-offs. You should have a practical reason, which, in my opinion, should go beyond implementation details - if you add abstraction, it should be because there's a practical reason to do so.

For example, a need for dependency injection, which would allow different message handlers to be plugged in, would allow testing with mock message handlers, and so on.

There are plenty of valid reasons to choose maps or other abstractions - this wasn't a criticism of the post, just an addendum. 🙂

Thread Thread
 
tomazfernandes profile image
Tomaz Lemos

Hi Rasmus!

One thing I’ve learned from this post and all the discussion around it is that it should have been more about tradeoffs. I wrote a new post, about a different pattern, based more around the tradeoffs, and I think it’s a far better approach.

About the flexibility, one thing that came to mind is that this pattern is just as flexible as a switch statements, isn’t it? If something coded as a switch statement has to embrace a more complex condition you’d have to refactor it anyway. And yet I’ve never seen anyone argue that this should be taken into consideration when using switches.

I’m writing a new post with some more examples of pattens such as this, and in my experience once you have a minimal toolset of these patterns you can change pretty much any repetitive-if situation into a declarative one, without much effort.

As for the valid reasons for using the pattern, my point is that it makes the business rules a lot more readable, which in my experience leads to easier maintenance and less bugs.

I’d have preferred that the discussion gravitated more towards the business rules clarity than to the if or not if part, but again that’s on me for the way I’ve written the post.

I do appreciate your feedback a lot, thanks!

Thread Thread
 
khtony profile image
Breton F

@Rasmus

We may not see the problem with the same lens. I ll just try to make my points clearer. Hope we could agree later.

A map is a contract and practically a function. You give it a key it does some magic and return back to you a value. Your map implementation is up to you. So by providing a specific map and boom you can do stuff of your imagination. This for me is flexibility as you pick your map based on your requirements.

Unit tests burden
With the map/function version, I give a key and I get back a value. I do not need to go for all possible keys for my unit tests. Because what I m interesting in is the contract i.e ability here to translate an error code to something else.