<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Betsy Haibel</title>
    <description>The latest articles on DEV Community by Betsy Haibel (@bhaibel).</description>
    <link>https://dev.to/bhaibel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F111269%2F6a279b93-3df3-431d-bff1-1403e7ef58b1.png</url>
      <title>DEV Community: Betsy Haibel</title>
      <link>https://dev.to/bhaibel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bhaibel"/>
    <language>en</language>
    <item>
      <title>What are "HTML-CSS-JS" and "CSS-in-JS", anyway?</title>
      <dc:creator>Betsy Haibel</dc:creator>
      <pubDate>Wed, 30 Jan 2019 12:51:42 +0000</pubDate>
      <link>https://dev.to/bhaibel/what-are-html-css-js-and-css-in-js-anyway-4cjp</link>
      <guid>https://dev.to/bhaibel/what-are-html-css-js-and-css-in-js-anyway-4cjp</guid>
      <description>&lt;p&gt;Yesterday afternoon, an early-career developer I know DMed me to ask: "&lt;em&gt;What&lt;/em&gt; are people defining as CSS-in-JS, anyway?" They had seen a lot of the debates flying around the internet, but didn't know how to engage with The Discourse, because no one was bothering to define terms. As I thought about how to answer them, I realized... "CSS-in-JS" is a large, umbrella term! There are a lot of different "CSS-in-JS" techniques out there, and some of them are closer to "traditional" HTML-CSS-JS approaches than others!&lt;/p&gt;

&lt;p&gt;A lot of the HTML-CSS-JS vs JS-JS-JS debate is rooted in &lt;a href="https://twitter.com/betsythemuffin/status/1090342513054007296"&gt;historical context and feelings&lt;/a&gt; rather than precise technical details. I don't think that trying to turn it into a purely technical discussion is a good idea, because there's so many other social dynamics in the room. But I also think that the technical aspects of the discussion will be healthier if we &lt;em&gt;bother to define our terms&lt;/em&gt;. In that spirit, I'd like to talk about some specific front-end strategies I've observed.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;From breaking these strategies down, the best working definition I can figure out of CSS-in-JS:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;any technique which uses JavaScript to apply styles &lt;em&gt;universally&lt;/em&gt;, as opposed to applying styles in response to user behavior.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  "Separate file" CSS.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Generally not considered CSS-in-JS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CSS is developed in &lt;code&gt;.css&lt;/code&gt; (or &lt;code&gt;.scss&lt;/code&gt;, or &lt;code&gt;.less&lt;/code&gt;) files that are maintained separately from &lt;code&gt;.js&lt;/code&gt; files. In development, they are generally be kept in a separate &lt;code&gt;stylesheets&lt;/code&gt; directory. These CSS files might be preprocessed from several small files into a larger CSS bundle, or they might not. If the CSS uses component-oriented techniques, developers use BEM or another naming convention to ensure that component-level styles stay component-level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web components and Shadow DOM
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Generally not considered CSS-in-JS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No strong conventions around "where" the CSS is kept yet here because it's a young technique! But in this style, Shadow DOM style isolation is used to ensure that component-level styles stay component level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Component-level CSS with &lt;em&gt;informal&lt;/em&gt; scoping
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Generally not considered CSS-in-JS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CSS is (usually) developed in &lt;code&gt;.css&lt;/code&gt;/.&lt;code&gt;scss&lt;/code&gt;/&lt;code&gt;.less&lt;/code&gt; files that are maintained in the same directory as other component files (e.g. HTML, JS, JSX). This strategy also covers &lt;code&gt;.vue&lt;/code&gt; files that do &lt;strong&gt;not&lt;/strong&gt; use the &lt;code&gt;scoped&lt;/code&gt; attribute in their &lt;code&gt;style&lt;/code&gt; block. These styles are preprocessed into a larger file for delivery, but no data attributes or "roboclasses" are added to enforce component scope. Instead, developers have to use BEM or another naming convention to ensure that component-level styles stay component-level.&lt;/p&gt;

