<?xml version="1.0" encoding="UTF-8"?><rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>A List Apart</title><link>https://alistapart.com/blog/topic/application-development</link><atom:link href="http://rss.144-124-237-35.sslip.io/alistapart/application-development" rel="self" type="application/rss+xml"></atom:link><description>Application-development Articles on aListApart.com - Powered by AtomRSS</description><generator>AtomRSS</generator><webMaster>contact@atomgroup.dev (AtomRSS)</webMaster><language>en-us</language><lastBuildDate>Mon, 19 Oct 2026 20:56:36 GMT</lastBuildDate><ttl>5</ttl><item><title>The Future of Web Software Is HTML-over-WebSockets</title><description>&lt;p class=&quot;wp-block-paragraph&quot;&gt;The future of web-based software architectures is already taking form, and this time it’s server-rendered (again). Papa’s got a brand new bag: HTML-over-WebSockets and broadcast everything all the time.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;The dual approach of marrying a Single Page App with an API service has left many dev teams mired in endless JSON wrangling and state discrepancy bugs across two layers. This costs dev time, slows release cycles, and saps the bandwidth for innovation.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;But a new WebSockets-driven approach is catching web developers’ attention. One that reaffirms the promises of classic server-rendered frameworks: fast prototyping, server-side state management, solid rendering performance, rapid feature development, and straightforward SEO. One that enables multi-user collaboration and reactive, responsive designs &lt;em&gt;without building two separate apps&lt;/em&gt;. The end result is a single-repo application that feels to users just as responsive as a client-side all-JavaScript affair, but with straightforward templating and far fewer loading spinners, and no state misalignments, since state only lives in one place. All of this sets us up for a considerably easier (and faster!) development path.&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Reclaiming all of that time spent addressing architecture difficulties grants you a pool of surplus hours that you can use to do awesome. Spend your dev budget, and your company’s salary budget, happily building full-stack features yourself, and innovating on things that benefit your company and customers.&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;And in my opinion, there’s no better app framework for reclaiming tedious development time than Ruby on Rails. Take another look at the underappreciated Stimulus. Beef up the View in your MVC with ViewComponents. Add in the &lt;a href=&quot;https://cableready.stimulusreflex.com/&quot;&gt;CableReady&lt;/a&gt; and &lt;a href=&quot;https://docs.stimulusreflex.com/&quot;&gt;StimulusReflex&lt;/a&gt; libraries for that Reactive Rails (as it has been dubbed) new car smell, and you’re off to the races. But we’ll get back to Rails in a bit…&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;This all started with web frameworks…&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Web frameworks burst onto the scene around 2005 amidst a sea of mostly figure-it-out-for-yourself scripting language libraries glued together and thrown onto hand-maintained Apache servers. This new architecture promised developers a more holistic approach that wrapped up all the fiddly stuff in no-touch conventions, freeing developers to focus on programming ergonomics, code readability, and fast-to-market features. All a developer had to do was learn the framework’s core language, get up to speed on the framework itself and its conventions, and then start churning out sophisticated web apps while their friends were still writing XML configuration files for all those &lt;em&gt;other&lt;/em&gt; approaches.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Despite the early criticisms that always plague new approaches, these server-rendered frameworks became tools of choice, especially for fast-moving startups—strapped for resources—that needed an attractive, feature-rich app up &lt;em&gt;yesterday&lt;/em&gt;.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;But then the &lt;em&gt;JavaScript everything&lt;/em&gt; notion took hold…&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;As the web development world pushed deeper into the 2010s, the tides began to turn, and server-rendered frameworks took something of a backseat to the Single Page Application, wholly built in JavaScript and run entirely on the client’s computer. At many companies, the “server” became relegated to hosting an API data service only, with most of the business logic and all of the HTML rendering happening on the client, courtesy of the big ’ol package of JavaScript that visitors were forced to download when they first hit the site.&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;This is where things started to get ugly.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Fast-forward to 2020 and the &lt;a href=&quot;https://www.nngroup.com/articles/the-need-for-speed/&quot;&gt;web isn’t getting any faster&lt;/a&gt;, as we were promised it would with SPAs. Shoving megabytes of JavaScript down an iPhone 4’s throat doesn’t make for a great user experience. And if you thought building a professional web app took serious resources, what about building a web app &lt;em&gt;and&lt;/em&gt; an API service &lt;em&gt;and&lt;/em&gt; a communication layer between them? Do we really believe that every one of our users is going to have a device capable of digesting 100 kB of JSON and rendering a complicated HTML table &lt;em&gt;faster&lt;/em&gt; than a server-side app could on even a mid-grade server?&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Developing and hosting these JavaScript-forward apps didn’t get any cheaper either. In many cases we’re now doing twice the work, and maybe even paying twice the developers, to achieve the same results we had before with server-side app development.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;In 2005, app frameworks blew everyone’s minds with “build a blog app in 15 minutes” videos. Fifteen years &lt;em&gt;later&lt;/em&gt;, doing the same thing with an SPA approach can require two codebases, a JSON serialization layer, and dozens of spinners all over the place so we can still claim a 50ms First Contentful Paint. Meanwhile, the user watches some blank gray boxes, hoping for HTML to finally render from all the JSON their browser is requesting and digesting.&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;How did we get here? This is not my beautiful house! Were we smart in giving up all of that server-rendered &lt;em&gt;developer happiness&lt;/em&gt; and doubling down on staff and the time to implement in order to chase the promise of providing our users some fancier user interfaces?&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Well. Yes. Sort of.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;We’re not building web software for &lt;em&gt;us&lt;/em&gt;. We’re building it for &lt;em&gt;them&lt;/em&gt;. The users of our software have expectations of how it’s going to work for &lt;em&gt;them&lt;/em&gt;. We have to meet them where they are. Our users are no longer excited about full-page refreshes and ugly Rube Goldberg-ian multi-form workflows. The SPA approach was the next logical leap from piles of unorganized spaghetti JavaScript living on the server. The problem, though: it was a 5% improvement, not a 500% improvement.&amp;nbsp;&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Is 5% better worth twice the work? What about the developer cost?&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Bedazzling the web app certainly makes things &lt;em&gt;fancier&lt;/em&gt; from the user’s perspective. Done well, it can make the app feel slicker and more interactive, and it opens up a wealth of new non-native interaction elements. Canonizing those elements as &lt;em&gt;components&lt;/em&gt; was the next natural evolution. Gone are the days of thinking through how an entire HTML document could be mutated to give the &lt;em&gt;illusion&lt;/em&gt; of the user interacting with an atomic widget on the page—now, that can be implemented directly, and we can think about our UX in terms of component breakdowns. But, alas, the costs begin to bite us almost immediately.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Go ahead, write that slick little rating stars component. Add some cool animations, make the mouseover and click area feel good, give some endorphin-generating feedback when a selection is made. But now what? In a real app, we need to &lt;em&gt;persist&lt;/em&gt; that change, right? The database has to be changed to reflect this new state, and the app in front of the user’s eyes needs to reflect that new reality too.&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;In the old days, we’d give the user a couple star GIFs, each a link that hit the same server endpoint with a different param value. Server-side, we’d save that change to the database, then send back a whole new HTML page for their browser to re-render; maybe we’d even get fancy and use AJAX to do it &lt;em&gt;behind the scenes&lt;/em&gt;, obviating the need for the full HTML and render. Let’s say the former costs &lt;em&gt;x&lt;/em&gt; in developer time and salary (and we won’t even talk about lost opportunity cost for features rolled out too late for the market). In that case, the fancy AJAX-based approach costs &lt;em&gt;x&lt;/em&gt; + &lt;em&gt;n (you know, some “extra JavaScript sprinkles”)&lt;/em&gt;, but the cost of lots and lots of &lt;em&gt;n&lt;/em&gt; grows as our app becomes more and more of a JavaScript spaghetti sprinkles mess.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Over in the SPA world, we’re now writing JavaScript in the client-side app and using JSX or Handlebars templates to render the component, then code to persist that change to the front-end data store, then a PUT request to the API, where we’re also writing an API endpoint to handle the request, a JSON serializer (probably with its own pseudo-template) to package up our successful response, and then front-end code to ensure we re-render the component (and some branching logic to maybe rollback and re-render the client-side state change if the backend failed on us). This costs a lot more than even &lt;em&gt;x + n &lt;/em&gt;in developer time and salary. And if you’ve split your team into “front-end” and “back-end” people, you might as well go ahead and double &lt;em&gt;that&lt;/em&gt; cost (both time and money) for many non-trivial components where you need two different people to finish the implementation. Sure, the SPA mitigates some of the ever-growing spaghetti problem, but at what cost for a business racing to be relevant in the market or get something important out to the people who need it?&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;One of the other arguments we hear in support of the SPA is the reduction in cost of cyber infrastructure. As if pushing that hosting burden onto the client (without their consent, for the most part, but that’s another topic) is somehow saving us on our cloud bills. But that’s ridiculous. For any non-trivial application, you’re still paying for a server to host the API and maybe another for the database, not to mention load balancers, DNS, etc. And here’s the thing: &lt;em&gt;none of that cost even comes close to what a software company pays its developers!&lt;/em&gt; Seriously, think about it. I’ve yet to work at any business where our technical infrastructure was anything more than a fraction of our salary overhead. And good developers expect raises. Cloud servers generally just get &lt;em&gt;cheaper&lt;/em&gt; over time.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;If you want to be efficient with your money—especially as a cash-strapped startup—you don’t need to cheap out on cloud servers; you need to get &lt;em&gt;more features faster out of your existing high-performance team&lt;/em&gt;.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;In the old, old days, before the web frameworks, you’d pay a developer for six weeks to finally unveil…the log-in page. Cue the sad trombone. Then frameworks made that log-in page an hour of work, total, and people were launching web startups overnight. The trumpets sound! Now, with our SPA approach, we’re back to a bunch of extra work. &lt;em&gt;It’s costing us more money because we’re writing two apps at once&lt;/em&gt;. There’s that trombone again…&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;We’re paying a lot of money for that 5% user experience improvement.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;But what if we could take the best client-side JavaScript ideas and libraries from that 5% improvement and reconnect them with the developer ergonomics and salary savings of a single codebase? What if components and organized JavaScript could all live in one rock-solid app framework optimized for server-side rendering? What if there &lt;em&gt;is&lt;/em&gt; a path to a 500% jump?&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Sound impossible? It’s not. I’ve seen it, like C-beams glittering in the dark near the Tannhäuser Gate. I’ve built that 500% app, in my free time, with my kids running around behind me barking like dogs. Push broadcasts to logged-in users. Instant updates to the client-side DOM in milliseconds. JavaScript-driven 3D animations that interact with real-time chat windows. All in a single codebase, running on the same server hardware I’d use for a “classic” server-rendered app (and maybe I can even scale that hardware down since I’m rendering HTML fragments more often than full-page documents). No separate front-end app. Clean, componentized JavaScript and server-side code, married like peanut butter and jelly. It’s real, I tell you!&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Socket to me! (Get it? Get it? Ah, nevermind…)&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Finalized in 2011, support for WebSockets in modern browsers ramped up throughout the 2010s and is now fully supported in all modern browsers. With the help of a small bit of client-side JavaScript, you get a &lt;a href=&quot;https://en.wikipedia.org/wiki/Duplex_(telecommunications)#FULL-DUPLEX&quot;&gt;full-duplex&lt;/a&gt; socket connection between browser and server. Data can pass both ways, and can be pushed from either side at any time, no user-initiated request needed.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Like the game industry’s ever-expanding moves into cloud-based gaming, the future of web apps is not going to be about pushing even heavier obligations onto the user/client, but rather the opposite: let the client act as a thin terminal that renders the state of things for the human. WebSockets provide the communication layer, seamless and fast; a direct shot from the server to the human.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;But this wasn’t terribly easy for many developers to grok at first. I sure didn’t. And the benefits weren’t exactly clear either. After years (decades, even) of wrapping our heads around the HTTP request cycle, to which all server-handled features must conform, adopting this WebSocket tech layer required a lot of head scratching. As with many clever new technologies or protocols, we needed a higher-level abstraction that provided something really effective for getting a new feature in front of a user, fast.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Enter HTML-over-WebSockets…&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Want a hyper-responsive datalist typeahead that is perfectly synced with the database? On every keystroke, send a query down the WebSocket and get back &lt;em&gt;precisely&lt;/em&gt; the changed set of &lt;strong&gt;option&lt;/strong&gt; tags, nothing more, nothing less.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;How about client-side validations? Easy. On every input change, round up the form values and send ’em down the WebSocket. Let your server framework validate and send back changes to the HTML of the form, including any errors that need to be rendered. No need for JSON or complicated error objects.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;User presence indicators? Dead simple. Just check who has an active socket connection.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;What about multi-user chat? Or document collaboration? In classic frameworks and SPAs, these are the features we put off because of their difficulty and the code acrobatics needed to keep everyone’s states aligned. With HTML-over-the-wire, we’re just pushing tiny bits of HTML based on one user’s changes to &lt;em&gt;every other&lt;/em&gt; &lt;em&gt;user&lt;/em&gt; currently subscribed to the channel. They’ll see &lt;em&gt;exactly&lt;/em&gt; the same thing as if they hit refresh and asked the server for the entire HTML page anew. And you can get those bits to every user in under 30ms.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;We’re not throwing away the promise of components either. Where this WebSockets-based approach can be seen as a thick server/thin client, so too can our components. It’s fractal, baby! Make that component &lt;em&gt;do&lt;/em&gt; delightful things for the user with smart JavaScript, and then just ask the server for updated HTML, and mutate the DOM. No need for a client-side data store to manage the component’s state since it’ll render itself to look &lt;em&gt;exactly like what the server knows it should look like now&lt;/em&gt;. The HTML comes from the server, so no need for JSX or Handlebars or &amp;lt;insert other JavaScript templating library here&amp;gt;. The server is always in control: rendering the initial component’s appearance &lt;em&gt;and&lt;/em&gt; updating it in response to any state change, all through the socket.&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;And there’s nothing saying you have to use those socket channels to send &lt;em&gt;only&lt;/em&gt; HTML. Send a tiny bit of text, and have the client do something smart. Send a chat message from one user to every other user, and have their individual clients render that message in whatever app theme they’re currently using. Imagine the possibilities!&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;But it’s complex/expensive/requires a bunch of new infrastructure, right?&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Nope. Prominent open-source web servers support it natively, generally without needing any kind of extra configuration or setup. Many server-side frameworks will automatically ship the JS code to the client for native support in communicating over the socket. In Rails, for example, setting up your app to use WebSockets is as easy as configuring the built-in ActionCable and then deploying as usual on the same hardware you would have used otherwise. Anecdotally, the typical single Rails server process seems to be perfectly happy supporting nearly 4,000 active connections. And you can easily swap in the excellent &lt;a href=&quot;https://docs.anycable.io/&quot;&gt;AnyCable&lt;/a&gt; to bump that up to around 10,000+ connections per node by not relying on the built-in Ruby WebSocket server. Again, this is on the usual hardware you’d be running your web server on in the first place. You don’t need to set up any extra hardware or increase your cloud infrastructure.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;This new approach is quickly appearing as extensions, libraries, or alternative configurations in a variety of languages and web frameworks, from Django’s &lt;a href=&quot;https://sockpuppet.argpar.se/&quot;&gt;Sockpuppet&lt;/a&gt; to Phoenix’s &lt;a href=&quot;https://dockyard.com/blog/2018/12/12/phoenix-liveview-interactive-real-time-apps-no-need-to-write-javascript&quot;&gt;LiveView&lt;/a&gt; and beyond. Seriously, go dig around for WebSockets-based libraries for your favorite app framework and then step into a new way of thinking about your app architectures. Build something amazing and marvel at the glorious HTML bits zipping along on the socket, like jet fighters passing in the night. It’s more than a new technical approach; it’s a new mindset, and maybe even a new wellspring of key app features that will drive your startup success.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;But I’d be remiss if I didn’t highlight for the reader &lt;em&gt;my &lt;/em&gt;contender for Best Framework in a Leading Role. Sure, any app framework can adopt this approach, but for my money, there’s a strong case to be made that the vanguard could be Ruby on Rails.&amp;nbsp;&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;So we come back around to Rails, 15 years on from its launch…&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Set up a Rails 6 app with the latest versions of &lt;a href=&quot;https://github.com/turbolinks/turbolinks&quot;&gt;Turbolinks&lt;/a&gt;, &lt;a href=&quot;https://stimulus.hotwire.dev/&quot;&gt;Stimulus&lt;/a&gt;, &lt;a href=&quot;https://docs.stimulusreflex.com/&quot;&gt;StimulusReflex&lt;/a&gt;, &lt;a href=&quot;https://cableready.stimulusreflex.com/&quot;&gt;CableReady&lt;/a&gt;, and GitHub’s &lt;a href=&quot;https://github.com/github/view_component&quot;&gt;ViewComponent&lt;/a&gt; gem, and you can be working with Reactive Rails in a way that simultaneously feels like building a classic Rails app &lt;em&gt;and &lt;/em&gt;like building a modern, componentized SPA, in a single codebase, with all the benefits of server-side rendering, HTML fragment caching, easy SEO, rock-solid security, and the like. You’ll suddenly find your toolbelt bursting with straightforward tools to solve previously daunting challenges.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Oh, and with Turbolinks, you also get wrappers allowing for hybrid native/HTML UIs in the same codebase. Use a quick deploy solution like Heroku or Hatchbox, and one developer can build a responsive, reactive, multi-platform app in their spare time. Just see &lt;a href=&quot;https://dev.to/julianrubisch/twitter-clone-with-stimulusreflex-gone-hybrid-native-app-17fm&quot;&gt;this Twitter clone&lt;/a&gt; if you don’t believe me.&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;OK, that all sounds exciting, but why Rails specifically? Isn’t it old and boring? You already said any framework can benefit from this new WebSocket, DOM-morphing approach, right?&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Sure. But where Rails has always shined is in its ability to make rapid prototyping, well…&lt;em&gt;rapid&lt;/em&gt;, and in its deep ecosystem of well-polished gems. Rails also hasn’t stopped pushing the envelope forward, with the latest version 6.1.3 of the framework boasting a ton of cool features.&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;If you’ve got a small, resource-strapped team, Rails (and Ruby outside of the framework) still serves as a potent force multiplier that lets you punch way above your weight, which probably explains the &lt;a href=&quot;https://charliereese.ca/article/top-50-y-combinator-tech-startups&quot;&gt;$92 billion in revenue it’s helped drive over the years&lt;/a&gt;. With this new approach, there’s a &lt;em&gt;ton&lt;/em&gt; more weight behind that punch. While your competitors are fiddling with their JSON serializers and struggling to optimize away all the loading spinners, you’re rolling out a new multi-user collaborative feature every week…or every &lt;em&gt;day&lt;/em&gt;.&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;You win. Your fellow developers win. Your business wins. And, most importantly, your &lt;em&gt;users&lt;/em&gt; win.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;That’s what Rails promised from the day it was released to the community. That’s why Rails spawned so many imitators in other languages, and why it saw such explosive growth in the startup world for years. And that same old rapid prototyping spirit, married to this new HTML-over-the-wire approach, positions Rails for a powerful resurgence.&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Ruby luminary and &lt;a href=&quot;https://www.amazon.com/Obie-Fernandez/e/B001IGV0LS&quot;&gt;author&lt;/a&gt; of &lt;em&gt;The Ruby Way&lt;/em&gt;, Obie Fernandez, &lt;a href=&quot;https://medium.com/@obie/react-is-dead-long-live-reactive-rails-long-live-stimulusreflex-and-viewcomponent-cd061e2b0fe2&quot;&gt;seems to think so&lt;/a&gt;.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Heck, even &lt;a href=&quot;https://www.youtube.com/watch?v=utxCm3uLhIE&quot;&gt;Russ Hanneman thinks this approach with StimulusReflex is the new hotness&lt;/a&gt;.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;And the good folks over at Basecamp (creators of Rails in the first place), dropped their own take on the concept, &lt;a href=&quot;https://hotwire.dev/&quot;&gt;Hotwire&lt;/a&gt;, just in time for the 2020 holidays, so your options for tackling this new and exciting technique continue to expand.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Don’t call it a comeback, because Rails has been here for years. With this new architectural approach, brimming with HTML-over-WebSockets and full-duplex JavaScript interactions, Rails becomes something new, something beautiful, something that demands attention (again).&amp;nbsp;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Reactive Rails, with StimulusReflex and friends, is a must-look for anyone exhausted from toiling with JSON endpoints or JSX, and I’m super excited to see the new crop of apps that it enables.&lt;/p&gt;
</description><link>https://alistapart.com/article/the-future-of-web-software-is-html-over-websockets/</link><guid isPermaLink="false">https://alistapart.com/article/the-future-of-web-software-is-html-over-websockets/</guid><pubDate>Thu, 25 Feb 2021 15:00:00 GMT</pubDate><author>brandongregory</author><category>Application Development</category><category>Code</category><category>HTML</category></item><item><title>Responsible JavaScript: Part III</title><description>&lt;p class=&quot;wp-block-paragraph&quot;&gt;You’ve done everything you thought was possible to address your website’s JavaScript problem. You &lt;a href=&quot;https://alistapart.com/article/responsible-javascript-part-1/&quot;&gt;relied on the web platform where you could&lt;/a&gt;. You &lt;a href=&quot;https://alistapart.com/article/responsible-javascript-part-2/#section9&quot;&gt;sidestepped Babel&lt;/a&gt; and &lt;a href=&quot;https://alistapart.com/article/responsible-javascript-part-2/#section7&quot;&gt;found smaller framework alternatives&lt;/a&gt;. You whittled your application code down to its most streamlined form possible. Yet, things are just not fast enough. When websites fail to perform the way we as designers and developers expect them to, we inevitably turn on ourselves:&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot; style=&quot;text-align:center&quot;&gt;&lt;em&gt;“What are we failing to do?” “What can we do with the code we have written?” “Which parts of our architecture are failing us?”&lt;/em&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;These are valid inquiries, as a fair share of performance woes &lt;em&gt;do&lt;/em&gt; originate from our own code. Yet, assigning blame solely to ourselves blinds us to the unvarnished truth that a sizable onslaught of our performance problems comes from the outside.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;When the third wheel crashes the party&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Convenience always has a price, and &lt;a href=&quot;https://httparchive.org/reports/state-of-javascript#bytesJs&quot;&gt;the web is wracked by our collective preference for it&lt;/a&gt;.&amp;nbsp; JavaScript, in particular, is employed in a way that suggests a rapidly increasing tendency to outsource whatever it is that We (the first party) don’t want to do. At times, this is a necessary decision; it makes perfect financial and operational sense in many situations.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;But make no mistake, &lt;a href=&quot;https://www.thirdpartyweb.today/&quot;&gt;third-party JavaScript is &lt;em&gt;never&lt;/em&gt; cheap&lt;/a&gt;. It’s a devil’s bargain where vendors seduce you with solutions to your problem, yet conveniently fail to remind you that you have little to no control over the side effects that solution introduces. If a third-party provider adds features to their product, &lt;em&gt;you&lt;/em&gt; bear the brunt. If they change their infrastructure, &lt;em&gt;you&lt;/em&gt; will feel the effects of it. Those who use your site &lt;em&gt;will&lt;/em&gt; become frustrated, and they aren’t going to bother grappling with an intolerable user experience. You can mitigate some of the symptoms of third parties, but you can’t cure the ailment unless you remove the solutions altogether—and that’s not always practical or possible.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;In this installment of &lt;em&gt;Responsible JavaScript&lt;/em&gt;, we’ll take a &lt;em&gt;slightly&lt;/em&gt; less technical approach than in the &lt;a href=&quot;https://alistapart.com/article/responsible-javascript-part-2/&quot;&gt;previous installment&lt;/a&gt;. We are going to talk more about the human side of third parties. Then, we’ll go down some of the technical avenues for how you might go about tackling the problem.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Hindered by convenience&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;When we talk about the sorry state of the web today, &lt;a href=&quot;https://infrequently.org/2018/09/the-developer-experience-bait-and-switch/&quot;&gt;some of us are quick to point out the role of &lt;em&gt;developer convenience&lt;/em&gt;&lt;/a&gt; in contributing to the problem. While I share the view that developer convenience has a tendency to harm the user experience, they’re not the only kind of convenience that can turn a website into a sluggish, janky mess.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;em&gt;Operational conveniences&lt;/em&gt; can become precursors to a very thorny sort of technical debt. These conveniences are what we reach for when we can’t solve a pervasive problem on our own. They represent third-party solutions that address problems in the absence of architectural flexibility and/or adequate development resources.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Whenever an inconvenience arises, &lt;em&gt;that&lt;/em&gt; is the time to have the discussion around how to tackle it in a way that’s comprehensive. So let’s talk about what it looks like to tackle that sort of scenario from a more human angle.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;The problem is pain&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;The reason third parties come into play in the first place is pain. When a decision maker in an organization has felt enough pain around a certain problem, they’re going to do a &lt;em&gt;very human thing&lt;/em&gt;, which is to find the fastest way to make that pain &lt;em&gt;go away&lt;/em&gt;.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Markets will always find ways to address these pain points, even if the way they do so isn’t sustainable or even remotely helpful. Web accessibility overlays—third-party scripts that purport to automatically fix accessibility issues—are among the worst offenders. First, you fork over your money for &lt;a href=&quot;https://blog.tenon.io/web-accessibility-overlays-dont-work/&quot;&gt;a fix that doesn’t &lt;em&gt;fix&lt;/em&gt; anything&lt;/a&gt;. Then you pay a wholly different sort of price when that “fix” harms the usability of your website. This is not a screed to discredit the usefulness of the tools some third-party vendors provide, but to illustrate how the adoption of third-party solutions happens, even those that are objectively awful&lt;/p&gt;



