<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jamund Ferguson</title>
    <description>The latest articles on DEV Community by Jamund Ferguson (@xjamundx).</description>
    <link>https://dev.to/xjamundx</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F614779%2Fefa75882-14f4-46cb-aeb1-81bb9ab040fb.jpg</url>
      <title>DEV Community: Jamund Ferguson</title>
      <link>https://dev.to/xjamundx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xjamundx"/>
    <language>en</language>
    <item>
      <title>UI Code is Throwaway Code, Always Has Been</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Sun, 22 Mar 2026 16:05:43 +0000</pubDate>
      <link>https://dev.to/xjamundx/designing-for-throwaway-ability-in-the-ai-coding-era-1b9p</link>
      <guid>https://dev.to/xjamundx/designing-for-throwaway-ability-in-the-ai-coding-era-1b9p</guid>
      <description>&lt;p&gt;The most impactful engineering leader I ever worked with was a guy named Bill Scott who led UI engineering at PayPal. What I loved about Bill was his constant enthusiasm for new technology. He helped lead the charge to take PayPal's old C++ and Java stack and modernise it into Java microservices and Node.js for the front end. And just absolutely surrounded himself with people who were looking for ways new technology could be used to create better experiences for our customers and improve the lives of developers.&lt;/p&gt;

&lt;p&gt;If he were still with us today, I think he would absolutely love the AI revolution taking place in software development right now. &lt;/p&gt;

&lt;p&gt;When I was interviewing at PayPal back in 2013 I spoke with him a an influential blog that he'd written called &lt;a href="https://looksgoodworkswell.blogspot.com/2012/04/experimentation-layer.html" rel="noopener noreferrer"&gt;The Experimentation Layer&lt;/a&gt;. Reflecting on his time at Netflix, he was pushing back against the cult of reusability in software development and talked about designing for throwaway-ability instead. He was a huge proponent of &lt;a href="https://www.oreilly.com/library/view/lean-ux-2nd/9781491953594/" rel="noopener noreferrer"&gt;Lean UX&lt;/a&gt; and A/B testing. In the article he mentioned that in his time at Netflix, after something like a year, only 10% of the front end code stayed the same. It was constantly being optimised and improved to deliver better outcomes for their viewers. &lt;/p&gt;

&lt;p&gt;He wasn't anti-reusability. He wrote an entire book about building reusable components for UIs. One that was extremely important to me as an early engineer coming up in the jQuery UI era through the HTML5 transition and the death of Flash. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjmxcmc0aw4wyu6rh2yp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjmxcmc0aw4wyu6rh2yp.png" alt="Designing Web Interfaces book from O'Reilly" width="800" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But regardless, it made me a little bit annoyed. It put me off. I had just come from a role where, for the past two years at oDesk, I had been building reusable component libraries. And so we sparred a bit, gently, in the interview. And he helped me understand where he was coming from. &lt;/p&gt;

&lt;p&gt;The goal is to build the best experiences for users as quickly as possible. Not being afraid to experiment and try new things, especially when the status quo isn't working. The biggest thing in his philosophy was just constantly getting user feedback and making sure that what you're putting out in front of users is actually working for them. And making sure that you have the infrastructure needed to iterate frequently and measure and observe your successes and failures. The other lesson that I've taken from that time is not to be married to my code. It's just code. It's an experiment. And it's okay if we decide to throw it away. &lt;/p&gt;

&lt;p&gt;The calculus of how "throwaway-able" your code needs to be depends on where it lives in the stack. He uses this funnel to illustrate the volatility of different parts of the software stack:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8txhqt122bpscj825j3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8txhqt122bpscj825j3l.png" alt="A funnel diagram to demonstrate different parts of the software stack" width="326" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're looking at a modern React application, you might think of it like this instead: &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4ntz0770ja31mv2vxpy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4ntz0770ja31mv2vxpy.png" alt="A modern React application designed as a building structure" width="674" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In modern client-side React architecture, there are places that we need to be more careful about changes than others. But there are places in a large codebase that ultimately don't matter so much. I think for many people, for better or worse, if a bunch of Tailwind CSS classes change in the code for a component used in only one place, you're not really bothered about it as long as the thing looks like it's supposed to look. &lt;/p&gt;

&lt;p&gt;In a different context, you can also think about which features are likely to be sort of permanent and which features are temporary, like landing pages, right, or some kind of feature-flagged experiment you don't expect to really make it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Death of the Code Review
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr03zrncpvwd6ed3uhelc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr03zrncpvwd6ed3uhelc.png" alt="Let the slop flow through you, meme" width="499" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's been a lot of talk lately about &lt;a href="https://www.latent.space/p/reviews-dead" rel="noopener noreferrer"&gt;the death of the code review&lt;/a&gt;. I think it's premature, at least for teams supporting real codebases with real users. If we use Bill Scott's framework for determining which code is likely to change frequently or should be designed for throw-away ability, I think that can help us understand where it might be OK for a little "slop" to enter our application without looking too hard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99e07qdtgw3wgu6s9hlc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99e07qdtgw3wgu6s9hlc.png" alt="Modified diagram of React application architecture, suggesting that the slot can live on the roof" width="674" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The way forward with this deluge of AI-generated code isn't to avoid reviewing it; it's figuring out where human review matters the most. &lt;/p&gt;

&lt;h2&gt;
  
  
  Anticipating UI Engineering's Future
&lt;/h2&gt;

&lt;p&gt;Today, I asked Claude if it wanted to play a game, and it generated one and let me play it, right in the chat interface. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8jz1kbkybfgxkbkih3h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8jz1kbkybfgxkbkih3h.png" alt="Playing a memory game with Claude" width="800" height="706"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Other companies like Vercel and Cloudflare are talking about similar things. &lt;a href="https://sunilpai.dev/posts/after-wimp/" rel="noopener noreferrer"&gt;Sandboxes and "code mode"&lt;/a&gt; and &lt;a href="https://json-render.dev/" rel="noopener noreferrer"&gt;generative UIs&lt;/a&gt;. There are also &lt;a href="https://modelcontextprotocol.io/extensions/apps/overview" rel="noopener noreferrer"&gt;MCP apps&lt;/a&gt; and &lt;a href="https://developer.chrome.com/blog/webmcp-epp" rel="noopener noreferrer"&gt;WebMCP&lt;/a&gt;, which are all different ways to allow AI agents to essentially bypass the UI layer created by devs and show something else to the user instead, something custom, something just for them. Dynamic AI-generated user interfaces are likely coming one way or another, and that UI code likely isn't going to be reviewed by humans.&lt;/p&gt;

&lt;p&gt;Even so, I'm pretty certain the architecture underlying those future interfaces will be reviewed and tested very carefully by human reviewers. Nobody wants to build their house on foundation of slop. But the "experimentation layer" part, the part of the code we're less fussed about. I'm pretty sure that part is going to get a whole lot bigger.&lt;/p&gt;




&lt;p&gt;RIP Bill. You were a real one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1zq7izpa2lfyh4ibrjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1zq7izpa2lfyh4ibrjf.png" alt="Bill Scott" width="219" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>coding</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Code Review Kinda Sucks Now</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Sun, 15 Mar 2026 15:09:53 +0000</pubDate>
      <link>https://dev.to/xjamundx/some-thoughts-on-code-review-in-the-ai-age-part-1-2k3m</link>
      <guid>https://dev.to/xjamundx/some-thoughts-on-code-review-in-the-ai-age-part-1-2k3m</guid>
      <description>&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; Code review was never just about finding bugs. We need better tools to help us make sure we don't lose the understanding of our codebases as the rate at which they grow increases with AI.&lt;/p&gt;




&lt;p&gt;Recently, I was really impressed by an article posted on X by &lt;a href="https://x.com/elmd_" rel="noopener noreferrer"&gt;Dominic Elm&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/elmd_/status/2032542113297031307" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fennz4q54bzoxfghjeqrz.png" alt=" " width="644" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In particular, this quote absolutely drew me in:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Code review was never really about catching bugs. It was about building shared understanding, a team's collective mental model of what the system does, why it works that way, and how it can safely change&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The article went on to detail all the challenges with AI making it so easy to generate code but not review it he had a couple of conclusions at the end, which I'll summarise here. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Make sure to apply AI code review right away, so humans can focus on the more important architectural issues. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Review AI-generated code with a different lens in mind than human-generated code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Put more emphasis on the author proving they understand their own code. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I thought these were fantastic and just wanted to add a few more ideas to that based on my own experience. &lt;/p&gt;

&lt;h2&gt;
  
  
  Code Review as Team Sport
&lt;/h2&gt;

&lt;p&gt;The quote about code review being for shared understanding that resonated with me so much reminded me of this &lt;a href="https://web.archive.org/web/20160305095953/https://www.box.com/blog/effective-learning-through-code-workshops/" rel="noopener noreferrer"&gt;incredibly hard to find blog post&lt;/a&gt; by Nicolas C. Zakas  (thank you, Internet Archive). Nicolas is the creator of ESLint and a prolific JavaScript author. The article is called "&lt;a href="https://web.archive.org/web/20160305095953/https://www.box.com/blog/effective-learning-through-code-workshops/" rel="noopener noreferrer"&gt;Effective learning through code workshops&lt;/a&gt;"&lt;/p&gt;

&lt;p&gt;What he describes in the beginning is the way code reviews were performed, at very serious companies, before GitHub and similar tools for async review became popular. Code reviews were literally meetings where the team would review code that had been printed out on pieces of paper. Everyone would be in there looking for bugs by hand. Writing notes with pens and pencils. With the person who wrote the code often looking quite uncomfortable and nervous, receiving all this negative feedback. That approach obviously couldn't scale and was eagerly replaced by the async code review model that was likely made popular with the proliferation of open source and GitHub. &lt;/p&gt;

&lt;p&gt;Nicolas took that old school approach and tried to modernise it for Box. He called them "code review workshops". Where weekly someone would be assigned to look at code that they didn't write and explain it to the team. And the whole team walks through that code together and identifies patterns and practices that they like and dislike, and makes notes for future improvement. Confusing code is really easy to notice and dissect in this type of meeting. Context is shared with the team. You're not reviewing a single pull request with the whole group; but usually it's a feature or file that might have been contributed to by multiple individuals. &lt;/p&gt;

&lt;p&gt;When I was at PayPal, I had a fantastic engineering manager named Rose Elliot, who used this technique as a way to strengthen and uplevel our team. &lt;/p&gt;

&lt;p&gt;It was a great way for people to learn about parts of the codebase that weren't theirs. And it promoted a culture where we were continually improving and documenting our code and best practices. During each session, we would make notes about what we wanted to change, and create issues in our task management system to follow up on those changes. We still leaned into asynchronous code reviews. We also spent a lot of time on linting and automating the identification of common mistakes. But taking the time to review code together regularly helped us build a shared understanding of both how things worked today and what we wanted our app to look like in the future. &lt;/p&gt;

&lt;p&gt;One thing I like about this approach is that it doesn't slow down progress in the sense that you have to wait for an in-person code review meeting to get the code merged or even shipped to production. But it provides a feedback mechanism to the whole system to make sure that you're going in the right direction and keeps everyone more informed.&lt;/p&gt;