&lt;h2&gt;
  
  
  JS-applied utility classes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sometimes considered CSS-in-JS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A utility class framework like Tailwind or Tachyons is maintained in a separate file. All components are rendered by JS, and use that JS to decide which utility classes to apply to HTML elements within the component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Component-level CSS with JS-enforced scoping
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sometimes considered CSS-in-JS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this frontend strategy, CSS is used for styling in conjunction with component files OR is embedded in those component files, &lt;code&gt;.vue&lt;/code&gt; style. The Vue &lt;code&gt;scoped&lt;/code&gt; attribute or a plugin like React's &lt;code&gt;styled-components&lt;/code&gt; is used during processing to add a "roboclass" prefix to the component's styles for scoping. This "roboclass" is applied during client or server rendering of the component, so this strategy &lt;em&gt;requires&lt;/em&gt; that JavaScript be used for template rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  JS-applied inline styling
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pretty much always considered CSS-in-JS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All components are rendered by JS, and use that JS to decide which specific inline styles to apply to HTML elements within the component. "CSS modules" fall into this category.&lt;/p&gt;




&lt;p&gt;I'm dashing this post off quickly before leaving for a month-long trip. My list isn't intended as exhaustive and my explanations may not be as clear as I'd want them to be in a more polished post. I'd really appreciate it if y'all could help fill in things I've missed or handwaved, so that this post/discussion can become a strong resource for folks who are confused by CSS-in-JS discourse.&lt;/p&gt;

&lt;p&gt;I'd appreciate it if y'all kept your opinions about these technologies OUT of the discussion. I intend to write a follow-up post about what I perceive these technologies' strengths and weaknesses to be. I'll welcome your opinions in &lt;em&gt;that&lt;/em&gt; comments section! But right here, I'd like to keep it to definitions, to maximize this post/discussion's usefulness as a resource.&lt;/p&gt;

</description>
      <category>explainlikeimfive</category>
      <category>discuss</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Haskell, Vectors, and Implicit Knowledge</title>
      <dc:creator>Betsy Haibel</dc:creator>
      <pubDate>Thu, 03 Jan 2019 16:01:36 +0000</pubDate>
      <link>https://dev.to/cohere/haskell-vectors-and-implicit-knowledge-4bal</link>
      <guid>https://dev.to/cohere/haskell-vectors-and-implicit-knowledge-4bal</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Hey folks!&lt;/p&gt;

&lt;p&gt;This piece is a few years old now, but I'm republishing it on dev.to as I move more of my stuff here. It's kind of personal. Unlike a lot of my other work, it's not about teaching folks how to tech better -- it's about why it's so important to me to do so in an accessible way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This winter I was teaching myself Haskell.&lt;/p&gt;

&lt;p&gt;I'd tried before, with everyone's darling &lt;em&gt;Learn You a Haskell for Great Good&lt;/em&gt;. My old boss had compared its "offbeat" approach to &lt;em&gt;_why's Poignant Guide to Ruby&lt;/em&gt;, which I love. Both have an informal tone, but the similarities stop there: where the Poignant Guide has adorable cartoon foxes, &lt;em&gt;Learn You a Haskell&lt;/em&gt; has upsetting bro humor. I think I snapped at one of the (many) fat jokes.&lt;/p&gt;

&lt;p&gt;This time around I tried &lt;em&gt;Real World Haskell&lt;/em&gt;, and at first things went much better. The material was more usefully organized, and the examples and exercises better suited to my learning style.&lt;br&gt;
Then I came to The Problem.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;The problem set at the end of Real World Haskell’s third chapter contains the following sequence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Consider three two-dimensional points a, b, and c. If we look at the angle formed by the line segment from a to b and the line segment from b to c, it either turns left, turns right, or forms a straight line. Define a Direction data type that lets you represent these possibilities.&lt;/li&gt;
&lt;li&gt;Write a function that calculates the turn made by three 2D points and returns a Direction.&lt;/li&gt;
&lt;li&gt;Define a function that takes a list of 2D points and computes the direction of each successive triple. Given a list of points [a,b,c,d,e], it should begin by computing the turn made by [a,b,c], then the turn made by [b,c,d], then [c,d,e]. Your function should return a list of Direction.&lt;/li&gt;
&lt;li&gt;Using the code from the preceding three exercises, implement Graham's scan algorithm for the convex hull of a set of 2D points. You can find good description of what a convex hull is, and how the Graham scan algorithm should work, on Wikipedia.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Problem 9 was pretty simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Direction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Left&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;Right&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;Straight&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Problem 10 took me a month.&lt;/p&gt;

