DEV Community

Cover image for Code Smell 193 - Switch Instead of Formula
Maxi Contieri
Maxi Contieri

Posted on • Originally published at maximilianocontieri.com

Code Smell 193 - Switch Instead of Formula

Which is better, declarative or shorter code?

TL;DR: Be declarative enough but no more.

Problems

Solutions

  1. Use a short version (or not).

  2. Always favor readability >> Premature optimization.

  3. Humans learn by examples, not by formulas.

  4. Shorter is not always better.

Context

Last week, a tweet went viral because of a missing formula.

It is the DigiD digital authentication iOS app in the Netherlands.

Sample Code

Wrong?

private static string GetPercentageRounds(double percentage)
        {
            if (percentage == 0)
                return "⚪⚪⚪⚪⚪⚪⚪⚪⚪⚪";
            if (percentage > 0.0 && percentage <= 0.1)
                return "🔵⚪⚪⚪⚪⚪⚪⚪⚪⚪";
            if (percentage > 0.1 && percentage <= 0.2)
                return "🔵🔵⚪⚪⚪⚪⚪⚪⚪⚪";
            if (percentage > 0.2 && percentage <= 0.3)
                return "🔵🔵🔵⚪⚪⚪⚪⚪⚪⚪";
            if (percentage > 0.3 && percentage <= 0.4)
                return "🔵🔵🔵🔵⚪⚪⚪⚪⚪⚪";
            if (percentage > 0.4 && percentage <= 0.5)
                return "🔵🔵🔵🔵🔵⚪⚪⚪⚪⚪";
            if (percentage > 0.5 && percentage <= 0.6)
                return "🔵🔵🔵🔵🔵🔵⚪⚪⚪⚪";
            if (percentage > 0.6 && percentage <= 0.7)
                return "🔵🔵🔵🔵🔵🔵🔵⚪⚪⚪";
            if (percentage > 0.7 && percentage <= 0.8)
                return "🔵🔵🔵🔵🔵🔵🔵🔵⚪⚪";
            if (percentage > 0.8 && percentage <= 0.9)
                return "🔵🔵🔵🔵🔵🔵🔵🔵🔵⚪";

            return "🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵";
        }
    }
}

// Full source
// https://github.com/MinBZK/woo-besluit-broncode-digid-app/blob/master/Source/DigiD.iOS/Services/NFCService.cs
Enter fullscreen mode Exit fullscreen mode

Right?

private static string GetPercentageRounds(double percentage)
{
    string dots = "🔵🔵🔵🔵🔵🔵🔵🔵🔵🔵⚪⚪⚪⚪⚪⚪⚪⚪⚪⚪";
    int blueDots = (int) Math.Truncate (percentage* 10);
    int startingPoint = 10-blueDots;
    return dots. Substring(startingPoint, 10);
}

Enter fullscreen mode Exit fullscreen mode

Detection

[X] Semi-Automatic

This is a semantic smell. In this case, we can count the number of if clauses.

Tags

  • Readability

Conclusion

You can read the original Twitter thread to take your own conclusions. There's some serious debate and, of course, several premature optimizators bringing obscure and unneeded solutions with (O) log(n) complexity and stupid benchmarks evidence for a loop that executes only once.

And lots of memes.

As a final conclusion, I asked ChatGPT and was not able to simplify it.

Relations

More Info

Disclaimer

Code Smells are just my opinion.


There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.

C. A. R. Hoare


This article is part of the CodeSmell Series.

Oldest comments (7)

Collapse
 
moopet profile image
Ben Sinclair

The thing that confused me most about this function is the fact that the parameter is called percentage but it's not a percentage.

It'll work if you pass a percentage like 37.5 or even 200.0, but it'll only display anything other than ten dots if it's < 1%.

Maybe that's what the code is supposed to do... but I doubt it!

Collapse
 
lionelrowe profile image
lionel-rowe • Edited

Why not just programmatically repeat the relevant glyphs the required number of times? Returning a substring of a string containing 10 of each glyph is a bit too magic for my liking, and difficult to see at-a-glance if you've miscounted.

private static string GetPercentageRounds(double fraction) {
    int max = 10;
    string on = "🔵";
    string off = "⚪";

    int numDots = (int) Math.Ceiling(fraction * max);

    return string.Concat(Enumerable.Repeat(on, numDots))
        + string.Concat(Enumerable.Repeat(off, max - numDots));
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
mcsee profile image
Maxi Contieri

This code is less declarative than the original one. It is very hard to understand what is doing without running it on your head

Collapse
 
lionelrowe profile image
lionel-rowe

I don't usually use C#, I just saw that string.Concat(Enumerable.Repeat(str, num)) is the idiomatic way to repeat a string in C# (as opposed to repeating a char, and '🔵' isn't a valid char due to being 2 code-units in UTF-16).

You could always split that into its own function:

private static string RepeatStr(string str, int num) {
    return string.Concat(Enumerable.Repeat(str, num));
}

private static string GetPercentageRounds(double fraction) {
    int max = 10;
    string on = "🔵";
    string off = "⚪";

    int numDots = (int) Math.Ceiling(fraction * max);

    return RepeatStr(on, numDots) + RepeatStr(off, max - numDots);
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
mcsee profile image
Maxi Contieri

still less declarative

Thread Thread
 
lionelrowe profile image
lionel-rowe

Under what definition of "declarative"? There's no explicit control flow whatsoever (whereas the original has 10 if statements, lol). What do you understand "declarative" to mean if it's not lack of explicit control flow?

Collapse
 
mcsee profile image
Maxi Contieri

Me too. Is more declarative. The spirit of the article is to create discussions