<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Joshua Comeau on Medium]]></title>
        <description><![CDATA[Stories by Joshua Comeau on Medium]]></description>
        <link>https://medium.com/@joshuawcomeau?source=rss-a11edf57e20a------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*HOhoDxXZomU-GTH3kqn5mQ.jpeg</url>
            <title>Stories by Joshua Comeau on Medium</title>
            <link>https://medium.com/@joshuawcomeau?source=rss-a11edf57e20a------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 23:43:39 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@joshuawcomeau/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[My Experience as a Remote Worker]]></title>
            <link>https://medium.com/@joshuawcomeau/my-experience-as-a-remote-worker-6ddd775a74e3?source=rss-a11edf57e20a------2</link>
            <guid isPermaLink="false">https://medium.com/p/6ddd775a74e3</guid>
            <category><![CDATA[remote-working]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[remote-work]]></category>
            <dc:creator><![CDATA[Joshua Comeau]]></dc:creator>
            <pubDate>Mon, 02 Dec 2019 15:19:03 GMT</pubDate>
            <atom:updated>2019-12-02T15:19:03.914Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>Note: This is a cross-post from <a href="https://www.joshwcomeau.com/posts/remote-work/"><strong>my personal blog</strong></a><strong>.</strong></blockquote><p>I had an interesting realization recently: I was three years into my career when I got my first remote job, and it’s been about three years since then. I’ve now spent half my career working in a traditional in-office software development job, and the other half working remotely!</p><p>Increasingly, remote work is becoming a common, mainstream thing. Twitter pundits have been quick to form and share opinions, and I’ve seen a lot of misconceptions and misinformation about what “remote work” is, and how it works.</p><p>This is part 1 of a three-part blog post series. Today, I’ll share what my experience has been like — it’ll be an honest look at the ups and downs of remote life. Hopefully, this context will be helpful if you’ve been considering remote work for yourself!</p><ul><li><strong>Part 1: My experience</strong></li><li>Part 2: Finding your first remote job</li><li>Part 3: Twitter Mailbag</li></ul><h3><strong>Clearing up misconceptions</strong></h3><p>Let’s start by getting this out of the way — most people talking about remote work are describing something <em>very different</em> from my experience.</p><p>For example, this common refrain:</p><blockquote>“Remote work sounds great because you can work from home in your pyjamas, but it’s not all it’s cracked up to be, because soon you’ll discover how isolating it is to spend all day alone”</blockquote><p>This discussion is predicated on a false idea, that “remote work” is synonymous with “working from home”, and that it means you work alone.</p><p>I think it would surprise people just how much my “remote work” lifestyle looks like their “normal office” lifestyle:</p><ul><li>I get up early, shower, change into street clothes, and commute every weekday to an office</li><li>I work from around 9:30am to around 5:30pm, grabbing lunch around 11:45am (gotta beat that lunch rush!)</li><li>I have regular meetings with my coworkers, doing things like pair programming with my peers, or hashing out implementation details with product &amp; design</li><li>I socialize in-person with other folks at the office.</li></ul><p>This schedule is not universal to remote workers, and that’s kind of the point — the idea with remote work is that <em>it’s flexible</em>. It allows you to construct whatever working situation works for you. Plenty of remote workers <em>do</em> work from home (though none that I’ve met have been the unshaven recluse so often depicted in remote-work discussions), but they do it because that’s the situation that works best <em>for them</em>.</p><h3><strong>Developing my working environment</strong></h3><p>I realized pretty quickly that working from home wasn’t going to work for me.</p><p>When I started working remotely for Khan Academy, I rented an office at WeWork. It ticked a bunch of boxes, but ultimately it wasn’t the right fit. It was rowdy at times. It was also kinda dreary — they keep their lights dim, so there’s a perpetual 7pm vibe. Despite having all-glass walls, my office wasn’t anywhere near natural light. The office I was renting was small enough that if I stood in the center, I could just about touch all 4 walls without moving.</p><p>About a year ago, I switched to a new office.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*hleR9RuQwyVQ6S7r.jpg" /></figure><p>I’m subletting it from a local Montreal company, located in Old Montreal. It’s not really a coworking space; it feels less like a trendy startup incubator and more like a traditional small business. It grants me the perfect level of in-person social interaction; there are always people around I can talk about hockey or the weather with.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*j03GCKX4yrum7Z7j.jpg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*8qXjzCaISK7drGa7.jpg" /></figure><p>My office is big and bright, featuring tall ceilings and a large window. It overlooks a public square, and I’ve set up a digital piano in front of it, so I can take frequent breaks and watch tourists meander while I noodle on the keyboard. It’s pretty great.</p><p>I am very aware that this office is a privilege that many cannot afford — it costs $700 CAD / $525 USD a month. In many cases, though, employers are willing to contribute towards these costs, either in part or in full. And this additional expense is often smaller than the bump in salary folks receive when transitioning to remote work.</p><h3><strong>Notable differences</strong></h3><p>For the most part, I’ve been surprised to see how <em>similar</em> remote work is from in-office work. There are some things that are different, though. Let’s look at them in depth.</p><h4><strong>Salary</strong></h4><p>I live in Montréal, Québec. According to <a href="https://www.payscale.com/research/CA/Job=Software_Developer/Salary/d8efee6e/Montr%C3%A9al-QC">Payscale</a>, the average Montreal software developer makes about $65,000 CAD, about $49,000 USD. This is dramatically less than in the Bay Area, where <a href="https://www.payscale.com/research/US/Job=Software_Engineer/Salary/a5e48575/San-Francisco-CA">Payscale</a> estimates the average salary at around $118,000 USD. That’s a <strong>2.4x multiple</strong>!</p><p>Remote-friendly companies don’t always pay Bay Area salaries, but in my experience, they tend to pay quite a bit better than local ones. For example, Buffer pays based on San Francisco rates, and <a href="https://buffer.com/salary/software-engineer/low">deducts up to 25% for cost-of-living</a>. This feels pretty harsh to me, and yet it still comes out to a much more generous salary than is common in Montreal.</p><p>If you already live in a high-pay, high-cost-of-living area like San Francisco or New York City, working remotely can grant you the freedom to move wherever you’d like. While not everyone can uproot their family and move, it’s still better to have the option than not.</p><blockquote>It’s worth noting: companies are moving away from cost-of-living multipliers. Employees should be paid based on the value they provide, not where they happen to live. The truth is that all kinds of things affect how much of our income is discretionary, such as having kids or being in debt, and employers have never adjusted salaries for those things. If you’re providing Bay Area value, you deserve Bay Area dollars!</blockquote><h4><strong>Meetings</strong></h4><p>One of the myths of remote work is that it’s “lone wolf” territory, meant for contractors who need little guidance and have little oversight. The truth is that all of my years as a remote worker have been fairly collaborative, working within tight-knit teams to develop and ship features.</p><p>As a remote worker, I have roughly the same number of meetings as I did when I worked in-office.</p><p>Most remote-friendly companies will have a policy that every meeting room is equipped with video-conferencing software, and every meeting has a Google Hangout or Zoom session created for it. This way, remote folks can join any meeting added to the calendar without meeting organizers having to do anything special.</p><p>It can be hard to fully participate, though. It’s human nature to interact primarily with the people in the same space as you. As a remote employee, your disembodied, televised head is often floating out of eye-line, off in the background. As conversation picks up, it can be hard to get a word in edge-wise. If you wait for the perfect opportunity, you might never have a chance to speak. And if you decide to interject haphazardly, you’ll be the booming voice of God, a gigantic face stretched across a 72&quot; screen, causing heads to swivel around like a mob of startled meerkats. I don’t like drawing that much attention to myself.</p><p>If you work for a fully-distributed company, this isn’t a problem, since everyone’s on their own laptop. And many companies are moving to a model where all meeting participants join on their own computer, even those in the same room together. This ensures a level playing field, and makes it much easier for remote participants to participate.</p><h4><strong>Being kept in the loop</strong></h4><p>A concern many folks have about remote work is that inevitably, no matter how much Slack is stressed, two employees will bump into each other in the office and share information or make decisions. Folks in other timezones and countries will miss out on that information, and sometimes this can make it harder to be effective at your job.</p><p>I can definitely think of times where, say, I spent a day working on something only to learn that the feature isn’t needed anymore… but the thing is, that’s happened to me both as a remote worker <em>and</em> as an in-office worker. Communication challenges are not unique to remote work. And the solutions are pretty much the same:</p><ul><li>Daily standups ensure visibility around what everyone is working on, and if they’re blocked by something</li><li>Being a good communicator, and being sure to follow up frequently. If I’m picking up a ticket from Jira that hasn’t had a comment on it in 4 months, for example, my first step is to contact the stakeholders and make sure the issue is still relevant.</li><li>Working in small (<a href="https://buffer.com/resources/small-teams-why-startups-often-win-against-google-and-facebook-the-science-behind-why-smaller-teams-get-more-done#:~:targetText=According%20to%20Bezos%2C%20the%20ideal,and%20talk%20with%20our%20customers.">“two pizza”</a>) teams, and checking in with teammates frequently</li></ul><p>People assume that it’s harder to stay in touch with people when you don’t work out of the same space, but I’d argue it’s the opposite. Tools like Slack let you instantly fire off a message, without worrying if you’re interrupting someone deep in concentration. When I worked in-office, I was always hesitant to walk over to someone hard at work. Slack gives me license to talk to people <em>more often</em>, not less.</p><h4><strong>Loneliness, and forming personal connections at work</strong></h4><p>Of the articles and Twitter threads I’ve read from people who <em>have actually tried remote work</em>, this is the most common issue. For folks who are used to working in an office, it can be hard to transition to a model where you only speak with your co-workers over screens, where there are no Thursday-evening game nights, mini birthday celebrations, or group lunches. In an office, it’s easy to spend twenty minutes by the watercooler, just hanging out with your peers. Those serendipitous interactions don’t occur remotely, every communication is intentional.</p><p>In my case, I’ve solved for this by renting an office. The people I share this space with technically aren’t coworkers — we don’t share an employer — but that doesn’t stop us from gossiping about the <a href="https://www.nhl.com/canadiens">Habs</a>, currently on their <a href="https://www.nhl.com/news/montreal-frustrated-during-losing-streak/c-292146694">worst losing streak since 1940</a>, or sharing vacation pictures with each other.</p><p>It’s also self-evident to me that it’s possible to form close personal relationships with remote coworkers — I’m still friends with many folks I worked with at my first remote job! It may not be ideal, but it works. If hit TLC television show <a href="https://www.tlc.com/tv-shows/90-day-fiance/">90 Day Fiancée</a> teaches us anything, it’s that humans are remarkably good at overcoming the artificial nature of long-distance communication.</p><p>Another important consideration: depending on where you live, and the size of the organization, you may not be alone in your city! I live in Montreal, a city not really known for being a tech hub, but when I worked at Khan Academy, I had two coworkers that lived here. Once every month or so we’d grab coffee and co-work together, either at a co-working space or at a coffee shop. Many orgs will rent out a small office for cities that reach a certain threshold, blurring the line between “remote work” and “flexible in-office work”.</p><h4><strong>Remote mentorship</strong></h4><p>Many folks I’ve spoken to have expressed concern around mentorship; for folks early in their careers, are they at a disadvantage by not being in the same room as the senior devs?</p><p><strong>Stress and asking for help — </strong>I remember when I was about a year into my career, I was working at a local startup and I had gotten myself into a big mess with Git. I was worried I’d accidentally erase all the progress I’d made on the task that day. The senior dev sat right near me — I could walk over and tap him on the shoulder, but what if he was in the middle of something? I imagined the frustration he might feel, watching his mental house-of-cards collapse as his focus evaporated, all because some sheepish junior dev doesn’t understand source control.</p><p>Now that I’m a senior developer myself, I recognize how silly this thought was — I’m always happy to help when someone needs it! But that fact is irrelevant; junior devs often worry about stuff like that, and that worry can lead to bad outcomes, like not asking for help when it’s needed.</p><p>There’s something to be said for Slack’s asynchronous model. It’s so much easier to send someone a message, knowing they probably won’t see it right away if they’re deep in concentration.</p><p><strong>Receiving help online — </strong>What about the actual getting-help itself? Surely it’s better for two devs to sit side-by-side when explaining a problem? I’m not so sure. Tools like Screen Hero (RIP) and Slack’s video conferencing let two people share a screen, each with their own connected mouse and keyboard. Pair programming works really well when the “driver” can use their cursor to indicate a specific line, or draw on the screen using a pencil tool. I expect the tooling will only improve as remote work becomes more common!</p><p>Also, I feel like text chat is underrated for stuff like this. It lets the explainer choose their words carefully, and make sure the explanation makes sense. And it provides a permanent transcript that the person being helped can reference in the future, if the explanation doesn’t stick.</p><p><strong>Remote intern mentorship — </strong>One more anecdote: every summer at Khan Academy, we’d hire a class of college interns. Every intern would be assigned a mentor, a point person to provide technical guidance, assign and review work, and generally make sure that the intern was having a happy, healthy, educational summer.</p><p>Mentors could either be remote or in-office, and after a few summers we concluded that it made no difference; interns were as likely to succeed regardless of whether their mentor was sitting next to then in Mountainview, or (as in my case) over 1000 miles away.</p><p>I was an intern mentor myself, and it was incredibly fulfilling! I don’t believe being remote was a hindrance at all.</p><p><strong>Proceed with caution — </strong>Despite all of this, I still recommend proceeding cautiously as a junior developer seeking remote work. I’ve had the privilege of working for stand-out organizations that have put a lot of resources into making the remote culture succeed. If certain conventions aren’t in place, it <em>can</em> be much harder to receive mentorship as a remote employee. I’ll talk more about this in the next post in this series.</p><h4><strong>Career progression challenges</strong></h4><p>I’ve had the privilege of working remotely for several different organizations now, and I’ve seen how different structures can lead to different cultures.</p><p>At one role in particular, about 50% of the engineering department was remote, while 100% of the executive team (and most managers) were in-office. A good chunk of the executive team was new to the org, and they had come from organizations that were not remote-friendly. This meant that in-office “individual contributors” (ICs) were able to form relationships with senior leadership in a way that remote workers weren’t.</p><p>I remember during a particularly contentious period, hearing from an in-office friend that a member of the senior leadership team had come up to them, bewildered to learn that remote workers were unhappy with recent policy shifts. This member of the exec team went to an <em>in-office</em> IC for clarification about how <em>remote folks</em> were feeling, because that’s who they knew.</p><p>This problematic dynamic was highlighted during performance reviews. As in many organizations, promotions were determined by senior leadership, and the process was not super transparent. When a remote worker is denied a promotion, it’s hard not to wonder if personal relationships played a part; after all, wouldn’t anyone have a subconscious bias towards the folks they have lunch with every day vs. someone they barely know?</p><p>These kinds of “office politics” are not unique to remote workers — at any organization, there’s the risk of executives biasing promotions towards folks they like. Even if everyone works in the same space, there’s no guarantee that relationships will form equally! And I suspect it’s human nature to reach for external factors when trying to understand why we weren’t selected for a promotion.</p><p>Despite these caveats, career progression can definitely be harder for remote workers if the company isn’t fully distributed. In the next part of this blog post series, we’ll dig into this a bit more as we learn more about how to find a great remote job.</p><h3><strong>Conclusion</strong></h3><p>The goal of this blog post was to share my experiences as a remote worker, with the hope that it provides a bit of clarity around whether or not remote work could be a good fit for you. And it’s a hard question to answer, since “remote work” can mean so many different things. Very few of the experiences I’ve had — both good and bad — are universally true for remote work.</p><p>Ultimately, looking back, there have definitely been some bumps on my remote journey, but the overall experience has been very positive. I don’t expect I’ll go back to traditional in-office employment any time soon.</p><p>I do think I’m a particularly well-suited person for remote work, though. When I worked in-office, I was on a perpetual mission to find a way to eat lunch alone, without offending anyone or arousing concern. I had wonderful co-workers, but my idea of a perfect lunch is sitting alone in a park, listening to a podcast. In that sense, remote work is a perfect fit for me.</p><p>While I do think the concern about isolation as a remote worker is overblown — after all, I’m around people constantly — it is true that it can be harder to form close personal relationships with folks you’re working <em>around</em>, rather than working <em>with</em>. Making friends as an adult is tough! If your current social network is comprised primarily of people you work with, and you thrive on that sort of camaraderie, remote work might be more of an uphill climb for you.</p><p>Aside from this, I believe the other concerns folks have about remote work can be mitigated, either by customizing your work environment, or finding a company with the right kinds of remote policies for you.</p><p>In Part II of this blog post series, we’ll look at how to go about finding your first remote job, and how to ensure that it’s setting you up for success. I’ve been involved in hiring for several remote-friendly orgs, and I’ll share what companies are looking for. We’ll also examine how to evaluate the “remote-friendliness” of a company, and learn to dodge some bullets.</p><p>I talk about remote work quite a bit <a href="https://twitter.com/JoshWComeau"><strong>on Twitter</strong></a>, so be sure to follow me there if this kind of stuff is your jam. I also share cute animals and React stuff. And be sure to check out <a href="https://www.joshwcomeau.com/"><strong>my actual blog</strong></a>, which features rich interactive posts not possible on Medium.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6ddd775a74e3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Clever code considered harmful.]]></title>
            <link>https://medium.com/@joshuawcomeau/clever-code-considered-harmful-a1fb1054e8a1?source=rss-a11edf57e20a------2</link>
            <guid isPermaLink="false">https://medium.com/p/a1fb1054e8a1</guid>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Joshua Comeau]]></dc:creator>
            <pubDate>Wed, 13 Nov 2019 23:09:16 GMT</pubDate>
            <atom:updated>2020-03-19T15:01:08.484Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yZqKiyJ4gWwvkD37Rs-xMA.jpeg" /></figure><p>There is something undeniably satisfying about coming up with clever solutions to hard problems. There is a joy when you challenge yourself to use recursion instead of iteration, for example, or when you create elegant, cascading layers of abstraction that ensure code is never duplicated.</p><p>My favourite outlet for this kind of programming is <a href="https://projecteuler.net/">Project Euler</a>.</p><p>Project Euler is a repository of challenges based around advanced mathematics, meant to be solved with software. The catch is that your program should run in under a minute, on 2004-era hardware. That means that a brute-force solution often won’t cut it, and you’ll have to come up with a smarter solution.</p><p>Here’s an example:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sbbO5gKvxk-TuJOIRMUzKA.png" /><figcaption>Helpful tip: Euler is pronounced “Oiler”. Impress your math friends with this knowledge!</figcaption></figure><p>The fun thing about these challenges is that they <em>seem</em> near-impossible at first (at least, to someone like me, who doesn’t have a math background), but often once you start breaking down the problem and experimenting, you arrive at a solution surprisingly quickly.</p><blockquote>At least, <em>sometimes</em>. Other times, the problems remain inscrutable. Looking at you, <a href="https://projecteuler.net/problem=60">Problem 60</a>.</blockquote><p>Once you’ve solved a problem, you’re able to view solutions that other solvers have posted. And oh wow, do people come up with terse, clever solutions for these things.</p><blockquote>I’m kinda breaking the Project Euler rules here — you’re not supposed to share solutions, to avoid spoiling it for others — but don’t worry, these solutions are totally indecipherable, at least for folks like me coming from a JS background. You won’t spoil the challenge.</blockquote><h4>A Haskell solution</h4><p>Haskell is a notoriously tricky functional language that allows for really concise solutions to hard problems:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d1a9a113709778041a2ffa65d1765a9b/href">https://medium.com/media/d1a9a113709778041a2ffa65d1765a9b/href</a></iframe><h4>A J solution</h4><p>This <a href="https://en.wikipedia.org/wiki/J_(programming_language)">J lang</a> solution takes the cake for brevity. J has a rich library of operators, consisting of one or more symbols, and so you can express a ton of logic in a small amount of space:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/65097f8c258e1a4179aed318c7f1846c/href">https://medium.com/media/65097f8c258e1a4179aed318c7f1846c/href</a></iframe><p>These solutions leave me pretty awestruck. Clearly these solutions are pretty remarkable. It’s a true skill, and I’d bet the author of this solution felt tremendously pleased with themselves — and rightfully so — for coming up with it.</p><p>But, there’s a <strong>big difference</strong> between recreational programming on your own, and working collaboratively on a shared codebase. When you’re at your day job, or working on a shared open-source project, there are an entirely different set of priorities.</p><h3>A good barometer: will an intern understand it?</h3><p>A metric I like to use when writing code is this: will an intern / bootcamp grad / someone just starting their career struggle to understand what I’ve written?</p><p>In the context of a shared codebase, good code is simple code. Code that doesn’t do anything fancy. Code that makes minimal use of abstractions. Code that you’d use to explain fundamental concepts to novices.</p><p>Let’s look at an example of some code that does some data-munging. Which version of this function do you think is clearer to a new programmer?</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d5325bb935c516c808ae8a3502b0c068/href">https://medium.com/media/d5325bb935c516c808ae8a3502b0c068/href</a></iframe><p>Version 2 has a number of things going for it, on paper:</p><ul><li>Less code.</li><li>Less duplication.</li><li>Follows functional-programming principles, like using generic utility functions, reduce, immutability, etc.</li><li>More scalable, could easily handle 10+ fields instead of 2.</li></ul><p>And yet, how much longer does it take to understand? How many more calories would be burned, as a new programmer, trying to make sense of it?</p><p>Version 2 ticks a lot of the boxes as to what “good” code is, at least in certain circles. But there is a <em>huge</em> readability cost for those characteristics, and in my opinion, it’s a bad deal.</p><blockquote>To be clear, I’m not saying that Version 2 is bad, just that it prioritises the wrong things. Everything is tradeoffs, but I believe that readability is king when it comes to shared code.<br> <br>Also, I am aware that neither version is ideal. This is the best example I could find, but it’s far from a perfect example.</blockquote><h3>Why is readability so important?</h3><p>To understand why I think readability is such a crucial attribute of good code, let’s look at a popular open-source library, <a href="https://github.com/lodash/lodash">lodash</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cDMSqwCi1aSPRxXdG5PUzg.png" /></figure><p>lodash is an immensely popular tool. It’s downloaded more than 26,000,000 times a week on NPM alone, and has over 42,000 Github stars. There is something absolutely curious about it, though; It often has <em>0 open issues</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/197/1*_gno-V8wVxKoLg-mLy_djA.png" /><figcaption>A real screenshot I took once</figcaption></figure><p>This has been true for years now, even when lodash was an essential library for a huge chunk of web developers. How can this be?!</p><p>Well, one reason is that the library’s primary author, John-David Dalton, is a passionate maintainer who spends a lot of his time triaging issues as they come in. But I don’t believe anyone, no matter how superhuman, can get a library this popular to 0 issues alone.</p><p>Years ago, I heard JDD on <a href="https://podcasts.apple.com/us/podcast/012-jsair-lodash-open-source-with-john-david-dalton/id1066446588?i=1000364088851">a podcast</a> talk about how the key to managing a project like this is to encourage lots of folks to contribute to it. One of the ways he’s done this is by keeping the code at a pretty fundamental level; by using simple, basic constructs, it ensures that aspiring contributors can understand and contribute to the code, regardless of how much experience they have. I believe JDD mentions that they prefer if/else to ternaries simply because less people have experience with ternaries. When the goal is to keep the code simple, the expressive power of the ternary operator is detrimental.</p><p>This is important to keep in mind if you’re building an OSS tool, but it’s <em>even more important</em> if you’re working in a production codebase with other humans. Especially ones that have less experience than you.</p><h3>A plethora of benefits.</h3><p>Have you ever heard someone say this?</p><blockquote>“Less code means less space for bugs to hide”</blockquote><p>Proponents of terse, sophisticated code will argue that for every added character, you’re increasing the likelihood of inadvertently introducing a bug, as though the bugs are an invasive species, just waiting for you to type it up a new hideout.</p><blockquote>There was going to be a fun image of lurking bugs here, but all the google results I got for “bugs hiding” were <strong>absolutely horrifying, </strong>so nevermind.</blockquote><p>While it may be true that every character stroke increases the likelihood of a <em>typo</em>, those issues are easily caught and quickly resolved. The pernicious bugs— the ones that tend to break user experiences for <em>weeks</em> as developers pass the support ticket around like a hot potato— are often caused by too much <em>complexity</em>, not too many characters.</p><p>In order to debug an issue, you have to wrap your mind around what the code is doing. When you create an abstraction to reduce duplication (“Make it DRY”), you add a layer of indirection that your mind has to unpack. The harder it is for your mental model to account for every edge-case and possible state, the more likely it is that you’ll have trouble diagnosing what’s gone wrong.</p><blockquote>“Everyone knows that debugging is twice as hard as writing a program in the first place. So if you’re as clever as you can be when you write it, how will you ever debug it?”</blockquote><blockquote>— <a href="https://en.wikipedia.org/wiki/Brian_Kernighan">Brian Kernighan</a>, The Elements of Programming Style</blockquote><h3>The cost of abstractions.</h3><p>If the goal is to reduce complexity, and abstractions add complexity, should we abolish abstractions altogether?</p><blockquote>I even came up with a silly acronym for this idea! WET — Write Everything Twice.</blockquote><p>Well, no. Abstractions are pervasive — loops are abstractions. Functions are abstractions. Programming languages themselves are abstractions over machine code, which itself is an abstraction over transistors flickering off and on really fast. It’s abstractions all the way down.</p><p>The key is to weigh the cost of an abstraction against its benefit. Say we’re building a React app, and we have a list of 100 things to render. We could copy/paste the same JSX 100 times, or we could map over an array and write the JSX once. The “complex” solution in this case is totally worth it, because the underlying complexity is commonly known, and the alternative would be burdensome to maintain.</p><p>As we build stuff, we make trade-off decisions like this all the time. If I have a point, it’s that we should consider these tradeoffs with the junior coder in mind; how much complexity are we adding for them? Is it worth it?</p><h3>Inevitable complexity.</h3><p>Code sometimes has to be complex, because the real world is complex and our software has to model it! We won’t always be able to write code that a junior engineer can easily parse and contribute to. Sometimes the business logic is genuinely really tricky, sometimes we have to use an API with an inscrutable interface, and so on.</p><p>I think the best way to deal with this is to try and sequester complexity. Set up clear boundaries between the simple stuff and the complex stuff. Don’t let the complexity seep into the surrounding areas.</p><p>John-David Dalton did this with lodash. According to his interview in <a href="https://podcasts.apple.com/us/podcast/012-jsair-lodash-open-source-with-john-david-dalton/id1066446588?i=1000364088851">that same podcast</a>, the vast majority of lodash code is simple and easy-to-follow, and they’ve pushed the complex bits to a sophisticated core that handles the hard problems. This means that most contributors are spared from having to deal with that complexity, since it isn’t sprinkled across the application.</p><p>If your app is architected so that the most complex concerns are all dealt with in the same place, you can keep the overwhelming majority of your app’s surface area simple.</p><p>What if the junior engineer needs to work on that complex core? Well, good news! They have a more-senior person (you) to help guide them through it. Mentorship and education is a huge part of being a senior developer.</p><h3>In conclusion.</h3><p>One of my favourite talks from React Rally last year was <a href="https://www.youtube.com/watch?v=-NP_upexPFg">Chantastic’s “Hot Garbage; Clean Code is Dead”</a>. I won’t spoil the talk (seriously, go watch it!), but one of the takeaways I took from it is that everyone suffers from impostor syndrome, and one of the problems with that is that we’re always trying to prove to each other that we know our shit. If we write really clever code that nobody else can understand, they’ll recognise how smart and capable we are!</p><p>Hopefully by this point in the blog post, if I haven’t failed spectacularly, it’s clear why that idea is flawed.</p><p>Over the past few years, my thinking has shifted. The code that impresses me is code that I can understand quickly. Turning a complex problem into simple code is an incredibly hard challenge, and so much more impressive than solving a simple problem with a complex solution.</p><p>My goal now isn’t to write clever code, my goal is to write welcoming, accessible code.</p><p>Thank you for coming to my TED talk.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a1fb1054e8a1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Lessons Learned as a Conference Speaker.]]></title>
            <link>https://medium.com/@joshuawcomeau/lessons-learned-as-a-conference-speaker-7d74750bc618?source=rss-a11edf57e20a------2</link>
            <guid isPermaLink="false">https://medium.com/p/7d74750bc618</guid>
            <category><![CDATA[conference]]></category>
            <category><![CDATA[public-speaking]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Joshua Comeau]]></dc:creator>
            <pubDate>Mon, 27 Aug 2018 16:47:17 GMT</pubDate>
            <atom:updated>2018-08-28T12:55:31.811Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/319/1*DVJ8wTUQuZY_CyUFueVPkA.jpeg" /><figcaption>React Rally 2018 logo</figcaption></figure><p>Earlier this month, I had the incredible privilege of speaking at React Rally, one of my favourite React conferences. It was amazing.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FXjFR9Jc-ras%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DXjFR9Jc-ras&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FXjFR9Jc-ras%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/14877be6df01d1b1ae8fae69112dafdf/href">https://medium.com/media/14877be6df01d1b1ae8fae69112dafdf/href</a></iframe><p>This was my second conference talk this year — the first being at <a href="https://www.youtube.com/watch?v=Z2d9rw9RwyE"><strong>React Europe</strong></a> — and so I wanted to take a step back and reflect a bit on the process. I remember being very curious about how speaking at tech conferences worked, before I started speaking; it felt pretty veiled and mystical to me.</p><p>My hope is that this post will be illuminating, especially for folks looking to get started as a speaker. I’ll go through some of the things that worked for me. Your mileage may vary, of course; this is just my experience.</p><h3>1. 💡 Coming up with an idea.</h3><p>The first step to any conference talk is figuring out what you want to talk about!</p><p>There are a lot of ways to approach this, but my favourite is to come up with something you feel passionate about, and that you feel isn’t getting enough attention.</p><p>In my case, I was really passionate about “explorable explanations”. <br>An explorable explanation, sometimes just called an explorable, is a project that mixes elements of data visualization, web applications, and video games to create interactive learning experiences. Their goal is to lower the bar for complex subjects by letting the user discover how it works through exploration and experimentation.</p><p>Some great examples of explorable explanations:</p><ul><li><a href="http://polytrope.com/district/"><strong>District by Christopher Walker</strong></a></li><li><a href="https://ncase.me/polygons/"><strong>Parable of the Polygons by Vi Hart + Nicky Case</strong></a></li><li><a href="https://learningmusic.ableton.com/"><strong>Learn Music Production from Ableton</strong></a></li><li>Tons more available on <a href="https://explorabl.es/"><strong>Explorabl.es</strong></a></li></ul><p>I decided in late 2017 that I wanted to build my own explorable about how waveforms work. It’s a subject I studied a decade ago, and thought could really benefit from being taught in an interactive way.</p><p>After several months of work, the project was launched: <a href="https://pudding.cool/2018/02/waveforms/"><strong>Let’s Learn About Waveforms</strong></a>.</p><p>The response to this project was overwhelming. I got <em>so many </em>deeply-personal thankful emails, from audio students, to people who had struggled learning it on their own, to teachers and college professors who want to use this tool to explain audio or physics concepts in class.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6mDJabC8xTq9xgAUOBldgQ.png" /><figcaption>An example of the kind of feedback the project received.</figcaption></figure><p>It made me realize that there is a strong need for this kind of content. React developers already have most of the skills needed to produce these kinds of experiences, so why aren’t more of us doing it?</p><p>A conference talk seemed like a great way to spread this message, and get folks excited about building their own explorables.</p><p>More broadly, I’m always fascinating by interesting intersections between disparate things. I’d love to see <a href="https://github.com/terkelg/awesome-creative-coding"><strong>creative coding</strong></a> represented more at programming conferences, for example!</p><p>Another category of “things we aren’t hearing more about” are things that our users need, that we tend to neglect: stuff like accessibility, localization/internationalization, performance. If you have ideas to make these things easier, even if they’re still hypothetical, I think it’s super worth pursuing!</p><h3>2. 👀 Finding a Conference.</h3><p>Once you have an idea for a talk, you’ll want to find a conference to submit it to!</p><p>A great resource for finding conferences is <a href="https://confs.tech/"><strong>confs.tech</strong></a>. There’s also <a href="https://github.com/asciidisco/web-conferences-2018"><strong>this repo</strong></a> full of web conferences.</p><p>Finally, you can find specific conferences by topic; if you work with React.js, for example, you can check the <a href="https://reactjs.org/community/conferences.html"><strong>React conferences list</strong></a> to find suitable conferences.</p><p>Not all talks will work for all conferences, so you should spend the time to get a sense of what a conference’s “feel” is.</p><p>Additionally, there may be restrictions associated with travel. Being Canadian, I’m fortunate enough that I can travel to most countries in the world without a lot of hassle, but this is not universally true.</p><h3>3. 📑 Submitting a proposal.</h3><p>Conferences generally have a few invited speakers, but the majority of the lineup will come from a process known as CFP — “Call for Proposals”. This is an open submissions process where anybody can submit proposals for giving a talk.</p><p>While every conference has their own submission guidelines, there are some common trends:</p><ul><li>A conference will accept proposals for several weeks/months, typically a few months before the conference. This gives you plenty of time to work on your talk, if it’s accepted.</li><li>There is a “CFP season” in the spring, when a large amount of conferences open up for submissions. Don’t worry if you miss the season, though — there are conferences year-round, so there are always conferences looking for proposals.</li><li>You’ll often need to provide a short public-facing blurb, as well as a more detailed outline that the conference organizers will use to help them decide.</li></ul><h4>Conference-Driven Development.</h4><p>A widely-known secret is that most of the time, conference speakers only have a vague idea about their talk when they submit their proposals. Especially for technical talks, it’s common to submit a proposal for a rough hypothesis, and to figure out the technicalities after it’s accepted.</p><p>Perhaps most famously, <a href="https://twitter.com/dan_abramov"><strong>Dan Abramov</strong></a> applied to speak at React Europe 2015 by pitching a new take on Flux that supported hot-reloading and time-traveling. This solution eventually became Redux, although he hadn’t actually gotten it working when his proposal was accepted!</p><p>There are a bunch of other examples as well:</p><h3>Kent C. Dodds on Twitter</h3><p>@JoshWComeau @dan_abramov In preparation for a talk I was giving about angular-formly, I made HUGE leaps and bounds in its capabilities leading up to the conference (https://t.co/l4WTlbOITi). Half of the things I talked about I had just barely published (https://t.co/gTED58Q8qW)</p><h3>Vincent Riemer on Twitter</h3><p>@JoshWComeau @dan_abramov While not as intense as proposing something you haven&#39;t built yet, the initial brainstorming and decision to go through with building RNDom was largely motivated with the desire to present something cool at React Conf</p><h3>Jared Forsyth on Twitter</h3><p>@JoshWComeau @dan_abramov just about all of my talks have some amount conference-driven development :)</p><p>Be warned, though, that this isn’t always the best idea. In addition to the added stress of having a hard deadline, you might kill your enthusiasm for the subject by overworking yourself:</p><h3>Max Stoiber on Twitter</h3><p>@JoshWComeau @dan_abramov Myself and @nikgraf also did that with carte-blanche at ReactEurope 2015 (?), in case that&#39;s helpful. We worked ourselves to death and then couldn&#39;t stand the project afterwards anymore... Maybe a good cautionary tale.</p><h4>Breaking in.</h4><p>While there is value in having experienced speakers deliver talks, nobody wants to see the exact same faces, year after year.</p><p>Happily, there are constantly new speakers giving talks. At React Rally this year, <a href="https://twitter.com/swyx">Shawn Wang</a> gave his <a href="https://www.youtube.com/watch?v=SaO-7Lk5hZ8">first-ever conference talk</a>, and it was great.</p><p>Some tips on breaking in:</p><ul><li>It can be easier to book a lightning talk than a full-length talk. My first-ever talk was at React Europe last year, where I gave a 5-minute lightning talk on <a href="https://www.youtube.com/watch?v=byCfsEP2gPk"><strong>components that don’t return React elements</strong></a>.<br> <br>Many conferences won’t cover travel expenses for short lightning talks, though. Frustratingly, this means that this option may not be available to folks without “professional development” budgets from work, or enough disposable income to afford the plane and hotel.</li><li>It’s often very easy to book a speaking gig at a local meetup (lots of meetups struggle to find speakers, and so there often isn’t any sort of approval process, you just email the organizers).<br> <br>Many CFP forms ask for recordings of previous talks; if you can get a recording of yourself speaking at a local meetup, you’ll have a huge advantage.</li><li>Many conferences will have an initial “blind round”. This means that proposals are evaluated purely by the submission itself, and nothing is known about the proposal’s author. This is a huge boon for first-time speakers, as they don’t have to compete in terms of speaking experience.</li><li>Don’t be afraid of asking for help! My schedule can be pretty hectic but in general I’m always up for helping review CFP proposals, <em>especially </em>for LGBTQ / underrepresented folks. Many speakers with more experience than me also make themselves available to help review proposals.</li></ul><h4>Don’t get discouraged.</h4><p>The sad reality is that conferences receive far more submissions than they have slots for. Many conferences can only accept 5% of submissions (or less).</p><p>You will get rejection emails. I think I’ve been profoundly lucky, and I still get rejected ~75% of the time.</p><p>If you have a talk you really want to give, don’t let a string of rejections stop you from giving it. Record it yourself at home, and share it on Twitter. Let me know if you do, I’ll gladly share it out!</p><h3>4. 🛠 Building your talk.</h3><p>After much hard work sunk into crafting your proposal, the stars align and your talk is accepted by a conference! 🎉🎇</p><p>If you’re anything like me, you’ll experience a few moments of jubilation, before a horrifying realization settles in: <strong>shit, I need to give this talk.</strong></p><h4>Stress and imposter syndrome.</h4><p>There is a gravity to conference talks. You’ll be speaking in front of a bunch of your peers, many of them far more experienced and knowledgeable than you. The talk is recorded, and will be available for anyone to watch, forever.</p><p>In all of my talks now, I’ve had moments of self-doubt. Imposter syndrome crept in, and I started questioning whether anything I was writing made sense. Maybe it’s all really obvious to everyone else. Maybe it’s all wrong.</p><p>These feelings can be helpful (after all, you should be critical of your own work, and try to find mistakes!), but often they outlive their usefulness.</p><h4>Iteration and Feedback.</h4><p>First drafts are always bad, in my experience. After sinking dozens of hours into getting a coherent talk together, you might realize that the whole thing stinks. It can be really discouraging.</p><p>The thing is, as with anything, iteration is key to success. Take a couple days away from it, and then come back with a fresh perspective. You may come up with solutions to fix the problems.</p><p>I changed the entire structure of my React Rally talk when I realized that the order made no sense (I was <em>starting</em> with the most complex bit of code, instead of working up to it). It was a lot of work, done only a few days before the conference, but the talk was <em>so</em> much better because of it.</p><p>Feedback is also extremely important. Find someone you trust to give you honest criticism. They’ll spot problems you hadn’t noticed, and offer encouragement for stuff you’re on the fence about. Trust their feedback more than your own.</p><p>Local meetups are also a great way to get feedback, and give your talk a “practice run”. It’s not always clear which parts of your presentation will prompt a reaction, and there’s nothing more awkward than having an audience laugh when you weren’t trying to make a joke. Get this out of the way when the audience is tiny!</p><p>For my React Europe talk earlier this year, I gave the same talk at React Montreal about a month beforehand, and then grilled everyone who came to talk to me afterwards. The feedback I heard most was that there was too much code in the middle, too much detail in side-pieces that weren’t super germane. I started inserting ✂️️ emoji in places where it wasn’t beneficial to go through the code line-by-line, and it meant I was able to fit much-needed high-level stuff in the talk.</p><h4>Learning about presenting.</h4><p>While I work on my talks, I take frequent breaks to watch other conference talks. Take note of the things you like in their talks, and steal them.</p><p>For example, in my React Europe talk, I decided to rearrange the slides so that the introduction card (“My name is Josh and today I’d like to talk about…”) only shows up 5 minutes into the talk, after seeing what a nice effect it had in Gary Bernhardt’s <a href="https://www.destroyallsoftware.com/talks/the-birth-and-death-of-javascript"><strong><em>The Birth and Death of Javascript</em></strong></a>.</p><p>Some other resources I found very helpful:</p><ul><li><a href="https://twitter.com/saronyitbarek">Saron Yitbarek</a> has <a href="https://medium.com/@saronyitbarek/transitions-the-easiest-way-to-improve-your-tech-talk-ebe4d40a3257"><strong>a great article</strong></a> on improving transitions in technical talks.</li><li><a href="https://twitter.com/nikkitaftw">Sara Vieira</a> created <a href="https://awesometalks.party/"><strong>a really helpful webapp</strong></a> for finding quality talks.</li><li><a href="https://twitter.com/r00k">Ben Orenstein</a> has <a href="https://www.youtube.com/watch?v=l9JXH7JPjR4"><strong>a must-see talk</strong></a> on how to talk to developers. It’s full of amazing tips.</li></ul><h3>5. 🎟 Attending the Conference.</h3><p>After months of work spent building your talk, whether you’re ready or not, the conference arrives. As a speaker, your conference-going experience will be different in a few ways.</p><h4>Perks.</h4><p>Being a speaker comes with perks. For example, many conferences have a “speaker dinner” the night beforehand. This is a great opportunity to meet and chat with the other speakers.</p><p>Another speaker perk is that there is often a “speaker’s lounge”, a quiet side-room that only speakers can pop into.</p><p>Initially, this idea was a little unsettling to me; one of the great things about going to conferences is being able to chat with the speakers, and if they’re all off in their own space, that doesn’t work as easily! It felt like it would lead to a sort-of caste system, rather than encouraging speakers to mingle with the people paying to see them speak.</p><p>After a couple conferences, though, I realized that speakers don’t tend to spend much time in the lounges. Mostly it’s just to give speakers a quiet place to work on their talk, or catch a moment of silence and solitude. As an introvert, I very much appreciated having a quiet spot to sit on my laptop from time to time.</p><p>Finally, the organizers typically give attendees a “speaker gift”. A collection of swag and personalized items, as a token of appreciation. At React Rally this year, here’s what we got:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8KYqhM84H2CxXBDuOWPVGg.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XZP-yi2pH7Zq-bsK1B450w.jpeg" /><figcaption>The personalized notebook is my favourite!</figcaption></figure><h4>Busy and Stressed.</h4><p>Depending on how prepared you are, you may still be trying to squeeze in some last-minute tweaks to your talk. At React Rally this year, I was still practicing my talk in the final hours, to the point that I was worried I was going to lose my voice!</p><p>There’s also a fair bit of nervous energy in the lead-up. For this reason, the good conference spots are the early ones. You want to go as early as possible, so that you can relax afterwards. Of course, you don’t typically have control over what slot you get, so this is a matter of luck 🤞🏻</p><h3>6. 🗣 Delivering your talk.</h3><p>Most people have a healthy fear of public speaking.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FyQ6giVKp9ec%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DyQ6giVKp9ec&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FyQ6giVKp9ec%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/a390ef4b503058fc89fb334312b62ec3/href">https://medium.com/media/a390ef4b503058fc89fb334312b62ec3/href</a></iframe><p>Somewhat remarkably, most people tell me that I don’t seem nervous in my talk! This is wild, because I’m <em>very</em> nervous. Maybe the trick is just learning how to not <em>seem</em> nervous?</p><p>The more improvised your talk is, the more likely it is that your nerves will get the best of you. For this reason, I don’t ever plan on live-coding in a talk. Maybe after years of practice.</p><p>On the other hand, you don’t want it to be too scripted; you want it to sound authentic, and that’s hard to do when you’re reading from a cue card. Instead I like to practice enough that I hit all the same points consistently, but the exact phrasing used varies from talk to talk.</p><p>The downside to this is that you <em>will</em> forget to mention things. In every talk I’ve given, I forget to say a handful of things I wanted to.</p><p>Time also passes ridiculously fast on a stage. 30 minutes can go by in an instant. Before you know it, people are clapping, and you’re done!</p><h3>🎭 Is it worth it?</h3><p>Conference talks are a tremendous amount of work. For my React Europe 2018 talk, I estimate that I spent over 150 hours on the talk; it consumed my mornings and weekends for a couple months.</p><p>Assuming you make the median US software engineering salary of $104,000 a year, and put 150 hours of work into the talk, you’ve spent $7500 worth of your time getting it ready.</p><p>In addition, preparing a talk is a bumpy ride. There’s a bunch of stress along the way, a bunch of nights and weekends where you really don’t feel like working on it but do anyway, moments of crisis where you think your talk won’t work or isn’t interesting.</p><p>For all of that, conference talks tend to reach a surprisingly small audience. It wouldn’t surprise me if this blog post is read more than my recent conference talk was seen!</p><h3>Sunil Pai on Twitter</h3><p>I can spend weeks, sometimes months on prepping a conf talk, and it&#39;s usually seen live by 200-800 people. the youtube recording gets about 500-2000 views after about a year. a snarky tweet reaches more people in a week. something&#39;s wrong here, and it&#39;s aching to be disrupted.</p><p>So on its face, the math doesn’t look favourable. Why spend so much time and energy on a conference presentation?</p><p>In my opinion, there are a few things that balance the scales:</p><ul><li>While relatively few people will see a conference talk, it can be a very impactful way to deliver a message. A well-crafted talk can inspire and motivate someone far more effectively than a tweet or blog post!<br> <br>For example, <a href="https://codesandbox.io/"><strong>CodeSandbox</strong></a> was created by <a href="https://twitter.com/compuIves"><strong>Ives Van Hoorne</strong></a> after attending React Europe, and <a href="https://www.youtube.com/watch?v=qURPenhndYA&amp;t=230">he credits</a> the conference with making him determined to build it!</li><li>You get to hang out with the other speakers. In many cases, these are the authors of the tools you use every day, or people whose work has inspired you for years.</li><li>It’s a tremendous way to meet like-minded people in attendance. After a conference talk, expect tons of folks to come up and ask pertinent follow-ups, or share some of the interesting things they’ve been doing.</li><li>Speaking at a conference makes people think that you’re a Real Expert™. It lends credibility to what you’re saying, for better or worse.</li><li>It’s an experience. It’s a memory that you’ll have for the rest of your life, a youtube video you’ll be able to watch many years down the line. It’s a heck of a thing!</li></ul><h3>Onwards!</h3><p>This has been a wildly educational year for me.</p><p>The biggest thing I’ve learned is that I should restrict how many conference talks I commit to writing. I have a finite amount of free time, and spending so much of it on conference talks means I’ve been neglecting <a href="https://github.com/joshwcomeau/guppy"><strong>other projects</strong></a>.</p><p>I think in the future, I’m going to create a single conference talk per year, and submit it to multiple conferences, instead of doing original work for each one. While not all conferences will accept “repeat” talks, there are enough that do that it seems like a reasonable strategy to me.</p><p>As your reputation as a speaker increases, new doors start opening. For example, I’m delighted to announce that I’ll be speaking at React Europe 2019! Evidently the organizers liked the talk I gave last year enough to invite me back this year, without submitting a CFP proposal. I’m thankful I have 9 months to prepare, as I have an idea that I think would be really cool, but would involve a whole lot of stuff I don’t (yet) know anything about.</p><p>I’ll also be doing a 1-day workshop there, on ✨ whimsical animations ✨. So that should be fun!</p><p>A realization I had a few weeks ago is that I’m still very much at the beginning of my career. I’m only ~5 years into what will likely be a 40-year career, so I’m only about 1/8th through! That thought is simultaneously liberating and dizzying; it means I don’t have to feel rushed when it comes to making the most of every available opportunity, but it also means I have <em>no clue</em> what’s ahead.</p><p>Conference-speaking is a worthwhile endeavour, but it’s one heck of a bumpy ride, and not <em>always</em> worth it. I’ll continue to prepare talks (as long as folks still want to hear what I have to say), but far fewer.</p><p>If you’ve made it all the way to the end here, you must be really interested in conference-speaking! I encourage you to give it a shot. Feel free to <a href="https://twitter.com/JoshWComeau"><strong>reach out to me</strong></a>, I’m always happy to give your proposal a quick read :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7d74750bc618" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[My new explorable, interactive blog]]></title>
            <link>https://medium.com/@joshuawcomeau/my-new-explorable-interactive-blog-1302383a9b45?source=rss-a11edf57e20a------2</link>
            <guid isPermaLink="false">https://medium.com/p/1302383a9b45</guid>
            <category><![CDATA[svg]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[blogging]]></category>
            <category><![CDATA[reactjs]]></category>
            <category><![CDATA[ui]]></category>
            <dc:creator><![CDATA[Joshua Comeau]]></dc:creator>
            <pubDate>Fri, 25 May 2018 15:06:58 GMT</pubDate>
            <atom:updated>2018-05-25T15:08:17.926Z</atom:updated>
            <content:encoded><![CDATA[<p>Hi friends!</p><p>A few months back, I created <a href="https://pudding.cool/2018/02/waveforms/"><strong>Waveforms</strong></a>, an explorable explanation that dug into the peculiar magic of sound waves. I got a bunch of feedback afterwards from audio folks who said that they <em>finally understood </em>how sound works, that my interactive thingy helped them bridge the gap between theoretical knowledge and intuitive understanding.</p><p>I started wishing I could build content like that in the same way that I wrote posts on Medium. I really like Medium as a publishing platform, but it’s primarily a traditional, text-based blogging engine (sure, you can embed gists and CodeSandbox and things, but it’s hard to make an integrated, seamless, dynamic experience with those tools).</p><p>If my blog was essentially a React application, I could build and embed my own interactive widgets. Over time, I’d develop a rich library of these embeddable components, and (hopefully) have the tools needed to create rich, explorable-explanation-style blog posts at the speed of static content.</p><p>A few weeks of side-hacking later, and that blog exists now! 🎉 🎆 🎊</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QCyLkPMmQD4vE9Z_7wJInA.png" /></figure><p>The first post is called <a href="https://www.joshwcomeau.com/posts/dynamic-bezier-curves"><strong>Dynamic Bézier Curves</strong></a>, and it’s a deep dive into building SVG curves that respond to user input in React.js. Here are some of the nifty interactive bits:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*kl2goVvtDr0zLh4l8uCiAw.gif" /><figcaption>A slider lets you control a single variable in a sandbox</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*PB-1ilJCum76mNM5t_F1Pg.gif" /><figcaption>Drag control points around, and toggle between Quadratic and Cubic</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*PSJ7VJGopMGAj5EcBoIMuw.gif" /><figcaption>Make changes to code snippets and see the results immediately.</figcaption></figure><p>These GIFs aren’t doing it justice, though; you should really go <a href="https://www.joshwcomeau.com/posts/dynamic-bezier-curves"><strong>play with it for yourself</strong></a><strong>!</strong></p><h3>My Future on Medium</h3><p>While I now have my own custom blogging engine, I <strong>won’t</strong> be shutting down my Medium account anytime soon!</p><p>I’ll likely still want to write mostly-words blog posts, not everything needs interactive elements. For those posts, I’ll cross-post in both places, so you can continue to read on the platform you prefer. Look for a blog post about the virtues of Redux beyond prop-drilling in the near future!</p><p>For future explorable-explanation-type posts, I’ll likely throw a quick note on here to let you all know about the new post (like I’m doing here!).</p><p>As always, let me know what you think about this decision, as well as the new blog content I’ll be producing!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1302383a9b45" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Performance-tuning a React application.]]></title>
            <link>https://codeburst.io/performance-tuning-a-react-application-f480f46dc1a2?source=rss-a11edf57e20a------2</link>
            <guid isPermaLink="false">https://medium.com/p/f480f46dc1a2</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[reactjs]]></category>
            <category><![CDATA[web-performance]]></category>
            <dc:creator><![CDATA[Joshua Comeau]]></dc:creator>
            <pubDate>Fri, 10 Nov 2017 18:55:33 GMT</pubDate>
            <atom:updated>2017-11-12T19:56:33.615Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6ElSDBNlanei43oH5SAh5w.png" /></figure><h4>A Case Study.</h4><p>In recent weeks, I’ve been working on <a href="https://tello.tv/"><strong>Tello</strong></a>, a web app to track and manage television shows:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UfHV4_HWAK4I_yGl0wSq0Q.png" /></figure><p>As web apps go, it’s relatively small — about 10,000 lines of code. It’s a React/Redux app, bundled by Webpack, served by a thin Node backend (using Express and MongoDB). 90% of the code is on the front-end. <br>Source code is available <a href="https://github.com/joshwcomeau/Tello"><strong>on Github</strong></a><strong>.</strong></p><p>There are a lot of aspects to web performance. Historically, I’ve focused more on the post-load front-end side of things: stuff like making sure scrolling is jank-free, and animations are smooth.</p><p>In contrast, I don’t often pay much attention to page-load time, at least not on small pet-projects. After all, there isn’t <em>that</em> much code being shipped; it has to be pretty fast out-of-the-box, right?</p><p>After doing an initial benchmark, however, I was surprised to see that my 10k-LOC pet project was <em>slowwww: </em>on a 3G connection, it took around 5 seconds for anything meaningful to show up, and more than <em>15 seconds</em> for all network requests to resolve.</p><p>I realized that I needed to invest some time and energy on this problem. It doesn’t matter how beautiful my animations are if folks bail after staring at a blank white screen for 5 seconds!</p><p>All in all, I experimented with half a dozen techniques, over the course of a weekend. The end result is that the page shows meaningful content after ~2300ms — A reduction of over 50%!</p><p>This blog post is a case-study in the specific techniques I tried, and how well they worked. More broadly, though, it’s about what I learned along the way about diagnosing problems, and what my thought process was for coming up with solutions.</p><h3>Methodology</h3><p>All profiling done uses the same settings:</p><ul><li>“Fast 3G” throttled network speed.</li><li>Desktop resolution.</li><li>Disabled HTTP cache.</li><li>Logged-in, to an account with 16 tracked TV shows.</li></ul><h3>Baseline</h3><p>We need a baseline that we can compare results against!</p><p>The page we’ll be testing is the main logged-in Summary view. it’s the most data-heavy page, and so it offers the most room for optimization.</p><p>The Summary view contains a set of cards, like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cag88WlFXxx_I452R5PEUA.png" /><figcaption>Each show gets its own card, and each episode gets its own square. Blue squares = seen episodes.</figcaption></figure><p>Here’s our baseline profile, on 3G speed. It’s… not great.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*116YOrGo-_hRvGUjMCieSA.png" /><figcaption>Yikes!</figcaption></figure><p><em>First Meaningful Paint</em>: ~5000ms<br><em>First image loaded</em>: ~6500ms<br><em>All requests finished</em>: &gt;15,000ms</p><p>Oof. The page doesn’t display anything useful until ~5 seconds in. The first image only finishes loading around 6.5 seconds, and it takes <em>well</em> <em>over 15 seconds</em> for all network requests to complete.</p><p>This timeline view offers a bunch of insights. Let’s walk through it and examine what it’s doing:</p><ol><li>The initial HTML page is fetched. This is nice and quick, because the app is not server-rendered.</li><li>The monolithic JS bundle has to be downloaded. This takes forever. 🚩</li><li>React traverses the component tree, computes the initial mount state, and pushes it to the DOM. It’s a header, a footer, and a lot of black space. 🚩</li><li>After mount, the application realizes that it needs some data, so it makes a GET request to <em>/me</em>, an API endpoint that returns the user’s data, as well as an array of shows they care about, and which episodes they’ve seen.</li><li>Once we have that crucial list of shows, the application can fetch: <br>- an image for each show,<br>- an array of episodes for each show*.<br> <br>This data comes from the wonderful <a href="https://www.tvmaze.com/api"><strong>TV Maze API</strong></a>.</li></ol><blockquote>* You may be wondering why I don’t just store episode info in my database, so I can skip all those calls to TV Maze. Ultimately, TV Maze is the source of truth; it has all the info about new episodes. I could make these requests on the server during Step 4, but that would greatly increase the amount of time that step takes, while a user stares into a sea of empty black space. Plus, I like having a lean server layer.<br> <br>One potential workaround could be to set up a cron job that does daily syncs with TV Maze, and only request episodes directly if I don’t already have recent data. I kinda like that the data is realtime, though… this avenue will be left unexplored, at least for now.</blockquote><h3>The Obvious Improvement</h3><p>The biggest bottleneck right now is that initial JS bundle’s size; it takes too long to download!</p><p>The bundle size is 526kb, and it’s not currently being compressed at all. Gzipping to the rescue!</p><p>With a Node/Express backend, this is easy; we just need to install the <a href="https://www.npmjs.com/package/compression"><strong>compression</strong></a> module, and use it as an Express middleware.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3a10458cceab2a9ca27e18e498c7dd4e/href">https://medium.com/media/3a10458cceab2a9ca27e18e498c7dd4e/href</a></iframe><p>With that incredibly simple fix, let’s see what effect it has on our timeline:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*N1pczEBknaQ_P6u-1S_FQw.png" /></figure><p>First meaningful paint: 5000ms -&gt; <strong>3100ms</strong><br>First image loaded: 6500ms -&gt; <strong>4600ms<br></strong>All data loaded: 6500ms -&gt; <strong>4750ms<br></strong>All images loaded: ~15,000ms -&gt; ~13,000ms</p><p>The bundle went from 526kb over-the-wire to just 156kb, and it make a huge difference on page-load speed.</p><h3>Caching with LocalStorage</h3><p>With the obvious first step taken, I looked at the timeline. The first paint is at 2400ms, but it isn’t meaningful. It gets better at 3100ms, but all that episode data isn’t received until almost 5000ms.</p><p>I started thinking about server-rendering, but that wouldn’t actually fix the problem; the server would still have to make a call to the DB, and then a call to the TV Maze API. Worse, the user would be staring at a white screen while the server did its work.</p><p>Why not use local-storage? We can persist all state changes to the browser, and rehydrate from that state when the user returns. The data will be stale, but that’s OK! The real data won’t be far behind, and this will make the initial load feel so much faster.</p><p>Because this app uses Redux, persisting/hydrating state is pretty straightforward. First, I needed a way to update localStorage whenever the Redux state changed:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1bcc23ae57c27f7a7b6d77ecd55b2d7f/href">https://medium.com/media/1bcc23ae57c27f7a7b6d77ecd55b2d7f/href</a></iframe><p>Next, we need to subscribe our Redux store to this method, as well as initialize it with any data from previous sessions:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/55c36d02fa72bfd3e9291bfe30f5145d/href">https://medium.com/media/55c36d02fa72bfd3e9291bfe30f5145d/href</a></iframe><p>There were a few kinks to work out, but for the most part, this was a really simple change, thanks to how Redux is architected.</p><p>Let’s take a gander at the new timeline:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wJ6uOFLCWUmhMpKtB7XuYw.png" /></figure><p>Cool! It’s hard to tell from how small the captured screenshots are, but our very first paint is meaningful now; it contains a full list of the shows and episodes from our previous session: at 2600ms</p><p>First meaningful paint: 3100ms -&gt; <strong>2600ms<br></strong>Episode data available: 4750ms -&gt; <strong>2600ms (!)</strong></p><p>While this hasn’t actually affected the loading time (we still do make those API requests and they still take a while), the user has data immediately, and so the <em>perceived</em> speed improvement is very noticeable.</p><p>Gone is the staggered, things-keep-changing second where content appears as it’s available. While this is often a popular technique for getting stuff on the page sooner, it can be overwhelming when the page keeps updating as new content is available. I much prefer being able to render the “final” UI immediately.</p><p>As an extra bonus, this winds up being pretty useful in non-perf ways too. For example, users have the ability to change the sorting of shows, but before this change, that preference would be forgotten when the session ends. Now, that preference is restored when they come back!</p><blockquote>There is a downside to this, though: it’s no longer clear whether you’re still waiting for new data or not. I plan to add a spinner in the corner that shows whether additional requests are still being waited on or not.</blockquote><blockquote>Also, you may be thinking “This is great for returning users, but does nothing for new users!”. You’re right, but actually, this isn’t applicable for new users. New users have no tracked shows, and so their page load is super quick; just a call-to-action to start adding shows. So we’ve effectively killed the experience of “staring at a black screen forever” for <strong>all</strong> users, new and returning.</blockquote><h3>Images and Lazy Loading</h3><p>Even with this latest improvement, images are still taking forever to load; this timeline doesn’t show it, but it still takes 12+ seconds for all images to be loaded, with 3G speeds.</p><p>The reason for this is simple: TV Maze returns large movie-poster-style photos, whereas I only need a narrow strip, used to help tell shows apart at-a-glance.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*wIhn8j9QkPIBvxAA6ulTxQ.jpeg" /><figcaption><strong>Left</strong>: what gets downloaded ················ <strong>Right</strong>: what gets used</figcaption></figure><p>To solve this problem, my initial thought was to use something like ImageMagick, a wonderful CLI tool I used while making <a href="http://colourmatch.ca/"><strong>ColourMatch</strong></a>.</p><p>When the user adds a new show, the server would request a copy of the image, use ImageMagick to crop out the middle of the image, send it over to S3, and use the S3 URL on the client, rather than using the TV Maze image link.</p><p>Rather than deal with this myself, though, I decided to outsource this concern to <a href="https://www.imgix.com/"><strong>Imgix</strong></a>. Imgix is a service that sits in front of S3 (or other cloud storage providers) and allows you to dynamically create cropped, resized images. You just use a URL like this, and it creates and serves an appropriate image:</p><pre>https://tello.imgix.net/some_file?w=395&amp;h=96&amp;crop=faces</pre><blockquote>A nice bonus is being able to crop based on interesting areas of the photos. You’ll notice in the left/right comparison photo above that it crops the 4 kids on the bikes, instead of just cropping the exact center of the image.</blockquote><p>For Imgix to work, the image has to be available via S3 or similar. Here’s a snippet from my back-end code, which uploads an image when a new show is added:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/85639e540d973fbb298e04e19c205631/href">https://medium.com/media/85639e540d973fbb298e04e19c205631/href</a></iframe><p>By running every new show through this promise, we get images that are ready to be dynamically cropped.</p><p>On the client, I use image properties <em>srcset</em> and <em>sizes</em> make sure that images are being served based on the window size and display pixel ratio:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/220861e182d2884fa56dbd8e58c1b5ac/href">https://medium.com/media/220861e182d2884fa56dbd8e58c1b5ac/href</a></iframe><p>This helps ensure that mobile clients get the larger version of the image (since those cards wind up taking up the whole viewport’s width), whereas desktop clients get a slightly smaller version.</p><h4>Lazy Loading</h4><p>Each image is now way smaller, but we’re still loading an entire page worth of shows at once! On my large desktop window, only 6 shows are visible at once, but we fetch all 16 images at once, on page-load.</p><p>Happily, the awesome package <a href="https://github.com/jasonslyvia/react-lazyload"><strong>react-lazyload</strong></a> offers really simple lazy loading. The code is as simple as:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/04662e7065d23d66eddc882f0c11d328/href">https://medium.com/media/04662e7065d23d66eddc882f0c11d328/href</a></iframe><p>Alright, it’s been a while since we looked at a timeline.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YLyKF1rKx1MMaLA-1jnZrg.png" /></figure><p>Our first-meaningful-paint numbers haven’t changed, but image download times are way better:</p><p>First image: 4600ms -&gt; <strong>3900ms</strong><br>All visible images: ~9000ms -&gt; <strong>4100ms</strong></p><blockquote>Eagle-eyed readers might have noticed that this timeline only downloads episode data for 6 episodes, instead of all 16. This is because my initial attempt (and the only one I remembered to capture) lazy-loaded the episode card, not just the show’s image.</blockquote><blockquote>Ultimately this introduced more problems than I was able to solve in this weekend-long-perf-tune, and so I simplified it. The impact on above-the-fold image load-times is unchanged, though.</blockquote><h3>Codesplitting</h3><p>We’re definitely getting to a pretty good place, perf-wise.</p><p>One obvious issue is that we only have a single bundle. Let’s use codesplitting to reduce the amount of on-request code needed!</p><p>Because I’m using React Router 4, it’s a simple matter of <a href="https://reacttraining.com/react-router/web/guides/code-splitting"><strong>following the docs</strong></a> to create a &lt;Bundle /&gt; component. I played around with a few different configurations, but ultimately, there wasn’t a lot of splitting that made sense.</p><p>In the end, I split out the mobile views from the desktop ones. The mobile version has its own views, which use a swiping library, custom assets, and a few extra components. This bundle wound up being surprisingly small — about 30kb before compression — but it nevertheless had a noticeable impact:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0eWlF3VGsWLqHulZtLzkDQ.png" /></figure><p>First meaningful paint: 2600ms -&gt; <strong>2300ms</strong><br>First image loaded: 3900ms -&gt; <strong>3700ms</strong></p><blockquote>Lesson learned: codesplitting’s effectiveness is hugely dependent on the given application. In this case, the biggest dependencies — React and its ecosystem packages — are used across the site, and don’t need to be split off. <br> <br>The components themselves could be split off at the route level for marginal gains in initial page load, but then you introduce additional latency on every route change; dealing with spinners everywhere isn’t fun.</blockquote><h3>Other Approaches Tried or Considered</h3><h4>Serverside Rendering</h4><p>I did toy with the idea of rendering a “shell” — a placeholder with the right layout, but without data — on the server.</p><p>The issue I foresaw was that the client already has access to the previous session’s data, through localStorage, and it initializes with that data. The server isn’t privy to that, and so I’d wind up with the warning about markup not matching between client and server.</p><p>I figure that I might’ve been able to shave half a second off my first-meaningful-paint time with SSR, but the site wouldn’t be interactive in that time; a personal pet-peeve of mine is when a site <em>looks</em> ready, but isn’t.</p><p>Plus, SSR introduces a lot of complexity, and can slow down development time. Performance is important, but “good enough” is good enough.</p><p>Something I’m interested in exploring, but haven’t found the time, is <em>compile-time SSR</em>. This would only work for static pages like the logged-out homepage, but I can imagine it being hugely effective. As part of my build process, I’d create and persist the index.html. This would get served to the users by the Node server as the plain HTML file that it is. The client would still download and run React, so the page would become interactive, but there would be zero server-side build time, since we’ve paid that cost before the code was even deployed.</p><h4>CDN Dependencies</h4><p>An idea I thought had a lot of potential was to serve React and ReactDOM from a CDN.</p><p>Webpack makes this easy; you can specify an <em>externals</em> key to have it not bundle the given dependency.</p><pre>// webpack.config.prod.js<br>{<br>  externals: {<br>    react: &#39;React&#39;,<br>    &#39;react-dom&#39;: &#39;ReactDOM&#39;,<br>  },<br>}</pre><p>It seemed as though there were two strong benefits to this approach:</p><ul><li>Serving a popular library from a CDN means it’s likely to already be cached for the user</li><li>Dependencies could be <em>parallelized</em>, downloading in tandem with the app bundle, instead of being a single large file.</li></ul><p>I was surprised to see, at least in the worst case where the CDN hasn’t cached it, that moving React to a CDN was <em>harmful</em>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JaujId8Or-HOxLuJGcKWSw.png" /></figure><p>First meaningful paint: <strong>2300ms</strong> -&gt; 2650ms</p><p>You’ll notice that React and React DOM are downloaded in parallel to my main desktop bundle, and yet… it actually slows down the total time.</p><blockquote>I don’t want to imply that using CDNs like this are never a good idea. I’m not an expert in this stuff and it’s entirely possible that this is something I’m doing wrong, not a flaw with the idea! At least in my case, though, it didn’t pan out.</blockquote><h3>Conclusion</h3><p>There are two main ideas I hope this post communicates:</p><ol><li>Small side-project apps are pretty fast out-of-the-box, but a weekend of experimentation can yield <em>huge</em> speed improvements. The Chrome developer tools make it really easy to poke around and see where the bottlenecks are, and it may surprise you how much low-hanging fruit there is. Servicers like Imgix allow you to defer hard problems to other people, often for free or for very low cost.</li><li>Every application is different. This post details specific tricks for Tello, which has a very unique set of concerns. Even if these tips aren’t directly applicable in your app, I hope I’ve showcased how <em>performance is a creative part of web development</em>.<br> <br>For example, the conventional wisdom is that server-side rendering is the way to go. In many applications it is, but maybe a client-side solution using local-storage and/or service-workers would be better! Maybe you can pay some of the cost of SSR during compile-time, or maybe you can do what Netflix does for some pages, and <a href="https://jakearchibald.com/2017/netflix-and-react/">skip shipping React to the client entirely</a>!<br> <br>Performance is actually really fun when you realize how much creativity and outside-the-box thinking is involved.</li></ol><blockquote>Thanks for reading! I hope this was helpful :) Lemme know what you think <a href="http://twitter.com/joshwcomeau">on Twitter</a>.</blockquote><blockquote><strong>View Tello’s source </strong><a href="https://github.com/joshwcomeau/Tello"><strong>on Github</strong></a><strong>.</strong>🌟</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f480f46dc1a2" width="1" height="1" alt=""><hr><p><a href="https://codeburst.io/performance-tuning-a-react-application-f480f46dc1a2">Performance-tuning a React application.</a> was originally published in <a href="https://codeburst.io/">codeburst</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Randomness in React Props]]></title>
            <link>https://medium.com/@joshuawcomeau/randomness-in-react-props-3929c1669f8b?source=rss-a11edf57e20a------2</link>
            <guid isPermaLink="false">https://medium.com/p/3929c1669f8b</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[reactjs]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[functional-programming]]></category>
            <dc:creator><![CDATA[Joshua Comeau]]></dc:creator>
            <pubDate>Sun, 22 Oct 2017 13:59:44 GMT</pubDate>
            <atom:updated>2017-10-22T13:59:44.657Z</atom:updated>
            <content:encoded><![CDATA[<p>I’m working on a side-project that involves these cute little animated critters:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1002/1*W_Dv78GWSBUV3H_VbhxpSg.gif" /></figure><p>While they’re all pretty similar from one another, they do vary in a few ways:</p><ul><li>Shape (rectangle, pentagon)</li><li>Color</li><li>Size</li><li>Walk speed</li></ul><p>I wanted the ability to control these props when needed, but also to have randomized values used by default, so that I could easily generate a crowd like this without worrying about having to come up with values for them.</p><p>In my mind, my ideal setup was something like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/342902ba46d6af9ec6451977dcf972c0/href">https://medium.com/media/342902ba46d6af9ec6451977dcf972c0/href</a></iframe><p>This didn’t work, because defaultProps doesn’t work like that: the expression is evaluated once, when the component is first seen, and the same randomized value is used for every instance of the component. In other words, I’d get a single randomized set of values, and 10 identical People with those values.</p><p>My next idea was to move the logic to the constructor function. When rendering a new Person, props would be copied to state, and blank values would be randomized:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a8cd2469e35ff084ab6ff7b126275d2e/href">https://medium.com/media/a8cd2469e35ff084ab6ff7b126275d2e/href</a></iframe><blockquote>I’m simply appending properties to the instance here because, in my application, I know these values are static; they never change once the component is created, so I don’t have to worry about updating them on re-render. If I did, I’d have to store these values in this.state, and then handle updates with componentWillReceiveProps.</blockquote><p>This works! I have a beautifully diverse group of People pacing around. <br>But, I’m not super happy with it.</p><p>It feels like there are two discrete chunks of logic here:</p><ol><li>The data-munging and randomization to manage the props,</li><li>Actually rendering the little person, and animating them around</li></ol><p>I like when React components only have a single responsibility. This bugger’s doing too many things!</p><p>The simplest solution involves just creating a thin wrapper, called RandomPerson:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c796239bda06441fb7556dcf5ed6fb01/href">https://medium.com/media/c796239bda06441fb7556dcf5ed6fb01/href</a></iframe><h4>Thin Wrappers wooo!</h4><p>Thin wrappers are such a nice pattern. They allow you to “cut the fat” out of your presentational components, so that they can focus on their core concern, without a bunch of important-but-unrelated business getting in the way.</p><p>I used this pattern in <a href="https://github.com/joshwcomeau/react-flip-move">React Flip Move</a>, an NPM package that handles animating list shuffles automatically. The FlipMove component was already complex enough without all the data-munging needed for its props, so I extracted a <a href="https://github.com/joshwcomeau/react-flip-move/blob/master/src/prop-converter.js">PropConverter</a> HOC that tackled all of this for me, so that working on FlipMove itself would be simpler.</p><p>You can also use thin wrappers to keep “leaf” components generic, and abstract specific concerns into a reusable “shell”. For example, I may have a &lt;Button&gt; component as the lowest-level primitive… but there might also be a &lt;RoundButton&gt; that provides a few of the Button props but allows the user to substitute most of them… and then maybe a &lt;RoundGoogleButton&gt; component that’s even more specific/concrete.</p><h4>Also, Purity</h4><p>Another nice side benefit of this pattern is that our Person component is now <em>pure</em>.</p><p>By <em>pure</em>, I mean in functional-programming terms: “given the same set of inputs, a function should produce the same output”.</p><p>In our original working example, calling a &lt;Person&gt; wasn’t deterministic: by design, each one would be a little different. Now that we’ve updated it, though, we know that each &lt;Person&gt; with the same props will produce an identical HTML element.</p><h4>Bonus: More Explicit?</h4><p>In general, I’m quite happy with the solution above.</p><p>If there’s one area I find it lacking, though, it’s a lack of data transparency.</p><p>To understand what I mean, let’s look at how you use this RandomPerson component:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6dda64ed34857e2a361cd0948b1ed7ab/href">https://medium.com/media/6dda64ed34857e2a361cd0948b1ed7ab/href</a></iframe><p>What props is Person receiving? We have no idea!</p><p>It would be nice if we had a window into what RandomPerson was actually doing, so that we’d have a clearer sense of how our Person component works. Plus, if we ever want to pass in our own props to override the random values, we’d have to go digging through other files to figure out what they are.</p><p>Thankfully, there are several ways around this! My personal favourite is function-as-children, a variant of the <a href="https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce">Render Prop pattern</a>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0f494346b61594be1011275bd2970c3f/href">https://medium.com/media/0f494346b61594be1011275bd2970c3f/href</a></iframe><p>The big change is that now we’re expecting a children function, and we’re invoking that function with all of our values.</p><p>Here’s how we use our new component:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5fc936c12b2657c245e9d3c27a20b41c/href">https://medium.com/media/5fc936c12b2657c245e9d3c27a20b41c/href</a></iframe><h4><strong>Is that actually better?</strong></h4><p>You may have noticed that the render-prop solution is much more verbose; you have to manually specify each prop going through. Plus, function-as-children is a contentious pattern; I love it, but many disagree.<br> <br>My opinion is that the transparency is a fair price to pay for the additional code, but this is indeed a trade-off, and your priorities might be different.</p><h3>In Conclusion (TL:DR;)</h3><p>By moving the randomness out of the Person component and into a thin wrapper, we keep our Person component pure. We also reduce the number of things it has to worry about, so that our Person only has a single responsibility.</p><p>By using function-as-children, we make it clear how data flows from the randomization process to the Person component, and the hierarchy is visible at a higher level. Your mileage may vary, though, when deciding if that added transparency is worth the cost.</p><blockquote>Thanks for reading! Let me know what you think <a href="https://twitter.com/JoshWComeau"><strong>on Twitter</strong></a>.</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3929c1669f8b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Simple React Development in 2020]]></title>
            <link>https://medium.com/hackernoon/simple-react-development-in-2017-113bd563691f?source=rss-a11edf57e20a------2</link>
            <guid isPermaLink="false">https://medium.com/p/113bd563691f</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[reactjs]]></category>
            <category><![CDATA[learn-react-js]]></category>
            <dc:creator><![CDATA[Joshua Comeau]]></dc:creator>
            <pubDate>Wed, 29 Mar 2017 17:15:16 GMT</pubDate>
            <atom:updated>2019-12-09T21:29:17.822Z</atom:updated>
            <content:encoded><![CDATA[<h4>Hi, aspiring React developer! 👋</h4><p>Maybe you’re a jQuery developer looking to experiment with a modern framework. Or, maybe you’re an Angular developer wanting to see what all the hype is about. Maybe you’re a seasoned back-end or systems programmer looking to make the jump to front-end. Maybe you’re new to programming in general, but want to learn how to build dynamic web applications.</p><p>Regardless of your background, you’ve likely had a similar experience: <a href="https://hackernoon.com/tagged/react">React</a> itself seems pretty straightforward, but the tooling and ecosystem is overwhelming.</p><p>You probably feel like this guy:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BZ-Q42ZmZID9Jfhib12dEQ.png" /><figcaption><a href="https://twitter.com/thomasfuchs/status/834481271443226627?lang=en">https://twitter.com/thomasfuchs/status/834481271443226627</a></figcaption></figure><p>I’ve seen and heard variations on this theme frequently. Especially for newcomers, React development can often seem like a complex maze of tools and libraries. Even experienced developers talk about how complicated modern web dev is, and pine for the simple days of just opening an editor and writing.</p><h4><strong>However, this is a solved problem!</strong></h4><p>Over the past few years, the React community has put a ton of effort into creating a tool that allows React developers to get up and running <em>almost</em> as quickly as downloading a dependency and opening an editor.</p><p>The goal of this guide is to help create your first React app. It shares a step-by-step process, from initial system setup through to deployment, without straying into tangent explanations that aren’t critical at this point in the learning process.</p><p>No prior experience with React or its related tools is required, although it does assume that you know the basics of working with a command line and git.</p><p>This is a living document, and I’ll be updating it as the landscape changes.</p><p><em>Last Updated: December 9th, 2019</em></p><h3>The Quickest Start: CodeSandbox</h3><p><a href="https://codesandbox.io/">CodeSandbox</a> is an online REPL. It’s friggin’ amazing.</p><p>It lets you instantly bootstrap a React project with everything you need. It runs in the browser, but it supports multiple files, third-party dependencies… It uses VS Code as its editor, which is <em>wild. </em>It’s essentially a full development environment that runs in-browser, and I can recommend it without reservation. You can build a full application using CodeSandbox.</p><p>There <em>is</em> something to be said for having everything run on your local machine, so we’ll cover that as well. But if you’re looking for a rocketship-speed start, head over to CodeSandbox, and jump straight to Step 3.</p><h3>Step 1: Install Yarn</h3><p>Yarn is a package manager. It helps us manage our project’s dependencies.</p><p>If you’re new to programming, essentially you can think of this as a tool to help us easily download and use other people’s code.</p><p>Download and installation instructions are available <a href="https://yarnpkg.com/en/docs/install"><strong>on the Yarn site</strong></a>.</p><p>Once you’ve installed yarn, verify that you can use it on the command line. Open a new terminal, and run:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*S72o05tk89aI2Gu9KqAm3A.png" /></figure><blockquote><strong>But what about NPM?<br></strong>You may have seen that NPM is the de facto package manager in the Javascript community, and may wonder why I’m suggesting Yarn.<br> <br>Without getting too far off-topic, Yarn is a concerted effort by the community to improve package management. Internally it still uses the NPM package repository, so you can <strong>still install all the same packages.</strong></blockquote><blockquote>Over the past couple of years, the default NPM client has improved. If you’re already comfortable with NPM, you can use it instead. Alternative NPM instructions will be provided as we go along.</blockquote><h3>Step 2: Create a React application</h3><p>When people talk about complexity in React development, often they’re referring not to React itself, but in the build system and development environment.</p><p>They have a point — as React developers, we tend to build pretty complex dev environments and build systems. We suffer this complexity because it makes React development quicker and more enjoyable.</p><p>However, that complexity is overwhelming for those just getting started, and worse, it gets in the way of learning what’s really important: React itself.</p><p>Thankfully, there is a have-your-cake-and-eat-it-too solution. It’s called <a href="https://github.com/facebook/create-react-app"><strong>create-react-app</strong></a><strong>.</strong></p><p>create-react-app is a command-line tool, owned by Facebook and maintained by talented developers both at Facebook and in the community. It’s <em>amazing</em>. It abstracts away all the complexity and difficulty of implementing Webpack, Babel, a dev server, a production build process, and a thousand other tedious-but-critical things.</p><p>It’s zero-configuration by default, and doesn’t clutter up your project directory with a bunch of files you don’t understand.</p><blockquote><strong>Note</strong>: Eventually, you will want to spend the time learning how this works internally. There’s a lot of neat stuff you can do with Webpack, for example. Our top priority at the moment, though, is getting you excited about building with React, so we can defer this stuff for later.</blockquote><p>Yarn comes with a built-in helper for using create-react-app:</p><pre>yarn create react-app [your-app-name]</pre><p>I’d like my application to be named <em>cats-n-stuff</em>, so I’ll run that:</p><figure><img alt="Terminal output for ‘yarn create react-app cats-n-stuff`" src="https://cdn-images-1.medium.com/max/1024/1*z-qA6jYeSV-nzW5tA_rN5Q.png" /><figcaption>The actual terminal output is <strong><em>a lot</em></strong><em>, so this screenshot cuts out a bunch of stuff in the middle.</em></figcaption></figure><blockquote>If you get an error starting with “A template was not provided”, it’s likely because you have an earlier incompatible version of create-react-app installed. Check out <a href="https://stackoverflow.com/questions/59188624/template-not-provided-using-create-react-app">this StackOverflow answer</a>.<br> <br>If you’re using NPM instead of yarn, you can run “<em>npx create-react-app cats-n-stuff” to achieve the same result.</em></blockquote><p>This command does quite a few things:</p><ul><li>Downloads and installs create-react-app</li><li>Creates a new project folder, cats-n-stuff (or whatever you name your app)</li><li>Scaffolds out a new project, including everything you need to compile a production-ready app, as well as run a development server</li><li>Installs dependencies</li></ul><p>You’ll notice the output towards the end gives you a set of commands. <br>Let’s start by following its instructions:</p><figure><img alt="Terminal commands: “cd cats-n-stuff/” and “yarn start”" src="https://cdn-images-1.medium.com/max/1024/1*wgz3by2ED2pg8ItWbNYGgw.png" /></figure><p>We should see the following output:</p><figure><img alt="Terminal output of running “yarn start” — a local IP I can visit to view my project" src="https://cdn-images-1.medium.com/max/1024/1*9vQqRJRcM-Dp9DFHaNUTPw.png" /></figure><p>A browser window should also have opened, showing the following:</p><figure><img alt="Browser window showing localhost, with an instruction to edit src/app.js and save" src="https://cdn-images-1.medium.com/max/1024/1*BvLrbBG_k4RCKfXT_3J95A.png" /></figure><p>Let’s open our new project in our code editor. I’m using VS Code. You should see the following files:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nUxmh2lwrcqzr8ytWwzlDw.png" /></figure><p>Let’s go through them:</p><h4>node_modules</h4><p>This directory holds all of our project dependencies, like <em>react</em> and <em>react-dom</em>. It also includes all the dependencies needed to run our build system and development server. Sometimes, folks are alarmed by the size of this directory (~200mb), but it’s important to remember that it includes a whole bunch of dev tooling. Very little code is actually shipped to the user.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/634/1*VAMPNhyTa0stDPiVEcFTpQ.png" /></figure><h4>public</h4><p>This directory holds static assets, stuff like our favicon and search-engine preferences. It also houses our project’s only HTML file. Because React is all-javascript, you only really need the HTML file to update the <em>&lt;head&gt;</em> stuff, like title and meta tags. This can always be modified with React as well, but for now it can be simplest to add your own &lt;title&gt; to this file.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/702/1*MuMaVmwI-3SgnH6aAlHl1g.png" /></figure><h4>src</h4><p>This directory holds the source code we’ll write to build our application. By default, <em>create-react-app</em> comes with one component — App — and an <em>index.js</em> file that mounts it. It also includes some CSS files — it’s conventional in the React community to colocate styles and code, so that each component has its own stylesheet.</p><p>For now, you can ignore the final two files, <em>serviceWorker.js </em>and<em> setupTests.js</em>. We don’t need to fuss with them yet.</p><h4>Root directory</h4><p>Finally, the root directory of the project holds stuff related to dependencies (<em>package.json</em> and <em>yarn.lock</em>), as well as a comprehensive documentation (<em>README.md</em>) for create-react-app.</p><blockquote><strong>Is this only for beginners? Will I be handicapping myself down the line?</strong><br>create-react-app abstracts away all configuration, to help you focus on writing the application itself. At some point, though, you may want to access that configuration.<br> <br>Thankfully, create-react-app has <a href="https://facebook.github.io/react/blog/2016/07/22/create-apps-with-no-configuration.html#no-lock-in"><strong>an</strong> <strong>eject</strong> <strong>feature</strong></a> that removes this abstraction and exposes the underlying configuration. This means that create-react-app is a brilliant tool not just for newcomers, but also for experienced React devs.</blockquote><p>A few years back, it was common to spend the first day on a new project getting the build system and development server set up. Now that you know this process, it should only take a few minutes! And, unlike the days of installing jQuery and firing up an editor, we have a <em>bunch </em>of fantastic tooling that makes our life easier:</p><ul><li>A development server will auto-refresh / hot-reload when we save our files</li><li>We can use modern JS features without worrying about browser compatibility, since <em>babel</em> will translate your code into an older version of JS that all major browsers can understand</li><li>You can import all kinds of files into your JS code, including CSS and images.</li><li>Your editor will warn you when you’re making mistakes, including things that may not be so obvious (like accessibility concerns)</li></ul><h3>Step 3: Write your application</h3><p>Alright, our project is ready to roll. Now we have to build our app.</p><p>I have a single piece of advice that I often find myself giving, when people are getting started: <strong>learn React on its own first.</strong></p><p>If you follow many of the tutorials intended for intermediate or advanced users, you may think you need to learn about and install a dozen “supplementary” packages. After all, React is just the view layer, right?</p><p>Wrong. Facebook used to say that React was the “V” in “MVC”. They <a href="https://twitter.com/dan_abramov/status/741462507861233665">stopped using that language</a>, because it isn’t true; React is an entirely different paradigm, not simply a template renderer. The truth is that React is surprisingly capable <em>on its own</em>.</p><p>For example, you don’t need to install Redux or any other state management library at first. I really like Redux, but it will be overwhelming if you try and learn them together, and React comes with a built-in solution for state management: React state.</p><p>I believe the best way to learn is to make several small “weekend project” applications. Try and <a href="https://reactjs.org/tutorial/tutorial.html">make a game</a>, or validate a form, or build a mini component library. These kinds of projects don’t require any additional dependencies.</p><p>Once you’ve built a couple test projects, you probably will want to add <a href="https://reacttraining.com/react-router/web/guides/quick-start">React Router</a>. Because React doesn’t come with a built-in router, it does feel pretty critical. <a href="https://gist.github.com/joshwcomeau/2a31d790fbd80edae0a562e96d503a46">Building your own router</a> can be a fun educational project, but I’m also pragmatic enough to realize that sometimes you just want to build a project, and using React Router will unblock you.</p><p>You may discover, after your second or third small React project, that certain things are more painful than you’d like. Maybe your homegrown router is proving to be too much trouble, or maybe you feel like your application’s state is hard to manage. This is when you should be searching for pre-existing solutions; <em>after</em> you’ve encountered the problem, not before<strong>.</strong></p><p>Spend time learning React on its own. Add dependencies as you need them. Try to solve problems yourself; if nothing else, you’ll understand the benefits provided by those dependencies.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bwSnfsOujX_dLfIU59FhWw.jpeg" /><figcaption>Dan Abramov, co-creator of Redux, explaining that Flux libraries like Redux aren’t always needed. <a href="https://twitter.com/dan_abramov/status/704304462739939328">https://twitter.com/dan_abramov/status/704304462739939328</a></figcaption></figure><h4>Resources for learning React</h4><p>After spending some time googling for React tutorials, I’ve realized exactly why newcomers find React so confusing.</p><p>It’s actually pretty tough to find reliable, up-to-date tutorials that cover React on its own, without delving into webpack and redux and a million other things.</p><p>Here are the resources I’ve found that do the job:</p><ol><li><a href="https://facebook.github.io/react/tutorial/tutorial.html"><strong>Official React Tutorial</strong></a> — Straight from the official team. Build a Tic Tac Toe game.</li><li><a href="https://www.robinwieruch.de/the-road-to-learn-react/"><strong>The Road to Learning React</strong></a> — A pay-what-you-want ebook that builds a fully-functional HackerNews clone, using create-react-app and minimal third-party libraries. Fantastic resource.</li><li><a href="https://daveceddia.com/pure-react/"><strong>Pure React</strong></a><strong> </strong>— A great React book by Dave Ceddia</li><li><a href="https://www.taniarascia.com/getting-started-with-react/"><strong>Getting Started with React</strong></a> — A wonderful blog post by Tania Rascia</li></ol><h4>Hooks?</h4><p>2019 was a big year for React, and one of the biggest changes was the stable release of “hooks” in February. Hooks are a modern React feature that let you access React features like state and refs and lifecycle methods from within functional components.</p><p>A common question I see is whether or not you should learn hooks or class components. My personal belief is that hooks are the future, and I’ve heard that it can be simpler and faster to start with hooks. But ultimately, both are important, and it doesn’t really matter which order you learn them in.</p><h3>Step 4: Deploy</h3><p>Alright, you’ve built an awesome little toy app. Now you want to show your creation to the world. How do we get this thing online?</p><p>Web development is fun, and it’s even better when you wind up with something neat to show off. There’s an incredible amount of satisfaction achieved by showing the world <a href="https://tinkersynth.com/">your</a> <a href="https://beatmapper.app/">random</a> <a href="https://pudding.cool/2018/02/waveforms/">side</a> <a href="http://panther.audio/">projects</a>.</p><p>The first thing we’ll need to do is build our project.</p><figure><img alt="Output of `yarn run build`" src="https://cdn-images-1.medium.com/max/1024/1*WRkRyMCTDP_EJZf7NbBSYg.png" /></figure><blockquote><strong>What does this do?<br></strong>`build` is an NPM script provided by create-react-app. It bundles up your code into ready-to-deploy static files. After running it, you’ll notice a new <em>build</em> directory in your project, including all the compiled JS and HTML needed to run your project.<br> <br>Builds also use the production version of React, which means it runs faster and doesn’t include the development-mode helpers like error screens.</blockquote><h4>Deployment services</h4><p>As with everything else in modern web development, there are a bunch of options for how to actually get your built files onto the internet.</p><p><a href="https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#deployment">Create-react-app’s documentation</a> covers several possible deployment options, and in my experience, <a href="http://surge.sh/">Surge.sh</a> is the quickest, simplest way to get code online quickly.</p><p>Let’s install it with Yarn:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HZ9TsA2QTsiVTt4EkF6aiA.png" /></figure><p>We install it globally so that we can use its CLI tool. Let’s run it now:</p><pre>surge</pre><p>The first time you run <em>surge</em>, it will prompt you to create an account. Enter your email and come up with a new password.</p><p>After that, it’ll ask you for a project path. <strong>This is important: </strong>it should auto-fill the current location, but we need to add /<em>build</em> to the path, since that’s where the static, compiled files are.</p><p>Finally, you can pick a domain. It’ll suggest one at random, or you can try your own.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZCzAGlflMCoS2u3zw3wGkg.png" /></figure><p>Remarkably, this is all we have to do. Surge will ship our files to the domain indicated. Check it out:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kbhqocayxaWstSThIsrMBg.png" /></figure><h4>Simplifying repeat deploys</h4><p>If we wanted to, we could just repeat this process every time; build, run <em>surge,</em> and then specify a project path and domain name.</p><p>We can use NPM scripts to be a little fancy though. Open up your <em>package.json</em>, and find the section for “scripts”. You should find the ones we’ve used already, like “start” and “build”. Let’s add a new one:</p><pre>&quot;deploy&quot;: &quot;yarn run build &amp;&amp; surge -p build -d your-domain.surge.sh&quot;</pre><p>Terminal commands can be stringed together with &amp;&amp;, and so we can create a single NPM script to do all the stuff we need. We build a fresh copy of our project, and then deploy it with Surge, pre-filling some of the required fields.</p><p>This command starts by building the latest version of our project, and then invoking Surge with some default arguments. Here’s my “scripts” object in package.json, with the new deploy script:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*a2M7MrzHODPud5M_GsaMCg.png" /></figure><p>Now, all we have to do is run a single command, and in under 20 seconds, our glorious project is up for anyone to see.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LgTjvmgQsRpZbmnHUinNXw.png" /></figure><h4>Other deployment options</h4><p>Surge is the quickest way I’ve found to get a project online, but there are plenty of options. I really like <a href="https://www.netlify.com/">Netlify</a> — it takes a slight bit more work to get an initial deploy going, but it gives you a ton of stuff in return, including a free SSL certificate and automatic deploys when you push your code to GitHub.</p><h3>Frameworks like Gatsby and Next</h3><blockquote>Disclaimer: I work for Gatsby!</blockquote><p>React applications have gotten a reputation for being bloated and performing poorly. I don’t think this is quite fair — React does <em>a lot</em> out of the box to make sure its performance is good! — but there is one bit of undeniable truth: by default, React applications do all of their work on the client.</p><p>This means that when you load a React application, the initial HTML document is blank, and React has to load all of the JS it needs before the user can see anything.</p><p>A common way around this problem is called <em>server-side rendering (SSR)</em>. The idea with SSR is that the HTML file can be built before being delivered to the user. Javascript will still run in the browser (otherwise, it wouldn’t be an interactive application), but the idea is that the user shouldn’t have to stare at a white screen while that happens.</p><p>create-react-app is a great choice for getting started, but it’s really pretty minimal; it gives you the dev tooling you need to get started fast, and stays out of your way. Over the past few years, frameworks have popped up that offer a bunch of additional features, while still being built on top of React.</p><h4>Gatsby</h4><p><a href="https://www.gatsbyjs.com/">Gatsby</a> is sometimes billed as a “static site generator” — It can be used similarly to Hugo or Jekyll. It’s quite a bit more powerful than that, though!</p><p>Gatsby builds all of your HTML files at “compile time”, when you build your site, instead of at “runtime” when the user wants to use it. It’s super quick, since unlike server-side rendering, all of the work is done before the user even makes the request!</p><p>In addition to this performance focus, we’re doing a lot of really cool stuff at Gatsby, but it’s beyond the scope of this article.</p><h4>Next</h4><p><a href="https://nextjs.org/">Next</a> is built on a powerful idea: routing should be mirrored in the filesystem, the way it was with PHP. You can create individual components to handle each route, so a file at <em>pages/about/the-team</em> can be reached at <em>your-domain.com/about/the-team</em>.</p><p>In addition to this clever routing scheme, Next comes with built-in server-side rendering and automatic code-splitting, two powerful features that keep bundle sizes small and responses quick.</p><p>Both Gatsby and Next are great options when looking to build a “real life” project. If you’re just starting out, it probably makes sense to stick with create-react-app until you’re comfortable with React fundamentals.</p><h3>Conclusion</h3><p>There are two misconceptions that newcomers often have about React:</p><ul><li>It takes forever to set up a decent build system and dev environment. You can’t start writing your actual application code until you spend <em>hours</em> getting that set up.</li><li>React is a small piece of the toolset needed to create basic web applications, and you have to learn a dozen other things before you can get started.</li></ul><p>I hope I’ve done a good job disproving these theories. You can get started <em>in seconds</em> building a glorious front-end web application, and you can start without any extra dependencies.</p><h4>Addendum: Community Resources</h4><p>By far the most popular community hub for React developers is <a href="https://www.reactiflux.com/"><strong>Reactiflux</strong></a>. It’s a great place to meet React developers, and get help if you find yourself stuck or confused.</p><p>For myself personally, Twitter has been an amazing source to learn more about React and meet the community. Dan Abramov, a member of the React core team and co-creator of Redux, has a <a href="https://medium.com/@dan_abramov/my-react-list-862227952a8c"><strong>great list of people to follow</strong></a>.</p><blockquote>Thanks for reading!</blockquote><blockquote>I’m keen to hear your feedback on this article! Anything I could do to make it more beginner-friendly? Let me know <a href="https://twitter.com/JoshWComeau"><strong>on twitter</strong></a>.</blockquote><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2Fdde502%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2Fhackernoon%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/3c851dac986ab6dbb2d1aaa91205a8eb/href">https://medium.com/media/3c851dac986ab6dbb2d1aaa91205a8eb/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=113bd563691f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/simple-react-development-in-2017-113bd563691f">Simple React Development in 2020</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Implementing Array Methods as React Components]]></title>
            <link>https://medium.com/@joshuawcomeau/array-filter-as-a-react-component-8a6570a2be82?source=rss-a11edf57e20a------2</link>
            <guid isPermaLink="false">https://medium.com/p/8a6570a2be82</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Joshua Comeau]]></dc:creator>
            <pubDate>Sat, 14 Jan 2017 17:00:20 GMT</pubDate>
            <atom:updated>2017-01-25T00:51:50.051Z</atom:updated>
            <content:encoded><![CDATA[<p>At React Rally last year, Ryan Florence gave <a href="https://www.youtube.com/watch?v=kp-NOggyz54">an amazing talk</a> about how we’re just scratching the surface of what can be done with React components.</p><p>Over the past few months, I’ve had great fun experimenting with this idea. I’ve found that higher-order components that handle event-listening are incredibly useful. I’ve even found it remarkably straightforward (although of questionable utility) to create a set of components that mimic the SVG spec, but render to Canvas.</p><p>Today, though, I’d like to share a mildly ridiculous idea I’ve had.</p><p><strong>EDIT: </strong><a href="https://github.com/joshwcomeau/react-collection-helpers"><strong>It’s a real thing now!</strong></a><strong> </strong>🎉</p><h4>Filtering props</h4><p>If you’ve worked with React for a while, you’ve undoubtedly ran into this situation.</p><p>You have an array of <em>items </em>in props, and you want to render a list of elements. Some of the items passed in, though, aren’t needed. For example, you have a list of <em>todos</em>, but the visibility filter is set to hide completed ones.</p><p>Here’s how one might approach the problem:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/48eec3d2cb1ee774cc3b1fa3d6005307/href">https://medium.com/media/48eec3d2cb1ee774cc3b1fa3d6005307/href</a></iframe><p>Essentially, we’re doing the filter within the component, in 1 of 2 places:</p><ul><li>Filter inline. Even if you’re not a separation-of-concerns curmudgeon, you have to admit that it’s a little “busy” to have all that logic in JSX</li><li>Filter ahead of time. This, to me, is clearer, but in a less trivial component, it can move your filtering logic far from your rendering logic. It also spoils the simplicity of a component that immediately returns JSX.</li></ul><p>I started thinking about whether there was a way to have my cake and eat it too. Could we keep the filtering logic in the JSX, without it <em>feeling</em> so logic-heavy?</p><p>I made a &lt;Filter&gt; component that attempts to do it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c66a8a683bda47d41b465f90a72c5d69/href">https://medium.com/media/c66a8a683bda47d41b465f90a72c5d69/href</a></iframe><p>So, that’s a thing.</p><p>We pass our &lt;Filter&gt;component the items it needs to filter, and a predicate function that will accept each item as an argument.</p><p>Instead of taking an array of children, we take a function instead, which will build that array by applying the function to each filtered item.</p><p>Let’s see what the implementation for this &lt;Filter&gt; component is:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1fc941ce8d6c7fd5d3dbbce67e3d8e03/href">https://medium.com/media/1fc941ce8d6c7fd5d3dbbce67e3d8e03/href</a></iframe><p>I’m guessing that’s simpler than you were expecting!</p><p>We wrap our output in a &lt;div&gt; because components can’t return arrays of elements. This is a downside to this technique, but <a href="https://twitter.com/threepointone/status/810058843325546496">it’s temporary</a>.</p><blockquote>Also: we could modify this component to accept an <em>element</em> prop that would allow you to specify a DOM element type or custom component wrapper, but I wanted to keep it simple.</blockquote><p>Another potential side benefit: We could hide <a href="https://jsperf.com/array-filter-performance">more performant methods</a> within this abstraction.</p><h4>Conclusions</h4><p>Is this all a terrible idea? Quite possibly. I think it’s worth exploring though!</p><p>In these contrived examples, the benefits aren’t that clear. <em>But</em>, imagine having a suite of composable array methods as components:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/91a3d0766f98ddfb88949facbd830719/href">https://medium.com/media/91a3d0766f98ddfb88949facbd830719/href</a></iframe><p>Now <em>this</em> is intuitive UI code, and the idea is super intriguing to me. That said, I’m still not totally sold; performance may be an issue, and really it’s common to do a lot of this work elsewhere (eg. in memoized selectors).</p><p><strong>What do <em>you</em> think?</strong> I wrote this blog post to get feedback from other React developers. Do you see any merit to this idea? Or, should it be taken behind the barn and shot? <a href="https://twitter.com/JoshWComeau"><strong>Let me know on twitter</strong></a><strong>.</strong></p><blockquote>Thanks for reading!</blockquote><blockquote>I set up a <a href="http://jsbin.com/guqinuzuru/edit?js,output">basic example on JSBin</a> for anyone who wants to tinker around with this idea :)</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8a6570a2be82" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Unsplash on a Map]]></title>
            <link>https://medium.com/unsplash/unsplash-on-a-map-bb65c335207f?source=rss-a11edf57e20a------2</link>
            <guid isPermaLink="false">https://medium.com/p/bb65c335207f</guid>
            <category><![CDATA[photography]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[articles]]></category>
            <category><![CDATA[product-design]]></category>
            <category><![CDATA[maps]]></category>
            <dc:creator><![CDATA[Joshua Comeau]]></dc:creator>
            <pubDate>Mon, 19 Dec 2016 19:49:39 GMT</pubDate>
            <atom:updated>2017-12-02T00:57:08.544Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BfgwsnnGcpmsPH-iAOzhcA.gif" /></figure><p>Every month, Unsplash holds a Makeday dedicated to building cool things, where we encourage everyone in our community to participate. Internally, Makedays are awesome opportunities to work on passion projects; anything that’s interesting and beneficial for Unsplashers, but non-critical.</p><p>Since I joined Unsplash a couple months ago, I’ve wanted to do something to expose the <a href="https://twitter.com/lukechesser/status/806530056193449985">crazy amount of traffic</a> that we receive. After some internal discussion, I paired up with Rails guru <a href="https://twitter.com/aaronklaassen?lang=en">Aaron Klaassen</a> to build a map that would highlight real-time Unsplash events across the world.</p><p>As one might expect, we r̶a̶n̶ ̶i̶n̶t̶o leapt over a number of hurdles, but overall I’m super pleased with the end result :)</p><p>Our map handles 4 different types of events: <em>downloads</em>, <em>likes</em>, <em>add-to-collections</em>, and <em>submissions</em>.</p><p><a href="http://unsplash.com/activity-map"><strong>Watch them unfold in real-time, across the world.</strong></a></p><h3>Caveats</h3><p>As is often the case, we had to make some concessions due to the time-restricted nature of a Makeday.</p><h4>Data</h4><p>The first hurdle we encountered was data. Ideally we’d like to show the <em>origin</em> source of the events — when Jane Smith in Australia likes a photo taken by John Smith in Portugal, we should show the little heart icon in Australia. Sadly, though, we don’t have reliable data for where Jane Smith is, and so all of our location data is based on the photo’s EXIF data.</p><p>It’s interesting to note that only ~50% of all Unsplash photos have usable location EXIF data. That means that our actual activity is <strong>twice</strong> as busy as the one visualized!</p><h4>Event Types</h4><p>We also wanted to include <em>viewed photo</em> events, but there’s too many of them. Every minute, more than 20,000 photos are viewed (that’s over 3 views every millisecond!). Our infrastructure wouldn’t have been able to support streaming that many events without some tinkering, and it would have made for a very noisy map.</p><p>Of the events we do broadcast, <em>downloads</em> are king; other events are relatively rare. I believe that a big part of this is that many people aren’t registered for an account, and while downloads can be done anonymously, the other events can’t. We have some very cool stuff coming out really soon for our registered members, so hopefully that ratio begins to change!</p><h4>Animations</h4><p>On the front-end, performance was a recurring issue. Originally, the markers were done through ‘traditional’ browser nodes, superimposed over the map. With CSS animations, markers faded out gradually. This became too intensive for the browser to keep up with, though, so we switched to rendering the icons directly into the map’s Canvas. This performs better, but we lost the animations; events blink out of existence.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jPoD7weLCDHo8M6iDR_BDA.jpeg" /><figcaption>Photo by NASA. <a href="https://unsplash.com/search/earth?photo=Q1p7bh3SHj8">Source</a></figcaption></figure><p>I think the biggest takeaway for me has been how geographically diverse the Unsplash community is. While there are certainly pockets of concentrated activity, I’ve seen photos get downloaded from all around the world. It’s fun to think that our photographers, collectively, have seen and captured so much of our planet.</p><blockquote><strong>Want to help us build Unsplash? </strong>We’re currently hiring for front-end development, back-end development, and designer positions. <a href="https://crew.co/hiring">Learn more</a>.</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bb65c335207f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/unsplash/unsplash-on-a-map-bb65c335207f">Unsplash on a Map</a> was originally published in <a href="https://medium.com/unsplash">Unsplash Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introducing ReduxVCR]]></title>
            <link>https://medium.com/@joshuawcomeau/introducing-redux-vcr-cad57b37540a?source=rss-a11edf57e20a------2</link>
            <guid isPermaLink="false">https://medium.com/p/cad57b37540a</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[redux]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[Joshua Comeau]]></dc:creator>
            <pubDate>Thu, 13 Oct 2016 14:33:56 GMT</pubDate>
            <atom:updated>2016-10-14T13:39:40.479Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/890/1*MbaH3FecL6azS1HVya5kiw.gif" /></figure><h4>The adorable tool that lets you record and re-watch user sessions.</h4><p>A few weeks ago, I was working on a Web Audio synthesizer called <a href="http://keyandpad.com/"><strong>Key&amp;Pad</strong></a>.</p><p>It struck me, while I was building it, that I wouldn’t be able to hear the interesting/beautiful/zany sounds that users made with it. What good is making a fun toy app if you can’t see (hear) what people do with it!</p><p>Because that project used Redux, though, the solution was obvious: Since every user action was already passing through the store, I just needed some middleware to capture it and track the time between each action. Then, I could just “replay” those actions in realtime.</p><p>As it turns out, there were a fair amount of problems that I hadn’t anticipated, and solving them in a generic way has been challenging. This tool is still in <em>early alpha</em>, and there’s a lot that has yet to be solved, but I’ve been using it in production without issue. I figure it’s time to have others start to poke and play with it :)</p><h3>The Results</h3><p>Here are some of my favourite recorded sessions so far:<br><em>(give the cassettes a second or two to load)</em></p><ul><li><a href="http://keyandpad.com/?adminMode=true&amp;cassetteId=8rflQRDWGlfuJzS9F52fgCdjyzD3"><strong>Noisecore</strong></a><br>A bunch of really neat, really dissonant sounds using bass notes, distortion, and a myriad of other effects.</li><li><a href="http://keyandpad.com/?adminMode=true&amp;cassetteId=cPWhypwNZAX4lYqA7RbaDvmuzBc2"><strong>Gradual Experimentation</strong></a><br>This user makes some interesting noises with chorus. Mostly I like this session because the experimentation and discovery process is so evident.</li><li><a href="http://keyandpad.com/?adminMode=true&amp;cassetteId=8zVPV0yH6Xdt8ffgXhllC1lUKiI3"><strong>Absolutely beautiful</strong></a><strong><br></strong>A lovely melody that becomes captivating with stereo tremolo. Evolves into a wub-wub dubstep bass.</li></ul><h4>Remixable</h4><p>Redux VCR doesn’t mind being interrupted; it’ll keep carrying out its sequence of actions, without complaining if you jam along with it.</p><p>I’ve been having a blast playing notes or tweaking effects on recorded sessions. <a href="http://keyandpad.com/?adminMode=true&amp;cassetteId=HbUkgUECdSa3ZzUeN0ubfcxULqx2"><strong>Here’s a simple session</strong></a> you can have fun with; try playing some notes over it, or changing the effects!</p><blockquote>Read on to learn more about how it works, how to get started, and where the project is going, or <a href="https://github.com/joshwcomeau/redux-vcr"><strong>jump straight to the project on GitHub</strong></a>.</blockquote><h3>How It Works</h3><p>Redux VCR is built to be modular. It consists of 4 main parts. Each of these pieces operate with Cassettes, plain objects that hold the sequence of actions needed to recreate a user’s session, as well as some metadata.</p><h4>Capture</h4><p>Capture is responsible for observing the stream of Redux actions, and selecting the ones it wants to record.</p><p>It’s pretty flexible: You can blacklist certain actions that you don’t want to record, or provide a “start action” that will kick off the recording (if, say, you don’t want to bother recording the onboarding process).</p><p>It creates a Cassette object, keeps track of how much time has elapsed between actions, and passes it on to the next module when stuff happens.</p><h4>Persist</h4><p>Persist is responsible for, well, persistence. The default module uses Firebase, and it will update the remote copy of the Cassette whenever it’s handed an updated version.</p><p>It can be debounced, to avoid spamming the server.</p><h4>Retrieve</h4><p>Retrieve is the inverse of Persist; it’s responsible for securely fetching the Cassettes. The default module uses Firebase as well.</p><p>Unlike the previous two modules, you likely don’t want to ship Retrieve in production. It’s used exclusively in development, so that you and you alone can re-watch user sessions.</p><h4>Replay</h4><p>Finally, Replay is the cute little VCR UI that lets you select and control cassettes. It offers the ability to modify the playback speed of actions, and I hope to add a scrubber that will let you jump to specific parts of the sequence.</p><p>It also consists of a middleware that allows us to pass custom options. For example, we can specify a max wait time between actions, to trim out long gaps where users are idle.</p><p>It also uses a higher-order reducer, to update the state when cassettes are loaded and ejected.</p><p>Similar to Retrieve, this is a production-only module.</p><h3>Serverless Security</h3><p>A concern with the development of this project was to ensure that users’ sessions were kept secure. At the same time, I didn’t want to enforce any kind of back-end. Key&amp;Pad lives on GitHub Pages with no server-side logic.</p><p>Firebase provides a nice solution, with its custom Rules API.</p><p>When your application loads, all users are automatically authenticated using Anonymous Authentication. Essentially this just gives them a unique ID that persists for the session.</p><p>Regular users are not able to read from the database at all, and they’re only allowed to write to their custom slice of the database, using their unique ID as the key.</p><p>For admins, I’m using GitHub OAuth. You specify, in the Firebase Rules, that read access is only given to users who match a specific GitHub account, and then authenticate by clicking the VCR and signing into GitHub.</p><h3>Getting Set Up</h3><p>Every project is different, and I’ve tried to make the setup as straightforward as possible while allowing for various configurations.</p><p>A <a href="https://github.com/joshwcomeau/redux-vcr#getting-started"><strong>full guide can be found on GitHub</strong></a>, but I think an easier way to grok the high-level concepts is to look at some examples.</p><p>I’ve created a repo, <a href="https://github.com/joshwcomeau/redux-vcr-todomvc"><strong>redux-vcr-todomvc</strong></a>, which installs Redux VCR in a few different ways. Each is a non-merged Pull Request, so you can view the diffs required to integrate Redux VCR into TodoMVC:</p><ul><li><a href="https://github.com/joshwcomeau/redux-vcr-todomvc/pull/1/files"><strong>Quickstart</strong></a><br>This is the easiest way to get started, but it’s not recommended for production usage.</li><li><a href="https://github.com/joshwcomeau/redux-vcr-todomvc/pull/2"><strong>Production-Ready</strong></a><br>This version takes care to keep admin-only modules out of the production build.</li><li><a href="https://github.com/joshwcomeau/redux-vcr-todomvc/pull/4"><strong>With an Initial Cassette</strong></a><br>Auto-load a specific cassette, specified by a query parameter. This is useful for favouriting a specific cassette, but can also be used to load the last-played cassette from localStorage.</li><li>More to come!</li></ul><p>Beyond the setup in the code, some setup is required with Firebase as well. Check out the <a href="https://github.com/joshwcomeau/redux-vcr/blob/master/documentation/firebase-config.md"><strong>Firebase Config docs</strong></a> to see how that works.</p><h3>Help Build Something Cool</h3><p>This project is <em>really early</em>, and there’s much work to be done. I have limited time to dedicate to this project, and I’m looking for contributors! I have huge ambitions for this tool, but I can’t do it all alone.</p><p>As it stands, Redux VCR works great for simple toy apps, like my synthesizer, but it isn’t sophisticated enough yet to handle most use-cases.</p><p>Some stuff I’d like to add:</p><ul><li>A way of stubbing out server requests. We likely don’t want to send real API requests when replaying sessions.</li><li>Native window-level event-capturing like mousemoves and scrolls.</li><li>A proper web interface for managing recorded cassettes.</li><li>A scrubber for being able to “skip to” sections of the tape, quickly replay certain sections, etc.</li></ul><p>Contributors who open a significant, acceptable PR will be given <a href="https://help.github.com/articles/permission-levels-for-a-user-account-repository/#collaborator-access-on-a-repository-owned-by-a-user-account">full collaborator rights</a>. I want this project to be yours as much as mine. For the community, by the community.</p><h2><a href="https://github.com/joshwcomeau/redux-vcr">Check it out now on GitHub</a></h2><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*W5xhpaxlbiBJlNVscwWwLg.gif" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cad57b37540a" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>