&lt;p&gt;I figured it had to be simple; if it were a difficult geometry problem, it wouldn’t be in a beginners' Haskell book, it would be in a "Haskell as applied to tricky math" book. But approach after approach after approach failed me. I compared slopes. I tried complicated conditionals based on what quadrant each line was in when its base was set at origin.&lt;/p&gt;

&lt;p&gt;Did you know that Haskell has two &lt;code&gt;Data.Vector&lt;/code&gt; modules? There's one in the standard library that deals with Vectors like the array-like CS concept. There's one on Hackage that deals with Vectors like the geometry and second-year algebra concept. They are called the same thing. I know this now, because I found the docs for the latter, imported &lt;code&gt;Data.Vector&lt;/code&gt; like a good girl, and spent aeons of subjective time banging my head against arity mismatch errors before giving up on a dot-product-based solution.&lt;/p&gt;

&lt;p&gt;Eventually I finally hammered out all of the special cases.&lt;/p&gt;

&lt;p&gt;I’d been pushing myself to finish, rather than cutting my losses and moving on in the book, because I figured it would feel good when I finally did. It didn’t. I just felt stupid, because it had taken me a month to figure out what the authors of the book had clearly expected to be simple.&lt;/p&gt;

&lt;p&gt;I moved on to Problem 12. Looked up the Graham Scan algorithm on Wikipedia, as ordered. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Again, determining whether three points constitute a "left turn" or a "right turn" does not require computing the actual angle between the two line segments, and can actually be achieved with simple arithmetic only. For three points &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qy0-KPqL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/e/3/8/e38e464b2ad39be72af38cacc8fc17de.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qy0-KPqL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/e/3/8/e38e464b2ad39be72af38cacc8fc17de.png" alt="p1=(x1,y1)"&gt;&lt;/a&gt;, &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xz6tybA0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/a/4/5/a45267c35535663e45d3a0bcc4db16e6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xz6tybA0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/a/4/5/a45267c35535663e45d3a0bcc4db16e6.png" alt="p1=(x2,y2)"&gt;&lt;/a&gt; and &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NU4RLRw4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/b/d/b/bdb6d1f831105c159498d203a95c41fb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NU4RLRw4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/b/d/b/bdb6d1f831105c159498d203a95c41fb.png" alt="p1=(x3,y3)"&gt;&lt;/a&gt;, simply compute the z-coordinate of the cross product of the two vectors &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1WjOoppD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/a/c/7/ac7a0fe21575792e379eb1caa37d5224.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1WjOoppD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/a/c/7/ac7a0fe21575792e379eb1caa37d5224.png" alt="p1p2"&gt;&lt;/a&gt; and &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5406PX2O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/2/b/5/2b5ba9e273a2f3c0de10b0a07125bd86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5406PX2O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/2/b/5/2b5ba9e273a2f3c0de10b0a07125bd86.png" alt="p1p3"&gt;&lt;/a&gt;, which is given by the expression &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d0uL_Hwx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/4/4/d/44dac4ebbcdd18ed0593418004b5e4c8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d0uL_Hwx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload.wikimedia.org/math/4/4/d/44dac4ebbcdd18ed0593418004b5e4c8.png" alt="(x2 - x1)(y3 - y1) - (y2 - y1)(x3 - x1)"&gt;&lt;/a&gt;. If the result is 0, the points are collinear; if it is positive, the three points constitute a "left turn" or counter-clockwise orientation, otherwise a "right turn" or clockwise orientation (for counter-clockwise numbered points).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Reader, I saw fire.&lt;/p&gt;

&lt;p&gt;At first I was angry at myself, because there had been a straightforward answer and '’d "just been too stupid" to get it. Then I was angry at the authors for not putting that "simple arithmetic" answer in the text for problem 10. Then I was furious at the authors — because I realized why they hadn't.&lt;/p&gt;

&lt;p&gt;They thought it was too simple to explain. They thought that anyone learning Haskell would have retained all the random topics that are contained in high school precalculus. They thought that anyone learning Haskell would be the Kind Of Person who just "naturally" remembers that sort of stuff.&lt;/p&gt;

&lt;p&gt;And now, because it's a woman writing this, you're probably assuming that this is a rant about how you don't need to know math to computer.&lt;/p&gt;