&lt;p&gt;I don't know if this is the solution for dealing with the massive amount of code that we're getting in this AI/agentic-engineering era, but it feels like it could help. &lt;/p&gt;

&lt;h2&gt;
  
  
  Reducing Cognitive Load
&lt;/h2&gt;

&lt;p&gt;Reviewing giant pull requests is never easy. And the code review article from Dominic goes into various stats on how the longer the pull request, the more likely a reviewer is to make mistakes or just gloss over it without giving any real feedback. This should pretty relatable for most devs. So how can we reduce the cognitive load for reviewers? &lt;/p&gt;

&lt;h3&gt;
  
  
  Smaller Pull Requests
&lt;/h3&gt;

&lt;p&gt;In the article, it was described that smaller pull requests help reduce cognitive load. And there was something mentioned about a code review tool called &lt;a href="https://graphite.com/" rel="noopener noreferrer"&gt;graphite&lt;/a&gt;, which uses an approach called &lt;a href="https://newsletter.pragmaticengineer.com/p/stacked-diffs" rel="noopener noreferrer"&gt;stacked diffs&lt;/a&gt;, to basically make it easier to look at the difference between individual commits and review them separately. It breaks down a complex pull request into smaller pieces that can be reviewed individually. It's a slightly different workflow than traditional GitHub pull requests, but it's backward compatible and looks promising. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa40gqkahmxu3bpi4vukr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa40gqkahmxu3bpi4vukr.png" alt=" " width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Outside of using a separate tool, I found recently when using Claude Code, instead of executing one large plan it can help to break down your work into smaller plans. So we talked through the work that needed to be done, created a large plan. I saved that to the side and then had Claude execute smaller individual plans and committed the results each time or in some cases made pull requests for each (smaller) implementation separately. Just because Claude can do a whole bunch of stuff at once doesn't mean you shouldn't break it down into easily understandable chunks. &lt;/p&gt;

&lt;h3&gt;
  
  
  Diagrams and Documentation
&lt;/h3&gt;

&lt;p&gt;One of the big suggestions in Dominic's article was asking the reviewer to include diagrams in their pull requests so that they could sort of prove that they understood the system impact of their code changes. I've been thinking a lot about how diagrams and visual representations of code can help us more quickly grasp what's going on. Line-by-line diffs are really hard to reason about and it's clear that more advanced semantic diffing and visual diffing can help us understand these things more quickly. But one thing I found interesting was he said at his work, people just use AI to generate the diagrams, and it didn't really help very much. Developers weren't actually internalising what was happening. &lt;/p&gt;

&lt;p&gt;Similarly, &lt;a href="https://x.com/mikeysee" rel="noopener noreferrer"&gt;Mikey See&lt;/a&gt; from Convex, tried to use nine different code review tools and &lt;a href="https://x.com/mikeysee/status/2031493811369877698" rel="noopener noreferrer"&gt;made a video with his results&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotp38ly13degynb1bgjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotp38ly13degynb1bgjl.png" alt=" " width="627" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the tools called Sorcery AI, automatically include diagrams with every pull request. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgfzosy37nhkuw58bf4wx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgfzosy37nhkuw58bf4wx.png" alt=" " width="765" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've been fairly convinced that this kind of thing will really help engineers better understand what's happening in code changes. But in the review, he just said it was noise and it was just completely ignored, every single time.&lt;/p&gt;

&lt;p&gt;Is there room for this kind of tool and graph automatic diagram generation? I think so. I think that we just haven't found the right place for it yet. One suggestion might be to essentially automatically include documentation with code. Again, with the emphasis that even though humans maybe didn't write the code, hopefully they'll be like a README file, say, with each component or each feature folder that can have some really good details about how it works and what's going on so humans can get up to speed very quickly.&lt;/p&gt;

&lt;p&gt;With React components, it would be super easy for AI to always create storybook examples for every single component you do, and then maybe we could even render those storybooks directly in the code review. Right? What if you could actually see the component right there alongside the code. &lt;/p&gt;

&lt;h3&gt;
  
  
  Semantic Diffs &amp;amp; Code Graphs
&lt;/h3&gt;

&lt;p&gt;I can still think of a lot of use cases for visuals and graphs that could help, even if the current implementations aren't that useful. Even just imagine a simpler way of looking at a diff between, let's say, two React components. The things that matter the most are prop changes, state changes, hook changes. Clearly line by line diffs aren't that useful here. Are we changing the types of the props? Are we changing how we're managing state? Is there a better way we could visualise that? Outside of React thinking about, say, a function, the inputs and outputs are the things that matter the most right, especially if the function is well tested. Can we surface that more clearly? &lt;/p&gt;

&lt;p&gt;I gave a talk ten years ago at UtahJS where I spoke about using abstract syntax trees to analyse your code systematically. And one of the examples I gave is using ASTs to generate meaningful diffs. &lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8uOXIM4giH8" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fha6f95bzkiuloc7bziph.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's a tool called &lt;a href="https://github.com/scinapse-labs/sem" rel="noopener noreferrer"&gt;Sem&lt;/a&gt; that I recently found that applies some of these approaches. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqti2mau9fycpgz3trhco.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqti2mau9fycpgz3trhco.png" alt=" " width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine something like this, but with arrows and colour coding and everything to make it really obvious what the type looked like before and what the type looked like after. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0xr8n3ffm3t7fupfva0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0xr8n3ffm3t7fupfva0.png" alt=" " width="317" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AI code review right now can help somewhat with basically fancier linting, and potentially matching architectural patterns, but AST-based diffs and semantic diffing might help us highlight the things that matter more in diffs, so that humans can more quickly grok what's going on. This is absolutely going to be necessary in the future if we're going to keep ahead of all this mountain of AI-generated code. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Maps &amp;amp; Blast Radius Detection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We're also seeing some movement around graphing code and understanding the blast radius of a change. I think this is also really interesting because, to some extent, with AI code review there might be parts of the code that we really don't care what the details are. Imagine there's a small feature not on a critical path. It might be good to know that no matter what's in this code, it's not going to affect anything else. Tools like that might help us narrow the scope of what human code review needs to look like, or at least emphasise where we really should pay attention to a code change. &lt;/p&gt;

&lt;p&gt;There's a tool going on right now called &lt;a href="https://github.com/abhigyanpatwari/GitNexus" rel="noopener noreferrer"&gt;GitNexus&lt;/a&gt; that attempts to do that, but I'm sure there are others as well. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxswv81arlioxnpvdnq46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxswv81arlioxnpvdnq46.png" alt=" " width="800" height="661"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitKraken also offers "mode maps" and other visualizations:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgomgm4jst1vf3jfz7c81.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgomgm4jst1vf3jfz7c81.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Code review kind of sucks right now. It's so easy to generate code that looks good. But it's hard to wrap our heads around the impact of those changes. We need to adopt better processes and tools to help our engineers quickly get up to speed in understanding the changes happening in our codebases.&lt;/p&gt;

&lt;p&gt;Here are a couple of suggestions that build on Dominic's article that I think might help.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We should take another look at Team Code Review workshops. With AI doing most of the coding these days, who's going to get offended if you don't like their implementation? Let's do it. Modified for the hybrid and remote workplace, of course. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We need to keep down the size of our code reviews, &lt;a href="https://graphite.com/guides/stacked-diffs" rel="noopener noreferrer"&gt;stacked diffs&lt;/a&gt; might be a real solution there. Or even just making sure your AI agents follow some simple guidelines on how frequently they commit changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We need better tools&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are literally dozens of VC-funded AI code review tools duking it out in the marketplace. While I think they are becoming even more essential at helping us find bugs in our apps, we need remember code review is also about "building shared understanding." These tools are not doing that and they really aren't trying to. We need new code review tools that focus on the other side of code review. Not just finding bugs, but helping the team understand what it is that they're putting into their codebase and guiding that massive flow of changes in the right direction.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codereview</category>
      <category>discuss</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>DIY Pre-Loading for Faster Data Fetching</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Fri, 17 Jun 2022 22:44:13 +0000</pubDate>
      <link>https://dev.to/xjamundx/diy-pre-loading-for-faster-data-fetching-24ka</link>
      <guid>https://dev.to/xjamundx/diy-pre-loading-for-faster-data-fetching-24ka</guid>
      <description>&lt;p&gt;If you're struggling with slow page load times in your React app, I want to show you a technique that can shave off hundreds of milliseconds.&lt;/p&gt;

&lt;p&gt;Here's how you can pre-load your data in the most optimal way without relying on any external dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, the problem
&lt;/h2&gt;

&lt;p&gt;We can break down the problem into three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React applications often end up in &lt;em&gt;large JavaScript bundles&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Many components rely on external data&lt;/li&gt;
&lt;li&gt;Data fetching &lt;em&gt;won't usually start&lt;/em&gt; until your JS bundle finishes downloading &lt;em&gt;and&lt;/em&gt; your components finish rendering&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a simple chart to help you visualize the problem. Look at how much happens before the data starts downloading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhbn413syiqtq6dn2u680.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhbn413syiqtq6dn2u680.png" alt="A timeline of critical elements for rendering your page showing html then js download then processing then data starting to load. following that we render data and then the page is ready." width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What we noticed in our app at Amazon was that components would fire off data fetching in a &lt;code&gt;useEffect&lt;/code&gt; while deeply nested in the component tree. That meant the fetch wouldn't &lt;em&gt;start&lt;/em&gt; until between &lt;code&gt;50&lt;/code&gt;ms and &lt;code&gt;250&lt;/code&gt;ms after our &lt;code&gt;ReactDOM.render()&lt;/code&gt; call. Furthermore, our huge JavaScript bundle took an additional 350ms (or more) to download and execute. Combining these together we saw a huge opportunity for improvement. &lt;/p&gt;

&lt;h2&gt;
  
  
  Measuring the Problem
&lt;/h2&gt;

&lt;p&gt;The Chrome Web Inspector provides a number of tools that should make it easy to figure out if you're affected by this problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check the Network Tab&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, find your main fetch call inside of the &lt;code&gt;Network&lt;/code&gt; tab. Then go to the &lt;code&gt;Timing&lt;/code&gt; section and look for "Started at". This shows how long it took us to send off our request after the page is loaded. &lt;em&gt;You want this number to be as low as possible&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bzdvdnotloue6wqoszn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bzdvdnotloue6wqoszn.png" alt="Reading the timing section of the network tab" width="546" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dive into the Performance Timeline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now run your app in the web performance inspector. Look at it carefully and see if you can recognize the problem:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9z7dhgkzgvyqc23dquu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9z7dhgkzgvyqc23dquu6.png" alt="Chrome Performance Inspector" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What you want to look for is your main app file and your main data fetch call. Here our app is bundled in a file called &lt;code&gt;vendor.f2843ed7.js&lt;/code&gt; and we're fetching data from &lt;code&gt;/api/slow/data&lt;/code&gt;. In this contrived example it takes around 200ms between the time vendor.js starts downloading and the time our fetch call begins. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvkls2qwri11yyaewf5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvkls2qwri11yyaewf5l.png" alt="Time wasted before fetching critical data" width="449" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The chart above highlights two specific blocks of time that we can mitigate to optimize performance of our data loading.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;The solution we came up with could be broken up into two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Kick off data fetching as early in our script as possible (i.e remove it from the React component lifecycle)&lt;/li&gt;
&lt;li&gt;Parallelize data fetching with loading our JavaScript bundle&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In order to accomplish the first of these we need some kind of global store. It doesn't need to be anything too fancy. In our case, we were already using redux, which we were able to dispatch actions to outside of the React tree as I'll demonstrate below.&lt;/p&gt;

