259 comments

[ 4.0 ms ] story [ 83.7 ms ] thread
I don’t remember anyone resigning from Apple because of a particular shade of blue. So maybe they have that going for them idk.
[delayed]
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.

If you're suggesting that the different columns of a comptometer would relate to different rotational axes of the ball, you will likely run into gimbal lock in 3D.

You could build an interface in 4D around quaternions but that is much more complicated than my suggestion (even including the part where you learn morse code).

The quoted part of my comment is in reference to the core topic of TFA where iOS and Nothing/Android photo apps handle the "pressed again during rotation" action differently. That "rotate the typewriter ball" interface runs against the same problem, by necessity of rotating a physical ball.

Seeing this makes me think of the controls from the original arcade version of Street Fighter 1.
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
(comment deleted)
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...

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.
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
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.

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.)

---

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 guess?

(comment deleted)
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!

This is so true. Sorry you got downvoted.
Similarly, why didn'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.
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.
Then don't give UI and haltic feedback.
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?
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.
I see it as the same problem of when to accept button input. In my view having the button give "ample warning a material change is about to happen" is making the button do something more than "one job." But maybe you're right if your point is that if you're showing a button it should do the work it says it will do.
Sorry how is this relevant to the example?
They are both about when it is best to accept user input. In the specific example with rotating images nothing covers or moves the buttons so it is not relevant. My impression of the article was that the buttons one job was to accept input always, my argument is that there are times it's okay to not accept input for a short time after certain layout changes
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.

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.

But there are things like consistency which one can check for. And should.
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.
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".

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?
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.

> 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.
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.
That's a good engagement bait if I've ever seen one
I’m being serious. I find skeuomorphic UIs to be too visually overwhelming compared to flat UIs.
If you introduce flatness without also adjusting the colors (or worse, making many backgrounds translucent) you end up with really poor contrast.
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.
That fact that they are common doesn't mean 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.

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]?

> Screw the dyslexic and colourblind, I guess.

You can also use checkmark/cross icons for success/failure. And What does this have to do with dyslexia?

> What's clearer? [Call] or [(telephone receiver emoji) Call]?

We’re arguing about flat vs. skeuomorphic design, so more like:

What's clearer? [(simple phone icon) Call] or [(photorealistic drawing of a telephone receiver) Call]?

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.

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.

[1]: https://archive.org/details/msdos_win3_1

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....

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.

It doesn’t just help to “get used to” computers, it continues to help even after being used to computers for decades. The fact that it helps to better recognize and distinguish UI controls from content never stops.
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.

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.

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.

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.

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...
Truly. The number of times I’ve been surprised by something on newer macOS versions and thought: “I think this used to go against the human interface guidelines” is crazy. IMO: the first major sign of the downfall was when stealing focus on OS X became common.

Jobs had no problem calling BS on annoying behavior. Unfortunately we’ve completely lost that, and Apple is no longer the bastion of usability that it once was.

Point to another source that does it as well or better. The problems might have been solved, but it seems the majority of the industry continues to ignore them.

That said, I’ve been using Niri with Noctalia for months now, and I’m continuously delighted by the lack of astonishing behavior.

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 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.

The button to place an order should 100% be idempotent. There's one order you're constructing in your shopping cart, perhaps with an internal ID, and the irreversible “commit” button should place that order, not create two separate orders.
[delayed]
Don't worry, the vibe coding AIs of the future will get it just right /s
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.

The correct action is to disable the button while the request is in flight so it can't be clicked a second time. Otherwise you won't see "user already logged in", because the user won't be logged in until the previous request returns (a race condition).
If you have a race condition, "correct action" is to solve that, because you shouldn't be papering over server-side bugs with client-side Javascript (and yes, it's a bug, because I shouldn't see an error page if I press the back button after logging in (and trying to navigate to what I was doing before logging in) either, which I still see quite often)
How would you solve this on the server?
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.
Of course, it's never impossible for the user to click a button. They can click on anything under their cursor. The key is giving them feedback to show them what their clicks will do or just did. If you can update the visuals within a frame or two, that's already fast enough to give that feedback.
I think that if you'd need to debounce requests, it would be better to put it in a pressed and/or highlighted state until the button is ready again. Then you'd indicate to the user that the press was successfully received and that pressing it again won't do any good.

The buttons in an elevator panel typically work this way. They each light up to confirm a pending request to reach a floor. They each turn off when its floor has been reached. And while a button is lit up, pressing it does nothing.

They should be toggles! Every now and then I will press the wrong button and will have to wait for the elevator to stop, open doors, close doors at a floor no one wants off on.

I mean, I haven’t done the usability research, probably there are some good reasons for it’s not a good idea to just make them toggles, but I would find it neat.

Debouncing also has nothing to do with the animation shown on the screen so tying the debounce time to the animation is almost certainly wrong no matter what those tradeoffs are.
> 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.

Got here to comment on the same. Was really surprised how the narrative turned at this point
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.

"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.

From the article:

> The Nothing Phone button gives you a tap confirmation via both haptics and sound, and then ignores the tap if a previous rotation is still animating.

This is the issue. Number of performed actions has to be equal to number of times the app identified that button press was registered. Debouncing is a good practice, but if it is used then debounced taps must not produce feedback.

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).
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.
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.

[delayed]
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.

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.
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.

They aren’t purely for that, they also contribute to how an application feels to use in a creative manner.
> 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.

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.

I find animations to almost always be gratuitous. I disable them in all cases where the app or system gives me that ability.
Apple used to know this. They've had animations after items were dismissed, but avoided animations before showing an item.

Old Apple understood design is more than making things pretty. The glassy Apple is all about how it looks in a demo.

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?
[delayed]
> 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.

[delayed]
>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.

They didn't say how often the reads are - could be 5ms.
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:

https://www.youtube.com/watch?v=vOvQCPLkPt4

It's not an embedded programmer's job to consider how people may later run their software in an unauthorized emulator. That is a problem for the makers of the emulator. Do you really think the people who programmed your microwave should have taken that into consideration?
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.
(comment deleted)
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.
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

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.

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.

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.
> 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.

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.

This is sometimes done intentionally to hide latency and make a UI feel faster - I certainly don’t like it though.
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.
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 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' for you encountering 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".

Why can the two things even fail at all?
A programmer had a problem, so they decided to use threads.

Now they have at least two problems.

> Now they two . at least problems have

FTFY

(comment deleted)
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?

The things in question were beeping and adding 30 to a variable.

The former can fail because the speaker is broken (probably not detectable by the CPU) and the latter can fail if the counter overflows, but it obviously wasn't the case because an overflow in a microwave timer is pretty obvious to the user and the user didn't mention it.

> 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:

    try {
      doSoemthing();
    } catch (CheckedException e) {
      logger.error("Didn't work", e);
    }
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...

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

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 h...

I don't disagree with anything in particular here, but other developers might fall into a trap with:

  we are not fully enumerating and reasoning about failure cases.
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.

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.

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.

(comment deleted)
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
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.

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.
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.

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.
I appreciate this reply but even as a technical reader these concepts are somewhat tricky to follow. In my opinion, this is more of a foot-gun than a feature. A user cannot know whether the screen is closed or not while it is next to their ear—and it’s possible that related inconsistent detection isssues sometimes automatically close the screen when the phone is not against the ear.