&lt;p&gt;Think again. I am That Kind Of Person. I started programming at either twelve or eight, depending on whether you count HyperCard. I learned Scheme in ninth grade. I am That Kind of Person, and the problem still made me feel like a fucking idiot. Like an impostor. Like I ought to just give up.&lt;/p&gt;

&lt;p&gt;Over whether I could remember offhand that vector cross products were not commutative, and what implications this had for turn direction problems.&lt;/p&gt;

&lt;p&gt;This could be a rant about the arrogance of the functional programming ivory tower. But a lot of people have made that rant already, and I'm more interested in self-reflection than in being yet another Ruby programmer who’s snotty about non-Rubyists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closer to Home
&lt;/h2&gt;

&lt;p&gt;I teach people to program in my free time. I co-organize a drop-in group called Learn Ruby in DC, so every other week I walk people of all different skill levels through how to code. This includes honest-to-god raw beginners, as well as apprentices and juniors.&lt;/p&gt;

&lt;p&gt;There is one understanding gap that every single one of them runs into at some point. They mix up local variables and instance variables, or variables and strings, or ivars and symbols — the exact mixup doesn't matter. They respond by randomly adding and subtracting &lt;code&gt;@&lt;/code&gt;s and colons and quotation marks until it works, and then they sigh relief. This happens because they don’t have mental scaffolding for the differences between variables and symbols, between locals and ivars — to them, they’re just words that may or may not have magic before them, and so you fiddle with the magic until it runs.&lt;/p&gt;

&lt;p&gt;It always takes me a few minutes of observation to figure out that that's what's happening in their heads. I’ve been writing Ruby since 2008; the scope differences between raw ivars and accessors and local variables are like breathing now. My intuitive brain assumes that everyone knows this, and I need to back up and remind it that that’s not true.&lt;/p&gt;

&lt;p&gt;I need to do this even though in 2008, as a woman who’d worked with various conventional languages for 8 years, I'd struggled like hell to internalize that difference myself.&lt;/p&gt;

&lt;p&gt;Am I making my students feel stupid? I hope not, but… sometimes I probably am.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where do we go?
&lt;/h2&gt;

&lt;p&gt;The educational materials we create encode our values -- often accidentally. &lt;em&gt;_why's Poignant Guide&lt;/em&gt; reflects an ethos where programming is a joyful, creative activity. &lt;em&gt;Learn You a Haskell&lt;/em&gt; conveys a worldview that fat jokes are hilarious fun. &lt;em&gt;Real World Haskell&lt;/em&gt; assumes that all truly educated people remember vector-math intricacies off the top of their heads.&lt;/p&gt;

&lt;p&gt;The values of our educational materials create our community values. People whose assumptions mesh with theirs proceed onward to community participation; people whose assumptions and values don't leak out of the pipeline. I think Haskell is a really pretty language, but I can't tell if the Haskell community wants me.&lt;/p&gt;

&lt;p&gt;It’s human to forget that knowledge one has internalized is not common knowledge. It's human to be a poor teacher. It's human to confuse students; to make them feel terrible. It's still cruel. And when we encode that cruelty into our educational materials -- however accidentally -- we turn surviving that cruelty into something we value above all.&lt;/p&gt;

&lt;p&gt;What implicit knowledge is needed in your language of choice? How do you deal with that around juniors?&lt;/p&gt;




&lt;p&gt;If you found this post helpful, I'd love it if you subscribed to &lt;a href="https://www.wecohere.com/newsletter?utm_campaign=haskell-vectors-implicit-knowledge&amp;amp;utm_medium=devto&amp;amp;utm_content=footer"&gt;my company's monthly newsletter&lt;/a&gt;! We share some of the things we've found valuable each month, as well as exclusive insights into being a more effective programmer and engineering leader.&lt;/p&gt;

</description>
      <category>haskell</category>
      <category>beginners</category>
      <category>functional</category>
      <category>mentorship</category>
    </item>
    <item>
      <title>A senior dev's #1 piece of advice for newbies</title>
      <dc:creator>Betsy Haibel</dc:creator>
      <pubDate>Thu, 01 Nov 2018 02:02:31 +0000</pubDate>
      <link>https://dev.to/bhaibel/a-senior-devs-1-piece-of-advice-for-newbies-345p</link>
      <guid>https://dev.to/bhaibel/a-senior-devs-1-piece-of-advice-for-newbies-345p</guid>
      <description>&lt;p&gt;Go ahead! Do the thing! Make that refactor you're scared of! You have version control.&lt;/p&gt;