&lt;p&gt;In their simplest form most of the network-dependent components looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// a simplified data loading example&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PageLevelComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDispatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dataLoaded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
   &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We ended up moving this &lt;code&gt;loadData()&lt;/code&gt; call into our root app file. The same one that starts rendering the react component tree. You'll notice we're still relying on redux to store the data, but we reference the &lt;code&gt;store&lt;/code&gt; directly for our dispatch method instead of getting it from context or hooks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// start loading data immediately and dispatch it to the redux store&lt;/span&gt;
&lt;span class="nf"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dataLoaded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;

&lt;span class="c1"&gt;// render the application with the same redux store&lt;/span&gt;
&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rootEl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After making that change you'll see that the data starts downloading only shortly after the JS starts executing. There's no longer a large delay.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzb0udgoso1lsdwdrs20l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzb0udgoso1lsdwdrs20l.png" alt="Data starts loading early in app execution" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this in place we asked ourselves if we could take it even further. The time to load our large JS bundle was clearly limiting how soon we were able to fetch our data. No matter how early we fired off the network request, the bundle still had to be downloaded and parsed before it was executed. Would it be possible to load our data in parallel with our JS somehow?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Optimization:
&lt;/h2&gt;

&lt;p&gt;Taking it to the next level required several clever steps to execute properly. First, we had to create a new &lt;code&gt;entry&lt;/code&gt; in our webpack config. We called it &lt;code&gt;preload.js&lt;/code&gt;. That &lt;code&gt;preload.js&lt;/code&gt; needed to be as small as possible. Ideally no Redux, no Axios, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preload.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this time we were still supporting IE11, which meant we would likely need to include a promise polyfill, a fetch polyfill of some kind and &lt;code&gt;URLSearchParams&lt;/code&gt;. In our case we were using Axios and ran into trouble when we didn't include that in both bundles, because of slightly different error handling and promise implementations. All of that ended up bumping our preload file to around 11kb minified. &lt;/p&gt;

&lt;p&gt;The contents of &lt;code&gt;preload.js&lt;/code&gt; looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./polyfills.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./xhr.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// kick off the promise and cache it in a global variable&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__DATA_LOADER_CACHE__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then in our main bundle later we would check for the presence of that global variable and if it exists use that instead of our &lt;code&gt;loadData()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__DATA_LOADER_CACHE__&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dataLoaded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We built the preload script in such a way that it would be completely optional. If it didn't run at all the normal app could continuing running properly. But that did result in a handful of modules being duplicated. With a little more care we probably could have gotten the script down to around 2kb. Despite it not being perfectly tiny, the results were tremendous:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexbdewmdvhjmd6rktw7n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexbdewmdvhjmd6rktw7n.png" alt="Time savings" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your data becomes available to your application as soon as it's needed. And even in the case that your data call is still outstanding when the app is ready to go, your app will re-render as soon as it's done downloading. It's a much better user experience and the only trade-off is a tiny bit of awkward code. &lt;/p&gt;

&lt;h2&gt;
  
  
  How'd it turn out?
&lt;/h2&gt;

&lt;p&gt;🏆 In the app we applied this to at Amazon our 90th percentile &lt;a href="https://web.dev/tti/" rel="noopener noreferrer"&gt;Time to Interactive&lt;/a&gt; went down by over &lt;code&gt;350ms&lt;/code&gt;. A huge savings for very little effort. I definitely recommend you figure out how to pre-load data in your application as well.&lt;/p&gt;




&lt;h3&gt;
  
  
  Notes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Check out Ryan Florence's &lt;a href="https://www.youtube.com/watch?v=95B8mnhzoCM" rel="noopener noreferrer"&gt;When to Fetch&lt;/a&gt; talk for a more elegant solution for faster data loading&lt;/li&gt;
&lt;li&gt;We ended up making a cache based on URL and query params and stuck that in the global variable including other data like any errors, etc.&lt;/li&gt;
&lt;li&gt;It's important to log if you end up fetching the data URL twice, which can happen if you incorrectly duplicate your URL parsing logic 😬&lt;/li&gt;
&lt;li&gt;I tried to reproduce this in &lt;code&gt;vite&lt;/code&gt; but couldn't quite figure out how to split out the &lt;code&gt;preload&lt;/code&gt; file. When I figure it out I'll post a demo of all 3 states.&lt;/li&gt;
&lt;li&gt;Can't we just use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload" rel="noopener noreferrer"&gt;link rel="preload" as="fetch"&lt;/a&gt; and call it good? I mean yes, try that way first! We couldn't get it working consistently, but that was a few years back and things seem better now.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webperf</category>
      <category>react</category>
      <category>jamstack</category>
    </item>
    <item>
      <title>Doing my Best Work as an Engineer with ADHD</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Thu, 13 Jan 2022 23:32:41 +0000</pubDate>
      <link>https://dev.to/xjamundx/doing-my-best-work-as-an-engineer-with-adhd-21k4</link>
      <guid>https://dev.to/xjamundx/doing-my-best-work-as-an-engineer-with-adhd-21k4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhlbvo2gtsr428y5egry.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhlbvo2gtsr428y5egry.JPG" alt="Speaking at EmpireJS in 2016" width="800" height="589"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was diagnosed with ADHD in 5th grade. I was in Mrs. Henry's class and while I was certainly a bright student I had a horrible time staying focused. After falling out of my chair in class constantly and being fairly disruptive I eventually was diagnosed and put on medication, which helped me quite a bit. I stayed on medication on and off through elementary and middle school and into most of high school as well. I felt different when I was on that medicine. I could focus more. My thoughts weren't always racing. Sometimes things felt like they were going in slow motion. And I lost my appetite and developed a tic. Eventually I stopped taking them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmj4oftjn6965u3t4mqfz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmj4oftjn6965u3t4mqfz.jpg" alt="Me as a Young Hacker" width="578" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In both high school and college I was one of those students that felt like things came naturally, but I struggled immensely when it came to studying and even normal classroom participation. I'd blurt out answers. I'd struggle with any kind of reading or carefully following instructions. In higher level math classes I could never memorize basic formulas, but sometimes I was able to work them out myself when I needed to during a test. Often that just translated to me taking longer than everyone else to finish a test. In other classes I would find myself drawn to overachieving on some trivial task, while completely ignoring my actual responsibilities. While I could hardly focus on my class work I would lug giant computer books to school or spend hours fiddling with Linux at home as kid. College really wasn't much better, though when it came time to choose a major in college I was drawn to the &lt;a href="https://cep.be.uw.edu/" rel="noopener noreferrer"&gt;Community &amp;amp; Environmental Planning&lt;/a&gt; program at the University of Washington partially because  it followed Evergreen's model of &lt;a href="https://www.evergreen.edu/evaluations" rel="noopener noreferrer"&gt;narrative grading&lt;/a&gt;, which worked infinitely better for me.&lt;/p&gt;

&lt;p&gt;Today I'm a successful front-end engineer that has worked at several large tech companies. Anyone you ask that I've worked with will say that I've had an outsized impact on their team (and likely the company as a whole). Unlike in school my accomplishments in tech have been measurable and I've been compensated well for my work. I also really really like my job and the various developer communities I've had the opportunity to be a part of. Despite all of that success, managing my ADHD symptoms has gotten more difficult over time. &lt;/p&gt;

&lt;p&gt;I've found myself viscerally uncomfortable in long meetings, which seem to be a staple in modern "agile" development. My memory is foggy and I often forget people I've met or meetings I'm supposed to attend. Any kind of long documentation that I need to read, like instructions for setting up a new code base can be excruciating. I often end up taking short cuts and missing key details. Complex task management software fries my brain and I haven't quite figured out how to successfully manage my inbox. And even beyond that it's taken me years to finally learn the basic algorithms commonly taught in intro to CS courses. And jobs. Despite having worked at several companies for multi-year stints within those companies I struggle to stay content in the same position for more than 6 months at a time. I'm always looking at new opportunities. &lt;em&gt;My mind is never still&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let me share how I've been able to modify my circumstances and in some cases take advantage of my disadvantages to make the most of my career in tech with ADHD.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Working at big companies has given me more outlets for exploring opportunities&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This one took me a while to accept, because I grew up in  Seattle idolizing grunge and punk rocks icons who despised stuffy corporate culture. Working in some kind of overly political and bureaucratic office filled with finance bros and ivy leaguers was never going to appeal to me. What I found though after starting my career in smaller companies and startups was that large tech companies can offer far more flexibility. For me, always chasing new dreams, it meant that in the 5.5 years I was at PayPal for example, I was able to work in several different roles, learn new technologies, lead teams, host events and basically never get bored. I had a similar experience at Amazon, after 18 months on one fantastic team, I jumped to another project. Many large companies even have rotation programs where you get to move between teams every 6 months. &lt;/p&gt;

&lt;p&gt;One thing that is hard for me about working for large companies is their love of acronyms. I try hard to avoid them (and I ask others to do the same).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If It's Confusing For Me It's Probably Also Confusing For Others&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the big skills that's helped me in my career has been acknowledging when something is confusing. Maybe it's during a code review. Maybe it's a user interface that's too complex. Or an onboarding guide. Just say it. "Hey I don't understand this". Or "this is difficult for me to follow". It's kind of weird in some quarters for a supposedly senior engineer to just nope out of something because it's too confusing, but it forces really important conversations about architecture, about product design and really all of it. As a developer relations engineer being able to articulate when an API or integration guide is too complex is extremely valuable. Struggling to stay focused with my ADHD can end up being a super power when it comes to advocating for a better experience for others. My entire career in developer experience has been made by gently (and not so gently) encouraging my friends and colleagues to make things less confusing for myself and others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting the Most of Meetings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Through my career in tech I've been invited to entirely too many meetings. Sometimes I've gotten frustrated and walked out when I didn't feel my time was being spent well. Working from home has made it much easier to tune out of bad meetings or avoid them altogether. I just can't sit still for that long and a bad meeting or especially stressful one will often dominate my mind for the rest of the day.&lt;/p&gt;

&lt;p&gt;I live for good meeting agendas with clear outcomes and a limited number of people attending. Make sure everyone knows why they're there or if they can opt-out. Don't pressure people to attend that aren't absolutely needed. And provide some real clarity around what outcomes are expected by the end of the meeting. The exception to that is what I think of as a chit chat meeting, which really is just about getting to know someone. Those are always fine. We can make time for friends. All hands meetings though. I'd rather skip them. &lt;/p&gt;

