The server hosting this website doesn't support TLS 1.3 - if it did then you'd have 0 round trip time (0-RTT) session resumption and it would be nearly identical to the http latency.
Do servers automatically support 0-RTT? I thought generally you have to explicitly enable 0-RTT because it's vulnerable to replay attacks. Generally you would only enable it for idempotent requests, and feedback is not idempotent (unless the database explicitly rejects duplicate feedback).
I've run into this before too. Sometimes I've actually added a delay timer to buttons that show loading spinners so that the spinner appears long enough for the user to see more than a flash. Is there a better option?
Dont use a spinner if it loads fast. One thing I have done is adding a little white box with the word "loading..." In it. Users don't have to wait for any animation to see what it means and it still looks fine for longer loading times.
Spinners are no better than static messages. They're animated GIFs completely detached from the state of the underlying application, so they'll happily keep spinning forever, even though the application itself has locked up or crashed. It's particularly painful on websites, since unlike desktop apps, a bug or failure in one AJAX handler tends to not break everything else - so the site may sort of work, except some actions never finish.
Maybe but it's the common implementation of a spinner.
I can't remember the last time I saw a spinner that actually showed some kind of variable behavior. If you have that, it's more likely you are being shown a progress bar.
Basically all spinners on the web work by sending a request which causes the spinner to show up, waiting for a response which causes the spinner to be removed. Many of them don't handle errors which causes them to keep spinning.
A static loading message is exactly the same, while the message is on the screen the request is still pending and while it is gone it is not. The only case you are not catching is where the browser locks up and becomes unable to render the spinning which is not that common or useful.
Make them solve a reCAPTCHA when clicking on the button. Make sure that the captcha takes at least one second to appear. This will make them feel that something is sent and validated.
You don't need a spinner if feedback from clicking the button is sufficiently quick.
According to Google that would be around 100ms.
> Guidelines:
> Process user input events within 50ms to ensure a visible response within 100ms, otherwise the connection between action and reaction is broken. This applies to most inputs, such as clicking buttons, toggling form controls, or starting animations. This does not apply to touch drags or scrolls.
That only applies to actions which have an immediate, perceivable effect, which might not be the case for submitting a form, as described in the OP. For example, opening a dropdown, selecting a checkbox or radio button, etc.
'hayksaakian mentioned toasts, which are global, but I think another option would be "toasts" local to the button. E.g. flash a checkmark next to the button user clicked for a second, indicating the action was registered and completed. Key here is: next to, and asynchronous. The checkmark can stay alive for a second, but the button shouldn't be blocked for that time. If the user clicks it again immediately, it should "refresh" the success indicator, or add another one.
UIs in games have this solved in countless of ways.
I use jquery ui "highlight" effect as visual confirmation for action completion. It's a background easing animation, basically it "flashes" before fading out.
It’s not that people are used to slow stuff, even if they are. It’s that there is a psychological “magic number” whereby something is short enough to seem instant.
There’s different values and tons of articles about this so I’ll just link a random one. I don’t know if there are formal studies on it but I fully believe in the idea that there is a magic “instantaneous” feeling threshold, just from personal experience, especially with tweaking animation delays.
There is such a thing as too fast. Flight ticket comparison websites like skyscanner.com insert fake progress delays ("scanning airline website") to make it seem like they're spending a lot of effort to do important work for you. Research has shown that, without that delay, users trust such websites less, or value them less, because the instantaneous response time is equated to less valuable work.
Wow, I am very different than those users. I just think "how fucking hard can it be to show me the same flight prices you showed me 30 seconds ago," and then switch to Google Flights
Which will most likely show non-bookable outdated prices more often... there's always a trade-off. There might also be some browser/geo profiling going on.
However, I'm not sure they really changed the engine underneath, and it was always designed as something that then was input to booking sites, often with filters on fares, because QPX (the engine) would show you fares that an agent with full view of GDSes would see - and sometimes the airlines don't want to sell certain fares (it already filtered the special unsellable ones of course, but it couldn't apply arbitrary policy decisions from airlines).
As I recall there are (or at least used to be) lots of computationally hard problems in searching for flights. I think it is already somewhat tricky to enumerate all the reasonable routes between two destinations (and back) (and sometimes there are C shaped plans of A->B, then days later B-> C), and then airlines have complex fee structures combining date, time, class (ie fare), loyalty programme memberships, legs, whole route, current demand, etc such that determining the price for a single route is somewhat tricky and searching for the fastest /cheapest route is also not easy (and crucially not reducible: if you have the cheapest flight from A to B, the cheapest return from A to B may not include it)
But maybe the landscape of airline booking/pricing has changed since I got this impression.
I imagine a big part is just having to talk to the airlines legacy systems. If Skyscanner (et al) had access to all the data, I expect they could compute prices quicker and give better options. I assume this is why Google bought ITA Software.
I've got first hand experience in this as we are working on it right now.
This problem is largely due to the closed and archaic nature of the GDS systems that are the source of truth. These systems have been running for 40+ years and no one wants to touch them to make substantive changes. As a result, modernisation is attempted via layers on top of layers that just add complexity confusion.
There is a difficult routing and fare calculation problem here, coupled with a distributed consensus problem. While better solutions to this exist or may exist, the biggest hurdles are the organisational ones.
Why is the routing and fare calculation a big problem? I can see writing to a legacy system being slow, but I would think there could be constant caching somewhere of the data as it is read by anyone, and thus reads could be mostly fast, making routing calculation fast. Then it would be a matter of checking for validity of chosen routes.
I worked at a GDS and you're pretty close. There's a component of not wanting to change, but when they do they are burdened by their fragile infrastructure and thousands of competing projects. Very small changes would cause defects in one project that one customer uses. While massive bugs are ignored.
> Research has shown that, without that delay, users trust such websites less, or value them less, because the instantaneous response time is equated to less valuable work.
I'm pretty sure jdc was talking about this research, not the specific implementation.
I hear this every time TurboTax gets brought up. I think it's a lot healthier to foster good relationships between users and tech so that they don't have to distrust instantaneous actions.
As an aside, I'm also suspicious of research that shows ~100ms as the threshold for "instantaneous" action, because in video games like FPS shooters most players seem to dislike playing on ping that high.
I have the same view. 100ms is fine for actions that require round trip to the server, in particular when you hide the latency the way multiplayer games do. But for things that are just local UI operations, if you're taking longer than 16.7 ms, you're doing something wrong. A typical videogame can update the whole screen and all game logic in less than that.
Please pass this memo on to people who feel the need to animate UI elements to hide laggyness, and then animate into and out of a loading screen (eg. Loading an app on Android).
Additionally, we're extra sensitive to things like latency between a tablet pen drawing and it's stroke appearing, or rendering lagging behind VR HMD rotation, or audio latency if we're trying to jam. Even if we register ~100ms as "instantaneous" in a lot of scenarios, it can still cause troubling disconnects between action and result.
The difference is the sense of touch vs vision. Touch is the most sensitive sense and the mismatch between it and vision is more noticeable in a video game than clicking buttons on a website. 300ms is actually the instantaneous threshold for non-dynamic interaction (typical website), but it is 1-10 ms for haptic devices.
While that's true of many products, I don't think it applies to SkyScanner - searching for air fares, especially aggregating multiple sources is actually really slow. They might be setting a minimum loading time so the search doesn't jump around so much, but it would never be even close to the timescales involved in the post. AFAIK Google is the only one that can do it faster due to having their own 'index'.
That does say a lot about the mindset of such sites. Instead of showing off their superior quality and reassuring the users that they are indeed that better than the competition, they would instead lie to the user and offer worse experience.
I remember back in university in the 1990s, someone in sysadmin added some sleep() to the startup script for Netscape with a comment like "pretend we're doing something".
I prefer things to be instantaneous. Slowness suggests it's been cobbled together by incompetents.
Like those cookie banners where you CAN opt out, but you get a spinner for about 30 seconds while the website pretends it’s soooooo difficult to save your preferences...
Ha. When building a high ticket price “AI” product recently, it definitely occurred to me that some level of slowness in compute time could definitely be a “feature not bug” from the user’s perspective. (eg. AI thinking really hard!) We didn’t have to implement that option in the end (normal solution was sufficiently slow) but there’s definitely merit in not making your product appear trivial.
I just took a quick look at Skyscanner and couldn't initially see this happening - do you have a link or example?
It's been a long time since I worked there but there was generally strong opposition to masking any delays.
That said it's frequently necessary to retrieve the latest fare quotes from the airlines (which involves network calls naturally), so that the user doesn't end up clicking through to wildly different pricing/availability -- but departure/arrival/carrier information about flights should generally be displayed without delay (unless things have changed - glad to see an example if so!).
We could get a Sub 300ms Response and Rendered, but if those results were not good, it would be seen as fast but inaccurate. No one complain about Google Results in its early days, it was fast, and comparatively accurate.
There is also a problem of varying response time, in ideal condition, all query and searches should be returned in roughly the same amount of time, that is because user do not understand there is a different in query complexity, to them all query are the same.
Without some sort of animation, user will be surprised to see their work being served and done without them really knowing and noticing, that could be both good and bad in different situations. ( Read Safari Rendering Progress Bar )
You need to tell the user that the message has been sent. If nothing happens when you press the button (just an ajax call, no refresh) the user will think there is something wrong.
The reverse can be used in an UI to tell the user that something went wrong, for example in a window pull-down menu, don't hide the menu right away, do what the user request, then hide the menu, so if it the request didn't complete, the menu will still be visible.
Hi, the web page in question has always had something to say what's going on. It's not beautiful but it does tell you that things are happening.
Right before it kicks off the call to the server, it lights up something to say "Submitting feedback", and as soon as it finishes, it flips that to "Feedback saved" (which now has a time attached).
Odds are, most people have never actually noticed the first message, since it is quickly replaced with the second.
The messages appear just to the left of the button which was just clicked (and right under the text field). So, in theory, it's right by where your eyes are looking anyway.
This is how I felt about Algolia's search when I first enabled it for our Vuepress site at https://developers.kloudless.com/guides/enterprise/ (the search bar at the very top). I assumed it had loaded some kind of index in memory via JavaScript since the XHR requests take < 30 ms (!) from my location in San Francisco, which is pretty much instant. That's faster than the delay between my keystrokes.
While it's a good idea to use performance.now() for it's better precision* and monotonic guarantee, it's not really a huge concern for this kind of application (measuring time between A and B on the client). You're extremely unlikely to experience clock skew during those brief windows, and the entire web relied on Date.now for performance monitoring for decades.
For dealing with timestamps reliably on the client, we'll just instantiate all dates based on server time instead.
* at least in FF it has been rolled back to 1ms resolution due to privacy/fingerprinting concerns
You can infer from there that anything around/under 100ms will feel like direct manipulatio, interpreted by the person in the post as 'no request was sent to the server'. The same interpretation might not result from a non-technical person, it will just feel 'different' or they won't notice what happened and submit it multiple times, if there is no success message.
You can also trace it back to one of their 10 heuristics: visibility of system status. If users cannot perceive a change because it happened too fast, the UI has failed and users don't know what happened. One of the reasons some websites add artificial delays, as mentioned in other comments, is not only to signify 'work' being done, but that flashing a spinner for a split second is also a bad experience. You're better off normalizing every action to take at-least-one-second, and ensuring the state of the system is always clear.
I remember attending a talk about speeding up web UIs once and it got to Q&A time.
I’d read some article about how if you respond too quickly, users can begin to doubt that any work is really being performed, and I’ve experienced that feeling a handful of times over the years myself.
Anyway, I asked the speaker that and everyone just kind of laughed, which it does seem a little absurd on the face of it.
I guess it’s also pretty far from most peoples minds given the web is caked in unnecessary bloat a lot of the time :)
> It's a link in the SF Bay Area, and the server is in Texas, so it has to get out there and back. That's at least 50 milliseconds right there when measured by a boring old ping.
Am I the only one surprised by this 50ms ping? I can reach cloud servers in the SF Bay Area from Paris in 50ms - and I'm on wifi. Surely SFO-TX should take much less time..?
According to this it takes 42ms to get from Paris to SF at the speed of light in a fiber in the great circle path across Earth's surface. Ping is rtt, so that would be 84ms.
On the topic of websites taking a long time to compute something, Wolfram Alpha is slow. I wonder if any of that slowness is artificial like flight price websites.
Hacker News itself is a good example of a related topic: voting here feels fast because the vote button disappears as soon as you click it, but it's actually very slow.
If you open your browser's Network panel in dev tools and vote on something, you'll see that it sends a request, gets back a 302 redirect, and then does another request to load a whole new copy of the page you were voting from in the background (and then just discards it). At least from my location, it consistently takes about 1.2 seconds for each vote to finish, even though it feels instant while using the site.
One consequence of this is that if you vote on multiple comments quickly, some of your votes are probably being lost with no indication. If you try to vote on something else before the first vote has fully finished, the second one gets a 503 error, but there's no indication of this at all.
It happens to me often - I read a good reply comment, vote it up, and then immediately vote up its parent (which I've already read) as well, since it resulted in that good comment. If I come back to the page later I'll notice that my vote on the parent didn't go through, and if you open the Network panel and try this, you'll see it - the second vote 503s if your second click was before the first one finished, but the site acts the same whether it failed or not.
That's a good observation. I've noticed it happening too, since I have a similar upvoting pattern: I tend to read a whole subtree, and then go back up, rapidly upvoting comments in it I considered insightful. I've noticed that the votes sometimes don't register, which is why I periodically reload the comment thread and reupvote comments.
I tried emailing him about it a couple months ago, after I made this comment about a different downside of it (bandwidth usage / response size): https://news.ycombinator.com/item?id=20854662
He didn't consider it an issue worth fixing, and didn't reply to my long follow-up email trying to explain how wasteful and inefficient the current voting process is and how simple it would be to improve. It seems unlikely to change.
I've been on the implementation side of this kind of thing more times than I'm proud of.
Hardcoded delays are especially prevalent in systems which attempt to emulate a human operator, such as virtual assistants which are starting to replace human live chat agents. The excuse is always UX related. Progressive disclosure is cited a /lot/. Apparently users get a better experience when systems pretend to be human and respond slowly, so we would hardcode delays which were a function of the length of the response message.
> If a user is confused about the interaction because of how fast it is, then that's a UX problem to fix
In some cases the confusion comes from a "did this do any work at all" question. like git branching compared to svn for big projects. As other have brought up, instantaneous reply in airline comparison sites can cause concern of how deep the search was.
A similar paradox is with psychiatrist hourly rates or the placebo effect. The high price (delay) is part of the therapy (interface).
Having your program sit in the chair and twiddle its thumbs to make it seem like it's working is just one possible solution. It's tragedy-of-the-commons-esque, because it perpetuates the myth that a given category of work has to be slow.
Alternatives would include: results speaking for themselves, or saying something like "Searched all 124,568,902 connections", or otherwise reaffirming users the work has been done without making them pay for it with time.
I feel like it's an issue we will never have on the project I'm currently working on, all requests have a noticeable delay. I guess there's too many layers on the back-end. And maybe some requests are totally not optimised (like doing 20 select 1 elt instead of select 20 elts). And maybe there's no enough caching. Or maybe the thing we're caching are not those that matter… But first we still have to migrate off Internet Explorer (or at least support another browser).
In a hobby desktop app, I show a splash screen before the UI is fully loaded. After optimizing startup time, it's now at a point where a hot start is very fast, less than 300 ms, to the point that you can't really read anything on the splash screen. Cold start still takes a second or so.
Is there a best practice here? At which point do you stop showing a splash screen? I've seen applications where the splash screen lingers even after the UI is loaded, which seems weird to me and gets in the way of getting things done.
Thank you very much for introducing me to this concept! This gives me some ideas on how to organize the loading. There is definitely stuff I do in the background of the splash screen that could be done later, after a simplified version of the main window is loaded.
To the last comment within the article: yes, we’re accustomed to laggy websites. Most sites have tons of chatter/bloat/trackers. Refreshing to encounter those that don’t. Thankfully HN is fairly low-bloat itself.
85 comments
[ 3.8 ms ] story [ 167 ms ] threadI can't remember the last time I saw a spinner that actually showed some kind of variable behavior. If you have that, it's more likely you are being shown a progress bar.
A static loading message is exactly the same, while the message is on the screen the request is still pending and while it is gone it is not. The only case you are not catching is where the browser locks up and becomes unable to render the spinning which is not that common or useful.
According to Google that would be around 100ms.
> Guidelines:
> Process user input events within 50ms to ensure a visible response within 100ms, otherwise the connection between action and reaction is broken. This applies to most inputs, such as clicking buttons, toggling form controls, or starting animations. This does not apply to touch drags or scrolls.
https://developers.google.com/web/fundamentals/performance/r...
"Sent X" or "Finished Y!" is sufficient to distinguish a failed ajax call from a successful button press
I remember some years ago when Ubuntu file sync would pop a notification every time a file was synced. That's a good example of what not to do.
UIs in games have this solved in countless of ways.
It might not be fancy but it's simple and helps.
There’s different values and tons of articles about this so I’ll just link a random one. I don’t know if there are formal studies on it but I fully believe in the idea that there is a magic “instantaneous” feeling threshold, just from personal experience, especially with tweaking animation delays.
https://www.nngroup.com/articles/response-times-3-important-...
Which will most likely show non-bookable outdated prices more often... there's always a trade-off. There might also be some browser/geo profiling going on.
Why do you assert that?
However, I'm not sure they really changed the engine underneath, and it was always designed as something that then was input to booking sites, often with filters on fares, because QPX (the engine) would show you fares that an agent with full view of GDSes would see - and sometimes the airlines don't want to sell certain fares (it already filtered the special unsellable ones of course, but it couldn't apply arbitrary policy decisions from airlines).
But maybe the landscape of airline booking/pricing has changed since I got this impression.
This problem is largely due to the closed and archaic nature of the GDS systems that are the source of truth. These systems have been running for 40+ years and no one wants to touch them to make substantive changes. As a result, modernisation is attempted via layers on top of layers that just add complexity confusion.
There is a difficult routing and fare calculation problem here, coupled with a distributed consensus problem. While better solutions to this exist or may exist, the biggest hurdles are the organisational ones.
I'm pretty sure jdc was talking about this research, not the specific implementation.
https://www.semanticscholar.org/paper/The-Labor-Illusion%3A-...
As an aside, I'm also suspicious of research that shows ~100ms as the threshold for "instantaneous" action, because in video games like FPS shooters most players seem to dislike playing on ping that high.
Even locally, FPS games can reach upwards of 100ms latency locally even before hitting the network, so 100ms ping is more like 100+100=200ms of latency. http://renderingpipeline.com/2013/09/measuring-input-latency...
Additionally, we're extra sensitive to things like latency between a tablet pen drawing and it's stroke appearing, or rendering lagging behind VR HMD rotation, or audio latency if we're trying to jam. Even if we register ~100ms as "instantaneous" in a lot of scenarios, it can still cause troubling disconnects between action and result.
John Carmack on VR HMD latency: https://danluu.com/latency-mitigation/
John Carmack noting that depressing a 360 gamepad trigger can take 20ms: https://twitter.com/id_aa_carmack/status/233240260568551425
A Microsoft Research video on tablet input latency, where the effects of 100ms vs 1ms latency are clearly visible: https://www.youtube.com/watch?v=vOvQCPLkPt4
Which makes ethics even more difficult.
I prefer things to be instantaneous. Slowness suggests it's been cobbled together by incompetents.
It's been a long time since I worked there but there was generally strong opposition to masking any delays.
That said it's frequently necessary to retrieve the latest fare quotes from the airlines (which involves network calls naturally), so that the user doesn't end up clicking through to wildly different pricing/availability -- but departure/arrival/carrier information about flights should generally be displayed without delay (unless things have changed - glad to see an example if so!).
We could get a Sub 300ms Response and Rendered, but if those results were not good, it would be seen as fast but inaccurate. No one complain about Google Results in its early days, it was fast, and comparatively accurate.
There is also a problem of varying response time, in ideal condition, all query and searches should be returned in roughly the same amount of time, that is because user do not understand there is a different in query complexity, to them all query are the same.
Without some sort of animation, user will be surprised to see their work being served and done without them really knowing and noticing, that could be both good and bad in different situations. ( Read Safari Rendering Progress Bar )
The reverse can be used in an UI to tell the user that something went wrong, for example in a window pull-down menu, don't hide the menu right away, do what the user request, then hide the menu, so if it the request didn't complete, the menu will still be visible.
Right before it kicks off the call to the server, it lights up something to say "Submitting feedback", and as soon as it finishes, it flips that to "Feedback saved" (which now has a time attached).
Odds are, most people have never actually noticed the first message, since it is quickly replaced with the second.
The messages appear just to the left of the button which was just clicked (and right under the text field). So, in theory, it's right by where your eyes are looking anyway.
But, here we are.
I may not be working on real-time systems at the moment, but I’ve had enough exposure to them in the past that I’d like to scratch that itch.
For dealing with timestamps reliably on the client, we'll just instantiate all dates based on server time instead.
* at least in FF it has been rolled back to 1ms resolution due to privacy/fingerprinting concerns
You can infer from there that anything around/under 100ms will feel like direct manipulatio, interpreted by the person in the post as 'no request was sent to the server'. The same interpretation might not result from a non-technical person, it will just feel 'different' or they won't notice what happened and submit it multiple times, if there is no success message.
You can also trace it back to one of their 10 heuristics: visibility of system status. If users cannot perceive a change because it happened too fast, the UI has failed and users don't know what happened. One of the reasons some websites add artificial delays, as mentioned in other comments, is not only to signify 'work' being done, but that flashing a spinner for a split second is also a bad experience. You're better off normalizing every action to take at-least-one-second, and ensuring the state of the system is always clear.
I’d read some article about how if you respond too quickly, users can begin to doubt that any work is really being performed, and I’ve experienced that feeling a handful of times over the years myself.
Anyway, I asked the speaker that and everyone just kind of laughed, which it does seem a little absurd on the face of it.
I guess it’s also pretty far from most peoples minds given the web is caked in unnecessary bloat a lot of the time :)
Am I the only one surprised by this 50ms ping? I can reach cloud servers in the SF Bay Area from Paris in 50ms - and I'm on wifi. Surely SFO-TX should take much less time..?
https://www.wolframalpha.com/input/?i=paris+to+san+francisco...
On the topic of websites taking a long time to compute something, Wolfram Alpha is slow. I wonder if any of that slowness is artificial like flight price websites.
The result was that it turned into a chat, so we had to add a "fake delay" for people to treat is as a serious comment system.
If you open your browser's Network panel in dev tools and vote on something, you'll see that it sends a request, gets back a 302 redirect, and then does another request to load a whole new copy of the page you were voting from in the background (and then just discards it). At least from my location, it consistently takes about 1.2 seconds for each vote to finish, even though it feels instant while using the site.
One consequence of this is that if you vote on multiple comments quickly, some of your votes are probably being lost with no indication. If you try to vote on something else before the first vote has fully finished, the second one gets a 503 error, but there's no indication of this at all.
It happens to me often - I read a good reply comment, vote it up, and then immediately vote up its parent (which I've already read) as well, since it resulted in that good comment. If I come back to the page later I'll notice that my vote on the parent didn't go through, and if you open the Network panel and try this, you'll see it - the second vote 503s if your second click was before the first one finished, but the site acts the same whether it failed or not.
'dang, is there any chance this gets improved?
He didn't consider it an issue worth fixing, and didn't reply to my long follow-up email trying to explain how wasteful and inefficient the current voting process is and how simple it would be to improve. It seems unlikely to change.
"I didn't get any 503 codes forcing me to click send a few times, this comment obviously didn't get through"
Hardcoded delays are especially prevalent in systems which attempt to emulate a human operator, such as virtual assistants which are starting to replace human live chat agents. The excuse is always UX related. Progressive disclosure is cited a /lot/. Apparently users get a better experience when systems pretend to be human and respond slowly, so we would hardcode delays which were a function of the length of the response message.
Speed is one of the most important properties of exceptional user experiences.
I'm building a developer tool and I'm ruthlessly optimizing for speed. Waiting 20ms for a CLI command versus 100-300 is a huge difference.
In some cases the confusion comes from a "did this do any work at all" question. like git branching compared to svn for big projects. As other have brought up, instantaneous reply in airline comparison sites can cause concern of how deep the search was.
A similar paradox is with psychiatrist hourly rates or the placebo effect. The high price (delay) is part of the therapy (interface).
Alternatives would include: results speaking for themselves, or saying something like "Searched all 124,568,902 connections", or otherwise reaffirming users the work has been done without making them pay for it with time.
“Are we to believe that boiling water soaks into a grit faster in your kitchen than on any place on the face of the earth?”
It’s simply Occam’s Razor. Which is more likely in 2019: a webpage is fast, or a webpage has a JavaScript bug?
Is there a best practice here? At which point do you stop showing a splash screen? I've seen applications where the splash screen lingers even after the UI is loaded, which seems weird to me and gets in the way of getting things done.
https://uxdesign.cc/what-you-should-know-about-skeleton-scre...