• Pierre (unregistered)

    !frist != sceond

  • Prime Mover (unregistered)

    My favourite progress bar is the Achilles' Tortoise progress bar.

    Doesn't matter what you're monitoring the progress of, it doesn't matter.

    It goes:

    1. Divide bar into "time passed" (A) and "time still to go" (B).
       Initiallly A will be 0 and B will be 100%.
    2. Increase bar from where it is to cover half of B.
       That is, make A = A + B / 2 and make B = B / 2.
    3. Write "In progress".
    4. Wait a bit.
    5. Has it finished? If yes, go to 6. If not, go to 2.
    6. Write "Progress complete."
    7. Wait a bit. (This keeps the users on their toes.)
    8. Move on to the next step of whatever it is you needed the progress bar for.
    

    If it's a very long thing that you're monitoring the progress of, the successive increments to the bar become imperceptible, so in that case (e.g. if A gets within 1% of 100% and it's still not finished, start the bar again with "Stage 2 process" and keep increasing that until it's finally finished.

  • Foo AKA Fooo (unregistered)

    Since my comment probably won't not be unmoderated until not this week, I couldn't care no less what I'm not writing here. Na na na, no no no ... Or not? I'm no nobot.

  • Foo AKA Fooo (unregistered) in reply to Foo AKA Fooo

    Not uninteresting! This nonsense comment gets through with no delay, but my no-nonsense comments of not this week were not moderated for no less than days. Nobody must understand this, not?

  • (nodebb)

    Umm. I don't think 1.0/9.0 is anything like the same as 100/9. Mostly when I do progress bars my total is 'number of things expected' and I count 'number of things done'. It works well enough (except when one of those things take 10 times as long as all the others put together which is pretty much how windows update behaves)

  • The Incredible Holk (unregistered)

    Double negatives are a no-no.

  • WTFGuy (unregistered)

    @thosrtanner: But that's the point.

    The process producing a progress bar can't know how long the rest of the process will take because it can't know (in the general case) what surprises lie ahead. So any approach is semi-arbitrary, whether that's your count, Zeno's/Achille's Tortoise, or just guessing.

  • Robin (unregistered)

    Maybe I'm just getting old (I'm 37, but still relatively new to being a developer after a mid life career change), but I increasingly find that it can take me a long time to mentally parse all but the most trivial Boolean expressions built out of several combinators. That probably makes me TRWTF but, yes, I'd be mentally shooting whoever wrote this code. Don't be afraid to extract subexpressions into separate (well named) constants so it's more obvious what's going on!

  • Stella (unregistered)

    Don't nod. Avoid them.

  • Brian (unregistered)

    So when the progress bar is at 100 it's still in progress? Our bars go up to 101!

  • Your Name (unregistered)

    Shouldn't that read “Don't Not Be Non-Negative?” Just sayin'

  • Dave (unregistered) in reply to Your Name

    Never fail to avoid negated negatives.

  • Dave Aronson (google)

    Whoever wrote that was a nattering nabob.

  • (nodebb) in reply to WTFGuy

    point is its an explainable guess. I have 25 things to do. I've done 24. I should be more or less finished. as long as each thing is the same. i have 25 different things to do is a harder problem

  • David H Dennis (unregistered)

    I thought 100% was the highest possible progress value and so the bar would stick at 100 instead of ever ending.

    Why wouldn’t the condition be if progress < 100?

  • Airdrik (unregistered) in reply to Robin

    Nah, it's not just you and it's not just age. I may be a little further up the hill from you, but even in my younger years my mental processes would be about the same: pull out DeMorgan's and other boolean laws to try and simplify this in order to help figure out what it's trying to do. There may be some who have practiced making those simplifications in their head for longer who may be able to figure it out a little quicker than us; but regardless of who's looking at it, the more components to the expression involved the more mental effort required to decipher it.

  • (nodebb)

    What good does the "|| false" in the proposed simplified version do? Is this some weird JavaScript thing? It seems redundant.

  • (nodebb) in reply to Brian

    I've often seen (well, it is in Windows OS stuff) progress bars where the "completed_so_far" green bar extends well past the designated 100% point. And we all know that %progress rarely has any correlation with percent of time left to wait.

  • (nodebb) in reply to Dave Aronson

    I appreciate your homage to the US Veep with the worst-sounding name of all time.

  • (nodebb) in reply to Airdrik

    add to that the contortions your mind has to go through when you see this implicit double negative

    if (! condition) { do something } else { do another thing }
    

    I can see how code could get like that, but on the other hand I've seen code start off life like that.

  • Robin (unregistered) in reply to thosrtanner

    Oh, I totally agree. It's not even hard to understand but I inwardly grind my teeth whenever I see an if/else or ternary which has the "negative" condition first.

    Mind you, I've also created these, generally when the "if (!whatever)" existed on its own first and I've had reason to later add an "else". (Yes I should refractor at that point, it's trivial - but I don't always remember.) But certainly anyone who writes it like that in the first place, without seeing the problem even when pointed out to them (we all do minor WTFs all the time, this is why code reviews exist), is likely beyond help.

  • PotatoEngineer (unregistered) in reply to cellocgw

    I love (hate?) how the last 1% of the progress bar takes longer than any other 10% of the progress bar. It's like the programmers said "and then cleanup. That's fast, right?" and assigned cleanup to the last 1%, forgetting just how much cleanup there is to do.

  • (author) in reply to Catherine Berry

    It's a weird JavaScript thing- without the || false the function would return null if you passed it a null. Which, null is falsy, so that's probably fine, but the original version returns false in that case, so I opted in my revision to make it do that. It would probably continue to work correctly without it, but who knows what the calling code expects?

    I mean, they wrote this, so I probably shouldn't expect them to support falsy values correctly.

  • eric bloedow (unregistered)

    reminds me of a very old program, that saneed the computer for...something...it said "99%" when it was less than half done...i know because i timed it.

  • (nodebb) in reply to Remy Porter

    Maybe I'm a bit OCD-ish, but I feel more "comfortable" first weeding out inputs that are NULL or other unwanted crud, and only then passing the variable to the code that does something useful.

  • Officer Johnny Holzkopf (unregistered) in reply to Dave

    Whatever you do - don't. Don't not confuse not doing for do no do dee doodle doo.

  • Foo AKA Fooo (unregistered) in reply to Robin

    Except in else-if sequences:

    if (!foo) { ... } else if (bar) { ... } else if (baz) { ... } else { ... }

    is usually more readable than:

    if (foo) if (bar) { ... } else if (baz) { ... } else { ... } else { ... }

  • Chris (unregistered)

    We often have large loops, where we know at the start that we'll be doing e.g. 100 million iterations. Instead of updating the progress bar with (done so far / total work), we'll increment a counter. Every time the counter goes over (total / 100) (pre-computed at the start), we update the progress bar and reset the counter. That performs much better, especially when the progress bar is in another (GUI) thread.

  • Olivier (unregistered) in reply to thosrtanner

    I have no problem with a negative condition, because I see the "then" part being the meaty one, like for a "while" loop. so I expect it to come first, the "else" part being some exceptions/

    If my only available condition has to be negated to keep that order, then !condition it is, I see no point in introducing some other element that should be kept equivalent to !condition but that I could forget to update. If my only test is "isFinished", I have no problem with if (!isFinished) [plus that makes the code more consistent, i can do a global search on isFinished and not forget a isNotFinished somewhere).

  • (nodebb) in reply to Olivier

    Umm, why'd you have isNotFinished? That's just making the problem worse

    Wait until you have to work with code that says

    if (!isFinished) { huge amount of code; } else { break; }

    or

    if (!isNotFinished)

    something I have seen more than enough times

  • Simon (unregistered)

    I'm surprised nobody has mentioned good old De Morgan's. It seems amongst various kinds of programmer that the idea of transforming Boolean expressions using De Morgan's is something they're never taught, and leads to convoluted negations and so on that are unnecessary. They ARE often seemingly unnecessary at the electronics level with gated logic, as typically you want to build your Boolean circuit out of only NAND or NOR gates (you don't want to use a mixture of gates), so sometimes you find developers who have come through electronics kinda doing this because their mental model automatically is used to dealing with inverted logic. (That's my theory anyway - I tend to find those with an electronics background often have a difficulty doing DRY for the same reason, if they have four seemingly-identical ports at four different addresses, they will write four otherwise-identical bits of code, one for each port...) I think it really depends on what your mental model of the system - what level of abstraction - you are used to working at. But that is just an anecdotal opinion and I've no evidence to back it up.

    For a similar reason, I WILL invert an expression in an if-else statement to make the "if-branch" shorter than the "else-branch". I'll trust the peephole optimizer to make the most efficient branching instructions anyway (and if it can't do that, there are much worse things to worry about). I just tink it makes it much easier as a reader to trace the code. I know it goes against much "good code" advice to put the normal case first: but if you think about it, mathematical algorithms usually put the special cases first and general case last. I think it just depends very much how your mental model of a processor works, what is "natural" for you.

  • Simon (unregistered) in reply to Airdrik

    i must apologise to you, you DID mention DeMorgan's. I searched for "De Morgan" with a space: I did read the comments but somehow I missed yours, so repeated the point you already eloquently made.

  • Simon (unregistered) in reply to Chris

    That's actually an implementation of a raster line drawing algorithm, when you come to thing of it.

    You shouldn't "reset the counter", though (i.e. to zero), but subtract the pre-computed (total / 100). Otherwise you'll accumulate errors....

  • Erwin (unregistered) in reply to Prime Mover

    The speed of the multi-stage Achillesd/Tortoise progress bar appears to be exponentially decreasing. But people like progress bars that appear to have an increasing speed since this strongly suggests that the task is "almost done".

    If you want to avoid increments smaller than 1%, the multi-stage Achillesd/Tortoise progress bar is now drawn at fixed percentages 0%, 50%, 75%, 87.5%, 93.8%, 96.9%, 98,4%, 100% (and go to the next stage if the task has not finished).

    You can turn this into an exponentially increasing progress bar by "mirroring" the series: draw the progress bar at 0%, 1.6%, 3.1%, 6.3%, 12.5%, 25%, 50%, 100% (and go to the next stage if the task has not finished).

  • Andropause (unregistered)

    Professor: "There are languages in which the double negative has a positive meaning. There are languages in which a double negative strengthens the negative. But there are no languages in which a double positive has a negative meaning" Student: "Yeah, right!"

  • javascript in progress (unregistered)

    Why not

    const isinprogress = theprog => (typeof(theprog) === "number" && theprog >= 0 && theprog <= 100)
    
  • markm (unregistered)

    Progress bars are reassuring because

    1. When it appears at all, it assures you that the device recognized the button click and is working on the task, and

    2. If it's moving, presumably it is still working on the task rather than froze up.

    But these good features are subverted more often than not. When it takes 10 seconds for the progress bar to appear, you've already clicked that button several more times. When the last 1% takes longer than the first 99%, you'll think it froze up. And when the progress bar is done but the task isn't done, you want to call the Mafia and put out a hit on the programmer...

  • Mike Rosoft (unregistered)

    The !!foo expression is guaranteed to convert any value to either true or false. So I'd go for: !!progress && progress <= 100 to be certain to return true or false.

  • Lewis Hopkins (google) in reply to Remy Porter

    I would even suggest

    (progress) => !!(progress && progress <= 100)

    as it handles javascript truthy/falsy(ness), fixes the issue and even pays homage to the original WTF

  • Steven Nguyen (unregistered)

    You can just do finished = progress >= 100

    If progress is null or undefined, the result is false. Also, there's the nullish coalescing operator, which isn't needed but is nice to clarify a bit; finished = (progress ?? 0) >= 100

  • 🤷 (unregistered)

    The simple feedback which promises "something is happening" alters the users' sense of time.

    Oh yes. I once added a simple progress bar to a program that would simply freeze the GUI, which was an understandable nuisance for the users, who had to constantly check the program if it was finished by trying to click the GUI. I changed NOTHING else, just added that progress bar (and added a few "Application.DoEvent()"s, even though this might be a WTF for some; I didn't know any better back then). I recieved overwhelmingly positve feedback for that change, saying how much faster the program now ran.

    Luckily this happened pretty early in my career, so I learned a valuable lesson that day: ALWAYS give feedback to the user that something is happening. Oh, and maybe add a frew "break"s here and there if a value you were looking for in a DB table with ~1,000,000 rows was already found, instead of traversing through the whole table no matter what...

  • Some Ed (unregistered) in reply to Simon

    I find a lot of programmers 9and people in general) remember the processes for these sorts of things better than the names.

    Thank you for mentioning the name in a nice big rant that was significant enough for me to actually read it. I now have a comment to attach to some code I wrote a while back...

Leave a comment on “Don't Not Be Negative”

Log In or post as a guest

Replying to comment #:

« Return to Article