&lt;p&gt;Amazon's approach of having 20-30 minutes at the start of a meeting to read a document or fill out whatever things people forgot to do before the meeting worked really well for me. It takes away a huge number of potential distractions and forces everyone to pay attention at that moment and with tools like Quip you can comment on the document inline and even engage in focused conversations before the meeting even begun. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Managing Agile Ceremonies and Software&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The meeting I've consistently struggled the most with is the sprint planning meeting or really any agile ceremony meetings (including standup). When we start busting out the backlog and assigning things to people it's just this immediate explosion of context all over the place that becomes extremely difficult for me to process. I also absolutely hate to commit to doing something for two weeks, which we all know may get interrupted or maybe I'll have a brilliant idea mid-sprint. I prefer a Kanban approach or the "trust me to do the right thing" approach, because &lt;em&gt;I will&lt;/em&gt;. And then there's the retro meetings where we rehash everything, it's all so dreary honestly and rarely proves productive for the team in my experience. &lt;/p&gt;

&lt;p&gt;Another aspect of modern agile development™ is task management software. PayPal used to use Rally, many companies use Jira. All of them offer similar features and usually get configured to inflict maximum developer pain. The purpose of this software should always be to help engineers do their job well. However, it's sold to and often rolled out by executives who want maximum visibility and rolled up stats about absolutely everything happening in the company. In practice this turns filing a simple bug report into an exercise in categorization and org-chart spelunking that me as an individual with ADHD has absolutely no time for. Sometimes I was lucky enough to be on teams where our product manager would be willing to keep Jira happy. Other times we were able to convince people to keep the process dead simple or allow us to bring in our own informal tools like Google Docs or Trello, which made it much easier to handle in my brain. Please allow your engineering teams flexibility over the tools they use. It's a relatively simple accommodation that can help neurodiverse folks so much.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Communication Style: And why I hate e-mail&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I don't know what I can say about e-mail exactly. I always have thousands of unreads just sitting there. Sometimes it's nice to be able to search through them when someone says "did you see the e-mail about X". I feel like what happens is I see this never-ending Inbox and I'll read something supposedly important and then immediately it gets lost in my mind and in a sea of other e-mails I don't really care about. I know people use folders and maybe that could work for me? I do a bit better with my personal e-mail because it's Gmail and I can just ⭐ everything that I want to keep track of and it gets pinned to the top. That really helps me. I haven't quite bothered to figure out an equivalent with outlook yet. I just keep hoping it goes away. (That includes really carefully crafted tech newsletter too, sorry.)&lt;/p&gt;

&lt;p&gt;If you want to talk to me, please reach out on slack or &lt;a href="https://twitter.com/xjamundx" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. Don't &lt;em&gt;ever&lt;/em&gt; call me. Always give me whatever context I need to respond later without assuming I'll be immediately joining a discussion with you. Because, I will not be. I also don't put slack or work email on my phone for the same reason. My time is precious and while I'm easily distracted I'm trying hard not to be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hyper Focus is a Thing (Though Rarely Since Covid Hit)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes I feel like I could go a whole sprint getting distracted on a million tangents and then in the last day or two get super focused and knock out all of the features in no time at all. This is often the case with bugs. I'll get distracted from my normal sprint work and just go on a tangent squashing a whole bunch of bugs in a really short period of time. I work in bursts. I need time away from the computer. I take walks. I'm probably only &lt;em&gt;really&lt;/em&gt; productive for about 8 hours a week. (I'm a 10x engineer, but only 1/10th of the time.) The rest of the time my mind is distracted thinking about politics or my family or an open source project or some new feature I want to build that has nothing to do with whatever I'm supposed to be working on. Part of being successful has been understanding how to take time away from the computer where my mind is still working out the problem, so that when I come back from literally laying on the floor or going for a walk, I'm all ready to go. Working from home always made this easier for me, but with covid and kids around a lot more and all the existential crises happening around it's honestly been pretty rough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I love reading &amp;amp; learning, but in small, focused packages with few distractions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I remember when the &lt;a href="https://abookapart.com/" rel="noopener noreferrer"&gt;A Book Apart&lt;/a&gt; series first came out and they published &lt;a href="https://abookapart.com/products/html5-for-web-designers" rel="noopener noreferrer"&gt;HTML5 for Web Designers&lt;/a&gt;. It was a really small book and only 150 pages. And then they released CSS3 for Web Designers which I remember reading on my phone in line at Old Navy. I had been reading tech books since I was in middle school, but these were some of the first I was able to really devour without having to completely force myself. Short. To the point. Beautifully laid out with plenty of white space and tasteful use of color. I love buying tech books like many of you, but struggle getting past about the first 100 pages or so. Usually I'll read that much and then just kind of skim the rest or skip around to an important chapter. I absolutely love short books. My favorite example recently was Sam Julien's &lt;a href="https://learn.samjulien.com/getting-started-in-developer-relations" rel="noopener noreferrer"&gt;Getting Started in Developer Relations&lt;/a&gt;. At 79 pages it's absolute perfection.&lt;/p&gt;

&lt;p&gt;Anything that limits distractions or the length needed to hold my attention helps my learning. Frankly it's one of the reasons I'm so stoked about VR, you're completely immersed on a single task. Another example is attending conference talks in-person. I do a good job of not bringing work to conferences and I'm not especially extroverted, so sitting there watching a few talks usually works pretty well for me. (At least for about 4 or 5 hours until it becomes too much information!) Similarly in-person or highly interactive workshops have always been really productive learning for me. An in-person all day GitHub workshop was incredibly helpful for me up-leveling my git skills. Working through EpicReact when I was recovering from covid. I learned so much and was able to stay focused because I didn't have any work obligations distracting me from learning.&lt;/p&gt;

&lt;p&gt;Other than that most of my learning comes from thinking and exploring, which is usually quite unstructured, and that's ok.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One on One Communication Has Always Been A Challenge&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because I often end up situations I'm not sure exactly what is proper and expected I rely a lot on my intuition to guide me. I also have tried to develop my emotional intelligence and adapt my approach in discussion based on how people seem to be responding. This is definitely helpful when teaching. It also makes me greatly prefer video calls over audio calls where I have a lot less visual cues I can respond to. I know that doesn't work for everyone and I understand that and adapt. One unfortunate trait many people with ADHD share is a tendency to go on long rants and in their enthusiasm talk over or interrupt other people. I do this &lt;em&gt;a lot&lt;/em&gt;. To compensate I often summarize my thoughts at the end of speaking and also acknowledge and stop myself when I do interrupt someone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Presentations &amp;amp; Teaching&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My ADHD sometimes gets perceived to others as having an unrelenting enthusiasm for new things. And truly sometimes I feel like Dory from Finding Nemo where everything is new an exciting each time even though I may have already learned that thing before. That enthusiasm translates well into public speaking and giving presentations and generally getting people hyped on new technology, which thankfully is an important part of my job.&lt;/p&gt;

&lt;p&gt;When it comes to actually preparing talks, I don't think I have any special techniques. Usually I find myself going for walks or drives and speaking the talk into existence even before writing slides or an outline. When I do write the slides I like to make outlines first and then fill them in with content later. Speaker notes help, though I rarely actually get them to work on the day of, I just practice them over and over (out loud ideally). I love the energy I get when giving a talk and feeding off questions and enthusiasm from the people in the room. After giving a talk though my brain is usually fried and I'm basically useless for the rest of the day.&lt;/p&gt;

&lt;p&gt;Writing is a little bit different. It takes me like 400 hours to write a simple e-mail and then I also have a typo or something in it. Blog posts are different because when I feel like blogging usually some idea is bursting to come out of me and I can usually type it up in a couple of hours, no matter how long it is. (Though I find myself publishing hastily and revising a few times after publishing, like I did with this post.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting Expectations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the best exercises I ever participated in a corporate environment was on my last team at Amazon where our manager asked us to present our &lt;a href="https://www.google.com/search?q=personal+user+guide" rel="noopener noreferrer"&gt;personal user guide&lt;/a&gt; which is a thing. You can google it. And it's basically just setting expectations with your team about how you like to work, including how you want people to give you feedback and what energizes/drains you. &lt;a href="https://github.com/xjamundx/about" rel="noopener noreferrer"&gt;I put mine up on github&lt;/a&gt;. While writing it out was really helpful for me , having space to communicate and acknowledge that everyone works and thinks and reacts a little bit differently was really powerful for our team. I would highly recommend it as an exercise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Living with ADHD has no doubt been a challenge. It's affected my relationships, education and career in ways that I'm not always happy about. Like so many of you dealing with this I've been able to make it work for me and sometimes I've been able to use my experience as an advantage. It's helped me see things through a fresh &amp;amp; empathetic perspective and other times it's forced me to cut out unnecessary processes or work that was really benefitting no one at all. I don't know if I'm grateful that I have ADHD, but I am glad my ADHD and I have come to a kind of mutual understanding. I'm used to it. I know it's there. And for the most part we get along.&lt;/p&gt;




&lt;p&gt;If you are neurodiverse in some way what kind of accommodations have allowed you to be successful at work? What techniques help you make the most of that challenge? How did medication make your condition more manageable? How has your experience with ADHD changed over time. Would love to hear your experiences.&lt;/p&gt;

</description>
      <category>adhd</category>
      <category>webdev</category>
      <category>career</category>
      <category>beginners</category>
    </item>
    <item>
      <title>One Cool Trick to Speed Up Your Website Performance (Not Really)</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Mon, 13 Dec 2021 20:00:36 +0000</pubDate>
      <link>https://dev.to/xjamundx/one-cool-trick-to-speed-up-your-website-performance-not-really-1219</link>
      <guid>https://dev.to/xjamundx/one-cool-trick-to-speed-up-your-website-performance-not-really-1219</guid>
      <description>&lt;p&gt;The truly greatest bang-for-your-buck performance impact I ever had was removing two lines of JavaScript. &lt;/p&gt;

&lt;h3&gt;
  
  
  My Background
&lt;/h3&gt;

&lt;p&gt;When I was at Amazon, I worked in the Seller Central org building tools to help companies sell their products. The app I primarily worked on was a complex multi-part form broken into numerous tabs with dozens of inputs dynamically populated based on product type, customer characteristics and various choices made along the way. The app was built with React and Redux, and the backend was a custom Java SpringMVC-based framework.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;As a company, Amazon has a strong culture of web performance, but it also values shipping code rapidly. These competing interests resulted in friction; it could be deeply frustrating to see a month's worth of work improving page performance wiped out by an unintended negative side effect from a new feature. When I started as the sole frontend engineer on my team, and one of a handful in the org, my primary focus was on frontend architecture and web performance. It was my responsibility to come up with sustainable ways to hit those goals without compromising our ability to ship code. At the time, we were regularly missing our web performance targets. Most of the team members were smart backend devs, but few had much experience with React, or with optimizing frontend performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Failed Attempts
&lt;/h3&gt;

&lt;p&gt;I came in, as many new hires do, wanting to be the hero who stepped in and neatly saved the day. I started by looking for the easy, high-yield performance wins: are we using an optimized lodash build for webpack? Are we bundle splitting? Exactly how many &lt;code&gt;fetch&lt;/code&gt; polyfills do we have in our bundle? I'd worked on performance in React apps before, and I had my mental checklist ready. The problem, though, was that the low hanging fruit wasn't yielding enough actual benefit. We shaved off 10kb here, 100kb there. Our bundle size dropped from 1.8mb to 1.5mb, and eventually all the way down to just over 1mb, but we still couldn't hit our performance goals. We relied heavily on &lt;a href="http://akamai.github.io/boomerang/" rel="noopener noreferrer"&gt;real user monitoring&lt;/a&gt; to understand how users experienced our site. We eventually found that due to how users interacted with our app, our cache hit rate was fairly high. The reductions to the size of our JS bundle were definitely a good thing, but they weren't giving us anywhere near the improvements in how users were experiencing our performance that we wanted. There had to be something else that could speed us up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Breakthrough
&lt;/h3&gt;

&lt;p&gt;The breakthrough came, as they sometimes do, after I'd exhausted my checklist and started exploring areas I was unfamiliar with. I was looking for new and different ways to analyze what was and wasn't working in our app, and that's when I stumbled on the coverage tab in Chrome's web inspector. Finding it is a convoluted process; it's buried two menus deep in the Chrome DevTools three-dot menu under "More Tools", or you can reach it by activating the Command Menu in DevTools with &lt;code&gt;⌘P&lt;/code&gt;, typing &lt;code&gt;&amp;gt;&lt;/code&gt; to see other available actions, and then typing &lt;code&gt;coverage&lt;/code&gt;.  Seeing its results for a first time were a revelation and I got excited enough to tweet about it joyfully.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1256377543566876672-440" src="https://platform.twitter.com/embed/Tweet.html?id=1256377543566876672"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1256377543566876672-440');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1256377543566876672&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;The Coverage tab can show you unused JS and CSS on your page. Once you get into the coverage panel, by default you'll see both JS and CSS files. But you can also filter to just CSS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxa7u676r786ligdrp42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxa7u676r786ligdrp42.png" alt="Show coverage select CSS" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What I saw there was that over 98% of our main CSS file went unused. I also realized that CSS file, on its own, was over 1mb. I'd been grinding away, paring down our JS bundle to the smallest possible size, but the CSS file was right there actually having a larger impact! &lt;em&gt;The CSS coverage below comes from a different website, but it follows a similar trend&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1tl5lr8k3sk30or14rl8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1tl5lr8k3sk30or14rl8.png" alt="Very low CSS coverage" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem with Large CSS Files
&lt;/h3&gt;