&lt;p&gt;You did commit first... right?&lt;/p&gt;

</description>
      <category>beginners</category>
    </item>
    <item>
      <title>Metrics, Async/Await, and Really Big Hammers</title>
      <dc:creator>Betsy Haibel</dc:creator>
      <pubDate>Tue, 30 Oct 2018 18:29:31 +0000</pubDate>
      <link>https://dev.to/bhaibel/metrics-asyncawait-and-really-big-hammers-f9e</link>
      <guid>https://dev.to/bhaibel/metrics-asyncawait-and-really-big-hammers-f9e</guid>
      <description>

&lt;p&gt;The other night my partner Chris asked me over dinner, “Betsy, how would you handle a call to a metrics library using async/await?”&lt;/p&gt;

&lt;p&gt;Chris makes developer tools at an e-commerce company. JavaScript isn’t a big part of the stack where he works, but everyone works with at least a little JavaScript nowadays. He needed to expose metrics APIs for the applications developers he works with. He wanted them to be easy to use, and not get in the way of their application code.&lt;/p&gt;

&lt;p&gt;Two things about metrics calls: first, they need to be &lt;em&gt;cheap&lt;/em&gt;. You don’t want to impose a runtime performance penalty on developers when they measure things. If you do, developers can’t measure that many things! Then, when everything crashes and they need to &lt;em&gt;have measured&lt;/em&gt; things, everyone’s stuck with guess-and-pray debugging. In a JavaScript context -- you don’t ever want a metrics call to block the execution thread.&lt;/p&gt;

&lt;p&gt;Second, we generally aren’t interested in the return value of a metrics call. We often don’t even care if they fail! Metrics calls aren’t about producing results the user cares about. They’re about observing the process that gets those results. We don’t want to get in the user’s way while we’re reporting on things that only developers care about.&lt;/p&gt;

&lt;p&gt;So: metrics calls shouldn’t block the thread, and we don’t care about their return values. Chris, therefore, figured that it was a bad idea to stick a metrics call in the middle of a function and await on it.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;showPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;priceWithoutShipping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;onSale&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;salePrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shippingCost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;shippingRate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;priceWithoutShipping&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;shippingCost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

  &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;postMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'userCheckoutStep3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;showUserTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;He’s right about that. That &lt;code&gt;await&lt;/code&gt; before &lt;code&gt;showUserTotal&lt;/code&gt; would mean that the user’s shopping cart wouldn’t get updated until the metrics posted! That might mean that they would get frustrated and close the tab before they bought things. A metrics API that presented that risk would be worse than useless. So Chris wondered — did it make more sense to make a convention of only &lt;code&gt;await&lt;/code&gt;ing metrics at the end of a function?&lt;/p&gt;

&lt;p&gt;This idea had some problems. This code is fine:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;showPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;priceWithoutShipping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;onSale&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;salePrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shippingCost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;shippingRate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;priceWithoutShipping&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;shippingCost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

  &lt;span class="nx"&gt;showUserTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;postMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'userCheckoutStep3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But this next code -- which is practically identical — has a bug in it. Can you spot it?&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;showPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;priceWithoutShipping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;onSale&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;salePrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shippingCost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;shippingRate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;priceWithoutShipping&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;shippingCost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

  &lt;span class="nx"&gt;showUserTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;postMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'userCheckoutStep3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The difference is that we’ve added a return statement midway through the function. Execution will never proceed beyond the return statement, so the metrics call will never happen.&lt;/p&gt;

&lt;p&gt;What if we change it so that the metrics call is on the last line &lt;em&gt;before&lt;/em&gt; the return?&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;showPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// beginning of function&lt;/span&gt;

  &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;postMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'userCheckoutStep3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That doesn’t really help us. We’re back to blocking part of the function’s work -- the return statement -- on the results of the metrics call! We don’t know how long it will take to complete. We do know -- computers being computers -- that it could be slow and flaky. We don’t want that to annoy our users.&lt;/p&gt;

&lt;p&gt;It’s a conundrum.&lt;/p&gt;

