- How about when users accidentally click too much, or they believe the first click didn’t register?
I am still reminded of a keynote where Steve Jobs was demoing how much faster PDF documents would display on the newer macOS. So he had engineers put a button in for him to click that would scroll through the PDF on the screen, and he accidentally clicked it more than once. Steve wondered aloud if it would scroll all the way through twice… and sure enough, it buffered the process! He had to wait for it go all the way back up and scroll through a second time!
Steve saved grace by telling the audience that, even with moving through the document a second time, altogether it was still faster than PDFs had been in the last version of the OS.
- Debouncing exists for a reason. Sometimes when a button is clicked twice, you want it executed twice, sometimes you don't. Distinguishing which is better in which situation is not trivial.
At the very least, you should consider which is appropriate for which situation, what if, in your UI, for some buttons one is the obvious choice, for others it's the other, but for some it's not so clear, and both behaviours are defensible? Now you've got an inconsistent UI.
I have no good solution for this.
- It’s really common for people to accidentally click a button twice. Yeah that’s what denouncing is for.
My favorite example of doing it wrong is a log in form: if the login button is clicked twice, the server would reject the login because the first click has already used up the one-time token so the user gets an error page.
But I think the biggest problem is that people either apply denouncing to all buttons in a UI (like turning it on within the framework they are using) or apply denouncing to nothing. So there really isn’t a culture for carefully considering which situations warrant which.
- the correct action is not to debounce but instead of error page see user already logged in in previous request and continue
- I think the better solution for a web page login form specifically is to disable the button "onPressDown", so this error path is impossible.
For users with JS disabled, your solution seems good.
- Don't worry, the vibe coding AIs of the future will get it just right /s
- a button that debounces requests should be disabled until the action is complete instead, so you can only click it once until it is ready to be clicked again. debouncing button clicks is a design failure (it makes more sense for things like requests that happen during typing, where you don't want to stop the feedback)
- There always will be time between the first click and the time the button gets disabled and even more time before the visual representation of the button gets updated to reflect that. Keeping that time so short that it is impossible for a human to click the button again can be very hard.
It would help if GUI elements had a property “automatically disable on click”, removing the need for the “on click handler” to disable the button (in exchange for adding the need to explicitly re-enable it).
I don’t remember seeing GUI libraries that do that, though.
That probably is because it would confuse users if buttons visually get disabled when they click them.
So, the best answer is to visually keep the button enabled, but ignore rapid further clicks. That’s debouncing.
- This is a fundamental misunderstanding of how GUIs must necessarily work. There should be no possibility of race conditions if you understand the threading model.
The visual representation updating (greying out button) is a result of disabling the button, not the same thing. In virtually every GUI toolkit I've ever used there is the concept of the main UI thread, and everything that happens (input and display updates) necessarily has to go through that single thread in order to ensure correctness. (This applies to browsers, too.) That's why input goes into a queue, so you can easily do things like:
(All on the main UI thread):
- Receive click event 1: disable button, start background process. Possibly redraw button UI *but it doesn't matter because the UI display is not the state, it's just a view*. - Receive click event 2: nothing happens, button is disabled - Background process finishes, posts update to re-enable the button - Receive click event 3: disable button, start background process, etc.
- It seems somewhat clear to me. You want it executed twice if and only if the operation isn't idempotent. Can you give an example where you think both behaviors are equally defensible?
- I guess the downvotes signal disagreement, but I value the conversation in spite of disagreeing with you. I'm not sure idempotence is the only concept in play.
If the operation is idempotent, well, clicking twice doesn't do anything. I'd still want to see the button light up to signal that the UI is alive, or the button could grey out or enter a "latched" state like a radio button if there is nothing to be done. Behind the scenes suppressing command propagation is an implementation detail and the trade off is between front-end complexity and redundant command execution overhead.
If the operation is not idempotent I can give you separate examples where different behaviors are appropriate:
1. A button used to increment a counter (e.g. quantity of GPUs to buy) should increment on every click, even if the UI response is delayed. The user can count clicks, and there is going to be a decrement button to reverse any error. You do not want the user waiting around guessing whether the software is still processing the remaining clicks. As a rule, so long as the operation is non-destructive (e.g. inc and dec buttons, all operations reversible/undoable, etc.) every user interaction can and should be actioned.
2. A button used to perform an irreversible action, i.e. a "commit", such as placing the order to purchase a GPU, should only perform that operation once. I would not call this an idempotent operation, certainly not with respect to your bank balance.
- > How about when users accidentally click too much, or they believe the first click didn’t register?
I was really confused at their mention of accessibility, because my mind jumped to people with hand tremors who would double press when they intended only one press.
And then, of course, there are the people that double-click every button. To handle that, disabling a submit button in the onclick is very common.
- "How about"? These situations might exist, but this clearly isn't one. Two reasons:
1. "The Nothing Phone button gives you a tap confirmation via both haptics and sound, and then ignores the tap […]"
2. There is a really good reason to tap this button 3 times in a row.
- I'm no longer the Apple/Mac/Jobs fan-boy I once was in my earlier days, but I do miss the Apple presentations that felt like they were run by a human being wanting to show off cool stuff.
I couldn't even finish the last Apple presentations as it all feels so stiff, inhuman and run by suits, they all seem like robots scared of diverging from the holy script who will get fired if they display emotions and humanity.
Off-topic perhaps, but got reminded how delightful even the somewhat messy ad-hoc presentations from Jobs were.
- I agree 100%. I stopped watching after iPhone 15 event or maybe M2.
Absolutely everything seems scripted including hand movements, shifting of postures, smiles..the whole works.
Now I just wait for the press release and that’s that.
- The scripted talks in front of fancy backgrounds do make it unpalatable, it’s just a fancier version of corporate slideshows. I suppose trillion-dollar companies aren’t as willing to take risks.
- > I suppose trillion-dollar companies aren’t as willing to take risks.
Which to me makes no sense, surely you have some budget for risks if you are a 1T company? I suppose their risks are more moonshots to some degree like the Apple Car but nevertheless, I do miss the old presentations.
- Apple keeps solving the same old problems. Why are we still talking about how well their buttons behave?
- If anything it seems to be getting worse with each iteration for long time. I guess I'm cautiously optimistic they'll get back closer to their roots with some high-level change, but really don't care that much about it these days either...
- That was a common problem in JS-based menu opening and closing, long ago: they were treated as animations and queued. This was sometimes quite ludicrous.
Nowadays, you use transitions instead, which are not queued. But I still very occasionally see things that use queued animations.
- Button ≠ Button. People like to believe they should all be the same, but they really should not be.
On physical keyboards we already have three different kinds: normal buttons, modifier keys (shift, etc) and toggle keys (caps lock).
High stakes rare actions can require special button designs. E.g. on a black magic cinema camera the button that formats the memory card needs to be held for three second while it visually counts down. This gives a small delay during which the user can decide: "Fuck this is the wrong memory card!" and cancle.
The downside is that some imaginary power user that uses the camera only to format a stack of SSDs will get burdened. You have to decide which is more common and make a decision.
- I want to support the "what about debouncing" argument mentioned elsewhere; the author shouldn't just ignore this.
But I also hate the "you had one job" meme and want to argue against its mindless usage. Most of the time, when people do the "you had one job" thing, it's false. And that's true most of the time in the case of buttons, too. In a typical user interface, a given button has some combination of these jobs:
* Communicate what action will occur should the button be pushed.
* (Sometimes) communicate the current status of some aspect of the system (e.g., often a button is used to enable/disable a mode, and the button itself visually conveys what the current mode is).
* Execute the intended action upon clicking.
* (Sometimes) communicate that the command has been received and is being executed (e.g., in the OP, the button might disable itself while animating the rotation in order to avoid the confusion the OP complains of).
- Your points are good ones, especially since they emphasize that different people have different expectations of what a "button" is and isn't. Your points individually describe a button with a label, one with a toggle, an actual button, and a progress indicator. All of those things can be "buttons" depending on the user.
- > what about debouncing
activate button function on touch release instead of touch down?
- anecdotally that feels so much worse and sluggish
- I used to have a device with a physical button which, when you pressed it, would beep and add 30 seconds to the time. However, sometimes it would beep and not add 30 seconds, and sometimes it would add 30 seconds without beeping, so you always had to squint at the dim display to discover whether it had worked or not. I thought this must be a peculiarly bad design ... but since then I have lost count of the number of purely software buttons that somehow seem to replicate this broken behaviour: whether the button changes colour on the screen is somehow only loosely correlated with whether the action requested will take place. Why? How, even, have they implemented this?
- I call it the "doing two things" problem.
Your write imperative code, which issues two commands, both of which can fail independently.
There are plenty of ways to pretend to 'deal with it'.
Firstly it will just pass all tests, so most devs can stop thinking about it right away.
A dev might think you can just catch and log the exception. Doesn't fix it.
You could run the code in prod for a while, see if it goes wrong. It will, at which point the dev will try it again, and it will probably work the second time, so they can stop thinking about it.
There was a big outbox pattern discussion a couple of days ago (split thing 1 into two halves, and do them atomically, leave thing 2 as an exercise for the reader.)
I think the reason you encounter this problem in the real world is that devs just exist in some quantum superposition of "it won't happen" and "I fixed it" and "it can't be fixed".
- > A dev might think you can just catch and log the exception. Doesn't fix it.
You've just succinctly made the argument against checked exceptions FWIW (which I agree with you on). Anyone who has used Java in anger (is there any other way?) will be familiar with:
Fault tolerance is general is terrible in most software. One of my biggest bugbears is network latency and transient failures in network requests that would be solved with a simple retry. But no, there's an incredibly lazy "Request failed" dialog to the user. That's the equivalent of the "log and silently swallow" pattern above. It can get a lot worse than that too. I have an app on my phone that will log me out and force me into a 2FA cycle if it hits a network timeout. Like.... WHYW?!?!?! Anyway, I digress...try { doSoemthing(); } catch (CheckedException e) { logger.error("Didn't work", e); }This is largely a sotware issue. Control systems are built to handle these kinds of things. A traffic light can't accidentally show green in two directions. It's literally wired for that to be impossible because it's simply too important for it to not be possible. You constantly have to deal with faulty sensors so you have systems that will seek a consensus from 3+ sensors and, if that fails, it'll fail until you fix it.
But in software the standards just seem to be much lower even though it can be critical, even lethal eg [1]. Network interfaces should be fuzzed. Every IO operation should assume it can fail and be tested for when it does. Every IO operation should produce unexpected output. And it's simply cost-cutting and a lack of regulation that allows this sloppiness to persist. There should certainly be strict liability for any companies that allow this to happen.
[1]: https://ethicsunwrapped.utexas.edu/case-study/therac-25
- As much as I agree with the spirit of your post, standards did in fact change after the Therac-25 incident. That was nearly 50 years ago, after all! There are very high quality bars for medical equipment.
- > It can get a lot worse than that too. I have an app on my phone that will log me out and force me into a 2FA cycle if it hits a network timeout.
I use some fairly popular (in the MSP space) backup software that thinks the network is infallible. The worst case I’ve seen is when it fails on a network request, doesn’t retry adequately, and incorrectly logs the error as data corruption.
- IMO a lot of these problems come down to the same root cause: we are not fully enumerating and reasoning about failure cases.
Let's say you want to retry a network request. It's... A bit more complex than it seems, right?
Firstly, you need to know exactly what type of error you ran into. Some errors aren't really recoverable. Maybe a programming issue occurred and you are constructing an invalid URL and the HTTP client is yelling at you. No sense in retrying that 20 times. Maybe it's a network error, that seems like a good candidate to retry. Maybe, the request succeeded and we have a response, but it is a 500 error, again, seems like a good candidate.
Secondly, you need to know if it is safe to retry. If the request is essentially idempotent, like a read-only GET request, then surely it is safe, right? But, what if it isn't safe? Forget about solutions like idempotency tokens; let's assume you don't control that. Now you need to figure out how you can know if the request had side effects. If a well-known 4xx error is returned you might know, but if you get a network error or a 5xx error it's much harder. Did the request fail during a buffered response after the side effects were already applied? Maybe you can check to see if the request applied with another request. Now you have two network requests, and both need error handling.
Finally, and probably most obviously, you have to make sure you don't hammer the server when it is under load. To avoid the thundering herd problem, you'll probably want to use an exponential backoff with some jitter.
What sucks about all of this is that while there are reusable components here, the concerns effortlessly cut through different layers, making them a pain in the ass to deal with. It isn't that it is impossible for a library to handle all of these problems (I anticipate an excited evangelist may reply explaining how their favorite library does it all in one package if this post gets enough visibility) it's just that this is hard and these problems repeat in different forms, in a way that makes it difficult to fully eliminate the repetition. And this is just the most obvious basics, whereas in reality there are almost always case-specific complexities.
You can, for example, encapsulate a reasonable exponential backoff with deadline implementation and apply that as appropriate for different things, but you can't really cheat your way out of having to think about all of these things, especially if you don't control all of the network APIs you might have to interface with.
This is one part of why I don't like try/catch exceptions. They are an appropriate mechanism to use as a failure isolation boundary due to their stack unwinding capability: it would still be bad in most cases if a logic error or upstream error not being handled properly in a single network request handler were able to crash an entire network server, so being able to blanket catch everything that bubbles up an log it is good. But then using this for normal error handling, it makes doing the wrong thing perhaps just a bit too easy. I don't think you should have to self-flaggelate in order to say "just crash if this errors", but I do think that you should have to say it. Try/catch exceptions are backwards by default, just write normal looking control flow and no errors are handled and it's hard to tell if there even are any. Checked exceptions try to fix this but somehow this feels even worse; now you have a flattened list of exceptions that may occur at various different layers of depth, in some cases the same exception can occur at different layers of depth, you may literally need to read source code and map out the call stack in your head to be sure. (Hope it doesn't change later.)
The Result or Expected type concept seems like the way to go in the frame of modern programming languages. Go's error passing also works OK though it has papercuts (that a linter can help you with, at least.) To me it makes more sense to make stack unwinding error handling a more niche feature used for isolating error domains, rather than use them for all error handling.
But even that! Even that doesn't solve the problem. You still have to sit there and think about the types of errors that can occur and their consequences. At best, explicit error handling with value types just encourages you to confront it and makes it visible, even in cases where you still say "OK, pass to caller".
- I don't disagree with anything in particular here, but other developers might fall into a trap with:
This might put (or keep) a developer in the mindset that they can code a series of imperative instructions to build their minimal viable product, and then come back and tighten things up later.we are not fully enumerating and reasoning about failure cases.I expend all my effort in avoiding 'doing two things'. It's bloody difficult, but since I've come around to thinking that recovering from 1-of-2-things-failing is probably impossible in most situations, doing it the bloody difficult way is easier.
- Why can the two things even fail at all?
- This is not a bad question!
If you flip it and instead ask "how do I write something that can't fail?" you might find some interesting ground.
The best things I know about are static type-checking, pure functions and totality. Different languages provide more or less help with these things. It's perfectly fine to do 'two things which don't fail or cause other things to fail'.
Forgive the digression, but there is an 'infectious' aspect to the above 3 things (see the function-colouring problem), e.g. you can't build pure functions which call non-pure functions. The Dependency Inversion Principle (of SOLID) gives some help in how to tackle this.
Also, the above things only work within one node (of a distributed system).
For multiple nodes, I use something like Kafka, where you write down one event, and have two systems subscribe to it, each doing one thing. Yes, there's still the obvious issue of them failing independently, but when that happens, you have an authoritative source of truth (in the form of Kafka events). This beats the craps out of developer logs.
You skip the laborious questions of "what happened in the system?" and "what should the correct state be?" Because the events are already the answer - just eyeball them.
Events also machine-readable, so if you diagnose a problem and a fix it in one case, there's a good chance you can build a detector for other cases. You don't have to wait for a support ticket to get escalated to the dev team.
You also divide the debugging space dramatically. If the Kafka log says one thing {Bob bought Minecraft for $10}, then the Ownership service is just wrong if it says Bob doesn't own Minecraft, and the Finance service is just wrong if it doesn't report the $10. Fix each independently. At no point do you need to look at Ownership and Finance together to see which one failed halfway through talking to the other, because they don't talk to each other.
Lastly, events are verifiable; they are their own audit trail. If your boss asks how much money is in the system, would you feel more confident reporting whatever the current balance is set to (i.e. the outcome of whatever code executed the last "UPDATE Balance ..." statement, or would you like to be able to sum over every transaction that you ever recorded?
- A programmer had a problem, so they decided to use threads.
Now they have at least two problems.
- > Why? How, even, have they implemented this?
This is really common because of two design features that most UI frameworks share:
- The code that changes the color of the button is an internal part of the "button" component, so that people don't have to individually implement it on every button. But this means that it's kind of disconnected from the code that actually performs the action. If the "on click" handler has some last-ditch check that aborts the action, like the "don't rotate the image if it's in the middle of the rotate animation" check from the article, often there's no way for it to tell the button to cancel the color change. (And conversely sometimes the "on click" handler can fire even if the color change animation doesn't play correctly.)
- Buttons usually change color when you press down the mouse button, but only perform the action when you release the mouse button. Sometimes this is used to intentionally give you a chance to cancel the action at the very last minute by dragging your mouse off the button while it's still held down (or, on mobile, to e.g. reinterpret your interaction as scrolling instead of clicking), other times it just creates more opportunities for something to happen that prevents the action from working after the color change has already happened.
- > there's no way for it to tell the button to cancel the color change
No, but what should happen in cases like that is that the on-click handler disables the button while it is unresponsive. This will communicate the fact that the button is unresponsive visually to the user and also inhibit the button-was-pressed feedback.
- Of course, one can fix these problems. GP was merely saying why this kind of mistake is common; it is definitely a mistake, not an inevitability.
- Simply disabling the button leads to people thinking something is broken, so you need to add a visual "disabled" state - which should probably be separate from the "you are currently pressing the button" state.
In most cases that is going to lead to annoying pointless flickering as most actions & animations are basically instantaneous, and with touchscreens even in the non-pointless scenarios it won't have the desired effect as the button itself will be hidden from the user by their own finger.
In principle I think you are right, but in practice buffering presses is often probably the more user-friendly option.
- > Simply disabling the button leads to people thinking something is broken, so you need to add a visual "disabled" state - which should probably be separate from the "you are currently pressing the button" state.
Well, yes, dropping user inputs is "being broken"
- > Sometimes this is used to intentionally give you a chance to cancel the action
EDIT: sometimes UI elements with mouse-held interaction allow you to use the escape key to cancel an in-progress interaction (ESC: abort, mouse-up: commit) however the reply button on this page doesn't work that way so I have to edit this message to add this. That escape-key behavior should be universal I think.
- I notice this pretty consistently with elevators: If you press the button for a short amount of time, it visibly lights up while pressed but doesn't actually register the button-press.
- I have long presumed that sort of thing to be deliberate, avoiding activation on accidental bump.
- Then it should light up when the request is acknowledged, and stay lit up until the elevator arrives.
But wait, there's more: when the elevator arrives until it leaves, the button should flash or change to a more prominent color. Why? Because imagine someone presses up and someone else presses down, and the elevator arrives going up. If the up button switches off at this point, now only the down button is lit which clearly signals the elevator is going down, which is wrong.
- Perhaps we’re not talking about the same thing. What I refer to has the button light up while you bump it, and then go dark again, whereas if you press it more deliberately, it stays lit (and takes effect). This can apply to the buttons inside or outside the lift.
- It does sounds somewhat reasonable on paper. But some of the crosswalk buttons in Belgium have this as well, and it's really jarring. You press the button, see the light go on and look away to look at the traffic light and wait for it to turn green. Except 20 seconds later you look back and the indicator light is off again. I feel very strongly that the indicator light should only turn on when your press has been registered.
Let's say you tell someone to do something, and they say "ok". But when you ask them later whether they did, they say "oh no, I just said ok to indicate that I heard you, not that I was going to do something about it." That doesn't make any sense. The indicator light has the same function. Going on and then off again is a violation of basic communication protocol.
- At intersections, I usually find myself not looking at my red “DON'T WALK” signal, but I’m watching the other traffic signals which are green, and watching for them to turn yellow then red, which means that the next step in the pattern is a green signal for me.
The more complex the intersection, the more controls I can watch, to get a feel for the rhythm, patterns, and triggers that influence the cue to activate my “WALK” signal.
I’m also watching the cars to see when the flows slow down or stop. I should perhaps pay more attention to the signal that pertains to me as a pedestrian or motorist...
- But then you might tap the button and think it's broken, because it does nothing. The light means "this button works", not "your desired action has registered".
I guess you might want to fade it from red to green (red being "this works" and green being "it'll do what I want"), but I don't mind the holding-down behaviour. The only problem is that you can never know how long you need to hold it down for unless you stop holding it.
- The color change of the button shows you succeeded in pushing it. If you don't do this instantly most people are conditioned to try again. This is especially valuable for people with reduced motor control. It is completely independent of whether that push is a useful input given the current state of the software. Obviously when well written software knows it can't accept the input it should have disabled the button, and even moderately well written software needs to provide a near instant feedback that the action is processing or has been cancelled.
- I suppose a lack of testing and an assumption that the action will fail so rarely that it’s not worth accounting for? But yes, such patterns make it hard to trust and efficiently use an interface.
- I've only worked for one company that actually did proper QA testing. It's expensive and time consuming and often the main functionality is okay, so many just skips QA altogether.
It is probably daily that I encounter products and procedures where I can see that a given scenario is kind of a an edge case, but not an unforeseeable one. Given the scale of many things, edge cases happen pretty frequently and with ever more ridged organisations, lack of customer service, human interaction and a quest for ever more cost savings, hitting an edge case can be everything from frustrating to catastrophic for a person.
Generally I think we, as in humans, need to slow down.
- Not handling rare cases is the root of a lot of bad software. “Oh, this bug will only affect 1% of users. Don’t bother fixing it: we have features to cram.”
- This is sometimes done intentionally to hide latency and make a UI feel faster - I certainly don’t like it though.
- Bad programming. People who have experience with embedded programming knows that reading out a button usually means denouncing. At the speed a microcontroller can read out a button it will change it's state multiple times per press because of contact bounce. Meaning when a user presses a button the program sees off, on, off, off, on, on, off, on, on, on, on, on, on, etc.
Now if you just naively read out the current state of the button and do something with it elsewhere in the program looping may be off or on randomly.
It is not hard to imagine if there is some other logic (or e.g. a rate limit) on the 30 seconds and on the beep that these would see different slices in time of the button. Congrats you built a button-debounce based RNG.
Physical buttons can be surprisingly complex if you don't rely on someone else's driver. The correct solution is to debounce the button, that can be done either in hardware (too expensive, so rarely done) or in softeare, by e.g. averaging the last 50 reads and wait till the majority is either off or on.
This should be common knowledge for embedded programmers, but every noe and then you will see someone who has never heard of it.
- >averaging the last 50 reads and wait till the majority is either off or on.
This is a bad way to do it because it adds avoidable latency. A moving average is a low-pass filter. The switch bounce is better handled by hysteresis. Change state as soon as you see an edge, then ignore further edges until a timer expires, e.g. 5 ms, which should be enough for the bouncing to settle. A 5 ms timeout limits your repetition rate to 100 presses per second, which is beyond human capabilities.
You might want a tiny bit of hardware low-pass filtering too, for EMI resistance, but that's with microsecond-scale time constant, not milliseconds.
- Lots of replies with good ideas here. The biggest question is that EMI resistance; do you really need to ignore brief closures? In the vast majority of situations, the answer is no.
- Yes, you need to deal with EMI and static bursts on your microcontroller inputs.
- They didn't say how often the reads are - 50 reads could be only 5ms.
- In practice switch bounce often lasts tens or even hundreds of milliseconds, and you need to space out the read process to cover the entire bouncing process if you want to avoid registering fake presses. Using basic averaging means your minimum input latency is going to be ~half your bounce time - which is often way too high for it to feel like real-time input.
If you want to achieve low-latency input, "act on first edge, then ignore for the switch bounce period" is a far better approach. It also conveniently solves the "press, then release within bounce period" problem where an averaging algorithm would completely ignore the button press.
- the cheaper the switch, the longer the bounce.
- Regardless, if the problem is an input that normally registers the state of a button except for noise for some time as it bounces when it transitions, 48 of those reads, the averaging and the 5ms latency that incurs are unnecessary with respect to the problem.
An averaging filter makes sense if you have a noisy analog input. For a button input that registers whether it is pressed or not except for a known noise around transitions specifically, ignoring the transitions immediately after the first one registered is not only faster (both in terms of latency and CPU cost) but easier to implement. It's also equally practical for switches with long bounce, where the time it would take for an average to favor a transition might be impractically long.
- Latency is cumulative, so avoidable latency is never acceptable. Maybe the hardware will change. Maybe somebody will run your software in an emulator. That 5ms could be enough to push the total latency into the "annoying" level.
And even with no additional latency, 5ms is perceptible in some cases anyway. Microsoft Research has a video demonstration:
- Do you really think the people who programmed your microwave should have taken into consideration that someone might write a microwave emulator in the future? Dealing with that is not their job, it is the job of the emulator creators.
- Who says the emulator is "unauthorized"?
For example, smartphone app developers routinely run their apps in emulators first to make the development process more convenient, only running it on a physical device for confirmation when the work is basically done.
Many embedded developers would kill for something similar, and we're already seeing the start of it with platforms like Wokwi. Being able to do integration tests without the physical device itself is an absolute game changer.
- Their job probably isn't to invent weird, stupid ways to account for button bounce, either.
- Doesn't matter, their way is terrible one that adds latency for no reason.
There are 2 things here worth paying attention
* first "bounce" is user action * last "bounce" is stop of user action.
You can run action on first bounce then just ignore the button for whatver debounce period you deem satisfactory. But adding delay to start action is always wrong answer for debouncing.
Now the harder problem is the off of the button, especially if hold is also an action but "be off for at least few ms" usually handles it well and off time is not lag user feels
- No. Act on first transition. Cool down period following. You did not spot something everyone overlooked for 100 years.
There are other situations but not for a button. There are inputs that might be continuously noisy where a sliding window / ring buffer rolling sample is the only way to tell the difference between states. But we are talking about binary input controls actuated by a person, not a thermometer or O2 sensor.
- Checking the button state a bunch of times and computing an average wastes a ton of clock cycles that you could be doing anything else (like updating a display, polling sensors, etc).
The standard way to debounce is to attach an timer to the button. When you press the button, an ISR runs that temporarily disable the timer from triggering again and starts the timer for a specific period (say 20ms). The processor is free to do whatever it wants for the next 20ms. When that timer expires, another routine checks to see if the button is still being held, sets the button's state accordingly, then re-enables the button Timer so it can be triggered again.
Averaging loops are much better for analog inputs where you may have noise that throws off the reading. You only care about a button being on or off, it doesn't matter if it's been mostly on for that period only that it's still on.
When you get into extremely fast digital inputs that need to be reacted to sooner than the debounce wait period, that's when you need hardware debouncing.
- > People who have experience with embedded programming knows that reading out a button usually means denouncing
I know you mean "debouncing" but I love the autocorrect. Like the button is some almighty authority that Denounces noisy signals.
- Ahh, the stochastic behavior of networked devices!
- Another one I see is low end devices have a volume knob that instead of being a potentiometer are a rotary dial encoder so you end up usually only being able to adjust the volume as fast as it's sampled, which is slower than you want for example in traffic turning the radio down to hear stuff
- People often forget that animations serve purely a supportive role and do not exist for the purpose of having animations.
They are there to mask loading times and ease from one state into the other. That's why we have them.
This knowledge eventually got lost (figuratively speaking) and now we have code that needs to wait on the animation to finish.
Another amazing example of cargo culting.
- > to mask loading times and ease from one state into the other
I'd expand on this: used well, they show the user than a state change is happening directly because of a particular action of theirs, and hint at how they might reverse or modify it.
In fact I'd disagree with masking. If something appeared instantly with no hint as to why, that is a distinct anti-pattern on a touch screen.
- They aren’t purely for that, they also contribute to how an application feels to use in a creative manner.
- I don't want my image editor to feel like something in a creative manner though.
I want it to rotate an image by 90° when I tap the button that does that.
See, this is exactly my point when I say that animations are no end in themselves. They serve a supporting role to better get the actual job done.
The actual job is not "feel" it is "do". For vibes, there are movies, Art, and AI hallucinations.
Of course, "feel" can greatly enhance the "do", but only if it takes the back seat, which is exactly what I just said.
__
The age-old debate "form follows function" vs "form over function", essentially.
One of them is correct tho, because in the real non-ZIRP world, correctness is defined as "achieves a tangible goal".
Which is not to say that stuff optimizing for other goals would be "incorrect" or "worthless", but it exists in a different category from "software". More like "software-adjacent Art".
The distinction being made based on "what is the primary goal we want to achieve here"
____
Related:
Also caused by ZIRP but differently, we have that problem that software trying to invoke feelings usually does so because it wants to sell you something or has any other style of goal that might not be aligned with yours.
So that adds yet another layer.
Pure utility cannot scam people into stuff they actually didn't want to do.
- I disable all animations everywhere (Android, Windows, Gnome) because I hate that they make me feel like I'm losing time waiting for something that could be instant, and they sometimes make me dizzy. I'm particularly exasperated that iOS doesn't offer that possibility.
But rotating an image is one of the rare use cases where I do want the animation. It makes me see what action happened, with which rotation angle, without having to think twice.
- Huh, good point. True.
The motion itself indeed gets picked up intuitively by the brain.
Okay, I'm convinced that picture rotation should be animated to the exact degree that achieves this.
- > The age-old debate "form follows function" vs "form over function", essentially.
It's not a debate. If you are making app to do something, "form follows function " is always the right choice. If anyone on UI/UX team tells you different you should fire them, they are not interested in making good UIs. If it comes out ugly, well, you need to get good at making useful stuff also look nice
"form over function" only applies to stuff that is looked on more than used by overwhelming degree. Any other case is just someone using it as excuse for them being shit at producing useful stuff that also happens to be beautiful
- I'm imagining someone doing the maths on the suffering created by programs prioritising form over function. How many times have people got annoyed (or worse) at a program because they couldn't get it to work, compared to how many times people have got annoyed because a program didn't look all that great?
I doubt the pleasure of aesthetically pleasing programs can weight up for much. Then there are the ugly and bad programs too. Those have no redemption to speak of.
- I find animations to almost always be gratuitous. I disable them in all cases where the app or system gives me that ability.
- I have disabled all animations on my Android, and it feels so much nice. I particularly HATE that one animation where the whole screen stretches if you try to overscroll.
- Dude that animation sucks so much I could not believe that there was no way of disabling that without disabling _all_ animations.
The fact that it makes content move in a way that is illegal breaks my mind. You try to check "is this the end" and it starts moving. What the hell. Why.
I kinda forgot just how much I hate this animation. Thanks for the reminder. Why, google.
- The author suggests they want three clicks at any pace to always == the same functionality, so they can whiz through their photos and rotate each predictably. Fair.
> And it would be so much more predictable and pleasant if you could just tap the button three times at any pace you wanted without thinking, without paying attention, without getting your UI blocked by an animation that no longer helps you.
They cite accessibility.
The thing is, I can imagine the complete opposite side of the argument, where someone with motor impairments or parkinson's, for example, ideally liking if their over-clicks were ignored if they'd already locked-in their intention.
It's tricky to get this stuff right.
- iOS has an accessibility option called "Ignore Repeats", which seems like a better approach because it's system-wide. So people who need that kind of accommodation can have it in places like the on-screen keyboard too, without needing everyone else to slow down their typing.
- That's good. I wonder if it should be opt-in instead of opt-out. Disabled people are arguably less able to find random configuration options than non-disabled counterparts. I get a bit bothered with how undiscoverable these options are. But power-users by their nature don't mind going to the extra mile to get perf out of their experiences.
- There are many types of disabilities. If "power user" means "someone who doesn't use defaults", then people with disabilities are actually more likely to be power users.
Being fast does not make you a power user. "The button works when I push it twice" is a reasonable expectation of a device by default. If that weren't the default, then most people would have a worse experience with their phone.
- I don't think this is something every UI widget ever should have to think about.
It could probably be done as a global device setting - e.g. ignore taps within 100ms if they're within 50px of each other or whatever.
- I totally agree, even not going as far as a Parkinson case, if you already so old and not too old persons use phones and touch screens, you will see that very often it is complicated for them to click on the small button at the right place and to have the feeling that "they have clicked".
So, for me, on the argument of about accessibility, the Nothing Phone behavior will work a lot better I think. In their mind they don't count and click 6 times to put the image in a specific position. In addition with considering that it would not make much sense to click 8 times in advance to turn back in the exact position where you are.
The mindset in their case is more: click and wait, compare if it is the position you want and do it again. The other sensitive button that will bufer would probably trigger overshooting, going too far, then too back, etc... similarly to when you have issue scrolling in a list to the right spot.
The case of the iphone would be better only for someone like a younger person, tech nerd, that want things to go fast without having to wait. Same thing for computer keyboards where I could type multiple letters in advance before the first one even show up on the screen with the lag.
- Around 2011, my grandfather with Parkinson’s and deteriorating eyesight received an iPad from family. They didn’t use it for much, mostly video calls and reading the Bible, with the text steadily getting larger and larger (up to letters being more than 5cm tall towards the end). It was funny just how good it was if an app only supported iPhone and not iPad, because then the iPad would scale it up to double physical size.
- Looking at the first comparison, I will admit, I thought the issue was with the iPhones example. The button and slider below the image disappear, then fade back in after each press of the rotate button, a behaviour I have seen on iOS across many applications that irks me to no end. The Screenshot app being a particular bug bear of mine.
If you have a UX element that I will be able to interact with before and after an interaction, then keep it visible during the transformation, process, whatever. What UX gain is there in hiding these buttons during the rotation on the iPhone? It doesn't even look better, though appearance has been the altar that recent Apple software has sacrificed actual UX gains.
Will agree with the author though that these taps need to be processed independent of animation.
- I wish software apps had "tape-out rules" the way that computer chips do. Basically, when you design a computer chip, a program reviews the design and compares it against something like 300 pages of rules with stuff like "wires of X metal and Y metal can't be within Z distance of each other".
We could make something similar for UX. Just a bunch of design pattern constraints that throw flags if you try to ship something with well established UX warts.
- There’s effectively no universal list of UX warts people agree with.
The Flat UX fad was objectively terrible on just about every metric I was taught, but people were actively pushing for such designs.
- What’s wrong with flat UIs? Skeuomorphic designs have served their purpose of helping people get used to computers, but now that is no longer necessary.
- It’s not that it’s impossible to make a useable flat UI, it’s that people constantly forgot critical functionality.
You need to denote a button is different from text. You need feedback that a UI element was interacted with, and for toggles you need to clearly define on vs off.
- New people are born every day.
- The newly born people grow up in a world where computers are already commonplace, so they don’t need to get used to them.
- Wild take. They’re not born “used to them,” so at some point they quite literally need to get used to them…
- The point is that a computer will just be another thing for them to learn, not a replacement for other tools they’ve been using for tens of years. Therefore, the computer does not need to look like those other tools in order to make sense to them.
- The fact that the people learning it will be younger is not a reason to make it harder for them to learn. The computer doesn't need to look like other items out there in the world, but it sure is helpful, even if only so you have a reference to explain things from, and so that the iconography is somewhat consistent.
- Yes, but they'll be doing it between age of 2 and 7, not 20 and 90.
- Have you tried teaching kids (or just people in general) abstract concepts? Even maths is taught to kids in terms real world items and reasonable actions you can perform with them (you have 5 friends and 25 cookies, how many cookies does it friend get if you give each friend the same number cookies?).
The more you can ground what you're teaching in real world terms, the easier it is to teach. And in the moments where it does deviate from real world conditions, that's where it becomes harder to learn, since now you have to remember exceptions in behaviour compared to what you already know.
- That fact that they are common doesn't mean they don't need to get used to them.
- And? What does that have to do with the merits/downsides of flat UI?
- Having people getting used to computers is not a thing that stops happening (short of people not having computers). Literally everyone who is born will need to get used to use computers.
Having computers imitate real world items is useful, because it provides a reference to other things rather than just being its own unique thing. This is useful even if you have never actually used it outside of a computer setting. A stereotypical telephone receiver icon almost always means 'call', even if you've never used a landline phone (much less one that's shaped like that icon usually is). Nobody has ever used a real-world hamburger menu, yet it's described in skeumorphic terms, since it's easier to explain and relate to.
- You can reference other things without resorting to skeomorphism. Like using stars to represent favorites, typography to emphasisze/deemphasize things, the color red for warnings/errors, the color green for go/submit/ready, or the clearest of all: using descriptive naming in buttons and having self-documenting labels.
Skeuomorphic UIs absolutely have a place in things like games and tutorials for the youngest of children (like 5-6 yr olds, max), but past that, I honestly think labelling, a UI with feedback after significant inputs (like sounds, button states being extremely distinct, animations, etc), and not overcrowding the UI with too many controls and jargon will all go much further than skeuomorphism.
- > Like using stars to represent favorites, typography to emphasisze/deemphasize things, the color red for warnings/errors, the color green for go/submit/ready,
Screw the dyslexic and colourblind, I guess.
> using descriptive naming in buttons and having self-documenting labels.
Screw the non(-native)-English speaking in this case.
And even in the case that you're a native speaker, this is really hard to do well. You should try. Most fail.
I agree you should do these things, and many of your other suggestions (within reason) if only to give your users a better chance at understanding your software, but they cannot replace a solid grounding in the real world. We should have both.
What's clearer? [Call] or [(telephone receiver emoji) Call]?
- If you introduce flatness without also adjusting the colors (or worse, making many backgrounds translucent) you end up with really poor contrast.
- This is a somewhat unpopular opinion here, however I do think flat UI can be done right and is well fitted to digital UIs.
It's possible to have a flat style but have buttons that look clearly like buttons, and elements that have shadows and colors.
- The original GUIs were all flat because that was the default. A button was a rectangle with text in it. A checkbox was a rectangle with or without an X across it. Pure black on pure white, no colors or shades. Windows used this style until Windows 95.
Nobody seemed to have a problem with it. It was largely clear what was a button and what was a checkbox. In hindsight it was certainly uglier than the 95 style (maybe just because I grew up with that) but it wasn't unusable at all. As you say, it was clear what was a button, what was a checkbox. I think it was because GUIs were mostly made out of standardized elements whereas today we have everyone trying to put their unique spin on every element.
- I might be misunderstanding what you're saying, but: In the PC space, Windows 3.x definitely had some skeuomorphic elements. This presents most-commonly with the minimize and maximize buttons[1].
We have to go all the way back to Windows 2 in before we find flatness.
- And Windows 1 and 2 were barely even used. Windows 2 sold less than 2 million copies. Windows 3 and co sold 7-ish million. Windows 95 sold more than 40 million.[1] There's a lot less people to complain about Windows 1 and 2, and those people were probably a lot more experienced in the first place.
[1] https://web.archive.org/web/20220418124401/https://techland....
- [flagged]
- I’m being serious. I find skeuomorphic UIs to be too visually overwhelming compared to flat UIs.
- That is a valid opinion to hold, however, the question of "what is wrong with X? Y is outdated and over" is
a) a different statement from "I prefer X"
and
b) pretty low effort, trivially to Google (or ask AI) and generally a bit on the ignorant side
A better reply would not just have said what it said but contained actual wonder about the topic. Like this, it's just indistinguishable from engagement bait.
- > pretty low effort, trivially to Google (or ask AI) and generally a bit on the ignorant side
I know the most common reason why people prefer skeuomorphic design (the visual metaphor), which is why my original reply directly addressed this complaint by saying that it’s no longer relevant. Some other complaints I’ve found online are about specific bad instances of flat design rather than flat designs in general. Therefore, I am asking about reasons that don’t fall under these two categories, which I haven’t been able to find.
- I’ve never seen a single instance of flat design without any significant usability issues.
A core issue is UI is a language and by reinventing things from scratch you ended up with some designs choosing A to represent something toggled on, and some designs using that same representation to show the exact opposite. Thus a user needed to interact with that specific design to learn core functionality.
- I think you're being overly hostile.
The parents question seems reasonable to my non designy mind.
- Yes in a vacuum.
No on the Internet.
Especially not on the sea-lion infested HR-world Internet, in which trolling has evolved to exploit good faith directly.
___
In fact, "being overly hostile" is exactly how you probe to see whether your suspicions are correct.
Sea lioning exploits the gap between what would be a real human thing to do and what still passes as what a real human would do.
So to get useful data, you need to modulate parameters so that people end up outside of that gap window.
Essentially you're probing for genuine Human-ness by creating a context in which the bad faith action space is no longer overlapping with the genuine human action space.
This works, because genuine humans have this amazing ability to reconcile and actually genuinely resolve misunderstandings. Something that is fundamentally impossible for bad faith actors.
(This should not be understood as "just be overly hostile" because simply being a dick doesn't provide any data at all.)
- > (This should not be understood as "just be overly hostile" because simply being a dick doesn't provide any data at all.)
If you're a dick for a reason, you're still being a dick. (Your word not mine)
And I don't see how your approach makes discourse any better.
To me the parents question was reasonable. Skeuomorphism was designed for people that may never have seen a computer before. Do we need to still be clicking a floppy disc to save a file?
There's probably differences in how you define flat design. You could include all the issues of current implementations in that definition, or you could say that the burger menu is just bad UX and could be fixed without going back to skeuomorphism.
But you haven't really delved into that.
- > But you haven't really delved into that.
Dude, are you also playing that script or what?
Of course you do not engage on the level the possibly malicious party wants you to engage, because if you do that, you play their game by their rules.
Have you even tried engaging with what I just said? (inb4 "but you didn't do either!!111")
God, this fucking platform. Whatever man. Go have fun being dragged (or dragging others) into never-ending bad-faith arguments.
- I bet people had the same concerns with the transition from Windows 3.1's flat UI (only basic shapes were used) to the pseudo-3D effects of Windows 95.
Although in 3.1 it was easy to tell what was interactable, despite being flat. I attribute this to the use of standardized components almost everywhere.
- Why was that? What causes such fads? Why did everyone go along with it?
- Speaking entirely out of my ass here:
FOMO for sure is one of the driving factors.
"We cannot risk looking outdated". So weak management, probably.
But also talent availability I suppose. If there's a new trend, the pool of people you can hire include many that are in on that trend.
UI frameworks too, probably. The modern thing™ does the modern thing™ and you do want to be on the modern thing, because you fear that only that receives security fixes or whatever.
- If UIs today still looked exactly the same as Windows 2.0 or System 7 or CDE people will be bored to death. Aesthetics come and go and come back, it's part of how humanity worked for a few centuries already.
- For some of us, the OS isn't a fashion statement, but rather a tool which is to be used to achieve other goals. It shifting around and changing its look is in fact a downside in that context.
I don't think I know any non-tech people who like things changing about. Some tech people like that (I don't), but for the non-techy, it's just another thing they have to relearn for no good reason.
- Do I need to be entertained by my butter knife, mop or screwdriver?
I really don't think that "keeping people entertained" is a sensible goal within the context of building software as tools and not software-adjacent Art.
Which is not to say that I would not want a great and polished experience, but that is not equivalent to "being entertained".
___
It would be nice if not everything one interacts with would try to get some sort of emotion out of me. Bring back being bored.
- Why do people say that? I am not bored by my Braun alarm clock, neither by my Singer sewing machine or my De Buyer cookware. Why would I be bored by well executed digital desktop designs such as BeOS, AmigaOS or even Windows 2000?
- > people will be bored to death
As opposed to what? Be entertained by all the bells and whistles of modern operating systems that have practically unusable user interfaces?
- Make-work. Managers needing to justify their promotions with a new way of doing things. Whole teams are given a reason to stay employed. OS and device obsolescence is achieved. A win all around, save for the consumer.
- But there are things like consistency which one can check for. And should.
- Reminds me of the time I built a BabyButton, which was built in a way so that a baby could use it. Instead of the normal click behaviour, it was using the touchdown event, because that way the kid saw that something happened, and there was no problem with holding the button too long or moving the finger while still holding the button.
Whether you should build systems for that age group is an entirely different topic, but I found it a good challenge to design something that fits the user's needs.
- It's interesting that we're so used to the GUI buttons having that specific behavior of only triggering when releasing, even if you exit and enter the button area while holding the mouse button down, etc.
IRL 99%+ of buttons work by just doing the thing as soon as you press them. But a button that works like that in a GUI would feel wrong.
- > But a button that works like that in a GUI would feel wrong.
No, it doesn't. It feels way more responsive.
My pet peeve is "stopwatch apps" which trigger on release instead of on press. When timing something where fractions of a second matter, most people won't realize that it triggers on release and tap down when they want to start / stop, adding some arbitrary delay until they actually release the button.
- No, even for stopwatch, trigger on release is the correct choice, as it’s more precise.
When tapping, I have to see, or in case of watching for some event to happen to stop the time, feel/guess when exactly the distance between screen and finger approaches zero. With a stop button triggered by release however, I can just calmly rest my finger on it and raise when the event happens, without any guesswork.
- How does a real stopwatch work? Hint: it starts/stops on press, not release. So that's what the app should do, to map with prior expectations.
"Nobody uses real stopwatches anymore" might be somewhat true, but in athletics training they still do, and it just shows that it's not possible to adequately reproduce a thing on a touch screen and have it be as functional as the real item.
- If the ui calls for it I take the current position of the element and the destination then change the current to be exactly in between repeatedly on a interval. That way it moves really fast and eases into position.
One more ancient trick: back when computers were slow I would always ask myself why the data is not already in the desired format.
For example: Today you might have data in a json and turn it into a row of divs. You could store the data as a file with a row of divs which would make it a pain working with it on the backend. But on the front end you wouldn't have to parse it.
The phone doesn't modify the image but it changes the image orientation.
This is much faster but all other operations would need to work with it and when eventually served in a browser all the 100 000 viewer clients would have to rotate it themselves.
I won't argue it's wrong but it shifts complexity from image rotation to image editing and viewing.
It seems strange to add "real" rotation to the ui but the phone app is the industrial standard for image editing.
- For me Apple's "hold the button until something happens" to turn on my iPhone is and always has been and always will be a FAIL.
- Are there times when, during a call, pressing an iPhone’s screen-on/off button will end the call, but other times when it will just turn the screen off?
I still do not know the pattern, but I have on occasion inadvertently ended a call by using that button prior to placing my iPhone in my pocket.
- When on Speaker/hands-free mode, it just closes screen. They assume you wouldn't press lock button while against your ear, because it closes the screen automatically. The problem is that there's some bugs that keep the screen open sometimes, or you may use it in a quiet room as if it were on hands-free.
- It's interesting that old Windows apps would accidentally do this by blocking the main thread.
They'd even give visual feedback - the button remains looking pressed until the click handler returns when the operation is complete!
Maybe blocking the main thread isn't so bad after all?
- As a user, I much prefer a blocking UI thread to one that lets me spam clicks on the "rotate left" and "flip along vertical axis" buttons and then makes me wonder why the resulting image is not the flipped verstion of what I saw the moment when I clicked "flip". However, I do like being able to abort my operations, and a blocking thread does not let me do that.
It might be quite a hard problem to determine which buttons should be disabled during which operations. One tricky candidate is the "safe" button. Should I be able to click it when the visual feedback I'm getting does not yet match the internal state of the application (which is what will be saved)? Should I be able to start further tasks when the save is still in progress? (If so, what if the save fails? Will I be able to roll back to the state before the attempted save and try again?)
- Its a perfect illustration of the tradeoffs between synchronous and asynchronous logic. Synchronous logic allows for maximal consistency at the cost of wasting time. Asynchronous logic allows you to use time efficiently, but requires you to track all the different states you can be in simultaneously.
- [dead]
- The real article getting to the point the author is trying to make is this one https://aresluna.org/show-your-hands-honor/
- Ok, we'll put that link in the toptext as well. Thanks!
- My wife is a behavior analyst and I’m a game developer. We both watch people and try to figure out how why they are doing stuff and how to get them to do what we want.
One thing I learned from her is that if you want someone to stop doing something you don’t punish them, you ignore them. No response.
- That’s good life advice.
- iPhones had their share of animations interfering with functionality, one instance being calculator app showing false results when tapped quickly: https://robservatory.com/the-calculator-bug-persists-in-ios-...
- There's a problem with buffering tho. If the device's slow and unresponsive, and the user tapped the rotation button several times, it would be confusing if the rotation action happens 10 seconds after the user tapping the button. The user'd be left confused like "alright. So, has my input been taken?"
Now that I'm wondering. How does iphone mitigate this problem?
- It shouldn't buffer them like the author describes. It should execute the button’s function immediately when pressed. This might mean to cancel the current animation and jump ahead, or it might mean to speed it up by the appropriate factor so it takes the same amount of time as it does for one button press. Either way is massively preferable to a button that swallows my input.
- One way to deal with it could be “guaranteed interrupt” action (something like sigkill, just for UI action queue).
Other way could be to actually visually indicate action queue depth.
- It's not so simple. There are times where you intend to tap one thing and something else appears underneath your finger instantaneously. So sometimes while rendering a layout you want to stop accepting input.
- That's a different bad UX pattern. If a button has already rendered in a certain location, a new button shouldn't replace it without first giving the user ample warning that a material change is about to happen.
- Isn't that a different issue from what the blog post described and easily solved by holding everyone who allows their UX elements to get pushed around, for whatever reason, to the fire?
- Yeah, that is an issue in Apple Maps.
If you tap for directions and then tap to change the mode of transportation as it's loading the routes then it thinks you've picked the first route because it bumps the transport mode panel up in order to show the first route in the list.
Very annoying as they could just account for the height of the first route from the start.
- Then don't give UI and haltic feedback.
- Sorry how is this relevant to the example?
- When I had my last Android phone (KitKat 4.4), best tip for increasing UI snappiness was reducing (or disabling) system animations. I still miss this option on most modern OSes, shells, apps, and websites.
It's very rare that animation is not blocking further user actions. No surprise animations are tricky to program - they're very async in nature. Designing animation system that doesn't leak into the rest of application logic code is a no simple feat.
- This still exists on modern Androids (thanks God!)
Even better: they moved it from developer options to accessibility options, which means that they treat it as a normal use case now
What is bad is that it still disables the animations for progress bars (the only place where the animation makes sense)
- Tangentially related, games added various menu transition animations on purpose, to disable user input while loading resources (from hdd or network).
Idea being that for user it is less frustrating to wait for animation to end, than to see some hourglass/waiting indication.
- We ( including myself ) like to shit on Apple's regression of UX and software. Which is true, on all of their OS. But every time we look into alternatives, the others are so far off that even Apple has regressed 10 - 20% they will still be so far ahead of others.
Google, Microsoft, Amazon, Netflix, Meta. Is there even one software company that does software UX well but not on Apple's platform?
- I have only iphone, but from my experience, apple ui quality is just a huge myth nothing to do with reality.
On average it is has same amount of crappy UI experience, just in different places.
- I think iOS has lots of refinement and polish, but still lots of ugly bugs and crappy UI. The others have the same crappy UI, but with no refinement and polish at all anywhere.
- What does the author think about the concept of debouncing (common in real world hardware, because electronically signals are not binary).
- That's a great example. But, it's not always so clear cut.
Following the exact "best practice" in the article, the iPhone lock screen has this issue. Say your password is 1234 but you accidentally type 11234. What the iPhone will do is see 1123, the pause to tell you you failed, then enter 4. Now you, having muscle memory, will type 1234 (your password). But iPhone kept that 4 so it sees 4123 then pauses to tell you entered the wrong password, then adds the 4, and you type 1234 again, which again it sees 4123.
Finally, frustrated, you pause and press delete or take some other action to reset the lock screen and this time it works.
This has happened to me countless times since iPhone had a lock screen.
The better UX would be to clear the that after the error which is effectively what the Nothing Phone is doing with the photo rotation
I agree 100% with the article that for photo rotation it should do what the iPhone is doing. Conversely, it's wrong thing to do on the lock screen.
- It's not that iphone keeps that 4; it's that iphone pretty quickly starts accepting the next round of input after 1123 and then you type 4.
Perhaps a longer pause will prevent you from typing that 4 but that also means other people who mistype their passcode have to wait longer to retry. It's a tradeoff. I suspect there are more people who type the wrong passcode of the correct length than the incorrect length.
- In summary:
Record actions until interrupt.
Animation should not be considered interrupt.
An Error message should be treated as interrupt.
- I’m thinking a lot about how older applications are often better than new for reasons like this.
Sometimes I log into my big Windows machine at home with RDP from out of the house to post photos to my socials, like
and with a folder with a few hundred images in it is is awkward to use the official file chooser dialog because it is based on modern UI toolkits and practices which are wasteful and slow over the net. It is much easier to use XnView MP because it is based on an old widget set which isn’t flashy.
Similarly I find myself impressed with the old Adobe apps like Photoshop and Illustrator because, sprawling as they are, they come out of an old time when they were expected to work on machines with a fraction (1/2000 of the RAM!) of the capacity of modern machines and there is just less junk. Adobe recently took the “(legacy)” label off “Save to Web” because that ancient feature alone goes a long way to justifying the creative cloud subscription.
- One similarly egregious UX issue on the latest Android is that pressing buttons in the dropdown tray doesn't give any feedback until the action is complete. I can press the "turn on WiFi" button and receive zero haptics or visual indication that the phone registered my tap, for over a second, and THEN it will decide "okay! let's shake the phone and change button color now".
And if you have a tray button that needs to e.g reach over the network to a HomeAssistant instance that needs to itself reach out to some fuckass IoT vendor server, you may as well not expect any sort of feedback before you close the tray.
- That's a good example of bad UX, and, in a way, counter to the article.
It sounds like Android needs a middle state indicator. When your action is in a pending state, the state indicator should not be the same as the previous state. A common pattern is to show a pending animation.
While this animation is running, what should happen if the user presses the button?
- I've yet to update to Android 17, but I ended up disabling haptics on 16 because the annoying pop sound feels like a gimmick compared to what haptic feedback used to be.
- Busted my Corne-ish Zen yesterday, going back to an Ergodox EZ (until I received 2 new Corne, including one as backup) I can tell that leaving a comfortable and efficient hand based setup is literal pain, both physiological and cognitive. I write and code using Vim (so navigation with keys) and browse with Tridactyl (same principle). It's very rough going back.
Also I work in XR and rely heavily on hand tracking and I'm precisely trying to use that accident so re-consider what does typing mean without a keyboard. How can one use hand tracking in XR as input without relying a virtual keyboard, which is so slow and lacks tactile feedback.
Anyway, all this to say yes, ours hands are impressively precise, fast, flexible. We take them for granted but it's definitely worth spending a bit of time training them, considering the interfaces at different level, ergonomic, physical interface, firmware, then the software with its UI.
- In the Google photos app (Pixel 10) there is no animation, the rotation just happens immediately and there's no button press to buffer.
- My rule of thumb is that animations need a purpose, otherwise you are just showing off and it gets tedious. This animation carries more purpose than most, conceptually you might understand which orientation will be next but it takes your brain a second to validate, and it is much simpler if you can see the path that it took.
- Eliminating these animations is indeed a massive win.
Overuse of animations is a terrible thing that has made iOS far worse over the years. I long for the days of yore, when the loading screenshot had a chance of being accurate.
These days, when loading something like the health app I get a series of three different screens, rather than just landing at the destination it knew o wanted to start at. It is idiocy of the highest order. Why show some series of random screen transitions while starting the app? Somebody who has no clue about UX programmed that piece of crap, and then an entire team put up with this behavior. I dearsay that if this shipped under jobs there would be a director level firing to stop it.
Same BS happens with Apple Maps. If you launch the app and it remembers that an hour, day, or two weeks ago you had your phone in a particular orientation forever ago, it slowly rotates the view pane over 1000-2000ms from you ancient view pane as if you've been waiting patiently over two weeks so that Maps doesn't suddenly disrupt your view...
Animation can be helpful but at some point a half-wit VP shoved it into everything Ruth disastrous results and Apple is still recovering. Liquid Glass is a similar disaster of incompetence being promoted far beyond capability.
- Hair dryers normally have 2 controls, one to adjust how much air it blows, and another one to adjust how hot the jet is.
When they're off, they don't blow any air so it would make sense to me to decide that the button to turn them on is the one that controls how much air it blows. It goes from 0 to 1 to turn on, so you just learned that that button changes how much air comes out of it.
But no, most of them do the opposite. So, you turn them on with the temperature control. The action is: no air, yes air, air gets super-hot if you keep pushing the button.
I can't find any modern air dryers where they get this right.
- Possibly a consumer air dryer problem, something-something safety. Check professional ones like Parlux, the one I checked has 2 dials: airflow and temperature. Turns on by air dial. They are also conveniently under the thumb so you can adjust without looking.
- Yes it's safety related. Turning the heater on while the airflow if off is a sure way to start a fire.
It could be fixed with a relay or a solid state switch on the heater, or with a multipolar toggle on the airspeed. But that's several cents more expensive than making it turn on at the heater switch.
- I imagine it’s similar to why a fan starts at max. Eg: 0->3->2->1
Something technical made it easier to implement.
- The Dyson Supersonic?
- There is a more general Android problem where it registers a single tap sufficiently to show a button press animation and vibrate and then ignores it because the tap wasn't held long enough.
- A different UX issue I have with these buttons is that the designers seen to have chosen the wrong rotation direction.
I almost always need to rotate photos 90⁰ to the right, so I have to tap that button three times. Apart from that, if I have only one way to rotate my photo, clockwise seems more intuitive to me anyway.
- Or another bug seen in the wild: the image rotates opposite to the button’s icon label.
- We like buffering of keystrokes or gestures when the system is completely reliable, exhibits reasonable latency and low jitter in its latency.
- Even in unstable or high latency I like the buffering. I’m thinking of a remote shell, where you want to type a command blindly, and see it appear seconds later, because keys got buffered in the Internet pipes. Without buffering it would feel awful, having to wait a full roundtrip per keystroke
- please, use mosh, if this is available for you
- If you're a button, you have one job: to transmit Morse code from the finger to the machine, Morse code representing a complicated POSIX shell command. And also to power down this entire one-button terminal with a 3 second press, power it up on any button press, with a firmware reset if powered up by a 30 second press.
- Now I am imagining a typewriter with just two huge round buttons, next to each other horizontally, and a spacebar bellow them:
A press of each round button rotates the typing ball accordingly, pressing the space prints the chosen letter and resets the ball to the neutral state. This whole thing should probably be electric lest you'd have to press the space bar by smashing it with both fists.*-----* *-----* | | | | | ● | | Ω | | | | | *-----* *-----* [================]- Now remove the spacebar, combine the two buttons into a single one for "tone" and adapt it to morse code. All the buttons still do only one thing and now there's only one button!
And, you don't have to worry about what to do in the case that someone hits the "rotate ball" button while it's still rotating.
- > And, you don't have to worry about what to do in the case that someone hits the "rotate ball" button while it's still rotating.
Eh, it's a pretty trivial problem, comptometers have it figured out more than a hundred years ago.
- Apple still did it best: https://www.youtube.com/watch?v=9BnLbv6QYcA
- The power button of my pc also has the job to tell wether the PC is turned on. So do bulb switch buttons that have a pilot light, and so on
- Yeah, sometimes, when I am sitting before my computer and typing comments on the Internet, I have a thought: "Is my computer turned on?" With a quick glance under my table I can reassure myself that it is indeed on and continue using it. No idea what I'd do without that small blue LED.
The pilot lights are slightly more useful in those stupid cross-wired double switches that for some weird reason implement a sort of XOR (or sometimes XNOR because why not) gate for controlling a single light: if it's on, then the bulb is depowered and you can safely change it without turning off the entire power rail. But then one day the pilot light itself burns out...
- You can safely change a bulb in a socket that is powered on. Just don't stick anything else in it but the bulb.
- This is literally the type of thing that caused the THERAC-25 disaster (https://en.wikipedia.org/wiki/Therac-25). Experienced users hitting keys faster than the app could process them, resulting in safety features being inadvertantly bypassed.
- That's a great example of bugs in overcomplexity. The requirements were relatively simple, but they went for a full-on multitasking OS with all the complexity that entails.
- Even calling it a button is going too far. Buttons are for elevators, doorbells, and payphones. What we have on iPhone and Android is a tactic response imitation system. If there is no physical depression, there is no button.
- This isn't unique to touchscreen interfaces. I have the same frustration when performing a sequence of keyboard commands and the OS can't keep up (or some other application or unwanted notification pop-up steals the focus).
- It's Android stop expecting it to make sense. You have to learn some intricacy of some tool so you can forget it and have to learn it again three months later.
iOS is no better. Sure everything is intuitive but it's going to get a redesign so next year you are going to have to learn everything from scratch or a feature you use often will just break.
- Using AOSP-based Android roms, I haven't noticed any big changes in years. In current "android 16" and my old "android 10" device one couldn't really tell a difference. Very simple UX, no bloatware apps, no hidden drawers coming out from sides.
I've tried the vendor ones by Samsung, OnePlus etc with fresh devices and this Android experience really is awful.
- I wish there was more love for more vanilla forms of Android. I would trade more simplicity out of the box and regular software updates over the current situation.
Personally I'm blown away by Motorola options in the budget range. For raw value alone there offerings are hard to beat.
- I couldn't disagree more.
Every button has two jobs. One is to accurately convey what it will do. Two is to then do it.
Several of us can neither remember what your dynamic, curvy, arrowed, action lines do, nor can we extrapolate from them. They are an exercise in frustration. The nod to situational disability is appreciated, but most would have been useless without text descriptions.
- You are talking about the label on the button. The button does one thing. The label does one thing. You put the two together and you have UX.
- I think this is a distinction without a difference. Imagine an array of buttons. What do they do? The label is intrinsic to the button. I understand this is a perspective. But, taking this to another level, perhaps an absurd one,the button only sends messages and ideally reacts to show it's been activated.
- I assumed that issues like "tap eight times for a no-op" not working was because of software patents not allowing the developer to do the obvious thing. Is that not the case?
- Software patents? Care to elaborate?
- I don't have any specifics, but based on experience, it feels like software giants like to patent what a lot of people would consider obvious wins (such as interruptible animations) if no other company happens to be doing it, and it felt like this would be something where that could be the case.
That said, I can't seem to find any evidence of this particular thing being patented to support my case, so it's probable that I'm wrong.
- I have a related cybersecurity point.
No interface should, on a regular basis, contain buttons that, if pressed -- harm the computer and other computers near it.
And of course, this is links in modern email.
- The author says: “Now, I’m going to exaggerate the problem a bit and tap 90-degree rotation quickly eight times.” I was wondering why the Nothing one stuck upside down after that, and expected a rant about Android not registering all taps or something. But the article got ahead with explaining how the Nothing’s solution was better. Huh?
The iPhone was eight taps. The Nothing was six. (Yeah, I could have noticed it while watching, but I was situationally incapacitated; namely, I’ve just waken up.)
---
Edit: I’ve rewatched it at 0.5× and the Nothing was eight taps after all, too. Author’s point was, indeed, that all taps should register regardless of what animation state is, and Nothing doesn’t do that. Sorry for the confusion!
---
Regardless! I still find the iPhone one more pleasant to look at, because the animation doesn’t stop. But if you press quickly enough, I guess what they could do is animate until the taps stop, then:
• if the image will arrive to the desired state: finish up the current 90°;
• if it’ll still be 90° away: finish up then show one more 90°;
• if it’ll be 180° away: flip it upside down, then finish up the current 90°;
• if it’ll be 270° away: flip it upside down, finish up, and show one more 90°.
But that’s not a very practical thing to implement I suppose.
- > But the article got ahead with explaining how the Nothing’s solution was better.
No? It makes the opposite argument.
- Then I definitely need to get some caffeine I guess *yawns*
> And it would be so much more predictable and pleasant if you could just tap the button three times at any pace you wanted without thinking, without paying attention, without getting your UI blocked by an animation that no longer helps you.
Am I misreading this?
- I'm not sure exactly how you're misreading it, but you are.
The Nothing isn't executing all the taps, some are blocked by the animation. It is responding visually and haptically to all of the taps, but some are blocked from doing any work by the animation.
You also said the Nothing was 6 taps but I'm not seeing anywhere the article says that. I believe it was 8 taps on both.
- Both animate, but Nothing blocks further inputs while it's animating (even though the haptics still fire).
- Okay, that one is on me indeed. I’ve re-watched it at 0.5× and he does make 8 taps indeed. Apparently, only the first and the last are registered then. Sorry for the confusion!
- Lie you have 4
- Click me?
- [dead]
- I'm sure it just my personal preference but I hate animations. Most often they do little other than slow an application down i.e. the code of the application could finish the task almost instantaneously but for the sake of appearance, they make it take longer to finish. I would much prefer no animations in applications. If the animation is there to disguise some actual slow response, just let me wait, give me jarring screen changes. please. Maybe app designers could still include all the animations for "smoothness", "premium look" or "sizzle" but please include an "expert" mode that just turns everything off.
- Some years ago, I attended an informal demo of some application we built. The engineer who had worked on the UI was showing an animation of the initial splash screen. It was only 5 seconds or so but I asked him whether there was an option to disable it. He said there wasn't. I then asked if he didn't think that a user, running this many times, was going to get very tired of seeing it run every time and want to just show the home window immediately on start. I said I knew I would. I told him that regardless of how "cool" it looked, when you see the same thing a few times, it can become annoying leaving the user pissed off because its out of their control. I don't know what happened after that. Since I didn't have any authority to request changes, I was probably ignored.
- [dead]
- [flagged]
- [dead]
- [flagged]
- [flagged]
- [flagged]
- Do you remember? Maybe just recall, don't tell me I'm absolutely right https://news.ycombinator.com/item?id=48787409
- Almost had it. Aw shit I lost it Lou.
- Camera app should negate the need. most pictures are of people and scenary, and 99.99% of the time the intent is to take the photo in the right order.
Simple totally offline ONNX models exist, whcih should make it trivial to categorize the right orientation. Acceleometer/magnetometer can feed this, but should not be the default.
Just do this and avoid the hassle of rotating at all!
- Similarly, why don't photos get auto-straightened, maybe with an option to revert to original? I spend too much time aligning the horizon properly on snapshots that I took while cycling. The phone even has the data from the rotation sensor, so this should be fairly easy to implement.
- This is so true. Sorry you got downvoted.
- I understand the design principle but I would argue it's a bad implementation principle.
Engineering attention is finite. Why would you spend time thinking about 8 clicks when most people will only need ~3?
Not all user-action possibilities are equally important, and if they are, then you better have infinite resources to spend on engineering.
- It's not really a question of how many taps they support, but how fast.
This same issue also seems like it would prevent you from quickly double-tapping the button to turn an image upside-down, a much more common use case.
- Not prevent, just not provide very responsive feedback, right?
I don't know, I understand the principle, but I don't see how you can determine the value of a principle outside of a specific context.
Even for accessibility, we can't target every context in the name of being accessible. We still have to pick which contexts of inaccessibility we'll need to support with more attention.
- Maybe I misread the article, but I think the Nothing photos app is literally ignoring the second tap, not just failing to provide feedback
- This may be true, but it is too random and too insignificant, to my taste.
Better post an overview of everything a good button should do (no it is not just one job).
Even better, post an overview of good GUI design in general.