&lt;p&gt;While it's pretty common to discuss the downsides of large JS bundles, large CSS bundles are arguably worse! CSS is a &lt;a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-blocking-css" rel="noopener noreferrer"&gt;render blocking resource&lt;/a&gt; which means the browser is going to wait for that CSS file to be downloaded, parsed and constructed into a &lt;a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model" rel="noopener noreferrer"&gt;CSSOM tree&lt;/a&gt; before rendering the contents of the page. Whereas JS files these days are usually added to the end of the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; or included with the &lt;code&gt;defer&lt;/code&gt; or &lt;code&gt;async&lt;/code&gt; tags, CSS files are rarely loaded in parallel with the page render. That's why it's imperative that you keep unused CSS out of your main CSS bundle.&lt;/p&gt;

&lt;p&gt;There has been talk for years about including only "above the fold" or critical-path CSS on initial page load, but despite &lt;a href="https://project-awesome.org/addyosmani/critical-path-css-tools" rel="noopener noreferrer"&gt;several tools&lt;/a&gt; that can try to automate this process it's not foolproof.  When it comes to just avoiding including unneeded CSS I think many would agree CSS-in-JS approaches and even CSS Modules do a better job at this compared to the ever-too-common approach of having one large Sass or LESS file that contains all of the styles anyone might ever need for your site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pinning Down the Problem
&lt;/h3&gt;

&lt;p&gt;My team's initial approach to styling was to have a single large Sass file with dozens of dependent stylesheets @imported in. That made it quite difficult to figure out exactly what parts we were or weren't using, and I spent hours scouring our CSS files looking for unused styling. Nothing looked obviously wasteful, and I certainly couldn't find a whole extra mb of unused style. Where else could the CSS be coming from? Was it from a shared header/footer that included extra styles? Maybe a JS-based CSS import somewhere? I had to find out.&lt;/p&gt;

&lt;p&gt;Searching through our JS code, I found only 4 or 5 CSS imports. Our webpack config made sure that all CSS imported from inside our JS files ended up bundled together in one large file. In our main JavaScript entry file (index.js), I found 2 CSS imports that looked particularly suspicious. This isn't the exact code, but it was something very similar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;semantic-ui/dist/styles.min.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;semantic-ui/dist/styles.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I had looked at this code and ignored it literally dozens of times. But given my new challenge to figure out where the extra CSS was coming from it stood out. Why were we importing this library at all? Did we even need it? And why were we importing it twice (both minified and non-minified)?&lt;/p&gt;

&lt;p&gt;The first thing I did was comment out both of them. I ran &lt;code&gt;npm run build&lt;/code&gt; and saw our CSS bundle drop from 1.25mb down to 30kb! It was ridiculous. This code was killing us. ☠️&lt;/p&gt;

&lt;p&gt;Unfortunately, as you might predict, our website looked horrible after removing the CSS. We were relying on something in those CSS bundles. Next, I commented out each of them one at a time. Strangely, we needed to keep the non-minified one in there to avoid breaking the look &amp;amp; feel of the site, but at least I was making progress. We shaved off around 500kb of CSS just by removing one line.&lt;/p&gt;

&lt;p&gt;Now began the more difficult part of removing our reliance on that UI library altogether. &lt;/p&gt;

&lt;h3&gt;
  
  
  What Was Left
&lt;/h3&gt;

&lt;p&gt;Like many teams, we relied on an internal UI library that our app was already importing. I figured we could probably use that internal library to provide most, if not all, of the functionality we were getting from the external library.&lt;/p&gt;

&lt;p&gt;An early approach I took was simply copy/pasting the whole built Semantic UI library CSS into a new file and then removing things we didn't need. That got me somewhere, but became increasingly difficult as the styles got more nested and complex. Eventually I removed the CSS imports completely, purposefully breaking the look of the site. That made it easy to identify which classes we were actually using. We took screenshots of the working site and then carefully compared them with the broken version.&lt;/p&gt;

&lt;p&gt;It turns out we were primarily using three components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The grid system&lt;/li&gt;
&lt;li&gt;The navigation tabs&lt;/li&gt;
&lt;li&gt;Modal dialogs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we figured which pieces of the library we were using, it was easy enough to search through our code base and see which components were relying on them. There were a lot that used the grid for example, but we had a drop-in replacement for those that only required a small class name change. In some other cases, we had to either add new CSS or move the HTML around a bit to get it to work with our other UI library. It ended up being about a month of work for a new team member to completely detach us from that external library. We carefully reviewed her work, compared before &amp;amp; after screenshots, and where there were minor style differences, ran it by a few team members to make sure the changes were close enough to the original to not block the change.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Impact
&lt;/h3&gt;

&lt;p&gt;After we shipped the changes we looked at our real user monitoring graphs and saw massive reductions in both our 50th and 90th percentile &lt;a href="https://web.dev/interactive/" rel="noopener noreferrer"&gt;time to interactive&lt;/a&gt; measurements across the app. At the 90th percentile there was around half a second of reduction in TTI. After making so many changes that didn't seem to matter, it was so satisfying to finally have a solid performance win.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Removing that one UI library bundle probably ended up having a larger effect than any other single change I witnessed in my entire time working on web performance at Amazon.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Takeaways
&lt;/h3&gt;

&lt;p&gt;I've found it's very difficult to generalize web performance wins. How likely is it that your app is also double importing a large CSS library? You might as well check, but it's probably not happening. What I hope you take away from my experience here is the underlying factors that enabled us to find &amp;amp; fix this problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't just optimize to a checklist (Learn the tools!)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The easier part is process-related: you can't just optimize to a checklist. It's important to have checklists when you're working on performance work, because many apps can be improved by a straightforward, well-known list of simple improvements. You can and should leverage the work you've done in the past, and that the community around you has done to improve performance. But when you reach the end of your checklist, you need to develop the skillset to keep digging. Just because other apps you've worked on benefitted from change A or change B doesn't mean it will work in your next app. You have to understand your tools. You have to know the specific characteristics &amp;amp; architecture of your site. And you have to know your customers. Lighthouse probably told me early on in this process that I had too much CSS on the page. Without a clear understanding of how our CSS files were built and better tools for analysis I wasn't able to do much with that information. While checklists of common web performance mistakes can absolutely be helpful, teaching teammates how to use the tools available to analyze web performance in the specific, is much more powerful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have a strong web performance mandate&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The other major takeaway, though, is about culture. To build performant applications, performance itself needs to be a first class KPI. I think many engineers enjoy optimizing things. It's really fun and difficult work. The results as we all know can be very inconsistent. I can't tell you how many times I promised to shave off 150ms from our experience, got that improvement when testing locally, but saw nothing or even a negative impact when the change actually went live. In many cases that can lead engineering or product managers to be weary of such promises. My org at Amazon had amazing leadership when it came to web performance. That mandate ensured that we had the buy-in we needed to keep going until we had the impact we wanted.&lt;/p&gt;




&lt;p&gt;I don't expect this article to provide any magic bullets for those out there trying to optimize their apps, but I do hope it encourages you to keep digging until you find your own.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;P.S. I want to give a shout out to my colleagues &lt;a href="https://www.linkedin.com/in/scott-gifford-7858709/" rel="noopener noreferrer"&gt;Scott Gifford&lt;/a&gt; and &lt;a href="https://twitter.com/mike_kirlin" rel="noopener noreferrer"&gt;Michael Kirlin&lt;/a&gt;. Scott remains hugely influential engineer at Amazon in the web performance space and mentored me throughout my time there. Michael not only reviewed this article, but edited it extensively for clarity. Thank you friends!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>performance</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Building 2D Websites for the Metaverse (or at least for the Oculus Quest Browser)</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Fri, 26 Nov 2021 05:13:38 +0000</pubDate>
      <link>https://dev.to/xjamundx/building-2d-websites-for-the-metaverse-or-at-least-for-the-oculus-quest-browser-3j5e</link>
      <guid>https://dev.to/xjamundx/building-2d-websites-for-the-metaverse-or-at-least-for-the-oculus-quest-browser-3j5e</guid>
      <description>&lt;p&gt;As a long-time web developer and non-gaming VR fan I'm really excited about the potential for the web on virtual reality platforms like the Oculus Quest. Last week I spent a few hours toying with &lt;a href="https://github.com/xjamundx/tetris" rel="noopener noreferrer"&gt;my 2D tetris clone&lt;/a&gt; on the Oculus Quest browser and actually got it installed it as a Progressive Web App on my headset. I'm excited to show off how I got this to work and what I learned in the process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3pscalifn1dwcc16bb6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3pscalifn1dwcc16bb6d.png" alt="Widescreen Tetris" width="800" height="400"&gt;&lt;/a&gt; &lt;/p&gt;




&lt;h2&gt;
  
  
  Oculus Quest is Essentially an Android Device
&lt;/h2&gt;