&lt;p&gt;Let’s re-examine the assumptions that went into writing this code. Do we really need to use &lt;code&gt;await&lt;/code&gt;? If we remove it, what happens?&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;showPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// beginning of function&lt;/span&gt;

  &lt;span class="nx"&gt;showUserTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;postMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'userCheckoutStep3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;totalPrice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The answer: it works just fine! Since we were awaiting on &lt;code&gt;postMetrics&lt;/code&gt; before, we know that that function returns a promise. But just because it returns a promise doesn’t mean we need to do anything with that promise. After all, we don’t need the value it resolves to. We can just remove the &lt;code&gt;await&lt;/code&gt; keyword. &lt;code&gt;postMetrics&lt;/code&gt; will perform its network call or socket write or whatever. It will do that happily in the background. The user will not need to care, and neither will we.&lt;/p&gt;

&lt;p&gt;Come to think of it, does &lt;code&gt;postMetrics&lt;/code&gt; even need to return a promise? Let’s take a look at the current definition of &lt;code&gt;postMetrics&lt;/code&gt;: &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;postMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;METRICS_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'POST'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt; &lt;span class="p"&gt;}}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;noop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It’s an async function that returns the result of fetch — which also returns a promise. But what if we didn’t make it return that promise? We do that by removing the return statement. We can also remove the async keyword. It's not relevant here. We don't need to guarantee that &lt;code&gt;postMetrics&lt;/code&gt; returns a promise, and we don't need to &lt;code&gt;await&lt;/code&gt; within it.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;postMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;METRICS_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'POST'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt; &lt;span class="p"&gt;}}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;noop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Just because a function does work asynchronously doesn’t mean that it needs to be marked with the &lt;code&gt;async&lt;/code&gt; keyword, or return a promise. There are three reasons you might want to return a promise from a function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You care about the value the promise resolves to.&lt;/li&gt;
&lt;li&gt;You care whether the operation succeeds or fails.&lt;/li&gt;
&lt;li&gt;You care that a side effect &lt;em&gt;has happened&lt;/em&gt; before you continue on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since none of those are the case here, it’s safe to not return anything from &lt;code&gt;postMetrics&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is an awful lot of words for “sometimes it’s ok for things to fail silently.” Is there any deeper moral here?&lt;/p&gt;

&lt;p&gt;Chris didn’t ask me “how should I design my metrics API?” He asked, “How should I use &lt;code&gt;await&lt;/code&gt; in my metrics API?” instead. &lt;/p&gt;

&lt;p&gt;Right now, async/await is the cool new kid on the block in JavaScript land. Chris hasn’t done much JS in years, but even he knew that it was what he was “supposed” to use nowadays. Whenever we learn a new programming technique, it’s easy to develop a bad case of hammer-and-nail syndrome.&lt;/p&gt;

&lt;p&gt;Async/await is a &lt;em&gt;really shiny&lt;/em&gt; hammer. So much of what we do with asynchronous code in JavaScript isn’t complicated evented code. It’s just waiting for things. It’s waiting for API results or database updates, doing a small calculation, and then waiting for something else. The only difference between it and the same code in Python is that the execution thread is doing something else while we wait. Async/await lets us make our code look like the same code would in Python, instead of jumping into Promise-chain hell.&lt;/p&gt;

&lt;p&gt;It’s such an obvious win that it’s easy to think that it ought to be a win everywhere.&lt;/p&gt;

&lt;p&gt;But that means we start looking at our code and asking, “how can I apply this solution?” It’s dangerous, because it means we skip right past, “what problem am I trying to solve?”&lt;/p&gt;

&lt;p&gt;Async/await can solve a lot of problems. But the fact that it’s often the answer doesn’t mean we can skip past asking the question.&lt;/p&gt;




&lt;p&gt;Want to learn more about async/await, or about asynchronous JavaScript generally? Sign up for &lt;a href="/products/untangling-asynchronous-javascript-free-email-course"&gt;Untangling Asynchronous JavaScript&lt;/a&gt;! This free email course looks at the history of asynchronous JavaScript. It puts async primitves like event emitters, promises, and async/await in the context of the problems folks were trying to solve. This lets us talk about what each of them is good for, and where each of them falls down.&lt;/p&gt;


</description>
      <category>node</category>
      <category>javascript</category>
      <category>asyncawait</category>
    </item>
  </channel>
</rss>