&lt;figure class=&quot;wp-block-image&quot;&gt;&lt;img data-recalc-dims=&quot;1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;960&quot; height=&quot;561&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2019/11/fig-1.png?resize=960%2C561&amp;amp;ssl=1&quot; alt=&quot;A depiction of a long task in a flame chart from the performance panel in Chrome DevTools.&quot; class=&quot;wp-image-7172133&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;figcaption&gt;A Chrome performance trace of a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Long_Tasks_API#Long_task&quot;&gt;long task&lt;/a&gt; kicked off by a third party’s web accessibility overlay script. The task occupies the main thread for roughly 600 ms on a 2017 &lt;a href=&quot;https://en.wikipedia.org/wiki/MacBook_(2015%E2%80%932019)&quot;&gt;Retina MacBook&lt;/a&gt;.&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;So when a vendor rolls up and promises to solve the very painful problem we’re having, there’s a good chance someone is going to nibble. If that someone is high enough in the hierarchy, they’ll exert downward pressure on others to buy in—if not circumvent them entirely in the decision-making process. Conversely, adoption of a third-party solution can also occur when those in the trenches are under pressure and lack sufficient resources to create the necessary features themselves.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Whatever the catalyst, it pays to gather your colleagues and collectively form a plan for navigating and mitigating the problems you’re facing.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Create a mitigation plan&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Once people in an organization have latched onto a third-party solution, however ill-advised, the difficulty you’ll encounter in forcing a course change will depend on how urgent a need that solution serves. In fact, you shouldn’t try to convince proponents of the solution that their decision was wrong. Such efforts almost always backfire and can make people feel attacked and more resistant to what you’re telling them. Even worse, those efforts could create acrimony where people stop listening to each other completely, and &lt;em&gt;that&lt;/em&gt; is a breeding ground for far worse problems to develop.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Grouse and commiserate amongst your peers if you must—as I myself have often done—but put your grievances aside and &lt;a href=&quot;https://csswizardry.com/2018/05/identifying-auditing-discussing-third-parties/#discussing&quot;&gt;come up with a mitigation plan&lt;/a&gt; to guide your colleagues toward better outcomes. The nooks and crannies of your specific approach will depend on the third parties themselves and the structure of the organization, but the bones of it could look like the following series of questions.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;What problem does this solution address?&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;There’s a reason why a third-party solution was selected, and this question will help you suss out whether the rationale for its adoption is sound. Remember, there are times decisions are made when all the necessary people are not in the room. You might be in a position where you have to react to the aftermath of that decision, but the answer to this question will lead you to a natural follow-up.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;How long do we intend to use the solution?&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;This question will help you identify the solution’s shelf life. Was it introduced as a bandage, with the intent to remove it once the underlying problem has been addressed, such as in the case of an accessibility overlay? Or is the need more long-term, such as the data provided by an A/B testing suite? The other possibility is that the solution can never be effectively removed because it serves a crucial purpose, as in the case of analytics scripts. &lt;a href=&quot;https://alistapart.com/article/the-foundation-of-technical-leadership/#section3&quot;&gt;It’s like throwing a mattress in a swimming pool&lt;/a&gt;: it’s easy to throw in, but nigh impossible to drag back out.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;In any case, you can’t know if a third-party script is here to stay if you don’t ask. Indeed, if you find out the solution is temporary, you can form a plan to eventually remove it from your site once the underlying problem it addresses has been resolved.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Who’s the point of contact if issues arise?&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;When a third-party solution is put into place, someone &lt;em&gt;must&lt;/em&gt; be the point of contact for when—not &lt;em&gt;if&lt;/em&gt;—issues arise.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;I’ve seen what happens (far too often) when a third-party script gets out of control. For example, when a tag manager or an A/B testing framework’s JavaScript grows slowly and insidiously because marketers aren’t cleaning out old tags or completed A/B tests. It’s for precisely these reasons that responsibility needs to be attached to a specific person in your organization for third-party solutions currently in use on your site. What that responsibility entails will differ in every situation, but could include:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;&lt;li&gt;periodic monitoring of the third-party script’s footprint;&lt;/li&gt;&lt;li&gt;maintenance to ensure the third-party script doesn’t grow out of control;&lt;/li&gt;&lt;li&gt;occasional meetings to discuss the future of that vendor’s relationship with your organization;&lt;/li&gt;&lt;li&gt;identification of overlaps of functionality between multiple third parties, and if potential redundancies can be removed;&lt;/li&gt;&lt;li&gt;and ongoing research, especially to identify speedier alternatives that may act as better replacements for slow third-party scripts.&lt;/li&gt;&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;The idea of responsibility in this context should never be an onerous, draconian obligation you yoke your teammates with, but rather an exercise in encouraging mindfulness in your colleagues. Because without mindfulness, a third-party script’s ill effects on your website &lt;em&gt;will&lt;/em&gt; be overlooked until it becomes a grumbling ogre in the room that can no longer be ignored. Assigning responsibility for third parties can help to prevent that from happening.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Ensuring responsible usage of third-party solutions&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;If you can put together a mitigation plan and get everyone on board, the work of ensuring the responsible use of third-party solutions can begin. Luckily for you, the actual technical work will be easier than trying to wrangle people. So if you’ve made it this far, all it will take to get results is time and persistence.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Load only what’s necessary&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;It may seem obvious, but load only what’s necessary. Judging by the amount of unused first-party JavaScript I see loaded—let alone &lt;em&gt;third-party&lt;/em&gt; JavaScript—it’s clearly a problem. It’s like trying to clean your house by stuffing clutter into the closets. Regardless of whether they’re actually needed, it’s not uncommon for third-party scripts to be loaded on every single page, so refer to your point of contact to figure out which pages need which third-party scripts.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;As an example, one of my past clients used a popular third-party tool across multiple brand sites to get a list of retailers for a given product. It demonstrated clear value, but that script only needed to be on a site’s product detail page. In reality, it was frequently loaded on &lt;em&gt;every&lt;/em&gt; page. Culling this script from pages where it didn’t belong significantly boosted performance for non-product pages, which ostensibly reduced the friction on the conversion path.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Figuring out which pages need which third-party scripts requires you to do some decidedly untechnical work. You’ll actually have to get up from your desk and talk to the person who has been assigned responsibility for the third-party solution you’re grappling with. This is very difficult work for me, but it’s rewarding when good-faith collaboration happens, &lt;em&gt;and&lt;/em&gt; good outcomes are realized as a result.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Self-host your third-party scripts&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;This advice isn’t a secret by any stretch. &lt;a href=&quot;https://alistapart.com/article/responsible-javascript-part-2/#section6&quot;&gt;I even touched on it&lt;/a&gt; in the previous installment of this series, but it needs to be shouted from the rooftops at every opportunity: you should &lt;a href=&quot;https://csswizardry.com/2019/05/self-host-your-static-assets/&quot;&gt;self-host as many third-party resources&lt;/a&gt; as possible. Whether this is feasible depends on the third-party script in question.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Is it some framework you’re grabbing from &lt;a href=&quot;https://developers.google.com/speed/libraries&quot;&gt;Google’s hosted libraries&lt;/a&gt;, &lt;a href=&quot;https://cdnjs.com/&quot;&gt;cdnjs&lt;/a&gt;, or other similar provider? Self-host that sucker &lt;em&gt;right now&lt;/em&gt;.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://medium.com/caspertechteam/we-shaved-1-7-seconds-off-casper-com-by-self-hosting-optimizely-2704bcbff8ec&quot;&gt;Casper found a way to self-host their Optimizely script&lt;/a&gt; and significantly reduced their start render time for their trouble. It really drives home the point that a major detriment of third-party resources is the fact that their mere existence on other servers is one of the worst performance bottlenecks we encounter.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;If you’re looking to self-host an analytics solution or a similar sort of script, there’s a higher level of difficulty to contend with to self-host it. You may find that some third-party scripts simply can’t be self-hosted, but that doesn’t mean it isn’t worth the trouble to find out. If you find that self-hosting isn’t an option for a third-party script, don’t fret. There are other mitigations you can try.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Mask latency of cross-origin connections&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;If you can’t self-host your third-party scripts, the next best thing is to preconnect to servers that host them. WebPageTest’s Connection View does a fantastic job of showing you which servers your site gathers resources from, as well as the latency involved in establishing connections to them.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image&quot;&gt;&lt;img data-recalc-dims=&quot;1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;930&quot; height=&quot;380&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2019/11/fig2.png?resize=930%2C380&amp;amp;quality=80&amp;amp;ssl=1&quot; alt=&quot;A screenshot of WebPageTest&#39;s connection view, which visualizes the latency involved with all the servers that serve content for a given page in a waterfall chart.&quot; class=&quot;wp-image-7172134&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;figcaption&gt;WebPageTest’s Connection View shows all the different servers a page requests resources from during load.&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://web.dev/uses-rel-preconnect&quot;&gt;Preconnections&lt;/a&gt; are effective because they establish connections to third-party servers before the browser would otherwise discover them in due course. Parsing HTML takes time, and parsers are often blocked by stylesheets and other scripts. Wherever you can’t self-host third-party scripts, preconnections make perfect sense.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Maybe don’t preload third-party scripts&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content&quot;&gt;Preloading resources&lt;/a&gt; is one of those things that sounds fantastic at first—until you consider &lt;a href=&quot;https://andydavies.me/blog/2019/02/12/preloading-fonts-and-the-puzzle-of-priorities/&quot;&gt;its potential to backfire&lt;/a&gt;, as &lt;a href=&quot;https://andydavies.me/&quot;&gt;Andy Davies&lt;/a&gt; points out. If you’re unfamiliar with preloading, it’s similar to preconnecting but goes a step further by instructing the browser to fetch a particular resource far sooner than it ordinarily would.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;The drawback of preloading is that while it’s great for ensuring a resource gets loaded as soon as possible, it changes the discovery order of that resource. Whenever we do this, we’re implicitly saying that other resources are less important—including resources crucial to rendering or even core functionality.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;It’s probably a safe bet that most of your third-party code is not as crucial to the functionality of your site as your own code. That said, if you &lt;em&gt;must&lt;/em&gt; preload a third-party resource, ensure you’re only doing so for third-party scripts that are critical to page rendering.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;If you do find yourself in a position where your site’s initial rendering depends on a third-party script, refer to your mitigation plan to see what you can do to eliminate or ameliorate your dependence on it. Depending on a third party for core functionality is never a good position to be in, as you’re relinquishing a lot of control to others who might not have your best interests in mind.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Lazy load non-essential third-party scripts&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://alistapart.com/article/the-best-request-is-no-request-revisited/&quot;&gt;The best request is no request&lt;/a&gt;. If you have a third-party script that doesn’t need to be loaded right away, consider lazy loading it with an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot;&gt;Intersection Observer&lt;/a&gt;. Here’s what it might look like to &lt;a href=&quot;https://codepen.io/malchata/pen/JjjGOGZ&quot;&gt;lazy load a Facebook Like button&lt;/a&gt; when it’s scrolled into the viewport:&lt;/p&gt;



&lt;pre id=&quot;snippet1&quot; class=&quot;wp-block-code language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;
let loadedFbScript = false;

const intersectionListener = new IntersectionObserver(entries =&amp;gt; {
  entries.forEach(entry =&amp;gt; {
    if ((entry.isIntersecting || entry.intersectionRatio) &amp;amp;&amp;amp; !loadedFbScript) {
      const scriptEl = document.createElement(&quot;script&quot;);

      scriptEl.defer = true;
      scriptEl.crossOrigin = &quot;anonymous&quot;;
      scriptEl.src = &quot;https://connect.facebook.net/en_US/sdk.js#xfbml=1&amp;amp;version=v3.0&quot;;
      scriptEl.onload = () =&amp;gt; {
        loadedFbScript = true;
      };
      
      document.body.append(scriptEl);
    }
  });
});

intersectionListener.observe(document.querySelector(&quot;.fb-like&quot;));
&lt;/code&gt;
&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;In the above snippet, we first set a variable to track whether we’ve loaded the Facebook SDK JavaScript. After that, an &lt;code&gt;IntersectionListener&lt;/code&gt; is created that checks whether the observed element is in the viewport, and whether the Facebook SDK has been loaded. If the SDK JavaScript hasn’t been loaded, a reference to it is injected into the DOM, which will kick off a request for it.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;You’re not going to be able to lazy load every third-party script. Some of them simply need to do their work at page load time, or otherwise can’t be deferred. Regardless, do the detective work to see if it’s possible to lazy load at least some of your third-party JavaScript.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;One of the common concerns I hear from coworkers when I suggest lazy loading third-party scripts is how it can delay whatever interactions the third party provides. That’s a reasonable concern, because when you lazy load anything, a noticeable delay may occur as the resource loads. You can get around this to some extent with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Link_prefetching_FAQ&quot;&gt;resource prefetching&lt;/a&gt;. This is different than preloading, which we discussed earlier. Prefetching consumes a comparable amount of data, yes, but prefetched resources are given lower priority and are less likely to contend for bandwidth with critical resources.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Staying on top of the problem&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Keeping an eye on your third-party JavaScript requires mindfulness bordering on hypervigilance. When you recognize poor performance for the technical debt that it truly is, you’ll naturally slip into a frame of mind where you’ll recognize and address it as you would any other kind of technical debt.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Staying on top of third parties &lt;em&gt;is&lt;/em&gt; refactoring—a sort that requires you to periodically perform tasks such as cleaning up tag managers and A/B tests, consolidating third-party solutions, eliminating any that are no longer needed, and applying the coding techniques discussed above. Moreover, you’ll need to work with your team to address this technical debt on a cyclical basis. This kind of work can’t be automated, so yes, you’ll need to knuckle down and have face-to-face, synchronous conversations with actual people.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;If you’re already in the habit of scheduling “cleanup sprints” on some interval, then &lt;em&gt;that&lt;/em&gt; is the time and space for you to address performance-related technical debt, regardless of whether it involves third- or first-party code. There’s a time for feature development, but that time should not comprise the whole of your working hours. Development shops that focus only on feature development are destined to be wholly consumed by the technical debt that will inevitably result.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;So it will come to pass that in the fourth and final installment of this series we’ll discuss what it means to do the hard work of using JavaScript responsibly in the context of process. Therein, we’ll explore what it takes to unite your organization under the banner of making your website faster and more accessible, and therefore more usable for everyone, everywhere.&lt;/p&gt;
</description><link>https://alistapart.com/article/responsible-javascript-part-3/</link><guid isPermaLink="false">https://alistapart.com/article/responsible-javascript-part-3/</guid><pubDate>Thu, 14 Nov 2019 14:30:42 GMT</pubDate><author>jeremy-wagner</author><category>Application Development</category><category>Code</category><category>Industry &amp;amp; Business</category><category>JavaScript</category><category>State of the Web</category></item><item><title>Responsible JavaScript: Part II</title><description>&lt;p class=&quot;wp-block-paragraph&quot;&gt;You and the rest of the dev team lobbied enthusiastically for a total re-architecture of the company’s aging website. Your pleas were heard by management—even up to the C-suite—who gave the green light. Elated, you and the team started working with the design, copy, and IA teams. Before long, you were banging out new code.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;It started out innocently enough with an &lt;code&gt;npm install&lt;/code&gt; here and an &lt;code&gt;npm install&lt;/code&gt; there. Before you knew it, though, you were installing production dependencies like an undergrad doing keg stands without a care for the morning after.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Then you launched.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Unlike the aftermath of most copious boozings, the agony didn’t start the morning after. &lt;em&gt;Oh&lt;/em&gt;, no. It came months later in the ghastly form of low-grade nausea and headache of product owners and middle management wondering why conversions and revenue were both down since the launch. It then hit a fever pitch when the CTO came back from a weekend at the cabin and wondered why the site loaded so slowly on their phone—if it indeed ever loaded at all.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Everyone was happy. Now &lt;em&gt;no&lt;/em&gt; one is happy. Welcome to your first JavaScript hangover.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;It’s not your fault&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;When you’re grappling with a vicious hangover, “I told you so” would be a well-deserved, if fight-provoking, rebuke—assuming you could even fight in so sorry a state.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;When it comes to JavaScript hangovers, there’s plenty of blame to dole out. Pointing fingers is a waste of time, though. The landscape of the web today demands that we iterate faster than our competitors. This kind of pressure means we’re likely to take advantage of any means available to be as productive as possible. &lt;em&gt;That&lt;/em&gt; means we’re more likely—but not necessarily doomed—to build apps with more overhead, and possibly use patterns that can hurt performance and accessibility.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Web development isn’t easy. It’s a long slog we rarely get right on the first try. The best part of working on the web, however, is that we don’t &lt;em&gt;have&lt;/em&gt; to get it perfect at the start. We can make improvements after the fact, and that’s just what the second installment of &lt;a href=&quot;https://alistapart.com/article/responsible-javascript-part-1/&quot;&gt;this series&lt;/a&gt; is here for. Perfection is a long ways off. For now, let’s take the edge off of that JavaScript hangover by improving your site’s, er, &lt;em&gt;scriptuation&lt;/em&gt; in the short term.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Round up the usual suspects&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;It might seem rote, but it’s worth going through the list of basic optimizations. It’s not uncommon for large development teams—particularly those that work across many repositories or don’t use optimized boilerplate—to overlook them.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Shake those trees&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;First, make sure your toolchain is configured to perform &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking&quot;&gt;&lt;em&gt;tree shaking&lt;/em&gt;&lt;/a&gt;. If tree shaking is new to you, I wrote &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-javascript/tree-shaking/&quot;&gt;a guide on it last year&lt;/a&gt; you can consult. The short of it is that tree shaking is a process in which unused exports in your codebase don’t get packaged up in your production bundles.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Tree shaking is available out of the box with modern bundlers such as &lt;a href=&quot;https://webpack.js.org/&quot;&gt;webpack&lt;/a&gt;, &lt;a href=&quot;https://rollupjs.org/&quot;&gt;Rollup&lt;/a&gt;, or &lt;a href=&quot;https://parceljs.org/&quot;&gt;Parcel&lt;/a&gt;. &lt;a href=&quot;https://gruntjs.com/&quot;&gt;Grunt&lt;/a&gt; or &lt;a href=&quot;https://gulpjs.com/&quot;&gt;gulp&lt;/a&gt;—which are not &lt;em&gt;bundlers&lt;/em&gt;, but rather &lt;em&gt;task runners&lt;/em&gt;—won’t do this for you. A task runner doesn’t build a &lt;a href=&quot;https://webpack.js.org/concepts/dependency-graph/&quot;&gt;dependency graph&lt;/a&gt; like a bundler does. Rather, they perform discrete tasks on the files you feed to them with any number of plugins. Task runners &lt;em&gt;can&lt;/em&gt; be extended with plugins to use bundlers to process JavaScript. If extending task runners in this way is problematic for you, you’ll likely need to manually audit and remove unused code.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;For tree shaking to be effective, the following must be true:&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;&lt;li&gt;Your app logic and the packages you install in your project must be authored as &lt;a href=&quot;https://ponyfoo.com/articles/es6-modules-in-depth&quot;&gt;ES6 modules&lt;/a&gt;. Tree shaking &lt;a href=&quot;https://en.wikipedia.org/wiki/CommonJS&quot;&gt;CommonJS&lt;/a&gt; modules isn’t practically possible.&lt;/li&gt;&lt;li&gt;Your bundler must &lt;em&gt;not&lt;/em&gt; transform ES6 modules into another module format at build time. If this happens in a toolchain that uses Babel, &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env&quot;&gt;@babel/preset-env configuration&lt;/a&gt; must specify &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#modules&quot;&gt;&lt;code&gt;modules: false&lt;/code&gt;&lt;/a&gt; to prevent ES6 code from being converted to CommonJS.&lt;/li&gt;&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;On the off chance tree shaking isn’t occurring during your build, getting it to work may help. Of course, its effectiveness varies on a case-by-case basis. It also depends on whether the modules you import introduce &lt;a href=&quot;https://en.wikipedia.org/wiki/Side_effect_(computer_science)&quot;&gt;side effects&lt;/a&gt;, which may influence a bundler’s ability to shake unused exports.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Split that code&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Chances are good that you’re employing some form of &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-javascript/code-splitting/&quot;&gt;code splitting&lt;/a&gt;, but it’s worth re-evaluating how you’re doing it. No matter &lt;em&gt;how&lt;/em&gt; you’re splitting code, there are two questions that are always worth asking yourself:&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;&lt;li&gt;Are you &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-javascript/code-splitting/#removing_duplicate_code&quot;&gt;deduplicating common code&lt;/a&gt; between &lt;a href=&quot;https://webpack.js.org/concepts/entry-points/&quot;&gt;entry points&lt;/a&gt;?&lt;/li&gt;&lt;li&gt;Are you lazy loading all the functionality you reasonably can with &lt;a href=&quot;https://developers.google.com/web/updates/2017/11/dynamic-import&quot;&gt;dynamic &lt;code&gt;import()&lt;/code&gt;&lt;/a&gt;?&lt;/li&gt;&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;These are important because reducing redundant code is essential to performance. Lazy loading functionality also improves performance by lowering the initial JavaScript footprint on a given page. On the redundancy front, using an analysis tool such as &lt;a href=&quot;https://github.com/samccone/bundle-buddy&quot;&gt;Bundle Buddy&lt;/a&gt; can help you find out if you have a problem.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image&quot;&gt;&lt;img data-recalc-dims=&quot;1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;652&quot; height=&quot;628&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2019/06/figure-6-2x.png?resize=652%2C628&amp;amp;ssl=1&quot; alt=&quot;The Bundle Buddy utility demonstrating how much code is shared between bundles of JavaScript.&quot; class=&quot;wp-image-7171674&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;figcaption&gt;Bundle Buddy can examine your webpack compilation statistics and determine how much code is shared between your bundles.&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Where lazy loading is concerned, it can be a bit difficult to know where to start looking for opportunities. When I look for opportunities in existing projects, I’ll search for user interaction points throughout the codebase, such as click and keyboard events, and similar candidates. Any code that requires a user interaction to run is a potentially good candidate for dynamic &lt;code&gt;import()&lt;/code&gt;.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Of course, loading scripts on demand brings the possibility that interactivity could be noticeably delayed, as the script necessary for the interaction must be downloaded first. If data usage is not a concern, consider using the &lt;a href=&quot;https://www.w3.org/TR/resource-hints/#prefetch&quot;&gt;&lt;code&gt;rel=prefetch&lt;/code&gt; resource hint&lt;/a&gt; to load such scripts at a low priority that won’t contend for bandwidth against critical resources. &lt;a href=&quot;https://caniuse.com/#feat=link-rel-prefetch&quot;&gt;Support for&lt;strong&gt; &lt;/strong&gt;&lt;code&gt;rel=prefetch&lt;/code&gt;&lt;/a&gt; is good, but nothing will break if it’s unsupported, as such browsers will ignore markup they doesn’t understand.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Externalize third-party hosted code&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Ideally, you should self-host as many of your site’s dependencies as possible. If for some reason you &lt;em&gt;must&lt;/em&gt; load dependencies from a third party, &lt;a href=&quot;https://webpack.js.org/configuration/externals/&quot;&gt;mark them as externals&lt;/a&gt; in your bundler’s configuration. Failing to do so could mean your website’s visitors will download both locally hosted code &lt;em&gt;and&lt;/em&gt; the same code from a third party.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Let’s look at a hypothetical situation where this could hurt you: say that your site loads Lodash from a public CDN. You’ve also installed Lodash in your project for local development. However, if you fail to mark Lodash as external, your production code will end up loading a third party copy of it &lt;em&gt;in addition&lt;/em&gt; to the bundled, locally hosted copy.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;This may &lt;em&gt;seem&lt;/em&gt; like common knowledge if you know your way around bundlers, but I’ve seen it get overlooked. It’s worth your time to check twice.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;If you aren’t convinced to self-host your third-party dependencies, then consider adding &lt;a href=&quot;https://css-tricks.com/prefetching-preloading-prebrowsing/#article-header-id-0&quot;&gt;&lt;code&gt;dns-prefetch&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://css-tricks.com/prefetching-preloading-prebrowsing/#article-header-id-1&quot;&gt;&lt;code&gt;preconnect&lt;/code&gt;&lt;/a&gt;, or possibly even &lt;a href=&quot;https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/&quot;&gt;&lt;code&gt;preload&lt;/code&gt;&lt;/a&gt; hints for them. Doing so can lower your site’s &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive&quot;&gt;Time to Interactive&lt;/a&gt; and—if JavaScript is critical to rendering content—your site’s &lt;a href=&quot;https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index&quot;&gt;Speed Index&lt;/a&gt;.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Smaller alternatives for less overhead&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://nodejs.org/en/knowledge/getting-started/what-is-node-core-verus-userland/&quot;&gt;Userland JavaScript&lt;/a&gt; is like an obscenely massive candy store, and we as developers are awed by the sheer amount of open source offerings. Frameworks and libraries allow us to extend our applications to quickly do all sorts of stuff that would otherwise take loads of time and effort.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;While I personally prefer to aggressively minimize the use of client-side frameworks and libraries in my projects, their value is compelling. Yet, we &lt;em&gt;do&lt;/em&gt; have a responsibility to be a bit hawkish when it comes to what we install. When we’ve already built and shipped something that depends on a slew of installed code to run, we’ve accepted a baseline cost that only the maintainers of that code can practically address. Right?&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Maybe, but then again, maybe not. It depends on the dependencies used. For instance, React is extremely popular, but &lt;a href=&quot;https://preactjs.com/&quot;&gt;Preact&lt;/a&gt; is an &lt;a href=&quot;https://bundlephobia.com/result?p=preact@8.4.2&quot;&gt;ultra-small&lt;/a&gt; alternative that largely shares the same API and retains compatibility with many React add-ons. &lt;a href=&quot;https://moment.github.io/luxon/&quot;&gt;Luxon&lt;/a&gt; and &lt;a href=&quot;https://date-fns.org/&quot;&gt;date-fns&lt;/a&gt; are much more compact alternatives to &lt;a href=&quot;https://momentjs.com/&quot;&gt;moment.js&lt;/a&gt;, which is &lt;a href=&quot;https://bundlephobia.com/result?p=moment&quot;&gt;not exactly tiny&lt;/a&gt;.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Libraries such as &lt;a href=&quot;https://lodash.com/&quot;&gt;Lodash&lt;/a&gt; offer many useful methods. Yet, some of them are easily replaceable with native ES6. &lt;a href=&quot;https://lodash.com/docs/4.17.11#compact&quot;&gt;Lodash’s &lt;code&gt;compact&lt;/code&gt; method&lt;/a&gt;, for example, is replaceable with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter&quot;&gt;&lt;code&gt;filter&lt;/code&gt; array method&lt;/a&gt;. &lt;a href=&quot;https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_chunk&quot;&gt;Many more can be replaced&lt;/a&gt; without much effort, and without the need for pulling in a large utility library.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Whatever your preferred tools are, the idea is the same: do some research to see if there are smaller alternatives, or if native language features can do the trick. You may be surprised at how little effort it may take you to seriously reduce your app’s overhead.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Differentially serve your scripts&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;There’s a good chance you’re using Babel in your toolchain to transform your ES6 source into code that can run on older browsers. Does this mean we’re doomed to serve giant bundles even to browsers that don’t need them, until the older browsers disappear altogether? &lt;a href=&quot;https://philipwalton.com/articles/deploying-es2015-code-in-production-today/&quot;&gt;Of course not&lt;/a&gt;! Differential serving helps us get around this by generating two different builds of your ES6 source:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;&lt;li&gt;Bundle one, which contains all the transforms and polyfills required for your site to work on older browsers. You’re probably already serving this bundle right now.&lt;/li&gt;&lt;li&gt;Bundle two, which contains &lt;em&gt;little to none&lt;/em&gt; of the transforms and polyfills because it targets modern browsers. This is the bundle you’re probably not serving—at least not &lt;em&gt;yet&lt;/em&gt;.&lt;/li&gt;&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Achieving this is a bit involved. &lt;a href=&quot;https://calendar.perfplanet.com/2018/doing-differential-serving-in-2019/&quot;&gt;I’ve written a guide on one way you can do it&lt;/a&gt;, so there’s no need for a deep dive here. The long and short of it is that you can modify your build configuration to generate an additional but smaller version of your site’s JavaScript code, and serve it only to modern browsers. The best part is that these are savings you can achieve without sacrificing any features or functionality you already offer. Depending on your application code, the savings could be quite significant.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image&quot;&gt;&lt;img data-recalc-dims=&quot;1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;960&quot; height=&quot;297&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2019/06/diff-serving-bundles.jpg?resize=960%2C297&amp;amp;ssl=1&quot; alt=&quot;&quot; class=&quot;wp-image-7171677&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;figcaption&gt;A webpack-bundle-analyzer analysis of a project’s legacy bundle (left) versus one for a modern bundle (right). &lt;a href=&quot;https://alistapart.com/wp-content/uploads/2019/06/diff-serving-bundles.jpg&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;View full-sized image&lt;/a&gt;.&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;The &lt;a href=&quot;https://developers.google.com/web/fundamentals/primers/modules#browser&quot;&gt;simplest pattern&lt;/a&gt; for serving these bundles to their respective platforms is brief. It also works a treat in modern browsers:&lt;/p&gt;