&lt;p&gt;The Oculus Quest is basically an Android smartphone that you strap to your face. To get started developing for the Quest, even on the web, you're going to want to download &lt;a href="https://developer.android.com/studio" rel="noopener noreferrer"&gt;Android Studio&lt;/a&gt; and the &lt;a href="https://developer.android.com/studio/releases/platform-tools" rel="noopener noreferrer"&gt;Android SDK Platform Tools&lt;/a&gt;. You'll be using the &lt;code&gt;adb&lt;/code&gt; command from time to time to confirm your device is properly connected, install your PWAs and make other advanced configuration changes. You also will need to enable developer mode for your device, which you need to do from the Oculus app on your phone. There's also another step in the Oculus settings menu where you'll need to enable USB debugging.&lt;/p&gt;

&lt;p&gt;Oculus provides some desktop software called &lt;a href="https://developer.oculus.com/downloads/native-android/" rel="noopener noreferrer"&gt;Oculus Developer Hub&lt;/a&gt; that simplifies a number of key developer tasks like verifying your connection, disabling the guardian, casting and taking screenshots.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdd9s8zt3qqvz6kgdkr55.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdd9s8zt3qqvz6kgdkr55.png" alt="Oculus Developer Hub" width="800" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s definitely a lot of steps, but after you've got all of this setup you're well on your way to building Oculus VR apps in 2D using web technology. It's exciting!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ss3yrnn797d66t92soq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ss3yrnn797d66t92soq.png" alt="Oculus Developer Hub Allows Casting" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Browsing the 2D Web in VR
&lt;/h2&gt;

&lt;p&gt;When you open up the Oculus Browser for the first time you might notice a few things that are unique about it compared to a normal web browser. The first is that it's capable of 3 browser windows side by side. So you're confronted with this 180° wall of browser windows which measures over 3000pixels in width. The default width of each window according to the &lt;a href="https://developer.oculus.com/documentation/web/browser-specs/" rel="noopener noreferrer"&gt;oculus browser specs&lt;/a&gt; is unique at 1000px wide by 505px high. And as of right now you can resize them, but only the width. You’re stuck with that strange height. (&lt;em&gt;Edit: &lt;a href="https://twitter.com/vrhermit/status/1470149581279305734?s=20" rel="noopener noreferrer"&gt;Width/Height Resizing is now available&lt;/a&gt; as of Dec. 13, 2021.&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;Try to pull up a few websites. If it's something interactive like my &lt;a href="https://xjamundx.github.io/tetris" rel="noopener noreferrer"&gt;tetris game&lt;/a&gt; there's a good chance it won't quite work!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqpadp1yq9nvxhovajsi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqpadp1yq9nvxhovajsi.jpg" alt="My bad Tetris Clone in the Oculus Browser" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If on the other hand you pull up a standard news site, blog or even the something optimized like the &lt;a href="https://rrppl0y8l4.csb.app/" rel="noopener noreferrer"&gt;React Three Fiber Demo App&lt;/a&gt; they should all look and work great.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4ox5p6k9wm8wtw4sjr1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4ox5p6k9wm8wtw4sjr1.png" alt="React Three Fiber Demo App Rendered in the Oculus Browser" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging Local Code
&lt;/h2&gt;

&lt;p&gt;Assuming you're building your app on your local computer you probably want to see those updates immediately in the oculus browser. To do that you need to setup a reverse proxy which forwards all traffic from a port on your Oculus device to one on your computer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adb reverse tcp:3000 tcp:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that you should be able to enter in URLs like &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; in the oculus browser and have them work perfectly, reading files off of your computer.&lt;/p&gt;

&lt;p&gt;If you're using something like codesandbox or glitch to host your files it can be really helpful to use this feature of Oculus Developer Hub which lets you enter in a URL and have it open automatically on your headset.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh8btom9nb81080riu795.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh8btom9nb81080riu795.jpg" alt="ODH URL Pass thru" width="392" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now comes the mind blowing part. You can inspect your oculus browser window from inside of Google Chrome. You simply go to &lt;br&gt;
 &lt;a&gt;chrome://inspect/#devices&lt;/a&gt; and click "inspect" on your device instance. It really feels like magic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4o9tta9vohy8uobqbind.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4o9tta9vohy8uobqbind.png" alt="chrome inspect devices" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I mostly used &lt;code&gt;console.log&lt;/code&gt; to log my event listeners, but as far as I can tell the full JavaScript debugger along with the network and element inspectors. Because going back and forth between your computer and your headset is obviously kind of a pain, I found testing by interacting with the little preview app inside of inspector window actually saved a lot of time.&lt;/p&gt;

&lt;h2&gt;
  
  
  UX &amp;amp; Web API Considerations
&lt;/h2&gt;

&lt;p&gt;✅ Now you have your app showing up in the Oculus browser and you're able to update and debug that app on your local computer. Here are some basic tips for optimizing that app for running in VR:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events" rel="noopener noreferrer"&gt;PointerEvents API&lt;/a&gt; for user input&lt;/li&gt;
&lt;li&gt;Make buttons and text Larger&lt;/li&gt;
&lt;li&gt;Optimize for a wide screen&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My initial tetris implementation relied on keyboard input to move things around. When first porting it over I started using mouse events like &lt;code&gt;mousedown&lt;/code&gt; and &lt;code&gt;mousemove&lt;/code&gt; and was surprised when they didn't work. I shouldn't have been surprised though. The Oculus Browser is running on an Android device. Instead of mouse events it supports &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch_events" rel="noopener noreferrer"&gt;Touch Events&lt;/a&gt; and the slightly cleaner &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events" rel="noopener noreferrer"&gt;PointerEvents API&lt;/a&gt;. Pointer Events give you have a single event for both touch and mouse events. They're fully supported in React and seem a little easier to work with than touch events, which support input from multiple touches simultaneously. &lt;/p&gt;

&lt;p&gt;Once you get your user input working properly make sure to make your interactive elements larger. As mobile web browsing began to take off a decade ago, both Apple and Google provided &lt;a href="https://developer.apple.com/design/tips/#interactivity" rel="noopener noreferrer"&gt;UI guidelines&lt;/a&gt; for how users interact with their devices. One of the main ones was to give a lot of padding to buttons &amp;amp; other controls you expected the user would touch. This was to make sure when someone's finger didn't quite make the target your app would give them what they wanted anyway. This is even more important in VR where your controllers are in a constant state of motion. Make those inputs larger and given the blurry text we still have in VR, make your text larger as well.&lt;/p&gt;

&lt;p&gt;My last realization is to consider the screen real estate you have in the Oculus Browser. You're dealing with 1000px wide, but only 505px high. It's a fairly wide screen, but it's really short. Scrolling in the Oculus Browser works fine, but I'd personally recommend designing for wide screen without having to scroll. Certainly for most games or more interactive apps you don't want to have to scroll to see some important part of the action. Think about how you can stretch your app out. Many tablet apps are designed to take advantage of space in landscape mode and I'm confident we'll figure out how to do this well for VR.&lt;/p&gt;

&lt;h3&gt;
  
  
  More To Learn
&lt;/h3&gt;

&lt;p&gt;My &lt;a href="https://xjamundx.github.io/tetris/" rel="noopener noreferrer"&gt;tetris clone&lt;/a&gt; still isn't fully optimized for VR, but I made the buttons a lot bigger and migrated to use the Touch Events API so that pieces can be moved around as they are falling. I also got it &lt;a href="https://developer.oculus.com/documentation/web/pwa-gs/" rel="noopener noreferrer"&gt;installed as a PWA&lt;/a&gt; so I can run it next to other apps in my library. My next steps are to migrate to the Pointer Events API and to figure out how to optimize for all of that horizontal screen real estate!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3pscalifn1dwcc16bb6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3pscalifn1dwcc16bb6d.png" alt="Widescreen Tetris" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once I get that sorted out there are definitely a few more questions I want to dive into. Do I need the &lt;a href="https://www.w3.org/TR/webxr-gamepads-module-1/" rel="noopener noreferrer"&gt;WebXR Gamepads API&lt;/a&gt; to capture the various buttons and trigger inputs from the oculus touch controllers? (&lt;em&gt;&lt;strong&gt;Follow up:&lt;/strong&gt; nope, they can't be accessed  outside of &lt;a href="https://immersive-web.github.io/webxr/#dom-xrsessionmode-immersive-vr" rel="noopener noreferrer"&gt;immersive-vr&lt;/a&gt; mode.&lt;/em&gt;) Could I make a super wide game that spans 3 browser windows using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage" rel="noopener noreferrer"&gt;postMessage&lt;/a&gt; or the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API" rel="noopener noreferrer"&gt;Web Storage API&lt;/a&gt;? And then beyond that, is a 2D web for VR even a thing worth pursuing?  How hard would it be to use something like &lt;a href="https://aframe.io/" rel="noopener noreferrer"&gt;a-frame&lt;/a&gt; or &lt;a href="https://github.com/pmndrs/react-three-fiber" rel="noopener noreferrer"&gt;React Three Fiber&lt;/a&gt; with &lt;a href="https://github.com/pmndrs/use-cannon" rel="noopener noreferrer"&gt;use cannon&lt;/a&gt; to make fully immersive 3D world? &lt;a href="https://blog.mozvr.com/hello-webxr/" rel="noopener noreferrer"&gt;People are doing it&lt;/a&gt;, so why not you and me? &lt;/p&gt;




&lt;p&gt;There are so many technologies generating enthusiasm right now in the world of web development, but I wouldn't sleep on building web apps for VR! Meta has sold over 10 million Quest 2 devices already and that growth seems to be sustainable. This is happening. What role is the 2D web going to have in virtual reality and the so-called metaverse? What about &lt;a href="https://experiments.withgoogle.com/collection/webxr?" rel="noopener noreferrer"&gt;WebXR &lt;/a&gt; and the 3D web? It's up to us to build the future we want to see. So start building!&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;&lt;a href="https://techcrunch.com/2021/10/28/facebook-opens-oculus-store-to-2d-progressive-web-apps/" rel="noopener noreferrer"&gt;https://techcrunch.com/2021/10/28/facebook-opens-oculus-store-to-2d-progressive-web-apps/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.theverge.com/2021/11/16/22785469/meta-oculus-quest-2-10-million-units-sold-qualcomm-xr2" rel="noopener noreferrer"&gt;https://www.theverge.com/2021/11/16/22785469/meta-oculus-quest-2-10-million-units-sold-qualcomm-xr2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.oculus.com/documentation/web/browser-remote-debugging/" rel="noopener noreferrer"&gt;https://developer.oculus.com/documentation/web/browser-remote-debugging/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/blog/2018/05/23/react-v-16-4.html" rel="noopener noreferrer"&gt;https://reactjs.org/blog/2018/05/23/react-v-16-4.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/design/human-interface-guidelines/ios/user-interaction/gestures/" rel="noopener noreferrer"&gt;https://developer.apple.com/design/human-interface-guidelines/ios/user-interaction/gestures/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/webxr-gamepads-module-1/" rel="noopener noreferrer"&gt;https://www.w3.org/TR/webxr-gamepads-module-1/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>vr</category>
      <category>xr</category>
    </item>
    <item>
      <title>Generating Universally Unique Identifiers with JavaScript</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Wed, 24 Nov 2021 23:19:24 +0000</pubDate>
      <link>https://dev.to/xjamundx/generating-universally-unique-identifiers-with-javascript-2919</link>
      <guid>https://dev.to/xjamundx/generating-universally-unique-identifiers-with-javascript-2919</guid>
      <description>&lt;p&gt;For as long as I can remember the recommended way to generate unique universal Identifiers in node.js was to the &lt;a href="https://www.npmjs.com/package/uuid" rel="noopener noreferrer"&gt;uuid&lt;/a&gt; module. These IDs are useful in all sorts of scenarios including for database keys, filenames, URLs, etc. Recently both node.js and the browser began offering nearly identical APIs that will generate 36-character &lt;a href="https://datatracker.ietf.org/doc/html/rfc4122#section-4.4" rel="noopener noreferrer"&gt;version 4 uuids&lt;/a&gt; without any dependencies.&lt;/p&gt;

