8 ms·
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 a
by bloak 2mo ago
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?
- simonklitj 2mo agoI 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.
- ryandrake 2mo agoNot 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.”
- mrweasel 2mo agoI'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.
- csande17 2mo ago> 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.
- rowyourboat 2mo ago> 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.
- RugnirViking 2mo agoOf 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.
- crote 2mo agoSimply 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.
- atoav 2mo agoBad 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.
- mrob 2mo ago>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.
- inigyou 2mo agoThey didn't say how often the reads are - 50 reads could be only 5ms.
- mrob 2mo agoLatency 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 https://www.youtube.com/watch?v=vOvQCPLkPt4
- markatto 2mo agoThis is sometimes done intentionally to hide latency and make a UI feel faster - I certainly don’t like it though.
- tgsovlerkhgsel 2mo agoI 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.
- chrismorgan 2mo agoI have long presumed that sort of thing to be deliberate, avoiding activation on accidental bump.
- inigyou 2mo agoThen 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.
- chrismorgan 2mo agoPerhaps 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.
- lebuin 2mo agoIt 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.
- ZiiS 2mo agoThe 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.
- mrkeen 2mo agoI 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".
- inigyou 2mo agoWhy can the two things even fail at all?
- bayindirh 2mo agoA programmer had a problem, so they decided to use threads. Now they have at least two problems.
- mrkeen 2mo agoThis 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?
- calvinmorrison 2mo agoAnother 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
- ButlerianJihad 2mo agoAhh, the stochastic behavior of networked devices!