&lt;pre id=&quot;snippet1&quot; class=&quot;wp-block-code language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!-- Modern browsers load this file: --&amp;gt;
&lt;a href=&quot;https://alistapart.com/js/app.mjs&quot;&gt;/js/app.mjs&lt;/a&gt;
&amp;lt;!-- Legacy browsers load this file: --&amp;gt;
&lt;a href=&quot;https://alistapart.com/js/app.js&quot;&gt;/js/app.js&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Unfortunately, there’s a caveat with this pattern: legacy browsers like IE 11—and even relatively modern ones such as Edge versions 15 through 18—will download &lt;em&gt;both&lt;/em&gt; bundles. If this is an acceptable trade-off for you, then worry no further.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;On the other hand, you’ll need a workaround if you’re concerned about &lt;a href=&quot;https://gist.github.com/jakub-g/5fc11af85a061ca29cc84892f1059fec&quot;&gt;the performance implications of older browsers downloading both sets of bundles&lt;/a&gt;. Here’s one potential solution that uses script injection (instead of the &lt;code&gt;script&lt;/code&gt; tags above) to avoid double downloads on affected browsers:&lt;/p&gt;



&lt;pre id=&quot;snippet2&quot; class=&quot;wp-block-code language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;var scriptEl = document.createElement(&quot;script&quot;);

if (&quot;noModule&quot; in scriptEl) {
  // Set up modern script
  scriptEl.src = &quot;/js/app.mjs&quot;;
  scriptEl.type = &quot;module&quot;;
} else {
  // Set up legacy script
  scriptEl.src = &quot;/js/app.js&quot;;
  scriptEl.defer = true; // type=&quot;module&quot; defers by default, so set it here.
}

// Inject!
document.body.appendChild(scriptEl);&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;This script infers that if a browser supports &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-nomodule&quot;&gt;the &lt;code&gt;nomodule&lt;/code&gt; attribute&lt;/a&gt; in the &lt;code&gt;script&lt;/code&gt; element, it understands &lt;code&gt;type=&quot;module&quot;&lt;/code&gt;. This ensures that legacy browsers only get legacy scripts and modern browsers only get modern ones. Be warned, though, that dynamically injected scripts load asynchronously by default, so set the &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-async&quot;&gt;async&lt;/a&gt;&lt;/code&gt; attribute to &lt;code&gt;false&lt;/code&gt; if dependency order is crucial.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Transpile less&lt;/h2&gt;



&lt;p class=&quot;has-text-align-left wp-block-paragraph&quot;&gt;I’m not here to trash Babel. It’s indispensable, but lordy, it adds a &lt;em&gt;lot&lt;/em&gt; of extra stuff without your ever knowing. It pays to peek under the hood to see what it’s up to. Some minor changes in your coding habits can have a positive impact on what Babel spits out.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image&quot;&gt;&lt;img data-recalc-dims=&quot;1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;758&quot; height=&quot;421&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2019/06/twete.png?resize=758%2C421&amp;amp;ssl=1&quot; alt=&quot;&quot; class=&quot;wp-image-7171676&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;figcaption&gt;&lt;a href=&quot;https://twitter.com/_developit/status/1110229993999777793&quot;&gt;https://twitter.com/_developit/status/1110229993999777793&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;To wit: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters&quot;&gt;default parameters&lt;/a&gt; are a &lt;em&gt;very&lt;/em&gt; handy ES6 feature you probably already use:&lt;/p&gt;