&lt;p&gt;Available in Chrome since July 2021 and coming soon other browsers is &lt;code&gt;crypto.randomUUID()&lt;/code&gt;. There's a global &lt;code&gt;crypto&lt;/code&gt; object that's available on the global &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/self" rel="noopener noreferrer"&gt;self&lt;/a&gt; property. You can use that to generate a UUID like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UUID it generates is a v4 UUID per the spec and ends up with a string that looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0aa9d4f3-efdb-4a06-806c-5f8fa5f1767d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jcc657y1ltkkiu0gjdi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jcc657y1ltkkiu0gjdi.png" alt="Browser Compatability for randomUUID" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You want to do the same thing in node? Instead of reaching for the &lt;a href="https://www.npmjs.com/package/uuid" rel="noopener noreferrer"&gt;uuid&lt;/a&gt; package. As long as you're on version 14.17 or newer, you can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;randomUUID&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// "0aa9d4f3-efdb-4a06-806c-5f8fa5f1767d"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's cool see node and the browser adopting powerful APIs for crypto and improved randomness. I'll definitely be reaching for these in the near future!&lt;/p&gt;




&lt;p&gt;You can read more in the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API" rel="noopener noreferrer"&gt;WebCrypto section in the MDN&lt;/a&gt; or the &lt;a href="https://nodejs.org/api/crypto.html#cryptorandomuuidoptions" rel="noopener noreferrer"&gt;crypto section in the node.js docs&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>security</category>
    </item>
    <item>
      <title>Redux Testing Lessons Learned: Render Components with a Real Store</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Tue, 23 Nov 2021 22:19:33 +0000</pubDate>
      <link>https://dev.to/xjamundx/redux-testing-lessons-learned-give-your-components-access-to-your-reducers-508k</link>
      <guid>https://dev.to/xjamundx/redux-testing-lessons-learned-give-your-components-access-to-your-reducers-508k</guid>
      <description>&lt;p&gt;This post is a follow up to &lt;a href="https://dev.to/xjamundx/redux-testing-hard-earned-lessons-learned-1o9e"&gt;Redux Testing: Hard Lessons Learned&lt;/a&gt; where I spoke about two important principles for testing redux apps: "Stop Testing your Disconnected Components" and "Build a Small Utility Library". Mostly we went through some of the key utilities that I use to make testing redux apps more manageable. This post will cover another area I called out in the first post: &lt;strong&gt;Render Components with a Real Store&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For a long time I relied on &lt;a href="https://github.com/reduxjs/redux-mock-store" rel="noopener noreferrer"&gt;redux mock store&lt;/a&gt; to preload data into my components for rendering during tests. This approach makes it easy to take a snapshot of a component with arbitrary data and ensure that it renders correctly. Where it completely fails is testing interactions.&lt;/p&gt;

&lt;p&gt;What happens when I click the close the button or when I select that image? With redux mock store you have a special method named &lt;a href="https://github.com/reduxjs/redux-mock-store#synchronous-actions" rel="noopener noreferrer"&gt;getActions&lt;/a&gt; that tells you what actions were fired, but that's it. Those actions don't actually make it to your reducers and they never update the UI. This makes your tests pretty frustrating to write. There's no good way to confirm that a component can transition from one state to another. You can only test snapshots.&lt;/p&gt;

&lt;p&gt;The first and quickest way to solve this is to pass your actual redux store into the &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; you use to wrap your tests and then return it. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../app/store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderWithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This immediately gives you all kinds of powers. The first one is the ability to dispatch actions to populate or otherwise your modify redux store. Because those actions are dispatched synchronously you can immediately assert that the UI was updated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;table should render all kinds of data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;renderWithContext&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ResultsTable&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// expect() table to be empty&lt;/span&gt;
    &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POPULATE_DATA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="c1"&gt;// expect() table to be full&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The other thing it lets you do is assert that your redux store changed in response to an event that wouldn't normally affect the component you are testing. For example let's say you had a button that updated a counter, but that counter component lived somewhere else. We can pretty easily test that clicking the button updated the count in our store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter should update count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;renderWithContext&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CounterButton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;userEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the issue with sharing your actual redux store is that the order of your tests shouldn't matter. You really want to run your tests in isolation. With the shared store approach if you dispatch an event in one test, the changes are propagated to all future tests. And that's why I ended up with the &lt;code&gt;getStoreWithState&lt;/code&gt; method I showed in &lt;a href="https://dev.to/xjamundx/redux-testing-hard-earned-lessons-learned-1o9e"&gt;my previous article&lt;/a&gt; as a key utility.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;configureStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getStoreWithState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;preloadedState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;configureStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;preloadedState&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two important parts here. The one that I mentioned before was the &lt;code&gt;preloadedState&lt;/code&gt; option, which lets us render components in tests with state already setup in a specific way (similar to mock redux store). The second and more subtle accomplishment here is that we're giving our generated store access to the same reducers used by our app's store. This gives us an isolated store to use for each test that also has access to the full power of our application's reducers.&lt;/p&gt;

&lt;p&gt;One benefit of this approach is that every time we test a component hooked into redux, we're also testing multiple reducers. It more economical and it more accurately reflects how our application actually works. Not to mention your tests are way easier to write this way. If you're used to testing with mock-redux-store this approach is going to give you a huge boost.&lt;/p&gt;

&lt;p&gt;If you want to learn more about my approach to testing redux applications please watch my course &lt;a href="https://egghead.io/courses/confidently-testing-redux-applications-with-jest-typescript-16e17d9b" rel="noopener noreferrer"&gt;Confidently Testing Redux Applications with Jest and TypeScript&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>react</category>
      <category>redux</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>Redux Testing: Hard-Earned Lessons Learned</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Tue, 23 Nov 2021 20:14:58 +0000</pubDate>
      <link>https://dev.to/xjamundx/redux-testing-hard-earned-lessons-learned-1o9e</link>
      <guid>https://dev.to/xjamundx/redux-testing-hard-earned-lessons-learned-1o9e</guid>
      <description>&lt;p&gt;To celebrate the launch of my new course &lt;a href="https://egghead.io/courses/confidently-testing-redux-applications-with-jest-typescript-16e17d9b" rel="noopener noreferrer"&gt;Confidently Testing Redux Applications with Jest &amp;amp; TypeScript&lt;/a&gt; I wanted to share some of the lessons I've learned about testing over my years of using redux in production react applications.&lt;/p&gt;

&lt;p&gt;Almost everything I learned through experience was already discovered by others and put down in the &lt;a href="https://redux.js.org/style-guide/style-guide" rel="noopener noreferrer"&gt;Redux Style Guide&lt;/a&gt; which I highly recommend reading and sharing with your teams.&lt;/p&gt;

&lt;p&gt;In particular I want to share four things that have helped me get to a place where I feel like I'm testing the right things without a lot of hassle. Here's that list:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stop Testing your Disconnected Components&lt;/li&gt;
&lt;li&gt;Build a Small Utility Library&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/xjamundx/redux-testing-lessons-learned-give-your-components-access-to-your-reducers-508k"&gt;Render Components with a Real Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Prefer Integration Style Tests&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One of the difficult things about bringing Redux into your apps is that any redux-connected component needs to be wrapped at some level in a redux &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt;. That &lt;a href="https://react-redux.js.org/api/provider" rel="noopener noreferrer"&gt;Provider&lt;/a&gt; ensures all components rendered in that tree use the same redux store. When you're building an app, you usually just add &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; at the top level and don't have to worry about it. When testing redux apps though it becomes a major pain. Each test for a redux-connected component has to be individually wrapped in its own provider. &lt;/p&gt;

&lt;p&gt;Many teams get around this by exporting a smart &lt;code&gt;connect()&lt;/code&gt;ed component and a basic (non-redux) version of the same component in the same file. They then just don't test the redux-connected version at all. Please don't do this.&lt;/p&gt;

&lt;p&gt;Avoiding testing your redux-connected components is a mistake for two reasons. The most obvious is that you're not testing the version of your component that your customers are going to use. This means you lose some confidence in your tests. You're explicitly leaving out important cases. The next reason is that the &lt;a href="https://egghead.io/courses/modernizing-a-legacy-redux-application-with-react-hooks-c528" rel="noopener noreferrer"&gt;redux hooks API&lt;/a&gt;, which provides a vastly superior developer experience to &lt;code&gt;connect()&lt;/code&gt; doesn't support this pattern. It's unlikely that you'll be able to continue to separate your component that way as you move into the future.&lt;/p&gt;

&lt;p&gt;A better approach is to create some utilities that simplify the way you setup and render your components. I use three in my course: &lt;code&gt;renderWithContext&lt;/code&gt;, &lt;code&gt;getStoreWithState&lt;/code&gt;, and &lt;code&gt;getStateWithItems&lt;/code&gt;. These utilities help me work with state and context without cluttering my tests with complex setup code. &lt;/p&gt;

&lt;p&gt;Let's start with the most simple one &lt;code&gt;getStoreWithState&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;configureStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@reduxjs/toolkit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;configureStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getStoreWithState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;preloadedState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;configureStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;preloadedState&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redux Toolkit includes a &lt;a href="https://redux-toolkit.js.org/api/configureStore" rel="noopener noreferrer"&gt;configureStore&lt;/a&gt; method that allows you to preload it with state. The &lt;a href="https://redux.js.org/api/createstore" rel="noopener noreferrer"&gt;createStore method&lt;/a&gt; in redux includes this option as well. In the old days I would rely on tools like &lt;a href="https://github.com/reduxjs/redux-mock-store" rel="noopener noreferrer"&gt;redux mock store&lt;/a&gt; to generate redux stores for testing, but you don't need it. You can generate a store for your tests that includes exactly the same reducers as your app, but also comes pre-loaded with whatever state you need for your tests.&lt;/p&gt;

&lt;p&gt;The next utility that you'll need is a way to render your components with state and context. For my tests I'm usually using &lt;a href="https://testing-library.com/docs/react-testing-library/intro/" rel="noopener noreferrer"&gt;React Testing Library&lt;/a&gt;, but the same approach works fine if you're using &lt;a href="https://enzymejs.github.io/enzyme/" rel="noopener noreferrer"&gt;enzyme&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderWithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getStoreWithState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;utils&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've seen a lot of test suites that include a &lt;code&gt;mountWithStore&lt;/code&gt; function inside of them, but I think you get a ton of benefit moving this into an app-wide utility file. It makes it a lot easier to pre-populate state consistently and provide any additional context that might be needed for your tests.&lt;/p&gt;

&lt;p&gt;With these two utilities in place it's fairly straight forward to render a component with arbitrary state pre-loaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;renderWithContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../test-utils&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error banner should appear&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;renderWithContext&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="cm"&gt;/* ...  */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toHaveTextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Could not load data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only other utility I found to improve on this a little bit is one that generates the whole app state for you, but lets you modify some piece you might want. Some apps put this state in a JSON file, which can be helpful, but having a utility function that lets you override some common parts has proven crucial. This will always be unique to your app, but here's one example of what that could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getStateWithErrors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;checkoutState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;READY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;errors&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that the test above might be written like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;renderWithContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getStateWithErrors&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../test-utils&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error banner should appear&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getStateWithErrors&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}]);&lt;/span&gt;
    &lt;span class="nf"&gt;renderWithContext&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toHaveTextContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Could not load data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error banner should not appear&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getStateWithErrors&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
    &lt;span class="nf"&gt;renderWithContext&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queryByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))).&lt;/span&gt;&lt;span class="nf"&gt;toBeNull&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this approach you can imagine making it easy to generate state where you only need to pass in a single error message while the function takes care of the rest.&lt;/p&gt;




&lt;p&gt;That's a bit about how utility functions have helped me write manageable and possibly enjoyable tests for my redux apps without having to resort to tricks that have made my tests less reliable. The next article in this series is &lt;a href="https://dev.to/xjamundx/redux-testing-lessons-learned-give-your-components-access-to-your-reducers-508k"&gt;Render Components with a Real Store&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to learn more about my approach to testing redux applications please watch &lt;a href="https://egghead.io/courses/confidently-testing-redux-applications-with-jest-typescript-16e17d9b" rel="noopener noreferrer"&gt;my course on egghead.io&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>redux</category>
      <category>webdev</category>
      <category>react</category>
      <category>testing</category>
    </item>
    <item>
      <title>Adding a REST API to your Vite Server in 5 Seconds</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Tue, 23 Nov 2021 18:04:40 +0000</pubDate>
      <link>https://dev.to/xjamundx/adding-a-rest-api-to-your-vite-server-in-5-seconds-270g</link>
      <guid>https://dev.to/xjamundx/adding-a-rest-api-to-your-vite-server-in-5-seconds-270g</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jjsr4utzivn42cjxjuq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jjsr4utzivn42cjxjuq.png" alt="Vite and Express" width="800" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like many others I've been blown way by the incredible performance and capabilities of &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;vite&lt;/a&gt; as a tool for rapidly building out React apps. In my role as an &lt;a href="https://egghead.io/q/redux-resources-by-jamund-ferguson?type=lesson,playlist" rel="noopener noreferrer"&gt;egghead educator&lt;/a&gt; and a &lt;a href="https://www.linkedin.com/in/jamund/" rel="noopener noreferrer"&gt;Developer Advocate at PayPal&lt;/a&gt; I'm looking for tools that install quickly, have minimal setup costs and let me start building &lt;em&gt;immediately&lt;/em&gt;. &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;vite&lt;/a&gt; does all that and more, but in the past I often run into one limitation: I need some kind of API to complement my apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F33nnws5jkxk06203mof5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F33nnws5jkxk06203mof5.png" alt="vite-plugin-mix on github" width="749" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've been using &lt;a href="https://github.com/expressjs/express/" rel="noopener noreferrer"&gt;express&lt;/a&gt; to build out APIs pretty much since it first came out. Checkout &lt;a href="https://egghead.io/courses/building-an-express-api-with-express-5-and-node-14-7b96" rel="noopener noreferrer"&gt;my course on using express 5&lt;/a&gt; if you want a quick tutorial. Express makes it easy to build out APIs and it's super easy to add express support to your vite app. You just need a single plugin: &lt;a href="https://github.com/egoist/vite-plugin-mix" rel="noopener noreferrer"&gt;vite-plugin-mix&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;I promised 5 seconds, so get ready to copy &amp;amp; paste!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; vite-plugin-mix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in your &lt;code&gt;vite.config.js&lt;/code&gt; file add this to your plugins array&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mix&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite-plugin-mix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./api.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then in &lt;code&gt;api.js&lt;/code&gt; type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you do that you can startup &lt;code&gt;vite&lt;/code&gt; with &lt;code&gt;npm run dev&lt;/code&gt; and like magic you'll have the ability to reference &lt;code&gt;/api/hello&lt;/code&gt; on your local dev server. Like everything else in vite, if you make any changes to your API they'll be available immediately without having to restart anything. Just edit the code and call the route again and you'll see the latest!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One little note:&lt;/strong&gt; I have only used vite so far for local development and can't personally vouch for it for production apps. If you're looking for something a bit more production ready you might want to check out &lt;a href="https://fastify-vite.dev/" rel="noopener noreferrer"&gt;fastify-vite&lt;/a&gt; which combines another popular API server, &lt;a href="https://www.fastify.io/" rel="noopener noreferrer"&gt;fastify&lt;/a&gt; with vite for one powerful and fast full-stack development tool.&lt;/p&gt;

&lt;p&gt;Happy hacking friends!&lt;/p&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>vite</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Two Simple Tricks for Typing Redux Apps with Typescript</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Fri, 23 Apr 2021 14:44:37 +0000</pubDate>
      <link>https://dev.to/xjamundx/two-simple-tricks-for-typing-redux-apps-with-typescript-1h7f</link>
      <guid>https://dev.to/xjamundx/two-simple-tricks-for-typing-redux-apps-with-typescript-1h7f</guid>
      <description>&lt;p&gt;Despite having used Typescript and Redux separately for a few years I haven't always had a good experience putting them together. Recently, I stumbled on two tricks that have helped me immensely. &lt;/p&gt;

&lt;h3&gt;
  
  
  Generate Reducer Type from Initial State
&lt;/h3&gt;

&lt;p&gt;When you're creating a new reducer you can use &lt;code&gt;typeof&lt;/code&gt; to generate the type for the reducer from your initial state. This also encourages us to fully fill out our initial state, which I find helpful for quickly understanding the purpose of each reducer.&lt;/p&gt;

&lt;p&gt;When you export your reducer make sure to include that generated type as its return type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;dogs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Callie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;green&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MyReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;myReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;MyReducer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your initial state doesn't include all of the values, you can include them as placeholder values such as &lt;code&gt;null&lt;/code&gt;. In those cases you can use &lt;code&gt;as &amp;lt;type&amp;gt;&lt;/code&gt; to indicate the intended type for that piece of state.&lt;/p&gt;

&lt;p&gt;For example &lt;code&gt;const initialState = { person: null as Person };&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Export Your Entire Redux State
&lt;/h3&gt;

&lt;p&gt;Once your reducers are all individually typed, you can create and export a combined &lt;code&gt;ReduxState&lt;/code&gt; type using Typescript's &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype" rel="noopener noreferrer"&gt;ReturnType&lt;/a&gt; utility. This type will contain information about every single reducer used in your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;reducers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./reducers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;combineReducers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducers&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ReduxState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use this to type the &lt;code&gt;state&lt;/code&gt; argument used by your selector functions, &lt;code&gt;mapStateToProps&lt;/code&gt; or anywhere else that may be needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ReduxState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nf"&gt;getDogs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReduxState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myReducer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dogs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;A version of these same ideas (and many others) can be found in the &lt;a href="https://redux.js.org/recipes/usage-with-typescript" rel="noopener noreferrer"&gt;Usage with Types&lt;/a&gt; section of the redux docs.&lt;/p&gt;

&lt;p&gt;While it doesn't cover typescript (yet!), don't forget to check out my course &lt;a href="https://egghead.io/courses/redux-with-react-hooks-8a37" rel="noopener noreferrer"&gt;Redux with React Hooks&lt;/a&gt; which shows how much simpler redux becomes when you drop the boilerplate.&lt;/p&gt;

&lt;p&gt;What are your favorite typescript tricks when using Redux?&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>redux</category>
    </item>
    <item>
      <title>My first git alias</title>
      <dc:creator>Jamund Ferguson</dc:creator>
      <pubDate>Fri, 16 Apr 2021 19:04:50 +0000</pubDate>
      <link>https://dev.to/xjamundx/my-first-git-alias-4ldh</link>
      <guid>https://dev.to/xjamundx/my-first-git-alias-4ldh</guid>
      <description>&lt;p&gt;At work I'm often jumping back and forth between various branches and pull requests and I sometimes find myself struggling to remember the name of a recent branch I need to use.&lt;/p&gt;

&lt;p&gt;For years I've used &lt;code&gt;git reflog&lt;/code&gt; as a short-cut to look at my git history and identify my recent work. It works okay, but it's very hard to make sense of:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fby2umf5k9jqztnpil2ym.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fby2umf5k9jqztnpil2ym.png" alt="git reflog output" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Other times I try to use &lt;code&gt;git branch&lt;/code&gt;, but that doesn't give you much context about anything and of course it can be easy to drown in the large number of branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/d/n/webapp (typescript ✔) git branch
  add-cognito-auth
  doritos
  eslint-prettier
  main
* typescript
  updated-husky
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recently I got frustrated by this and decided to find a solution and stumbled on this stackoverflow question, &lt;a href="https://stackoverflow.com/questions/5188320/how-can-i-get-a-list-of-git-branches-ordered-by-most-recent-commit" rel="noopener noreferrer"&gt;How can I get a list of git branches ordered by most recent commit?&lt;/a&gt;, which taught me two really useful techniques.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You can sort branches by commit date&lt;/strong&gt; using &lt;code&gt;git branch --sort=-committerdate&lt;/code&gt; which is great in an of itself (watch out for the &lt;code&gt;-&lt;/code&gt; after &lt;code&gt;sort=&lt;/code&gt; which puts the most recent branches first)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You can enhance this output a bit&lt;/strong&gt; using this wild syntax &lt;code&gt;git branch --sort=-committerdate --format='%(HEAD)%(color:yellow)%(refname:short) | %(color:bold green)%(committerdate:relative) | %(color:blue)%(subject)%(color:reset)' --color=always&lt;/code&gt; which I'm never going to remember.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Which led me to create my first git alias after over 12 years of using it. Here's how I did it and here's what it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config --global alias.branches "branch --sort=-committerdate --format='%(HEAD)%(color:yellow)%(refname:short) | %(color:bold green)%(committerdate:relative) | %(color:blue)%(subject)%(color:reset)' --color=always"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That command added this to the boottom of my &lt;code&gt;~/.gitconfig&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[alias]
        branches = branch --sort=-committerdate --format='%(HEAD)%(color:yellow)
%(refname:short) | %(color:bold green)%(committerdate:relative) | %(color:blue)%(subject)%(color:reset)' --color=always
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when I type &lt;code&gt;git branches&lt;/code&gt; I see this lovely output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fua9191j2s8wlcq8rc61k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fua9191j2s8wlcq8rc61k.png" alt="nicely formatted git branch list" width="757" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Git isn't always the easiest to use, but this alias has made it just a little bit better, for me anyway. What kind of aliases do you use?&lt;/p&gt;

</description>
      <category>github</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