&lt;pre id=&quot;snippet3&quot; class=&quot;wp-block-code language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;function logger(message, level = &quot;log&quot;) {
  console[level](message);
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;The thing to pay attention to here is the &lt;code&gt;level&lt;/code&gt; parameter, which has a default of “log.” This means if we want to invoke &lt;code&gt;console.log&lt;/code&gt; with this wrapper function, we don’t need to specify &lt;code&gt;level&lt;/code&gt;. Great, right? Except when Babel transforms this function, the output looks like this:&lt;/p&gt;



&lt;pre id=&quot;snippet4&quot; class=&quot;wp-block-code language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;function logger(message) {
  var level = arguments.length &amp;gt; 1 &amp;amp;&amp;amp; arguments[1] !== undefined ? arguments[1] : &quot;log&quot;;

  console[level](message);
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;This is an example of how, despite our best intentions, developer conveniences can backfire. What was a handful of bytes in our source has now been transformed into &lt;em&gt;much&lt;/em&gt; larger in our production code. Uglification can’t do much about it either, as arguments can’t be reduced. Oh, and if you think &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters&quot;&gt;rest parameters&lt;/a&gt; might be a worthy antidote, Babel’s transforms for them are even bulkier:&lt;/p&gt;



&lt;pre id=&quot;snippet5&quot; class=&quot;wp-block-code language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Source
function logger(...args) {
  const [level, message] = args;

  console[level](message);
}

// Babel output
function logger() {
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key &amp;lt; _len; _key++) {
    args[_key] = arguments[_key];
  }

  const level = args[0],
        message = args[1];
  console[level](message);
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Worse yet, Babel transforms this code even for projects with a &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env&quot;&gt;@babel/preset-env&lt;/a&gt; configuration &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#targetsesmodules&quot;&gt;targeting modern browsers&lt;/a&gt;, meaning the modern bundles in your differentially served JavaScript will be affected too! You &lt;em&gt;could&lt;/em&gt; use &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#loose&quot;&gt;loose transforms&lt;/a&gt; to soften the blow—and that’s a fine idea, as they’re often quite a bit smaller than their more spec-compliant counterparts—&lt;a href=&quot;http://2ality.com/2015/12/babel6-loose-mode.html&quot;&gt;but enabling loose transforms can cause issues if you remove Babel from your build pipeline later on&lt;/a&gt;.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Regardless of whether you decide to enable loose transforms, here’s one way to cut the cruft of transpiled default parameters:&lt;/p&gt;



&lt;pre id=&quot;snippet6&quot; class=&quot;wp-block-code language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;pre id=&quot;snippet2&quot; class=&quot;wp-block-code language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Babel won&#39;t touch this
function logger(message, level) {
  console[level || &quot;log&quot;](message);
}&lt;/code&gt;&lt;/pre&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Of course, default parameters aren’t the &lt;em&gt;only&lt;/em&gt; feature to be wary of. For example, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax&quot;&gt;spread syntax&lt;/a&gt; gets transformed, as do &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot;&gt;arrow functions&lt;/a&gt; and a whole host of &lt;a href=&quot;https://babeljs.io/repl/#?babili=false&amp;amp;browsers=%3E%200.25%25%2C%20ie%20%3E%2010%2C%20Firefox%20ESR%2C%20not%20dead&amp;amp;build=&amp;amp;builtIns=false&amp;amp;spec=false&amp;amp;loose=false&amp;amp;code_lz=MYGwhgzhAECyYDsCuAzMwAuSBOBTb0A3gFDTTAD2CEG2SmFBAFALaKrpZ7YA05FSBLQCeASiKky0DAAsAlhAB0bZGkw580ALzQVHddwDcksrIWLKgkdv5Xsw42QC-xF8VCQYAYTAFcADwxcBAATGHhVTg0CEjJKalp6DEZoVgoQ3BA-YVxfPkoQRj5FEt8AcwhxWKkIJAAHfCYSxXLKxykTaXklFnTMm16MkHbTbsUc3xsJ7BGu8wKUnQWZyRcySTw6sDkhVOWqzrMlZZtl9pc3eJpoNBY5EGEfAh0EXAB3aCemACIfFntvnxvgAmAAMoOBgOg3wAMoJJrAFBg4LgMGAQCA5MAod8ACoUYQUNE4gBSYC2CG-okMQA&amp;amp;debug=false&amp;amp;forceAllTransforms=false&amp;amp;shippedProposals=false&amp;amp;circleciRepo=&amp;amp;evaluate=true&amp;amp;fileSize=true&amp;amp;timeTravel=false&amp;amp;sourceType=module&amp;amp;lineWrap=true&amp;amp;presets=env&amp;amp;prettier=false&amp;amp;targets=&amp;amp;version=7.4.5&amp;amp;externalPlugins=&quot;&gt;other stuff&lt;/a&gt;.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;If you don’t want to avoid these features altogether, you have a couple ways of reducing their impact:&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;&lt;li&gt;If you’re authoring a library, consider using &lt;a href=&quot;https://babeljs.io/docs/en/babel-runtime&quot;&gt;@babel/runtime&lt;/a&gt; in concert with &lt;a href=&quot;https://babeljs.io/docs/en/babel-plugin-transform-runtime&quot;&gt;@babel/plugin-transform-runtime&lt;/a&gt; to deduplicate the helper functions Babel puts into your code.&lt;/li&gt;&lt;li&gt;For polyfilled features in apps, you can include them selectively with &lt;a href=&quot;https://babeljs.io/docs/en/babel-polyfill&quot;&gt;@babel/polyfill&lt;/a&gt; via &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#usebuiltins&quot;&gt;@babel/preset-env’s useBuiltIns: “usage”&lt;/a&gt; option.&lt;/li&gt;&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;This is solely my opinion, but I believe the best choice is to avoid transpilation altogether in bundles generated for modern browsers. That’s not always possible, especially if you use &lt;a href=&quot;https://reactjs.org/docs/introducing-jsx.html&quot;&gt;JSX&lt;/a&gt;, which must be transformed for &lt;em&gt;all&lt;/em&gt; browsers, or if you’re using bleeding edge language features that aren’t widely supported. In the latter case, it might be worth asking if those features are really necessary to deliver a good user experience (they rarely are). If you arrive at the conclusion that Babel must be a part of your toolchain, then it’s worth peeking under the hood from time to time to catch suboptimal stuff Babel might be doing that you can improve on.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Improvement is not a race&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;As you massage your temples wondering when this horrid JavaScript hangover is going to lift, understand that it’s precisely when we rush to get something out there as fast as we possibly can that the user experience can suffer. As the web development community obsesses on iterating faster in the name of competition, it’s worth your time to &lt;a href=&quot;https://en.wikipedia.org/wiki/Thinking,_Fast_and_Slow&quot;&gt;&lt;em&gt;slow down a little bit&lt;/em&gt;&lt;/a&gt;. You’ll find that by doing so, you may not be iterating as fast as your competitors, but &lt;em&gt;your product&lt;/em&gt; will be &lt;em&gt;faster&lt;/em&gt; than theirs.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;As you take these suggestions and apply them to your codebase, know that progress doesn’t spontaneously happen overnight. Web development is a job. The truly impactful work is done when we’re thoughtful and dedicated to the craft for the long haul. Focus on steady improvements. Measure, test, repeat, and your site’s user experience will improve, and you’ll get faster bit by bit over time.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;em&gt;Special thanks to &lt;/em&gt;&lt;a href=&quot;https://twitter.com/_developit&quot;&gt;&lt;em&gt;Jason Miller&lt;/em&gt;&lt;/a&gt;&lt;em&gt; for tech editing this piece. Jason is the creator and one of the many maintainers of &lt;/em&gt;&lt;a href=&quot;https://preactjs.com/&quot;&gt;&lt;em&gt;Preact&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, a vastly smaller alternative to React with the same API. If you use Preact, &lt;/em&gt;&lt;a href=&quot;https://opencollective.com/preact&quot;&gt;&lt;em&gt;please consider supporting Preact through Open Collective&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
</description><link>https://alistapart.com/article/responsible-javascript-part-2/</link><guid isPermaLink="false">https://alistapart.com/article/responsible-javascript-part-2/</guid><pubDate>Thu, 13 Jun 2019 13:30:28 GMT</pubDate><author>jeremy-wagner</author><category>Application Development</category><category>Browsers</category><category>JavaScript</category></item><item><title>Responsible JavaScript: Part I</title><description>&lt;p class=&quot;wp-block-paragraph&quot;&gt;By the numbers,&amp;nbsp;&lt;a href=&quot;https://httparchive.org/reports/state-of-javascript#bytesJs&quot;&gt;JavaScript is a performance liability&lt;/a&gt;. If the trend persists, the median page will be shipping at least 400 KB of it before too long, and that’s merely what’s&amp;nbsp;&lt;em&gt;transferred&lt;/em&gt;. Like other text-based resources, JavaScript is almost always served compressed—but that might be the only thing we’re getting consistently right in its delivery.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Unfortunately, while reducing resource transfer time is a big part of that whole performance thing, compression has no effect on how long browsers take to process a script once it arrives in its entirety. If a server sends 400 KB of compressed JavaScript, the actual amount browsers have to process after decompression is north of a megabyte. How well devices cope with these heavy workloads depends, well, on the&amp;nbsp;&lt;em&gt;device&lt;/em&gt;.&amp;nbsp;&lt;a href=&quot;https://medium.com/@addyosmani/the-cost-of-javascript-in-2018-7d8950fbb5d4&quot;&gt;Much has been written&lt;/a&gt;&amp;nbsp;about how adept various devices are at processing lots of JavaScript, but the truth is, the amount of time it takes to process even a trivial amount of it varies greatly between devices.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Take, for example, this&amp;nbsp;&lt;a href=&quot;https://devmode.jeremy.codes/&quot;&gt;throwaway project of mine&lt;/a&gt;, which serves around 23 KB of uncompressed JavaScript. On a mid-2017 MacBook Pro, Chrome chews through this comparably tiny payload in about 25 ms. On a&amp;nbsp;&lt;a href=&quot;https://www.gsmarena.com/nokia_2-8513.php&quot;&gt;Nokia 2 Android phone&lt;/a&gt;, however, that figure balloons to around 190 ms. That’s not an insignificant amount of time, but in either case, the page gets interactive reasonably fast.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Now for the big question: how do you think that little Nokia 2 does on an average page? It chokes. Even on a fast connection, browsing the web on it is an exercise in patience as JavaScript-laden web pages brick it for considerable stretches of time.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image&quot;&gt;&lt;img data-recalc-dims=&quot;1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;960&quot; height=&quot;88&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2019/04/fig-01-2x.png?resize=960%2C88&amp;amp;ssl=1&quot; alt=&quot;A performance timeline for a JavaScript-heavy website. Most of the timeline is JavaScript.&quot; class=&quot;wp-image-6000652&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;figcaption&gt;&lt;em&gt;Figure 1. A performance timeline overview of a Nokia 2 Android phone browsing on a page where excessive JavaScript monopolizes the main thread.&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;While devices and the networks they navigate the web on are largely improving, we’re eating those gains as trends suggest. We need to use JavaScript&amp;nbsp;&lt;em&gt;responsibly&lt;/em&gt;. That begins with understanding&amp;nbsp;&lt;em&gt;what&lt;/em&gt;&amp;nbsp;we’re building as well as&amp;nbsp;&lt;em&gt;how&lt;/em&gt;&amp;nbsp;we’re building it.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;section1&quot;&gt;The mindset of “sites” versus “apps”&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Nomenclature can be strange in that we sometimes loosely identify things with terms that are inaccurate, yet their meanings are implicitly understood by everyone. Sometimes we overload the term “bee” to also mean “wasp”, even though the differences between bees and wasps are substantial. Those differences can motivate you to deal with each one differently. For instance, we’ll want to destroy a wasp nest, but because bees are highly beneficial and vulnerable insects, we may opt to relocate them.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;We can be just as fast and loose in interchanging the terms “website” and “web app”. The differences between them are less clear than those between yellowjackets and honeybees, but conflating them can bring about painful outcomes. The pain comes in the affordances we allow ourselves when something is merely a “web&lt;em&gt;site&lt;/em&gt;” versus a fully-featured “web app.” If you’re making an informational website for a business, you’re less likely to lean on a powerful framework to manage changes in the DOM or implement client-side routing—at least, I&amp;nbsp;&lt;em&gt;hope&lt;/em&gt;. Using tools so ill-suited for the task would not only be a detriment to the people who use that site but arguably less productive.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;When we build a web&amp;nbsp;&lt;em&gt;app&lt;/em&gt;, though,&amp;nbsp;&lt;em&gt;look out&lt;/em&gt;. We’re installing packages which usher in hundreds—if not&amp;nbsp;&lt;em&gt;thousands&lt;/em&gt;—of dependencies,&amp;nbsp;&lt;a href=&quot;https://snyk.io/blog/malicious-code-found-in-npm-package-event-stream/&quot;&gt;some of which&lt;/a&gt;&amp;nbsp;we’re not sure are even safe. We’re also writing complicated configurations for module bundlers. In this frenzied, yet ubiquitous, sort of dev environment, it takes knowledge and vigilance to ensure what gets built is fast and accessible. If you doubt this, run&amp;nbsp;&lt;a href=&quot;https://docs.npmjs.com/cli/ls.html#prod--production&quot;&gt;&lt;code&gt;npm ls --prod&lt;/code&gt;&lt;/a&gt;&amp;nbsp;in your project’s root directory and&amp;nbsp;&lt;a href=&quot;https://gist.github.com/malchata/dae0a011033846e2cb44d315b0496f0d&quot;&gt;see if you recognize everything in that list&lt;/a&gt;. Even if you do, that doesn’t account for third party scripts—of which I’m sure your site has at least a few.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;What we tend to forget is that the environment websites and web apps occupy is one and the same. Both are subject to the&amp;nbsp;&lt;em&gt;same environmental pressures&lt;/em&gt;&amp;nbsp;that the large gradient of networks and devices impose. Those constraints don’t suddenly vanish when we decide to call what we build “apps”, nor do our users’ phones gain magical new powers when we do so.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;It’s our responsibility to evaluate who uses what we make, and accept that the conditions under which they access the internet can be different than what we’ve assumed. We need to know the purpose we’re trying to serve, and only&amp;nbsp;&lt;em&gt;then&lt;/em&gt;&amp;nbsp;can we build something that admirably serves that purpose—&lt;a href=&quot;https://css-tricks.com/simple-boring/&quot;&gt;even if it isn’t exciting to build&lt;/a&gt;.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;That means reassessing our reliance on JavaScript and how the use of it—particularly to the exclusion of HTML and CSS—can tempt us to adopt unsustainable patterns which harm performance and accessibility.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;section2&quot;&gt;Don’t let frameworks force you into unsustainable patterns&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;I’ve been witness to some strange discoveries in codebases when working with teams that depend on frameworks to help them be highly productive. One characteristic common among many of them is that poor accessibility and performance patterns often result. Take the React component below, for example:&lt;/p&gt;



&lt;pre class=&quot;wp-block-code language-javascript&quot;&gt;&lt;code&gt;import React, { Component } from &quot;react&quot;;
import { validateEmail } from &quot;helpers/validation&quot;;

class SignupForm extends Component {
  constructor (props) {
    super(props);

    this.handleSubmit = this.handleSubmit.bind(this);
    this.updateEmail = this.updateEmail.bind(this);
    this.state.email = &quot;&quot;;
  }

  updateEmail (event) {
    this.setState({
      email: event.target.value
    });
  }

  handleSubmit () {
    // If the email checks out, submit
    if (validateEmail(this.state.email)) {
      // ...
    }
  }

  render () {
    return (
      &lt;div&gt;
        &lt;span class=&quot;email-label&quot;&gt;Enter your email:&lt;/span&gt;
        
        &lt;button&gt;Sign Up&lt;/button&gt;
      &lt;/div&gt;
    );
  }
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;There are some notable accessibility issues here:&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;&lt;li&gt;A form that doesn’t use a&amp;nbsp;&lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;&amp;nbsp;element is&amp;nbsp;&lt;em&gt;not&lt;/em&gt;&amp;nbsp;a form. Indeed, you could paper over this by specifying&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Form_Role&quot;&gt;&lt;code&gt;role=&quot;form&quot;&lt;/code&gt;&lt;/a&gt;&amp;nbsp;in the parent&amp;nbsp;&lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, but if you’re building a form—and this&amp;nbsp;&lt;em&gt;sure looks like one&lt;/em&gt;—use a&amp;nbsp;&lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;&amp;nbsp;element with the proper&amp;nbsp;&lt;code&gt;action&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;method&lt;/code&gt;&amp;nbsp;attributes. The&amp;nbsp;&lt;code&gt;action&lt;/code&gt;&amp;nbsp;attribute is crucial, as it ensures the form will still do&amp;nbsp;&lt;em&gt;something&lt;/em&gt;&amp;nbsp;in the absence of JavaScript—provided the component is server-rendered, of course.&lt;/li&gt;&lt;li&gt;A&amp;nbsp;&lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;&amp;nbsp;is not a substitute for a&amp;nbsp;&lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;&amp;nbsp;element, which provides accessibility benefits&amp;nbsp;&lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;s don’t.&lt;/li&gt;&lt;li&gt;If we intend to do something on the client side prior to submitting a form, then we should move the action bound to the &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element’s &lt;code&gt;onClick&lt;/code&gt; handler to the &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;&amp;nbsp;element’s&amp;nbsp;&lt;code&gt;onSubmit&lt;/code&gt; handler.&lt;/li&gt;&lt;li&gt;Incidentally, why use JavaScript to validate an email address when HTML5 offers form validation controls in almost every browser back to IE 10? There’s an opportunity here to rely on the browser and use an&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/email&quot;&gt;appropriate input type&lt;/a&gt;, as well as the&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Form_validation#The_required_attribute&quot;&gt;&lt;code&gt;required&lt;/code&gt;&lt;/a&gt;&amp;nbsp;attribute—but be aware that getting this to work right with screen readers&amp;nbsp;&lt;a href=&quot;https://developer.paciellogroup.com/blog/2019/02/required-attribute-requirements/&quot;&gt;takes a little know-how&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;While not an accessibility issue, this component doesn’t rely on any state or lifecycle methods, which means it can be refactored into a stateless functional component, which uses considerably less JavaScript than a full-fledged React component.&lt;/li&gt;&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Knowing these things, we can refactor this component:&lt;/p&gt;



&lt;pre class=&quot;wp-block-code language-javascript&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;

const SignupForm = props =&amp;gt; {
  const handleSubmit = event =&amp;gt; {
    // Needed in case we&#39;re sending data to the server XHR-style
    // (but will still work if server-rendered with JS disabled).
    event.preventDefault();

    // Carry on...
  };
  
  return (
    &amp;lt;form method=&quot;POST&quot; action=&quot;/signup&quot; onSubmit={handleSubmit}&amp;gt;
      &amp;lt;label for=&quot;email&quot; class=&quot;email-label&quot;&amp;gt;Enter your email:&amp;lt;/label&amp;gt;
      &amp;lt;input type=&quot;email&quot; id=&quot;email&quot; required /&amp;gt;
      &amp;lt;button&amp;gt;Sign Up&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Not only is this component now more accessible, but it also uses less JavaScript. In a world that’s drowning in JavaScript, deleting lines of it should feel downright therapeutic.&amp;nbsp;&lt;a href=&quot;https://alistapart.com/article/paint-the-picture-not-the-frame&quot;&gt;The browser gives us so much for free&lt;/a&gt;, and we should try to take advantage of that as often as possible.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;This is not to say that inaccessible patterns occur&amp;nbsp;&lt;em&gt;only&lt;/em&gt;&amp;nbsp;when frameworks are used, but rather that a sole preference for JavaScript&amp;nbsp;&lt;em&gt;will&lt;/em&gt;&amp;nbsp;eventually surface gaps in our understanding of HTML and CSS. These knowledge gaps will often result in mistakes we may not even be aware of. Frameworks can be useful tools that increase our productivity, but continuing education in core web technologies is essential to creating&amp;nbsp;&lt;em&gt;usable&lt;/em&gt;&amp;nbsp;experiences, no matter what tools we choose to use.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;section3&quot;&gt;Rely on the web platform and you’ll go far, fast&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;While we’re on the subject of frameworks, it must be said that the web platform is a formidable framework of its own. As the previous section showed, we’re better off when we can rely on established markup patterns and browser features. The alternative is to reinvent them, and invite all the pain such endeavors all but guarantee us, or worse: merely&amp;nbsp;&lt;em&gt;assume&lt;/em&gt;&amp;nbsp;that the author of every JavaScript package we install has solved the problem comprehensively and thoughtfully.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot; id=&quot;section4&quot;&gt;SINGLE PAGE APPLICATIONS&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;One of the tradeoffs developers are quick to make is to adopt the single page application (SPA) model, even if it’s not a fit for the project. Yes, you&amp;nbsp;&lt;em&gt;do&lt;/em&gt;&amp;nbsp;gain better perceived performance with the client-side routing of an SPA, but what do you&amp;nbsp;&lt;em&gt;lose&lt;/em&gt;? The browser’s own navigation functionality—albeit synchronous—provides a slew of benefits. For one, history is managed according to&amp;nbsp;&lt;a href=&quot;https://html.spec.whatwg.org/#the-history-interface&quot;&gt;a complex specification&lt;/a&gt;. Users without JavaScript—be it by&amp;nbsp;&lt;a href=&quot;https://kryogenix.org/code/browser/everyonehasjs.html&quot;&gt;their own choice or not&lt;/a&gt;—won’t lose access altogether. For SPAs to remain available when JavaScript is not, server-side rendering suddenly becomes a thing you have to consider.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image&quot;&gt;&lt;img data-recalc-dims=&quot;1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;960&quot; height=&quot;324&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2019/04/fig2.png?resize=960%2C324&amp;amp;ssl=1&quot; alt=&quot;Two series of screenshots. On the left, we have a blank screen for several seconds until the app appears after 5.24s. On the right, the basic components appear at 4ms and the site is fully usable at 5.16s.&quot; class=&quot;wp-image-6000653&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;figcaption&gt;&lt;em&gt;Figure 2. A comparison of an example app loading on a slow connection. The app on the left depends entirely upon JavaScript to render a page. The app on the right renders a response on the server, but then uses&amp;nbsp;&lt;/em&gt;&lt;a href=&quot;https://reactjs.org/docs/react-dom.html#hydrate&quot;&gt;client-side hydration&lt;/a&gt;&lt;em&gt;&amp;nbsp;to attach components to the existing server-rendered markup.&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Accessibility is also harmed if a client-side router fails to let people know what content on the page has changed. This can leave those reliant on assistive technology to suss out what changes have occurred on the page, which can be an arduous task.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Then there’s our old nemesis: overhead. Some client-side routers are very small, but when you&amp;nbsp;&lt;em&gt;start&lt;/em&gt;&amp;nbsp;with&amp;nbsp;&lt;a href=&quot;https://bundlephobia.com/result?p=react-dom@16.8.2&quot;&gt;React&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://bundlephobia.com/result?p=react-router@4.3.1&quot;&gt;a compatible router&lt;/a&gt;, and possibly even&amp;nbsp;&lt;a href=&quot;https://bundlephobia.com/result?p=redux@4.0.1&quot;&gt;a state management library&lt;/a&gt;, you’re accepting that there’s a certain amount of code you can never optimize away—approximately 135 KB in this case. Carefully consider what you’re building and whether a client side router is worth the tradeoffs you’ll inevitably make. Typically, you’re better off without one.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;If you’re concerned about the perceived navigation performance, you&amp;nbsp;&lt;em&gt;could&lt;/em&gt;&amp;nbsp;lean on&amp;nbsp;&lt;a href=&quot;https://www.w3.org/TR/resource-hints/#prefetch-link-relation-type&quot;&gt;&lt;code&gt;rel=prefetch&lt;/code&gt;&lt;/a&gt;&amp;nbsp;to speculatively fetch documents on the same origin. This has a dramatic effect on improving perceived loading performance of pages, as the document is immediately available in the cache. Because prefetches are done at a low priority, they’re also less likely to contend with critical resources for bandwidth.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image&quot;&gt;&lt;img data-recalc-dims=&quot;1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;960&quot; height=&quot;438&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2019/04/fig3.png?resize=960%2C438&amp;amp;ssl=1&quot; alt=&quot;Screenshot showing a list of assets loaded on a webpage. &#39;writing/&#39; is labeled as prefetched on initial navigation. This asset is then loaded in 2ms when actually requested by the user.&quot; class=&quot;wp-image-7171594&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;figcaption&gt;Figure 3. The HTML for the writing/ URL is prefetched on the initial page. When the writing/ URL is requested by the user, the HTML for it is loaded instantaneously from the browser cache.&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;The primary drawback with link prefetching is that you need to be aware that it&amp;nbsp;&lt;em&gt;can&lt;/em&gt;&amp;nbsp;be potentially wasteful.&amp;nbsp;&lt;a href=&quot;https://github.com/GoogleChromeLabs/quicklink&quot;&gt;Quicklink&lt;/a&gt;, a tiny link prefetching script from Google, mitigates this somewhat by checking if the current client is on a slow connection—or has&amp;nbsp;&lt;a href=&quot;https://support.google.com/chrome/answer/2392284?co=GENIE.Platform%3DAndroid&amp;amp;hl=en&quot;&gt;data saver mode&lt;/a&gt;&amp;nbsp;enabled—and avoids prefetching links on cross-origins by default.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://adactio.com/articles/13796&quot;&gt;Service workers&lt;/a&gt;&amp;nbsp;are also hugely beneficial to perceived performance for returning users, whether we use client side routing or not—&lt;a href=&quot;https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#for_best_performance_bypass_the_network_for_navigations&quot;&gt;provided you know the ropes&lt;/a&gt;.&amp;nbsp;&lt;a href=&quot;https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker&quot;&gt;When we precache routes with a service worker&lt;/a&gt;, we get many of the same benefits as link prefetching, but with a much greater degree of control over requests and responses. Whether you think of your site as an “app” or not, adding a service worker to it is perhaps one of the most responsible uses of JavaScript that exists today.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot; id=&quot;section5&quot;&gt;JAVASCRIPT ISN’T THE SOLUTION TO YOUR LAYOUT WOES&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;If we’re installing a package to solve a layout problem, proceed with caution and ask “what am I trying to accomplish?” CSS is&amp;nbsp;&lt;a href=&quot;https://twitter.com/rachelandrew/status/1088870059240505344&quot;&gt;&lt;em&gt;designed to do this job&lt;/em&gt;&lt;/a&gt;, and requires no abstractions to use effectively. Most layout issues JavaScript packages attempt to solve, like&amp;nbsp;&lt;a href=&quot;https://www.npmjs.com/package/flexibility&quot;&gt;box placement, alignment, and sizing&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://www.npmjs.com/package/shave&quot;&gt;managing text overflow&lt;/a&gt;, and even&amp;nbsp;&lt;a href=&quot;https://www.npmjs.com/package/lost&quot;&gt;entire layout systems&lt;/a&gt;, are solvable with CSS&amp;nbsp;&lt;em&gt;today&lt;/em&gt;. Modern layout engines like Flexbox and Grid are supported well enough that we shouldn’t need to start a project with any layout framework. CSS&amp;nbsp;&lt;em&gt;is&lt;/em&gt;&amp;nbsp;the framework. When we have&amp;nbsp;&lt;a href=&quot;https://hacks.mozilla.org/2016/08/using-feature-queries-in-css/&quot;&gt;feature queries&lt;/a&gt;, progressively enhancing layouts to adopt new layout engines is suddenly&amp;nbsp;&lt;a href=&quot;https://hacks.mozilla.org/2016/08/using-feature-queries-in-css/&quot;&gt;not so hard&lt;/a&gt;.&lt;/p&gt;



&lt;pre class=&quot;wp-block-code language-css&quot;&gt;&lt;code&gt;/* Your mobile-first, non-CSS grid styles goes here */

/* The @supports rule below is ignored by browsers that don&#39;t
   support CSS grid, _or_ don&#39;t support @supports. */
@supports (display: grid) {
  /* Larger screen layout */
  @media (min-width: 40em) {
    /* Your progressively enhanced grid layout styles go here */
  }
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Using JavaScript solutions for layout and presentations problems is not new. It was something we did when we lied to ourselves in 2009 that every website had to look in IE6 exactly as it did in the more capable browsers of that time. If we’re still developing websites to look the same in every browser in 2019, we should reassess our development goals. There will&amp;nbsp;&lt;em&gt;always&lt;/em&gt;&amp;nbsp;be some browser we’ll have to support that can’t do everything those modern, evergreen browsers can. Total visual parity on all platforms is not only a pursuit made in vain, it’s the principal foe of&amp;nbsp;&lt;a href=&quot;https://alistapart.com/article/understandingprogressiveenhancement&quot;&gt;progressive enhancement&lt;/a&gt;.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;section6&quot;&gt;I’m not here to kill JavaScript&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Make no mistake, I have no ill will toward JavaScript. It’s given me a career and—if I’m being honest with myself—a source of enjoyment for over a decade. Like any long-term relationship, I learn more about it the more time I spend with it. It’s a mature, feature-rich language that only gets more capable and elegant with every passing year.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Yet, there are times when I feel like JavaScript and I are at odds. I&amp;nbsp;&lt;em&gt;am&lt;/em&gt;&amp;nbsp;critical of JavaScript. Or maybe more accurately, I’m critical of how we’ve developed a tendency to view it as a first resort to building for the web. As I pick apart yet another bundle not unlike a tangled ball of Christmas tree lights, it’s become clear that the web is&amp;nbsp;&lt;em&gt;drunk&lt;/em&gt;&amp;nbsp;on JavaScript. We reach for it for almost everything, even when the occasion doesn’t call for it. Sometimes I wonder how vicious the hangover will be.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;In a series of articles to follow, I’ll be giving more practical advice to follow to stem the encroaching tide of excessive JavaScript and how we can wrangle it so that&amp;nbsp;&lt;em&gt;what&lt;/em&gt;&amp;nbsp;we build for the web is usable—or at least&amp;nbsp;&lt;em&gt;more&lt;/em&gt;&amp;nbsp;so—for everyone everywhere. Some of the advice will be preventative. Some will be mitigating “hair of the dog” measures. In either case, the outcomes will hopefully be the same. I believe that we all love the web and want to do right by it, but I want us to think about how to make it more resilient and inclusive for all.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;br&gt;&lt;/p&gt;
</description><link>https://alistapart.com/article/responsible-javascript-part-1/</link><guid isPermaLink="false">https://alistapart.com/article/responsible-javascript-part-1/</guid><pubDate>Thu, 28 Mar 2019 09:07:40 GMT</pubDate><author>jeremy-wagner</author><category>Application Development</category><category>JavaScript</category></item><item><title>Coding with Clarity: Part II</title><description>&lt;p&gt;As any developer who works with other developers can attest, if code is unclear, problems occur. In &lt;a href=&quot;https://alistapart.com/article/coding-with-clarity&quot;&gt;Part I&lt;/a&gt; of this series, I went over some principles to improve clarity in our code to prevent problems that can arise from unclear code. As our apps get larger, clarity becomes even more important, and we need to take extra care to ensure that our code is easy to read, understand, and modify or extend. This article discusses some more-advanced principles related to object-oriented programming (OOP) to improve clarity in larger apps.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Note: Though the principles in this article are applicable to a variety of programming languages, the examples pull from object-oriented JavaScript. If you’re not familiar with this, read &lt;a href=&quot;https://alistapart.com/article/coding-with-clarity&quot;&gt;my first article&lt;/a&gt; to get up to speed, as well as to find some other resources to help improve your understanding of object-oriented programming.&lt;/i&gt;&lt;/p&gt;
&lt;h2&gt;The Law of Demeter&lt;/h2&gt;
&lt;p&gt;Imagine you’re an office manager at an apartment complex. The end of the month comes and the rent is due. You go through the drop box in the office and find checks from most of your tenants. But among the neatly-folded checks is a messy note on a scrap of paper that instructs you to unlock apartment 309, open the top drawer of the dresser on the left side of the bed, and remove the money from the tenant’s wallet. Oh, and don’t let the cat out! If you’re thinking that’s ridiculous, yeah, you’re right. To get the rent money each month, you shouldn’t be required to know how a tenant lays out their apartment and where they store their wallet. It’s just as ridiculous when we write our code this  way.&lt;/p&gt;
&lt;p&gt;The &lt;i&gt;Law of Demeter&lt;/i&gt;, or &lt;i&gt;principle of least knowledge&lt;/i&gt;, states that a unit of code should require only limited knowledge of other code units and should only talk to close friends. In other words, your class should not have to reach several levels deep into another class to accomplish what it needs to. Instead, classes should provide abstractions to make any of its internal data available to the rest of the application.&lt;/p&gt;
&lt;p&gt;(&lt;i&gt;Note: the Law of Demeter is a specific application of &lt;a href=&quot;https://alistapart.com/article/coding-with-clarity#section3&quot;&gt;loose coupling&lt;/a&gt;, which I talk about in my first article.&lt;/i&gt;)&lt;/p&gt;
&lt;p&gt;As an example, let’s say we have a class for a department in your office. It includes various bits of information, including a manager. Now, let’s say we have another bit of code that wants to email one of these managers. Without the Law of Demeter, here’s how that function might look:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function emailManager(department) {
  const managerFirstName = department.manager.firstName;
  const managerLastName = department.manager.lastName;
  const managerFullName = `${managerFirstName} ${managerLastName}`;
  const managerEmail = department.manager.email;
  sendEmail(managerFullName, managerEmail);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Very tedious! And on top of that, if anything changes with the implementation of the manager in the &lt;code&gt;Department&lt;/code&gt; class, there’s a good chance this will break. What we need is a level of abstraction to make this function’s job easier.&lt;/p&gt;
&lt;p&gt;We can add this method to our &lt;code&gt;Department&lt;/code&gt; class:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;getManagerEmailObj: function() {
  return {
    firstName: this.manager.firstName,
    lastName: this.manager.lastName,
    fullName: `${this.manager.firstName} ${this.manager.lastName}`,
    email: this.manager.email
  };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, the first function can be rewritten as this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function emailManager(department) {
  let emailObj = department.getManagerEmailObj();
  sendEmail(emailObj.fullName, emailObj.email);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This not only makes the function much cleaner and easier to understand, but it makes it easier to update the &lt;code&gt;Department&lt;/code&gt; class if needed (although that can also be dangerous, as we’ll discuss later). You won’t have to look for every place that tries to access its internal information, you just update the internal method. &lt;/p&gt;
&lt;p&gt;Setting up our classes to enforce this can be tricky. It helps to draw a distinction between traditional OOP objects and data structures. Data structures should expose &lt;i&gt;data&lt;/i&gt; and contain no behavior. OOP objects should expose &lt;i&gt;behavior&lt;/i&gt; and limit access to data. In languages like C, these are separate entities, and you have to explicitly choose one of these types. In JavaScript, the lines are blurred a bit because the object type is used for both.&lt;/p&gt;
&lt;p&gt;Here’s a data structure in JavaScript:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let Manager = {
  firstName: &#39;Brandon&#39;,
  lastName: &#39;Gregory&#39;,
  email: &#39;brandon@myurl.com&#39;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note how the data is easily accessible. That’s the whole point. However, if we want to expose behavior, per best practice, we’d want to hide the data using internal variables on a class:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;class Manager {
  constructor(options) {
    let firstName = options.firstName;
    let lastName = options.lastName;
    this.setFullName = function(newFirstName, newLastName) {
      firstName = newFirstName;
      lastName = newLastName;
    };
    this.getFullName = function() {
      return `${firstName} ${lastName}`;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if you’re thinking that’s unnecessary, you’re correct in this case—there’s not much point to having getters and setters in a simple object like this one. Where getters and setters become important is when internal logic is involved:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;class Department {
  constructor(options) {
    // Some other properties
    let Manager = options.Manager;
    this.changeManager(NewManager) {
      if (checkIfManagerExists(NewManager)) {
        Manager = NewManager;
        // AJAX call to update Manager in database
      }
    };
    this.getManager {
      if (checkIfUserHasClearance()) {
        return Manager;
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is still a small example, but you can see how the getter and setter here are doing more than just obfuscating the data. We can attach logic and validation to these methods that consumers of a &lt;code&gt;Department&lt;/code&gt; object shouldn’t have to worry about. And if the logic changes, we can change it on the getter and setter without finding and changing every bit of code that tries to get and set those properties. Even if there’s no internal logic when you’re building your app, there’s no guarantee that you won’t need it later. You don’t have to know what you’ll need in the future, you just have to leave space so you can add it later. Limiting access to data in an object that exposes behavior gives you a buffer to do this in case the need arises later.&lt;/p&gt;
&lt;p&gt;As a general rule, if your object exposes behavior, it’s an OOP object, and it should not allow direct access to the data; instead, it should provide methods to access it safely, as in the above example. However, if the point of the object is to expose data, it’s a data structure, and it should not also contain behavior. Mixing these types muddies the water in your code and can lead to some unexpected (and sometimes dangerous) uses of your object’s data, as other functions and methods may not be aware of all of the internal logic needed for interacting with that data.&lt;/p&gt;
&lt;h2&gt;The interface segregation principle&lt;/h2&gt;
&lt;p&gt;Imagine you get a new job designing cars for a major manufacturer. Your first task: design a sports car. You immediately sit down and start sketching a car that’s designed to go fast and handle well. The next day, you get a report from management, asking you to turn your sports car into a sporty minivan. Alright, that’s weird, but it’s doable. You sketch out a sporty minivan. The next day, you get another report. Your car now has to function as a boat as well as a car. Ridiculous? Well, yes. There’s no way to design one vehicle that meets the needs of all consumers. Similarly, depending on your app, it can be a bad idea to code one function or method that’s flexible enough to handle everything your app could throw at it.&lt;/p&gt;
&lt;p&gt;The &lt;i&gt;interface segregation principle&lt;/i&gt; states that no client should be forced to depend on methods it does not use. In simpler terms, if your class has a plethora of methods and only a few of them are used by each user of the object, it makes more sense to break up your object into several more focused objects or interfaces. Similarly, if your function or method contains several branches to behave differently based on what data it receives, that’s a good sign that you need different functions or methods rather than one giant one.&lt;/p&gt;
&lt;p&gt;One big warning sign for this is flags that get passed into functions or methods. Flags are Boolean variables that significantly change the behavior of the function if true. Take a look at the following function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function addPerson(person, isManager) {
  if (isManager) {
    // add manager
  } else {
    // add employee
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, the function is split up into two different exclusive branches—there’s no way both branches are going to be used, so it makes more sense to break this up into separate functions, since we know if the person is a manager when we call it.&lt;/p&gt;
&lt;p&gt;That’s a simplified example. An example closer to the actual definition of the interface segregation principle would be if a module contained numerous methods for dealing with employees and separate methods for dealing with managers. In this case, it makes much more sense to split the manager methods off into a separate module, even if the manager module is a child class of the employee module and shares some of the properties and methods.&lt;/p&gt;
&lt;p&gt;Please note: flags are not automatically evil. A flag can be fine if you’re using it to trigger a small optional step while most of the functionality remains the same for both cases. What we want to avoid is using flags to create “clever” code that makes it harder to use, edit, and understand. Complexity can be fine as long as you’re gaining something from it. But if you’re adding complexity and there’s no significant payoff, think about why you’re coding it that way.&lt;/p&gt;
&lt;p&gt;Unnecessary dependencies can also happen when developers try to implement features they think they might need in the future. There are a few problems with this. One, there’s a considerable cost to pay now in both development time and testing time for features that won’t be used now—or possibly at all. Two, it’s unlikely that the team will know enough about future requirements to adequately prepare for the future. Things will change, and you probably won’t know &lt;em&gt;how&lt;/em&gt; things will change until phase one goes out into production. You should write your functions and methods to be open to extend later, but be careful trying to guess what the future holds for your codebase.&lt;/p&gt;
&lt;p&gt;Adhering to the interface segregation principle is definitely a balancing act, as it’s possible to go too far with abstractions and have a ridiculous number of objects and methods. This, ironically, causes the same problem: added complexity without a payoff. There’s no hard rule to keep this in check—it’s going to depend on your app, your data, and your team. But there’s no shame in keeping things simple if making them complex does not help you. In fact, that’s usually the best route to go.&lt;/p&gt;
&lt;h2&gt;The open/closed principle&lt;/h2&gt;
&lt;p&gt;Many younger developers don’t remember the days before web standards changed development. (Thanks, Jeffrey Zeldman, for making our lives easier!) It used to be that whenever a new browser was released, it had its own interpretation of things, and developers had to scramble to find out what was different and how it broke all of their websites. There were articles and blog posts written quickly about new browser quirks and how to fix them, and developers had to drop everything to implement those fixes before clients noticed that their websites were broken. For many of the brave veterans of the first browser war, this wasn’t just a nightmare scenario—it was part of our job. As bad as that sounds, it’s easy for our code to do the same thing if we’re not careful about how we modify it.&lt;/p&gt;
&lt;p&gt;The &lt;i&gt;open/closed principle&lt;/i&gt; states that software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. In other words, your code should be written in such a way that it’s easy to add new functionality while you disallow  changing existing functionality. Changing existing functionality is a great way to break your app, often without realizing it. Just like browsers rely on web standards to keep new releases from breaking our sites, your code needs to rely on its own internal standards for consistency to keep your code from breaking in unexpected ways.&lt;/p&gt;
&lt;p&gt;Let’s say your codebase has this function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function getFullName(person) {
  return `${person.firstName} ${person.lastName}`;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A pretty simple function. But then, there’s a new use case where you need just the last name. &lt;em&gt;Under no circumstances&lt;/em&gt; should you modify the above function like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function getFullName(person) {
  return {
    firstName: person.firstName,
    lastName: person.lastName
  };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That solves your new problem, but it modifies existing functionality and will break every bit of code that was using the old version. Instead, you should extend functionality by creating a new function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function getLastName(person) {
  return person.lastName;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, if we want to make it more flexible:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function getNameObject(person) {
  return {
    firstName: person.firstName,
    lastName: person.lastName
  };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a simple example, but it’s easy to see how modifying existing functionality can cause major problems. Even if you’re able to locate every call to your function or method, they all have to be tested—the open/closed principle helps to reduce testing time as well as unexpected errors.&lt;/p&gt;
&lt;p&gt;So what does this look like on a larger scale? Let’s say we have a function to grab some data via an &lt;code&gt;XMLHTTPrequest&lt;/code&gt; and do something with it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function request(endpoint, params) {
  const xhr = new XMLHttpRequest();
  xhr.open(&#39;GET&#39;, endpoint, true);
  xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 &amp;amp;&amp;amp; xhr.status == 200) {     
      // Do something with the data
    }
  };
  xhr.send(params);
}

request(&#39;https://myapi.com&#39;,&#39;id=91&#39;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s great if you’re always going to be doing the same thing with that data. But how many times does that happen? If we do &lt;em&gt;anything else&lt;/em&gt; with that data, coding the function that way means we’ll need another function to do almost the same thing.&lt;/p&gt;
&lt;p&gt;What would work better would be to code our request function to accept a callback function as an argument:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function request(endpoint, params, callback) {
  const xhr = new XMLHttpRequest();
  xhr.open(&#39;GET&#39;, endpoint, true);
  xhr.onreadystatechange = function() {
    if(xhr.readyState == 4 &amp;amp;&amp;amp; xhr.status == 200) {     
      callback(xhr.responseText);
    }
  };
  xhr.send(params);
}

const defaultAction = function(responseText) {
  // Do something with the data
};

const alternateAction = function(responseText) {
  // Do something different with the data
};

request(&#39;https://myapi.com&#39;,&#39;id=91&#39;,defaultAction);
request(&#39;https://myapi.com&#39;,&#39;id=42&#39;,alternateAction);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the function coded this way, it’s much more flexible and useful to us, because it’s easy to add in new functionality without modifying existing functionality. Passing a function as a parameter is one of the most useful tools we have in keeping our code extensible, so keep this one in mind when you’re coding as a way to future-proof your code.&lt;/p&gt;
&lt;h2&gt;Keeping it clear&lt;/h2&gt;
&lt;p&gt;Clever code that increases complexity without improving clarity helps nobody. The bigger our apps get, the more clarity matters, and the more we have to plan to make sure our code is clear. Following these guidelines helps improve clarity and reduce overall complexity, leading to fewer bugs, shorter timelines, and happier developers. They should be a consideration for any complex app.&lt;/p&gt;
&lt;h2&gt;Thanks&lt;/h2&gt;
&lt;p&gt;A special thanks to Zell Liew of &lt;a href=&quot;https://learnjavascript.today/&quot;&gt;Learn JavaScript&lt;/a&gt; for lending his technical oversight to this article. Learn JavaScript is a great resource for moving your JavaScript expertise from beginner to advanced, so it’s worth checking out to further your knowledge!&lt;/p&gt;
</description><link>https://alistapart.com/article/coding-with-clarity-part-ii/</link><guid isPermaLink="false">https://alistapart.com/article/coding-with-clarity-part-ii/</guid><pubDate>Thu, 23 Aug 2018 13:05:00 GMT</pubDate><author>brandongregory</author><category>Application Development</category><category>Code</category><category>JavaScript</category></item><item><title>Designing for Research</title><description>&lt;p&gt;If you’ve spent enough time developing for the web, this piece of feedback has landed in your inbox since time immemorial:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“This photo looks blurry. Can we replace it with a better version?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Every time this feedback reaches me, I’m inclined to question it: “What about the photo looks bad to you, and can you tell me &lt;em&gt;why?&lt;/em&gt;”&lt;/p&gt;
&lt;p&gt;That’s a somewhat unfair question to counter with. The complaint is rooted in a subjective perception of image quality, which in turn is influenced by many factors. Some are technical, such as the export quality of the image or the compression method (often lossy, as is the case with JPEG-encoded photos). Others are more intuitive or perceptual, such as content of the image and how compression artifacts mingle within. Perhaps even performance plays a role we’re not entirely aware of.&lt;/p&gt;
&lt;p&gt;Fielding this kind of feedback for many years eventually lead me to design and develop &lt;a href=&quot;https://imagesurvey.site/&quot; rel=&quot;noopener&quot;&gt;an image quality survey&lt;/a&gt;, which was my first go at building a research project on the web. I started with twenty-five photos shot by a professional photographer. With them, I generated a large pool of images at various quality levels and sizes. Images were served randomly from this pool to users who were asked to rate what they thought about their quality.&lt;/p&gt;
&lt;p&gt;Results from the first round were interesting, but not entirely clear: users seemed to have a tendency to overestimate the actual quality of images, and poor performance &lt;em&gt;appeared&lt;/em&gt; to have a negative impact on perceptions of image quality, but this couldn’t be stated conclusively. A number of UX and technical issues made it necessary to implement important improvements and conduct a second round of research. In lieu of spinning my wheels trying to extract conclusions from the first round results, I decided it would be best to improve the survey as much as possible, and conduct another round of research to get better data. This article chronicles how I first built the survey, and then how I subsequently listened to user feedback to improve it.&lt;/p&gt;
&lt;h2&gt;Defining the research&lt;/h2&gt;
&lt;p&gt;Of the subjects within web performance, image optimization is especially vast. There’s a wide array of formats, encodings, and optimization tools, all of which are designed to make images small enough for web use while maintaining reasonable visual quality. Striking the balance between speed and quality is really what image optimization is all about.&lt;/p&gt;
&lt;p&gt;This balance between performance and visual quality prompted me to consider how people &lt;em&gt;perceive&lt;/em&gt; image quality. &lt;a href=&quot;https://en.wikipedia.org/wiki/Lossy_compression&quot; rel=&quot;noopener&quot;&gt;Lossy image quality&lt;/a&gt;, in particular. Eventually, this train of thought lead to a series of questions spurring the design and development of an image quality perception survey. The idea of the survey is that users are providing &lt;em&gt;subjective&lt;/em&gt; assessments on quality. This is done by asking participants to rate images without an objective reference for what’s “perfect.” This is, after all, how people view images &lt;em&gt;in situ&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;A word on surveys&lt;/h3&gt;
&lt;p&gt;Any time we want to quantify user behavior, it’s inevitable that a survey is at least considered, if not ultimately chosen to gather data from a group of people. After all, surveys are perfect when your goal is to get something measurable. However, the survey is a seductively dangerous tool, &lt;a href=&quot;https://medium.com/research-things/on-surveys-5a73dda5e9a0&quot; rel=&quot;noopener&quot;&gt;as Erika Hall cautions&lt;/a&gt;. They’re easy to make and conduct, and are routinely abused in their dissemination. They’re not great tools for assessing past behavior. They’re just as bad (if not worse) at predicting future behavior. For example, the 1–10 scale often employed by customer satisfaction surveys don’t really say much of anything about how satisfied customers actually are or how likely they’ll be to buy a product in the future.&lt;/p&gt;
&lt;p&gt;The unfortunate reality, however, is that in lieu of my lording over hundreds of participants in person, the survey is the only truly practical tool I have to measure how people perceive image quality as well as if (and potentially how) performance metrics correlate to those perceptions. When I designed the survey, I kept with the following guidelines:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Don’t ask participants about anything other than what their perceptions are in the moment. By the time a participant has moved on, their recollection of what they just did rapidly diminishes as time elapses.&lt;/li&gt;
&lt;li&gt;Don’t assume participants know everything you do. Guide them with relevant copy that succinctly describes what you expect of them.&lt;/li&gt;
&lt;li&gt;Don’t ask participants to provide assessments with coarse inputs. Use an input type that permits them to finely assess image quality on a scale congruent with the lossy image quality encoding range.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All we can do going forward is acknowledge we’re interpreting the data we gather under the assumption that participants are being truthful and understand the task given to them. Even if the perception metrics are discarded from the data, there are still some objective performance metrics gathered that could tell a compelling story. From here, it’s a matter of defining the questions that will drive the research.&lt;/p&gt;
&lt;h3&gt;Asking the right questions&lt;/h3&gt;
&lt;p&gt;In research, you’re seeking answers to questions. In the case of this particular effort, I wanted answers to these questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How accurate are people’s perceptions of lossy image quality in relation to &lt;em&gt;actual&lt;/em&gt; quality?&lt;/li&gt;
&lt;li&gt;Do people perceive the quality of JPEG images differently than &lt;a href=&quot;https://en.wikipedia.org/wiki/WebP&quot; rel=&quot;noopener&quot;&gt;WebP images&lt;/a&gt;?&lt;/li&gt;
&lt;li&gt;Does performance play a role in all of this?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are important questions. To me, however, answering the last question was the primary goal. But the road to answers was (and continues to be) a complex journey of design and development choices. Let’s start out by covering some of the tech used to gather information from survey participants.&lt;/p&gt;
&lt;h3&gt;Sniffing out device and browser characteristics&lt;/h3&gt;
&lt;p&gt;When measuring how people perceive image quality, devices must be considered. After all, any given device’s screen will be more or less capable than others. Thankfully, HTML features such as &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-srcset&quot; rel=&quot;noopener&quot;&gt;srcset&lt;/a&gt;&lt;/code&gt; and &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture&quot; rel=&quot;noopener&quot;&gt;picture&lt;/a&gt;&lt;/code&gt; are highly appropriate for delivering the best image for any given screen. This is vital because one’s perception of image quality can be adversely affected if an image is ill-fit for a device’s screen. Conversely, performance can be negatively impacted if an exceedingly high-quality (and therefore behemoth) image is sent to a device with a small screen. When sniffing out potential relationships between performance and perceived quality, these are factors that deserve consideration.&lt;/p&gt;
&lt;p&gt;With regard to browser characteristics and conditions, JavaScript gives us plenty of tools for identifying important aspects of a user’s device. For instance, the &lt;code&gt;currentSrc&lt;/code&gt; property reveals which image is being shown from an array of responsive images. In the absence of &lt;code&gt;currentSrc&lt;/code&gt;, I can somewhat safely assume support for &lt;code&gt;srcset&lt;/code&gt; or &lt;code&gt;picture&lt;/code&gt; is lacking, and fall back to the &lt;code&gt;img&lt;/code&gt; tag’s &lt;code&gt;src&lt;/code&gt; value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const surveyImage = document.querySelector(&quot;.survey-image&quot;);
let loadedImage = surveyImage.currentSrc || surveyImage.src;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where screen capability is concerned, &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio&quot; rel=&quot;noopener&quot;&gt;devicePixelRatio&lt;/a&gt;&lt;/code&gt; tells us the &lt;a href=&quot;https://en.wikipedia.org/wiki/Pixel_density&quot; rel=&quot;noopener&quot;&gt;pixel density&lt;/a&gt; of a given device’s screen. In the absence of &lt;code&gt;devicePixelRatio&lt;/code&gt;, you may safely assume a fallback value of &lt;code&gt;1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;let dpr = window.devicePixelRatio || 1;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://caniuse.com/#feat=devicepixelratio&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;devicePixelRatio&lt;/code&gt; enjoys excellent browser support&lt;/a&gt;. Those few browsers that don’t support it (i.e., IE 10 and under) are highly unlikely to be used on high density displays.&lt;/p&gt;
&lt;p&gt;The stalwart &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;getBoundingClientRect&lt;/code&gt; method&lt;/a&gt; retrieves the rendered width of an &lt;code&gt;img&lt;/code&gt; element, while the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;HTMLImageElement&lt;/code&gt;&lt;/a&gt; interface’s &lt;code&gt;complete&lt;/code&gt; property determines whether an image has finished loaded. The latter of these two is important, because it may be preferable to discard individual results in situations where images haven’t loaded.&lt;/p&gt;
&lt;p&gt;In cases where JavaScript isn’t available, we can’t collect &lt;em&gt;any&lt;/em&gt; of this data. When we collect ratings from users who have JavaScript turned off (or are otherwise unable to run JavaScript), I have to accept there will be gaps in the data. The basic information we’re still able to collect does provide some value.&lt;/p&gt;
&lt;h3&gt;Sniffing for WebP support&lt;/h3&gt;
&lt;p&gt;As you’ll recall, one of the initial questions asked was how users perceived the quality of WebP images. The HTTP &lt;code&gt;Accept&lt;/code&gt; request header advertises WebP support in browsers like Chrome. In such cases, the &lt;code&gt;Accept&lt;/code&gt; header might look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;Accept: image/webp,image/apng,image/*,*/*;q=0.8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the WebP content type of &lt;code&gt;image/webp&lt;/code&gt; is one of the advertised content types in the header content. In server-side code, you can check &lt;code&gt;Accept&lt;/code&gt; for the &lt;code&gt;image/webp&lt;/code&gt; substring. Here’s how that might look in &lt;a href=&quot;https://expressjs.com/&quot; rel=&quot;noopener&quot;&gt;Express&lt;/a&gt; back-end code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const WebP = req.get(&quot;Accept&quot;).indexOf(&quot;image/webp&quot;) !== -1 ? true : false;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, I’m recording the browser’s WebP support status to a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const&quot; rel=&quot;noopener&quot;&gt;JavaScript constant&lt;/a&gt; I can use later to modify image delivery. I &lt;em&gt;could&lt;/em&gt; use the &lt;code&gt;picture&lt;/code&gt; element with multiple &lt;code&gt;source&lt;/code&gt;s and let the browser figure out which one to use based on the &lt;code&gt;source&lt;/code&gt; element’s &lt;code&gt;type&lt;/code&gt; attribute value, but this approach has clear advantages. First, it’s less markup. Second, the survey shouldn’t &lt;em&gt;always&lt;/em&gt; choose a WebP source simply because the browser is capable of using it. For any given survey specimen, the app should randomly decide between a WebP or JPEG image. Not &lt;code&gt;all&lt;/code&gt; participants using Chrome should rate &lt;code&gt;only&lt;/code&gt; WebP images, but rather a random smattering of both formats.&lt;/p&gt;
&lt;h3&gt;Recording performance API data&lt;/h3&gt;
&lt;p&gt;You’ll recall that one of the earlier questions I set out to answer was if performance impacts the perception of image quality. At this stage of the web platform’s development, there are several APIs that aid in the search for an answer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://w3c.github.io/navigation-timing/&quot; rel=&quot;noopener&quot;&gt;Navigation Timing API (Level 2)&lt;/a&gt;: This API tracks performance metrics for page loads. More than that, it gives insight into specific page loading phases, such as redirect, request and response time, DOM processing, and more.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://w3c.github.io/navigation-timing/#obsolete&quot; rel=&quot;noopener&quot;&gt;Navigation Timing API (Level 1)&lt;/a&gt;: Similar to Level 2 but with key differences. The timings exposed by Level 1 of the API lack the accuracy as those in Level 2. Furthermore, Level 1 metrics are expressed in &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_time&quot; rel=&quot;noopener&quot;&gt;Unix time&lt;/a&gt;. In the survey, data is only collected from Level 1 of the API if Level 2 is unsupported. It’s far from ideal (and also technically obsolete), but it does help fill in small gaps.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://w3c.github.io/resource-timing/&quot; rel=&quot;noopener&quot;&gt;Resource Timing API&lt;/a&gt;: Similar to Navigation Timing, but Resource Timing gathers metrics on various loading phases of page resources rather than the page itself. Of the all the APIs used in the survey, Resource Timing is used most, as it helps gather metrics on the loading of the image specimen the user rates.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://w3c.github.io/server-timing/&quot; rel=&quot;noopener&quot;&gt;Server Timing&lt;/a&gt;: In select browsers, this API is brought into the Navigation Timing Level 2 interface when a page request replies with a &lt;code&gt;Server-Timing&lt;/code&gt; response header. This header is open-ended and can be populated with timings related to back-end processing phases. This was added to round two of the survey to quantify back-end processing time in general.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://w3c.github.io/paint-timing/&quot; rel=&quot;noopener&quot;&gt;Paint Timing API&lt;/a&gt;: Currently only in Chrome, this API reports two paint metrics: &lt;a href=&quot;https://developers.google.com/web/updates/2017/06/user-centric-performance-metrics#first_paint_and_first_contentful_paint&quot; rel=&quot;noopener&quot;&gt;&lt;em&gt;first paint&lt;/em&gt; and &lt;em&gt;first contentful paint&lt;/em&gt;&lt;/a&gt;. Because a significant slice of users on the web use Chrome, we &lt;em&gt;may&lt;/em&gt; be able to observe relationships between perceived image quality and paint metrics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using these APIs, we can record performance metrics for most participants. Here’s a simplified example of how the survey uses the Resource Timing API to gather performance metrics for the loaded image specimen:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Get information about the loaded image
const surveyImageElement = document.querySelector(&quot;.survey-image&quot;);
const fullImageUrl = surveyImageElement.currentSrc || surveyImageElement.src;
const imageUrlParts = fullImageUrl.split(&quot;/&quot;);
const imageFilename = imageUrlParts[imageUrlParts.length - 1];

// Check for performance API methods
if (&quot;performance&quot; in window &amp;amp;&amp;amp; &quot;getEntriesByType&quot; in performance) {
  // Get entries from the Resource Timing API
  let resources = performance.getEntriesByType(&quot;resource&quot;);

  // Ensure resources were returned
  if (typeof resources === &quot;object&quot; &amp;amp;&amp;amp; resources.length &amp;gt; 0) {
    resources.forEach((resource) =&amp;gt; {
      // Check if the resource is for the loaded image
      if (resource.name.indexOf(imageFilename) !== -1) {
        // Access resource images for the image here
      }
    });
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the Resource Timing API is available, and the &lt;code&gt;getEntriesByType&lt;/code&gt; method returns results, an object with timings is returned, looking something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;{
  connectEnd: 1156.5999999947962,
  connectStart: 1156.5999999947962,
  decodedBodySize: 11110,
  domainLookupEnd: 1156.5999999947962,
  domainLookupStart: 1156.5999999947962,
  duration: 638.1000000037602,
  encodedBodySize: 11110,
  entryType: &quot;resource&quot;,
  fetchStart: 1156.5999999947962,
  initiatorType: &quot;img&quot;,
  name: &quot;https://imagesurvey.site/img-round-2/1-1024w-c2700e1f2c4f5e48f2f57d665b1323ae20806f62f39c1448490a76b1a662ce4a.webp&quot;,
  nextHopProtocol: &quot;h2&quot;,
  redirectEnd: 0,
  redirectStart: 0,
  requestStart: 1171.6000000014901,
  responseEnd: 1794.6999999985565,
  responseStart: 1737.0999999984633,
  secureConnectionStart: 0,
  startTime: 1156.5999999947962,
  transferSize: 11227,
  workerStart: 0
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I grab these metrics as participants rate images, and store them in a database. Down the road when I want to write queries and analyze the data I have, I can refer to the &lt;a href=&quot;https://w3c.github.io/navigation-timing/#processing-model&quot; rel=&quot;noopener&quot;&gt;Processing Model for the Resource and Navigation Timing APIs&lt;/a&gt;. With SQL and data at my fingertips, I can measure the distinct phases outlined by the model and see if correlations exist.&lt;/p&gt;
&lt;p&gt;Having discussed the technical underpinnings of how data can be collected from survey participants, let’s shift the focus to the survey’s design and user flows.&lt;/p&gt;
&lt;h2&gt;Designing the survey&lt;/h2&gt;
&lt;p&gt;Though surveys tend to have straightforward designs and user flows relative to other sites, we must remain cognizant of the user’s path and the impediments a user could face.&lt;/p&gt;
&lt;h3&gt;The entry point&lt;/h3&gt;
&lt;p&gt;When participants arrive at &lt;a href=&quot;https://imagesurvey.site/&quot; rel=&quot;noopener&quot;&gt;the home page&lt;/a&gt;, we want to be direct in our communication with them. The home page intro copy greets participants, gives them a succinct explanation of what to expect, and presents two navigation choices:&lt;/p&gt;
&lt;figure&gt;
&lt;img data-recalc-dims=&quot;1&quot; decoding=&quot;async&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2018/03/fig-01-v2-1x.png?w=960&amp;amp;quality=80&amp;amp;ssl=1&quot; srcset=&quot;https://alistapart.com/wp-content/uploads/2018/03/fig-01-v2-2x.png 2x, https://alistapart.com/wp-content/uploads/2018/03/fig-01-v2-1x.png 1x&quot; alt=&quot;One button with the text “I want to participate!” and another button with the text “What data do you gather?”&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;br&gt;
&lt;/figure&gt;
&lt;p&gt;From here, participants either start the survey or read a privacy policy. If the user decides to take the survey, they’ll reach a page politely asking them what their professional occupation is and requesting them to disclose any eyesight conditions. The fields for these questions can be left blank, as some may not be comfortable disclosing this kind of information. Beyond this point, the survey begins in earnest.&lt;/p&gt;
&lt;h3&gt;The survey primer&lt;/h3&gt;
&lt;p&gt;Before the user begins rating images, they’re redirected to &lt;a href=&quot;https://imagesurvey.site/presurvey&quot; rel=&quot;noopener&quot;&gt;a primer page&lt;/a&gt;. This page describes what’s expected of participants, and explains how to rate images. While the survey is promoted on design and development outlets where readers regularly work with imagery on the web, a primer is still useful in getting everyone on the same page. The first paragraph of the page stresses that users are rating image &lt;em&gt;quality&lt;/em&gt;, not image &lt;em&gt;content&lt;/em&gt;. This is important. Absent any context, participants may indeed rate images for their content, which is not what we’re asking for. After this clarification, the concept of lossy image quality is demonstrated with the following diagram:&lt;/p&gt;
&lt;figure&gt;
&lt;img data-recalc-dims=&quot;1&quot; decoding=&quot;async&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2018/03/fig-02-v2-1x.jpg?w=960&amp;amp;quality=89&amp;amp;ssl=1&quot; srcset=&quot;https://alistapart.com/wp-content/uploads/2018/03/fig-02-v2-2x.jpg 2x, https://alistapart.com/wp-content/uploads/2018/03/fig-02-v2-1x.jpg 1x&quot; alt=&quot;A divided photo with one half demonstrating low image quality and the other demonstrating high quality.&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;br&gt;
&lt;/figure&gt;
&lt;p&gt;Lastly, the function of the rating input is explained. This could likely be inferred by most, but the explanatory copy helps remove any remaining ambiguity. Assuming your user knows everything you do is not necessarily wise. What seems obvious to one is not always so to another.&lt;/p&gt;
&lt;h3&gt;The image specimen page&lt;/h3&gt;
&lt;p&gt;This page is the main event and is where participants assess the quality of images shown to them. It contains two areas of focus: the image specimen and the input used to rate the image’s quality.&lt;/p&gt;
&lt;p&gt;Let’s talk a bit out of order and discuss the input first. I mulled over a few options when it came to which input &lt;code&gt;type&lt;/code&gt; to use. I considered a &lt;code&gt;select&lt;/code&gt; input with coarsely predefined choices, an &lt;code&gt;input&lt;/code&gt; with a &lt;code&gt;type&lt;/code&gt; of &lt;code&gt;number&lt;/code&gt;, and other choices. What seemed to make the most sense to me, however, was a slider &lt;code&gt;input&lt;/code&gt; with a &lt;code&gt;type&lt;/code&gt; of &lt;code&gt;range&lt;/code&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img data-recalc-dims=&quot;1&quot; decoding=&quot;async&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2018/03/fig-03-v2-1x.png?w=960&amp;amp;quality=80&amp;amp;ssl=1&quot; srcset=&quot;https://alistapart.com/wp-content/uploads/2018/03/fig-03-v2-2x.png 2x, https://alistapart.com/wp-content/uploads/2018/03/fig-03-v2-1x.png 1x&quot; alt=&quot;A rating slide with “worst” at the far left, and “best” at the far right. The slider track is a gradient from red on the left to green on the right.&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;br&gt;
&lt;/figure&gt;
&lt;p&gt;A slider &lt;code&gt;input&lt;/code&gt; is more intuitive than a text &lt;code&gt;input&lt;/code&gt;, or a &lt;code&gt;select&lt;/code&gt; element populated with various choices. Because we’re asking for a subjective assessment about something with such a large range of interpretation, a slider allows participants more granularity in their assessments and lends further accuracy to the data collected.&lt;/p&gt;
&lt;p&gt;Now let’s talk about the image specimen and how it’s selected by the back-end code. I decided early on in the survey’s development that I wanted images that weren’t prominent in existing stock photo collections. I also wanted uncompressed sources so I wouldn’t be presenting participants with recompressed image specimens. To achieve this, I procured images from &lt;a href=&quot;http://www.wolftownmedia.com/&quot; rel=&quot;noopener&quot;&gt;a local photographer&lt;/a&gt;. The twenty-five images I settled on were minimally processed &lt;a href=&quot;https://en.wikipedia.org/wiki/Raw_image_format&quot; rel=&quot;noopener&quot;&gt;raw images&lt;/a&gt; from the photographer’s camera. The result was a cohesive set of images that felt visually related to each other.&lt;/p&gt;
&lt;p&gt;To properly gauge perception across the entire spectrum of quality settings, I needed to generate each image from the aforementioned sources at ninety-six different quality settings ranging from 5 to 100. To account for the varying widths and pixel densities of screens in the wild, each image also needed to be generated at four different widths for each quality setting: 1536, 1280, 1024, and 768 pixels, to be exact. Just the job &lt;code&gt;srcset&lt;/code&gt; was made for!&lt;/p&gt;
&lt;p&gt;To top it all off, images &lt;em&gt;also&lt;/em&gt; needed to be encoded in both JPEG and WebP formats. As a result, the survey draws randomly from 768 images &lt;em&gt;per specimen&lt;/em&gt; across the entire quality range, while also delivering the best image for the participant’s screen. This means that across the twenty-five image specimens participants evaluate, the survey draws from a pool of &lt;em&gt;19,200&lt;/em&gt; images total.&lt;/p&gt;
&lt;p&gt;With the conception and design of the survey covered, let’s segue into how the survey was improved by implementing user feedback into the second round.&lt;/p&gt;
&lt;h2&gt;Listening to feedback&lt;/h2&gt;
&lt;p&gt;When I launched round one of the survey, feedback came flooding in from designers, developers, accessibility advocates, and even researchers. While my intentions were good, I inevitably missed some important aspects, which made it necessary to conduct a second round. Iteration and refinement are &lt;em&gt;critical&lt;/em&gt; to improving the usefulness of a design, and this survey was no exception. When we improve designs with user feedback, we take a project from average to something more memorable. Getting to that point means taking feedback in stride and addressing distinct, actionable items. In the case of the survey, incorporating feedback not only yielded a better user experience, it improved the integrity of the data collected.&lt;/p&gt;
&lt;h3&gt;Building a better slider input&lt;/h3&gt;
&lt;p&gt;Though the first round of the survey was serviceable, I ran into issues with the slider input. In round one of the survey, that input looked like this:&lt;/p&gt;
&lt;figure&gt;
&lt;img data-recalc-dims=&quot;1&quot; decoding=&quot;async&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2018/03/fig-04-v2-1x.png?w=960&amp;amp;quality=80&amp;amp;ssl=1&quot; srcset=&quot;https://alistapart.com/wp-content/uploads/2018/03/fig-04-v2-2x.png 2x, https://alistapart.com/wp-content/uploads/2018/03/fig-04-v2-1x.png 1x&quot; alt=&quot;A slider with evenly-spaced spaced labels from left to right reading respectively, “Awful”, “Bad”, “OK”, “Good”, “Great”. Below it is a disabled button with the text “Please Rate the Image...”.&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;br&gt;
&lt;/figure&gt;
&lt;p&gt;There were two recurring complaints regarding this specific implementation. The first was that participants felt they had to align their rating to one of the labels beneath the slider track. This was undesirable for the simple fact that the slider was chosen &lt;em&gt;specifically&lt;/em&gt; to encourage participants to provide nuanced assessments.&lt;/p&gt;
&lt;p&gt;The second complaint was that the submit button was disabled until the user interacted with the slider. This design choice was intended to prevent participants from simply clicking the submit button on every page without rating images. Unfortunately, this implementation was unintentionally hostile to the user and needed improvement, because it blocked users from rating images without a clear and obvious explanation as to why.&lt;/p&gt;
&lt;p&gt;Fixing the problem with the labels meant redesigning the slider as it appeared in Figure 3. I removed the labels altogether to eliminate the temptation of users to align their answers to them. Additionally, I changed the slider &lt;code&gt;background property&lt;/code&gt; to a gradient pattern, which further implied the granularity of the input.&lt;/p&gt;
&lt;p&gt;The submit button issue was a matter of how users were prompted. In round one the submit button was visible, yet the disabled state wasn’t obvious enough to some. After consulting with a colleague, I found a solution for round two: in lieu of the submit button being initially visible, it’s hidden by some guide copy:&lt;/p&gt;
&lt;figure&gt;
&lt;img data-recalc-dims=&quot;1&quot; decoding=&quot;async&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2018/03/fig-05-v2-1x.png?w=960&amp;amp;quality=80&amp;amp;ssl=1&quot; srcset=&quot;https://alistapart.com/wp-content/uploads/2018/03/fig-05-v2-2x.png 2x, https://alistapart.com/wp-content/uploads/2018/03/fig-05-v2-1x.png 1x&quot; alt=&quot;The revised slider followed by the text “Once you rate the image, you may submit.”&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;br&gt;
&lt;/figure&gt;
&lt;p&gt;Once the user interacts with the slider and rates the image, a &lt;code&gt;change&lt;/code&gt; event attached to the input fires, which hides the guide copy and replaces it with the submit button:&lt;/p&gt;
&lt;figure&gt;
&lt;img data-recalc-dims=&quot;1&quot; decoding=&quot;async&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2018/03/fig-06-v2-1x.png?w=960&amp;amp;quality=80&amp;amp;ssl=1&quot; srcset=&quot;https://alistapart.com/wp-content/uploads/2018/03/fig-06-v2-2x.png 2x, https://alistapart.com/wp-content/uploads/2018/03/fig-06-v2-1x.png 1x&quot; alt=&quot;The revised slider now followed by a button reading “Submit rating”.&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;br&gt;
&lt;/figure&gt;
&lt;p&gt;This solution is less ambiguous, and it funnels participants down the desired path. If someone with JavaScript disabled visits, the guide copy is never shown, and the submit button is immediately usable. This isn’t ideal, but it doesn’t shut out participants without JavaScript.&lt;/p&gt;
&lt;h3&gt;Addressing scrolling woes&lt;/h3&gt;
&lt;p&gt;The survey page works especially well in portrait orientation. Participants can see all (or most) of the image without needing to scroll. In browser windows or mobile devices in landscape orientation, however, the survey image can be larger than the viewport:&lt;/p&gt;
&lt;figure&gt;
&lt;img data-recalc-dims=&quot;1&quot; decoding=&quot;async&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2018/03/fig-07-v2-1x.png?w=960&amp;amp;quality=80&amp;amp;ssl=1&quot; srcset=&quot;https://alistapart.com/wp-content/uploads/2018/03/fig-07-v2-2x.png 2x, https://alistapart.com/wp-content/uploads/2018/03/fig-07-v2-1x.png 1x&quot; alt=&quot;Screen shot of the survey with an image clipped at the bottom by the viewport and rating slider.&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;br&gt;
&lt;/figure&gt;
&lt;p&gt;Working with such limited vertical real estate is tricky, especially in this case where the slider needs to be fixed to the bottom of the screen (which addressed an earlier bit of user feedback from round one testing). After discussing the issue with colleagues, I decided that animated indicators in the corners of the page could signal to users that there’s more of the image to see.&lt;/p&gt;
&lt;figure&gt;
&lt;img data-recalc-dims=&quot;1&quot; decoding=&quot;async&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2018/03/fig-08-v2-1x.png?w=960&amp;amp;quality=80&amp;amp;ssl=1&quot; srcset=&quot;https://alistapart.com/wp-content/uploads/2018/03/fig-08-v2-2x.png 2x, https://alistapart.com/wp-content/uploads/2018/03/fig-08-v2-1x.png 1x&quot; alt=&quot;The survey with the clipped image, but now there is a downward-pointing arrow with the word “Scroll”.&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;br&gt;
&lt;/figure&gt;
&lt;p&gt;When the user hits the bottom of the page, the scroll indicators disappear. Because animations may be jarring for &lt;a href=&quot;https://a11yproject.com/posts/understanding-vestibular-disorders/&quot; rel=&quot;noopener&quot;&gt;certain users&lt;/a&gt;, a &lt;a href=&quot;https://css-tricks.com/introduction-reduced-motion-media-query/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;prefers-reduced-motion&lt;/code&gt; media query&lt;/a&gt; is used to turn off this (and all other) animations if the user has a stated preference for reduced motion. In the event JavaScript is disabled, the scrolling indicators are always hidden in portrait orientation where they’re less likely to be useful and always visible in landscape where they’re potentially needed the most.&lt;/p&gt;
&lt;h3&gt;Avoiding overscaling of image specimens&lt;/h3&gt;
&lt;p&gt;One issue that was brought to my attention from a coworker was how the survey image seemed to expand boundlessly with the viewport. On mobile devices this isn’t such a problem, but on large screens and even modestly sized high-density displays, images can be scaled excessively. Because the responsive &lt;code&gt;img&lt;/code&gt; tag’s &lt;code&gt;srcset&lt;/code&gt; attribute specifies a maximum resolution image of &lt;code&gt;1536w&lt;/code&gt;, an image can begin to overscale at as “small” at sizes over 768 pixels wide on devices with a device pixel ratio of 2.&lt;/p&gt;
&lt;figure&gt;
&lt;img data-recalc-dims=&quot;1&quot; decoding=&quot;async&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2018/03/fig-09-v2-1x.jpg?w=960&amp;amp;quality=89&amp;amp;ssl=1&quot; srcset=&quot;https://alistapart.com/wp-content/uploads/2018/03/fig-09-v2-2x.jpg 2x, https://alistapart.com/wp-content/uploads/2018/03/fig-09-v2-1x.jpg 1x&quot; alt=&quot;The survey with an image expanding to fill the window.&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;br&gt;
&lt;/figure&gt;
&lt;p&gt;Some overscaling is inevitable and acceptable. However, when it’s excessive, compression artifacts in an image can become more pronounced. To address this, the survey image’s &lt;code&gt;max-width&lt;/code&gt; is set to &lt;code&gt;1536px&lt;/code&gt; for standard displays as of round two. For devices with a device pixel ratio of 2 or higher, the survey image’s &lt;code&gt;max-width&lt;/code&gt; is set to half that at &lt;code&gt;768px&lt;/code&gt;:&lt;/p&gt;
&lt;figure&gt;
&lt;img data-recalc-dims=&quot;1&quot; decoding=&quot;async&quot; src=&quot;https://i0.wp.com/alistapart.com/wp-content/uploads/2018/03/fig-10-v2-1x.jpg?w=960&amp;amp;quality=89&amp;amp;ssl=1&quot; srcset=&quot;https://alistapart.com/wp-content/uploads/2018/03/fig-10-v2-2x.jpg 2x, https://alistapart.com/wp-content/uploads/2018/03/fig-10-v2-1x.jpg 1x&quot; alt=&quot;The survey with an image comfortably fitting in the window.&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;br&gt;
&lt;/figure&gt;
&lt;p&gt;This minor (yet important) fix ensures that images aren’t scaled beyond a reasonable maximum. With a reasonably sized image asset in the viewport, participants will assess images close to or at a given image asset’s natural dimensions, particularly on large screens.&lt;/p&gt;
&lt;p&gt;User feedback is valuable. These and other UX feedback items I incorporated improved both the function of the survey and the integrity of the collected data. All it took was sitting down with users and listening to them.&lt;/p&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;As round two of the survey gets under way, I’m hoping the data gathered reveals something exciting about the relationship between performance and how people perceive image quality. If you want to be a part of the effort, &lt;a href=&quot;https://imagesurvey.site/&quot; rel=&quot;noopener&quot;&gt;please take the survey&lt;/a&gt;. When round two concludes, keep an eye out here for a summary of the results!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thank you to those who gave their valuable time and feedback to make this article as good as it could possibly be: &lt;a href=&quot;https://www.aaron-gustafson.com/&quot; rel=&quot;noopener&quot;&gt;Aaron Gustafson&lt;/a&gt;, &lt;a href=&quot;https://www.zeldman.com/&quot; rel=&quot;noopener&quot;&gt;Jeffrey Zeldman&lt;/a&gt;, &lt;a href=&quot;http://brandongregorycreative.com/&quot; rel=&quot;noopener&quot;&gt;Brandon Gregory&lt;/a&gt;, &lt;a href=&quot;https://rachelandrew.co.uk/&quot; rel=&quot;noopener&quot;&gt;Rachel Andrew&lt;/a&gt;, &lt;a href=&quot;https://www.bruceontheloose.com/&quot; rel=&quot;noopener&quot;&gt;Bruce Hyslop&lt;/a&gt;, &lt;a href=&quot;http://adrianroselli.com/&quot; rel=&quot;noopener&quot;&gt;Adrian Roselli&lt;/a&gt;, &lt;a href=&quot;https://www.megkurdziolek.com/&quot; rel=&quot;noopener&quot;&gt;Meg Dickey-Kurdziolek&lt;/a&gt;, and &lt;a href=&quot;https://www.linkedin.com/in/tukkrr/&quot; rel=&quot;noopener&quot;&gt;Nick Tucker&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Additional thanks to those who helped improve the image quality survey: &lt;a href=&quot;https://twitter.com/mandytensen&quot; rel=&quot;noopener&quot;&gt;Mandy Tensen&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/darleendenno&quot; rel=&quot;noopener&quot;&gt;Darleen Denno&lt;/a&gt;, &lt;a href=&quot;http://www.charlottedann.com/&quot; rel=&quot;noopener&quot;&gt;Charlotte Dann&lt;/a&gt;, &lt;a href=&quot;https://www.timdunklee.com/&quot; rel=&quot;noopener&quot;&gt;Tim Dunklee&lt;/a&gt;, and &lt;a href=&quot;https://thadroe.com/&quot; rel=&quot;noopener&quot;&gt;Thad Roe&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description><link>https://alistapart.com/article/designing-for-research/</link><guid isPermaLink="false">https://alistapart.com/article/designing-for-research/</guid><pubDate>Tue, 20 Mar 2018 13:09:00 GMT</pubDate><author>jeremy-wagner</author><category>Application Development</category><category>Usability</category><category>User Research</category></item><item><title>Owning the Role of the Front-End Developer</title><description>&lt;p&gt;When I started working as a web developer in 2009, I spent most of my time crafting HTML/CSS layouts from design comps. My work was the final step of a linear process in which designers, clients, and other stakeholders made virtually all of the decisions.&lt;/p&gt;
&lt;p&gt;Whether I was working for an agency or as a freelancer, there was no room for a developer’s input on client work other than when we were called to answer specific technical questions. Most of the time I would be asked to confirm whether it was possible to achieve a simple feature, such as adding a content slider or adapting an image loaded from a CMS.&lt;/p&gt;
&lt;p&gt;In the ensuing years, as front-end development became increasingly challenging, developers’ skills began to evolve, leading to more frustration. Many organizations, including the ones I worked for, followed a traditional waterfall approach that kept us in the dark until the project was ready to be coded. Everything would fall into our laps, often behind schedule, with no room for us to add our two cents. Even though we were often highly esteemed by our teammates, there still wasn’t a chance for us to contribute to projects at the beginning of the process. Every time we shared an idea or flagged a problem, it was already too late.&lt;/p&gt;
&lt;p&gt;Almost a decade later, we’ve come a long way as front-end developers. After years of putting in the hard work required to become better professionals and have a bigger impact on projects, many developers are now able to occupy a more fulfilling version of the role.&lt;/p&gt;
&lt;p&gt;But there’s still work to be done: Unfortunately, some front-end developers with amazing skills are still limited to basic PSD-to-HTML work. Others find themselves in a better position within their team, but are still pushing for a more prominent role where their ideas can be fostered.&lt;/p&gt;
&lt;p&gt;Although I’m proud to believe I’m part of the group that evolved with the role, I continue to fight for our seat at the table. I hope sharing my experience will help others fighting with me.&lt;/p&gt;
&lt;h2&gt;My road to earning a seat at the table&lt;/h2&gt;
&lt;p&gt;My role began to shift the day I watched &lt;a href=&quot;https://www.youtube.com/watch?v=o76qx7ZzFs4&quot; rel=&quot;noopener&quot;&gt;an inspiring talk by Seth Godin&lt;/a&gt;, which helped me realize I had the power to start making changes to make my work more fulfilling. With his recommendation to demand responsibility whether you work for a boss or a client, Godin gave me the push I needed.&lt;/p&gt;
&lt;p&gt;I wasn’t expecting to make any big leaps—just enough to feel like I was headed in the right direction.&lt;/p&gt;
&lt;h3&gt;Taking small steps within a small team&lt;/h3&gt;
&lt;p&gt;My first chance to test the waters was ideal. I had recently partnered with a small design studio and we were a team of five. Since I’d always been open about my soft spot for great design, it wasn’t hard to sell them on the idea of having me begin to get a bit more involved with the design process and start giving technical feedback before comps were presented to clients.&lt;/p&gt;
&lt;p&gt;The results were surprisingly amazing and had a positive impact on everybody’s work. I started getting design hand-offs that I both approved of from a technical point of view and had a more personal connection with. For their part, the designers happily noticed that the websites we launched were more accurate representations of the comps they had handed off.&lt;/p&gt;
&lt;p&gt;My next step was to get involved with every single project from day one. I started to tag along to initial client meetings, even before any contracts had been signed. I started flagging things that could turn the development phase into a nightmare; at the same time I was able to throw around some ideas about new technologies I’d been experimenting with.&lt;/p&gt;
&lt;p&gt;After a few months, I started feeling that my skills were finally having an impact on my team’s projects. I was satisfied with my role within the team, but I knew it wouldn’t last forever. Eventually it was time for me to embark on a journey that would take me back to the classic role of the front-end developer, closer to the base of the waterfall.&lt;/p&gt;
&lt;h3&gt;Moving to the big stage&lt;/h3&gt;
&lt;p&gt;As my career started to take off, I found myself far away from that five-desk office where it had all started. I was now working with a much bigger team, and the challenges were quite different. At first I was amazed at how they were approaching the process: the whole team had a strong technical background, unlike any team I had ever worked with, which made collaboration very efficient. I had no complaints about the quality of the designs I was assigned to work with. In fact, during my first few months, I was constantly pushed out of my comfort zone, and my skills were challenged to the fullest.&lt;/p&gt;
&lt;p&gt;After I started to feel more comfortable with my responsibilities, though, I soon found my next challenge: to help build a stronger connection between the design and development teams. Though we regularly collaborated to produce high-quality work, these teams didn’t always speak the same language. Luckily, the company was already making an effort to improve the conversation between creatives and developers, so I had all the support I needed.&lt;/p&gt;
&lt;p&gt;As a development team, we had been shifting to modern JavaScript libraries that led us to work on our applications using a strictly component-based approach. But though we had slowly changed our mindset, we hadn’t changed the ways we collaborated with our creative colleagues. We had not properly shared our new vision; making that connection would become my new personal goal.&lt;/p&gt;
&lt;p&gt;I was fascinated by &lt;a href=&quot;http://atomicdesign.bradfrost.com/chapter-4/#death-to-the-waterfall&quot; rel=&quot;noopener&quot;&gt;Brad Frost’s “death to the waterfall” concept&lt;/a&gt;: the idea that UX, visual design, and development teams should work in parallel, allowing for a higher level of iteration during the project.&lt;/p&gt;
&lt;p&gt;By pushing to progressively move toward a collaborative workflow, everyone on my team began to share more responsibilities and exchange more feedback throughout every project. Developers started to get involved in projects during the design phase, flagging any technical issues we could anticipate. Designers made sure they provided input and guidance after the projects started coming to life during development. Once we got the ball rolling, we quickly began seeing positive results and producing rewarding (and award-winning) work.&lt;/p&gt;
&lt;p&gt;Even though it might sound like it was a smooth transition, it required a great amount of hard work and commitment from everybody on the team. Not only did we all want to produce better work but we also needed to be willing to take a big leap away from our comfort zones and our old processes.&lt;/p&gt;
&lt;h2&gt;How you can push for a seat at the table&lt;/h2&gt;
&lt;p&gt;In my experience, making real progress required a combination of sharpening my skills as a front-end developer and pushing the team to improve our processes.&lt;/p&gt;
&lt;p&gt;What follows are more details about what worked for me—and could also work for you.&lt;/p&gt;
&lt;h3&gt;Making changes as a developer&lt;/h3&gt;
&lt;p&gt;Even though the real change in your role may depend on your organization, sometimes your individual actions can help jump-start the shift:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Speak up.&lt;/strong&gt; In multidisciplinary teams, developers are known as highly analytical, critical, and logical, but not always the most communicative of the pack. I’ve seen many who quietly complain and claim to have better ideas on how things should be handled, but bottle up those thoughts and move on to a different job. After I started voicing my concerns, proposing new ideas, and seeing small changes within my team, I experienced an unexpected boost in my motivation and noticed others begin to see my role differently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Always be aware of what the rest of the team is up to.&lt;/strong&gt; One of the most common mistakes we tend to make is to focus only on our craft. To connect with our team and improve in our role, we need to understand our organization’s goals, our teammates’ skill sets, our customers, and basically every other aspect of our industry that we used to think wasn’t worth a developer’s time. Once I started having a better understanding of the design process, communication with my team started to improve. The same applied to designers who started learning more about the processes we use as front-end developers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep core skills sharp.&lt;/strong&gt; Today our responsibilities are broader and we’re constantly tasked with leading our teams into undiscovered technologies. As a front-end developer, it’s not uncommon to be required to research technologies like WebGL or VR, and introduce them to the rest of the team. We must stay current with the latest practices in our technical areas of focus. Our credibility is at stake every time our input is needed, so we must always strive to be the best developers in the business.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Rethinking practices within the company&lt;/h3&gt;
&lt;p&gt;In order to make the most of your role as a developer, you’ll have to persuade your organization to make key changes. This might be hard to achieve, since it tends to require taking all members of your team out of their comfort zones.&lt;/p&gt;
&lt;p&gt;For me, what worked was long talks with my colleagues, including designers, management, and fellow developers. It’s hard for a manager to turn you down when you propose an idea to improve the quality of your work and only ask for small changes. Once the rest of the team is on board, you have to work hard and start implementing these changes to keep the ball rolling:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Involve developers in projects from the beginning.&lt;/strong&gt; Many companies have high standards when it comes to hiring developers but don’t take full advantage of their talent. We tend to be logical thinkers, so it’s usually a good idea to &lt;a href=&quot;https://www.smashingmagazine.com/2014/11/why-you-should-include-your-developer-in-the-design-process/&quot; rel=&quot;noopener&quot;&gt;involve developers in many aspects of the projects&lt;/a&gt; we work on. I often had to take the first step to be invited to project kickoffs. But once I started making an effort to provide valuable input, my team started automatically involving me and other developers during the creative phase of new projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Schedule team reviews.&lt;/strong&gt; Problems frequently arise when teams present to clients without having looped in everyone working on the project. Once the client signs off on something, it can be risky to introduce new ideas, even if they add value. Developers, designers, and other key players must come together for team reviews before handing off any work. As a developer, sometimes you might need to raise your hand and invest some of your time to help your teammates review their work before they present it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Get people to work together.&lt;/strong&gt; Whenever possible, get people in the same room. We tend to rely on technology and push to communicate only by chat and email, but there is real value in face time. It’s always a good idea to have different teammates sit together, or at least in close enough proximity for regular in-person conversation, so they can share feedback more easily during projects. If your team works remotely, you have to look for alternatives to achieve the same effect. Occasional video chats and screen sharing can help teams share feedback and interact in real time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make time for education.&lt;/strong&gt; Of all the teams I’ve worked on, those that foster a knowledge-sharing culture tend to work most efficiently. Simple and casual presentations among colleagues from different disciplines can be vital to creating a seamless variety of skills across the team. So it’s important to encourage members of the team to teach and learn from each other.&lt;p&gt;&lt;/p&gt;
&lt;p&gt;When we made the decision to use only a component-based architecture, we prepared a simple presentation for the design team that gave them an overview of how we all would benefit from the change to our process. Shortly after, the team began delivering design comps that were aligned with our new approach.
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s fair to say that the modern developer can’t simply hide behind a keyboard and expect the rest of the team to handle all of the important decisions that define our workflow. Our role requires us to go beyond code, share our ideas, and fight hard to improve the processes we’re involved in.&lt;/p&gt;
</description><link>https://alistapart.com/article/owning-the-role-of-the-front-end-developer/</link><guid isPermaLink="false">https://alistapart.com/article/owning-the-role-of-the-front-end-developer/</guid><pubDate>Tue, 27 Feb 2018 13:30:00 GMT</pubDate><author>jeremy-wagner</author><category>Application Development</category><category>Process</category></item><item><title>Coding with Clarity</title><description>&lt;p&gt;Working code isn’t necessarily good code. Your code also needs to be easy to read, understand, and modify. It needs clarity, and to achieve that, it has to be organized well, with careful planning and proper separation of ideas taking place before you even open your code editor. Coding for clarity is something that separates the great developers from the merely good, and there are a few basic principles that can set you on that path.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: Though the principles in this article are applicable to a variety of programming languages, most of the examples pull from object-oriented JavaScript. If you’re not familiar with this,&lt;/em&gt; A List Apart &lt;em&gt;has articles on &lt;a href=&quot;https://alistapart.com/article/the-design-of-code-organizing-javascript&quot;&gt;the module pattern&lt;/a&gt; and &lt;a href=&quot;https://alistapart.com/article/prototypal-object-oriented-programming-using-javascript&quot;&gt;prototypal inheritance&lt;/a&gt; to help bring you up to speed.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;The single responsibility principle&lt;/h2&gt;
&lt;p&gt;Imagine you’re working on a home project and you pick up a drill to drive a screw into a wall. When you pull the drill away from the screw, you discover that this drill has an interesting feature: it squirts a quick-drying drywall compound over the driven screw to hide it. Well, that’s great if you want to paint over the screw, but that’s not always the case. You shouldn’t have to get a second drill just to drill a hole in something. The drill would be much more usable and reliable if it just did one thing, and it would also be flexible enough to use in a variety of situations.&lt;/p&gt;
&lt;p&gt;The single responsibility principle states that a block of code should do one thing, and do it well. Like the drill above, limiting its functionality actually increases the usefulness of a block of code. Coding this way not only saves you a lot of headache, but it will save future developers on the project a lot of headache as well.&lt;/p&gt;
&lt;p&gt;Think of functions and methods in terms of responsibilities. As you increase its responsibilities, a block of code becomes less flexible and reliable, more demanding of changes, and more susceptible to errors. For the most clarity, each function or method should have one responsibility.&lt;/p&gt;
&lt;p&gt;If you’re describing what a function does and you have to use the word “and,” that function is probably too complex. What a function does should be simple enough to explain with only a descriptive function name and descriptive arguments.&lt;/p&gt;
&lt;p&gt;I was tasked recently with creating an electronic version of the Myers-Briggs personality test. I’d done this before, and when I first approached the problem a few years ago, I coded one giant function called &lt;code&gt;processForm&lt;/code&gt;—it gathered the scores, generated the charts, and took care of everything in the DOM to display things to the user.&lt;/p&gt;
&lt;p&gt;The problem was that if anything had to change, you had to search through a mountain of code to figure out where to make the alteration. Also, if something went wrong in the middle of the function, it was a lot harder to find the error.&lt;/p&gt;
&lt;p&gt;So when facing the problem this time, I broke everything down into single-responsibility functions wrapped up in a module object instead. The resulting function called upon form submission looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;return {
    processForm: function() {
        getScores();
        calculatePercentages();
        createCharts();
        showResults();
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;text&quot;&gt;
&lt;p&gt;(&lt;a href=&quot;https://codepen.io/pulpexploder/pen/pNpdeq&quot;&gt;View complete app here&lt;/a&gt;)&lt;/p&gt;
&lt;/figure&gt;
&lt;p&gt;Extremely easy to read, understand, and modify—even a non-coder can make sense of this. And each of those functions does (you guessed it!) only one thing. This is the single responsibility principle in action.&lt;/p&gt;
&lt;p&gt;If I wanted to add form validation, rather than having to modify a giant working function (potentially breaking it), I could simply add a new method. This approach also enables related logic and variables to be segmented off, cutting down on conflicts for greater reliability, and it makes it very easy to reuse the function for other purposes if needed.&lt;/p&gt;
&lt;p&gt;So remember: one function, one responsibility. Large functions are where classes go to hide. If a function does lots of things that are closely tied together and that are working with the same data, it would make more sense to break it up into an object with methods, much like I did with my large form function.&lt;/p&gt;
&lt;h2&gt;Command-query separation&lt;/h2&gt;
&lt;p&gt;The funniest email chain I’ve ever seen was the &lt;a href=&quot;http://www.27bslash6.com/missy.html&quot;&gt;series of Missing Missy posters from David Thorne&lt;/a&gt; about a missing cat. Each time his coworker Shannon makes a request, David complies, but puts his own little twist on it and delivers something different than what was expected. The exchange is very funny and worth a read, but it’s less funny when your code does the same thing.&lt;/p&gt;
&lt;p&gt;Command-query separation provides a basis of safeguarding your code against unintended side effects to avoid surprises when functions are called. Functions fall into one of two categories: &lt;i&gt;commands&lt;/i&gt;, which perform an action, and &lt;i&gt;queries&lt;/i&gt;, which answer a question. You should not mix them. Consider the following function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function getFirstName() {
    var firstName = document.querySelector(&quot;#firstName&quot;).value;
    firstName = firstName.toLowerCase();
    setCookie(&quot;firstName&quot;, firstName);
    if (firstName === null) {
        return &quot;&quot;;
    }
    return firstName;
}
 
var activeFirstName = getFirstName();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a simplistic example—most side effects are harder to find—but you can see some potentially unanticipated side effects in action.&lt;/p&gt;
&lt;p&gt;The function name, &lt;code&gt;getFirstName&lt;/code&gt;, tells us that the function is going to return the first name. But the first thing it does is convert the name to lowercase. The name says it’s getting something (a query), but it’s also changing the state of the data (a command)—a side effect that is not clear from the function name.&lt;/p&gt;
&lt;p&gt;Worse, the function then sets a cookie for the first name without telling us, potentially overwriting something we could have been counting on. A query function should never, ever overwrite data.&lt;/p&gt;
&lt;p&gt;A good rule of thumb is that if your function answers a question, it should return a value and &lt;em&gt;not&lt;/em&gt; alter the state of the data. Conversely, if your function does something, it should alter the state of the data and &lt;em&gt;not&lt;/em&gt; return a value. For maximum clarity, a function should never return a value &lt;em&gt;and&lt;/em&gt; alter the state of the data.&lt;/p&gt;
&lt;p&gt;A better version of the code above would be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function getFirstName() {
    var firstName = document.querySelector(&quot;#firstName&quot;).value;
    if (firstName === null) {
        return &quot;&quot;;
    }
    return firstName;
}
 
setCookie(&quot;firstName&quot;, getFirstName().toLowerCase());&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a basic example, but hopefully you can see how this separation can clarify intent and prevent errors. As functions and code bases become larger, separation becomes much more important, as hunting for the function definition whenever you want to use it just to find out what it does is not an efficient use of anybody’s time.&lt;/p&gt;
&lt;h2&gt;Loose coupling&lt;/h2&gt;
&lt;p&gt;Consider the difference between a jigsaw puzzle and Lego blocks. With a jigsaw puzzle, there’s only one way to put the pieces together, and there’s only one finished product. With Lego, you can put the pieces together any way you want to make any end result you want. If you had to pick one of these types of building block to work with before you knew what you’d be building, which would you choose?&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Coupling&lt;/i&gt; is a measure of how much one program unit relies on others. Too much coupling (or tight coupling) is rigid and should be avoided. That’s the jigsaw puzzle. We want our code to be flexible, like Lego blocks. That’s loose coupling, and it generally results in much greater clarity.&lt;/p&gt;
&lt;p&gt;Remember, code should be flexible enough to cover a wide variety of use cases. If you find yourself copying and pasting code and making minor changes, or rewriting code because code changed somewhere else, this is tight coupling in action. (For example, to make the &lt;code&gt;getFirstName&lt;/code&gt; function from earlier reusable, you could replace the hard-coded &lt;code&gt;firstName&lt;/code&gt; with a generic ID passed to the function.) Other signs of this include hard-coded IDs in functions, too many function parameters, multiple similar functions, and large functions that violate the single responsibility principle.&lt;/p&gt;
&lt;p&gt;Tight coupling is most prevalent in a group of functions and variables that really should be a class instead, but it can also happen when classes depend on methods or properties from other classes. If you’re having trouble with interdependencies in functions, it’s probably time to think about breaking your functions into a class.&lt;/p&gt;
&lt;p&gt;I encountered this when looking at some code for a series of interactive dials. The dials had a number of variables, including dimensions, handle size, fulcrum size, and more. Because of this, the developer was forced to either use an absurd amount of function parameters or create multiple copies of each function with the variables hard-coded in each one. Additionally, each dial did something different when interacted with. This led to three sets of nearly identical functions—one for each dial. In short, coupling was increased due to the hard-coding of variables and behavior, so, like a jigsaw puzzle, there was only one way to put those pieces together. The codebase was unnecessarily complex.&lt;/p&gt;
&lt;p&gt;We solved the problem by breaking up the functions and variables into a reusable class that was instantiated for each of the three dials. We set up the class to take a function as an argument for output, so different outcomes could be configured when the individual dial objects were instantiated. As a result, we had fewer functions, and the variables were stored in only one place, making updates much easier.&lt;/p&gt;
&lt;p&gt;Classes that interact with each other can also be culprits of tight coupling. Let’s say we have a class that can create objects of another class, like a college course that can create students. Our &lt;code&gt;CollegeCourse&lt;/code&gt; class works fine. But then we need to add a parameter to the constructor of the &lt;code&gt;Student&lt;/code&gt; class. Oh no! Now we have to modify our &lt;code&gt;CollegeCourse&lt;/code&gt; class to account for the change in the &lt;code&gt;Student&lt;/code&gt; class.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;var CollegeCourse = (function() {
    function createStudent_WRONG(firstName, lastName, studentID) {
        /*
        If the Student constructor changes, we&#39;ll have to modify this method and all calls to it, too!
        */
    }

    function createStudent_RIGHT(optionsObject) {
        /*
        Passing an object as an argument allows the Student object to deal with the change. We may need to change this method, but we won’t need to change any existing calls to it.
        */
    }
}());&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You shouldn’t have to modify a class because another class changes. This is a classic case of tight coupling. Constructor parameters can be passed as an object with the receiving object having fallback default values, which loosens coupling and means code won’t break when you add new parameters.&lt;/p&gt;
&lt;p&gt;The point is that you should build your code like Lego blocks, not like jigsaw puzzle pieces. If you find yourself facing problems similar to the ones above, the problem is probably tight coupling.&lt;/p&gt;
&lt;h2&gt;High cohesion&lt;/h2&gt;
&lt;p&gt;Have you ever seen a kid clean a room by stuffing everything into the closet? Sure, it works, but it’s impossible to find anything and things that don’t belong together often get placed right next to each other. The same can happen with our code if we don’t strive for a high level of cohesion.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Cohesion&lt;/i&gt; is a measure of how much the various different program units belong together. A high level of cohesion is good and adds clarity to code blocks; a low level of cohesion is bad and leads to much confusion. Functions and methods in a code block should make sense together—they’ll have a high level of cohesion.&lt;/p&gt;
&lt;p&gt;High cohesion means sticking related things, like database functions or functions relating to a particular element, in one block or module. This helps not only with understanding how such things are laid out and where to find them, but also with preventing naming conflicts. If you have 30 functions, the chances of a conflicting name are far greater than if you have 30 methods split over four classes.&lt;/p&gt;
&lt;p&gt;If two or three functions use the same variables, they belong together; this is a great case for an object. If you have a series of functions and variables that control a page element, like a slider, it’s a great opportunity for high cohesion, so you should bundle them up into an object.&lt;/p&gt;
&lt;p&gt;Remember the example above about the class we made that decoupled the solution for the dial? That’s a great case of high cohesion as a cure for tight coupling. In that case, high cohesion and tight coupling were on opposite ends of a sliding scale, and focusing on one fixed the other.&lt;/p&gt;
&lt;p&gt;Repeated code is a sure sign of low cohesion. Similar lines of code should be broken into functions, and similar functions should be broken into classes. The rule of thumb here is that a line of code should never be repeated twice. In practice, this isn’t always possible, but for clarity’s sake you should always be thinking about how to cut down on repetition.&lt;/p&gt;
&lt;p&gt;Similarly, the same bit of data should not exist in more than one variable. If you’re defining the same bit of data in multiple places, you definitely need a class. Or if you find yourself passing references to the same HTML element to multiple functions, the reference should probably be a property in an instance of a class.&lt;/p&gt;
&lt;p&gt;Objects can even be put inside other objects to increase cohesion further. For example, you might put all AJAX functions in a single module that includes objects for form submission, grabbing content, and login syntax, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;Ajax.Form.submitForm();
Ajax.Content.getContent(7);
Ajax.Login.validateUser(username, password);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Conversely, you shouldn’t throw unrelated things together in the same class. An agency I used to work for had an internal API with an object called &lt;code&gt;Common&lt;/code&gt; that had a hodgepodge of common methods and variables that had nothing to do with each other. The class became huge and confusing simply because there was little thought given to cohesion.&lt;/p&gt;
&lt;p&gt;If properties are not used by multiple methods in a class, this can be a sign of low or bad cohesion. Similarly, if methods can’t be reused in a few different situations—or if a method isn’t used at all—this can also be a sign of low or bad cohesion.&lt;/p&gt;
&lt;p&gt;High cohesion helps to alleviate tight coupling, and tight coupling is a sign that greater cohesion is needed. If the two ever come into conflict, though, choose cohesion. High cohesion is generally a greater help to the developer than loose coupling, although both can usually be accomplished together.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;If our code is not immediately clear, problems occur. Achieving clarity is about so much more than proper indentation—it takes careful planning from the beginning of the project. While tough to master, abiding by the principles of single responsibility, command-query separation, loose coupling, and high cohesion can improve clarity in our code greatly. It should be a consideration in any significant programming project.&lt;/p&gt;
</description><link>https://alistapart.com/article/coding-with-clarity/</link><guid isPermaLink="false">https://alistapart.com/article/coding-with-clarity/</guid><pubDate>Thu, 26 Oct 2017 12:19:00 GMT</pubDate><author>brandongregory</author><category>Application Development</category><category>JavaScript</category></item><item><title>Yes, That Web Project Should Be a PWA</title><description>&lt;p&gt;It seems like ever since &lt;a href=&quot;https://fberriman.com/&quot;&gt;Frances Berriman&lt;/a&gt;  coined the term “Progressive Web App” in an effort to describe a new class of website, there’s been a great deal of confusion over exactly what a Progressive Web App (PWA) is. Sure, her husband, Alex Russell, put together a handy guide to the &lt;a href=&quot;https://medium.com/@slightlylate/progressive-apps-escaping-tabs-without-losing-our-soul-3b93a8561955&quot;&gt;characteristics of a PWA&lt;/a&gt;, and they have been the subject of reams of documentation, dozens of blog posts, and equally as many conference talks.&lt;/p&gt;
&lt;p&gt;Even with so much well-written, accessible content about PWAs freely available, &lt;a href=&quot;https://news.ycombinator.com/item?id=14752542&quot;&gt;misinformation abounds&lt;/a&gt;. Maybe you’ve run into one or more of these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you’re building a PWA, you need to use a JavaScript framework.&lt;/li&gt;
&lt;li&gt;To build a PWA, start with a single page app.&lt;/li&gt;
&lt;li&gt;PWAs only make sense for “apps” your users want to install.&lt;/li&gt;
&lt;li&gt;PWAs only make sense in mobile.&lt;/li&gt;
&lt;li&gt;PWAs are an Android thing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these are true, but like so much misinformation these days, each contains a shred of truth that has been contorted into a falsehood. If you’re considering building a PWA, you &lt;em&gt;might&lt;/em&gt; use a JavaScript framework or build it as a single page app, but it’s by no means necessary. They’re an option for building a PWA just like they’re an option for any other web project. After all, every PWA is (or at least should be) a website. PWAs just have some features that empower them to do more than websites have traditionally been able to … like install. But, similarly, installation is not the &lt;em&gt;raison d’être&lt;/em&gt; of every PWA. And, while many of the first PWAs were focused on mobile and only worked on Android, PWAs are &lt;a href=&quot;https://www.aaron-gustafson.com/notebook/progressive-web-apps-and-the-windows-ecosystem/#whats-the-timeline-for-progressive-web-apps-in-windows&quot;&gt;not limited to small screen devices anymore&lt;/a&gt;. They’re also &lt;a href=&quot;https://medium.com/@nekrtemplar/progressive-web-apps-aint-google-s-thing-31ca581e7a1&quot;&gt;more than a Google thing too&lt;/a&gt;; Microsoft, Mozilla, Opera, and Samsung are all on board. Apple &lt;a href=&quot;https://webkit.org/status/#specification-service-workers&quot;&gt;recently declared their intent to implement Service Workers&lt;/a&gt; (one of the technical underpinnings of PWAs), but time will tell if they’ll support aspects like installation. No matter, as &lt;a href=&quot;https://cloudfour.com/thinks/ios-doesnt-support-progressive-web-apps-so-what/&quot;&gt;Progressive Web Apps work really well in Safari anyway&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Sadly, misinformation like this has convinced many designers and developers (and their management teams) that PWAs aren’t appropriate for their projects. They &lt;em&gt;are&lt;/em&gt;! Your site—every site—should be a PWA. This approach offers benefits for every project on the web, but I’ll get to that in a minute. Before I do, I want to level-set on what, exactly, makes a PWA a PWA. If you’ve been tracking PWAs closely or have already built one, you can skim or skip the next section. If you aren’t all that familiar or don’t feel like you have a good grasp on what they are, no worries, the next section is a very brief primer that will get you up to speed quickly.&lt;/p&gt;
&lt;h2&gt;So what is a PWA?&lt;/h2&gt;
&lt;p&gt;As I mentioned, a PWA is a website with special powers. The term “app” in the “Progressive Web App” is not indicative of the sort of content or experience users should expect with a PWA. You shouldn’t get hung up on it; &lt;a href=&quot;https://fberriman.com/2017/06/26/naming-progressive-web-apps/&quot;&gt;“Progressive Web App” is a marketing term&lt;/a&gt;. PWAs have the ability to connect with the operating system (and, thereby, its users) on a deeper level through installation and APIs offering capabilities like notifications, access to the address book, and more. Not all of these APIs require installation for access, but some do. It may help to think about a PWA as being a website++.&lt;/p&gt;
&lt;p&gt;What makes a PWA a PWA? Not much, actually; there are only three requirements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;You need to be running under HTTPS.&lt;/strong&gt; PWAs can be granted a whole host of extra privileges in an operating system, so it’s critical that the connection to your web server be secure. If you need help with this, you should check out &lt;a href=&quot;https://letsencrypt.org/getting-started/&quot;&gt;the free SSL service Let’s Encrypt&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You need a &lt;a href=&quot;https://developer.mozilla.org/docs/Web/Manifest&quot;&gt;Web App Manifest&lt;/a&gt;.&lt;/strong&gt; This is a lot less scary than it sounds. It’s a JSON file with information about your site. You may even have a bare-bones one already if you’ve used a favicon generator. Make sure you &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Manifest#Deploying_a_manifest_with_the_link_tag&quot;&gt;reference it using a &lt;code&gt;link&lt;/code&gt; in the &lt;code&gt;head&lt;/code&gt; of your web pages&lt;/a&gt; so browsers and search spiders can find it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You need a Service Worker.&lt;/strong&gt; This is probably the most complicated step, but there are a ton of recipe guides out there for creating Service Workers tailored to the kind of jobs you want them to do. &lt;a href=&quot;https://serviceworke.rs/&quot;&gt;This one&lt;/a&gt;, from Mozilla, is especially good.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That’s it. Once you have those in place, your website is a Progressive Web App. At least &lt;em&gt;technically&lt;/em&gt;. Why the qualification? Well, this is where things get a little more nuanced.&lt;/p&gt;
&lt;p&gt;Back in 2015, when he debuted the PWA concept, &lt;a href=&quot;https://infrequently.org/2015/06/progressive-apps-escaping-tabs-without-losing-our-soul&quot;&gt;Alex Russell outlined ten characteristics PWAs shared&lt;/a&gt; (or at least were capable of). Most of those characteristics are, without a doubt, how we should be building for the web. Others are not as universal and would not make sense in every kind of project. I suspect that might be one of the sources of confusion for folks considering adopting the PWA approach and it’s the reason I decided to write this article.&lt;/p&gt;
&lt;h2&gt;Quality experiences and the universal benefits of PWAs&lt;/h2&gt;
&lt;p&gt;In the next few sections, I will discuss several web project archetypes and how adopting some of these PWA characteristics can benefit their users. After all, that’s who we’re doing this for. But before I get to that, I want to discuss the seven characteristics of PWAs that are useful in any web project.&lt;/p&gt;
&lt;p&gt;As I mentioned, there are some characteristics of PWAs that will absolutely provide value to your users and are well worth your time and consideration. In fact, all of them are considered best practices in web design and development.&lt;/p&gt;
&lt;p&gt;First off, PWAs must be &lt;strong&gt;safe&lt;/strong&gt;. As I mentioned in my discussion of their technical requirements, PWAs must be running under HTTPS. Period. Thankfully, the cost of running your site under HTTPS has &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;dropped to zero&lt;/a&gt;. Sure, &lt;a href=&quot;https://www.wired.com/2016/09/wired-completely-encrypted/&quot;&gt;there are legitimate challenges to converting large existing websites&lt;/a&gt; over, but it’s worth it for so many reasons. The primary one is that it protects your users from malicious man-in-the-middle attacks &lt;a href=&quot;https://www.aaron-gustafson.com/notebook/the-network-effect/&quot;&gt;being made by ISPs&lt;/a&gt;, &lt;a href=&quot;https://www.tripwire.com/state-of-security/security-data-protection/nabil-ouchn-airport-hotel-security/&quot;&gt;in hotels and airports&lt;/a&gt;, &lt;a href=&quot;https://www.pcmag.com/article2/0,2817,2406806,00.asp&quot;&gt;infected routers&lt;/a&gt;, or &lt;a href=&quot;https://www.wifipineapple.com/&quot;&gt;others with network access&lt;/a&gt;. HTTPS ensures that both the code and content you send to your users actually arrives intact. &lt;a href=&quot;https://www.aaron-gustafson.com/notebook/links/gogo-is-using-man-in-the-middle-malware-tactics-on-its-own-users/&quot;&gt;It’s not fool-proof&lt;/a&gt;, but it’s an important step in protecting your users and your data. Running HTTPS is also a prerequisite for access to many of the newer (and more sensitive) APIs including &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Geolocation&quot;&gt;Geolocation&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Service_Worker_API&quot;&gt;Service Workers&lt;/a&gt; and for performance-boosting technologies like &lt;a href=&quot;https://http2.github.io/&quot;&gt;HTTP/2&lt;/a&gt; and &lt;a href=&quot;https://github.com/google/brotli&quot;&gt;Brotli compression&lt;/a&gt;. It’s also worth noting that &lt;a href=&quot;https://www.troyhunt.com/life-is-about-to-get-harder-for-websites-without-https/&quot;&gt;many browsers are beginning to mark non-HTTPS sites “unsafe”&lt;/a&gt; and &lt;a href=&quot;https://security.googleblog.com/2014/08/https-as-ranking-signal_6.html&quot;&gt;SSL also affects search ranking&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I mentioned earlier that PWAs were never intended to be a mobile-only approach. PWAs are for everyone. Making your project available to more people on more devices with wildly varying operating systems, browser capabilities, system APIs, and screen sizes is only going to increase your reach and create more opportunities to be successful. This is where &lt;strong&gt;&lt;a href=&quot;https://alistapart.com/article/understandingprogressiveenhancement&quot;&gt;progressive enhancement&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;https://alistapart.com/article/responsive-web-design&quot;&gt;responsive design&lt;/a&gt;&lt;/strong&gt; come in. By building responsive layouts, your designs will adapt to provide the most appropriate layout given the screen real estate you have to work with, whether dependent on the dimensions of the device or on the window size set by your user. Progressive enhancement enables your projects to adapt to an even wider array of variance, in both the execution environment (device, OS, etc.) and, more importantly, your users.&lt;/p&gt;
&lt;p&gt;Progressive enhancement also helps you avoid situations where &lt;a href=&quot;http://youzeek.com/browserupgrade.aspx&quot;&gt;users can’t access your project&lt;/a&gt; because they happen to use a device or browser you’re unfamiliar with or haven’t tested on. It ensures your site works on any device that can access the web, regardless of its capabilities, allowing you to use your valuable time optimizing that experience for more modern browsers and devices. It’s also &lt;a href=&quot;https://medium.com/@AaronGustafson/the-true-cost-of-progressive-enhancement-d395b6502979&quot;&gt;a more economical approach&lt;/a&gt; in the long-run.&lt;/p&gt;
&lt;p&gt;Another quality Alex identified was that many PWAs are “app-like”. Note the &lt;em&gt;like&lt;/em&gt;. They are not apps, but rather, provide &lt;strong&gt;app-like experiences&lt;/strong&gt; that users—dare I say it?—enjoy using. The more you can do to provide a consistent, seamless, effortless user experience (which is really what “app-like” is implying here), &lt;a href=&quot;https://blog.kissmetrics.com/speed-is-a-killer/&quot;&gt;the more likely you are to see repeat visits, increased sales, etc&lt;/a&gt;. It’s worth noting that this doesn’t mean you have to use JavaScript; it simply means you should think about the flow your users take through your site and take every opportunity to remove the friction from the process of them accomplishing their goals.&lt;/p&gt;
&lt;p&gt;If you’ve built something, you probably want folks to find it. PWAs, by definition, are &lt;strong&gt;easy to discover&lt;/strong&gt;. Your site’s content should be written in such a way that it pops up organically when people search for related topics. Don’t get all spammy, but take care to author content in a thoughtful, appropriate, and straightforward way. &lt;/p&gt;
&lt;p&gt;Related to discoverability is that PWAs are &lt;strong&gt;linkable&lt;/strong&gt;. If your users can reach a certain point in your site via natural navigation, you should do your best to ensure they can save their place by bookmarking it or when they re-launch their web browser and your site’s tab is re-launched. This also plays into how shareable your project is. You may also want to do yourself a favor and spend some time putting together some &lt;a href=&quot;http://ogp.me/&quot;&gt;Open Graph &lt;code&gt;meta&lt;/code&gt; tags&lt;/a&gt; and some &lt;a href=&quot;https://json-ld.org/&quot;&gt;JSON-LD&lt;/a&gt; to make your content even more shareable.&lt;/p&gt;
&lt;p&gt;Last, but certainly not least, there’s &lt;strong&gt;network independence&lt;/strong&gt;. This is the big one that gets developers so excited. Offline capabilities and persistent storage has, to some extent, been possible for a while now; heck, Microsoft debuted &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ms531424(v=vs.85).aspx&quot;&gt;client-side data storage back in 1999&lt;/a&gt;! Alas, while client side data stores–&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/IndexedDB_API&quot;&gt;IndexedDB&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Storage/LocalStorage&quot;&gt;&lt;code&gt;localStorage&lt;/code&gt;&lt;/a&gt;, etc.–have definitely come of age in the last few years, &lt;a href=&quot;https://alistapart.com/article/application-cache-is-a-douchebag&quot;&gt;true control over resource caching has been pretty abysmal&lt;/a&gt;. Then came &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Service_Worker_API&quot;&gt;Service Workers&lt;/a&gt; and the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Cache&quot;&gt;Cache API&lt;/a&gt;. These two technologies work in concert with the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Fetch_API&quot;&gt;Fetch API&lt;/a&gt; to make, intercept, augment, and store resource requests made from within your site, meaning your users may still access your content, even if their network connection is interrupted.&lt;/p&gt;
&lt;p&gt;There are a ton of fantastic resources covering the ins and outs of Service Workers, so I’m going to skip the technical stuff and just talk about some of the neat things you can do with them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://googlechrome.github.io/samples/service-worker/prefetch/index.html&quot;&gt;Prefetch and cache resources&lt;/a&gt; you know your users are going to need. This can improve performance dramatically.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://googlechrome.github.io/samples/service-worker/read-through-caching/index.html&quot;&gt;Cache every page and asset&lt;/a&gt; requested by your site so they don’t need to be retrieved from the server each time a new page is loaded. This improves performance on navigation as well as on return visits.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://googlechrome.github.io/samples/service-worker/custom-offline-page/index.html&quot;&gt;Define a custom “offline” page.&lt;/a&gt; This prevents users from seeing the browser’s generic “You’re not connected” message.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://googlechrome.github.io/samples/service-worker/fallback-response/index.html&quot;&gt;Look for a network connection first&lt;/a&gt; and provide the “live” copy of a given resource if it’s available, falling back to a previously cached “stale” version if it’s not. This can also prevent users from seeing “You’re not connected” messages.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.deanhume.com/Home/BlogPost/service-workers--dynamic-responsive-images-using-webp-images/10132&quot;&gt;Respond to requests for JPEG images with WebP&lt;/a&gt; (which tend to be considerably smaller) versions of those images if the browser supports them. This strategy allows you to provide alternate image sources that improve performance &lt;em&gt;without&lt;/em&gt; having to modify your markup.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Service Workers are capable of a whole lot more—some of which I will get into shortly—and are on track to be granted many more incredibly useful features in the not too distant future. They have already proven their worth and bring value to any project on the web. For a useful list of recipes, check out &lt;a href=&quot;https://serviceworke.rs/&quot;&gt;this cookbook from Mozilla&lt;/a&gt; or &lt;a href=&quot;https://github.com/GoogleChrome/samples/tree/gh-pages/service-worker&quot;&gt;this one from the Chrome team&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Other PWA benefits by project type&lt;/h2&gt;
&lt;p&gt;Now that we’ve looked at the universally-beneficial qualities of PWAs, let’s shift gears. Every project is different, but there are a handful of archetypes that most web projects tend to fall into. And each of those archetypes can derive real benefits from running as a PWA.&lt;/p&gt;
&lt;h3&gt;Informational&lt;/h3&gt;
&lt;p&gt;When I think about informational sites, I’m talking about the kinds of sites many of us in the industry refer to as “brochureware.” Vanity sites are a good example of this. Small business sites whose interactivity tops out at a contact for or a phone number link are another. Portfolios would also fall into this category as would many restaurant sites.&lt;/p&gt;
&lt;p&gt;In most cases, projects like these are there to serve folks wanting to know more about you, your business, a project, or something similar. In most cases, you’re not going to see a ton of repeat visits. Folks come to the site looking to find out a specific piece of information—which hopefully they can access quickly and easily—and they’re off again. They might return, but they might not, meaning the  performance gains provided by a Service Worker’s offline caching could be useful, but likely won’t have quite the level of impact it would have on a site that gets frequent repeat visits. It’s also highly unlikely—though not impossible—that someone will actually install a project like this.&lt;/p&gt;
&lt;p&gt;Depending on the type of site you’re building, you might consider integrating some device APIs. If the site is for a brick-and-mortar business, add &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Geolocation&quot;&gt;Geolocation&lt;/a&gt; support. If you have sales or specials you’d like to inform your visitors about, you might consider integrating Notifications (either &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Notifications_API/Using_the_Notifications_API&quot;&gt;Web&lt;/a&gt; or &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Push_API&quot;&gt;Push&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Even though two of the oft-touted “major” benefits of being a PWA—install-ability and offline capability—are less applicable for informational sites, making projects like these a PWA is still beneficial. Those are just two aspects of being a PWA. Your users will thank you for building a site that works on every one of their devices, is easy to use, comes up in search, and is easily shared with their friends.&lt;/p&gt;
&lt;h3&gt;Periodical&lt;/h3&gt;
&lt;p&gt;Periodical sites encompass everything from a blog or newsletter or podcast to online comics, magazines, newspapers, and video programs. These sorts of projects are like informational projects, but are updated regularly (or semi-regularly). They also have an audience that is likely to return (ahem) periodically to read a new article, watch a new video, or listen to a new podcast episode. Since they share much of their DNA with informational sites—heck, a periodical may even be part of an informational site—all of the qualities that benefit informational sites benefit periodicals as well. There are, however, some capabilities that PWAs offer that periodicals are perfectly suited to take advantage of.&lt;/p&gt;
&lt;p&gt;In discussing promotions or specials, I mentioned that &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Push_API&quot;&gt;Push Notifications&lt;/a&gt; could be an option for informational sites. They should be a given for a periodical site. Push Notifications provide a mechanism for your server to send an update to any instances of your Service Worker that are installed on your users’ machines. And, assuming they’ve granted you permission, those updates can be displayed to your users even if they don’t have your PWA installed or a browser tab open to your site.&lt;/p&gt;
&lt;p&gt;Don’t take this as an opportunity to spam your users, as you’ll likely lose their eyeballs and business. Instead, choose appropriate times to ping them. If your site only gets updates once or twice a week, notifying them of individual posts is probably good and can provide a nice alternative for folks who don’t use a feed reader. If you have frequent updates, consider a daily or weekly roll-up. This might even be a good candidate for some A-B testing.&lt;/p&gt;
&lt;p&gt;You could also up your game by offering an easy in-page tool for saving an article for offline reading. Why would you want to do that rather than caching everything the user ever sees using the Service Worker? Well, given the nature of a periodical, the reuse of individual content items is likely pretty low. If you cache everything the use ever sees—especially if your content contains a lot of high resolution images—you’re gonna be filling their cache up with stuff they may never want to see again. In order to be a good web citizen, you could either clean that up regularly by keeping track of the last time a resource was accessed (which, frankly, seems like a lot of work) or you could cache just the necessary long-lived resources like your CSS and JavaScript files. Then you can put your users in control by providing &lt;a href=&quot;https://una.im/save-offline/&quot;&gt;a button&lt;/a&gt; that enables them to save an entry for later.&lt;/p&gt;
&lt;p&gt;Continuing our journey through Service Worker land, you could start exploring &lt;a href=&quot;https://github.com/WICG/BackgroundSync/blob/master/explainer.md&quot;&gt;Background Sync&lt;/a&gt; to pull in new resources periodically. If you’re a newspaper, maybe you want to prime your users’ caches every morning with the front page and the top feature stories. If you’re a podcast, maybe you want to load in the newest episode on a regular cadence. Again, to play nicely in the sandbox, you’ll probably want to trash older articles, episodes, and so on, but this could be a great way to provide an incredibly fast experience for your users. Think about it … they launch your site and the browser already has everything it needs to render today’s issue. Magic!&lt;/p&gt;
&lt;p&gt;Finally, periodicals are one of those archetypes where the option to install your site begins to make sense. Some people like being able to hit an icon on their home screen or in the Start Menu to access their local newspaper. It’s not for everyone and may not be right for every periodical, but it’s an option. And offering your users the ability to install your PWA comes for free, so you may as well embrace it and make sure your &lt;a href=&quot;http://www.w3.org/TR/appmanifest/&quot;&gt;Web App Manifest&lt;/a&gt; has been thoughtfully authored to provide a good user experience when your PWA is installed.&lt;/p&gt;
&lt;h3&gt;Transactional&lt;/h3&gt;
&lt;p&gt;Any site that facilitates the exchange of information could be considered transactional. The most common examples include online shops, banking and stock trading tools, travel booking systems, and payment portals. PWAs have, to a large extent, already proven their value in this area. A quick peek on &lt;a href=&quot;https://www.pwastats.com/&quot;&gt;PWA Stats&lt;/a&gt; revealed the following “wins”:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.pwastats.com/2017/07/raphael-hotel/&quot;&gt;The Raphael Hotels&lt;/a&gt;&lt;/strong&gt; increased website conversions by 20%, pageviews by 66%, sessions by 59%, and reduced bounce rate 51%.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.pwastats.com/2017/05/makemytrip/&quot;&gt;MakeMyTrip&lt;/a&gt;&lt;/strong&gt; saw a 3× increase in conversion and 160% increase in shopper sessions and first-time shoppers are 3× more likely to convert on the PWA than in native app.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.pwastats.com/2017/05/lancome/&quot;&gt;Lancôme&lt;/a&gt;&lt;/strong&gt; saw a 17% increase in conversions, a 51% increase in mobile sessions overall and a 53% increase on iOS alone.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The kicker on that last one? iOS doesn’t even support Service Workers!&lt;/p&gt;
&lt;p&gt;It’s well-known that &lt;a href=&quot;https://blog.kissmetrics.com/speed-is-a-killer/&quot;&gt;improving page performance increases conversions&lt;/a&gt;, so the speed improvements granted by a smart caching and offline strategy with Service Workers are incredibly important here. But there are numerous other ways PWAs can benefit transactional sites as well.&lt;/p&gt;
&lt;p&gt;Since I mentioned offline, I’ll add that your offline strategy should not begin and end with Service Workers. For a while now, we’ve used cookies to track transactional data shopping cart contents, but cookies have always been severely limited in terms of the amount of data they can store because they get sent along with every network request. With &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/IndexedDB_API&quot;&gt;IndexedDB&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Storage/LocalStorage&quot;&gt;&lt;code&gt;localStorage&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Window/sessionStorage&quot;&gt;&lt;code&gt;sessionStorage&lt;/code&gt;&lt;/a&gt;, we have the ability to store more (and richer) data about the transaction taking place on the client side. Storing this information on the client makes it easier to recover from problems like a network loss. If a transaction fails, you will still have access to the data (which might have otherwise been lost in a failed POST) and you can either periodically try the transaction again or wait until you see the network is back before submitting it. Either way, adding real-time messaging about what’s going on and how you are working to resolve it will go a long way toward assuring your users that their data is not lost.&lt;/p&gt;
&lt;p&gt;If your project is highly transactional, you will definitely want to look at &lt;a href=&quot;https://github.com/WICG/BackgroundSync/blob/master/explainer.md&quot;&gt;Background Sync&lt;/a&gt; as a means of keeping your users’ local data in sync with server data. For example, if you are building a banking system, synchronizing information like recent transactions and current balances will be incredibly useful to your customers. Same goes with current stock prices and balances if you’re working on a trading platform.&lt;/p&gt;
&lt;p&gt;In most transactional scenarios, notifications can be quite helpful. Borrowing on the scenario I mentioned earlier, notifications can be used to let someone know when their transaction has completed (after all, in a PWA you could complete the transaction during a Background Sync when your site isn’t running). Notifications come in a two flavors: &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Notifications_API/Using_the_Notifications_API&quot;&gt;Web Notifications&lt;/a&gt; are triggered via JavaScript in an active page, &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Push_API&quot;&gt;Push Notifications&lt;/a&gt; are sent from the server and can be delivered even when the site isn’t open. Depending on the scenario, one or the other will probably make more sense. Just be aware that Push Notifications are &lt;a href=&quot;http://caniuse.com/#search=notifications&quot;&gt;not as well supported&lt;/a&gt; as Web Notifications … yet.&lt;/p&gt;
&lt;p&gt;For transactional sites that are frequently accessed (and I realize “frequently” is a very relative term) the install-ability of a PWA is a huge win. Isolating your site within its own app container allows users to focus on the task at hand, without the distraction of other tabs. It also insulates the processes running your code from the process running all of the sites they have open in their browser. Additionally, it has less overhead since there’s no browser chrome running alongside it. All of these benefits work together to create a streamlined, frictionless experience for your users.&lt;/p&gt;
&lt;p&gt;Once installed, many operating systems will grant your project access to internal APIs. Perhaps you want to let them choose an address to ship a gift to, from their contacts. Or maybe you want to enable them to add the flights they just booked directly to their calendar. Or perhaps you want to voice-enable your app by integrating with their virtual assistant. All of those scenarios become possible in the context of a PWA, which is a huge boon for transactional websites.&lt;/p&gt;
&lt;h3&gt;Social&lt;/h3&gt;
&lt;p&gt;Social websites—think Twitter, Facebook, etc.—are excellent candidates for PWA-ification. In fact, &lt;a href=&quot;https://lite.twitter.com/&quot;&gt;Twitter has already gone that route&lt;/a&gt;. Social sites combine aspects of periodical and transactional websites, so they naturally inherit many of the benefits of those archetypes. &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Push_API&quot;&gt;Push Notifications&lt;/a&gt;, in particular, are incredibly important for sites like this, as re-engagement is crucial for the long-term success of your platform. Install-ability is also important in that regard.&lt;/p&gt;
&lt;p&gt;Performance, especially initialization speed, is going to be an important benchmark for social projects, as users will not sit around waiting for all of their feed items (and their associated imagery, videos, etc.) to load. Caching your site’s assets will help a bit, but—depending on your project goals and situation—you might consider using &lt;a href=&quot;https://github.com/WICG/BackgroundSync/blob/master/explainer.md&quot;&gt;Background Sync&lt;/a&gt; to update your users’ news feeds so they are ready to go (or close to it) the next time they open it up.&lt;/p&gt;
&lt;p&gt;As transactional projects, social websites will also benefit from access to device and system APIs when installed. Most social networks, for example, request permission to peruse your Contacts to look for friends and colleagues that are also using the service. If you go that route, it’s imperative that you don’t abuse the privilege by trying to trick your users into spamming their friends with info about your service. If we don’t respect our users and their private information, we run the risk of losing access to it (and them) altogether.&lt;/p&gt;
&lt;h3&gt;Software&lt;/h3&gt;
&lt;p&gt;When we talk about “web apps,” often online software is what naturally comes to mind. Some examples include email clients, accounting tools, project management suites, version control systems, and photo editors. In many ways, these are software in the traditional sense, they just exist on the web instead of being installed locally … until now.&lt;/p&gt;
&lt;p&gt;Through the magic of PWAs, these software-as-a-service projects can become full-fledged desktop (and mobile) applications. This enables teams that have gone all-in on web technologies to continue (or even increase) their investment in that area without sacrificing the  convenience of install-ability on native platforms. Sure, there are absolutely some solid reasons why you might want to customize a native experience for your software, but for the vast majority of cases the web offers everything necessary to run your application … that’s why it’s on the web in the first place.&lt;/p&gt;
&lt;p&gt;Offline data stores, background synchronization, and file system access help to elevate the experience for your users, making this archetype the most obvious beneficiary from Progressive Web Apps.&lt;/p&gt;
&lt;h3&gt;Institutional&lt;/h3&gt;
&lt;p&gt;Some projects are, frankly, too sprawling to fall neatly into one archetype or another. I’m thinking of schools, large corporations, mammoth financial institutions. These projects are often an amalgam of many or all of the archetypes I’ve covered here. As such, all of the benefits accrued to those archetypes apply, in context of course.&lt;/p&gt;
&lt;p&gt;When looking at a large institutional project, it can be difficult to figure out how to assemble an overarching strategy for turning it into a PWA. The good news is that you don’t necessarily have to. You can carve up your project into many individual PWAs that can exist independently.&lt;/p&gt;
&lt;p&gt;Take, for example, an online learning system. You could create a PWA for the learning system itself, but you could also carve off each individual course as its own, installable PWA, with its own cache, notifications, etc. The reason you can do this is that Service Workers and Web App Manifests can be scoped. You can scope them to a specific hostname or you could even scope them to a specific path within your URL structure. While obviously more complicated, if you think of each of those courses as having a course template and you think of a Web App Manifest and Service Worker being part of that template, it becomes easier to wrap your head around.&lt;/p&gt;
&lt;h2&gt;It’s your turn&lt;/h2&gt;
&lt;p&gt;Progressive Web Apps may seem overly technical or beyond the needs of your project, but they’re really not. They’re just a shorthand for quality web experiences—experiences that can absolutely make a difference in our users’ lives. If you hadn’t considered building a PWA before, I hope this article has changed your mind. And if you’re already neck-deep in Service Workers, perhaps it’s given you some ideas for new ways to approach the projects you’re working on.&lt;/p&gt;
</description><link>https://alistapart.com/article/yes-that-web-project-should-be-a-pwa/</link><guid isPermaLink="false">https://alistapart.com/article/yes-that-web-project-should-be-a-pwa/</guid><pubDate>Wed, 30 Aug 2017 18:30:00 GMT</pubDate><author>brandongregory</author><category>Application Development</category></item><item><title>Web Maintainability Industry Survey: How Do We Maintain?</title><description>&lt;p&gt;How often do we consider the maintenance and general maintainability of our websites and apps? What steps do we actively take to make and keep them maintainable? What stands in the way when we maintain our and other people’s projects?&lt;/p&gt;
&lt;p&gt;Many of us, as web developers, know very well how to code something. But whether we know just as well how to maintain what we—and others—have written, that is not so clear. Our bosses and clients may not always think about maintenance down the road, either.&lt;/p&gt;
&lt;p&gt;As an &lt;a href=&quot;http://www.oreilly.com/pub/au/6348&quot;&gt;O’Reilly author&lt;/a&gt; and former Googler, I’ve been &lt;a href=&quot;https://cse.google.com/cse?cx=007435340685329731950%3Auo6twvdbp_m&amp;amp;q=maintainability#gsc.tab=0&amp;amp;gsc.q=maintainability&quot;&gt;studying the topic of maintainability&lt;/a&gt; since 2008—and we have yet to gather our industry’s views on the subject. To help us all get a better picture of &lt;em&gt;how&lt;/em&gt; we maintain and how we can maintain &lt;em&gt;more effectively&lt;/em&gt;, I set up a &lt;a href=&quot;https://docs.google.com/forms/d/e/1FAIpQLSe8HjnEoVFBevk80_MKH2Te5SmAs8p6cJbdQWVgC1V-OorMUw/viewform&quot;&gt;brief, unassuming survey&lt;/a&gt; (&lt;a href=&quot;https://meiert.com/en/blog/20170514/maintainability-survey/&quot;&gt;announcement&lt;/a&gt;) and kindly ask for your assistance.&lt;/p&gt;
&lt;p&gt;The survey aims to collect specific practices and resources—in other words, your views on current practices (both useful and harmful) and everything you find helpful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What helps maintenance?&lt;/li&gt;
&lt;li&gt;What prevents maintenance?&lt;/li&gt;
&lt;li&gt;What resources do developers turn to for improving maintainability?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The outcome of the survey and an updated guide to web maintainability will be published in a few weeks on &lt;a href=&quot;https://meiert.com/en/&quot;&gt;my website, meiert.com&lt;/a&gt; (and noted on &lt;a href=&quot;https://twitter.com/j9t&quot;&gt;my Twitter profile&lt;/a&gt;). Thank you for your support.&lt;/p&gt;
</description><link>https://alistapart.com/article/web-maintainability-survey/</link><guid isPermaLink="false">https://alistapart.com/article/web-maintainability-survey/</guid><pubDate>Tue, 16 May 2017 16:05:00 GMT</pubDate><author>mmcpheeters</author><category>Application Development</category><category>Industry &amp;amp; Business</category><category>Process</category></item></channel></rss>