<?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:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Frontside Software RSS Feed]]></title><description><![CDATA[Developer Experience and Backstage consultancy based in Austin, Texas.]]></description><link>https://frontside.com</link><generator>GatsbyJS</generator><lastBuildDate>Thu, 02 Apr 2026 13:48:27 GMT</lastBuildDate><item><title><![CDATA[Announcing Effection 3.0 -- Structured Concurrency and Effects for JavaScript]]></title><description><![CDATA[A major milestone in bringing Structured Concurrency and Effects to JavaScript, Effection 3.0 has excellent TypeScript support, a powerful new context API, and harmonizes perfectly with the JavaScript APIs you know and love.]]></description><link>https://frontside.com/blog/2023-12-18-announcing-effection-v3/</link><guid isPermaLink="false">https://frontside.com/blog/2023-12-18-announcing-effection-v3/</guid><category><![CDATA[javascript]]></category><category><![CDATA[structured concurrency]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 18 Dec 2023 20:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://frontside.com/effection&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Effection&lt;/a&gt; is Structured Concurrency and Effects for JavaScript.&lt;/p&gt;
&lt;p&gt;It’s a library purpose-built to help developers write code that can easily manage the most complex concurrent computations whether in the frontend or backend. It provides the guarantees of Structured Concurrency in order to make code leak-proof by default, and it achieves this while being simple to read, understand, and maintain.&lt;/p&gt;
&lt;p&gt;Just over five years ago, in November of 2018, when Structured Concurrency was a little-known peculiarity, we started a helper library to coordinate the many moving parts in some of our open-source projects (such as &lt;a href=&quot;https://frontside.com/interactors&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Interactors&lt;/a&gt;). Since then, it has grown into a mature project in its own right; deployed in production worldwide, helping developers use Structured Concurrency to push the limit of what is possible with JavaScript.&lt;/p&gt;
&lt;p&gt;Today, we are pushing things further and concentrating even more power into the hands of JavaScript developers with the release of Effection 3.0. This new version refines and simplifies the abstractions we first created in version 2.0 while introducing some new ones of exceptional power. This release has much to look forward to, including the new Context API and an even better TypeScript experience. Most of all, however, we’re proud of how we’ve realigned all of the APIs so that working with Effection feels just like working with JavaScript, only with the protections of structured concurrency baked in.&lt;/p&gt;
&lt;p&gt;That’s why we say more than ever before: &lt;em&gt;Effection is Structured Concurrency and Effects for JavaScript&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here’s an overview of some key features you’ll find in Effection 3.0&lt;/p&gt;
&lt;p&gt;- &lt;a href=&quot;#%EF%B8%8F-first-class-typescript-experience&quot;&gt;Excellent TypeScript Experience&lt;/a&gt;: TypeScript types have been carefully re-imagined to be as small and helpful as possible.&lt;/p&gt;
&lt;p&gt;- &lt;a href=&quot;#%EF%B8%8F-embrace-the-javascript&quot;&gt;Embrace of JavaScript&lt;/a&gt;: Version 3 is easier to learn and safer to integrate into your projects than ever because of its dedication to following JavaScript standards in spirit and form.&lt;/p&gt;
&lt;p&gt;- &lt;a href=&quot;#-new-context-api&quot;&gt;Context API&lt;/a&gt;: Shared environmental data (like auth tokens), shared resources, and contextual (aka algebraic) effect handlers have at least one thing in common: They are all made possible by the new Context API.&lt;/p&gt;
&lt;p&gt;- &lt;a href=&quot;#-rebuilt-with-delimited-continuations&quot;&gt;Rebuilt with Delimited Continuations&lt;/a&gt;: The v3 API is so simple it feels like it almost isn’t there. But that doesn’t mean there isn’t some serious brainpower behind the ideas that make this possible.&lt;/p&gt;
&lt;h2 id=&quot;️-excellent-typescript-experience&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EF%B8%8F-excellent-typescript-experience&quot; aria-label=&quot;️ excellent typescript experience permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;🏷️ Excellent TypeScript Experience&lt;/h2&gt;
&lt;p&gt;Since version 2.0, Effection itself has been written in TypeScript. As a result, a lot of thought was put into making it pleasant to use there. However, some rough edges remained.&lt;/p&gt;
&lt;p&gt;The first area where the TypeScript experience improved is in the &lt;code class=&quot;language-text&quot;&gt;Operation&amp;lt;T&gt;&lt;/code&gt; type itself. In the 2.x versions of Effection, it was a union of seven member types, one of which was &lt;code class=&quot;language-text&quot;&gt;undefined&lt;/code&gt;. It was unclear what you should set as your return type if you were writing a function that returned an Operation. Compound this with the fact that all Effection APIs were inconsistent in what they returned. Some returned &lt;code class=&quot;language-text&quot;&gt;Resource&amp;lt;T&gt;&lt;/code&gt;, others &lt;code class=&quot;language-text&quot;&gt;OperationFunction&amp;lt;T&gt;&lt;/code&gt;. Now, there is a single &lt;code class=&quot;language-text&quot;&gt;Operation&amp;lt;T&gt;&lt;/code&gt;, which is a &lt;a href=&quot;https://github.com/thefrontside/effection/blob/45b181f2ca99b512c1b869a10538576bd49d4675/lib/types.ts#L43-L45&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;simple interface&lt;/a&gt; that can be used consistently as a function parameter and return type.&lt;/p&gt;
&lt;p&gt;However, the most vexing issue with Effection v2 in TypeScript arose because the generator type prevented the left side of a &lt;code class=&quot;language-text&quot;&gt;yield&lt;/code&gt; expression from being inferred properly. That meant you had to annotate values bound in this way manually. For example, if we had an operation of type &lt;code class=&quot;language-text&quot;&gt;createNumber(): Operation&amp;lt;number&gt;&lt;/code&gt;, then we would have to manually tell TypeScript that the result of &lt;code class=&quot;language-text&quot;&gt;createNumber()&lt;/code&gt; was, in fact, a &lt;code class=&quot;language-text&quot;&gt;number&lt;/code&gt;, even though the return type already clearly indicated this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// we have to declare that `count` is a number&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toExponential&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But that was only ever a hint, not a constraint, and a completely bogus annotation would breeze right through the type checker as well.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// we have to declare that `count` is a number&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toExponential&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// TypeError!&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This was a major Achilles heel for TypeScript developers who wanted to use Effection. They expected the complete experience, not just of compile-time type checking, but also all the language server tooling that having type information enables. Sadly, the TypeScript experience with Effection v2 fell short of what they expected.&lt;/p&gt;
&lt;p&gt;Effection 3.0 makes this completely a non-issue by using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield*&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;yield*&lt;/code&gt;&lt;/a&gt; to evaluate operations in the context of another. This has many benefits, including shorter stack traces and lower memory overhead, but one of the greatest is that it completely solves the type inference problem. This is because the type of a &lt;code class=&quot;language-text&quot;&gt;yield*&lt;/code&gt; expression is independent of the type of function that evaluates it. Now, if we try to assign an incompatible type from an operation, we’ll get a type-checking error:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;//@ts-expect-error `string` is not assignable to `number`!&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toExponential&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;-new-context-api&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#-new-context-api&quot; aria-label=&quot; new context api permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;✨ New Context API&lt;/h2&gt;
&lt;p&gt;Sometimes, you need to share something across a wide range of operations. It could be anything from a simple string like an auth token to a shared service that other code needs to function. But so much depends on this shared thing that you don’t want to pollute your APIs by passing it around as an argument everywhere.  Instead, you want it to be “just there” as part of the environment in the same way the &lt;code class=&quot;language-text&quot;&gt;document&lt;/code&gt; reference is “just there” on a web page.&lt;/p&gt;
&lt;p&gt;Effection now ships with an API that solves this need elegantly. It is deceptively simple, but don’t let that fool you. The new &lt;a href=&quot;https://deno.land/x/effection/mod.ts?s=Context&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Context&lt;/code&gt;&lt;/a&gt; API is jam-packed with power, and it’s one of the features we’re most thrilled to be releasing.&lt;/p&gt;
&lt;p&gt;To see this in action, let’s make a &lt;code class=&quot;language-text&quot;&gt;Username&lt;/code&gt; context to track our current user so that we can greet them from an operation.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createContext &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;effection&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// create the username context;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Username &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can now use this context from within any operation! Let’s create an operation to greet the current user:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// greet the current user, whoever that is&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; username &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Username&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;username&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Username&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we run the above code, it will print the following to the console.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;Hello anonymous&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But here is the kicker. Context is sensitive to scope.&lt;/p&gt;
&lt;p&gt;Because of this, when you set the value of a context, it is only visible to &lt;em&gt;that scope and its children&lt;/em&gt;. All other scopes are completely unaffected.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Username&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Username&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;bob&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Username&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;alice&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;prints&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Hello anonymous!
Hello bob!
Hello alice!
Hello anonymous!&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, the child operations get their own private definition of &lt;code class=&quot;language-text&quot;&gt;Username&lt;/code&gt; that neither interferes with each other, nor the definition of their parent.&lt;/p&gt;
&lt;p&gt;Call it a foundation for dependency injection, or a basis for algebraic effect handlers, the range of uses for this mechanism are &lt;em&gt;massive&lt;/em&gt;  and we can’t wait to see what folks end up doing with it.&lt;/p&gt;
&lt;h2 id=&quot;️-embrace-the-javascript&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EF%B8%8F-embrace-the-javascript&quot; aria-label=&quot;️ embrace the javascript permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;❤️ Embrace the JavaScript&lt;/h2&gt;
&lt;p&gt;Our goal with Effection has always been to make it easy to write JavaScript code protected by Structured Concurrency&apos;s guardrails. That’s why our project’s tagline is “Structured Concurrency and Effects for JavaScript.”  We believe you shouldn’t have to learn an entirely new way to write programs to achieve the benefits of Structured Concurrency. Instead, we believe that the &lt;em&gt;only&lt;/em&gt; new thing you should have to learn is Structured Concurrency, and everything else should feel like plain JavaScript/TypeScript every step of the way.&lt;/p&gt;
&lt;p&gt;With version 3.0, we’ve doubled down on this idea by re-imagining our APIs as mirrors to existing counterparts in JavaScript. That way, if you know how to do it in JavaScript, you know how to do it in Effection. We call this conversion between vanilla JavaScript and Effection our &lt;a href=&quot;https://frontside.com/effection/docs/async-rosetta-stone&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;“Async Rosetta Stone.”&lt;/a&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Async&lt;/th&gt;
&lt;th&gt;Effection&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Promise&lt;/td&gt;
&lt;td&gt;Operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;new Promise()&lt;/td&gt;
&lt;td&gt;action()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;await&lt;/td&gt;
&lt;td&gt;yield*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;async function&lt;/td&gt;
&lt;td&gt;function*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AsyncIterable&lt;/td&gt;
&lt;td&gt;Stream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AsyncIterator&lt;/td&gt;
&lt;td&gt;Subscription&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;for await&lt;/td&gt;
&lt;td&gt;for yield*&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There is a structured analog for any construct you use for &lt;code class=&quot;language-text&quot;&gt;async&lt;/code&gt; programming. For everything else, &lt;em&gt;JavaScript and its wider ecosystem is your standard library.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Consider &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/async_function#examples&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;this example from MDN&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;async&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#async&quot; aria-label=&quot;async permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Async&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAfter2Seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// async function expression assigned to a variable&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAfter2Seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAfter2Seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;effection&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#effection&quot; aria-label=&quot;effection permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Effection&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAfter2Seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; timeout &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clearTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timeout&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// operation function expression assigned to a variable&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAfter2Seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolveAfter2Seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Interoperation between these two worlds will always be our project’s foremost concern. For example, creating a &lt;code class=&quot;language-text&quot;&gt;Stream&lt;/code&gt; at runtime is trivial from a reference to an &lt;code class=&quot;language-text&quot;&gt;AsyncIterable&lt;/code&gt; and vice-versa. The same is true for &lt;code class=&quot;language-text&quot;&gt;Subscription&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;AsyncIterator&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Effection is dedicated to keeping this alignment with core JavaScript in place both now and into the future so that developers can have peace of mind knowing that Effection will always be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Easy to learn for any developer encountering Effection code for the first time. If they know JavaScript, they (mostly) know Effection.&lt;/li&gt;
&lt;li&gt;Easy to adapt to any existing codebase, no matter what other paradigms it may use.&lt;/li&gt;
&lt;li&gt;Easy to “sprinkle” into a codebase without requiring massive refactors.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;-rebuilt-with-delimited-continuations&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#-rebuilt-with-delimited-continuations&quot; aria-label=&quot; rebuilt with delimited continuations permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;🧠 Rebuilt with Delimited Continuations&lt;/h1&gt;
&lt;p&gt;You might think that a robust implementation of Structured Concurrency and Effects for JavaScript could easily be large, complex, difficult to understand, and a pain to debug. And if you were talking about Effection prior to version 3.0, you might even be right!&lt;/p&gt;
&lt;p&gt;Versions 1.x and 2.x used a combination of state machines and cascading chains of callbacks that fired events and transitioned those state machines to orchestrate code to run at the right time. In a way, those past versions of Effection jumped on the grenade of callback hell so that users didn’t have to.&lt;/p&gt;
&lt;p&gt;While that was a worthy tradeoff, Effection 3.0 gets to have its cake and eat it, too by undergirding its entire implementation on the foundation of &lt;strong&gt;delimited continuations&lt;/strong&gt;. These curious constructs from the world of functional programming are extraordinarily powerful artifacts. They can express &lt;em&gt;all&lt;/em&gt; the standard control mechanisms we’re familiar with, from &lt;code class=&quot;language-text&quot;&gt;while&lt;/code&gt; loops to &lt;code class=&quot;language-text&quot;&gt;try/catch&lt;/code&gt;blocks, to algebraic effect handlers.&lt;/p&gt;
&lt;p&gt;Having an abstraction of this power drive Effection v3 means that its core logic can be expressed in only about 150 lines of TypeScript. And because it isn’t based on asynchronous callbacks but instead delimited continuations, execution is linear and straightforwardly follows its source code. As a result, it is an order of magnitude easier to understand and maintain.&lt;/p&gt;
&lt;p&gt;We’re packing a more powerful, performant, and maintainable library into a much smaller footprint thanks to delimited continuations. The bundle size has been slashed in half and clocks in at a miniscule 4.6kb gzipped.&lt;/p&gt;
&lt;p&gt;To delve deeper into the subject of delimited continuations in JavaScript, we recommend:&lt;/p&gt;
&lt;p&gt;- &lt;a href=&quot;https://www.youtube.com/watch?v=uRbqLGj_6mI&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Eric Bower’s talk for Michigan TypeScript&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;- &lt;a href=&quot;https://en.wikipedia.org/wiki/Delimited_continuation&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;On Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;- &lt;a href=&quot;https://github.com/cowboyd/delimited-continuations-tutorial&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;TypeScript tutorial on delimited continuations&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;get-started-with-effection-30-today&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#get-started-with-effection-30-today&quot; aria-label=&quot;get started with effection 30 today permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Get Started With Effection 3.0 Today!&lt;/h2&gt;
&lt;p&gt;Wondering what the next step is? Whether you&apos;re beginning a new project, or wanting to bring more clarity to an existing one, &lt;a href=&quot;https://frontside.com/effection&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Effection&lt;/a&gt; is meant to be both the simplest &lt;em&gt;and&lt;/em&gt; the easiest way to use structured concurrency and effects in JavaScript.&lt;/p&gt;
&lt;p&gt;Check it out on &lt;a href=&quot;https://github.com/thefrontside/effection&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GitHub&lt;/a&gt;, have a look at our &lt;a href=&quot;https://frontside.com/effection/docs/installation&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;guide to getting started&lt;/a&gt;, or &lt;a href=&quot;https://discord.gg/r6AvtnU&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;drop into our Discord Server&lt;/a&gt; to say hi. We&apos;re always eager to talk, and look forward to hearing from you all soon.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/ffbaf23c1012bc2af2221c370fb1c7da/2a4de/2023-12-18-announcing-effection-v3.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[The await event horizon in JavaScript]]></title><description><![CDATA[Why async functions in JavaScript are insufficient as a Structured Concurrency primitive]]></description><link>https://frontside.com/blog/2023-12-11-await-event-horizon/</link><guid isPermaLink="false">https://frontside.com/blog/2023-12-11-await-event-horizon/</guid><category><![CDATA[javascript]]></category><category><![CDATA[structured concurrency]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 11 Dec 2023 20:00:00 GMT</pubDate><content:encoded>&lt;p&gt;There is a boundary around every black hole where the velocity required to escape its gravitational pull exceeds the speed of light. Once anything, including light itself, passes over that threshold, it is trapped inside the mysterious interior of the black hole forever. There is no escape, and there is no return back to the rest of the universe. This boundary is called the black hole’s event horizon.&lt;/p&gt;
&lt;p&gt;A similar boundary exists around every JavaScript Promise, and once the flow of execution crosses over it, there is no way to forcibly escape and return back from whence it came. I refer to this boundary as the Promise’s &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon.&lt;/p&gt;
&lt;p&gt;An async function traverses an &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon every time it pauses for the result of a Promise. When it does, control can never return back to it until such time as that Promise settles; and there is absolutely no way to guarantee that it (or any) Promise will ever settle. It might happen in the next tick of the event loop, or in the worst case scenario, it just might never settle at all. When that happens, the poor waiting function is stuck forever helpless… suspended like an insect in amber.&lt;/p&gt;
&lt;p&gt;This is not theoretical. It is of important, practical concern. For example, consider this async function that implements the very common pattern of doing some setup, performing an operation, and then doing necessary teardown. In the code below, the async function acquires a lock, awaits a function it receives as an argument, and then, once that operation is complete, releases the lock.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;protect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lock &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;acquireLock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lock&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But what happens if the Promise returned by &lt;code class=&quot;language-text&quot;&gt;work()&lt;/code&gt; never settles? The answer is that the &lt;code class=&quot;language-text&quot;&gt;protect()&lt;/code&gt; function has passed over the &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon, never to resume. As a result, the lock it acquired at its start is never released, and so we say the lock has been “leaked”.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Resource leaks are considered by many to be the most insidious category of bug in software because of the difficulty in tracking them down coupled with the fact that they often lay hidden until the system is under the stress of a heavy workload.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Of course as a rule, most promises &lt;em&gt;do&lt;/em&gt; settle if we let them run long enough and so for the most part we abide by the blissful convention that they &lt;em&gt;will&lt;/em&gt;. But happy assumptions rarely pan out at scale. In fact, we find out pretty quickly that it isn’t just promises taking forever that are problematic.&lt;/p&gt;
&lt;p&gt;Let’s suppose that we wanted to call our &lt;code class=&quot;language-text&quot;&gt;protect()&lt;/code&gt; function from within a command line interface, and that when the user hits CTRL-C, we exit our process. If our work takes ten seconds, but the user hits CTRL-C after nine and a half seconds, then control never returns from beyond the &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon and the lock is leaked once again.&lt;/p&gt;
&lt;p&gt;We aren’t talking about a promise that never settles here. We’re talking about one that would have settled imminently, and yet it only took a difference of five hundred milliseconds for the leak to manifest.&lt;/p&gt;
&lt;h2 id=&quot;is-explicit-resource-management-a-solution&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#is-explicit-resource-management-a-solution&quot; aria-label=&quot;is explicit resource management a solution permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Is Explicit Resource Management a solution?&lt;/h2&gt;
&lt;p&gt;In a word: no.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tc39/proposal-explicit-resource-management&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Explicit resource management&lt;/a&gt;, a stage 3 TC39 proposal as of this writing, allows you to bundle setup and teardown code together. It saves you from going through the ceremony of a  &lt;code class=&quot;language-text&quot;&gt;try/catch&lt;/code&gt; block and makes it much more difficult to inadvertantly leak resources. If our hypothetical locking mechanism had it built in, it would allow us to write our &lt;code class=&quot;language-text&quot;&gt;protect()&lt;/code&gt; function much more clearly.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;protect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  using lock &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;acquireLock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When &lt;code class=&quot;language-text&quot;&gt;protect()&lt;/code&gt; finishes and &lt;code class=&quot;language-text&quot;&gt;lock&lt;/code&gt; passes out of scope, it is automatically released according to its pre-bundled deallocation logic.&lt;/p&gt;
&lt;p&gt;While this a handy improvement, it does nothing to change the fundamental physics of the &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon. Once flow control passes through it, there is no coming back until &lt;code class=&quot;language-text&quot;&gt;work()&lt;/code&gt; settles. If that takes too long, then &lt;code class=&quot;language-text&quot;&gt;protect()&lt;/code&gt; will take too long, and as a result, the automatic destruction of the &lt;code class=&quot;language-text&quot;&gt;lock&lt;/code&gt; resource will never be triggered. In other words, it is leaked.&lt;/p&gt;
&lt;h2 id=&quot;does-abortsignal-help&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#does-abortsignal-help&quot; aria-label=&quot;does abortsignal help permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Does AbortSignal help?&lt;/h2&gt;
&lt;p&gt;In theory yes, but in actual practice kinda-not-really. Abort signals can, when applied with discipline, remediate the problem somewhat, but they cannot solve it.  It begins with the reality that there is no agreed upon way to “cancel” a promise when handed an &lt;code class=&quot;language-text&quot;&gt;AbortSignal&lt;/code&gt;. In fact, it is a very thorny issue which caused T39 to &lt;a href=&quot;https://github.com/tc39/proposal-cancelable-promises/issues/70&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;throw up its hands almost a decade ago&lt;/a&gt;, and if you think you know the answer offhand, then the odds are that you haven’t &lt;a href=&quot;https://news.ycombinator.com/item?id=13214487&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;thought about it long enough&lt;/a&gt;. However if we must, one way is to wrap every promise in a &lt;code class=&quot;language-text&quot;&gt;safe()&lt;/code&gt; function that serves as a barrier to protect us from the &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;safe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;promise&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; signal&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;race&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    promise&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;reject&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; signal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;abort&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reject&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If &lt;code class=&quot;language-text&quot;&gt;signal&lt;/code&gt; fires before &lt;code class=&quot;language-text&quot;&gt;promise&lt;/code&gt; settles, then our safe function will immediately reject, returning control to the caller by throwing an error. With this mechanism in hand, we can re-write our &lt;code class=&quot;language-text&quot;&gt;protect()&lt;/code&gt; function to thread an abort signal throughout the entire computation.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;protect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;work&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; signal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lock &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;safe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;acquireLock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; signal&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;safe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;work&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;signal&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; signal&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lock&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The function now uses &lt;code class=&quot;language-text&quot;&gt;safe()&lt;/code&gt; to wrap every &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; expression in a circle of protection that prevents execution from becoming trapped beyond its event horizon. In addition, it passes &lt;code class=&quot;language-text&quot;&gt;signal&lt;/code&gt; down to &lt;code class=&quot;language-text&quot;&gt;work()&lt;/code&gt; so that it, and any functions that it calls can do the same. Now, when &lt;code class=&quot;language-text&quot;&gt;signal&lt;/code&gt; is fired, no matter if &lt;code class=&quot;language-text&quot;&gt;work()&lt;/code&gt; becomes stuck, our &lt;code class=&quot;language-text&quot;&gt;protect()&lt;/code&gt; function will exit, and the lock will be released. However, the approach still comes with this serious and unavoidable caveat: the abort signal is a hope, not a constraint.&lt;/p&gt;
&lt;p&gt;It’s not just that an extra abort signal is cumbersome to both use and pass around. It is. It’s that if &lt;code class=&quot;language-text&quot;&gt;work()&lt;/code&gt; or any of the functions that it calls, or any of the functions that &lt;em&gt;they&lt;/em&gt; call, fail to use &lt;code class=&quot;language-text&quot;&gt;signal&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;safe&lt;/code&gt;() then we are right back in the same boat of having async functions in our call tree that become trapped beyond the &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon and leak resources as a result.&lt;/p&gt;
&lt;p&gt;What’s fundamentally missing is the power of abstraction: the freedom to think about &lt;code class=&quot;language-text&quot;&gt;work()&lt;/code&gt; as a black box and feel secure that it will return control to its caller whenever it needs it most, no matter how &lt;code class=&quot;language-text&quot;&gt;work()&lt;/code&gt; is constructed internally. Using abort signals, the only way to achieve this is would be to read its source code and the source code of all its transitive dependencies to ensure that they also observe abort signal discipline. In practice, nobody would do that, and the scarcity of libraries that actually integrate abort signals shows that nobody does. While they can work around the obstacle through the imposition of discipline, they cannot make it disappear altogether. The fact remains that once control passes through the &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon, it cannot be brought back.&lt;/p&gt;
&lt;h2 id=&quot;structured-concurrency-and-the-await-event-horizon&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#structured-concurrency-and-the-await-event-horizon&quot; aria-label=&quot;structured concurrency and the await event horizon permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Structured Concurrency and the await event horizon&lt;/h2&gt;
&lt;p&gt;There are many remediations for the problem this poses, but most of them amount to some variation of the abort signal. The &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon however, remains axiomatic because the mechanics of it are baked into the heart of the runtime. There is no way to reliably pierce through it.&lt;/p&gt;
&lt;p&gt;The consequence of this is that the &lt;em&gt;minimum&lt;/em&gt; lifetime of any given &lt;code class=&quot;language-text&quot;&gt;async&lt;/code&gt; function is determined solely by the lifetime of its &lt;em&gt;innermost&lt;/em&gt; promises. In other words, the natural lifetime of an &lt;code class=&quot;language-text&quot;&gt;async&lt;/code&gt; function is determined from the inside out.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;protect()&lt;/code&gt; cannot continue until &lt;code class=&quot;language-text&quot;&gt;work()&lt;/code&gt; settles… whenever that may be. So it is &lt;code class=&quot;language-text&quot;&gt;work()&lt;/code&gt; that determines when &lt;code class=&quot;language-text&quot;&gt;protect()&lt;/code&gt; can continue, and it is &lt;code class=&quot;language-text&quot;&gt;protect()&lt;/code&gt; that determines the natural lifetime of our main function. Anything that overruns the exit of our process is in the “danger zone” of being leaked. This includes our hypothetical lock&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2023-12-11-await-event-horizon/leak-zone.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Any code that runs longer than needed is in danger of being leaked&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;In fact, this is precisely the opposite of what is required by a Structurally Concurrent system. Namely, that the &lt;em&gt;maximum&lt;/em&gt; lifetime of a function is constrained by the lifetime of the function that calls it. Instead of waiting around for async operations to complete that have no bearing on the outcome of a computation, a structurally concurrent system will return from those functions immediately the moment they are no longer necessary. In our example of the command line interface, as soon as the user hits ctrl-c, everything else becomes immediately irrelevant.&lt;/p&gt;
&lt;p&gt;What we would like to see in this case is the forcible return of control &lt;em&gt;back&lt;/em&gt; to the &lt;code class=&quot;language-text&quot;&gt;protect()&lt;/code&gt; function, so that it can run its &lt;code class=&quot;language-text&quot;&gt;finally&lt;/code&gt; block so that the lock is not leaked and the process exits gracefully.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2023-12-11-await-event-horizon/graceful-shutdown.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;A well behaved operation always returns&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;However, in order to enforce the shutdown of these irrelevant functions, there must be some mechanism by which to impose a return of control from the top down. But we’ve just seen how in &lt;code class=&quot;language-text&quot;&gt;async&lt;/code&gt; functions, once control passes through the &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon, it cannot be brought back. It’s for this reason that primitives based on &lt;code class=&quot;language-text&quot;&gt;async&lt;/code&gt; functions can at best hope for structured concurrency, but they can never guarantee it.&lt;/p&gt;
&lt;h2 id=&quot;structured-concurrency-and-javascript&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#structured-concurrency-and-javascript&quot; aria-label=&quot;structured concurrency and javascript permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Structured Concurrency and JavaScript&lt;/h2&gt;
&lt;p&gt;You might be thinking at this point that structured concurrency in JavaScript is a lost cause because it can’t be achieved with &lt;code class=&quot;language-text&quot;&gt;async&lt;/code&gt; functions. Far from it! Structured Concurrency is not only possible, you can already find it out in the wild today in the likes of projects like &lt;a href=&quot;https://frontside.com/effection&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Effection&lt;/a&gt;, &lt;a href=&quot;http://effects.js.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Effect-TS&lt;/a&gt;, and &lt;a href=&quot;https://github.com/neurosnap/starfx&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;StarFX&lt;/a&gt; (to name a few). These libraries come in all shapes and sizes, but one thing that they all share in common is an embrace of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;generator functions&lt;/a&gt; as a core technique.&lt;/p&gt;
&lt;p&gt;This is because generators functions in JavaScript are not limited by the &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon. They represent full-fledged &lt;a href=&quot;https://en.wikipedia.org/wiki/Delimited_continuation&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;delimited continuations&lt;/a&gt;, which is one of the most (if not the most) powerful flow control primitive there is. Without delving into what delimited continuations are, suffice it to say that they can be used to express &lt;em&gt;any&lt;/em&gt; other control mechanism you’d care to implement, from &lt;code class=&quot;language-text&quot;&gt;while&lt;/code&gt; loops, to &lt;code class=&quot;language-text&quot;&gt;try/catch&lt;/code&gt; blocks to algebraic effect handlers. In fact, in their essence, &lt;code class=&quot;language-text&quot;&gt;async&lt;/code&gt; functions themselves are just a watered down version of generator functions limited to the specific domain of promise handling.&lt;/p&gt;
&lt;p&gt;Critically for our use-case, generator functions allow for an explicit &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/return&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;return()&lt;/code&gt;&lt;/a&gt; which signals them to exit &lt;em&gt;posthaste&lt;/em&gt; from wherever they are currently executing. Yet as they do, they will still follow critical code paths such as &lt;code class=&quot;language-text&quot;&gt;finally {}&lt;/code&gt; blocks or explicit resource methods.&lt;/p&gt;
&lt;p&gt;Perhaps someday in the distant future, &lt;code class=&quot;language-text&quot;&gt;async&lt;/code&gt; functions will provide the programmer with a mechanism to escape the &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; event horizon, but until that time, a structured concurrency model based on &lt;code class=&quot;language-text&quot;&gt;async/await&lt;/code&gt; will be nothing more than science fiction.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/f41050ac2ccba19fd9dd0c46f90fc75f/2a4de/2023-12-11-await-event-horizon.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Backstage: Unblock Innersource Development with Plugins and Code Owners.]]></title><description><![CDATA[Navigating the challenges of inner-source Backstage portals? Discover how successful adopters harness code owners to streamline contributions and maintain code quality.]]></description><link>https://frontside.com/blog/2023-10-24-innersource-codeowners-backstage/</link><guid isPermaLink="false">https://frontside.com/blog/2023-10-24-innersource-codeowners-backstage/</guid><category><![CDATA[backstage]]></category><category><![CDATA[dx]]></category><category><![CDATA[innersource]]></category><dc:creator><![CDATA[Taras Mankovski]]></dc:creator><pubDate>Tue, 24 Oct 2023 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Backstage empowers platform and product teams within their organization to extend their internal developer portal in an &lt;a href=&quot;https://en.wikipedia.org/wiki/Inner_source&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;inner-source&lt;/a&gt; manner. Keeping up with the growth of an inner-source Backstage portal brings its challenges. In this blog post, we’ll describe how successful Backstage adopters use plugins and the concept of code owners to unblock the development of their Backstage portal.&lt;/p&gt;
&lt;p&gt;Most successful Backstage adopters have a single team responsible for the overall Backstage portal - we’ll call this team the Backstage team. The default project structure for a Backstage portal is a monorepo, meaning that a single repository contains multiple packages. The Backstage team is responsible for the Backstage repository. Developers from other teams make inner-source contributions to the Backstage repository by making pull or merge requests. The Backstage team is responsible for reviewing inner-source contributions to ensure they follow Backstage best practices.&lt;/p&gt;
&lt;p&gt;As the project grows and the number of inner-source contributions increases, so does the number of code reviews that the Backstage team has to review. At some point in every Backstage project, the inner-source contributions exceed the bandwidth the Backstage team has to perform requested code reviews. This situation can be difficult for everyone involved. The Backstage team is responsible for the overall code health of the project - not reviewing code is a bad idea. On the other hand, teams making inner-source contributions have their commitments and timelines that they need to meet.&lt;/p&gt;
&lt;p&gt;Most successful Backstage adopters resolve this conflict by giving inner-source contributors autonomy to review their code while requiring the Backstage team’s review of shared components. Enforcing these boundaries is done by defining areas of ownership within the Backstage repository using code owners. Code owners are configured via a file in a repository that contains a list of directories and teams responsible for the content of each directory. The team responsible for a directory must review a pull request that changes a file in their directory. &lt;a href=&quot;https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GitHub&lt;/a&gt;, &lt;a href=&quot;https://docs.gitlab.com/ee/user/project/codeowners/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GitLab&lt;/a&gt;, and &lt;a href=&quot;https://confluence.atlassian.com/bitbucketserver/code-owners-1296171116.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;BitBucket&lt;/a&gt; support code owners. Here is an example of &lt;a href=&quot;https://github.com/backstage/backstage/blob/master/.github/CODEOWNERS&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;CODEOWNERS&lt;/a&gt; file of the Backstage project itself.&lt;/p&gt;
&lt;p&gt;One of the challenges of adopting code owners is that not every Backstage portal is easy to describe in a CODEOWNERS file. This usually happens because the code in the repository is not organized into Backstage plugins. You can often tell if this is happening if your project’s &lt;em&gt;packages/app&lt;/em&gt; has lots of card components. Some of these card components should be in a directory of the plugin owned by the team that’s maintaining that plugin. For example, a team responsible for CI/CD may have a CI/CD card in the Backstage app instead of importing that component from their plugin in the repository. Refactoring the project to create clear boundaries between the Backstage team’s code and the inner-source contributor’s code is often the first step to introducing code owners to reduce the code review burden on the Backstage team.&lt;/p&gt;
&lt;p&gt;In this blog post, we covered how to use code owners and Backstage plugins to streamline inner-source contribution by giving individual teams the autonomy to review their plugins without giving up the oversight necessary for the Backstage team to support the portal’s development. We hope this blog post is helpful to you on your organization’s journey to a successful Backstage adoption.&lt;/p&gt;
&lt;p&gt;If you&apos;d like to learn more about building Backstage plugins, check out our workshop on &lt;a href=&quot;https://frontside.com/workshops/advanced-backstage-plugin-development&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Advanced Backstage Plugin Development&lt;/a&gt;. If you’d like Frontside developers to work alongside your team to make your Backstage portal successful, check out our &lt;a href=&quot;https://frontside.com/backstage&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Backstage consulting&lt;/a&gt; services.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/daab22b9c585edf70869506e82ff1cdc/2a4de/2023-10-24-innersource-codeowners-backstage.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Backstage: How to fix linting errors without slowing down development]]></title><description><![CDATA[In this guide Min will show you a unique approach to tackling a mountain of linting errors without disrupting delivery]]></description><link>https://frontside.com/blog/2023-10-16-backstage-linting/</link><guid isPermaLink="false">https://frontside.com/blog/2023-10-16-backstage-linting/</guid><category><![CDATA[backstage]]></category><category><![CDATA[dx]]></category><dc:creator><![CDATA[Min Kim]]></dc:creator><pubDate>Mon, 16 Oct 2023 05:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; This blog post outlines the steps in creating a patch for the lint command in Backstage, which organizes errors by package, rules, and overall counts. The author explains how to use the generated lint error data to monitor and manage lint issues efficiently, and emphasizes the importance of tracking progress in reducing lint errors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I recently worked with a team that had the lint command in their Backstage project misconfigured. The result? They ended up amassing an overwhelming number of lint errors - literally hundreds upon hundreds. In fact, the report output by the lint command was so long it would max out the terminal.&lt;/p&gt;
&lt;p&gt;Normally, you would run the lint command in CI for every commit of your pull requests. This practice ensures that any new lint errors introduced by the changes would prevent the pull request from being merged. However, we could not set up this configuration right away; doing so would have brought development to a screeching halt.&lt;/p&gt;
&lt;p&gt;With so many lint errors, it was difficult to pinpoint a starting point. To gain a clearer overview of the types and quantity of lint errors we were dealing with, I made modifications to the Backstage lint command. The modified command produced reports within a structured file system and generated an errors&apos; summary.&lt;/p&gt;
&lt;h1 id=&quot;writing-the-patch&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#writing-the-patch&quot; aria-label=&quot;writing the patch permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Writing the Patch&lt;/h1&gt;
&lt;p&gt;The lint command of the &lt;code class=&quot;language-text&quot;&gt;backstage-cli&lt;/code&gt; package can be found &lt;a href=&quot;https://github.com/backstage/backstage/blob/5578c3de6354bf9ef65aaac50fe73b890b0ad0e5/packages/cli/src/commands/repo/lint.ts&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;. We&apos;re going to write a patch for it to produce the summary file so let&apos;s start by installing &lt;a href=&quot;https://www.npmjs.com/package/patch-package&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;patch-package&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;yarn add patch-package -W&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And modify the root &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; of your Backstage project:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&quot;scripts&quot;: {
&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  &quot;postinstall&quot;: &quot;patch-package&quot;
&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then navigate to the correct lint command file in &lt;code class=&quot;language-text&quot;&gt;./node_modules/@backstage/cli/dist/cjs/lint&lt;/code&gt;. There will be three Javascript files for linting - one for the base lint command, another for the repo lint command, and a third for the versions lint command. The file we&apos;re going to modify is the one designated for the repo lint command.&lt;/p&gt;
&lt;p&gt;Here is a high level view of the patch we&apos;re going to be writing:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;md&quot;&gt;&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;create &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`errors`&lt;/span&gt; directory
create &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`summary`&lt;/span&gt; file

for &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`errors`&lt;/span&gt; of each &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`package`&lt;/span&gt;
  &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; create directory for this specific package
  &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; output lint report of this package to a text file in its corresponding directory
  &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; output the total lint error count of this package and list the rules that are being violated

calculate grand total count of lint errors for the entire project
combine the total count of lint errors by rule for the entire project&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And here&apos;s the actual patch. Typically we would use diff syntax to indicate which lines to be added, but in order to make the code easier to read, we will display the code snippet with Javascript syntax highlighting.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The code snippet below is quite long so you can check out a working demo of a Backstage app with the lint patch &lt;a href=&quot;https://github.com/minkimcello/backstage-lint-demo&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;. The actual patch can be found &lt;a href=&quot;https://github.com/minkimcello/backstage-lint-demo/blob/main/patches/%40backstage%2Bcli%2B0.22.12.patch&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;, and you could also follow along its &lt;a href=&quot;https://github.com/minkimcello/backstage-lint-demo/commits/main&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;commit history&lt;/a&gt; for a more step-by-step approach in creating the patch.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; fs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;fs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; failed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; errors_dir &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;errors&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;existsSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errors_dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rmSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errors_dir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;recursive&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;force&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; errors_summary &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;total_count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;per_package&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; violations_combined &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; relativeDir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resultText &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; resultsList&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; package_dir &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errors_dir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; relativeDir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mkdirSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;package_dir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;recursive&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stripAnsi &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RegExp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=&gt;&amp;lt;]&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; resultTextFormatted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; resultText&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stripAnsi&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;package_dir&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/results.txt&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;relativeDir&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;resultTextFormatted&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;\n&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; violations_count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      resultTextFormatted
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;✘ [0-9]+ problem.*&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;\s*✘\s*&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt; problem.*&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; violations_index &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; resultTextFormatted&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Errors:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; resultTextFormatted&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Errors:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; resultTextFormatted&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Warnings:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; package_violations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    resultTextFormatted&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;violations_index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;line&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; error_details &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;line&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;\d+&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;rule&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; line&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;http.*&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        package_violations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error_details&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        violations_combined&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error_details&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    errors_summary&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;per_package&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; relativeDir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      violations_count&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;package_violations&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; package_violations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;localeCompare&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    errors_summary&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;total_count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; errors_summary&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;total_count &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; violations_count&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;failed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; combined_violations_sorted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; violations_combined
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; already_exists &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; acc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc_item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; acc_item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rule &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;already_exists &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        acc&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;already_exists&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; acc&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;already_exists&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; acc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errors_dir &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/summary.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; errors_summary&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;total_count&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;errors_combined&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; combined_violations_sorted&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;localeCompare&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;per_package&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; errors_summary&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;per_package&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;package&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;localeCompare&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Note:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;ESLint rules are categorized by &lt;code class=&quot;language-text&quot;&gt;warning&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;error&lt;/code&gt;, but we have found that the categorization is highly opinionated and do not necessarily align to its actual severity so for that reason we merged warnings with errors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ESLint offers a wide variety of options for &lt;a href=&quot;https://eslint.org/docs/latest/use/formatters/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;formatters&lt;/a&gt;. I have reviewed each formatter but ultimately the &lt;code class=&quot;language-text&quot;&gt;stylish&lt;/code&gt; (default) formatter met all our needs. Although the sylish output required a bit of formatting, it is the only formatter that provides a relative path of the package location, count of errors per package, and provides source URLs to the violated rules.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;viewing-and-updating-the-summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#viewing-and-updating-the-summary&quot; aria-label=&quot;viewing and updating the summary permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Viewing and Updating the Summary&lt;/h1&gt;
&lt;p&gt;With the patch code shown above, our new lint command will output a summary file that will look something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  errors_combined&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      rule&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://eslint.org/docs/latest/rules/foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      rule&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://eslint.org/docs/latest/rules/bar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  per_package&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      package&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/packages/a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      violations_count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      package_violations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          rule&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://eslint.org/docs/latest/rules/foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ...
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From the generated summary file, we can extract the following information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Total count of lint errors of the entire project&lt;/li&gt;
&lt;li&gt;Total count of lint errors per rule of the entire project&lt;/li&gt;
&lt;li&gt;Total count of lint errors of each package&lt;/li&gt;
&lt;li&gt;Total count of lint errors per rule of each package&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to the summary file, the modified lint command will output each package results to an organized file structure:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;errors/
  |-- summary.json
  |-- packages/
    |-- foo/
      |-- results.txt
    |-- bar/
      |-- results.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ideally from here you would divide and conquer to resolve all of your project&apos;s rule violations. However, if your team lacks the capacity to address these errors right away, the best you could do is try to prevent the problem from growing.&lt;/p&gt;
&lt;p&gt;The best way to keep track of your lint errors would be to keep the &lt;code class=&quot;language-text&quot;&gt;errors&lt;/code&gt; directory up to date in all of your pull requests. You could tell your developers to run the modified lint command, but having to rely on people remembering to do things is rarely a good idea, so you&apos;re left with two options: you could have your CI run the patched lint command and push the updated summaries to your pull requests - which would require your developers to pull their own branch after each commit they push - or you could use &lt;a href=&quot;https://typicode.github.io/husky&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;husky&lt;/code&gt;&lt;/a&gt; to force your local dev environments to run lint for you.&lt;/p&gt;
&lt;p&gt;Follow their &lt;a href=&quot;https://typicode.github.io/husky/getting-started.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Getting Started&lt;/a&gt; guide for installing Husky to your Backstage project and configure a pre-push hook to run lint:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/usr/bin/env sh&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dirname&lt;/span&gt; -- &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$0&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;/_/husky.sh&quot;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; lint
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; status &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;errors/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;You forgot to run &apos;yarn lint&apos;. The lint command was ran for you just now, commit the generated errors directory and git push again&quot;&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Note:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Instead of having husky run before a git push, you could configure it to run every time a developer creates a new commit. Depending on the size of your Backstage project, the lint command could take quite a while. In this guide we opted for the pre-push hook to provide a more pleasant developer experience.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Having the pre-push hook create the commit and subsequently push the updated set of commits in a single step, without requiring developers to initiate an additional git push, would be a convenient approach. But, unfortunatey, the pre-push hook&apos;s mechanism involves calculating the specific commits to push at the moment the hook is activated. As a result, it&apos;s incapable of generating a fresh commit and incorporating that newly created commit within the confines of the hook itself.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;using-the-data&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#using-the-data&quot; aria-label=&quot;using the data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using the Data&lt;/h1&gt;
&lt;p&gt;Now that we have a better overview of our linting errors (and a way to keep it reliably up to date), we need to decide on a method of using that data.&lt;/p&gt;
&lt;p&gt;The simplest approach to check if someone is introducing more lint errors would be to quickly check the git diff of their pull request for the total count in the summary file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;{
&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  count: 3,
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  count: 5,
&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; errors_combined: [...],
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; per_package: [...]
&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, should a developer address a minor rule violation while simultaneously introducing a more severe error, the overall count of lint errors would remain unchanged. To avoid this scenario, you&apos;d need to compare the cumulative count for each specific rule:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;{
&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; count: 3,
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; errors_combined: [
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   {
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;     rule: &quot;https://eslint.org/docs/latest/rules/foo&quot;,
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;      count: 2,
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;      count: 1,
&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   },
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   {
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;     rule: &quot;https://eslint.org/docs/latest/rules/bar&quot;,
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;      count: 1,
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;      count: 2,
&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   }
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; ],
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; per_package: [...],
&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And if you want to ensure that a particular rule isn&apos;t being resolved in one package while a new one is being introduced in another, you would have to take a look at the differences under the &lt;code class=&quot;language-text&quot;&gt;per_package&lt;/code&gt; property and review the git diff of the lint reports of each package.&lt;/p&gt;
&lt;p&gt;Whether you choose to resolve your lint issues rule-by-rule or package-by-package, providing your developers with the capability to access the lint reports for each package in a file format offers significant convenience. This will enable them to search through the entire directy for particular rules and be able to view the details of the lint report without having to run the command.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;If your project has accumulated a long list of lint errors, it&apos;s crucial to strategize an approach for addressing them. Your team might be able to allocate resources to fix those linting errors right away or they may need to chip away at it incrementally. Regardless of the approach, it would be beneficial for your team to be able to track the progress of their efforts - it&apos;s also very satisfying to see the total count number within the summary file decrease in your pull requests.&lt;/p&gt;
&lt;p&gt;Upon successfully reducing your lint errors count to zero, you can promptly remove the patch and reconfigure your CI system to mandate linting as an obligatory check for all pull requests.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/363877537a4c176532fe50374dbfa685/2a4de/2023-10-16-backstage-linting.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Deno is the best tool for maintaining NPM packages]]></title><description><![CDATA[Even if you primarily run your JavaScript in Node, Deno is a fantastic tool for building and distributing packages on NPM (and everywhere else). This article shows how to publish modules to both https://deno.land/x and https://npmjs.org using nothing more than the deno CLI.]]></description><link>https://frontside.com/blog/2023-04-27-deno-is-the-easiest-way-to-author-npm-packages/</link><guid isPermaLink="false">https://frontside.com/blog/2023-04-27-deno-is-the-easiest-way-to-author-npm-packages/</guid><category><![CDATA[Deno]]></category><category><![CDATA[Node]]></category><category><![CDATA[NPM]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 01 May 2023 05:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Even if you primarily run your JavaScript in Node, Deno is a
fantastic tool for building and distributing packages on NPM (and
everywhere else). This article shows how to publish modules to both
&lt;a href=&quot;https://deno.land/x&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://deno.land/x&lt;/a&gt; and &lt;a href=&quot;https://npmjs.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://npmjs.org&lt;/a&gt; using nothing more than
the deno CLI.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;myth&lt;/strong&gt;: You need to use &lt;code class=&quot;language-text&quot;&gt;node&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;npm&lt;/code&gt; , &lt;code class=&quot;language-text&quot;&gt;yarn&lt;/code&gt; , &lt;code class=&quot;language-text&quot;&gt;pnpm&lt;/code&gt; , et al. to
publish packages to &lt;a href=&quot;https://npmjs.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://npmjs.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt;: Deno is perfectly capable of maintaining NPM packages. Studies
conclusively show that maintaining NPM packages with Deno instead of Node is up
to 900% more stress free.&lt;sup id=&quot;fnref-1&quot;&gt;&lt;a href=&quot;#fn-1&quot; class=&quot;footnote-ref&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;As you may or may not know, here at Frontside &lt;a href=&quot;https://frontside.com/blog/2022-12-01-deno-is-blazing-fast-for-humans/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;we’re migrating toward
Deno as our primary tool for JavaScript
development&lt;/a&gt;. That means that we’ll not only use Deno
from the get-go to develop our new JavaScript projects and publish
them to &lt;a href=&quot;https://deno.land/x&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;deno.land&lt;/a&gt;, but over time we’ll also migrate our existing
repositories that use Node as the primary development tool. But that
doesn’t mean we’re rejecting the Node ecosystem – far from it!&lt;/p&gt;
&lt;p&gt;We have a ton of NPM packages &lt;a href=&quot;https://www.npmjs.com/package/@frontside/graphgen&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;already&lt;/a&gt;
&lt;a href=&quot;https://www.npmjs.com/package/effection&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;developed&lt;/a&gt; that &lt;a href=&quot;https://www.npmjs.com/package/@interactors/core&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;we&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/package/@simulacrum/ldap-simulator&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;our
clients&lt;/a&gt; critically &lt;a href=&quot;https://www.npmjs.com/package/@simulacrum/auth0-simulator&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;rely on&lt;/a&gt;. Moving
forward we want all of our new packages to be available to all
JavaScript developers, not just those that happen to run their
programs on Deno. And finally there is our work with
&lt;a href=&quot;https://backstage.io&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Backstage&lt;/a&gt;, which comprises the lion’s share of our
business. It runs on Node and will do so for years to come. In a
nutshell: we have been and are going to continue to be deeply
integrated with the Node community for the long haul.&lt;/p&gt;
&lt;p&gt;But given this, how will we swap over to use Deno without
losing what we have in terms of our existing install base of NPM
packages and Node applications? Simple intuition tells us we should
use Node to develop Node packages and Deno to develop Deno modules:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 470px; flex:1.64;&quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d0302dfd964f61bd8cb8109a96f9dfd1/f96db/dev-publish-silo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 60.9375%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAABVElEQVQoz41SXauCQBDd//+HfPAlBEV9MCIyklAjC7L8Sk2NbOIMbHi7em8Dw+jOzNmzM0ccj0dar9e02+047vd76vueYM/n85fLXNd1XB8EAccwDDknAGjbNjmOQ7quk6Zp9Hg86D+73+8MZpomzWYzms/nfC5kQZ7nVBTFuwFswKIsS6rrmm63G38fDgc6n89cE8cxnU4napqGsixjZ8C2bZn2crnkm2FoRiMiGuAAjqKIgWCr1Yp7cInnefxsASafNnb2rYmx4U8t5LMGS4APz4Xc3DAOAafYT/WJMdpTTx6CTeUFdLfdbnmwvu9TkiR/PlnqsKoq2mw274XIzQv8qKrKOkS0LOurxUBG6IFuFUVh8B9LgSSG1MEEApeDh5wgHTC6Xq+cAyswhewulwtjMCAEbRgG60gCQujQG0YAAOgRda7rUpqmDA6GGBP6FosF51/4UZvRq82xngAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Deno for publishing to Deno ecosystem and Node for publishing to Node ecosystem&quot;
        title=&quot;Deno for publishing to Deno ecosystem and Node for publishing to Node ecosystem&quot;
        src=&quot;/static/d0302dfd964f61bd8cb8109a96f9dfd1/f96db/dev-publish-silo.png&quot;
        srcset=&quot;/static/d0302dfd964f61bd8cb8109a96f9dfd1/72799/dev-publish-silo.png 320w,
/static/d0302dfd964f61bd8cb8109a96f9dfd1/f96db/dev-publish-silo.png 470w&quot;
        sizes=&quot;(max-width: 470px) 100vw, 470px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;But as it turns out, Deno has excellent capabilities to build NPM
packages that we use every day, allowing us to both have our cake and
eat it too. With a slight tweak to how we think about versioning, we
can get all the DX goodness of Deno, but our code is accessible to the
widest possible audience of developers on both deno.land and NPM.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 582px; flex:2.05;&quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/4ee5aab68bb8b5b9400d9b70a36db19d/7c1cd/one-tool-for-both.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 48.75000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABCUlEQVQoz4VSyaqEQAzs//8pT95FBBVxAXdRwX03j8rQg4i+KQi9mJSpSgv6gfM8Oe57IE1TsiyLw3VdvhMy6Vr0RiZR1zX1fc/h+z4ZhkFBEHwIj+MgGfdO7mTIAUkcxzTPMzVNQ6ZpUp7nTFhVFYk3iXfSZVmoKAoax/GbC1LZLchxFpqmka7rhBVFT+i6jsn2fX/08goBM5MkIcdxuHBdVw4Ut23Lf8b6pEDacLVMoF1MCQTbtrEEEEMavMqyjIZhYDmyQwmQ3O0SSEIxyN6Ab9M0fScL89E1BqGqKimKQp7nfST/GsjdK5zLsqQoilhJGIZsGe7Q8eM7/C+uQIe2bfOzwVuE0j81OAm1l1LcbQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Deno for publishing to both Deno and Node package managers&quot;
        title=&quot;Deno for publishing to both Deno and Node package managers&quot;
        src=&quot;/static/4ee5aab68bb8b5b9400d9b70a36db19d/7c1cd/one-tool-for-both.png&quot;
        srcset=&quot;/static/4ee5aab68bb8b5b9400d9b70a36db19d/72799/one-tool-for-both.png 320w,
/static/4ee5aab68bb8b5b9400d9b70a36db19d/7c1cd/one-tool-for-both.png 582w&quot;
        sizes=&quot;(max-width: 582px) 100vw, 582px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The key change in thinking that enables this transition is to move
away from package.json as the final source of truth regarding the
package version and to replace it instead with a humble git tag. Each
released version will have a single tag to represent it, with the
result that package.json goes from being authoritative to just another
build artifact. In short, moving forward we’re following this mantra:
If it doesn’t have a tag, it ain’t a release.&lt;/p&gt;
&lt;h2 id=&quot;tag-once-publish-twice&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#tag-once-publish-twice&quot; aria-label=&quot;tag once publish twice permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tag once. Publish twice.&lt;/h2&gt;
&lt;p&gt;With that mental shift in place, we can implement the following
scheme:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Wait until a release tag is pushed&lt;/li&gt;
&lt;li&gt;Then use it to build and publish to both deno.land/x and npmjs.com&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 582px; flex:1.21;&quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/756ab11c71a5d4b4951ef67258345665/7c1cd/tag-to-publish.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 82.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAABt0lEQVQ4y42T2W7jMAxF/f9/lac8TSZANiCdNAtiZ3PjRd4l6g5IN67duHEJEIJs6ojLlWOtBVuz6hwmOMBELoy6gLI79Me7uCXTie0zpwOrMphgj8r9K7Dq+Afa/wf9sYH232AtDQMbGBlQcsOQvYJ1gFTEsKb8PERy8Mup+fa7kkmDyqQJbh/8DeQJSHkEq4snyFDZvBJR47x3uBSeZBvWl+VPmX+/qM6wUE3JP2XSBzqfz1gul+Lr9foLKKnnESj16+HoQvraB2ULggBJkiBNU+x2OywWC2y327qHTQ9sLR3RYnyCvr09CZnjwjDE4XBAURSI4xjz+Ryn00nA1+u1zrBTpkydYCJPxP2AMoAPcFYPK8sSURQhyzIopSTGmUwmmE6n4LUqy86LscoDqESsFG63q2Q4pASHa79cLthsNnKTMQZaG+gihQp8hGEkpT3sIY92Gzqy4eDVaiUfqqqS1Bmc5xlc14XneZ/7HFrrl89QgJwR9+V7cNv4H8fc73dx3/flgv1+j/F4jNFoJBU2L6V9Q5+3jSthKGuQq+HpHo9HGRj/c169giE4y4fbxbDZbCba/A8sNTHL91F8rwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The 1.0.0 git tag causes a 1.0.0 version on both deno.land and npmjs.org&quot;
        title=&quot;The 1.0.0 git tag causes a 1.0.0 version on both deno.land and npmjs.org&quot;
        src=&quot;/static/756ab11c71a5d4b4951ef67258345665/7c1cd/tag-to-publish.png&quot;
        srcset=&quot;/static/756ab11c71a5d4b4951ef67258345665/72799/tag-to-publish.png 320w,
/static/756ab11c71a5d4b4951ef67258345665/7c1cd/tag-to-publish.png 582w&quot;
        sizes=&quot;(max-width: 582px) 100vw, 582px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We’ll spend the rest of this blog post showing how we will do this for
both platforms.&lt;/p&gt;
&lt;h3 id=&quot;stage-1-the-release-tag&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#stage-1-the-release-tag&quot; aria-label=&quot;stage 1 the release tag permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Stage 1: The release tag&lt;/h3&gt;
&lt;p&gt;For all projects, a release tag is a combination of a “version prefix”
followed by a semantic version number. The most common version prefix
is the letter ‘&quot;v&quot;’, so for example, the semantic version &lt;code class=&quot;language-text&quot;&gt;1.3.5&lt;/code&gt; would be
tagged with &lt;code class=&quot;language-text&quot;&gt;&quot;v1.3.5&quot;&lt;/code&gt; . The beta version &lt;code class=&quot;language-text&quot;&gt;1.6.0-beta.3&lt;/code&gt; would be tagged
with &lt;code class=&quot;language-text&quot;&gt;&quot;v1.6.0-beta.3&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 While &lt;code class=&quot;language-text&quot;&gt;&quot;v&quot;&lt;/code&gt; is the most common version prefix for a single module,
monorepos that contain multiple distributed modules will need to use
a more specific version prefix for tags like &lt;code class=&quot;language-text&quot;&gt;“package-a-v,”&lt;/code&gt; which
will result in release tags like &lt;code class=&quot;language-text&quot;&gt;package-a-v2.0.0&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;stage-2-build-and-publish&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#stage-2-build-and-publish&quot; aria-label=&quot;stage 2 build and publish permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Stage 2: Build and Publish&lt;/h3&gt;
&lt;h4 id=&quot;21-publish-to-denoland&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#21-publish-to-denoland&quot; aria-label=&quot;21 publish to denoland permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.1: Publish to deno.land&lt;/h4&gt;
&lt;p&gt;The &lt;a href=&quot;https://deno.land/x&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;deno.land&lt;/a&gt; build/publish is almost a gimme since it uses git
tags natively. All we have to do is create and register the webhook
for our module and we’re done!  Moving forward, every time
&lt;a href=&quot;https://deno.land/x&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;deno.land&lt;/a&gt; sees a release tag, it will snapshot our source at that
tag and make that version available to users – in perpetuity.&lt;/p&gt;
&lt;h4 id=&quot;22-publish-to-npm&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#22-publish-to-npm&quot; aria-label=&quot;22 publish to npm permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.2: Publish to NPM&lt;/h4&gt;
&lt;p&gt;There’s a little more work to be done getting our package onto NPM,
but with a helping hand from Deno, we can do it in just two steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a script to take a version number and build an NPM package corresponding to it.&lt;/li&gt;
&lt;li&gt;Implement a GitHub workflow to listen for a release tag and then invoke the script from (1) to build the package and publish it to &lt;a href=&quot;https://npmjs.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://npmjs.org&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You might be asking yourself, “How are we going to take a bare ESM
module implemented in &lt;em&gt;TypeScript&lt;/em&gt; and just whip up a script that does
all the things needed to end up with a valid NPM package?”&lt;/p&gt;
&lt;p&gt;The short answer is that the script practically writes itself! That&apos;s
because Deno has our backs with a brilliant little tool called &lt;a href=&quot;https://github.com/denoland/dnt&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;dnt&lt;/a&gt; or
&lt;strong&gt;D&lt;/strong&gt;eno to &lt;strong&gt;N&lt;/strong&gt;ode &lt;strong&gt;T&lt;/strong&gt;ransform. &lt;a href=&quot;https://github.com/denoland/dnt&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;dnt&lt;/a&gt; is downright amazing, and its capabilities
are way undersold. Whether we&apos;re creating a new package that we want
to publish everywhere or we are just migrating repositories from Node
to Deno, &lt;a href=&quot;https://github.com/denoland/dnt&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;dnt&lt;/a&gt; is the secret sauce we use that does all the heavy
lifting for us.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/denoland/dnt&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;dnt&lt;/a&gt; works by taking a single ES module entry point as the input and
generating a feature-complete NPM package containing all its exports
as the output. Along the way, it does all the terrible, tedious,
un-fun, and error-prone things you hate about NPM-ing, such as
maintaining the list of dependencies, compiling typescript, generating
source maps and typings files, creating both commonjs as well as esm
builds, and optionally vendoring any dependencies. The results work
for users consuming the package from TS, JS, on the browser or the
node – including every possible combination of those – and you didn&apos;t
have to think about any of it. Magic!&lt;/p&gt;
&lt;p&gt;I won’t go into all of the details because the &lt;a href=&quot;https://github.com/denoland/dnt#setup&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;dnt setup
instructions&lt;/a&gt; are very thorough, but as an example, look at
our build script at
&lt;a href=&quot;https://github.com/thefrontside/graphgen/blob/v1.8.1/tasks/build-npm.ts&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;tasks/build-npm.ts&lt;/a&gt;
in the &lt;a href=&quot;https://www.npmjs.com/package/@frontside/graphgen&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GraphGen&lt;/a&gt; repository. It can build any version of
our package, but here’s how we would invoke it to build version
&lt;code class=&quot;language-text&quot;&gt;1.0.0&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ deno run -A tasks/build-npm.ts 1.0.0
[dnt] Transforming...
[dnt] Running npm install...
added 6 packages, and audited 7 packages in 1s
found 0 vulnerabilities
[dnt] Building project...
[dnt] Emitting declaration files...
[dnt] Emitting ESM package...
[dnt] Emitting script package...
[dnt] Complete!&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we have the script to build an NPM package from source, the
only remaining step is to add a GitHub workflow to be able to call
it. Here is an &lt;a href=&quot;https://github.com/thefrontside/graphgen/blob/v1/.github/workflows/npm-release.yml&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;example from the GraphGen
repository&lt;/a&gt;. Each
step below is linked to the relevant section in it, but the overall
sequence is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thefrontside/graphgen/blob/v1.8.1/.github/workflows/npm-release.yml#L4-L9&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Listen for any tag that matches our release pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thefrontside/graphgen/blob/v1.8.1/.github/workflows/npm-release.yml#L28-L30&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Capture the target version number based off the tag that triggered the workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thefrontside/graphgen/blob/v1.8.1/.github/workflows/npm-release.yml#L39-L42&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Invoke our dnt script to build an NPM package corresponding to the captured version number&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thefrontside/graphgen/blob/v1.8.1/.github/workflows/npm-release.yml#L44-L48&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Publish the built package to https://npmjs.org&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It’s about as straightforward as a GitHub workflow can get, and with
it in place, we can now publish to two locations – just by creating a
tag. (Trust me, it feels even easier when you try it yourself.)&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Like many JavaScript developers, we have a heavy investment in the
Node ecosystem, which means that we rely on NPM to distribute most of
our code. However, because of Deno’s excellent support for NPM and NPM
distribution, we’ve been able to forge ahead with migrating more and
more of our repositories so they can use Deno as their primary
JavaScript development tool – without sacrificing any of our NPM
audience. Not only is Deno perfectly capable of managing NPM packages,
but from our point of view it is actually a more pleasant experience
than doing so with Node itself.  I hope I’ve shown that if you’re
thinking of giving Deno a spin it isn’t an either/or proposition. You
can happily develop with Deno yet still publish your code to NPM,
where it can be consumed just the way it always was by applications
running on Node. That means that you can adopt it incrementally at a
pace that makes sense for you and your organization.&lt;/p&gt;
&lt;p&gt;So what are you waiting for?&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;Results obtained by conducting a survey of me.&lt;a href=&quot;#fnref-1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded><media:content url="https://frontside.com/static/2c1fe6c214acbe17dd3db9dfd6237dd3/2a4de/2020-07-29-simulator-social.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Seven ways to build a single glass pane with Backstage]]></title><description><![CDATA[Learn strategies for integrating external services into Backstage that improve discoverability and lower congantive load for your users]]></description><link>https://frontside.com/blog/2023-01-22-seven-ways-to-single-glass-pane/</link><guid isPermaLink="false">https://frontside.com/blog/2023-01-22-seven-ways-to-single-glass-pane/</guid><category><![CDATA[backstage]]></category><category><![CDATA[internal-developer-platform]]></category><dc:creator><![CDATA[Taras Mankovski]]></dc:creator><pubDate>Sun, 22 Jan 2023 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The concept of a single glass pane is popular in the Cloud Native ecosystem because it promises to prevent fragmentation within many platforms where users have to interact with different systems to get their work done. Instead of going to one interface to see their builds, another to see their deployments, and yet another to see their logs, a single glass pane would make all of this information available in one place. Increasingly, organizations building platforms see Backstage as the one place to surface everything developers need to be productive.&lt;/p&gt;
&lt;p&gt;Backstage is well positioned to be the single glass pane because it offers a user-friendly architecture designed with this in mind and a suite of plugins that make it easier to integrate with external systems. This blog post will review the Backstage architecture and cover seven separate ways to integrate with external systems to form a single glass pane in Backstage:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Explore Backstage Plugin&lt;/li&gt;
&lt;li&gt;Entity Links&lt;/li&gt;
&lt;li&gt;Custom React Component&lt;/li&gt;
&lt;li&gt;Proxy Backstage Plugin&lt;/li&gt;
&lt;li&gt;Custom Backend Plugin as a Gateway&lt;/li&gt;
&lt;li&gt;Custom Processor&lt;/li&gt;
&lt;li&gt;Custom Entity Provider&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each approach is valid and has both benefits and tradeoffs. Picking the most suitable approach depends on several factors related to security and integration complexity. This list is organized in order of increasing complexity, but as the complexity increases, so does the value you get from the integration. For first-time users, we recommend starting with the least complex integration as it will take the least time and effort while still delivering value. Based on the feedback you get from users, over time you can increase your integration complexity to generate more value.&lt;/p&gt;
&lt;h2 id=&quot;background&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#background&quot; aria-label=&quot;background permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Background&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/static/6c10dbfc92442be6a538e9581e4e0dd4/background-architecture.svg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Client-Server Architecture in Backstage&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Backstage has a fairly traditional client-side architecture with a sprinkle of a framework to make integrating easier.&lt;/p&gt;
&lt;p&gt;A user interacts with the Backstage App via their browser. The Backstage App is a React-based Single Page Application. It consists of Backstage Plugins, each of which is a React Component. Each React Component can retrieve data by calling the Backstage Backend or calling external services directly.&lt;/p&gt;
&lt;p&gt;The Backstage Backend is a Node.js service that uses Express.js to mount Backstage Backend plugins on the &lt;code class=&quot;language-text&quot;&gt;/api&lt;/code&gt; endpoint. There are several core plugins (like Catalog and Proxy plugins) that can be configured via TypeScript or YAML. The Backend plugins call external services via a variety of different protocols. The most common is HTTP, but there is no limit to the services that Backstage Backend plugins can connect to.&lt;/p&gt;
&lt;h2 id=&quot;option-1-explore-backstage-plugin&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#option-1-explore-backstage-plugin&quot; aria-label=&quot;option 1 explore backstage plugin permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Option 1: Explore Backstage Plugin&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/static/04999603bf6c946d58b9ee7b06a6ef7c/option-1.svg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Link to external services using the Explore Backstage Plugin&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;One of the most important goals of a single glass pane approach is to give users a unified view of the internal developer platform. This is achieved by using Backstage as a launch pad into the platform by making links to all external services available in Backstage. In effect, this means gathering and listing links to external services in the Backstage App. This is so simple and obvious that it’s easy to overlook how valuable this is for users. One of our clients had a user who maintained a list of 150 links that they shared with others. Without these links it was challenging to do their work. If you’re considering creating a single glass pane, your organization likely is experiencing a similar challenge.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 977px; flex:1.71;&quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/20263c47c666644373f265819a8270d7/339e3/options-1-backstage-explore-plugin.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 58.4375%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABcSAAAXEgFnn9JSAAAC2UlEQVQoz62QSUxTURSGr8boglcELe2Ctg8LhGAiK2M0xhgXJsaFjS7RRCM4VFEjVQqRJkbjsBDnKOJQbYpaFBAwiMyCE2IES1E0KPV1KYhYS1/vve/+xpoYh40LT/LlnJz/P2fxE4THZYA7ARQCcADMMfnlkwOCxmeAOxCbdIBFHYBw/PD8xffbEtDofGLPz1vtLCmEc58Tex27Uea9iEvN9XA33UHFvRqcqfehrNqLEk85nJUVOHLbg8M+N47VeFFW48WRqqsovnYOBRdPYuOJQwfJDElalWg0QmdIiU2ZOpWlr17Blh8sYoud29iy0l1sYZGdzdudx9LsuWxBkZ0tKd7OsuxrWfa2dSxn5waWs2MDy9yaG5ueuxJkxaJSYjQYbHNkGbLFwmclJYvzXo/ofj0ougJ+0R14KZ4ODYrOgX7R8/aVGBgZFoHgO/FKGRGDH96LQPB9vA8pI3xIGUHbsycuYjQabVarFakmkybpdKLtfgsQ04AYxz+WABA3f/446iImi8WWmZmJ1NRULTlxpii/WQn3i4e48LgF53pacarrLk531GF//TWcaatFw3AAtwafo6K3A6e6G3H2QYPY33CDu2o9aO195CLWudm29PR0WGRZm504UxyvqoSrvxNb7lUiv+4KttdeQsGt81jvPoo91RU41NuOwvYa5Ne7Yb9zGQXVF8SW6yf4Zs8x1D1sdxGDwWBLS0vDHKtV0+l0orGpCRFOMTr+CaqqQhMCTOOIUg6VMox+mcDoxGeEw2FEIhFwTRMq4zwaYwiFlPjDVRkZGcjKyqKSJPHm+83f8+CqqnJKaRxGKf86GeORSZVzSjmn7DctqsZoOKJCUT6UEn1KyhqTyQSz2QxJktDS2hpPOhqNglL6E8Z+8OvuTz0UCh0ger1+qSzLb8xmc39CQoLf5/P5x8bG/MFg0K8oyr/Sr4RCw319fZsIIWQaISSJEJL8H5jxDc1Rfmc/iBsQAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Explore Backstage Plugin shows cards of links in Backstage App&quot;
        title=&quot;Explore Backstage Plugin shows cards of links in Backstage App&quot;
        src=&quot;/static/20263c47c666644373f265819a8270d7/339e3/options-1-backstage-explore-plugin.png&quot;
        srcset=&quot;/static/20263c47c666644373f265819a8270d7/72799/options-1-backstage-explore-plugin.png 320w,
/static/20263c47c666644373f265819a8270d7/6af66/options-1-backstage-explore-plugin.png 640w,
/static/20263c47c666644373f265819a8270d7/339e3/options-1-backstage-explore-plugin.png 977w&quot;
        sizes=&quot;(max-width: 977px) 100vw, 977px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The easiest way to add a list of links to external services is to use the &lt;a href=&quot;https://github.com/backstage/backstage/tree/master/plugins/explore&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Explore Plugin&lt;/a&gt;. It allows you to show a list of cards for each service with a link and organize these links into tabs. Instead of maintaining a list of links in say a Google Doc, developers will conveniently find these links in the Backstage portal.&lt;/p&gt;
&lt;h2 id=&quot;option-2-entity-links&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#option-2-entity-links&quot; aria-label=&quot;option 2 entity links permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Option 2: Entity Links&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/static/19be788593862aef683e3c0232cb85aa/option-2.svg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Eliminate unecessary steps by deep linking to external services using Entity Links&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The Explore Backstage Plugin is helpful when linking to a webpage on an external service, but usually those external services have information related to a specific component in your catalog. For example, if your platform offers Kibana for viewing logs, you can add a link from Explore Backstage Plugin to Kibana’s home page. However, the user will still need to navigate Kibana to find the logs of a specific component. Navigating an external service from its home page is very time-consuming and difficult for users unfamiliar with these systems.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/static/d640532b0e8b9433e50aa3ad8897b1a1/option-2-entity-links-card.svg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Show links in Entity Links Card by editing Entity Links metadata&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;A single glass pane can make it easier for users to navigate to specific pages in external services by providing URLs in the links property of the entity’s metadata. Backstage Catalog will show these links in the Links card on the Entity Page for that component. This technique provides native security protection by allowing the external system to ensure that the user is authenticated when the user arrives at the external system.&lt;/p&gt;
&lt;h2 id=&quot;option-3-custom-react-component&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#option-3-custom-react-component&quot; aria-label=&quot;option 3 custom react component permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Option 3: Custom React Component&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/static/7157b99944406ea8f42b7575c52dbd78/option-3.svg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Give users a preview of content in external system by displaying it using a custom React component&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;An Entity Links Card is helpful when you want to show a simple list of links, but the user has to leave Backstage to see the content behind those links. This can be inefficient because it requires context switching to even simply glance at the information behind a link. We can provide a better user experience by embedding the information from the external service in the catalog’s Entity Page.&lt;/p&gt;
&lt;p&gt;If we use Kibana as an example, instead of deep linking to a page on Kibana, we could fetch the last 100 log messages and display them directly on the Entity Page of a service component. A custom React Component would be responsible for making an API call to Kibana’s API and showing the returned information in the browser.&lt;/p&gt;
&lt;h2 id=&quot;option-4-proxy-backstage-plugin&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#option-4-proxy-backstage-plugin&quot; aria-label=&quot;option 4 proxy backstage plugin permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Option 4: Proxy Backstage Plugin&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/static/f40458a69fa375cea44aabd034596561/option-4.svg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Use Proxy Backend Plugin to authenticate requests using a secret&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Making API requests from a Custom React Component directly an external service is convenient when the user can authenticate directly against the external service and retrieve a token that can be used securely in the browser. Most services do not provide in-browser authentication. In this case, you can use Backstage’s Proxy plugin to call the external service on behalf of the user using a token stored in the Backstage Backend configuration.&lt;/p&gt;
&lt;p&gt;Several Backstage Plugins integrate with external services this way (if you’re looking for inspiration on implementing this kind of integration, check out the &lt;a href=&quot;https://github.com/backstage/backstage/tree/master/plugins/circleci&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;CircleCI Backstage Plugin&lt;/a&gt;). However, be aware that once you configured the proxy plugin using a Backstage specific token, that token can be used by anyone who can call &lt;code class=&quot;language-text&quot;&gt;/api/proxy/&amp;lt;your_service&gt;&lt;/code&gt; endpoint. Take care not to leak any information that should not be available to everyone authenticated with Backstage.&lt;/p&gt;
&lt;h2 id=&quot;custom-backend-plugin-as-a-gateway&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#custom-backend-plugin-as-a-gateway&quot; aria-label=&quot;custom backend plugin as a gateway permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Custom Backend Plugin as a Gateway&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/static/367a525a1426d5d2cfe48a60059669ab/option-5.svg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Combine data from multiple services using a custom Backend Plugin as a gateway&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;There are various reasons why using the Backstage Proxy Plugin method to expose information to the Backstage App might not be enough. If you want to restrict the information users can retrieve from an external service, format the retrieved information, or combine information from multiple sources, a simple proxy is not enough. In these cases you need a custom Backstage plugin that is a gateway to your external service.&lt;/p&gt;
&lt;p&gt;This gateway will respond to requests coming from the front end. It can inspect the requests to see if the user has permission to ask for the information they are requesting, make the necessary calls, format the retrieved response, and return everything as a single response.&lt;/p&gt;
&lt;h2 id=&quot;option-6-custom-processor&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#option-6-custom-processor&quot; aria-label=&quot;option 6 custom processor permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Option 6: Custom Processor&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/static/244e5d6337f8b48b42d76fc372f9e553/option-6.svg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Enrich entity information using Custom Processors&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The five options we described so far all require a browser to access information in the external system. Some external systems (like LDAP) cannot be accessed from the browser. Integrating these kinds of systems while building a single glass pane with Backstage requires a different approach. Since accessing this information is not possible, we can instead use the Catalog’s REST API as a temporary cache. This cache is populated using Backstage Catalog’s processing loop.&lt;/p&gt;
&lt;p&gt;You can configure the processing loop using &lt;a href=&quot;https://backstage.io/docs/features/software-catalog/external-integrations#custom-processors&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Custom Processors&lt;/a&gt;. Custom Processors run on every entity stored in the catalog and can connect to external services to retrieve additional information. The retrieved information can then be used to enrich the entity. However, you must take care to ensure that you do not perform unnecessary asynchronous operations in your Custom Processors because it can eventually slow down the processing speed of other entities.&lt;/p&gt;
&lt;h2 id=&quot;option-7-custom-entity-provider&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#option-7-custom-entity-provider&quot; aria-label=&quot;option 7 custom entity provider permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Option 7: Custom Entity Provider&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/static/761142032c389e24d71e4bf27a05c6da/option-7.svg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Create new entities using a Custom Entity Provider&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;A Custom Processor can enrich existing entities, but where do entities come from in the first place? Entities come from &lt;a href=&quot;https://backstage.io/docs/features/software-catalog/external-integrations#custom-entity-providers&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Entity Providers&lt;/a&gt;. An Entity Provider is an extension point of the Catalog that allows you to commit new entities to the processing loop. Entity Providers extract information from external services, format them as entities and commit them for processing. Entities committed by Entity Providers will execute each Custom Processor relevant to that entity kind.&lt;/p&gt;
&lt;p&gt;Entity Providers follow two ingestion strategies: direct or indirect. Indirect Entity Providers discover URLs of possible sources of entity information and commit discovered URLs as an entity of Location kind. Indirect Entity Providers in Backstage usually discover catalog-info.yaml files and expect Custom Processors to actually read these files and extract entities from them.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this blog post, we covered an overview of the Backstage architecture and seven separate ways to integrate services into Backstage to create a single glass pane. In future blog posts, we’ll expand on techniques you can use to create a single glass pane with a unified data graph of all developer assets.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you would like Frontside to help your team put these techniques into practice, check out our &lt;a href=&quot;/backstage/support/&quot;&gt;Backstage Enterprise Support&lt;/a&gt; and &lt;a href=&quot;/consulting&quot;&gt;consulting&lt;/a&gt; services.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/0f0653bf5910603bc12aec4f2f2691cb/2a4de/seven-ways-to-single-glass-pane.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Dynamic Github Action Jobs]]></title><description><![CDATA[Ever wanted to run parallel jobs in Github Actions with a high level of flexibility? We have, and now you can too!]]></description><link>https://frontside.com/blog/2022-12-12-dynamic-github-action-jobs/</link><guid isPermaLink="false">https://frontside.com/blog/2022-12-12-dynamic-github-action-jobs/</guid><category><![CDATA[github-actions]]></category><category><![CDATA[continuous-delivery]]></category><dc:creator><![CDATA[Jacob Bolda]]></dc:creator><pubDate>Mon, 12 Dec 2022 05:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;dynamic-github-action-jobs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#dynamic-github-action-jobs&quot; aria-label=&quot;dynamic github action jobs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Dynamic Github Action Jobs&lt;/h1&gt;
&lt;p&gt;Github Actions is a CI/CD platform integrated directly with your github.com repository. It is a popular choice to build and test your code within a pull request or on a commit to a branch. It also has many other options for triggering a workflow.&lt;/p&gt;
&lt;p&gt;As a team embraces their Github Action implementation the CI+CD run times can explode. This leads a team towards tuning their implementation and only running the specific jobs that are required. Naturally in this evolution, the need to build workflow context dynamically exponentially increases. Keeping all of the context in a workflow file becomes quite difficult to maintain, and is limited by static values.&lt;/p&gt;
&lt;p&gt;The workflows are written in YAML. The event(s) that triggers the workflow are specified with the &lt;code class=&quot;language-text&quot;&gt;on&lt;/code&gt; parameter. Each workflow file has one or many &lt;code class=&quot;language-text&quot;&gt;jobs&lt;/code&gt; with a named parameter, in this example &lt;code class=&quot;language-text&quot;&gt;run-linters&lt;/code&gt;. Each job has a list of &lt;code class=&quot;language-text&quot;&gt;steps&lt;/code&gt; which is the actions or commands that are run. This job has three steps which install the dependencies and run the lint script.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Lint

&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; push

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;run-linters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Lint
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest

    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v2
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; volta&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;cli/action@v1

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install Node.js dependencies
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm ci

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Run linters
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm run lint&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Within a GitHub action workflow, steps can pass data to the following steps. A step can set output, and the following steps can use that it as a variable. In the example below, the named step, &lt;code class=&quot;language-text&quot;&gt;Get Version&lt;/code&gt;, sets an output value. The &lt;code class=&quot;language-text&quot;&gt;::&lt;/code&gt; syntax is picked up by the Github Action runner when output to stdout, ie. the terminal. More information about this syntax can be found at the &lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;workflow commands&lt;/a&gt; Github docs. The &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt; is also set in this step as &lt;code class=&quot;language-text&quot;&gt;vars&lt;/code&gt;. This is important as this is the variable the following steps use to retrieve the value. The step named &lt;code class=&quot;language-text&quot;&gt;Build&lt;/code&gt; immediately following sets an env using &lt;code class=&quot;language-text&quot;&gt;steps.vars&lt;/code&gt; to refer to the &lt;code class=&quot;language-text&quot;&gt;Get Version&lt;/code&gt; step.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Release to NPM
&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;push&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest

    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; checkout
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v3
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; setup deno
        &lt;span class=&quot;token comment&quot;&gt;# uses: denoland/setup-deno@v1&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; denoland/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;deno@004814556e37c54a2f6e31384c9e18e983317366
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;deno-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; v1.x
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Get Version
        &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; vars
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; echo &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;set&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;output name=version&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;$(echo $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;github.ref_name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; sed &apos;s/^v//&apos;)
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Build
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; deno task build&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;npm $NPM_VERSION
        &lt;span class=&quot;token key atrule&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;NPM_VERSION&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;steps.vars.outputs.version&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Publish
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm publish &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;access=public
        &lt;span class=&quot;token key atrule&quot;&gt;working-directory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./build/npm
        &lt;span class=&quot;token key atrule&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;NODE_AUTH_TOKEN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;secrets.NPM_TOKEN&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This concept also applies to jobs. A step can set an output, and the job can take that step output and set it as a job output. This allows you to do actions dependent on previous job output. &quot;How might this be useful though?&quot;, you ask.&lt;/p&gt;
&lt;p&gt;One way to level up your jobs is a parameter called &lt;code class=&quot;language-text&quot;&gt;strategy&lt;/code&gt;. It allows you to pass an argument, &lt;code class=&quot;language-text&quot;&gt;matrix&lt;/code&gt;, to run multiple jobs in parallel. This takes an array or multiple arrays of arguments which will then be combined into a number of jobs. In the example below, we specify a &lt;code class=&quot;language-text&quot;&gt;matrix&lt;/code&gt; with two sets of values. The &lt;code class=&quot;language-text&quot;&gt;platform&lt;/code&gt; is referenced in the &lt;code class=&quot;language-text&quot;&gt;runs-on&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;node-version&lt;/code&gt; is used by the &lt;code class=&quot;language-text&quot;&gt;volta-cli/action&lt;/code&gt;. This specific array will produce a job set of consisting of six jobs run in parallel, e.g. &lt;code class=&quot;language-text&quot;&gt;ubuntu-latest&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;nodejs@16&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Test
&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;pull_request&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; matrix.platform &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; matrix.platform &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; test node@$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; matrix.node&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;version &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;fail-fast&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; windows&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;14&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;16&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;18&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;rs/toolchain@v1
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;toolchain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.63&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v2
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn install
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn build
      &lt;span class=&quot;token comment&quot;&gt;# specifically running this after build&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;# using the n-api, the default node on github actions&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;# should build a .node that works in any of the node&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;# versions that we have specified in the matrix&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; volta&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;cli/action@v1
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; matrix.node&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;version &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;yarn-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.22.19
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As an example in a monorepo, you may have ten different packages. You can give it an array which includes a list of each of the packages and an array of nodejs versions. The jobs that would be then created based on these two matrix inputs and would produce 20 jobs, 10 services by the two nodejs versions. It enables parallel processing and may increase the speed of your CI runs. This can also increase the transparency as you see the separate jobs in the status section of a pull request.&lt;/p&gt;
&lt;p&gt;![[dynamic-github-action-jobs-status-checks.png]]&lt;/p&gt;
&lt;p&gt;The downside of the static array of values is having multiple sources of truth. If you have multiple workflows, this matrix needs to be replicated across each and kept in sync. The matrix accepts an argument called &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; which allows you to specify additional jobs over and above the jobs derived from the matrix arrays or additional metadata each job(s).&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrixinclude&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Github Actions documentation&lt;/a&gt; has an advanced example. This following example would add a &lt;code class=&quot;language-text&quot;&gt;matrix.color&lt;/code&gt; to each job with a value of &lt;code class=&quot;language-text&quot;&gt;green&lt;/code&gt;. There would be four total jobs each with a &lt;code class=&quot;language-text&quot;&gt;{ fruit, animal, color }&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;fruit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;apple&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pear&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cat&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dog&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; green&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A &lt;code class=&quot;language-text&quot;&gt;strategy&lt;/code&gt; is able to specify only an &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt;. The following example create two jobs, each with &lt;code class=&quot;language-text&quot;&gt;{ color, fruit }&lt;/code&gt;. The first job would be &lt;code class=&quot;language-text&quot;&gt;{ color: &quot;green&quot;, fruit: &quot;apple&quot; }&lt;/code&gt; and the second job would be &lt;code class=&quot;language-text&quot;&gt;{ color: &quot;blue&quot;, fruit: &quot;pear&quot; }&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; green
        &lt;span class=&quot;token key atrule&quot;&gt;fruit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; apple
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue
        &lt;span class=&quot;token key atrule&quot;&gt;fruit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pear&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is where a few built-in functions within GitHub Actions can become immensely useful using output passed between jobs and a function to convert that output into a matrix value. We can use this to our advantage; compute the array of jobs ourselves and pass it to this &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; argument.&lt;/p&gt;
&lt;p&gt;Through the &lt;a href=&quot;https://docs.github.com/en/actions/learn-github-actions/expressions#tojson&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;toJSON&lt;/code&gt; function&lt;/a&gt;, the &lt;code class=&quot;language-text&quot;&gt;matrix&lt;/code&gt; argument can receive a stringified object. The &lt;code class=&quot;language-text&quot;&gt;toJSON&lt;/code&gt; function takes a string and outputs a value that the job is able to use. This allows us to programmatically, in a previous job, determine the matrix of jobs to run.&lt;/p&gt;
&lt;p&gt;It is particularly powerful in monorepos where you can use static analysis to determine which code paths have changed, and only test those. With the monorepo helper Nx, for example, we can run a function which describes the code that has been affected by a change in pull request, nx affected. Using this output, we can parse it into an object and pass it into our matrix.&lt;/p&gt;
&lt;p&gt;The object can be created however it is most convenient, as long as it can be output to the terminal. For an example using nodejs, we would log out the output of a &lt;code class=&quot;language-text&quot;&gt;JSON.stringify()&lt;/code&gt;. The script shown below, when run, would create three jobs with a &lt;code class=&quot;language-text&quot;&gt;matrix.package&lt;/code&gt; value being passed into each.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; matrixList &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;package-a&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;package-b&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;package-c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;pkg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; pkg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; includeStatement &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; matrixList &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;::set-output name=matrix::&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;includeStatement&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We use this script in the following workflow. It has two jobs: &lt;code class=&quot;language-text&quot;&gt;generate-matrix&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;test&lt;/code&gt;. In the &lt;code class=&quot;language-text&quot;&gt;generate-matrix&lt;/code&gt; job, we run the &lt;code class=&quot;language-text&quot;&gt;matrix-script.js&lt;/code&gt; shown above which logs the string to &lt;code class=&quot;language-text&quot;&gt;stdout&lt;/code&gt;. The &lt;code class=&quot;language-text&quot;&gt;::set-output name=matrix::&lt;/code&gt; is a special function within Github Actions which tells the runner to set this as an output value for this step. We assign it to a variable by setting the &lt;code class=&quot;language-text&quot;&gt;id: set-matrix&lt;/code&gt;. Finally, we can set it as an output for the whole job by specifying it in &lt;code class=&quot;language-text&quot;&gt;outputs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The following job can use the output from the previous job by setting the job ID in the &lt;code class=&quot;language-text&quot;&gt;needs&lt;/code&gt; property. The &lt;code class=&quot;language-text&quot;&gt;test&lt;/code&gt; job uses &lt;code class=&quot;language-text&quot;&gt;needs: [generate-matrix]&lt;/code&gt; and can use the values via the &lt;code class=&quot;language-text&quot;&gt;needs&lt;/code&gt; elsewhere in the job. It has a conditional which determines if the job should run or skip with &lt;code class=&quot;language-text&quot;&gt;if: needs.generate-matrix.outputs.matrix != &apos;&apos;&lt;/code&gt;. It is referenced with the &lt;code class=&quot;language-text&quot;&gt;needs.&amp;lt;job id&gt;.outputs.&amp;lt;property from job id outputs&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;generate-matrix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Generate Job Matrix
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; steps.set&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;matrix.outputs.matrix &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v3
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; node ./matrix&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;script.js
        &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; set&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;matrix

  &lt;span class=&quot;token key atrule&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Check $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; matrix.nickname &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; needs.generate&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;matrix.outputs.matrix &lt;span class=&quot;token tag&quot;&gt;!=&lt;/span&gt; &apos;&apos;
    &lt;span class=&quot;token key atrule&quot;&gt;needs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;generate&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;matrix&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;fail-fast&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;max-parallel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;fromJSON(needs.generate&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;matrix.outputs.matrix)&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v3
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn workspace $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; matrix.package &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Building on this functionality, we can level up our script, &lt;code class=&quot;language-text&quot;&gt;matrix-script.js&lt;/code&gt; with static code analysis. As we mentioned previously, &lt;code class=&quot;language-text&quot;&gt;Nx&lt;/code&gt; has a command called &lt;code class=&quot;language-text&quot;&gt;nx affected&lt;/code&gt;. We can wire this into our script similar to the following. This would return a list of &lt;code class=&quot;language-text&quot;&gt;affected&lt;/code&gt; packages. (Note this is a generator function expected to run within an &lt;a href=&quot;https://frontside.com/effection&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;effection&lt;/code&gt; context&lt;/a&gt;, so you may not be able to copy and paste this directly.) This would give you a dynamic array that can be used in the script rather than directly hardcoding the array as &lt;code class=&quot;language-text&quot;&gt;[&apos;package-a&apos;, &apos;package-b&apos;, &apos;package-c&apos;]&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;affectedList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; nxBase &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NX_BASE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;main&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; nxHead &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NX_HEAD&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;HEAD&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// if you want to check it locally with uncommitted changes&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// const command = `nx affected:libs --plain --uncommitted`;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; command &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;nx affected:libs --plain --base=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;nxBase&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; --head=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;nxHead&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; stdout&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stderr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; code &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;command&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;..&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stderr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;exited with code &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;code&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; affected &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stdout
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;,&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; affected&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the additional context required to fuel &lt;code class=&quot;language-text&quot;&gt;nx affected&lt;/code&gt;, the following workflow would create the extra context via &lt;code class=&quot;language-text&quot;&gt;nwql/nx-set-shas&lt;/code&gt;, derive the &lt;code class=&quot;language-text&quot;&gt;nx affected&lt;/code&gt;, pipe the generated matrix into &lt;code class=&quot;language-text&quot;&gt;test&lt;/code&gt; job, create a job for each affected package and run the test for the package. The nx command &lt;code class=&quot;language-text&quot;&gt;yarn nx run ${{ matrix.package}}:test&lt;/code&gt; will have the &lt;code class=&quot;language-text&quot;&gt;${{ matrix.package }}&lt;/code&gt; populated with the value passed into each job. The command run for the job with &lt;code class=&quot;language-text&quot;&gt;{ package: &apos;package-a&apos; }&lt;/code&gt; would in turn be &lt;code class=&quot;language-text&quot;&gt;yarn nx run package-a:test&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;generate-matrix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Generate Job Matrix
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; steps.set&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;matrix.outputs.matrix &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;nxBase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; steps.nx&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;sha.outputs.base &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;nxHead&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; steps.nx&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;sha.outputs.head &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v3
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;# We need to fetch all branches and commits so that Nx affected has a base to compare against.&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;fetch-depth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Derive appropriate SHAs for base and head for `nx affected` commands
        &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; nx&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;sha
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; nrwl/nx&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;set&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;shas@v2
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; node ./matrix&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;script.js
        &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; set&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;matrix

  &lt;span class=&quot;token key atrule&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Check $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; matrix.nickname &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; needs.generate&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;matrix.outputs.matrix &lt;span class=&quot;token tag&quot;&gt;!=&lt;/span&gt; &apos;&apos;
    &lt;span class=&quot;token key atrule&quot;&gt;needs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;generate&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;matrix&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;fail-fast&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;max-parallel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;fromJSON(needs.generate&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;matrix.outputs.matrix)&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v2
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; volta&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;cli/action@v1
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn nx run $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; matrix.package &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this workflow and creating our own array of jobs, it enables tight control of what and when CI runs. This can save on time and build minutes, as well as increase transparency through the parallel CI runs. With a set of workflows that builds, tests, creates docker files and helm charts and finally deploys, tuning the CI+CD is required to merge more than a single pull request or two a day.&lt;/p&gt;
&lt;p&gt;We can use static code analysis to drive a CI setup that only builds and tests the code paths that have changed. It provides the most feedback in the shortest amount of time. From this, we can enable CD to deploy only the services that have changed into a QA environment and save this metadata for production deploys.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Want to learn more? We have a great community in &lt;a href=&quot;https://discord.gg/9xfdDYthpF&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Discord&lt;/a&gt;; come and say hello! We like to help and discuss all kinds of tech and code topics.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/34d3b4cfaf13078c38dafa972164d82f/2a4de/2022-08-22-dynamic-github-actions-jobs.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Ingestion tests in Backstage Part 2: Safely refactoring an LDAP integration]]></title><description><![CDATA[To test whether the Backstage is setting up the Catalog properly, you must start a Backstage server, wait for a while, and assert. This feat is easier said than done. Here is part 2 in which Charles will guide you through it in this article.]]></description><link>https://frontside.com/blog/2022-12-05-ingestion-testing-in-backstage-part-2/</link><guid isPermaLink="false">https://frontside.com/blog/2022-12-05-ingestion-testing-in-backstage-part-2/</guid><category><![CDATA[backstage]]></category><category><![CDATA[testing]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 05 Dec 2022 05:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Heads up: This is the second part in a series on how to achieve real confidence in your Backstage Ingestion via testing. We’ll be relying on the techniques introduced in the first blog post to test a non-trivial external application. What follows may not make much sense without a grasp of those techniques, so I highly recommend starting with &lt;a href=&quot;../2022-03-24-testing-backstage-catalog-ingestors&quot;&gt;Part 1&lt;/a&gt; first and then coming back.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In our article on testing your Backstage catalog ingestion, we discussed the technique of using the concepts of structured concurrency and eventual consistency to test a backstage server solely via its external interfaces: as an operating system process and an http server. The payoff for organizing your tests that way is that they end up at the ideal sweet spot intersection: replicating how the server actually runs and behaves in production while still maintaining desirable test properties such as speed, isolation, and repeatability.&lt;/p&gt;
&lt;p&gt;Rather than reaching into the guts of your ingestion code and testing the inputs and outputs of individual viscera, this approach instead embeds your server as a single holistic unit directly into your test cases. This means that not only can you test anything in your server using the exact same test harness, but also you are free to re-organize the internals of the server as you see fit, and your test cases need never change.&lt;/p&gt;
&lt;p&gt;In this article, we’ll demonstrate why this is so important by refactoring in order to upgrade a Backstage server from a legacy LDAP org processor to a new LDAP entity provider – all without changing a single line of the test case.&lt;/p&gt;
&lt;p&gt;If you recall, the fundamental strategy of the basic ingestion test case for locations defined in a fixed YAML was as straightforward as we dared to make it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Start a Backstage server;&lt;/li&gt;
&lt;li&gt;Let it run for a while; and&lt;/li&gt;
&lt;li&gt;Check to make sure that the entities we expect were ingested.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We’ll use the exact same strategy as before with the only difference being that instead of checking that service components are ingested from our YAML files, we’ll check that our user entities are properly ingested from our LDAP server.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2022-ingestion-testing-in-backstage-part-2/test-architecture.svg&quot; title=&quot;Backstage Client talks to Backstage Server, which talks to LDAP Simulator&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Testing Architecture featuring a simulated LDAP server&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Using a simulator as a test double means that we get all the benefits of isolation and repeatability when using a mock or stub, but without having to sacrifice any of the confidence in the viability of our test because it’s actually using 100% of the production code with no additives or substitutes.&lt;/p&gt;
&lt;p&gt;In fact, we’ve developed an LDAP simulator just for this purpose, which we can use inside of our test case. With this tool in hand, we can start up a simulated LDAP server instantaneously – right before we start our Backstage server – so the only thing that is different is that our test goes from this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createBackstage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;to this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createLDAPServer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createBackstage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That was easy! Now that we have our very own LDAP server embedded in our test case, all we have to do is seed it with user and group data, and then use our convergent assertions to confirm that those records were ingested in the catalog:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; catalog&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CatalogApi&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createLDAPServer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    users&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        cn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cowboyd&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uid&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cowboyd&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Charles Lowell&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uuid&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;xyz123-cowboyd&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        mail&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cowboyd@example.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        password&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;password&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        avatar&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;https://avatars.dicebear.com/api/open-peeps/cowboyd.svg&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  catalog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createBackstage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/// other catalog tests&lt;/span&gt;

it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eventually&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ingests users from LDAP into the catalog&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; catalog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEntityByRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;user:cowboyd&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toMatchObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    spec&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      profile&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cowboyd@example.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        picture&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;https://avatars.dicebear.com/api/open-peeps/cowboyd.svg&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        displayName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Charles Lowell&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;upgrade-with-confidence&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#upgrade-with-confidence&quot; aria-label=&quot;upgrade with confidence permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Upgrade with confidence&lt;/h3&gt;
&lt;p&gt;One of the main points I’ve been stressing in these articles is that this style of test only ever uses the public API of Backstage, which means that no matter what is going on under the covers, our test case verifies the most important aspect of its behavior: what it will do when you actually use it. And because our test only uses the “outside” of Backstage, it means that we have a free hand to change whatever is inside without worrying that we might break our tests.&lt;/p&gt;
&lt;p&gt;In the example repository, our initial LDAP integration used a processor combined with a custom user transformer in order to map the fields from our LDAP user entry into a Backstage user entity. Here is our transformer that maps the name and avatar fields from our entry into the spec.profile.displayName and spec.profile.picture fields of our user entity:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;userTransformer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vendor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;defaultUserTransformer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vendor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    spec&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      profile&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        displayName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vendor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;decodeStringAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        picture&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vendor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;decodeStringAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;avatar&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But this is the &lt;a href=&quot;https://backstage.io/docs/integrations/ldap/org#using-a-processor-instead-of-a-provider&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;old way&lt;/a&gt;. The new way is to use an entity provider, and a simple set of field mappings in your app-config.yaml. We want the transformation to look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; name
    &lt;span class=&quot;token key atrule&quot;&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; avatar&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s start with a passing test suite:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;PASS  src/catalog.test.ts (18.847 s)
  catalog ingestion
    ✓ can connect to the catalog (5348 ms)
    ✓ ingests the artist lookup component  (4469 ms)
    ✓ ingests the example user from ldap into the catalog (4298 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        19.208 s
Ran all test suites.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we first migrate our catalog to use the entity provider instead of the processor, but don’t add the field mappings yet, our test suite automatically fails:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;FAIL  src/catalog.test.ts (21.039 s)
  catalog ingestion
    ✓ can connect to the catalog (4318 ms)
    ✓ ingests the artist lookup component  (4700 ms)
    ✕ ingests the example user from ldap into the catalog (9063 ms)

  ● catalog ingestion › ingests the example user from ldap into the catalog

    expect(received).toMatchObject(expected)

    - Expected  - 2
    + Received  + 1

      Object {
        &quot;spec&quot;: Object {
          &quot;profile&quot;: Object {
    -       &quot;displayName&quot;: &quot;Charles Lowell&quot;,
    +       &quot;displayName&quot;: &quot;cowboyd&quot;,
            &quot;email&quot;: &quot;cowboyd@example.com&quot;,
    -       &quot;picture&quot;: &quot;https://avatars.dicebear.com/api/open-peeps/cowboyd.svg&quot;,
          },
        },
      }

      45 |   it.eventually(&apos;ingests the example user from ldap into the catalog&apos;, function*() {
      46 |     let user = yield catalog.getEntityByRef(&apos;user:cowboyd&apos;)
    &gt; 47 |     expect(user).toMatchObject({
         |                  ^
      48 |       spec: {
      49 |         profile: {
      50 |           email: &apos;cowboyd@example.com&apos;,

      at Object.&amp;lt;anonymous&gt; (catalog.test.ts:47:18)
      at produce (../../../node_modules/@effection/core/src/future.ts:115:15)
      at Promise.race.then.produce.state (../../../node_modules/@effection/core/src/controller/promise-controller.ts:11:9)
          at runMicrotasks (&amp;lt;anonymous&gt;)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 2 passed, 3 total
Snapshots:   0 total
Time:        21.514 s
Ran all test suites.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not only has it detected that something is amiss, but it has also told us exactly what went wrong. The record has been found, but the spec.profile.displayName and spec.profile.picture fields are no longer being populated correctly. However, if we add those mappings to our app-config.yaml the tests re-run and pass again:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;PASS  src/catalog.test.ts (17.195 s)
  catalog ingestion
    ✓ can connect to the catalog (4962 ms)
    ✓ ingests the artist lookup component  (5102 ms)
    ✓ ingests the example user from ldap into the catalog (4223 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        17.645 s, estimated 22 s
Ran all test suites.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We completely changed the mechanism for ingestion of users from LDAP, and yet our tests did not change by a single line. Don’t believe me? &lt;a href=&quot;https://github.com/cowboyd/backstage-integration-testing-example/compare/ldap...ldap-entity-provider&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Check the diff!&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;focus-on-what-matters&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#focus-on-what-matters&quot; aria-label=&quot;focus on what matters permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Focus on what matters&lt;/h3&gt;
&lt;p&gt;We know tests are important, but they can be so difficult to set up and such a nightmare to evolve along with your codebase that most of the time we don’t even bother. But a workable and efficient solution is to imagine the simplest, most durable test you can, and then put the work in to attack the complexity – separating that from being able to express that simple, durable test in code. In the case of ingestion, the simplest thing that could possibly work is to turn it all on and see what happens, and take a “wait-and-see” attitude toward complexity.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/55b0aa4df66c229d21b92013d072543c/2a4de/2022-04-26-ingestion-test-in-backstage-part-2.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Deno is "blazing fast" for humans]]></title><description><![CDATA[Every systems claims to be "blazing fast", but does that actually mean faster development?]]></description><link>https://frontside.com/blog/2022-12-01-deno-is-blazing-fast-for-humans/</link><guid isPermaLink="false">https://frontside.com/blog/2022-12-01-deno-is-blazing-fast-for-humans/</guid><category><![CDATA[javascript]]></category><category><![CDATA[deno]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Thu, 01 Dec 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Are you old enough to remember back in the day when Node.js was the new kid on the block? I am. I remember the excitement of having a dead-simple way to run JavaScript on the server. I remember being intrigued by the prospect of running the same code run on both the frontend and the backend. But above all else, I remember the promise that it was going to be fast. Like, really, really fast. And it was…. sort of.&lt;/p&gt;
&lt;p&gt;The code ran quickly enough. The separation of every single I/O operation via callbacks meant absolutely no wait time was introduced into a program without you explicitly asking for it, and compared with other prominent scripting languages of the day like Ruby and Python it was quite the coup. I still recall the first time I ran a node-based CLI and being impressed by the complete absence of any gap between when the command was invoked and when it produced its first output. Here was a tool which not only felt familiar to JavaScript developers, but which also let you build programs that felt really responsive. The response time was so far below the threshold of perception that it soon became customary (to the point of parody) to label every new application or library written for Node.js as “blazing fast.”&lt;/p&gt;
&lt;p&gt;But a funny thing happened over time as the ecosystem of “blazing fast” applications ballooned in size: while they ran faster than ever, individually they each became slower and more painful to write and maintain. I often wonder what my 2010 self would say to me if he learned about how regularly I would spend 30 minutes of my day just waiting for a JavaScript codebase to build – sometimes multiple times a day! What would his face convey as I explained to him all of the daily “necessities” that gradually and relentlessly chipped away at his joy?&lt;/p&gt;
&lt;p&gt;“yarn install,&quot; I imagine myself saying to him a tad defensively. “It’s absolutely critical to maintain dependencies.  You can’t live without it.”&lt;/p&gt;
&lt;p&gt;I see him staring back at me impassively, saying nothing.&lt;/p&gt;
&lt;p&gt;“TypeScript,” I offer. “JSX too. You don’t know about either of these yet, but trust me, they are incredible time-savers.”&lt;/p&gt;
&lt;p&gt;Silence. I’m beginning to feel uneasy.&lt;/p&gt;
&lt;p&gt;“Babel?” I say almost sheepishly. “Webpack?”&lt;/p&gt;
&lt;p&gt;His face is impassive, save for the single tear that slowly slides down the side of one cheek.&lt;/p&gt;
&lt;p&gt;“ESLint!” I shout. “Prettier!” I’m aware of the shrill edge creeping into my voice, but I can’t help it. I’m beginning to feel desperate.&lt;/p&gt;
&lt;p&gt;“Thirty minutes?” he whispers, his voice nearly inaudible.&lt;/p&gt;
&lt;p&gt;“Relay Compiler!” I plead. “Look, I know that Jest has its own completely parallel build toolchain that is unrelated to production, but it’s a really handy, popular tool!”&lt;/p&gt;
&lt;p&gt;He glances down at his watch, shakes his head, and turns away from me.&lt;/p&gt;
&lt;p&gt;“Why can’t he see it?” I think to myself. Of course, each little tool we use in our projects these days comes with its own small overhead, and yes, they come with their own configuration mechanisms, and no, they don’t always play nice with each other and cause you to lose a day here and there untangling them from each other, but surely he can see the value in them can’t he?&lt;/p&gt;
&lt;p&gt;Unfortunately, the dispute between us can never really be resolved to either of our satisfaction and the reason why is that we’re both right.&lt;/p&gt;
&lt;p&gt;From my perspective in 2022, I can plainly see all the clear wins that things like TypeScript and JSX offer, not to mention modern comforts like an established testing framework that Jest provides. But just as relevant to that class of time savers is the feeling of fleetness that Node imbued. And that&apos;s his point: how many hours – no, days – have I spent waiting for the code to build? I’ll never get those back.&lt;/p&gt;
&lt;p&gt;Luckily now there’s a tool that both of us can get behind. Deno brings together the best parts of 2010 and 2022 and fuses them together for an outstanding developer experience without compromises. You have all the power and speed of a modern JavaScript runtime but none of the time-intensive install and build steps that you have to intermittently run during every portion of the development process. With Deno, you just get the code and run it.&lt;/p&gt;
&lt;p&gt;Why and how is that possible? Because Deno is more than a JavaScript runtime. It’s a fully formed software development kit that contains all the tools you need baked right in.&lt;/p&gt;
&lt;p&gt;Want to just run a JavaScript file? Easy.&lt;/p&gt;
&lt;p&gt;Or perhaps TypeScript? Same.&lt;/p&gt;
&lt;p&gt;Linter? Formatter? Yup.&lt;/p&gt;
&lt;p&gt;Bundler? Task Runner? Test Framework? Language Server? Check. Check. Check…. and let’s see… yup, check.&lt;/p&gt;
&lt;p&gt;It even comes pre-rolled with a cross-compiler to turn scripts into platform binaries, and there’s more pieces of the SDK puzzle being added to it every day.&lt;/p&gt;
&lt;p&gt;As a result of all the wins baked in, working on a Deno codebase feels nearly frictionless. The time between when you clone a repository to when you’re running tests or even starting it up is barely noticeable.&lt;/p&gt;
&lt;p&gt;So yeah, it’s time to resurrect the cliché – only this time it’s really true. Deno &lt;em&gt;is&lt;/em&gt; blazing fast. It runs code quickly to be sure, but even more important than the rate at which it can shove bytes through a CPU is how Deno optimizes &lt;em&gt;my&lt;/em&gt; time – and I appreciate that more than anything. That’s what I mean when I say that Deno is blazing fast and why it’s quickly become my tool of choice for JavaScript development.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/6338b121b8c5fea12925f33ea1533ab1/2a4de/2022-12-01-deno-is-blazing-fast-for-humans.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[What Is Spotify Backstage: a developer portal overview]]></title><description><![CDATA[What can Backstage do for your team? In this post, we are going to discuss how backstage can improve your organization.]]></description><link>https://frontside.com/blog/2022-05-16-what-is-spotify-backstage/</link><guid isPermaLink="false">https://frontside.com/blog/2022-05-16-what-is-spotify-backstage/</guid><category><![CDATA[backstage]]></category><dc:creator><![CDATA[Javier Lainfiesta]]></dc:creator><pubDate>Tue, 17 May 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Backstage is a powerful open-source developer portal platform. What started as an internal tool for the Spotify developing team has become a versatile option for creating and managing developer portal ecosystems. Backstage stands out for its flexibility and high degree of customization. Below I want to share some features Backstage offers.&lt;/p&gt;
&lt;h2 id=&quot;what-can-backstage-do-for-you-and-your-team&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-can-backstage-do-for-you-and-your-team&quot; aria-label=&quot;what can backstage do for you and your team permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What can Backstage do for you and your team?&lt;/h2&gt;
&lt;p&gt;Let&apos;s do a short exercise. Imagine you have several teams distributed around the world working on different aspects of an application. Some are working on the mobile app, others on a web app, and many people are working on microservices. They all overlap in one way or another. The web app might need a GraphQL API provided by another team. The GraphQL API team might need to consume microservices. Teams maintaining a microservice might need to access data. Each of these teams works autonomously but they rely on the software created by others in the organization.&lt;/p&gt;
&lt;p&gt;The autonomy allows developers to move fast, but it also brings unexpected problems. Over time individual services diverge and critical information gets lost. Developers wind up spending more time gathering information and finding resources than actually coding.&lt;/p&gt;
&lt;p&gt;The team at Spotify calls this phenomenon the Speed Paradox. In simple terms, the faster you grow, the more fragmented your software ecosystem becomes. And that slows you down again.&lt;/p&gt;
&lt;p&gt;That brings us to the main problem Backstage solves for many organizations: centralizing services and standardizing your tooling. It may sound counterintuitive, but uniformity breeds creativity. Having an integrated development environment from end to end gives your developers the freedom and resources they need to solve any complex problem fast.&lt;/p&gt;
&lt;p&gt;Backstage helps teams by giving a uniform overview of all the services, libraries, websites, ML models, etcetera. This way, a team can manage all the software they own, including deployments, data pipelines, and libraries. The platform also makes it easier to locate info related to ownership and dependencies by other teams.&lt;/p&gt;
&lt;h2 id=&quot;technical-speaking-what-can-we-find-in-backstage&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#technical-speaking-what-can-we-find-in-backstage&quot; aria-label=&quot;technical speaking what can we find in backstage permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Technical speaking, what can we find in Backstage?&lt;/h2&gt;
&lt;p&gt;By now, the skeptic in you might be thinking: “All of the above sounds great, but how exactly does Backstage accomplish all of that?”&lt;/p&gt;
&lt;p&gt;Through Backstage’s frontend application, team members can find not only the information they’re looking for but discover unknown resources and scaffolding for new projects. The core Backstage features include Software Catalog, Software Templates, Search, TechDocs, and Plugins. In that sense, the most fundamental use case of Backstage is information retrieval and accessing resources like documentation, ownership information, and status of running services. Let’s take a brief look at each feature.&lt;/p&gt;
&lt;h3 id=&quot;software-catalog&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#software-catalog&quot; aria-label=&quot;software catalog permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Software Catalog&lt;/h3&gt;
&lt;p&gt;This feature helps your team find the metadata and ownership information of all the software they are working on. The catalog is based on metadata YAML files. It offers one place to view all the external tools to manage your code by tracking third-party software.&lt;/p&gt;
&lt;h3 id=&quot;software-templates&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#software-templates&quot; aria-label=&quot;software templates permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Software Templates&lt;/h3&gt;
&lt;p&gt;This powerful tool lets your organization create projects from a predefined reference template with forms that the team can fill out. The templates help standardize your tooling when the team starts coding a new project. Developers can use it for onboarding guides and good practices, and organizations can push their templates to GitHub or GitLab.&lt;/p&gt;
&lt;h3 id=&quot;search&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#search&quot; aria-label=&quot;search permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Search&lt;/h3&gt;
&lt;p&gt;The search bar in Backstage was designed to reduce the time teams spend looking for context and switching between sources of information. Backstage Search lets you customize the search tool for your specific needs with modular backend and frontend components. You can integrate your plugins, wiki, or even Stack Overflow, so all the results appear on the same screen.&lt;/p&gt;
&lt;h3 id=&quot;techdocs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#techdocs&quot; aria-label=&quot;techdocs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;TechDocs&lt;/h3&gt;
&lt;p&gt;Creating technical documentation is easy with this Backstage feature. TechDocs allow collocating documentation with the project source code to make it convenient for both developers working on the project and consumers of the project. This feature significantly reduces the time looking for documentation so it can be used.&lt;/p&gt;
&lt;h3 id=&quot;plugins&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#plugins&quot; aria-label=&quot;plugins permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Plugins&lt;/h3&gt;
&lt;p&gt;The best way to extend and extract all the value Backstage can offer your organization is with plugins. The community behind the Backstage open-source project is constantly working on plugins to benefit all the organizations that implement it. Plugins are React components and optional Node.js microservices that power these components. It’s also possible to build your own plugins.&lt;/p&gt;
&lt;h2 id=&quot;unleash-the-power-of-backstage&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#unleash-the-power-of-backstage&quot; aria-label=&quot;unleash the power of backstage permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Unleash the power of Backstage&lt;/h2&gt;
&lt;p&gt;Although these features are part of Backstage’s core offerings, the real power of this platform is in how customizable it is. You can create tailor-made developer portals and introduce all kinds of specific functionalities like testing, data analysis, etc. What you see here is just the tip of the iceberg.&lt;/p&gt;
&lt;p&gt;If you are interested in learning more, check out Frontside’s blog or consider subscribing to our newsletter. As proud members of the Backstage development community, we are constantly working to extend this platform&apos;s power.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Want to learn more? We have a great community in &lt;a href=&quot;https://discord.gg/9xfdDYthpF&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Discord&lt;/a&gt;; come and say hello! We like to help and discuss all kinds of tech and code topics.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/6ea0e7a151ed21f41e36defcf86edb56/2a4de/2022-What-Is-Spotify-Backstage.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Tutorial: Using Github Webhooks with Backstage Entity Provider]]></title><description><![CDATA[In this short tutorial, Min will show you how to configure Github Webhooks for Backstage's Github Entity Provider]]></description><link>https://frontside.com/blog/2022-05-03-backstage-entity-provider/</link><guid isPermaLink="false">https://frontside.com/blog/2022-05-03-backstage-entity-provider/</guid><category><![CDATA[backstage]]></category><dc:creator><![CDATA[Min Kim]]></dc:creator><pubDate>Tue, 03 May 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://backstage.io/docs/features/software-catalog/external-integrations#custom-entity-providers&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Entity Providers&lt;/a&gt; are a more scalable and robust alternative to &lt;a href=&quot;https://backstage.io/docs/features/software-catalog/external-integrations#custom-processors&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Entity Processors&lt;/a&gt;. The Backstage team introduced Entity Providers to solve problems that big deployments of Backstage were experiencing with the ingestion pipeline. If you take a look at their documentation on &lt;a href=&quot;https://backstage.io/docs/features/software-catalog/life-of-an-entity&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Life of an Entity&lt;/a&gt;, it illustrates how your new ingestion pipelines should be structured.&lt;/p&gt;
&lt;p&gt;Before the Entity Providers came into the picture, the preexisting processors essentially took on the roles of both the entity providers &lt;em&gt;and&lt;/em&gt; the processors described in the documentation. I bring this up as it may provide clarity to anyone confused by some of the overlapping functionality of the current processors and entity providers in the Backstage plugins; some of those processors have not yet been updated to adapt to the new proposed ingestion pipeline.&lt;/p&gt;
&lt;p&gt;Getting back to why Entity Providers were introduced, there are some common issues with ingestion &lt;em&gt;processors&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The processing queue would get filled with no-op processing, putting pressure on external systems. In some cases, it leads to rate limiting requests.&lt;/li&gt;
&lt;li&gt;Writing performant custom processors required implementing caching, which many teams did not.&lt;/li&gt;
&lt;li&gt;Failure in external service leads to the creation of orphan entities, which disappear components from the catalog.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Entity providers eliminate these problems by giving developers complete control over the execution of ingestion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Entity Providers do not have an implicit queue that drives their execution; instead, developers specify the mechanism that drives each entity provider. A driver for an entity provider can be a simple callback that runs on an interval, an event listener triggered by a Web Socket connection, or a response to the HTTP request.&lt;/li&gt;
&lt;li&gt;There is no need to cache requests because there is no implicit orphaning of entities. Entities are only mutated when the Entity Provider calls &lt;em&gt;commitMutation&lt;/em&gt; on the connection. The developer can control update frequency by configuring the mechanism that drives the entity provider.&lt;/li&gt;
&lt;li&gt;Entity Providers automatically handle efficiently merging small changes to many entities without explicitly applying deltas. It’s possible to use just the deltas if the data source provides them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since entity providers do not have an implicit queue, you’ll need to specify what drives each entity provider. You could use a task scheduler and specify the frequency of entity provider executions. Ideally, your entity provider would respond to changes in the original data source and remain idle all other times. Developers can accomplish this with webhooks and streaming.&lt;/p&gt;
&lt;p&gt;In this tutorial, we&apos;ll walk you through the steps of adding &lt;code class=&quot;language-text&quot;&gt;GitHubOrgEntityProvider&lt;/code&gt; to your catalog and then show you how you can configure Github Webhooks to trigger mutations to your Backstage database.&lt;/p&gt;
&lt;h2 id=&quot;adding-an-entity-provider&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#adding-an-entity-provider&quot; aria-label=&quot;adding an entity provider permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adding an Entity Provider&lt;/h2&gt;
&lt;p&gt;Assuming you already have your own instance of Backstage, let&apos;s install the necessary packages for adding the Github Org Entity Provider:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;yarn workspace backend add @backstage/plugin-catalog-backend-module-github @backstage/integration&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then you can import the provider to your catalog builder in &lt;code class=&quot;language-text&quot;&gt;packages/backend/src/plugins/catalog.ts&lt;/code&gt;. Be sure to replace the orgUrl with your own:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt; import { CatalogBuilder } from &apos;@backstage/plugin-catalog-backend&apos;;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import { CatalogBuilder, EntityProvider } from &apos;@backstage/plugin-catalog-backend&apos;;
&lt;/span&gt;...
&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import { ScmIntegrations, DefaultGithubCredentialsProvider } from &apos;@backstage/integration&apos;;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import { GitHubOrgEntityProvider } from &apos;@backstage/plugin-catalog-backend-module-github&apos;;
&lt;/span&gt;
export default async function createPlugin(
&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; env: PluginEnvironment,
&lt;/span&gt;): Promise&amp;lt;Router&gt; {
&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; const builder = await CatalogBuilder.create(env);
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; builder.addProcessor(new ScaffolderEntitiesProcessor());
&lt;/span&gt;
&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  const integrations = ScmIntegrations.fromConfig(env.config);
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  const githubCredentialsProvider = DefaultGithubCredentialsProvider.fromIntegrations(integrations);
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  const gitProvider = GitHubOrgEntityProvider.fromConfig(env.config, {
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    id: &quot;github-org-entity-provider&quot;,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    orgUrl: &quot;https://github.com/my-organization&quot;, // 🚨 REPLACE
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    logger: env.logger,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    githubCredentialsProvider
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  });
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  builder.addEntityProvider(gitProvider as EntityProvider);
&lt;/span&gt;
&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; const { processingEngine, router } = await builder.build();
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; await processingEngine.start();
&lt;/span&gt;
&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; return router;
&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you try to run your Backstage app, you should notice nothing has changed in your catalog. As mentioned earlier, developers must provide the mechanism that will drive the entity provider. For the sake of this example, let&apos;s add the GitHubOrgEntityProvider&apos;s &lt;code class=&quot;language-text&quot;&gt;read()&lt;/code&gt; at the end of our catalog builder:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; await processingEngine.start();
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  await gitProvider.read();
&lt;/span&gt;
&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; return router;
&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you restart your Backstage, you &lt;em&gt;should&lt;/em&gt; see the members and teams of your organization. If you do not, you should check the permissions of your Github authentication. Whether you&apos;re using a personal access token or a &lt;a href=&quot;https://backstage.io/docs/integrations/github/github-apps&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Github App&lt;/a&gt;, you need to make sure it has permissions for &lt;code class=&quot;language-text&quot;&gt;read:user&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;read:org&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Calling &lt;code class=&quot;language-text&quot;&gt;read()&lt;/code&gt; towards the end of the catalog building process will only update your database once during deployment so now we&apos;re going to configure a webhook to trigger the updates.&lt;/p&gt;
&lt;h2 id=&quot;configure-github-webhook&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#configure-github-webhook&quot; aria-label=&quot;configure github webhook permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configure Github Webhook&lt;/h2&gt;
&lt;p&gt;Let&apos;s start by creating your webhook on Github. From your Github organization&apos;s settings page, click &lt;code class=&quot;language-text&quot;&gt;Webhooks&lt;/code&gt; in the side bar and then &lt;code class=&quot;language-text&quot;&gt;Add webhook&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2022-05-03-add-webhook.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;github-webhook-section-screenshot&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;You can get a &lt;code class=&quot;language-text&quot;&gt;Payload URL&lt;/code&gt; from &lt;a href=&quot;https://smee.io&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;smee.io&lt;/a&gt; - this is a service that proxies payloads from your webhook for local development.&lt;/p&gt;
&lt;p&gt;Set the content type to &lt;code class=&quot;language-text&quot;&gt;application/json&lt;/code&gt; and let&apos;s specify the events we want by selecting &lt;code class=&quot;language-text&quot;&gt;Let me select individual events&lt;/code&gt;. The &lt;code class=&quot;language-text&quot;&gt;GitHubOrgEntityProvider&lt;/code&gt; adds users and teams to your catalog so the webhook events we want to receive from Github are &lt;code class=&quot;language-text&quot;&gt;Orgnaization&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Teams&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For your actual deployment, you&apos;ll want to modify the Payload URL from the smee URL to the URL of your live Backstage app.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once the webhook is added, you should follow the instructions displayed on &lt;a href=&quot;https://smee.io&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;smee.io&lt;/a&gt; to install their client and use &lt;code class=&quot;language-text&quot;&gt;http://localhost:7007/api/catalog/github/webhook&lt;/code&gt; as the target URL.&lt;/p&gt;
&lt;p&gt;Next, update your catalog builder so that it runs &lt;code class=&quot;language-text&quot;&gt;read()&lt;/code&gt; when a webhook event is posted to &lt;code class=&quot;language-text&quot;&gt;/github/webhook&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; await processingEngine.start();
&lt;/span&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  await gitProvider.read();
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  router.post(&quot;/github/webhook&quot;, async (req, _res) =&gt; {
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    const event = req.headers[&quot;x-github-event&quot;];
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    if (event == &quot;membership&quot; || event == &quot;organization) {
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;      await gitProvider.read();
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    }
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  })
&lt;/span&gt;
&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; return router;
&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you run the smee client and your Backstage app, you&apos;ll see that the entity provider will update the database only when a webhook event is posted by Github.&lt;/p&gt;
&lt;p&gt;If you have concerns of the possibily of a webhook being missed, you might want to consider using the Backstage &lt;a href=&quot;https://github.com/backstage/backstage/tree/master/packages/backend-tasks&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;task scheduler&lt;/a&gt; to run &lt;code class=&quot;language-text&quot;&gt;read()&lt;/code&gt; once a day for that extra assurance.&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-next&quot; aria-label=&quot;whats next permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What&apos;s next?&lt;/h2&gt;
&lt;p&gt;In this tutorial we quickly went over the steps of adding an entity provider to your catalog and using smee to proxy webhook events to your local environment, but this is just the beginning!&lt;/p&gt;
&lt;p&gt;If you look at the implementation of &lt;a href=&quot;https://github.com/backstage/backstage/blob/master/plugins/catalog-backend-module-github/src/GitHubOrgEntityProvider.ts#L106-L147&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;GitHubOrgEntityProvider&lt;/code&gt;&lt;/a&gt;, the &lt;code class=&quot;language-text&quot;&gt;read()&lt;/code&gt; function queries data directly from Github and runs a &lt;code class=&quot;language-text&quot;&gt;full&lt;/code&gt; mutation. In its current state, depending on the size of your organization, your &lt;code class=&quot;language-text&quot;&gt;read()&lt;/code&gt; function might end up triggering way too frequently - resulting in too many Github requests and performing a full mutation of your database each time.&lt;/p&gt;
&lt;p&gt;When you create your own custom entity provider, you will want to create a function that applies a &lt;code class=&quot;language-text&quot;&gt;delta&lt;/code&gt; mutation just from the data received from the webhook events. You can read more about the mutation types &lt;a href=&quot;https://backstage.io/docs/features/software-catalog/external-integrations#provider-mutations&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/089fea5cc9ab03dd1375a107244fcc3e/2a4de/2022-Github-with-Backstage.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Testing Backstage Catalog's ingestion]]></title><description><![CDATA[To test whether the Backstage is setting up the Catalog properly, you must start a Backstage server, wait for a while, and assert. This feat is easier said than done, but Charles will guide you through it in this article.]]></description><link>https://frontside.com/blog/2022-03-24-testing-backstage-catalog-ingestors/</link><guid isPermaLink="false">https://frontside.com/blog/2022-03-24-testing-backstage-catalog-ingestors/</guid><category><![CDATA[backstage]]></category><category><![CDATA[testing]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Thu, 24 Mar 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A test is a mechanism to answer a simple yes or no question. In my case, the question I want to ask is, &quot;When my Backstage server runs, is it going to ingest stuff into the Catalog properly?&quot;&lt;/p&gt;
&lt;p&gt;It seems to me that there is only one way to find an honest answer:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Start a backstage server.&lt;/li&gt;
&lt;li&gt;Let it run for a while.&lt;/li&gt;
&lt;li&gt;Query its Catalog API over HTTP to see if it contains the records we want.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It&apos;s a small ask that can nevertheless be quite difficult to satisfy. Not only are operating system processes difficult enough to manage already, but also &quot;let it run for a while&quot; is an easy thing to say that is quite hard to put into practice.&lt;/p&gt;
&lt;p&gt;Fortunately, by using &lt;a href=&quot;https://frontside.com/blog/2021-10-26-effection-async-await/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;structured concurrency&lt;/a&gt; coupled with the novel application of &lt;a href=&quot;https://en.wikipedia.org/wiki/Eventual_consistency&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;eventual consistency&lt;/a&gt; from database theory, you can write tests for your backend that are expressive of this question and are both fast and reliable. I&apos;ll show you the technique what we use at Frontside with large Backstage codebases to achieve this.&lt;/p&gt;
&lt;p&gt;For this article, I&apos;ve applied the same technique to a sample application scaffolded with &lt;code class=&quot;language-text&quot;&gt;npx @backstage/create-app&lt;/code&gt; (you can find it in &lt;a href=&quot;https://github.com/cowboyd/backstage-integration-testing-example&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt; github.com/cowboyd/backstage-testing-example&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Our approach works the same whether we&apos;re testing the humblest starter kit or the most heavily customized Backstage instance because the tests only interact with Backstage as an &lt;em&gt;OS process&lt;/em&gt; and an &lt;em&gt;HTTP server&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Here is what a test looks like to check that the sample data is ingested into the Catalog. I&apos;ll go over each section in turn, but as you read it, take note that the test really is telling you what it is doing.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; CatalogApi &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@backstage/catalog-client&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; describe&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; beforeEach&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; it &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@effection/jest&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createBackstage &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./support&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;catalog ingestion&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; catalog&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CatalogApi&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    catalog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createBackstage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eventually&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ingests the artist lookup component &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; component &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; catalog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEntityByRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;component:artist-lookup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;component&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toMatchObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      metadata&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;artist-lookup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Artist Lookup&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        tags&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;java&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      spec&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;service&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        owner&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;team-a&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        system&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;artist-engagement-portal&apos;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This test does what I stated initially: start a backstage server, let it run for a while, and then query its catalog API over HTTP to see if it contains the records I expect. Let&apos;s break down how this is accomplished.&lt;/p&gt;
&lt;h2 id=&quot;controlling-the-server&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#controlling-the-server&quot; aria-label=&quot;controlling the server permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Controlling the Server&lt;/h2&gt;
&lt;p&gt;The first thing we do is to start a Backstage server with the following declaration:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; catalog&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CatalogApi&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    catalog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createBackstage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This deceptively small piece of code bears quite a bit of weight. It starts a Backstage server and returns a reference to a Catalog API pointing to that server so that we can query its state.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;createBackstage&lt;/code&gt; starts a completely fresh backstage server, with a completely new database &lt;em&gt;for every single test case&lt;/em&gt;. The Backstage logs are persisted on a per-test basis in a special &lt;code class=&quot;language-text&quot;&gt;tests/logs&lt;/code&gt; directory to aid in debugging what went wrong whenever there is a failure.&lt;/p&gt;
&lt;p&gt;This way, you achieve isolation, foster transparency, and avoid &lt;a href=&quot;https://stackoverflow.com/a/333704/218137&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;hidden dependencies&lt;/a&gt; between your tests. It may seem like a tall order, but this is where &lt;a href=&quot;https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;structured concurrency&lt;/a&gt;, and in particular, the application of its principles &lt;a href=&quot;https://frontside.com/effection&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;to javascript&lt;/a&gt; can help out.&lt;/p&gt;
&lt;p&gt;Structured concurrency ties the lifetime of the Backstage process to the test. If the test passes, Backstage is shut down. If the test fails, Backstage is shut down. If the test errors or times out, Backstage is shut down. In other words, no matter the test&apos;s outcome, the Backstage server process will always be terminated. And importantly, at no point did we have to tell it to do so via an &lt;code class=&quot;language-text&quot;&gt;afterEach&lt;/code&gt; hook or some other explicit teardown mechanism.&lt;/p&gt;
&lt;p&gt;These process guarantees give you incredible flexibility by allowing you to embed the Backstage server anywhere in your test case and not worry about how it is cleaned up.&lt;/p&gt;
&lt;h3 id=&quot;assertions-made-simple&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#assertions-made-simple&quot; aria-label=&quot;assertions made simple permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Assertions Made Simple&lt;/h3&gt;
&lt;p&gt;Now that the server process is running, how can you make reliable assertions against it? Ideally, assertions should be as simple, fast, and predictable as if you were unit testing a pure synchronous function.&lt;/p&gt;
&lt;p&gt;The problem, of course, is that, unlike a pure function, a server is a kinetic mass of state that is in continuous flux. Nevertheless, if you wait long enough, its internal motion will carry it to the point where we will reliably observe the state you expect to see, which is to the presence of the artist lookup service in the Catalog. Now is when the &quot;wait a while&quot; comes into play. The main question is, how long should the test wait?&lt;/p&gt;
&lt;p&gt;Believe it or not, the answer is &quot;long enough.&quot;&lt;/p&gt;
&lt;p&gt;You could try an explicit wait via &lt;code class=&quot;language-text&quot;&gt;setTimeout()&lt;/code&gt;, but that is a well-documented antipattern. Alternatively, you could get some callback from Backstage that fired after each ingestion cycle was complete, but that adds an internal API used only for testing and means that we can no longer treat our server as a black box.&lt;/p&gt;
&lt;p&gt;It turns out the theory of &lt;a href=&quot;https://en.wikipedia.org/wiki/Eventual_consistency&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;eventual consistency&lt;/a&gt; and its concept of &quot;state convergence&quot; can determine how long is long enough with relative ease.&lt;/p&gt;
&lt;p&gt;In a regular synchronous assertion, there is no delay between cause and effect:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2022-03-24-backstage-ingestion-testing/assertion-after.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Diagram of an assertion at the right time&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The effect of any action is immediately observable, and so when an assertion runs, it can always see that effect, making it simple and reliable.&lt;/p&gt;
&lt;p&gt;However, in a highly asynchronous environment such as a Backstage server, you will likely try to run an assertion &lt;em&gt;before&lt;/em&gt; an action&apos;s effects have yet to settle and become externally observable.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2022-03-24-backstage-ingestion-testing/false-negative.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;An assertion yielding a false negative&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;This would result in a false negative, where if you&apos;d just had the patience to wait just a wee bit longer, you could have observed the effect, but instead, you made your assertion too soon, and the test failed.&lt;/p&gt;
&lt;p&gt;Here is when eventual consistency comes to the rescue. If you assume that the server state is not immediately available, but is instead only in the process of converging onto some expected state, then instead of making a single observation at the right time, you continually make the same observation again and again until it eventually becomes true.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2022-03-24-backstage-ingestion-testing/convergent-assertion.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Converging assertion&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Convergence guarantees that if the state you expect can be observed, it will be observed and that you&apos;ll wait just long enough to observe it and no longer. If there is something wrong, and the state is never achieved, then the test case will time out, and you&apos;ll be presented with the last failed assertion.&lt;/p&gt;
&lt;p&gt;That may seem like a lot of conceptual overhead, but it&apos;s all put on the table so that when it comes to writing and reading test cases, your assertions are as simple as though your Backstage server were just another object.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eventually&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ingests the artist lookup component &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; component &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; catalog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEntityByRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;component:artist-lookup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;component&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toMatchObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      metadata&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;artist-lookup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Artist Lookup&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        tags&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;java&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      spec&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;service&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        owner&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;team-a&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        system&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;artist-engagement-portal&apos;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Except for the &lt;code class=&quot;language-text&quot;&gt;eventually&lt;/code&gt; marker, that&apos;s the kind of assertion you would expect if you were testing a pure function.&lt;/p&gt;
&lt;h3 id=&quot;the-dividend&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-dividend&quot; aria-label=&quot;the dividend permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Dividend&lt;/h3&gt;
&lt;p&gt;The upshot of all this is that you now have a test suite that can answer the most critical question and crystal clear in how those questions are expressed. Not only that, but it does so reliably and without any need to account for the timing of internal server processes.&lt;/p&gt;
&lt;p&gt;As a result, we have converted our Backstage server from an &quot;environment&quot; that needs to be set up, torn down, and carefully managed throughout our suite into a lightweight resource to be instantiated and tested according to the usual fashion.&lt;/p&gt;
&lt;p&gt;If you want to dig deeper into this testing technique, check out the complete &lt;a href=&quot;https://github.com/cowboyd/backstage-integration-testing-example&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;source code in Github&lt;/a&gt;. If you have any questions, ask away in our &lt;a href=&quot;https://discord.gg/r6AvtnU&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;discord community&lt;/a&gt;!&lt;/p&gt;
&lt;h3 id=&quot;up-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#up-next&quot; aria-label=&quot;up next permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Up Next&lt;/h3&gt;
&lt;p&gt;Not all Backstage ingestion is done with simple YAML files as the Catalog. Often it can be a complicated process involving integration with many third-party services. Building on the test suite in this article, we&apos;ll show how you can test these integrations without resorting to fixtures, mocking, stubbing, or other hacks.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/61b58a7549b07eb3bdfbb4f29dcbeb90/2a4de/2022-backstage-ingestion-test.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Backstage tutorial: plugin integration tests with Cypress + Interactors]]></title><description><![CDATA[In this tutorial, you'll learn how to set up integration tests for your Backstage plugins using Material UI Interactors]]></description><link>https://frontside.com/blog/2022-03-03-backstage-tutorial-plugin-tests-interactors/</link><guid isPermaLink="false">https://frontside.com/blog/2022-03-03-backstage-tutorial-plugin-tests-interactors/</guid><category><![CDATA[backstage]]></category><category><![CDATA[testing]]></category><dc:creator><![CDATA[Jorge Lainfiesta]]></dc:creator><pubDate>Thu, 03 Mar 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Plugins are the most common way to extend the power of Backstage. A plugin most often includes a UI built using &lt;a href=&quot;https://backstage.io/docs/reference/core-components&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@backstage/core-components&lt;/code&gt;&lt;/a&gt; and other &lt;a href=&quot;https://mui.com/getting-started/installation/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Material UI&lt;/a&gt; components.&lt;/p&gt;
&lt;p&gt;While Material UI makes it quick and easy to put together a good-looking UI, it also poses challenges when testing.&lt;/p&gt;
&lt;p&gt;Consider this button:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Button&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;variant&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;contained&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;large&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;primary&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  =
&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Button&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It generates the following output:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;MuiButtonBase-root-201 MuiButton-root-216 MuiButton-contained-224 MuiButton-containedPrimary-225 MuiButton-containedSizeLarge-234 MuiButton-sizeLarge-236&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;tabindex&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;=&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;MuiButton-label-217&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;=&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;MuiTouchRipple-root-304&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&apos;s &lt;em&gt;a lot&lt;/em&gt; of generated classes. How will you know which selectors to use for your test actions and assertions? Usually you&apos;d have to guess and try to craft selectors for each MUI component you use every time you use one.&lt;/p&gt;
&lt;p&gt;Happily you don&apos;t have to worry about this anymore! The &lt;a href=&quot;/backstage&quot;&gt;Frontside team&lt;/a&gt; has gone through the MUI components and created &lt;a href=&quot;https://frontside.com/blog/2021-08-04-interactors-design-systems/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&quot;Interactors&quot;&lt;/a&gt; like the following that you can use in your tests:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Button &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@interactors/material-ui&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;=&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This tutorial will show you how to set up integration tests for your Backstage plugin using Cypress and Interactors. In it you’ll learn how to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#set-up&quot;&gt;Set up Cypress and Interactors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#assert-with-interactors&quot;&gt;Assert with Interactors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#act-with-interactors&quot;&gt;Act with Interactors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#extend-existing-interactors&quot;&gt;Extend existing Interactors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#write-your-own-interactor&quot;&gt;Write your own Interactor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#other-material-ui-interactors&quot;&gt;Use other Material UI Interactors&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;what-youll-be-testing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-youll-be-testing&quot; aria-label=&quot;what youll be testing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What you&apos;ll be testing&lt;/h2&gt;
&lt;p&gt;I created a Backstage plugin calculator with Material UI to use as an example for this tutorial. It features a &apos;classic calculator&apos; with a button-based UI and a &apos;text-based calculator&apos; which relies on a text field for input:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2022-backstage-interactors/demo.gif&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;A gif showing the calculator demo&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The calculator doesn&apos;t do anything exciting, so we won&apos;t go over the implementation details. You can have a look at the &lt;a href=&quot;https://github.com/jorgelainfiesta/backstage-calculator-plugin-tutorial&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;whole code in this repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;set-up-cypress-and-interactors&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#set-up-cypress-and-interactors&quot; aria-label=&quot;set up cypress and interactors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Set up Cypress and Interactors&lt;/h2&gt;
&lt;p&gt;By default, Backstage sets up new plugins with Jest. Jest can help you with unit tests, but integration tests have significant performance problems due to the DOM virtualization.&lt;/p&gt;
&lt;p&gt;Thus, I recommend using Cypress for your plugin&apos;s integration tests, which Backstage uses as well to test the instance as a whole.&lt;/p&gt;
&lt;p&gt;I won&apos;t cover Cypress in much detail because you probably already have it set up for Backstage. All you need to do is apply those configurations and practices to your plugins too.&lt;/p&gt;
&lt;p&gt;There&apos;s actually only two Interactors-specific settings to consider. First, make sure you&apos;re importing &lt;code class=&quot;language-text&quot;&gt;@interactors/with-cypress&lt;/code&gt; in your plugin&apos;s &lt;code class=&quot;language-text&quot;&gt;cypress/support/index.ts&lt;/code&gt; file. Secondly, adjust your eslint settings to accommodate Interactor&apos;s assertions in your plugin&apos;s cypress directory:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;plugins&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cypress&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;extends&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;plugin:cypress/recommended&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;jest/expect-expect&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;assertFunctionNames&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cy.expect&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;new-cap&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;off&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, add the Material UI Interactors to your plugin. You know the drill:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--dev&lt;/span&gt; @interactors/material-ui&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can &lt;a href=&quot;https://frontside.com/interactors/docs/jest&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;use Interactors with Jest&lt;/a&gt; in this step if you want, but because we&apos;ll be using them with Cypress, we need to install specific bindings:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--dev&lt;/span&gt; @interactors/with-cypress&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;assert-with-interactors&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#assert-with-interactors&quot; aria-label=&quot;assert with interactors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Assert with Interactors&lt;/h2&gt;
&lt;p&gt;I&apos;ll use the Calculator plugin I created as an example for this tutorial. You can &lt;a href=&quot;https://github.com/jorgelainfiesta/backstage-calculator-plugin-tutorial&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;clone my repo&lt;/a&gt; and work from &lt;a href=&quot;https://github.com/jorgelainfiesta/backstage-calculator-plugin-tutorial/tree/testless-calculator&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;testless-calculator&lt;/code&gt;&lt;/a&gt; branch if you want to follow along.&lt;/p&gt;
&lt;p&gt;The first test we&apos;ll write is to assert that the plugin&apos;s entry page renders when someone visits the plugin&apos;s URL:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Heading&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Tab &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@interactors/material-ui&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;The calculator plugin&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/calculator&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;should render simple calculator by default&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;Heading&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Classic Calculator&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;Tab&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;CLASSIC CALCULATOR&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; active&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;cy.expect&lt;/code&gt; is one of Interactors bindings for Cypress and it&apos;s used for assertions (the ther binding is explained &lt;a href=&quot;#act-with-interactors&quot;&gt;next section&lt;/a&gt;). In the test above, you&apos;re telling Cypress to check if a MUI Heading with the text &quot;Classic Calculator&quot; exists and if a MUI Tab with the label &quot;CLASSIC CALCULATOR&quot; is active.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2022-backstage-interactors/assertion-test-passing.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshot of tests passing&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id=&quot;act-with-interactors&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#act-with-interactors&quot; aria-label=&quot;act with interactors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Act with Interactors&lt;/h2&gt;
&lt;p&gt;Interactors enforce an AAA (Arrange-Act-Assert) pattern to provide helpful errors. So far, you&apos;ve seen the function used for assertions (&lt;code class=&quot;language-text&quot;&gt;cy.expect&lt;/code&gt;). Now let&apos;s take a look at actions, well, &lt;em&gt;in action&lt;/em&gt; with &lt;code class=&quot;language-text&quot;&gt;cy.do&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The second test you&apos;ll write will confirm that the inner navigation of the plugin works correctly. To do that, you&apos;ll have Cypress click on a tab that takes the user to another page and verify if the UI reflects that state:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;should change to input calculator with tab&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;do&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;Tab&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;TEXT CALCULATOR&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;Heading&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Text-based Calculator&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;Tab&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;TEXT CALCULATOR&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; active&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;cy.do&lt;/code&gt; is the other Interactors binding for Cypress, and it lets you perform actions. As you can see, you use the same Interactors to act and assert.&lt;/p&gt;
&lt;h2 id=&quot;extend-existing-interactors&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#extend-existing-interactors&quot; aria-label=&quot;extend existing interactors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Extend existing Interactors&lt;/h2&gt;
&lt;p&gt;The classic calculator from the example also has some interactions that need to be tested. A recurring element that we&apos;ll need to check is the calculator&apos;s results box, so let&apos;s write an Interactor to target it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;HTML&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@interactors/material-ui&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; CalculatorResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HTMLParagraphElement&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;Calculator result&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;selector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.calculator-results&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the code above you&apos;re creating a new Interactor called &quot;Calculator result&quot;, which &lt;a href=&quot;https://frontside.com/interactors/docs/create-first-interactor#extending-an-interactor&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;extends the base HTML Interactor&lt;/a&gt; and specifies its selector as &lt;code class=&quot;language-text&quot;&gt;.calculator-result&lt;/code&gt;. (You can organize your Interactors in dedicated directories and files, but for simplicity I added this interactor on top of the spec file.)&lt;/p&gt;
&lt;p&gt;Let&apos;s use the new &lt;code class=&quot;language-text&quot;&gt;CalculatorResult&lt;/code&gt; Interactor to check that clicking on the digit buttons results in their corresponding value appearing in the results panel:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;should show inputted numbers in the result box&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;do&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;3&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;CalculatorResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You&apos;re checking that the calculator result corresponds to the digits pressed. It&apos;s worth noticing that the &lt;code class=&quot;language-text&quot;&gt;CalculatorResult()&lt;/code&gt; needs to match a single element or it&apos;ll throw an exception.&lt;/p&gt;
&lt;p&gt;In this example, there&apos;s no way two results will be present on the same page, so if that did happen you&apos;d certainly want your test to fail. You can specify &lt;a href=&quot;https://frontside.com/interactors/docs/locators-filters&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;filters&lt;/a&gt; and &lt;a href=&quot;https://frontside.com/interactors/docs/matchers&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;matchers&lt;/a&gt; to fine-tune your Interactor selection so it only picks up one element.&lt;/p&gt;
&lt;h2 id=&quot;write-your-own-interactor&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#write-your-own-interactor&quot; aria-label=&quot;write your own interactor permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Write your own Interactor&lt;/h2&gt;
&lt;p&gt;The classic calculator has several cases to be tested. Does addition and substraction work correctly? What about the sequence of operations? If I wanted to test an operation like &lt;code class=&quot;language-text&quot;&gt;101+23-7&lt;/code&gt;, I&apos;d need to write a test like the following:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;should add two numbers correctly&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;do&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;+&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;3&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;-&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;7&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;=&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;CalculatorResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;117&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can imagine, testing more complex operations can be burdensome with all the manual button clicking. Instead, you can write an interactor for the classic calculator that performs the button clicking for you:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ClassicCalculator &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createInteractor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Calculator&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;selector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.classic-calculator&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;inputDigits&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;calculator&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; digits&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; digit &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; digits&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; calculator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;digit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the code above, you&apos;re defining an Interactor called &quot;Calculator&quot; and specifying an action for it. The &lt;code class=&quot;language-text&quot;&gt;inputDigits&lt;/code&gt; action will receive &lt;em&gt;this&lt;/em&gt; &lt;code class=&quot;language-text&quot;&gt;calculator&lt;/code&gt; interactor instance as the first argument with a &lt;code class=&quot;language-text&quot;&gt;digits&lt;/code&gt; parameter. For every digit, you&apos;re &lt;code class=&quot;language-text&quot;&gt;find&lt;/code&gt;ing a &lt;code class=&quot;language-text&quot;&gt;Button&lt;/code&gt; interactor with the specified &lt;code class=&quot;language-text&quot;&gt;digit&lt;/code&gt; within the &lt;code class=&quot;language-text&quot;&gt;calculator&lt;/code&gt; Interactor and clicking it.&lt;/p&gt;
&lt;p&gt;Using your &lt;code class=&quot;language-text&quot;&gt;ClassicCalculator&lt;/code&gt; Interactor, you can write the previous test example as:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;should add two numbers correctly with Interactor&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;do&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;ClassicCalculator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;inputDigits&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;101+23-7=&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;CalculatorResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;117&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;other-material-ui-interactors&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#other-material-ui-interactors&quot; aria-label=&quot;other material ui interactors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Other Material UI Interactors&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;@interactors/material-ui&lt;/code&gt; comes packed with 30+ Interactors for Material UI components. You can choose whichever interactor suits your UI from the &lt;a href=&quot;https://frontside.com/interactors/mui/api/index.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;detailed MUI Interactors API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To illustrate how useful these are, let’s use another Interactor with a test for the other tab of my calculator plugin. Instead of a button-based input, the &quot;Text-based calculator&quot; accepts a math expression from the user and prints the result to the result box. Thus, I can use the Material UI &lt;code class=&quot;language-text&quot;&gt;TextField&lt;/code&gt; Interactor as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Button&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TextField &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@interactors/material-ui&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;The text calculator&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/calculator/text&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;should render initail state&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;TextField&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Math expression&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;=&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;CalculatorResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;0&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;should solve an expression&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;do&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;TextField&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Math expression&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;101+23&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;=&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;CalculatorResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;124&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you run the test suite based on Cypress and Interactors, it should look like this:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2022-backstage-interactors/test-suite-whole.gif&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;A gif with tests executing on cypress&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Using &lt;a href=&quot;https://frontside.com/interactors&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Interactors&lt;/a&gt; in your Backstage integration tests can help you save time and development efforts. Try them out, and if you need any help, reach out via &lt;a href=&quot;https://discord.gg/r6AvtnU&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;our Discord server&lt;/a&gt; and ask away!&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/03ed6fdada940abc5b98342d3217d351/2a4de/2022-backstage-cypress-interactors.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Announcing GraphGen: the search for the graph factory]]></title><description><![CDATA[Creating fake datasets that resemble real ones is nearly impossible today. That's why Frontside is working on a tool that can generate graphs with coherent data and relationships]]></description><link>https://frontside.com/blog/2022-02-21-graphgen-graph-factory/</link><guid isPermaLink="false">https://frontside.com/blog/2022-02-21-graphgen-graph-factory/</guid><category><![CDATA[dx]]></category><category><![CDATA[simulation]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 21 Feb 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;From the very beginning of my career until the present day I have relied on fake data. That may sound odd to the uninitiated—especially in a world where that seems overrun with fake data—but it’s true for me and every other developer I know. We couldn’t do what we do—build reliable applications that work every time—without high-quality fake data.&lt;/p&gt;
&lt;p&gt;The first such set I can remember using was &lt;code class=&quot;language-text&quot;&gt;tinydata.sql&lt;/code&gt;, an SQL file that contained an aggressively curated list of INSERT statements that reconstructed a complete and realistic dataset from scratch. “Tiny Data” was quite revered by the developers in the team because it was so critical to both testing and developing apps. Indeed, I had so much respect for Tiny Data that I would often sing to it in the tune of Elton John’s “Tiny Dancer.” Not only did it allow you to see fake high-fidelity receipts and product data for the point of sale application we were writing, but it also let you write tests that could rely on certain records always being present. You were in big trouble if you made a change to the application that was incompatible with Tiny Data because it would instantly disrupt the workflows of more than thirty developers. They would not be happy about it at all.&lt;/p&gt;
&lt;p&gt;There has been a lot of progress since those days. We now recognize the value of high-quality fake data, and we intentionally place it at the center of our development practice. Instead of static hand-curated datasets we use factories, and instead of obviously fake names like “Test User 1” we use tools like faker.js to generate random yet realistic values. However, despite these improvements, other problems remain as vexing now as they were back then.&lt;/p&gt;
&lt;p&gt;Though I didn’t know the name for it at the time, Tiny Data was what we now call a fixture. And while we all did our very best to make sure that it was always in sync with the app we were developing, we somehow managed to break it pretty often. Invariably the breakage had to do with relationships between rows—or in the parlance of SQL, maintaining the foreign keys. For example, if you wanted to add a &lt;code class=&quot;language-text&quot;&gt;receipt&lt;/code&gt;, then it wasn’t just enough to add a row to the &lt;code class=&quot;language-text&quot;&gt;receipts&lt;/code&gt; table. You also needed to make sure and add a corresponding &lt;code class=&quot;language-text&quot;&gt;product&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;store&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;clerk&lt;/code&gt;. If you didn’t, otherwise it wouldn’t truly be valid: it might work just fine in the context of a daily receipt listing, but then break if you tried to navigate through to the receipt details page. &lt;/p&gt;
&lt;p&gt;Fast forward twenty years, and it is still the relationship between records that causes the most problems with fake data. Isn’t it odd that while we’ve gotten good at generating realistic data structures, we still run into problems when trying to relate those data structures with each other? Why is that so? And what can we do about it? &lt;/p&gt;
&lt;p&gt;Consider for a moment the critical innovation of tools like faker.js—you use a randomly selected value and yet it feels real. You reach your hand into a bag and draw out a name, an address, whatever you need. But what if we could reach our hand into a bag and draw out a fully formed and realistic graph? In other words, what if the network itself was the fake data and not the individual nodes within it? What would that look like?&lt;/p&gt;
&lt;p&gt;This was the question we decided to try and answer in late 2021. The result was &lt;code class=&quot;language-text&quot;&gt;@frontside/graphgen&lt;/code&gt; (&lt;a href=&quot;https://github.com/thefrontside/graphgen&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://github.com/thefrontside/graphgen&lt;/a&gt;). Like faker.js, it uses a probabilistic approach to generating values—except now the values generated are graphs instead of names or addresses.&lt;/p&gt;
&lt;p&gt;Much to our surprise, even in its most rudimentary implementation the tool was instantly powerful. Using a single generated graph, we were able to drive a GitHub simulator, an LDAP simulator, and a custom GraphQL simulator, all of which reported a state of the world consistent with each other. The same user data could be found in LDAP, GitHub, and the custom API.&lt;/p&gt;
&lt;p&gt;Most posts announcing a new tool do so at the end of a long journey after which a finished product is presented with a bow on top for general availability. This is not that, because that’s not how we do things at Frontside. Instead, we’re announcing graphgen at the beginning of its creation. We don’t know what form it will take eventually, and there are undoubtedly many challenges to overcome along the way. But we are sure that we’ll create a future where you can summon—in the blink of an eye—a fake dataset nearly indistinguishable from production.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/eede6e82e5ca35b8a669ead7ce41c804/2a4de/2022-graphgetn.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Tutorial: How to use your company’s component library with Backstage]]></title><description><![CDATA[In this tutorial, Taras will show you how to replace Material UI for your component library in Backstage without losing access to its API.]]></description><link>https://frontside.com/blog/2022-02-14-component-library-backstage/</link><guid isPermaLink="false">https://frontside.com/blog/2022-02-14-component-library-backstage/</guid><category><![CDATA[backstage]]></category><dc:creator><![CDATA[Taras Mankovski]]></dc:creator><pubDate>Mon, 14 Feb 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the first questions that a developer starting a Backstage project has to answer is how to make their developer portal match their company’s corporate style. There are several ways of doing this, but I recommend using an approach that will allow developers to use as much of the Backstage UI as possible so that everyone gets the most value from Backstage. The further the developer portal is from the beaten path, the fewer Backstage elements the development team will have access to.&lt;/p&gt;
&lt;p&gt;The approach that retains the most value from Backstage is using a &lt;a href=&quot;https://backstage.io/docs/getting-started/app-custom-theme#example-of-a-custom-theme&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;custom Material UI theme&lt;/a&gt; which allows developers to use &lt;strong&gt;all&lt;/strong&gt; of the existing Backstage plugins. If specific components need to be modified, there is the option of &lt;a href=&quot;https://backstage.io/docs/getting-started/app-custom-theme#overriding-backstage-and-material-ui-components-styles&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;overriding Backstage and Material UI styles&lt;/a&gt;. Admittedly, this approach can take a fair bit of tweaking and can be somewhat tedious, but will likely result in being able to use all of the existing and future Backstage plugins.&lt;/p&gt;
&lt;p&gt;If using the UI components provided by Backstage plugins is less important than using your internal component library, there are still good reasons to maintain access to their data. In addition to Material UI components, the Backstage frontend framework provides a data fetching API for retrieving data from the backend. Even if you’re not using the UI components of Backstage plugins, you can continue to benefit from them by leveraging their data API.&lt;/p&gt;
&lt;p&gt;In this tutorial, I will illustrate how to replace Material UI with the &lt;a href=&quot;https://developer.microsoft.com/en-us/fluentui#/controls/web&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Fluent UI&lt;/a&gt; component library, then use the Catalog Client API and FluentUI’s DetailList to display a list of catalog entities from Backstage&apos;s backend. Let’s get started!&lt;/p&gt;
&lt;h2 id=&quot;create-a-backstage-app&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#create-a-backstage-app&quot; aria-label=&quot;create a backstage app permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create a Backstage App&lt;/h2&gt;
&lt;p&gt;If you don’t already have an instance of a Backstage app, create one by running:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npx @backstage/create-app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For this tutorial, you can select &lt;code class=&quot;language-text&quot;&gt;SQLite&lt;/code&gt; as your backend database as it will save you the hassle of having to run a local instance of &lt;code class=&quot;language-text&quot;&gt;Postgres&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;clean-up-your-app&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#clean-up-your-app&quot; aria-label=&quot;clean up your app permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Clean up your app&lt;/h2&gt;
&lt;p&gt;Before we start adding our theme, we need to do a bit of clean up. Since we’re not going to be using Material UI, there is no need to keep its dependencies. We’ll start by removing those packages:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;yarn workspace app remove @backstage/theme @material-ui/core @material-ui/icons&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can also go ahead and delete everything in the &lt;code class=&quot;language-text&quot;&gt;packages/app/src/components/&lt;/code&gt; directory and create a simple &lt;code class=&quot;language-text&quot;&gt;Home&lt;/code&gt; component that will be our new Home page (without all the Backstage frontend elements):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// packages/app/src/components/Home.tsx&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Home&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, you need to remove all the routes and plugins and add the new Home component to your app. There is a lot to remove so I’ll show you what your &lt;code class=&quot;language-text&quot;&gt;App.tsx&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;./packages/app/src/&lt;/code&gt; should look like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Route &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react-router&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; apis &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./apis&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createApp &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@backstage/app-defaults&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; FlatRoutes &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@backstage/core-app-api&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Home &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./components/Home&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createApp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  apis&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; AppProvider &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; AppRouter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getRouter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; routes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FlatRoutes&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Route&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FlatRoutes&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AppProvider&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AppRouter&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;routes&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AppRouter&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AppProvider&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; App&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;install-your-component-library&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#install-your-component-library&quot; aria-label=&quot;install your component library permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install your component library&lt;/h2&gt;
&lt;p&gt;Next, install the &lt;code class=&quot;language-text&quot;&gt;@fluentui/react&lt;/code&gt; component library to your frontend by running:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;yarn workspace app add @fluentui/react&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will allow you to use components from the library in the frontend application. We can now modify &lt;code class=&quot;language-text&quot;&gt;Home.tsx&lt;/code&gt; to display a component from &lt;code class=&quot;language-text&quot;&gt;@fluentui/react&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;import React from &apos;react&apos;;
&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import { PrimaryButton } from &apos;@fluentui/react&apos;;
&lt;/span&gt;
export const Home = () =&gt; {
&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;  return &amp;lt;p&gt;Home&amp;lt;/p&gt;;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  return &amp;lt;PrimaryButton&gt;Press me!&amp;lt;/PrimaryButton&gt;;
&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you run &lt;code class=&quot;language-text&quot;&gt;yarn start&lt;/code&gt;, you should be able to see a button with the default Fluent UI style that says “Press me!”.&lt;/p&gt;
&lt;h2 id=&quot;change-the-theme-provider&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#change-the-theme-provider&quot; aria-label=&quot;change the theme provider permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Change the theme provider&lt;/h2&gt;
&lt;p&gt;By default, Backstage’s &lt;code class=&quot;language-text&quot;&gt;createApp&lt;/code&gt; uses a Material UI theme provider that adds Backstage’s specific styles. We want to replace this default theme provider with the one from your component library. To do this, you need to modify &lt;code class=&quot;language-text&quot;&gt;App.tsx&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt; import React from &apos;react&apos;;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import React, { ComponentType } from &apos;react&apos;;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import { ThemeProvider, PartialTheme } from &apos;@fluentui/react&apos;;
&lt;/span&gt;...
&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; const myTheme: PartialTheme = {
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   semanticColors: {
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     primaryButtonBackground: &apos;red&apos;,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     primaryButtonText: &apos;white&apos;,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   },
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; }
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; 
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; const MyThemeProvider: ComponentType&amp;lt;{}&gt; = ({ children }) =&gt; {
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   return (&amp;lt;ThemeProvider theme={myTheme}&gt;{children}&amp;lt;/ThemeProvider&gt;);
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; }
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;
&lt;/span&gt;const app = createApp({
&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; apis,
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  components: {
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;    ThemeProvider: MyThemeProvider,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;  }
&lt;/span&gt;})&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once you make these changes, your UI is now using your component library. Be aware that if you render any components that come with Backstage, they will not work because the default Backstage theme provider will be missing.&lt;/p&gt;
&lt;h2 id=&quot;use-backstage-catalog-api-to-fetch-data-and-display-it-in-a-table&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-backstage-catalog-api-to-fetch-data-and-display-it-in-a-table&quot; aria-label=&quot;use backstage catalog api to fetch data and display it in a table permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Backstage Catalog API to fetch data and display it in a table&lt;/h2&gt;
&lt;p&gt;The work that you did so far was to add a new theme to the Backstage component. You did this by modifying the frontend app. Other teams sometimes take a different approach where they create an entirely new Create React App project and import &lt;em&gt;that&lt;/em&gt; to their Backstage app. Starting a new project may seem appealing, but in practice you’d be giving up more features than you realize. One of the most important lost features is the ability to call data APIs provided by the Backstage framework.&lt;/p&gt;
&lt;p&gt;If your connection to the backend is intact, you can still use the data fetching API provided by Backstage. The Backstage UI components you deleted earlier already had data fetching implemented, which means the &lt;code class=&quot;language-text&quot;&gt;Home&lt;/code&gt; component you created is missing that functionality. I will now show how to use the data API to fetch data from the Backstage backend and display it in a &lt;code class=&quot;language-text&quot;&gt;DetailList&lt;/code&gt; component.&lt;/p&gt;
&lt;h2 id=&quot;make-catalog-api-available-in-your-application&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#make-catalog-api-available-in-your-application&quot; aria-label=&quot;make catalog api available in your application permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Make catalog API available in your application&lt;/h2&gt;
&lt;p&gt;First, install &lt;code class=&quot;language-text&quot;&gt;@backstage/catalog-client&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;yarn workspace app add @backstage/catalog-client&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can make the Catalog API available in your application by adding an API factory to the &lt;code class=&quot;language-text&quot;&gt;apis.ts&lt;/code&gt; file in your &lt;code class=&quot;language-text&quot;&gt;package/app/src/&lt;/code&gt; directory:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; createApiFactory,
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   discoveryApiRef
&lt;/span&gt;} from &apos;@backstage/core-plugin-api&apos;;
&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import { catalogApiRef } from &apos;@backstage/plugin-catalog-react&apos;;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import { CatalogClient } from &apos;@backstage/catalog-client&apos;;
&lt;/span&gt;
export const apis: AnyApiFactory[] = [
&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   createApiFactory({
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     api: catalogApiRef,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     deps: { discoveryApi: discoveryApiRef },
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     factory: ({ discoveryApi }) =&gt; new CatalogClient({ discoveryApi })
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   }),
&lt;/span&gt;&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; createApiFactory({&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s unpack what you see above. You will use the Catalog API reference (which comes from &lt;code class=&quot;language-text&quot;&gt;@backstage/plugin-catalog-react&lt;/code&gt;) to look up the API in your components when using the &lt;code class=&quot;language-text&quot;&gt;useApi&lt;/code&gt; hook. The &lt;code class=&quot;language-text&quot;&gt;AnyApiFactory&lt;/code&gt; factory controls how the Catalog Client is created. &lt;code class=&quot;language-text&quot;&gt;CatalogClient&lt;/code&gt; needs &lt;code class=&quot;language-text&quot;&gt;DiscoveryApiRef&lt;/code&gt;, which provides the factory access to the &lt;code class=&quot;language-text&quot;&gt;DiscoveryApi&lt;/code&gt;. The DiscoveryApi is used to find the URL where the Backstage Catalog API can be found. This piping will make it easy to call the API in future steps.&lt;/p&gt;
&lt;h2 id=&quot;use-useapi-hook-to-get-the-catalogapi&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-useapi-hook-to-get-the-catalogapi&quot; aria-label=&quot;use useapi hook to get the catalogapi permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use &lt;code class=&quot;language-text&quot;&gt;useApi&lt;/code&gt; hook to get the CatalogApi&lt;/h2&gt;
&lt;p&gt;Let’s get rid of the &lt;code class=&quot;language-text&quot;&gt;PrimaryButton&lt;/code&gt; from earlier and make the following additional changes in your &lt;code class=&quot;language-text&quot;&gt;Home&lt;/code&gt; component:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt; import { PrimaryButton } from &apos;@fluentui/react&apos;;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import { catalogApiRef } from &apos;@backstage/plugin-catalog-react&apos;;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import { useApi } from &apos;@backstage/core-plugin-api&apos;;
&lt;/span&gt;
export const Home = () =&gt; {
&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt;   return &amp;lt;PrimaryButton&gt;Press me!&amp;lt;/PrimaryButton&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   const catalogApi = useApi(catalogApiRef);
&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This provides your component with access to reference to the Catalog API. As a result, we can call this API to retrieve data from the Catalog API.&lt;/p&gt;
&lt;h2 id=&quot;use-useasync-hook-to-call-the-catalogapi&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-useasync-hook-to-call-the-catalogapi&quot; aria-label=&quot;use useasync hook to call the catalogapi permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use &lt;code class=&quot;language-text&quot;&gt;useAsync&lt;/code&gt; hook to call the CatalogApi&lt;/h2&gt;
&lt;p&gt;To call the CatalogApi, we need to call &lt;code class=&quot;language-text&quot;&gt;catalogApi.getEntities&lt;/code&gt; function. This function needs to be called with our component renders. We can use the &lt;code class=&quot;language-text&quot;&gt;useAsync&lt;/code&gt; hook to call &lt;code class=&quot;language-text&quot;&gt;catalogApi.getEntities&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import useAsync from &apos;react-use/lib/useAsync&apos;;
&lt;/span&gt;
export const Home = () =&gt; {
&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; const catalogApi = useApi(catalogApiRef);
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   const {
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     value = { items: [] },
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     // loading,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     // error,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   } = useAsync(() =&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     catalogApi.getEntities({
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;       filter: {
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;         kind: &apos;Component&apos;,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;       },
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     }),
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   );
&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We could implement the same thing with &lt;code class=&quot;language-text&quot;&gt;useEffect&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;useState&lt;/code&gt; but it’s a lot more work. &lt;code class=&quot;language-text&quot;&gt;useAsync&lt;/code&gt; automatically gives us &lt;code class=&quot;language-text&quot;&gt;loading&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;error&lt;/code&gt; values so we don’t need to handle those situations manually.&lt;/p&gt;
&lt;h2 id=&quot;use-usememo-hook-to-convert-result-from-catalogapi-into-items-for-detailslist&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-usememo-hook-to-convert-result-from-catalogapi-into-items-for-detailslist&quot; aria-label=&quot;use usememo hook to convert result from catalogapi into items for detailslist permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use &lt;code class=&quot;language-text&quot;&gt;useMemo&lt;/code&gt; hook to convert result from CatalogApi into items for &lt;code class=&quot;language-text&quot;&gt;DetailsList&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;FluentUI’s &lt;code class=&quot;language-text&quot;&gt;DetailList&lt;/code&gt; needs to convert results from the CatalogApi. The data needs to be in a specific format so that we can display it in the table:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token deleted-sign deleted&quot;&gt;&lt;span class=&quot;token prefix deleted&quot;&gt;-&lt;/span&gt; import React from &apos;react&apos;;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import React, { useMemo } from &apos;react&apos;;
&lt;/span&gt;
export const Home = () =&gt; {
&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; ...
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   const items = useMemo(
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     () =&gt;
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;       value.items.map(item =&gt; ({
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;         key: item.metadata.uid,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;         name: item.metadata.name,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;         description: item.metadata.description,
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;       })),
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;     [value],
&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   );
&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;useMemo&lt;/code&gt; allows us to covert the response from a CatalogApi response format to DetailList format and cache the result. The caching part is important because without it the list will re-render every time anything in that component changes.&lt;/p&gt;
&lt;h2 id=&quot;render-detaillist-with-items&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#render-detaillist-with-items&quot; aria-label=&quot;render detaillist with items permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Render &lt;code class=&quot;language-text&quot;&gt;DetailList&lt;/code&gt; with items&lt;/h2&gt;
&lt;p&gt;The final step is to import &lt;code class=&quot;language-text&quot;&gt;DetailList&lt;/code&gt; from &lt;code class=&quot;language-text&quot;&gt;@fluentui/react&lt;/code&gt; and render it. Making this last change should generate a list of items from the catalog using the Catalog API and rendered in the components from FluentUI library:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;diff&quot;&gt;&lt;pre class=&quot;language-diff&quot;&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt; import { DetailsList } from &apos;@fluentui/react&apos;;
&lt;/span&gt;
export const Home = () =&gt; {
&lt;span class=&quot;token unchanged&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt; ...
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;   return &amp;lt;DetailsList items={items} /&gt;;
&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To check to make sure these new changes are working properly, run &lt;code class=&quot;language-text&quot;&gt;yarn dev&lt;/code&gt; (you’ll need the backend to be running too).&lt;/p&gt;
&lt;p&gt;This whole process is a bit involved but doing it this way saves you a lot of trouble in the long run by allowing you to use the data fetching APIs that come with Backstage plugins.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, I showed you how to clean up the frontend application in preparation for using your own component library, install a component library other than Material UI, override the theme provider to use your component library’s theme provider, and use Backstage’s data fetching API provided by the Catalog API plugin.&lt;/p&gt;
&lt;p&gt;This is the “right” way to use your company’s component library because it allows you to use it without completely eliminating all of the benefits that the Backstage framework provides in the frontend application. You might not be able to use the components that Backstage plugins provide because they are tied to Material UI, but you can still use the data fetching APIs that idiomatic Backstage plugins include.&lt;/p&gt;
&lt;p&gt;I hope you enjoyed this tutorial and learned something about Backstage. You can find me on &lt;a href=&quot;https://twitter.com/tarasm&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Twitter&lt;/a&gt;, &lt;a href=&quot;https://github.com/taras&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GitHub&lt;/a&gt;, or via email - &lt;a href=&quot;mailto:tarasm@frontside.com&quot;&gt;tarasm@frontside.com&lt;/a&gt;. All of the code from this tutorial can be found in &lt;a href=&quot;https://github.com/taras/backstage-custom-frontend&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://github.com/taras/backstage-custom-frontend&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/20b208f9f906897d36d20a0ea7065e58/2a4de/2022-backstage-components.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[When to use SemVer or CalVer: project type considerations]]></title><description><![CDATA[Choosing a versioning scheme helps you manage the understanding and expectations of your project over time. In this article, you'll learn about how to decide on whether to use SemVer or CalVer according to your project type. ]]></description><link>https://frontside.com/blog/2022-02-09-semver-or-calver-by-project-type/</link><guid isPermaLink="false">https://frontside.com/blog/2022-02-09-semver-or-calver-by-project-type/</guid><category><![CDATA[dx]]></category><dc:creator><![CDATA[Jacob Bolda]]></dc:creator><pubDate>Wed, 09 Feb 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Reaching meaningful versions is more than setting a number within a package&apos;s main file (e.g., package.json, pubspec.yaml, etc.). Versioning aims to build up quality metadata that humans and computers can understand. With this metadata, you can understand the impact a change will have downstream and communicate with users more effectively.&lt;/p&gt;
&lt;p&gt;The two most common versioning schemes—SemVer (semantic versioning) and CalVer (calendar versioning)—can help you build the desired aggregated understanding. But going with either of them is not a boolean choice but a spectrum whose adherence specifications you must outline depending on your project&apos;s needs and circumstances.&lt;/p&gt;
&lt;p&gt;For instance, strict SemVer tends to have the most value in libraries because it is easy to offer rationales for changes and tie them to version numbers. But as codebases become larger and more multifaceted or marketing gets involved, the decision to cut a major version release becomes less about breaking changes and more driven by external factors.&lt;/p&gt;
&lt;p&gt;On the other hand, projects with large, shifting codebases tend to prefer using the year for the major version. This works particularly well if there is a Long Term Support (LTS) and maintenance release schedule, as in &lt;a href=&quot;https://calver.org/#ubuntu&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;the case of Ubuntu&lt;/a&gt;. It might also lend itself well as a scheme for marketing purposes.&lt;/p&gt;
&lt;p&gt;In this article, I&apos;ll outline the notions behind SemVer and CalVer and then propose considerations for which versioning scheme to use depending on whether your project is a library, an app, a service that expects breakage, or an additive-only service.&lt;/p&gt;
&lt;h2 id=&quot;what-is-semver&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-semver&quot; aria-label=&quot;what is semver permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is SemVer?&lt;/h2&gt;
&lt;p&gt;SemVer&apos;s &lt;a href=&quot;https://semver.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;fundamental rules&lt;/a&gt; are simple:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Given a version number MAJOR.MINOR.PATCH, increment the:
1. MAJOR version when you make incompatible API changes,
2. MINOR version when you add functionality in a backward-compatible manner, and
3. PATCH version when you make backward-compatible bug fixes.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, it is hard to track which version we are dealing with in a living codebase with dozens of developers continuously contributing changes. Thankfully, teams can nowadays set up tools like &lt;a href=&quot;https://github.com/changesets/changesets&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;changesets&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://github.com/jbolda/covector&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;covector&lt;/code&gt;&lt;/a&gt; (for monorepos) to automatically aggregate versions. That means that the team must clearly define bump strategies so that all developers have a consistent understanding of the different kinds of changes.&lt;/p&gt;
&lt;p&gt;Furthermore, adhering to SemVer&apos;s strict definition is not always convenient. For instance, a project may only rely on a &lt;code class=&quot;language-text&quot;&gt;MAJOR.MINOR&lt;/code&gt; and group all bug fixes and features into a minor release. Or a team may use &lt;code class=&quot;language-text&quot;&gt;MAJOR.MINOR.PATCH&lt;/code&gt; internally when publishing and releasing, but only publicly release the &lt;code class=&quot;language-text&quot;&gt;MAJOR&lt;/code&gt; version for consumption. The critical consideration is that the strategy employed is communicated clearly and then consistently used.&lt;/p&gt;
&lt;h2 id=&quot;what-is-calver&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-calver&quot; aria-label=&quot;what is calver permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is CalVer?&lt;/h2&gt;
&lt;p&gt;While SemVer proposes rules that determine the version number, CalVer invites its adopters to define their scheme, considering how time impacts their project. The scheme structure is similar, &lt;code class=&quot;language-text&quot;&gt;MAJOR.MINOR.MICRO&lt;/code&gt;, but what each segment means is more fluid. In most cases, the &lt;code class=&quot;language-text&quot;&gt;MAJOR&lt;/code&gt; number is linked to the year of the release. For &lt;code class=&quot;language-text&quot;&gt;MINOR&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;MICRO&lt;/code&gt;, CalVer adopters use ad-hoc strategies and combine notions from &lt;code class=&quot;language-text&quot;&gt;SemVer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;CalVer has natural synergies with marketing schedules, as they can be tied to the shared time-based milestones.&lt;/p&gt;
&lt;h2 id=&quot;versioning-considerations-by-project-nature&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#versioning-considerations-by-project-nature&quot; aria-label=&quot;versioning considerations by project nature permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Versioning considerations by project nature&lt;/h2&gt;
&lt;p&gt;One way to resolve the question of which versioning model to adopt is to let the nature of your project decide for you.&lt;/p&gt;
&lt;h3 id=&quot;libraries&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#libraries&quot; aria-label=&quot;libraries permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Libraries&lt;/h3&gt;
&lt;p&gt;A library lends itself well to versioning using SemVer. Smaller scoped libraries with well-understood changes and impacts can more naturally adopt SemVer in a relatively strict manner. But as the velocity of code (the number of commits in a given period) increases and inter-dependencies build up, decisions around major and minor become more involved, and you might choose to loosen the stringent requirements.&lt;/p&gt;
&lt;p&gt;As code velocity increases, it makes sense to group commits into larger releases. But as this progression happens, it becomes more challenging to release a package separate from other changes that have been committed to the monorepo. In light of this, SemVer allows for dependencies within a monorepo to calculate a bump for related packages in response to a specific code change.&lt;/p&gt;
&lt;h3 id=&quot;web-apps--mobile-apps&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#web-apps--mobile-apps&quot; aria-label=&quot;web apps  mobile apps permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Web apps / mobile apps&lt;/h3&gt;
&lt;p&gt;The value and schema of a version number have different expectations in web or mobile apps because users will rarely be concerned about it. Thus the choice between SemVer and CalVer lies less in the nature of the codebase nature or its users but rather in external influences. A user may not see internal shifts in the code, but they will notice an extensive design refresh, which is often tied to marketing efforts.&lt;/p&gt;
&lt;p&gt;The different expectation doesn&apos;t necessarily dictate one option over the other, as either would allow communication between the user and support and the user/support to the developer. Instead, the release cadence and marketing schedules will most likely dictate the versioning scheme. The app may have a plan that best matches releases at CalVer’s specific time intervals, which is often seen in Tax prep software offerings. If there is no synergy with other departments, following SemVer is probably simpler for developers.&lt;/p&gt;
&lt;h3 id=&quot;services-that-expect-breakages&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#services-that-expect-breakages&quot; aria-label=&quot;services that expect breakages permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Services that expect breakages&lt;/h3&gt;
&lt;p&gt;Services such as REST are designed with the expectation of breaking changes and it is common for REST APIs to use the major version within the URL. The incremental changes may be internally considered a minor and a patch version, but the external version may only be a major version. The SemVer scheme seems to lend itself well to services, but maintaining many service versions increases complexity.&lt;/p&gt;
&lt;h2 id=&quot;additive-only-services&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#additive-only-services&quot; aria-label=&quot;additive only services permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Additive-only Services&lt;/h2&gt;
&lt;p&gt;An additive-only schema paradigm (where every change can only add to the schema and not cause any breaking changes) has recently come to the forefront. This paradigm devalues major, minor, and patch use, as every release should theoretically be minor. However, in reality there could be breaking changes, but such changes would be elegantly handled through deprecations. As the schema is adjusted, fields can be marked as deprecated. These fields still allow use but will be monitored, and completely removed from the schema when their activity falls below a threshold (while this is technically a breaking change, messaging about a major change does not need to be created to prepare developers to make these changes on a timed schedule).&lt;/p&gt;
&lt;p&gt;In light of this rhythm, a case could be made for CalVer. Deprecated fields below the activity threshold could be removed on an annual cadence and the major version bumped to a new year. Every other change only needs to communicate the addition to the schema, expressed by bumping the second number or minor version (there may not be value in using a patch version in this situation).&lt;/p&gt;
&lt;h2 id=&quot;conclusion-and-recommendations&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion-and-recommendations&quot; aria-label=&quot;conclusion and recommendations permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion and Recommendations&lt;/h2&gt;
&lt;p&gt;In general, developers find it easier to work with a SemVer scheme because it&apos;s more intuitive given that it&apos;s closer to the code. But as projects grow, more considerations have to be made to define a versioning scheme that communicates effectively with users.&lt;/p&gt;
&lt;p&gt;It is also not uncommon for projects to change their versioning scheme as they evolve. A project started using strict SemVer doesn’t have stick with that approach; don&apos;t be afraid of revising that decision further down the line if it&apos;s causing churn or confusion for developers, users, or other teams.&lt;/p&gt;
&lt;p&gt;But no matter what you decide, explicit definitions of your versioning scheme helps developers and users navigate changes and expectations over time. Be sure that these norms are written down and accessible for all stakeholders.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/375aab58fb3c31794777d331cd33884a/2a4de/2022-versioning.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[What is DX anyway: a chronological overview]]></title><description><![CDATA[You can only optimize for concrete indicators, that’s why having a clear understanding of DX is important to improve it. In this article, we review the main trends of the past decade.]]></description><link>https://frontside.com/blog/2022-01-26-what-is-dx/</link><guid isPermaLink="false">https://frontside.com/blog/2022-01-26-what-is-dx/</guid><category><![CDATA[dx]]></category><category><![CDATA[newsletter]]></category><dc:creator><![CDATA[Jorge Lainfiesta]]></dc:creator><pubDate>Wed, 26 Jan 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It was bound to happen: after UX (user experience) and CX (customer experience) it was only a matter of time before DX (Developer Experience) took center stage. Nowadays it&apos;s in the marketing copy of every library and product aimed at developers. But what does DX mean?&lt;/p&gt;
&lt;p&gt;As it turns out, the definition of DX has evolved in important ways over the past decade. This month in the DX Newsletter, we’ll review three trends found in academic and industry articles to set the stage for a broader conversation.&lt;/p&gt;
&lt;h2 id=&quot;1-the-first-traces-of-dx&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-the-first-traces-of-dx&quot; aria-label=&quot;1 the first traces of dx permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. The first traces of DX&lt;/h2&gt;
&lt;p&gt;The combination of “developer” and “experience” yields a jumble of ambiguous concepts throughout the years. For instance, most results point to the seniority of a developer.&lt;/p&gt;
&lt;p&gt;But as we understand it today, “Developer Experience” was used first in 2012 in a paper by Finnish Ph.D. candidates &lt;a href=&quot;https://ieeexplore.ieee.org/document/6225984&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;published in the renowned technical journal IEEE&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The authors built a conceptual framework for Developer Experience, drawing concepts from psychology and UX practice:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2022-what-is-dx-psychology.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;A diagram depecting three dimensions of DX: cognition, affect, and connation&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Adapted from Figure 1: Developer Experience: Conceptual Framework (*Fagerholm F. and Münch J., 2012).&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;2-the-code-centered-era-of-dx&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-the-code-centered-era-of-dx&quot; aria-label=&quot;2 the code centered era of dx permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. The code-centered era of DX&lt;/h2&gt;
&lt;p&gt;Subsequently, most references to DX before 2021 were mainly concerned with code, with API ergonomics, documentation, and a support community taking a privileged place.&lt;/p&gt;
&lt;p&gt;For example, as &lt;a href=&quot;https://www.redhat.com/architect/developer-experience&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Red Hat argued in 2020&lt;/a&gt;, good documentation and a welcoming community are “essential parts” of DX and will help you decide if it’s even worth trying out an API, no matter how “ergonomic” its creators deem it to be.&lt;/p&gt;
&lt;p&gt;For teams creating tools, services, or products for developers, Sam Jarman wrote an &lt;a href=&quot;https://hackernoon.com/the-best-practices-for-a-great-developer-experience-dx-9036834382b0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ever-green DX guide back in 2017&lt;/a&gt; with practical considerations to improve any API’s documentation and distribution.&lt;/p&gt;
&lt;h2 id=&quot;3-holistic-dx-the-present-and-future&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-holistic-dx-the-present-and-future&quot; aria-label=&quot;3 holistic dx the present and future permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. Holistic DX: the present and future&lt;/h2&gt;
&lt;p&gt;Code is fundamental in DX, but developers spend only around a third of their time coding. In 2021, we’ve come full circle from 2012’s psychology-based definition of Developer Experience. Now the attention is back to the developer as a whole: tools are still a focus, but so are factors like psychological safety.&lt;/p&gt;
&lt;p&gt;Jean Yang, CEO of Akita Software and former professor of Computer Science at Carnegie Mellon University, &lt;a href=&quot;https://future.a16z.com/the-case-for-developer-experience/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;proposes that DX has two aspects&lt;/a&gt;: one is abstracting complexity away, and the other (less explored purpose) is helping developers navigate complexity. Developers face messy and complex problems in their daily work, and can rarely swap their systems for new abstract “dev-friendly” tools.&lt;/p&gt;
&lt;p&gt;In sum, improving the Developer Experience for any team is a holistic endeavor that encompasses technology, working practices, and organizational enablement. As &lt;a href=&quot;https://clouddamcdnprodep.azureedge.net/gdc/gdclVJnEl/original?ocid=eml_pg243447_gdc_comm_mw&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Microsoft explained in a review of four industry case studies&lt;/a&gt;, companies undertake multi-year plans to improve their DX to achieve more productivity and better retention rates.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Originally published in our DX Newsletter. Subscribe below!&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><media:content url="https://frontside.com/static/e41712679e606c5f80d5a10ab3e2ef92/2a4de/2022-what-is-dx.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Tutorial: Easier onboarding with Backstage and VSCode dev containers]]></title><description><![CDATA[In this tutorial, you'll learn how to set up dev containers to make it easier to onboard developers.]]></description><link>https://frontside.com/blog/2022-01-24-backstage-with-vscode/</link><guid isPermaLink="false">https://frontside.com/blog/2022-01-24-backstage-with-vscode/</guid><category><![CDATA[backstage]]></category><dc:creator><![CDATA[Min Kim]]></dc:creator><pubDate>Mon, 24 Jan 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;An often underrated aspect of developer onboarding is how quickly a new contributor can go from cloning the source code to running the project on their machine. An onboarding experience full of friction can be discouraging and leave a poor impression, while a smooth one is valuable for new and seasoned contributors alike.&lt;/p&gt;
&lt;p&gt;However, onboarding can be especially challenging for &lt;a href=&quot;https://backstage.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Backstage&lt;/a&gt; because it is a full-stack application. Developing a Backstage-based Developer Portal requires having a recent version of Node.js, Yarn, and PostgreSQL running on the developer&apos;s machine. These are relatively easy to install on macOS and Linux but can be challenging on Windows, especially for someone new to the Node.js ecosystem.&lt;/p&gt;
&lt;p&gt;At Frontside, we&apos;ve had success improving onboarding by using &lt;a href=&quot;https://code.visualstudio.com/docs/remote/containers&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;dev containers&lt;/a&gt;, which spins up a docker-based local environment with all the dependencies that a project needs.&lt;/p&gt;
&lt;p&gt;Dev containers has a CLI called &lt;a href=&quot;https://code.visualstudio.com/docs/remote/devcontainer-cli&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;devcontainer-cli&lt;/a&gt; you can use to open the container from the command line. It will open in VSCode, which uses &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Remote Containers Extension&lt;/a&gt; to create a smooth integration.&lt;/p&gt;
&lt;p&gt;For the most part, running dev containers inside VSCode feels like the application is running on your machine. Once you&apos;ve added dev containers to your project, there’s a clear pathway to adopting GitHub Codespaces, which &lt;a href=&quot;https://github.blog/2021-08-11-githubs-engineering-team-moved-codespaces/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;makes onboarding even easier&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This blog post will explain setting up dev containers for Backstage projects as a first step to create a streamlined onboarding for developers.&lt;/p&gt;
&lt;h2 id=&quot;requirements&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#requirements&quot; aria-label=&quot;requirements permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Requirements&lt;/h2&gt;
&lt;p&gt;Before you get started, make sure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/Download&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Remote Containers Extension for VSCode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.docker.com/products/docker-desktop&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Docker Desktop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/compose/install/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Docker Compose&lt;/a&gt; (if you&apos;re running Linux)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;create-a-backstage-app&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#create-a-backstage-app&quot; aria-label=&quot;create a backstage app permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create a Backstage App&lt;/h2&gt;
&lt;p&gt;To spin up a dev container, you first need a project to work from. You can instantiate a Backstage app using &lt;code class=&quot;language-text&quot;&gt;@backstage/create-app&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npx @backstage/create-app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For this tutorial, you&apos;ll be using PostgreSQL:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2022-01-24-backstage-devcontainer/backstage-create-app.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;backstage-create-app&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Once the app is done installing, open the new app&apos;s workspace in visual studio code and set up a dev container.&lt;/p&gt;
&lt;h2 id=&quot;opening-a-project-inside-a-dev-container&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#opening-a-project-inside-a-dev-container&quot; aria-label=&quot;opening a project inside a dev container permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Opening a Project inside a dev container&lt;/h2&gt;
&lt;p&gt;If you have the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Remote Containers&lt;/code&gt;&lt;/a&gt; extension installed, you should be able to access its commands. Press &lt;code class=&quot;language-text&quot;&gt;F1&lt;/code&gt; and select &lt;code class=&quot;language-text&quot;&gt;Remote-Containers: Open Folder in Container...&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2022-01-24-backstage-devcontainer/remote-containers-open.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;open-folder-container&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;VSCode will detect that you do not have dev container configurations yet and prompt you to select a predefined container. You can go ahead and select any of them, as you&apos;ll be replacing all of those configurations later.&lt;/p&gt;
&lt;p&gt;Once you make your selection, VSCode will create configuration files in the &lt;code class=&quot;language-text&quot;&gt;.devcontainer&lt;/code&gt; directory, build the container according to those files, and launch your workspace in the container. (You can go to your Docker Desktop dashboard to confirm that the new container is running.)&lt;/p&gt;
&lt;p&gt;If you change your dev container configuration, you can run &lt;code class=&quot;language-text&quot;&gt;Remote-Containers: Rebuild Container&lt;/code&gt;. And when you are ready to exit out of your dev container, run &lt;code class=&quot;language-text&quot;&gt;Remote-Containers: Reopen Folder Locally&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now that you know how to launch and exit out of dev containers, you need to add configurations to run Backstage.&lt;/p&gt;
&lt;h2 id=&quot;docker-compose---postgres&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#docker-compose---postgres&quot; aria-label=&quot;docker compose   postgres permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Docker Compose - Postgres&lt;/h2&gt;
&lt;p&gt;If you try to start up Backstage now, you&apos;ll get an error in the terminal about there being no database to connect to. This is because you&apos;re not running an instance of Postgres yet, so you should start there. At the root of your project workspace create a &lt;code class=&quot;language-text&quot;&gt;docker-compose.yaml&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;3.8&quot;&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;my_postgres_db&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; postgres
    &lt;span class=&quot;token key atrule&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;POSTGRES_USER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; postgres_username
      &lt;span class=&quot;token key atrule&quot;&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; postgres_password&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You&apos;re creating a &lt;code class=&quot;language-text&quot;&gt;my_postgres_db&lt;/code&gt; service with the official &lt;a href=&quot;https://hub.docker.com/_/postgres&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;postgres docker image&lt;/a&gt; and providing it a username and password to bootstrap a Postgres account for local development.&lt;/p&gt;
&lt;h2 id=&quot;docker-compose---dev-container&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#docker-compose---dev-container&quot; aria-label=&quot;docker compose   dev container permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Docker Compose - dev container &lt;/h2&gt;
&lt;p&gt;Next, create a service for your dev container (this will replace the one that VSCode automatically generated earlier).&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;my_postgres_db&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;my_devcontainer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; mcr.microsoft.com/vscode/devcontainers/typescript&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;node&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /bin/sh &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;c &quot;while sleep 1000; do&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;; done&quot;
    &lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; .&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/workspace
    &lt;span class=&quot;token key atrule&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;POSTGRES_HOST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; my_postgres_db
      &lt;span class=&quot;token key atrule&quot;&gt;POSTGRES_USER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; postgres_username
      &lt;span class=&quot;token key atrule&quot;&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; postgres_password&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For your dev container image, you’re using one of the docker images &lt;a href=&quot;https://hub.docker.com/_/microsoft-vscode-devcontainers&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;created by Microsoft&lt;/a&gt; and running a shell command to prevent the container from exiting on its own as suggested in the &lt;a href=&quot;https://code.visualstudio.com/docs/remote/create-dev-container#_use-docker-compose&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;devcontainer docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For a container to have all of the files of the backstage app, you need to add &lt;code class=&quot;language-text&quot;&gt;volumes: .:/workspace&lt;/code&gt; as shown in the previous snippet. This will take the current directory (relative to the docker-compose file) and copy its contents to your container&apos;s &lt;code class=&quot;language-text&quot;&gt;/workspace&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;You&apos;re also passing in environment variables to access the local instance of Postgres. These should correspond to the values you specified when creating the &lt;code class=&quot;language-text&quot;&gt;my_postgres_db&lt;/code&gt; service. (Alternatively, you could provide these values as environment variables and pass them through the start script of your backstage backend.)&lt;/p&gt;
&lt;h2 id=&quot;rebuild-devcontainer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#rebuild-devcontainer&quot; aria-label=&quot;rebuild devcontainer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Rebuild &lt;code class=&quot;language-text&quot;&gt;devcontainer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Now you need to update your dev container configurations to use the docker-compose file you created:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// .devcontainers/devcontainer.json&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;dockerComposeFile&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../docker-compose.yaml&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;my_devcontainer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;workspaceFolder&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/workspace&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For these changes to be applied, you will need to rebuild your dev container by running either &lt;code class=&quot;language-text&quot;&gt;Remote-Containers: Rebuild Container&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;Rebuild and Reopen in Container&lt;/code&gt;, depending on if you returned to your local environment or if you&apos;re still in the first dev container you launched. You can go ahead and delete the other files that were created inside &lt;code class=&quot;language-text&quot;&gt;.devcontainer/&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;using-persistent-volumes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#using-persistent-volumes&quot; aria-label=&quot;using persistent volumes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using Persistent Volumes&lt;/h2&gt;
&lt;p&gt;At this point, if you try to add a dependency or run &lt;code class=&quot;language-text&quot;&gt;yarn install&lt;/code&gt;, you may notice that it takes much longer than it usually does in your local environment. This is because when you create files in a docker container, it writes to the container&apos;s writable layer, which is not very fast. The standard practice (as suggested by &lt;a href=&quot;https://docs.docker.com/storage/volumes/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;docker docs&lt;/a&gt;) is to use volumes.&lt;/p&gt;
&lt;p&gt;In your docker-compose file, add the three node_modules directories of your backstage app:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;my_postgres_db&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;my_devcontainer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; .&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/workspace
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; /workspace/node_modules
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; /workspace/packages/app/node_modules
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; /workspace/packages/backend/node_modules&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This syntax can be a little confusing at first, and you may be wondering if and why &lt;code class=&quot;language-text&quot;&gt;.:/workspace&lt;/code&gt; omits &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt;. Although they are nested under the same &lt;code class=&quot;language-text&quot;&gt;volumes&lt;/code&gt; property, what they achieve is different. When you specify both a source and target path, docker-compose will treat that as a bind mount. But when you pass in only a target path, docker-compose will create an anonymous volume.&lt;/p&gt;
&lt;p&gt;What&apos;s happening here is docker-compose first copies your backstage app to the &lt;code class=&quot;language-text&quot;&gt;/workspace&lt;/code&gt; directory of your dev container and then maps out the contents of node_modules to persistent volumes. You can read more about the differences between a bind mount and a volume &lt;a href=&quot;https://docs.docker.com/storage/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once you complete these steps and rebuild and reopen your dev container, you should see a significant improvement when you run &lt;code class=&quot;language-text&quot;&gt;yarn install&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;dev-containers-are-a-first-step&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#dev-containers-are-a-first-step&quot; aria-label=&quot;dev containers are a first step permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Dev containers are a first step&lt;/h2&gt;
&lt;p&gt;Now that you know how to set up dev containers optimized for Backstage development, you can make it easier for your teammates to contribute to your Developer Portal (regardless of whether they use macOS, Linux or Windows) by including the settings explained in this tutorial in your repository.&lt;/p&gt;
&lt;p&gt;The setup we explained in this tutorial also allows people to opt-in (or not) to running dev containers, so these changes do not affect anybody with other local development preferences.&lt;/p&gt;
&lt;p&gt;Dev containers are meant to lower barriers for those who cannot run the project locally. However, it&apos;s important to point out that even though dev containers are a convenient way to run the project, the DX of developing in a dev container is still inferior in some ways to running the project locally because it introduces the overhead of running Docker containers. With that said, we still believe that they are a handy tool and will drive the DX of your project in the right direction.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/69c0454f06a75c884b68d6358a0058af/2a4de/2022-backstage-dev-containers-windows.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Simplified local development and testing with Auth0 simulation]]></title><description><![CDATA[Auth0 can be difficult to manage in local development and within testing environments such as CI/CD pipelines. An Auth0 simulator can save you from branching your code or maintaining mocks in your tests.]]></description><link>https://frontside.com/blog/2022-01-13-auth0-simulator/</link><guid isPermaLink="false">https://frontside.com/blog/2022-01-13-auth0-simulator/</guid><category><![CDATA[dx]]></category><category><![CDATA[simulation]]></category><category><![CDATA[testing]]></category><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Paul Cowan]]></dc:creator><pubDate>Thu, 13 Jan 2022 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Auth0 is an excellent service that lets you focus on your app instead of trying to stay up to date with the latest safe and secure authentication practices. However, what’s not so great is having to use Auth0 as part of your local development process or within end-to-end tests.&lt;/p&gt;
&lt;p&gt;Recently I had a tough time using Auth0 while running tests that required authentication in a continuous integration environment with no access to the internet. The issue emerged because adding logical branches to my code targeting specific environments and stubbing functions at the test level leaves room for undesired effects.&lt;/p&gt;
&lt;p&gt;There are many ways you can address the issue, but most of them are a disaster. Probably the most naïve solution is to write conditionals that check which environment the code is currently running against. Consider this example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;redirectToFakeAuthentication&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loginWithDefaultDirectory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    username&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    password&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// etc.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This kind of conditional forks your app by environment, leading to bugs escaping into production because developers and tests don&apos;t really assess the same app that ends up being deployed but a version catered for them only.&lt;/p&gt;
&lt;p&gt;Unfortunately mocking or stubbing calls to Auth0 in a unit or end-to-end test never ends well either. It usually leads to an explosion of mocking code that you must maintain through every change. It may start small, as in the following snippet:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;mockConfig&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doMock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;../auth_config.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;test-domain.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      clientId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; virtual&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But further down the line, you&apos;ll find yourself writing mock JSON web tokens (JWTs) and specifying key algorithms, which means wasting precious development time. Before you know it, token checking code has crept into the tests (and who wants to maintain test helpers like this?):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;verifyAuth0Token&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reject&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    jwt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;verify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; getKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; algorithms&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;RS256&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; decoded&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;decoded&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Packages like &lt;a href=&quot;https://www.npmjs.com/package/mock-jwks&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;mock-jwks&lt;/a&gt; help, but it’s still code that needs to be maintained, and as we all know, the less code we write, the fewer problems we have.&lt;/p&gt;
&lt;p&gt;At last, we arrive at what seems to be the most popular solution but which is arguably the worst: to create phoney Auth0 accounts in multiple environments, as documented in &lt;a href=&quot;https://auth0.com/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;this post&lt;/a&gt;. This is needless overhead. You&apos;ll have to keep all these environments or tenants in sync, and it does not cure the problem of running end-to-end tests behind a firewall with no internet.&lt;/p&gt;
&lt;p&gt;Another downside of this approach is that all tests that use a particular phoney account will share state in different tests. Auth0 tenants are not scalable, which means we&apos;d be moving headfirst into a maintainability nightmare.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#solution&quot; aria-label=&quot;solution permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Solution&lt;/h2&gt;
&lt;p&gt;However, the unworkable “solutions” presented above also point to the principle that will guide our workable one: namely that we should always strive to have the same code running in every environment. The only difference should be the configuration.
For example, in production we might have this auth0 configuration:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;domain&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;myapp.eu.auth0.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;clientId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PMkiueyWaFdfsbAKXrIpVPmyBTFs4g5iq&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;audience&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://thefrontside.auth0.com/api/v1/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// etc.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And in non-production environments it might look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;domain&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;localhost:4400&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;clientId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;00000000000000000000000000000000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;audience&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://your-audience/&quot;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// etc.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only discernable difference is the &lt;code class=&quot;language-text&quot;&gt;domain&lt;/code&gt; field, which points to a localhost when running in non-production environments (such as your very own laptop or maybe even in a continuous integration environment (CI) that does not have access to the internet).&lt;/p&gt;
&lt;p&gt;Imagine your very own Auth0 server running locally to configure specific scenarios while developing or running tests. What if we called it “auth0 simulator” and allowed you to create fake data without cluttering up your existing codebase?&lt;/p&gt;
&lt;h2 id=&quot;auth0-simulator&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#auth0-simulator&quot; aria-label=&quot;auth0 simulator permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Auth0 simulator&lt;/h2&gt;
&lt;p&gt;As chance would have it, such a beast exists as part of the &lt;a href=&quot;https://github.com/thefrontside/simulacrum&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;simulacrum&lt;/a&gt; suite of tools, created to help simulate complex external bounded contexts such as LDAP or Auth0.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/thefrontside/simulacrum/tree/v0/packages/auth0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@simulacrum/auth0-simulator&lt;/a&gt; package is your very own Auth0 simulator that eliminates the need to log into Auth0 while developing in a non-production environment. It is enormously helpful in local development and end-to-end testing – and even features ready-to-use integrations with Cypress!&lt;/p&gt;
&lt;h2 id=&quot;start-your-engines&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#start-your-engines&quot; aria-label=&quot;start your engines permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Start your engines&lt;/h2&gt;
&lt;p&gt;To use it you&apos;ll first need to set up a simulation. You can either create your simulation using a &lt;a href=&quot;https://github.com/thefrontside/simulacrum/tree/v0/packages/auth0#graphql&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GraphQL interface&lt;/a&gt; or through the &lt;code class=&quot;language-text&quot;&gt;@simulacrum/client&lt;/code&gt; JavaScript package:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setupClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; url &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; simulation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createSimulation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;auth0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    options&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      audience&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;https://your-audience/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;openid profile email offline_access&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      clientId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;YOUR_AUTH0_CLIENT_ID&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    services&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      auth0&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        port&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// port for the auth0 service itself&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;auth0 service running at &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;simulation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;services&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; person &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;given&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;simulation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;person&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;username = &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; password = &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;password&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Fake users are created through &lt;code class=&quot;language-text&quot;&gt;client.given&lt;/code&gt; with random values assigned by default. You can also supply the values if you want:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; person &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;given&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;simulation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;person&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bob@gmail.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;local-development&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#local-development&quot; aria-label=&quot;local development permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Local Development&lt;/h2&gt;
&lt;p&gt;The goal of &lt;code class=&quot;language-text&quot;&gt;@simulacrum/auth0-simulator&lt;/code&gt; is to behave just like the real Auth0 server does. That means that libraries like &lt;code class=&quot;language-text&quot;&gt;@auth0/auth0-react&lt;/code&gt; should not notice any difference so that you can keep using your regular code and expect it to work without any adjustment when you switch to the real deal. The following snippet would work just as well using the Auth0 simulator and the production environment.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useAuth0 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@auth0/auth0-react&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;LoginButton&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; loginWithRedirect &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useAuth0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;loginWithRedirect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Log In&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;testing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#testing&quot; aria-label=&quot;testing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Testing&lt;/h2&gt;
&lt;p&gt;Having to redirect to login pages and enter user input when executing unit tests or end-to-end tests would be untenable. What’s especially useful about &lt;code class=&quot;language-text&quot;&gt;@simulacrum/auth0-simulator&lt;/code&gt; is that it makes local simulation instances available to test environments for end-to-end and unit tests without trips to Auth0.&lt;/p&gt;
&lt;h3 id=&quot;end-to-end-testing-with-cypress&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#end-to-end-testing-with-cypress&quot; aria-label=&quot;end to end testing with cypress permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;End-to-end testing with Cypress&lt;/h3&gt;
&lt;p&gt;Simulacrum has a &lt;a href=&quot;https://github.com/thefrontside/simulacrum&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@simulacrum/auth0-cypress&lt;/a&gt; package that can silently get an authentication token from the Auth0 simulator often required to run end-to-end tests. In the following example, we&apos;ll create an Auth0 simulation instance within a test, enabling the app to run under the config we wish:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Scenario&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Simulation &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@simulacrum/client&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@simulacrum/client&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; auth0Config &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../../cypress.env.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;log in&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;should get token without signing in&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createSimulation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auth0Config&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Log out&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;should&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;not.exist&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;given&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bob@gmail.com&apos;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Log out&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;logout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;unit-tests&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#unit-tests&quot; aria-label=&quot;unit tests permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Unit tests&lt;/h3&gt;
&lt;p&gt;At present, the Auth0 simulator has no official helper for obtaining an access token from the simulation server. But most javascript Auth0 SDKs have helpers for a client login that you can abstract into a helper function and use in conjunction with &lt;code class=&quot;language-text&quot;&gt;@simulacrum/auth0-simulator&lt;/code&gt; in unit tests.&lt;/p&gt;
&lt;p&gt;For instance, if you&apos;re using &lt;code class=&quot;language-text&quot;&gt;@auth0/auth0-spa-js&lt;/code&gt;, you could use &lt;code class=&quot;language-text&quot;&gt;getTokenSilently&lt;/code&gt; to obtain tokens:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; configJson &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../../src/auth_config.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Auth0Client &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@auth0/auth0-spa-js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; auth0Client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Auth0Client&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  audience&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; configJson&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;audience&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  client_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; configJson&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clientId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  connection&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Username-Password-Authentication&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; configJson&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domain&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;openid profile email&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  cacheLocation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;localstorage&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  useRefreshTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;silentLogin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; currentUser &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;currentUser&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; auth0Client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getTokenSilently&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; currentUser &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;or you could use &lt;code class=&quot;language-text&quot;&gt;loginWithDefaultDirectory&lt;/code&gt; if you&apos;re using &apos;auth0-js&apos;.&lt;/p&gt;
&lt;h2 id=&quot;epilogue&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#epilogue&quot; aria-label=&quot;epilogue permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Epilogue&lt;/h2&gt;
&lt;p&gt;Our Auth0 simulator &lt;code class=&quot;language-text&quot;&gt;@simulacrum/auth0-simulator&lt;/code&gt; makes Auth0’s “pain points” disappear by allowing developers to work locally and test their apps—without introducing fragmentation into their codebase, having to write cumbersome mocking code, or dealing with Auth0 accounts for different environments.
If you are using Auth0 then you really should give &lt;a href=&quot;https://github.com/thefrontside/simulacrum/tree/v0/packages/auth0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt; a spin.&lt;/p&gt;
&lt;p&gt;Feel free join our &lt;a href=&quot;https://discord.gg/r6AvtnU&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Discord community&lt;/a&gt;, or &lt;a href=&quot;/contact&quot;&gt;contact us&lt;/a&gt;, for questions or help to get started!&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/c671689697dc07b7c5bc20c9cd078abe/2a4de/2022-auth-simulator.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Effection: for when async/await is not enough]]></title><description><![CDATA[Everyone who has built a complex system in JavaScript has hit a critical moment when concurrent processes become unmanageable. But with Effection—an OSS async/await alternative—you'll spare memory leaks and headaches. ]]></description><link>https://frontside.com/blog/2021-10-26-effection-async-await/</link><guid isPermaLink="false">https://frontside.com/blog/2021-10-26-effection-async-await/</guid><category><![CDATA[dx]]></category><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Jonas Niklas]]></dc:creator><pubDate>Tue, 26 Oct 2021 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Everyone who has built a complex system in JavaScript has hit a critical moment where the illusion of control comes crashing down. Those are the moments when there are dozens (maybe hundreds) of concurrent processes running and it feels like you&apos;ve lost control over them. Maybe a promise handler or callback executes even though it is no longer relevant and messes up the state of the system. Or perhaps an error disappears into the void or a socket is not closed when it should be.&lt;/p&gt;
&lt;p&gt;The problem with concurrent processes in JavaScript is that it is fundamentally unstructured. Anyone can add a callback, or await a promise at any time, and once that task is created, it has an &lt;em&gt;unconstrained&lt;/em&gt; lifetime. If the async function or the callback is no longer relevant, how do you cancel it? Worse yet, if you&apos;re performing multiple callbacks or promises or awaits, are you sure you&apos;re dealing correctly with errors in all of them?&lt;/p&gt;
&lt;h2 id=&quot;introducing-effection&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#introducing-effection&quot; aria-label=&quot;introducing effection permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Introducing Effection&lt;/h2&gt;
&lt;p&gt;The solution is to adopt the ideas of &lt;a href=&quot;https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;structured concurrency&lt;/a&gt; and apply them to JavaScript. The core idea of structured concurrency is that the lifetime of a task is always constrained. This means that a task must not outlive its parent, or in other words, it is impossible to create a task that runs &lt;em&gt;forever&lt;/em&gt;. This might seem like an obvious constraint, but it is important to note that this is very much &lt;em&gt;not&lt;/em&gt; the case with the core concurrency primitives available in JavaScript.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://frontside.com/effection&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Effection&lt;/a&gt; is an Open Source concurrency framework that replaces async/await with a more structured way of writing code. Let&apos;s look at how this applies to async/await code:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/users/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There is nothing special about this async function. And this is what happens when we call this function from another function:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchSomeUsers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; userOne &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; userTwo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; userOne&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; userTwo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we&apos;re calling &lt;code class=&quot;language-text&quot;&gt;fetchUser&lt;/code&gt; twice, and then awaiting both calls. This will cause both calls to &lt;code class=&quot;language-text&quot;&gt;fetchUser&lt;/code&gt; to execute concurrently. We could also implement this using &lt;code class=&quot;language-text&quot;&gt;Promise.all&lt;/code&gt;, which would behave similarly and is subject to the exact same pitfalls:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchSomeUsers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; userOne &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; userTwo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;userOne&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userTwo&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It looks like the &lt;code class=&quot;language-text&quot;&gt;fetchSomeUsers&lt;/code&gt; function is nice and self-contained, but in fact it isn&apos;t. We start fetching two users, but both of those fetches are in no way tied to the &lt;code class=&quot;language-text&quot;&gt;fetchSomeUsers&lt;/code&gt; function. They run in the background, and no matter what happens within &lt;code class=&quot;language-text&quot;&gt;fetchSomeUsers&lt;/code&gt;, &lt;em&gt;they just keep running&lt;/em&gt;. Potentially they could run forever; that&apos;s what we mean when we say that their lifetime is unconstrained.&lt;/p&gt;
&lt;p&gt;For example, there is nothing stopping us from doing something silly like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;I&apos;m still running, lol!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/users/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Even ages after the &lt;code class=&quot;language-text&quot;&gt;fetchUser&lt;/code&gt; function has finished, it will still print something to the console. We can&apos;t close the existing loopholes (such as &lt;code class=&quot;language-text&quot;&gt;setTimeout&lt;/code&gt;), but as long as you are writing idiomatic Effection code, something like the above just cannot happen.&lt;/p&gt;
&lt;p&gt;Let&apos;s look at this example again – but this time using Effection:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; spawn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fetch &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;effection&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/users/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchSomeUsers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; userOne &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;spawn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; userTwo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;spawn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; userOne&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; userTwo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It&apos;s not that different from before: Effection uses generator functions instead of async functions, and there is something going on with &lt;code class=&quot;language-text&quot;&gt;spawn&lt;/code&gt;, but other than that it looks pretty much the same.&lt;/p&gt;
&lt;p&gt;However, the way that this function runs is very different. When we spawn a task with Effection, its lifetime is tied to the current task, which means that &lt;code class=&quot;language-text&quot;&gt;fetchUser(1)&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;fetchUser(2)&lt;/code&gt; cannot ever outlive fetchSomeUsers. Moreover, no task that &lt;code class=&quot;language-text&quot;&gt;fetchUser&lt;/code&gt; spawns can outlive &lt;code class=&quot;language-text&quot;&gt;fetchUser&lt;/code&gt; either. Effection tasks ensure that everything that happens within the task stays within the task.&lt;/p&gt;
&lt;h2 id=&quot;using-effection&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#using-effection&quot; aria-label=&quot;using effection permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using Effection&lt;/h2&gt;
&lt;p&gt;This might seem like a trivial outcome but the implications are profound. For example, Effection ships with an operation called &lt;code class=&quot;language-text&quot;&gt;withTimeout&lt;/code&gt;, which adds a time limit to any task. If the time limit is exceeded, an error is thrown.&lt;/p&gt;
&lt;p&gt;That means we can now do this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; withTimeout &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;effection&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchSomeUsersWithTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchSomeUsers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Right now in JavaScript something like this is pretty much impossible to implement with promises. There is just no way to know what &lt;code class=&quot;language-text&quot;&gt;fetchSomeUsers&lt;/code&gt; does internally, and there is no way to know whether we really can abort all of it. Trying to write a function like this is at best unsafe and at worst impossible.&lt;/p&gt;
&lt;p&gt;With Effection it all just works. We know that nothing can escape &lt;code class=&quot;language-text&quot;&gt;fetchSomeUsers&lt;/code&gt; and we know that everything that &lt;code class=&quot;language-text&quot;&gt;fetchSomeUsers&lt;/code&gt; does will be canceled if we cancel &lt;code class=&quot;language-text&quot;&gt;fetchSomeUsers&lt;/code&gt; itself.&lt;/p&gt;
&lt;p&gt;Now, imagine that our async/await &lt;code class=&quot;language-text&quot;&gt;fetchSomeUsers&lt;/code&gt; fails for some reason:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchSomeUsers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; userOne &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; userTwo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;boom&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; userOne&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; userTwo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What will happen in this case? &lt;code class=&quot;language-text&quot;&gt;fetchUser(1)&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;fetchUser(2)&lt;/code&gt; will happily keep running, even though the &lt;code class=&quot;language-text&quot;&gt;fetchSomeUsers&lt;/code&gt; function which initially called them has already failed.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-effection-intro/intro-effection-async-await.svg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;fetchSomeUsers timing with async/await&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;This can&apos;t happen in Effection. Because given that &lt;code class=&quot;language-text&quot;&gt;fetchUser(1)&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;fetchUser(2)&lt;/code&gt; are scoped to their parent function, they will be terminated when &lt;code class=&quot;language-text&quot;&gt;fetchSomeUsers&lt;/code&gt; enters into an error state.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-effection-intro/intro-effection-effection.svg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;fetchSomeUsers timing with effection&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;And this is the power of Effection&apos;s structured concurrency: it allows us to build abstractions that would otherwise be impossible to construct. We think it is a fundamentally better way to write JavaScript.&lt;/p&gt;
&lt;h3 id=&quot;going-further&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#going-further&quot; aria-label=&quot;going further permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Going further&lt;/h3&gt;
&lt;p&gt;There is much more to Effection than what we&apos;ve shown here. Effection is not only a framework that allows you to write rock-solid code, but it also gives you amazing insights into your application through our experimental &lt;a href=&quot;http://frontside.com/effection/docs/guides/inspector&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;inspector&lt;/a&gt;. If you&apos;re curious to learn more, this &lt;a href=&quot;http://frontside.com/effection/docs/guides/introduction&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;guide&lt;/a&gt; explains in greater detail how to use Effection, and the &lt;a href=&quot;https://frontside.com/effection/api/index.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;API Reference&lt;/a&gt; contains a complete reference of all methods and types that Effection provides.&lt;/p&gt;
&lt;p&gt;We are a small but dedicated team at Frontside that likes to tackle challenging problems with an ambitious solution. There is boundless work to be done, and boundless ideas to explore. Do you want to join us on this journey? Come hang out with us &lt;a href=&quot;https://discord.gg/Ug5nWH8&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;on discord&lt;/a&gt;, where we stream our work and are always interested in discussing where to go next.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/c588855a2e02779b29504f163481ca0a/2a4de/2021-intro-effection.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Interactors: the design systems testing ally]]></title><description><![CDATA[Components from a design system make building UIs easy. It should be just as easy to test them. Interactors enable more robust tests for component-based UIs, and improve component libraries' maintainability.]]></description><link>https://frontside.com/blog/2021-08-04-interactors-design-systems/</link><guid isPermaLink="false">https://frontside.com/blog/2021-08-04-interactors-design-systems/</guid><category><![CDATA[testing]]></category><category><![CDATA[design-systems]]></category><dc:creator><![CDATA[Charles Lowell, Jeffrey Cherewaty]]></dc:creator><pubDate>Wed, 04 Aug 2021 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The reusable component libraries shipped with design systems enable developers to use on-brand and battle-tested components. Developers don&apos;t have to re-invent the wheel every time they need a common element like an input, modal dialog, or date picker.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-08-04-interactors-design-system/date-picker-click-map.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshots of date picker components highlighting clickable areas&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;re building an application with some of these components, you&apos;ll want to write some tests. With the date picker component pictured above, a user needs at least four clicks to select a date. That means a UI test will also need to step through those four clicks. Testing this interaction with React Testing Library and Cypress could look like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;#date .MuiCalendarPicker-root&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;within&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByLabelText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;calendar view is open, switch to year view&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;1992&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByLabelText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Next month&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;16&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To effectively write a test using this date picker, we had to include specifics about its implementation, like IDs and classes. If the underlying component changes its DOM structure, our tests are suddenly brittle.&lt;/p&gt;
&lt;p&gt;There&apos;s a well-trod design pattern for fixing this problem: &lt;a href=&quot;https://www.martinfowler.com/bliki/PageObject.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;page objects&lt;/a&gt;. They&apos;re object-oriented classes that serve as an interface. As an application matures alongside its accompanying tests, page objects act as a buffer and a more explicit API for the tests to interact with the application.&lt;/p&gt;
&lt;h2 id=&quot;introducing-interactors&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#introducing-interactors&quot; aria-label=&quot;introducing interactors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Introducing Interactors&lt;/h2&gt;
&lt;p&gt;At Frontside, we&apos;ve built &lt;a href=&quot;https://frontside.com/interactors&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Interactors&lt;/a&gt; (&lt;code class=&quot;language-text&quot;&gt;@interactors/html&lt;/code&gt;), a library inspired by page objects that helps teams structure, share, and reuse their UI testing practices.&lt;/p&gt;
&lt;p&gt;Interactors evolve the idea of a page object. Modern applications are usually arranged into composable components, and the &quot;page&quot; is no longer the dominant unit of organization. An Interactor is similarly composable, and can abstract any level of object in the DOM hierarchy.&lt;/p&gt;
&lt;p&gt;Design systems maintainers can build interactors alongside components to reduce the mental distance between the user interface and its testing-friendly abstraction. In the same way strong typing can make components easier to build with, interactors make components easier to test.&lt;/p&gt;
&lt;p&gt;Interactors...&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;... are composable, so they make tests easier to write, read, and run.&lt;/li&gt;
&lt;li&gt;... act as an abstraction layer on top of the component&apos;s implementation, improving design systems&apos; maintainability.&lt;/li&gt;
&lt;li&gt;... have TypeScript support and provide helpful errors, resulting in an improved developer experience.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&apos;s take a closer look at each of these advantages.&lt;/p&gt;
&lt;h3 id=&quot;interactors-make-tests-easier-to-write&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#interactors-make-tests-easier-to-write&quot; aria-label=&quot;interactors make tests easier to write permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Interactors make tests easier to write&lt;/h3&gt;
&lt;p&gt;We provide basic &lt;a href=&quot;https://frontside.com/bigtest/docs/interactors/built-in-dom&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;built-in Interactors&lt;/a&gt; that correspond to HTML elements, like &lt;code class=&quot;language-text&quot;&gt;button&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;link&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;checkbox&lt;/code&gt;. Using these alone, you could interact with and assert the majority of cases of a web UI. Take the following example of a collapsable navigation menu test:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Button&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Link&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Heading &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@interactors/html&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;goes to international news page with mobile menu&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;do&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string-property property&quot;&gt;&apos;aria-label&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Show Navigation Menu&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;International&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&apos;class&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;nav-link&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;Heading&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;News&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You&apos;ll often want to avoid repeating yourself and pack together interactions and assertions that correspond to your design system&apos;s components.&lt;/p&gt;
&lt;p&gt;It&apos;s likely that &lt;code class=&quot;language-text&quot;&gt;Nav&lt;/code&gt; is indeed a component in our design system. Thus, we can create a &lt;code class=&quot;language-text&quot;&gt;Nav&lt;/code&gt; Interactor that queries the nav and has actions that a user can perform with it.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;goes to international news page with mobile menu&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;do&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;goTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;News&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;goes to entertainment news page with mobile menu&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;do&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;goTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Entertainment&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that we can target the &lt;code class=&quot;language-text&quot;&gt;Nav&lt;/code&gt; directly and perform the action we care about in a single line. If the component changes its internal classes or markup, these tests won&apos;t break. Its Interactor received updates to account for those changes.&lt;/p&gt;
&lt;p&gt;Retaking the example from the introduction, you could provide a &lt;code class=&quot;language-text&quot;&gt;DatePicker&lt;/code&gt; Interactor such that everyone using the pick date component have standard methods to test their features using an interface like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;cy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;do&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DatePicker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;month&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;August&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1992&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Composable Interactors also respect their lifecycle in the browser. That means that they don&apos;t waste time waiting on dead components or looking for new ones when there&apos;s no rendering happening.&lt;/p&gt;
&lt;h3 id=&quot;interactors-improve-maintainability-in-a-design-system&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#interactors-improve-maintainability-in-a-design-system&quot; aria-label=&quot;interactors improve maintainability in a design system permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Interactors improve maintainability in a design system&lt;/h3&gt;
&lt;p&gt;Interactors rapidly become design system&apos;s maintainers&apos; best friend because they provide freedom by abstracting the testing practice away from the component&apos;s implementation. Instead of relying on fragile internal component classes, developers and maintainers can use Interactors as an API contract for the UI.&lt;/p&gt;
&lt;p&gt;Typically, developers would target elements in the UI in their tests by reaching into the internals of the components they use. It&apos;s common to see tests that target chains of selectors like this one:&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;#notes-modal-notes-list [class*=&quot;mclRowFormatterContainer--&quot;]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;However, referencing internal selectors couples the test implementation to the HTML structure of the component; a slight change to the markup may cause tests to fail. Thus, tests are fragile and introduce fear in the design system&apos;s maintainers because they have no way of knowing what might cause tests to fail. Worst of all, this fragility makes tests unreliable when updating the design system, which is precisely the kind of system-wide change that you write your tests for.&lt;/p&gt;
&lt;p&gt;Interactors are the missing contract between the design system&apos;s maintainer and its users. The maintainers can control the API that test authors use to interact with the component. The maintainers can freely change the markup of components without worrying about inadvertently breaking tests. And test authors have a more convenient way to write their tests. In the end, the tests are more reliable and provide more confidence to everyone.&lt;/p&gt;
&lt;h3 id=&quot;interactors-improve-developers-experience-while-testing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#interactors-improve-developers-experience-while-testing&quot; aria-label=&quot;interactors improve developers experience while testing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Interactors improve developers&apos; experience while testing&lt;/h3&gt;
&lt;p&gt;Interactors know more about the components under test than mere selectors, which allows them to provide helpful information while you develop or debug tests. Having an explicit API to test your app provides static checking safety, and understanding that API enables Interactors to provide suggestions when things go wrong in a test.&lt;/p&gt;
&lt;p&gt;When you write your test assertions and actions using selectors, you&apos;re on your own. There are no checks available while you write the test, or while it compiles. You&apos;ll only find out about a typo after running the tests, and inspecting closely why your test is failing although it seems that it should pass.&lt;/p&gt;
&lt;p&gt;Interactors bring in static checks for your tests, which means your IDE and compiler can provide more support as you develop:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-08-04-interactors-design-system/interactors-ide-suggestions.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshot of IDE showing in-line suggestions and documentation about Interactors&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Not everything can be found by static analysis in a test, but Interactors are ready to provide helpful suggestions for common small mistakes that are usually hard to debug. For example, if you were looking for a login button in your test case, but forgot for a moment that the button actually reads &quot;Log In&quot;, Interactors will hint that to you:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-08-04-interactors-design-system/interactors-error-suggest-not-found.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshot of interactors suggestion similar elements to the one that was not found&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Interactors not only check for presence before committing an action in the UI, they also check if the &lt;a href=&quot;https://github.com/thefrontside/element-is-visible&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;element is visible&lt;/a&gt;—through various heuristics—and that it is enabled. For example, if Interactors did find the button and it is visible but not enabled, it will throw an error like this:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-08-04-interactors-design-system/interactors-error-disabled-element.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshot of interactors failing a test because the target element was visible but not enabled&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id=&quot;try-out-interactors&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#try-out-interactors&quot; aria-label=&quot;try out interactors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Try out Interactors!&lt;/h2&gt;
&lt;p&gt;If you&apos;re still not sure about trying out Interactors, take a look at this &lt;a href=&quot;https://github.com/folio-org/stripes-testing/pull/112&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;pull request in FOLIO&lt;/a&gt;, an open-source project, adopting Interactors in their component library:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-08-04-interactors-design-system/diff-react-testing-library-vs-interactors.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshot of code diff resulting in refactoring a test using React Testing Library to use Interactors&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The selectors are difficult to follow and are quite fragile, while the Interactors are easier to read and focus on testing the app as a user would use it.&lt;/p&gt;
&lt;p&gt;You can start using Interactors as part of your current test setup, they&apos;re compatible out of the box with Cypress and Jest, so it&apos;s easy to &lt;a href=&quot;https://frontside.com/bigtest/docs/interactors&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;get started!&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;posts-list-list&quot;&gt;
  &lt;h2&gt;Related articles:&lt;/h2&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2021-18-02-there-and-back-again-testing-and-upgrades/&quot;&gt;
        There and Back Again: Testing and Stack Upgrades
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      Upgrading your application stack to new major versions can be terrifying, especially when you have a massive application with 75 developers working on features non-stop. However, a good testing strategy gives you confidence to make bold moves that take your organization to heretofore unexplored lands.
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2021-18-02-there-and-back-again-testing-and-upgrades/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2021-04-07-helping-designers-and-developers-storybook/&quot;&gt;
        Unleashing the Genie: Helping both designers and developers with Storybook
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      Good documentation is key to design systems. However, what &quot;good&quot; means varies according to the reader. This article will go through tips to generate documentations for designers and developers from a single Storybook—keep everyone happy with minimum effort!
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2021-04-07-helping-designers-and-developers-storybook/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/aside&gt;</content:encoded><media:content url="https://frontside.com/static/bb88c83f430d07176b473a11176c7d15/2a4de/2021-interactors-design.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Relieve developers’ churn in your Cloud native strategy with Backstage]]></title><description><![CDATA[Adopting Cloud native strategies has proven to improve organizations' delivery performance, but the complexity brought in with them is making life harder for developers. Using the example of a unified Secret manager, I present how Backstage can improve DX in the Cloud native world.]]></description><link>https://frontside.com/blog/2021-05-14-avoid-cloud-native-churn-with-backstage/</link><guid isPermaLink="false">https://frontside.com/blog/2021-05-14-avoid-cloud-native-churn-with-backstage/</guid><category><![CDATA[cloud-native]]></category><category><![CDATA[dx]]></category><category><![CDATA[backstage]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Taras Mankovski]]></dc:creator><pubDate>Fri, 14 May 2021 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When you start breaking your monolithic platform into microservices and deploying components independently, you can’t help but feel excited about adopting a Cloud native strategy. You see releases becoming more frequent and smooth and your teams feel more productive and motivated as they see their work rapidly move into production.&lt;/p&gt;
&lt;p&gt;It’s all great – that is until you hit a critical fragmentation point. As you keep adding microservices to your Cloud native platform, it gets harder and harder to keep track of what’s going on. Who’s building this service and with which stack and patterns? Why do we have three authentication mechanisms? Where are all these Cloud provider bills coming from?&lt;/p&gt;
&lt;p&gt;The landscape for your developers is not much better. They must launch into detective mode and trace APIs and codebases in order to figure out the services they need to build their features. Then they need to figure out how to deploy their own work, which usually turns into an epic quest against the Cloud monster.&lt;/p&gt;
&lt;p&gt;The problems with Cloud native practices seem to proliferate with each passing day, yet companies keep pushing towards their adoption across their teams because of its proven track record of increasing software development velocity. What’s a developer to do?&lt;/p&gt;
&lt;p&gt;Thankfully, soon everyone will have access to Backstage: an all-purpose platform to make the Cloud native experience better for everyone!&lt;/p&gt;
&lt;p&gt;Backstage is an Open Source platform for creating Developer Portals. Currently a Cloud Native Computing Foundation sandbox project first developed by Spotify, Backstage is getting a lot of traction among organizations experiencing the problems of microservices at scale when combined with the challenge of supporting dozens of developers on their team.&lt;/p&gt;
&lt;p&gt;In this article we’ll cover the challenges developers experience using Cloud native strategies and how Backstage alleviates them. We’ll use the example of a secrets manager to illustrate just how useful Backstage is. By the end of the article I guarantee you’ll want to slip Backstage too and see what’s got everyone excited!&lt;/p&gt;
&lt;h2 id=&quot;churn-n-burn&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#churn-n-burn&quot; aria-label=&quot;churn n burn permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Churn ‘n Burn&lt;/h2&gt;
&lt;p&gt;Organizations who adopt Cloud native strategies do so because they &lt;em&gt;need&lt;/em&gt; to in order to stay competitive. Users cannot bear the traditional cadence where a special commission would sit down for months to release one feature. Your customers expect you to deliver new features faster and improve the user experience all the time, and will switch to the competition in the blink of an eye if they’re not getting that from you. Having &lt;em&gt;no&lt;/em&gt; bugs is the baseline now, so whenever one sneaks into production you need to be able to roll back immediately. Kubernetes provides you with the automated technology to make all of this possible. But it&apos;s an open secret that Kubernetes is quite difficult to use, and that has a direct effect on how your teams operate. What’s gotten lost in the transition to developing Cloud native apps is an awareness of &lt;em&gt;your&lt;/em&gt; team’s experience and their comfort level with the tools they use.&lt;/p&gt;
&lt;p&gt;Since the inception of Kubernetes in 2014 and throughout its evolution, a whole industry has spawned to help companies adopt it. And no wonder: Kubernetes is not an easy technology to learn and manage due to the enormous complexity that it’s designed to deal with. For that reason, most Cloud providers have created managed-Kubernetes platforms: Microsoft Azure AKS, Amazon EKS, Google GKE, and IBM CloudFundry are just a few of the most obvious examples. Each of them imagined a UI that would work nicely to manage Kubernetes, and countless other vendors offer tools to monitor and automate different aspects of Kubernetes, each with their own interfaces and abstractions as well.&lt;/p&gt;
&lt;p&gt;While the attempt to support the adoption of Cloud based practices is to be applauded, what’s emerged is a very complicated landscape for those people tasked with implementing Kubernetes. Not only must they master this intricate technology, but they must also be proficient at the diverging set of tools that serve it, which change and evolve as fast as Kubernetes itself. Oftentimes, engineers wind up having to manage two or three Cloud solutions providers at a time, forced to use Microsoft’s Azure because of a company-wide policy but also required to handle Amazon’s AWS to spin up macOS containers on demand.&lt;/p&gt;
&lt;p&gt;Nor is it just your DevOps team who are experiencing the churn of Cloud native solutions. Developers are also taking the hit with today’s trend of self-service deployment setups. Developers are not only expected to write robust apps, understand the business, and coordinate with other teams – they’re asked to be Cloud native too, which implies getting to know an entirely new world of complexity that seemingly changes every six weeks. That much churn puts developers at risk of burnout.&lt;/p&gt;
&lt;h2 id=&quot;a-one-stop-tool-shop&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-one-stop-tool-shop&quot; aria-label=&quot;a one stop tool shop permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A one-stop tool shop&lt;/h2&gt;
&lt;p&gt;Backstage’s mission is to empower developers. Instead of creating yet another platform to manage the infrastructure that supports Cloud native solutions, Backstage’s innovation is to create a portal to manage the organization’s services. While the infrastructure is a critical piece of any service, Backstage sees it as a means to the real end: achieving business goals.&lt;/p&gt;
&lt;p&gt;Backstage brings together in one place the various aspects of each service: its codebase, documentation, environments, infrastructure, and of course the people who build them. The teams like Spotify who are adopting Backstage are learning that investing in their developers’ experience pays off. When working with Frontside’s enterprise clients, I see the true magic of Backstage is in how it provides developers real ownership of what they’re building. It’s truly giving them the keys to the castle.&lt;/p&gt;
&lt;p&gt;Yet a funny thing happens when you give someone the freedom of ownership: it transforms into responsibility. When the people who design and develop your software have the freedom of ownership over their services or apps, their creativity and productivity goes through the roof. But with that freedom comes a genuine sense of responsibility to deliver best-in-class experiences.&lt;/p&gt;
&lt;p&gt;Prior to Backstage, teams would often be “ready to ship,” only to discover that being merely feature-complete isn’t enough – they still had an unknown path to go down before their work reached production stage. For a developer, having to set up a ‘war room’ to push the update or app through the development path is the equivalent of trying to get spaghetti to roll uphill – a frustrating and often fruitless experience.&lt;/p&gt;
&lt;p&gt;But with Backstage the development experience is transformed. For example, by using Backstage Scaffolder, developers can easily set up work environments that resemble production more faithfully, resulting in less friction and fewer surprises along the development path. They can start developing apps that are compliance-ready and infosec-approved from the very beginning by pulling in pre-made solutions and proven architecture patterns that are shared in Scaffolder.&lt;/p&gt;
&lt;p&gt;Thanks to Backstage’s Service Catalog, teams can break through heaps of emails, meetings and bureaucracy by bringing together all the aspects of every service under a single portal. With a 360-degree view of the development process, your team will be able to discover new synergies, generating opportunities for joint efforts while avoiding duplicated solutions across the organization. Now that all your services are visible in a single portal, you can also find orphaned projects and take care of them.&lt;/p&gt;
&lt;h2 id=&quot;dont-tell-a-soul-secrets-management&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#dont-tell-a-soul-secrets-management&quot; aria-label=&quot;dont tell a soul secrets management permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Don’t tell a soul: Secrets management&lt;/h2&gt;
&lt;p&gt;Every organization’s Cloud platform needs a way to manage secrets and apply them to containers. The easiest place to start is to use Kubernetes&apos; built-in secrets management. This approach is easy to set up but difficult to manage and secure long term. A more permanent solution is to manage secrets via a Git repository with GitOps workflow or by using a secrets vault like Azure Key Vault or Hashicorp Vault. Some organizations adopt a more-the-merrier approach and use all three of these in sequence. The options that are available to your platform team might depend on procurement practices of your organization or its familiarity with these tools.&lt;/p&gt;
&lt;p&gt;But when it comes to secret management, it’s not just the UI that changes across providers: each platform has their own idiosyncrasies. For example, the requirements in minimum length for secret values are different in Microsoft Azure and Hashicorp’s Vault. In short, there’s a lot of variables to keep track of. At least one thing is certain, however: expecting your developers to fluidly switch between three different ways of managing secrets will make them want to tear their hair out.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-backstage-dx/different-managers-ui.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshots from different secret management UIs - they all look different, yet do the same thing!&lt;/figcaption&gt;&lt;/figure&gt;
&lt;em&gt;Screenshots from four secrets management UIs from different providers&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A better developer experience would provide your developers with a consistent and familiar interface for managing secrets no matter which Cloud providers come and go. That’s Backstage in a nutshell.&lt;/p&gt;
&lt;p&gt;Given that it already aggregates services and other assets, a natural place for such an interface to live is in Backstage. And the benefit of building it in Backstage is that instead of having your developers deal with specificities in a UI, you can abstract them away in a unified API for your aggregator microservice. Your secret manager UI in Backstage will reflect these unified rules, removing these complexities from your team.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-backstage-dx/backstage-plugin-prototype.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshot of a possible secret manager implemented in Backstage&lt;/figcaption&gt;&lt;/figure&gt;
&lt;em&gt;A Prototype of a Secret Manager plugin build on Backstage&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And best of all, your team already knows how to build a Backstage plugin like this! Somebody familiar with React and the company’s microservices setup can take up the task and have it done in no time at all.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-backstage-dx/plugin-architecture.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Architecture diagram for the plugin. The secret manager plugin is inserted in Backstage&apos;s UI, which is all rendered in the user&apos;s browser. This UI communicates with an aggregating microservice, that contacts external Cloud providres&lt;/figcaption&gt;&lt;/figure&gt;
&lt;em&gt;Basic architecture diagram for the Secret Manager plugin&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In Backstage, plugins are React components that get added to each service’s page. Thus, the secret manager plugin will be a React component with a UI where your developers will create and edit secrets. This component will make HTTP requests to a microservice that will be responsible for retrieving and editing secrets in your current Cloud providers. Going forward, your team will only have to adjust the aggregating microservice whenever there is a change in Cloud providers.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Backstage not only allows you to keep evolving your Cloud native strategy without compromising the productivity of your developers: it empowers them to take your organization to the next level by uncovering collaboration possibilities and promoting shared solutions on top of the Cloud. Secrets management is but one example! The possibilities are quite broad for expanding Backstage to fit in your needs, from Enterprise API integrations with tools like WSO2 or Mulesoft, to putting together infrastructure workflows for data processing.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/87fd89b9dbb428106f89adc3c652a0a8/2a4de/avoid-developer-churn-with-backstage.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Unleashing the Genie: Helping both designers and developers with Storybook]]></title><description><![CDATA[Good documentation is key to design systems. However, what "good" means varies according to the reader. This article will go through tips to generate documentations for designers and developers from a single Storybook—keep everyone happy with minimum effort!]]></description><link>https://frontside.com/blog/2021-04-07-helping-designers-and-developers-storybook/</link><guid isPermaLink="false">https://frontside.com/blog/2021-04-07-helping-designers-and-developers-storybook/</guid><category><![CDATA[design-systems]]></category><category><![CDATA[dx]]></category><dc:creator><![CDATA[Varya Stepanova]]></dc:creator><pubDate>Wed, 07 Apr 2021 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The goal of a design system is to have everyone using it across apps, products, and teams, but achieving that is easier said than done. It’s no mystery that the easier a design system is to use the more uptake it will get. But a design system’s ease of use is oftentimes contingent on how good its documentation is.&lt;/p&gt;
&lt;p&gt;Using &lt;a href=&quot;https://storybook.js.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Storybook&lt;/a&gt; can move your team a long way towards creating effective and easy to use documentation for a design system. Storybook allows you to showcase “stories” for each of your design system’s elements, including permutations of their visual and functional options. As your design system grows, you can add to the stories you tell about it.&lt;/p&gt;
&lt;p&gt;However, teams often hit a point in which there’s so much information that Storybook becomes hard to use and navigate. Designers have to scroll through APIs that are not relevant to them, or decipher technical names that have been generated for their UIs. Developers similarly have to skip through the various design edge-cases to find the parameters they’re interested in. Too often what was once a manageable collection of stories becomes as long as the classic One Thousand and One Nights.&lt;/p&gt;
&lt;p&gt;One obvious solution to arrive at more usable documentation for both groups would be to create a version for designers and another one for developers. But maintaining two Storybooks would require a lot of work and result in a fair bit of duplicated effort.&lt;/p&gt;
&lt;p&gt;As it turns out, we don’t have to keep two separate Storybooks to achieve the same usability goals for both designers and developers. In this article, I’ll explain ideas to generate Storybook stories straight from your codebase, and thus avoid maintenance churn. After that, I’ll overview techniques to generate two different sets of documentation from a single Storybook using build options.&lt;/p&gt;
&lt;h2 id=&quot;documenting-design-tokens&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#documenting-design-tokens&quot; aria-label=&quot;documenting design tokens permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Documenting Design Tokens&lt;/h2&gt;
&lt;p&gt;Storybook allows you to document your stories with &lt;a href=&quot;https://www.npmjs.com/package/@storybook/addon-docs&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@storybook/addon-docs&lt;/a&gt;, including design tokens and other elements of your design system.&lt;/p&gt;
&lt;p&gt;For example, you can use blocks from &lt;code class=&quot;language-text&quot;&gt;@storybook/addon-docs&lt;/code&gt; to document your color palette:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ColorPalette&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ColorItem &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@storybook/addon-docs/blocks&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Palette&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ColorPalette&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ColorItem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Primary&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;subtitle&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Pink&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#F74D7B&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ColorItem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Secondary&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;subtitle&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Dark&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#15325D&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ColorItem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Tertiary&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;subtitle&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Blue&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#26ABE7&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ColorPalette&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Similarly, there&apos;s other blocks available for documenting other design tokens such as typography (&lt;code class=&quot;language-text&quot;&gt;&amp;lt;Typeset&gt;&lt;/code&gt;) and iconography (&lt;code class=&quot;language-text&quot;&gt;&amp;lt;IconGallery&gt;&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;&amp;lt;IconItem&gt;&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The full documentation for these blocks &lt;a href=&quot;https://github.com/storybookjs/storybook/issues/9133&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;is yet to be completed&lt;/a&gt;, but in the meantime you can read an explanation about them in detail in Storybook’s team announcement: “&lt;a href=&quot;https://storybook.js.org/blog/rich-docs-with-storybook-mdx/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Rich docs with Storybook MDX&lt;/a&gt;.&quot;
While inputting design tokens documentation by hand is simple, it can be redundant because we have already stored those values in our codebase. We can leverage that existing code to guarantee up to date documentation – and avoid extra work.&lt;/p&gt;
&lt;p&gt;In the case of the color palette, we don&apos;t need to list the colors manually: as we usually store them as a JavaScript hash, we can iterate and display them all one by one as shown in this example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ColorPalette&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ColorItem &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@storybook/addon-docs/blocks&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; colors &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;path/to/tokens.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Palette&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ColorPalette&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;colors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ColorItem&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;color&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;subtitle&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;color&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ColorPalette&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can extend this idea to document helper classes that assign specific text colors, background colors, margins, padding, and borders. These kinds of classes are typically used for fast prototyping. Helper classes are handy for making quick changes and variations like these:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-helping-designers-and-developers-storybook/text-classes.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshot of texts with classes applied on a story&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Classes are not stored in a hash, but we can iterate through CSS classes directly just as we did for the colors.&lt;/p&gt;
&lt;p&gt;You know the saying: it’s easier to show than tell. So instead of just listing the available classes, you can document them applied to a &lt;code class=&quot;language-text&quot;&gt;&amp;lt;p&gt;&lt;/code&gt; element so people can immediately see the effect of the class. An implementation could look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; styles &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;path/to/_helper-classes.scss&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;textColors&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; textColors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;color--&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      acc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; acc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; textColorSamples &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; textColors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cl&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cl&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Text color with .&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cl&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;textColorSamples&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, the story imports the SCSS file used in the codebase, which means even the documentation of helper classes is automatically up-to-date and accurate.&lt;/p&gt;
&lt;p&gt;We can generate stories from our codebase for other types of design tokens. For example, if your design system contemplates button variations or icon options, you can take them from your code and display them automatically as well.&lt;/p&gt;
&lt;p&gt;But here’s where things can get messy. Let’s take a closer look at the example of icons. A single project can use hundreds of icons, and each can be available in light, regular, or filled – not to mention that each of those can be available in different sizes. If we generated a story that displayed every possible permutation of the icons available from the code, we’d get a grid with thousands of icons that would endlessly go on like Scheherazade speaking to the king. Nobody wants to scroll infinitely trying to find a single icon!&lt;/p&gt;
&lt;p&gt;When we’re confronted with such a situation, bringing in some interactivity to our story can help. To make the list of icons more useful, you can implement a component that generates all of the icons from the codebase but offers filters to show only those that are interesting for the user, depending on type, size, and even name:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-helping-designers-and-developers-storybook/generated-icons.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshot of story with generated icons&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;As you can see in the screenshot above, generating the icons from the codebase has another feature (or challenge): the names are written as they are in the codebase, like &lt;code class=&quot;language-text&quot;&gt;&amp;lt;IconEmailFilled /&gt;&lt;/code&gt;. For developers, this is great because that’s exactly what they want to know. However, designers may find such names quite confusing, especially if your designers are consuming your stories through a tool like &lt;a href=&quot;https://zeroheight.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ZeroHeight&lt;/a&gt;. Is there a way we can summon Aladdin’s genie from the lamp and have him grant us a wish to solve this conundrum?&lt;/p&gt;
&lt;h2 id=&quot;different-users-different-stories&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#different-users-different-stories&quot; aria-label=&quot;different users different stories permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Different users, different stories&lt;/h2&gt;
&lt;p&gt;Designers and developers are interested in different aspects of a design system: a designer wants to know about edge-cases in the UI like a button with a very long text, while developers want to know about how &lt;code class=&quot;language-text&quot;&gt;onClick&lt;/code&gt; works in a given component. Trying to cobble together both perspectives in the same story doesn&apos;t work very well, so instead I usually write separate stories for developers and designers. Before you raise your hand, let me explain that I don&apos;t maintain two Storybooks (that&apos;d be hard): I host two different kinds of Stories in the same Storybook but in order to avoid the copy-paste one is usually inherited from another. They are also seasoned with different decorators, bringing only the desired experience to their target audience.&lt;/p&gt;
&lt;p&gt;My Storybook is implemented so that the same component has some stories that describe it from the design perspective and some that are good to follow for developers. Mostly, the difference is in what I explain about each component&apos;s story. In the design-oriented stories, I show what visible variations a component might have and the design edge cases. While in the stories for developers I focus on functional features of a component.&lt;/p&gt;
&lt;p&gt;However, not every component needs separate stories for designers and developers. There&apos;s cases when you only need to make a small tweak to the content to make it fit the needs of developers or designers.&lt;/p&gt;
&lt;p&gt;Let’s go back to that list of all icons where the names were equal to the corresponding React components and therefore served the needs of developers. For designers, I coded a second story. Instead of showing the react component name, it displayed the icon’s name from the component’s meta data. Since I coded the icons story to be generic enough, I didn&apos;t have to make any copy-paste to create two stories. Instead, I only need to reuse the story and tell it which kind of name to use by passing in a parameter. The designers’ story would look like this:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-helping-designers-and-developers-storybook/generated-icons-designer.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshot of story with generated icons with designer names&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;It is possible to keep pushing towards a more refined experience for our readers depending on how they consume Storybook. For example, in a project I lead, developers used a special UI to keep documentation on sight on a side screen while they coded. In that case, a different background and a thicker stroke around stories came a long way to provide a nicer UX for them. However, those styles would look odd for designers who only consumed Storybook through a regular web view.&lt;/p&gt;
&lt;p&gt;You can generate two documentations with different styles without having to manage two Storybooks or make any copy-pastes in the process. The key is to rely on &lt;a href=&quot;https://storybook.js.org/docs/react/writing-stories/decorators&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;decorators&lt;/a&gt; to apply special styling (and do any other needed processing to the story) depending on its target audience;&lt;/p&gt;
&lt;p&gt;For instance, you can implement a &lt;code class=&quot;language-text&quot;&gt;@developerStory&lt;/code&gt; decorator that would only be applied to the stories kept in the files with a special &lt;code class=&quot;language-text&quot;&gt;.docs.stories.js&lt;/code&gt;.This decorator performs all the necessary style adjustments to the display of the stories when they are built. And you can do this all with a single line of code! It looks like Alladin’s genie (or rather Storybook’s genie) came through for us.&lt;/p&gt;
&lt;p&gt;When it’s time to ship our documentation to their target users, having enriched stories allows you to have more granular control over how the production build will look like. You can go as far as having two different Storybook configurations that you toggle with a flag on the build command. Or you can decide to not include stories for developers for a target site (for instance if it&apos;ll be consumed by a tool like Zeroheight). The opposite outcome is also possible: you can build a site that targets developers only and not show the design-centric stories.&lt;/p&gt;
&lt;p&gt;In other words, pretty much anything you could wish for.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The tips and tricks written above are indeed not the only things that one can do to improve the Storybook setup. But they nicely illustrate how you can tailor your team’s Storybook to improve your design system&apos;s adoption across your organization and make its users more satisfied.&lt;/p&gt;
&lt;p class=&quot;blog-post--guest-intro&quot;&gt;
    &lt;a href=&quot;https://varya.me/&quot; target=&quot;_blank&quot;&gt;Varya Stepanova&lt;/a&gt; is a design systems architect—and co-creator of &lt;a href=&quot;http://getbem.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt;BEM&lt;/a&gt;—based in Finland. Varya has improved the way dozens of teams, large and small, develop and evolve their design process towards better collaboration among stakeholders.
&lt;/p&gt;
&lt;aside class=&quot;posts-list-list&quot;&gt;
  &lt;h2&gt;Related article:&lt;/h2&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2021-01-15-design-tokens-and-components/&quot;&gt;
        The context dilemma: design tokens and components
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      Design tokens are used to keep a consistent look across an entire system. How do you name them semantically if they have to make sense everywhere but also respond to the inner logic of individual components which are independently developed? 
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2021-01-15-design-tokens-and-components/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2021-08-04-interactors-design-systems/&quot;&gt;
        Interactors: the design systems testing ally
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      Components from a design system make building UIs easy. It should be just as easy to test them. Interactors enable more robust tests for component-based UIs, and improve component libraries&apos; maintainability.
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2021-08-04-interactors-design-systems/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/aside&gt;</content:encoded><media:content url="https://frontside.com/static/683168e1a545f8c5e3d2d1988a6f14df/2a4de/2021-helping-designers-and-developers-storybook.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[There and Back Again: Testing and Stack Upgrades]]></title><description><![CDATA[Upgrading your application stack to new major versions can be terrifying, especially when you have a massive application with 75 developers working on features non-stop. However, a good testing strategy gives you confidence to make bold moves that take your organization to heretofore unexplored lands.]]></description><link>https://frontside.com/blog/2021-02-18-there-and-back-again-testing-and-upgrades/</link><guid isPermaLink="false">https://frontside.com/blog/2021-02-18-there-and-back-again-testing-and-upgrades/</guid><category><![CDATA[testing]]></category><dc:creator><![CDATA[Taras Mankovski]]></dc:creator><pubDate>Thu, 18 Feb 2021 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Upgrading your application stack to new major versions can be terrifying, especially when you have a massive application with 75 developers working on features non-stop. The situation gets more complicated when you also have important deadlines pressing down on you, new defects popping up every day, mounting tech debt, and 30% of the team is new to the company. What should be prioritized and what can wait? My call in 2018 was none of the above. Instead I reached for J. R. R. Tolkein for inspiration to find the one “ring” that would address all these issues in one fell swoop. After surveying the options I put automated testing at the front of the queue. But unlike in &lt;em&gt;Lord of the Rings&lt;/em&gt;, automated testing didn’t cause more problems than it solved – in fact my decision paid off big time.&lt;/p&gt;
&lt;p&gt;I was hired by a major bank who had recently acquired a development firm in India and was facing tough challenges within their engineering organization. They had brought in several consulting firms to do staff augmentation, and everyone was doing their best to keep hitting delivery targets. But every step forward seemed to be met with two steps backward, and the quality of the product was in decline. They started to look a lot like Frodo and Sam going in circles on their way to Mordor.&lt;/p&gt;
&lt;p&gt;It turned out that part of the problem was that the application was being built on top of an early and balkier version of modern JavaScript. A newer version of the framework allowed lazy loading parts of the application, which could solve performance issues that they were experiencing. Upgrading was both necessary and urgent so the team could use open source solutions that were available without requiring them to completely rewrite the application.&lt;/p&gt;
&lt;p&gt;But how do you go about upgrading an application that is under active development? First of all, you need a way to tell that everything works properly throughout the upgrade process. There were more than 10 rounds of upgrades to perform to take the app to the most recent one, and each one might prove to introduce complications rivaling those that Saruman put in the way of the Fellowship of the Ring. Frodo and Sam went on foot to Mount Doom, but as anyone familiar with the epic knows their journey was interminably long. Manual tests would face the same fate, making the upgrade process impossibly slow, especially in light of the size of the app in question.&lt;/p&gt;
&lt;p&gt;What we needed was a test suite and a robust one at that. The codebase had a few unit tests sprinkled here and there but they didn’t inspire any more confidence than the “assistance” of Merry and Pippin did. QA had a test suite but it was too slow and unreliable to run on every commit. We needed one that developers could use locally, that would run quickly on CI, and that would give us the confidence that we didn’t break anything. Our tests had to put the whole app under the microscope and ensure everything worked correctly from the users&apos; perspective. This is what I call “testing big.”&lt;/p&gt;
&lt;p&gt;Building that test suite was the problem that we had to address first. It took a good deal of convincing to get their technical leadership on board with prioritizing testing in the midst of so much pressure. When I first floated my proposal to switch gears and prepare tests in order to upgrade the application stack, the architects in the room looked at me as if I was as crazy as Frodo in setting out to destroy the ring.&lt;/p&gt;
&lt;p&gt;Yet I was confident that robust testing and a sound tech stack was the most urgent need for the company to address. Developing a test suite is relatively predictable, and once you have tests that you can trust, even scary upgrades become predictable. My confidence in testing did not come from a false belief in my own ability but like Frodo from a belief in those around me. In this case it stemmed from the experience of the entire Ember.js community and ecosystem, which had made testing a fundamental part of their mindset. The framework the client was using was Ember 1.13 and we were aiming for 2.8 – an impossible task in the eyes of many at the company. But what they were not aware of was the framework’s hidden strength: seamless upgrading thanks to automated testing. The combination of the two is very effective, and community surveys show that &lt;a href=&quot;https://emberjs.com/ember-community-survey-2019/#MS_Q401&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;41% of the users use the most recent version, and more 80% use the latest major version&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I was on site in Bangalore leading the team who would be responsible for writing this first test suite. The client assigned six engineers to the newly formed team – those who had the most knowledge about the app. We had six weeks to succeed or die trying.&lt;/p&gt;
&lt;p&gt;We first developed a test harness, which required creating simulation mechanisms for authentication and the backend responses. The process was a great learning experience, as we discovered patterns in the app and found implementation problems in several sections. By the end of our time together we had finished the test harness, refactored the application to use tests, and had guidelines for creating new tests. After a celebratory dinner of masalas I’ll never forget (no lembas bread for us) I returned home to Canada. In the meantime, the team managed to merge all the new features that had been put on hold while they were writing tests. Better yet was the fact that they were able to use the test suite to make sure that the new features didn&apos;t break anything in the app – a wholly new experience for the team. They additionally had developed strict testing policies to accept new PRs.&lt;/p&gt;
&lt;p&gt;Once the codebase was fully tested and stable, I returned to Bangalore to drive the upgrade process. The process was predictable as we were following deprecation warnings progressively, and fixing failing tests as we moved along. The team discovered many unpleasant surprises in the codebase as we refactored through the app. Just as Frodo grew in his knowledge as a result of his journey, I used those cases as learning opportunities to explain to the team why change in their development process was necessary. But we were able to go through two years of evolution of the framework smoothly in just six weeks.&lt;/p&gt;
&lt;p&gt;Not only did we do a massive upgrade, we had tested the entire application and developed a testing mindset across the frontend team. And this was all done by a small team who had no prior experience testing or upgrading tech stacks.&lt;/p&gt;
&lt;p&gt;Long story short: investing in your test suite pays off, but you need to make sure that that investment is covering your business value: your users. Testing big gives you confidence to keep pushing forward, knowing that you can try new things because your app functionality is protected. Without the fear of costly mistakes your creativity increases, and like Frodo you have more time to make bold moves that take your organization to heretofore unexplored lands.&lt;/p&gt;
&lt;aside class=&quot;posts-list-list&quot;&gt;
  &lt;h2&gt;Related article:&lt;/h2&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2020-triple-threat-to-testing-part-1-speed/&quot;&gt;
        The Triple Threat to Testing — Part 1: Speed
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      Speed, reliability, and relevance constitute the mains pillars of a robust testing strategy. The faster a test suite can diagnose an issue in its application, the more value it renders. In this article, we navigate through the most significant causes of slow tests and suggest ideas to deal with them.
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2020-triple-threat-to-testing-part-1-speed/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/aside&gt;</content:encoded><media:content url="https://frontside.com/static/fd7c8e9fa73b8fad253cbac7e22727f6/2a4de/2021-testing-rings.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Kubernetes: Dip your toes in this]]></title><description><![CDATA[Kubernetes is on the rise and having it in your toolkit can get you a long way. In this article, Min shows us how to set up a MicoK8s in your local machine.]]></description><link>https://frontside.com/blog/2021-01-29-kubernetes-wet-your-toes/</link><guid isPermaLink="false">https://frontside.com/blog/2021-01-29-kubernetes-wet-your-toes/</guid><category><![CDATA[kubernetes]]></category><category><![CDATA[CI/CD]]></category><dc:creator><![CDATA[Min Kim]]></dc:creator><pubDate>Fri, 29 Jan 2021 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Kubernetes is perhaps one of the most exciting developments in the DevOps world in the last 15 years. It is an open source implementation of the Borg system that was Google’s “secret sauce” – the thing that allowed them to deploy and manage thousands of services in their clusters.&lt;/p&gt;
&lt;p&gt;With modern cloud PaaS (platform as a service) like Google Cloud and AWS, most frontend and many backend developers can deploy services without learning about the architecture and technologies that power these platforms. In the past, not knowing about these platforms could be easily forgiven because the learning curve was too steep.&lt;/p&gt;
&lt;p&gt;Kubernetes changes all that. It makes understanding these platforms approachable and manageable, allowing frontend developers to learn all about them fairly quickly. The architecture of Kubernetes and the approach that the community is taking towards building Kubernetes continuously lowers the barrier for people who otherwise wouldn’t have an opportunity to learn about Cloud Native Deployment.&lt;/p&gt;
&lt;p&gt;At its core, Kubernetes is based on a concept that anyone familiar with React would recognize. It’s a declarative system for service management. Similar to how React allows you to declare what components you want to render with it handling the creation of DOM elements, Kubernetes allows you to declare what services you want to deploy and it takes care of deploying them.&lt;/p&gt;
&lt;p&gt;Grasping this comparison can take you surprisingly far into understanding Kubernetes. For example, you can use the same components’ syntax to describe their composition for both web and mobile platforms. React DOM and React Native are adapters that control how your components are rendered in these different environments. Similarly, you can use the same services and same syntax to deploy services to Google Cloud, AWS, Azure or Digital Ocean via different &lt;a href=&quot;https://kubernetes.io/docs/concepts/cluster-administration/cloud-providers/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;cloud providers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;React takes care of the difficult work of applying declarative state changes to DOM. Kubernetes does the hard work of applying declarative state changes to your infrastructure and services. The important part to remember is that with Kubernetes, you tell it what to do rather than how to do it.&lt;/p&gt;
&lt;p&gt;Under the hood, Kubernetes consists of a &lt;a href=&quot;https://kubernetes.io/docs/concepts/overview/components/%23control-plane-components&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;control panel&lt;/a&gt; that manages worker &lt;a href=&quot;https://kubernetes.io/docs/concepts/overview/components/%23node-components&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;nodes&lt;/a&gt;. The control panel’s API is RESTful, but most of the time you’re not going to be interacting with the API directly. Instead you’ll use the CLI, which talks to the RESTful API. The control panel’s specs are agreed on by the Kubernetes community, but the API definition makes it possible for different implementations of Kubernetes to exist.&lt;/p&gt;
&lt;p&gt;In this tutorial, we’ll show you how to set up MicroK8S, which is Ubuntu’s implementation of Kubernetes. It’s small enough to run on your machine and will allow you to play around with Kubernetes without having to pay a cloud provider to host it for you.&lt;/p&gt;
&lt;h2 id=&quot;installation-and-start&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#installation-and-start&quot; aria-label=&quot;installation and start permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Installation and Start&lt;/h2&gt;
&lt;p&gt;Let’s go ahead and install MicroK8S for macOS:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ brew install ubuntu/microk8s/microk8s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;For installation instructions for Windows or Linux, go to the &lt;a href=&quot;https://microk8s.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;MicroK8S website&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once it has finished installing, run the following commands:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ microk8s install
$ microk8s start&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;microk8s install&lt;/code&gt; will start the VM and &lt;code class=&quot;language-text&quot;&gt;microk8s start&lt;/code&gt; will create a Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;Once you start up a cluster, you should be able to run the &lt;code class=&quot;language-text&quot;&gt;microk8s status&lt;/code&gt; command to display all of the available services. Entering &lt;code class=&quot;language-text&quot;&gt;microk8s stop&lt;/code&gt; into your terminal will shut off both the VM and the cluster.&lt;/p&gt;
&lt;h2 id=&quot;dashboard&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#dashboard&quot; aria-label=&quot;dashboard permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Dashboard&lt;/h2&gt;
&lt;p&gt;Although all of MicroK8S’ functionality can be accessed via your terminal, you can also start up the dashboard service and see everything through the web UI.&lt;/p&gt;
&lt;p&gt;Run &lt;code class=&quot;language-text&quot;&gt;microk8s dashboard-proxy&lt;/code&gt; and you should see the following output:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ microk8s dashboard-proxyChecking if Dashboard is running.
Waiting for Dashboard to come up.
Dashboard will be available at https://xxx.xxx.xx.x:xxxxx
Use the following token to login:
abcdefgh1234567
Forwarding from 0.0.0.0:xxxx -&gt; xxxx&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Go to your browser and enter in the address provided (including the https://) and copy/paste the token to gain access to your dashboard, which will look something like this:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-01-kubernetes/dashboard.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Microk8s Dashboard screenshot&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Now when you go back to your terminal, entering the &lt;code class=&quot;language-text&quot;&gt;microk8s status&lt;/code&gt; command will show that the dashboard has been enabled. If you wish you can run &lt;code class=&quot;language-text&quot;&gt;microk8s disable dashboard&lt;/code&gt; to disable it again.&lt;/p&gt;
&lt;h2 id=&quot;kubectl&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#kubectl&quot; aria-label=&quot;kubectl permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Kubectl&lt;/h2&gt;
&lt;p&gt;Coo-beck-tul? Cube-control? However it’s pronounced, &lt;code class=&quot;language-text&quot;&gt;kubectl&lt;/code&gt; is a MicroK8S command to help you control Kubernetes clusters; like the ones we started earlier with &lt;code class=&quot;language-text&quot;&gt;microk8s start&lt;/code&gt;. Let’s use &lt;code class=&quot;language-text&quot;&gt;kubectl&lt;/code&gt; to deploy a service. For this tutorial we’ll be using a lightweight microservice: &lt;a href=&quot;https://github.com/stefanprodan/podinfo&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://github.com/stefanprodan/podinfo&lt;/a&gt;. The service itself does not do much. It is just to help us practice starting and stopping Kubernetes services.&lt;/p&gt;
&lt;p&gt;Use the following command to deploy Podinfo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ microk8s kubectl apply -k github.com/stefanprodan/podinfo//kustomize&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now you can run &lt;code class=&quot;language-text&quot;&gt;microk8s kubectl get deployments&lt;/code&gt; to confirm that &lt;code class=&quot;language-text&quot;&gt;podinfo&lt;/code&gt; has been deployed.&lt;/p&gt;
&lt;h2 id=&quot;k9s&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#k9s&quot; aria-label=&quot;k9s permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;k9s&lt;/h2&gt;
&lt;p&gt;We haven’t port-forwarded our deployment so we can’t access it with a browser just yet. There’s a way to port-forward with &lt;code class=&quot;language-text&quot;&gt;microk8s&lt;/code&gt; but we’ll show you an easier way using &lt;code class=&quot;language-text&quot;&gt;k9s&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You’ll need to first install it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ brew install k9s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After it finishes installing, you can start it up using the command &lt;code class=&quot;language-text&quot;&gt;k9s&lt;/code&gt;. Your terminal should look something similar to this:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-01-kubernetes/k9s-terminal.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;k9s running on terminal screenshot&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can exit out of &lt;code class=&quot;language-text&quot;&gt;k9s&lt;/code&gt; with either &lt;code class=&quot;language-text&quot;&gt;ctrl + c&lt;/code&gt; or you can press &lt;code class=&quot;language-text&quot;&gt;:&lt;/code&gt; to initiate a command and enter &lt;code class=&quot;language-text&quot;&gt;quit&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In order for &lt;code class=&quot;language-text&quot;&gt;k9s&lt;/code&gt; to work properly, you’ll need to add your Kubernetes configuration to your local root directory:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$ mkdir ~/.kube &amp;amp;&amp;amp; microk8s config &gt; ~/.kube/config&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now when you start up &lt;code class=&quot;language-text&quot;&gt;k9s&lt;/code&gt; again, you’ll notice the configurations have taken effect.&lt;/p&gt;
&lt;p&gt;If you’ve been following along with all of the previous steps, your &lt;code class=&quot;language-text&quot;&gt;k9s&lt;/code&gt; screen should show the pods that we deployed earlier:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-01-kubernetes/k9s-listed-pods.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;k9s with pods listed screenshot&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;What we’re seeing here are the pods from the service we deployed. We’ll be returning to this page very shortly, but for practice if you want to navigate to the list of deployments, press &lt;code class=&quot;language-text&quot;&gt;:&lt;/code&gt; and type in &lt;code class=&quot;language-text&quot;&gt;deployments&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-01-kubernetes/k9s-deployments.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;k9s with deployments listed screenshot&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;To port-forward this deployment, press &lt;code class=&quot;language-text&quot;&gt;enter&lt;/code&gt; on &lt;code class=&quot;language-text&quot;&gt;podinfo&lt;/code&gt; to display its pods again.&lt;/p&gt;
&lt;p&gt;Navigate to any one of the pods and press &lt;code class=&quot;language-text&quot;&gt;shift + f&lt;/code&gt; to port-forward the service. Then press &lt;code class=&quot;language-text&quot;&gt;f&lt;/code&gt; to see the hosted URL. Copy and paste this URL to your browser and you should be able to see the service.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-01-kubernetes/podinfo.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Podinfo screenshot&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Kubernetes is on the rise and having it in your toolkit can get you a long way. Now that you’ve set up a MicroK8S in your machine, you can play around with the basics to start getting familiar with Kubernetes.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/9f8c35191a7b24c8f12ff00d5b656104/2a4de/hero.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[The context dilemma: design tokens and components ]]></title><description><![CDATA[Design tokens are used to keep a consistent look across an entire system. How do you name them semantically if they have to make sense everywhere but also respond to the inner logic of individual components which are independently developed? ]]></description><link>https://frontside.com/blog/2021-01-15-design-tokens-and-components/</link><guid isPermaLink="false">https://frontside.com/blog/2021-01-15-design-tokens-and-components/</guid><category><![CDATA[design-systems]]></category><category><![CDATA[dx]]></category><dc:creator><![CDATA[Varya Stepanova]]></dc:creator><pubDate>Fri, 15 Jan 2021 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Design systems are growing in popularity as organizations realize how greatly they empower their various teams to create accessible on-brand web and mobile apps while avoiding duplicated work. However, they often encounter conflicts when mapping established style architecture patterns onto the new abstractions inherent in a design system. In this article I want to talk about a common problem: context and naming around shared variables.&lt;/p&gt;
&lt;p&gt;On one hand there are design tokens, which have been used successfully by countless teams over the years to ensure that elements across their UIs are consistent. There are design tokens for fonts, colors, sizes, spaces, and even indivisible pieces of an interface. Designers want every part of the app interface and all the elements to have the same look and feel, and design tokens were created to help them achieve that outcome.&lt;/p&gt;
&lt;p&gt;On the other hand, design systems emerged to facilitate easier development with premade components while ensuring that style remains consistent. The team employs them to reuse elements and functionality across the app. Components include branded date-pickers, buttons, modals, and other functional elements of an interface. They too can be used across different sections of an app, but their implementation is oriented locally: the styles and logic are written as if the component is an independent element.&lt;/p&gt;
&lt;p&gt;Reuniting these two worlds can be conflicting: how do you name design tokens semantically if they have to make sense everywhere but also respond to the inner logic of individual components which are independently developed? In this article, we&apos;ll explore the problem and how BEM—a well-known naming design pattern—can come to the rescue.&lt;/p&gt;
&lt;h2 id=&quot;the-crux-of-the-matter-illustrated&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-crux-of-the-matter-illustrated&quot; aria-label=&quot;the crux of the matter illustrated permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The crux of the matter illustrated&lt;/h2&gt;
&lt;p&gt;Let&apos;s say we are defining design tokens for colors. We give them semantic names to reflect the meaning of each color:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sass&quot;&gt;&lt;pre class=&quot;language-sass&quot;&gt;&lt;code class=&quot;language-sass&quot;&gt;&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-primary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #f74d7b;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-disabled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;  #767677;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-inverse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #FFFFFF;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-lines&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #404041;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When building components, we could use these tokens to define colors for the component elements. In the case of a checkbox, the chosen names work very well.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-design-tokens/tokens-checks@1.5x.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Diagram showing how $dt-disabled is assigned as color to a disabled checkbox color&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;For a component of similar semantic meaning, we can use the same names. You can see below how the design tokens translate to the scope of a radio button:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-design-tokens/tokens-radios@1.5x.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Diagram showing how $dt-disabled is assigned as color to a disabled radio color&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;However, when it comes to a different component, the same names may not reflect the purpose of the color even though the color palette stays the same. Let&apos;s have a closer look at a hypothetical progress bar where we re-use the colors we had available:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-design-tokens/tokens-bar@1.5x.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Diagram showing how $dt-disabled is assigned as color to the empty space of a progress bar because for aesthetic purposes&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The &quot;primary&quot; color works well for the progress content color. But the label text uses &quot;lines&quot; and the bar’s background is “disabled.&quot; These names are confusing and make the component styles fragile. We’d be in trouble if, say in a later iteration, the color of the lines is changed to a very light gray, making the progress bar label hard to read as an unintended side-effect.&lt;/p&gt;
&lt;p&gt;It would make sense to keep color-like names for the tokens, because then they easily translate to any component. But how semantic are such names?&lt;/p&gt;
&lt;h2 id=&quot;meet-me-at-the-middle-layer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#meet-me-at-the-middle-layer&quot; aria-label=&quot;meet me at the middle layer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Meet me at the middle layer&lt;/h2&gt;
&lt;p&gt;With design tokens we are trying to create a global context for the whole interface we are building, including future not-yet-known components. No matter how thoroughly we try to anticipate all the different twists and turns app development might take, we will never cover all future bases. It may seem that we nailed it on the first iteration, but sooner or later new components will come and shatter our pristine global token names – that is unless we introduce a middle-layer between the universal design token and the variables used within the context of a component.&lt;/p&gt;
&lt;p&gt;Middle layers are common practice in software engineering when we have to match two abstractions. In this case, we introduce local design tokens that make sense at the component context level but which receive their data from universal design tokens.&lt;/p&gt;
&lt;p&gt;Let&apos;s transform our previous example into a middle layer approach. Doing so requires us to think differently about the semantics we provide to our tokens. In this iteration, let&apos;s define our global design tokens as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sass&quot;&gt;&lt;pre class=&quot;language-sass&quot;&gt;&lt;code class=&quot;language-sass&quot;&gt;&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--900&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #000000;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--700&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #404041;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$ds-color__neutral--400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #767677;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #FFFFFF;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--900&lt;/span&gt;;&lt;/span&gt;

&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-color__primary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #f74d7b;&lt;/span&gt;

&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$ds-color__transparent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice that now instead of being prescriptive about the purpose of each color, the semantics of the variable names lean on describing the color. For instance, instead of the name &lt;code class=&quot;language-text&quot;&gt;$dt-disabled&lt;/code&gt; we use &lt;code class=&quot;language-text&quot;&gt;$dt-color__neutral--700&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Within a component we will not use the global design tokens directly as we did before. Rather, we&apos;ll define new component-scoped variables to serve as a middle layer. It&apos;s only at this point that we associate functionality to our design tokens:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sass&quot;&gt;&lt;pre class=&quot;language-sass&quot;&gt;&lt;code class=&quot;language-sass&quot;&gt;&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--700&lt;/span&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__border--disabled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$ds-color__neutral--400&lt;/span&gt;;&lt;/span&gt;

&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__content--active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--100&lt;/span&gt;;&lt;/span&gt;

&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$dt-color__transparent&lt;/span&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__background--disabled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$ds-color__neutral--400&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using the middle layer approach we employ these variables in the checkbox component instead of referencing the universal design tokens directly:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-design-tokens/middle-checks@1.5x.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Diagram showing how $dt-form__background--disabled is assigned as color to a disabled radio color&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;And because radio buttons and check buttons share the same semantics for colors, we can reuse those names for both components:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-design-tokens/middle-radios@1.5x.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Diagram showing how $dt-form__background--disabled is assigned as color to a disabled radio color&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Best of all, we don&apos;t have the problem of conflicting names for the progress bar. Instead, we can define a local design tokens that make sense for the different elements of the component while still using the overall colors:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;$dt-progressbar__background: $ds-color__neutral--400;
$dt-progressbar__content: $dt-color__primary;
$dt-progressbar__text: $ds-color__neutral—700;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2021-design-tokens/middle-bar@1.5x.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Diagram showing how $dt-progressbar__background is assigned as color to the empty space of a progress bar&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-naming-old-friend-bem&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-naming-old-friend-bem&quot; aria-label=&quot;a naming old friend bem permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A naming old-friend: BEM&lt;/h2&gt;
&lt;p&gt;Does the naming scheme for the variables remind you of something? It should: it&apos;s &lt;a href=&quot;http://getbem.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Block-Element-Modifier syntax&lt;/a&gt;. BEM was created to help developers write consistent CSS before contextual styles were available. Technically, in these times of CSS-in-JS solutions, we have a scope per every component, so there is no need to simulate &quot;unique&quot; CSS classes (which was BEM&apos;s original intent). However, given its popularity, BEM can help developers create consistent variable names for design tokens &lt;em&gt;without&lt;/em&gt; introducing new mental models.&lt;/p&gt;
&lt;p&gt;Following BEM in choosing the names for our variables, we can define the main entities of our system (aka &quot;blocks&quot;): sometimes they are the components and other times semantical groups of components (like &quot;form&quot;). The &quot;elements&quot; are the parts that comprise the components, and &quot;modifiers&quot; are optional variants for components.&lt;/p&gt;
&lt;p&gt;By defining the variables this way we can set up the inner structure of the component(s) we are developing, listing all their elements and modifications. Everything becomes visible, leading to what I call “conscious development.”&lt;/p&gt;
&lt;p&gt;The same naming scheme can work for both universal design tokens and per-component variables. As we observed above, we can describe universal design tokens with BEM&apos;s conventions around semantics:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sass&quot;&gt;&lt;pre class=&quot;language-sass&quot;&gt;&lt;code class=&quot;language-sass&quot;&gt;&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--900&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #000000;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--700&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #40404A;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$ds-color__neutral--400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #D2D2D6;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #FFFFFF;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--900&lt;/span&gt;;&lt;/span&gt;

&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-color__primary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #006AED;&lt;/span&gt;

&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$ds-color__transparent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case &lt;code class=&quot;language-text&quot;&gt;color&lt;/code&gt; is the block we&apos;re describing, &lt;code class=&quot;language-text&quot;&gt;neutral&lt;/code&gt; an element of that block, and &lt;code class=&quot;language-text&quot;&gt;900&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;700&lt;/code&gt; are variations.&lt;/p&gt;
&lt;p&gt;In the component variables example, we describe all the inner component elements and their states. With the form case the full list will be more extensive than before:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sass&quot;&gt;&lt;pre class=&quot;language-sass&quot;&gt;&lt;code class=&quot;language-sass&quot;&gt;&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--700&lt;/span&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-from__border--active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$dt-color__primary&lt;/span&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-from__border--disabled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$ds-color__neutral--400&lt;/span&gt;;&lt;/span&gt;

&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$dt-color__transparent&lt;/span&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__content--active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$dt-color__neutral--100&lt;/span&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__content--disbaled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$ds-color__neutral--400&lt;/span&gt;;&lt;/span&gt;

&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$dt-color__transparent&lt;/span&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__background--active&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$dt-color__primary&lt;/span&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable-line&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$dt-form__background--disabled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$ds-color__neutral--400&lt;/span&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that the same colors translate to more than one variable. Even if two styles are visually similar, sometimes they have different meanings. Having a fine-grained semantic description for the design tokens of our components helps us decouple styles from tokens, which will enable us to execute future changes more easily when the time comes for a rebranding or a new dark theme.&lt;/p&gt;
&lt;h2 id=&quot;middle-layers-work-everywhere&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#middle-layers-work-everywhere&quot; aria-label=&quot;middle layers work everywhere permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Middle layers work everywhere&lt;/h2&gt;
&lt;p&gt;As you may notice, the examples in this article are given in SCSS. However, it&apos;s worth to highlight that the idea of a middle layer connecting global design tokens with the scope of each independent component is conceptually technology agnostic.&lt;/p&gt;
&lt;p&gt;For example, the same approach will work with styled-components. We&apos;d define our universal style tokens as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; colors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token string-property property&quot;&gt;&apos;neutral--900&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#000000&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token string-property property&quot;&gt;&apos;neutral--700&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#40404A&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token string-property property&quot;&gt;&apos;neutral--400&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#D2D2D6&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token string-property property&quot;&gt;&apos;neutral--100&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#FFFFFF&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token string-property property&quot;&gt;&apos;neutral&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#000000&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

&lt;span class=&quot;token string-property property&quot;&gt;&apos;primary&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#006AED&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

&lt;span class=&quot;token string-property property&quot;&gt;&apos;transparent&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;transparent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And implement the component-specific tokens like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; colors &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./tokens.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; form &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;border&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; colors&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;neutral--700&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;border--active&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; colors&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;primary&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;border--disabled&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; colors&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;neutral--400&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token string-property property&quot;&gt;&apos;content&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; colors&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;transparent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;content--active&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; colors&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;neutral--100&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;content--disbaled&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; colors&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;neutral--400&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token string-property property&quot;&gt;&apos;background&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; colors&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;transparent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;background--active&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; colors&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;primary&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;background--disabled&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; colors&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;neutral--400&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; StyledCheckbox &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; styled&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;div`
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;disabled &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; form&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;background--disabled&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; form&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;background&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because we naturally have scopes with styled-components (and JavaScript in general), there is no need to follow BEM for naming any more. However, I like to still have the modifiers for the described entities named this way because it helps keep the structure flat.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Re-assigning design tokens to per-component variables makes it possible to define the design tokens as global entities but develop the components operating within their own semantic context. The middle layer approach pushes designers to explicitly describe the component visual architecture and that translates to its better understanding. Such a “conscious development” approach is especially helpful when the work is shared by the team.&lt;/p&gt;
&lt;p class=&quot;blog-post--guest-intro&quot;&gt;
    &lt;a href=&quot;https://varya.me/&quot; target=&quot;_blank&quot;&gt;Varya Stepanova&lt;/a&gt; is a design systems architect—and co-creator of &lt;a href=&quot;http://getbem.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt;BEM&lt;/a&gt;—based in Finland. Varya has improved the way dozens of teams, large and small, develop and evolve their design process towards better collaboration among stakeholders.
&lt;/p&gt;
&lt;aside class=&quot;posts-list-list&quot;&gt;
  &lt;h2&gt;Related article:&lt;/h2&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2021-04-07-helping-designers-and-developers-storybook/&quot;&gt;
        Unleashing the Genie: Helping both designers and developers with Storybook
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      Good documentation is key to design systems. However, what &quot;good&quot; means varies according to the reader. This article will go through tips to generate documentations for designers and developers from a single Storybook—keep everyone happy with minimum effort!
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2021-04-07-helping-designers-and-developers-storybook/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2021-08-04-interactors-design-systems/&quot;&gt;
        Interactors: the design systems testing ally
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      Components from a design system make building UIs easy. It should be just as easy to test them. Interactors enable more robust tests for component-based UIs, and improve component libraries&apos; maintainability.
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2021-08-04-interactors-design-systems/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/aside&gt;</content:encoded><media:content url="https://frontside.com/static/275837a01039bd9f3ba22079182d43f8/2a4de/design-tokens-header.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Renaming `main` with purpose ]]></title><description><![CDATA[As generic default branch names like `master` for Git repos have gone out of fashion, possibilities emerge for more effective and informative naming conventions. Learn about the branch naming strategy Frontside uses for our Open Source libraries and how we name app project branches.]]></description><link>https://frontside.com/blog/2020-12-11-default-branch-names/</link><guid isPermaLink="false">https://frontside.com/blog/2020-12-11-default-branch-names/</guid><category><![CDATA[continuous-delivery]]></category><category><![CDATA[best-practices]]></category><category><![CDATA[dx]]></category><dc:creator><![CDATA[Jorge Lainfiesta]]></dc:creator><pubDate>Fri, 11 Dec 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At Frontside &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; (or any similar name) has never seemed like a great branch name. Like many developers, we navigate through different kinds of repositories all the time, from user-facing apps to Open Source libraries. It can be difficult to keep track of how code flows from development to its final purpose when merging our work into a codebase, making naming branches not just a matter of efficiency but affecting the clarity of the code as well.&lt;/p&gt;
&lt;p&gt;Every project has its own goal and process, which means that merging code into &apos;main&apos; has different meanings. For instance, it&apos;s not the same to merge a PR into a Jamstack blog that will immediately publish the new content as it is to merge a PR into a finance app that has to go through manual QA before getting published. The same applies to library maintenance: submit a PR to a private library with few users is quite different than to submit it to a widely adopted Open Source library.&lt;/p&gt;
&lt;p&gt;That&apos;s why we propose naming the default branch of each repository such that it reflects its purpose. For instance, in &lt;code class=&quot;language-text&quot;&gt;effection&lt;/code&gt;—a library we maintain—the default branch is &lt;code class=&quot;language-text&quot;&gt;v0&lt;/code&gt; because the code merged there is part of version zero, and we cut releases from it. Another example is our website: the default branch is called &lt;code class=&quot;language-text&quot;&gt;production&lt;/code&gt; because everything we merge into it is automatically published to production.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2020-12-11-default-branch-name--screenshot.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshot of PR getting merged to &apos;production&apos;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The author and reviewers of a PR that will be merged into &lt;code class=&quot;language-text&quot;&gt;production&lt;/code&gt; are now conscious of the aims and purpose in the code in question.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this article, we present Frontside’s naming strategy for semver libraries and the guiding principle we use for apps repositories. We also share our ideas about changing the name of the default branch of a repository in the form of a helpful FAQ.&lt;/p&gt;
&lt;h2 id=&quot;semver-libraries&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#semver-libraries&quot; aria-label=&quot;semver libraries permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Semver libraries&lt;/h2&gt;
&lt;p&gt;We follow the popular &lt;a href=&quot;https://semver.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Semantic Versioning&lt;/a&gt; (Semver) format to issue releases. Semver distinguishes three types of releases: &lt;code class=&quot;language-text&quot;&gt;major&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;minor&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;patch&lt;/code&gt;. Although it provides a semantic framework for release names, Semver makes no comment on how each team goes about developing their libraries – there&apos;s still plenty of room to decide how you cut your releases. At Frontside, instead of curating each release manually, we tie major versions to branches so we can cut automated minor and patch releases, which ultimately leads to setting our default branch name to a major version branch instead of simply &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Releases are often manually put together by the maintainers, who also judge the type of release they&apos;re issuing. That means that branches and releases are not coupled: their relationship is curated by the library maintainers on a case-by-case basis. This approach has proven itself effective for many projects, but is an added burden for the maintainers. It becomes especially problematic with monorepos, where several packages with codependencies have to be updated and released at once.&lt;/p&gt;
&lt;p&gt;At Frontside, we instead tie branches to major releases: everything that is merged into a &lt;code class=&quot;language-text&quot;&gt;v1&lt;/code&gt; branch must be releasable in a &lt;code class=&quot;language-text&quot;&gt;v1.x.x&lt;/code&gt; version. That enables us to use &lt;a href=&quot;https://github.com/atlassian/changesets&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;changesets&lt;/a&gt; to cut minor and patch releases with minimal effort – even within monorepos.&lt;/p&gt;
&lt;p&gt;With our approach having a &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; branch is just not helpful. And it&apos;s usually confusing in other approaches too: what can you expect to find in &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt;? the latest released version? a future version? the most popular version? not a release candidate at all? It&apos;s impossible to tell by simply looking at the name, and a lot of (unnecessary) work to dive into the code to find out.&lt;/p&gt;
&lt;p&gt;Instead of using &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; as a default branch, we set our default branch to be the latest major version branch that is currently under development. This means that the default branch will change over time, and that&apos;s a good thing, because the evolving name gives contributors clear directions when navigating the codebase.&lt;/p&gt;
&lt;h2 id=&quot;apps&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#apps&quot; aria-label=&quot;apps permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Apps&lt;/h2&gt;
&lt;p&gt;Unlike libraries, there&apos;s no widely popular way of structuring releases for apps. Apps are wildly different across teams and industries not only in how they look, but also in the way they&apos;re developed and deployed. Our advice is to think of the branch as a pneumatic tube that takes the code somewhere and to ask what is the name of that place? If putting code in that tube means that it will be shuttled to production, then naming the default branch &quot;production&quot; is a sensible idea because (like with our suggestions about libraries) the name offers a clear indication of the code’s purpose instead of requiring you to fish around to find out what the codebase is trying to accomplish.&lt;/p&gt;
&lt;h2 id=&quot;repository-default-branches-a-faq&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#repository-default-branches-a-faq&quot; aria-label=&quot;repository default branches a faq permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Repository Default Branches: a FAQ&lt;/h2&gt;
&lt;h3 id=&quot;why-should-i-move-away-from-master&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-should-i-move-away-from-master&quot; aria-label=&quot;why should i move away from master permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why should I move away from &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt;?&lt;/h3&gt;
&lt;p&gt;You&apos;ll soon become obsolete if you keep &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt; as your default branch. The industry standard for default branches is &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt;, so we advise you to at least move to that name if you haven&apos;t. But we think you’d be wise to shift away from generic names altogether and consider moving to purposeful branch naming.&lt;/p&gt;
&lt;h3 id=&quot;wont-it-be-annoying-to-have-different-default-branch-names-for-my-projects&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#wont-it-be-annoying-to-have-different-default-branch-names-for-my-projects&quot; aria-label=&quot;wont it be annoying to have different default branch names for my projects permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Won’t it be annoying to have different default branch names for my projects?&lt;/h3&gt;
&lt;p&gt;Perhaps at the beginning. But it&apos;s not common for developers to push to &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt;: in fact it&apos;s generally discouraged. Interactions with the default branch are therefore limited: typically to just when cloning a repo, creating a PR, or syncing up with the latest developments.&lt;/p&gt;
&lt;h3 id=&quot;whats-the-upside-of-using-specifically-named-default-branches&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-the-upside-of-using-specifically-named-default-branches&quot; aria-label=&quot;whats the upside of using specifically named default branches permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What’s the upside of using specifically named default branches?&lt;/h3&gt;
&lt;p&gt;Everybody working with your codebase will have a concrete understanding of the goal of the repository. From the very beginning when they clone your repo until when they create a PR, everyone clearly understands the purpose and goal of their work.&lt;/p&gt;
&lt;h3 id=&quot;how-do-i-change-my-default-branch-name&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-do-i-change-my-default-branch-name&quot; aria-label=&quot;how do i change my default branch name permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How do I change my default branch name?&lt;/h3&gt;
&lt;p&gt;Github is making it easier for you to change the default branch of your repository. Check out their recommendations for &lt;a href=&quot;https://github.com/github/renaming&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;renaming your default branch&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Naming is hard. It&apos;s been a challenge in computer science for decades. But what we call things conditions the way we think about them. At Frontside we think it’s time to move away from the “tried and true” generic names – especially when these naming conventions are actually causing inefficiencies and unnecessary work.&lt;/p&gt;
&lt;aside class=&quot;posts-list-list&quot;&gt;
  &lt;h2&gt;Related article:&lt;/h2&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2020-7-reasons-for-good-pull-request-descriptions/&quot;&gt;
        7 reasons to write good Pull Request descriptions
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      A good Pull Request description can lead to better reviews, improved solutions, better documentation, and more. In this article, Taras surveys seven big wins of PR descriptions.
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2020-7-reasons-for-good-pull-request-descriptions/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/aside&gt;</content:encoded><media:content url="https://frontside.com/static/e84e2f02df3737e96cd1588e7578a6f2/2a4de/2020-12-11-default-branch-names.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[MirageJS: Choosing the right Serializer ]]></title><description><![CDATA[MirageJS ships with four out-of-the-box serializers. In this blog post, we overview the basics of serializers in Mirage, and examine in detail the specific format of each JSON API, Active Model, Rest and generic serializers.]]></description><link>https://frontside.com/blog/2020-08-31-mirage-serializers/</link><guid isPermaLink="false">https://frontside.com/blog/2020-08-31-mirage-serializers/</guid><category><![CDATA[simulation]]></category><category><![CDATA[mirage]]></category><category><![CDATA[dx]]></category><dc:creator><![CDATA[Min Kim]]></dc:creator><pubDate>Mon, 31 Aug 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;MirageJS is one of the pioneers in enabling frontend developers to use mocks systematically for their tests and development. It was originally built for Ember.js in 2015, but due to its popularity the maintainers created a standalone version compatible with any javascript framework.&lt;/p&gt;
&lt;p&gt;Mirage introduces itself as a mocking library, but at Frontside we don&apos;t think that&apos;s a good enough term to refer to its extensive power. If your application uses a RESTful API (an &lt;a href=&quot;https://github.com/miragejs/graphql&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;adapter for GraphQL&lt;/a&gt; is on the way), Mirage is a great choice to simulate your backend with high-fidelity outputs. We&apos;ve used Mirage in several projects to enable frontend developers to keep advancing the UI while the backend is not yet ready. Its flexibility also makes it a perfect test companion compatible with many tools out there, including Cypress.&lt;/p&gt;
&lt;p&gt;A key element of Mirage that enables it to generate realistic responses lies on its serializer layer. The serializer takes the data stored in Mirage&apos;s seeded database and outputs it in the format that you configure for it. For an effective &lt;a href=&apos;/blog/2020-07-29-decoupling-teams-through-simulation/&apos; target=&apos;_blank&apos; rel=&apos;nofollow noopener&apos;&gt;simulation strategy&lt;/a&gt;, you want that output format to match exactly your backend API specifications.&lt;/p&gt;
&lt;p&gt;In this article, we&apos;ll explore the four serializers available on Mirage by default. Choosing which one is the right one for you depends on your API formats. There might be a serializer that works with your backend right out of the box or you may have to customize it from a base. After outlining how the serializer layer works in Mirage, we&apos;ll dive into the specifics of each one.&lt;/p&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;
  &lt;h2&gt;Already familiar with serializers? Jump to:&lt;/h2&gt;
  &lt;ul&gt;
      &lt;li&gt;
          &lt;a href=&apos;#json-api-serializer&apos;&gt;JSON API Serializer&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&apos;#active-model-serializer&apos;&gt;Active Model Serializer&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&apos;#rest-serializer&apos;&gt;Rest Serializer&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&apos;#serializer&apos;&gt;Generic Serializer&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&quot;#cheat-sheet&quot;&gt;Cheat sheet&lt;/a&gt;
      &lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;
&lt;h2 id=&quot;how-mirage-serializers-work&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-mirage-serializers-work&quot; aria-label=&quot;how mirage serializers work permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How Mirage Serializers Work&lt;/h2&gt;
&lt;p&gt;Understanding how Mirage’s various serializers work begins with reviewing how data flows thought Mirage. At the most basic level, Mirage allows you to create mocks in a traditional way, returning hand-crafted objects:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/blog-posts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Beyond mocking&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;A lesson about Interactors&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Github Actions: all about pull_request&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, hand-crafted anything is not a scalable solution, and these sorts of objects become difficult to maintain when your data relies on relationships.&lt;/p&gt;
&lt;p&gt;Instead, we recommend taking advantage of Mirage modeling and &lt;a href=&quot;https://miragejs.com/docs/main-concepts/orm/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ORM&lt;/a&gt; capabilities so you can shape your backend in Mirage and seed it with generated data. As the snipped code below illustrates, you can use the seeded models of the database directly from your route handle:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/users&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;schema&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case you don&apos;t have to manually deal with IDs, formats, or the concrete user records. Instead, you use a schema query that will bring records (based on models and factories) from Mirage&apos;s database and output the format that your backend uses.&lt;/p&gt;
&lt;p&gt;In order to do that, you have to set up models, factories, and serializers in Mirage. Models deal with the relationship between records, factories generate sample data for the records&apos; attributes, and serializers format how the records will be mapped in a JSON response. The following diagram illustrates how these pieces come together to enable you to query records in your Mirage route handles:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2020-08-21-mirage-serializers-setup.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Diagram: Set up relationships → configure data generation → specify JSON response format through serializers → Query schema on route handle&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The role of the serializer is to map the data to a JSON structure that matches your backend needs. The structure of the JSON refers to how the object keys are named and what&apos;s nested inside which keys.&lt;/p&gt;
&lt;p&gt;Given that the serializer&apos;s main purpose is to make it easy for you to have Mirage outputting realistic data for your frontend, we recommend discussing with your backend team how they plan to format the responses from their endpoints. Then you can compare those responses to what the different Mirage serializers offer and choose the closest one, customizing it if necessary.&lt;/p&gt;
&lt;h2 id=&quot;model-and-factories-setup&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#model-and-factories-setup&quot; aria-label=&quot;model and factories setup permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Model and Factories Setup&lt;/h2&gt;
&lt;p&gt;The job of a serializer is to provide a format that represents the attributes and relationships of the records stored in Mirage’s database. To illustrate how the different serialiser options work, in this section we’ll describe a hypothetical set up. It’s worth noting at the outset that in Mirage models only describe relationships, not attributes; that means attributes can be defined arbitrarily when the model is instantiated in a factory.&lt;/p&gt;
&lt;p&gt;In the code below we’ll use three models to describe the relationships among our data:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;blogPosts&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hasMany&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token literal-property property&quot;&gt;blogPost&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
	&lt;span class=&quot;token literal-property property&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;belongsTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;post_blogComments&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hasMany&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token literal-property property&quot;&gt;post_blogComment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;blogPost&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;belongsTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice the inconsistencies in case and separators in the names for the model’s fields. We&apos;ve used arbitrary casing so the effect of the serializers described below is more apparent.&lt;/p&gt;
&lt;p&gt;Now for the factories, we’ll set them as described below. As we mentioned earlier, it’s in this part where the attributes for our records are declared:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;factories&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Factory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;author_emailAddress&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; faker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;blogPost&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Factory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;blogPost_title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; faker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;token literal-property property&quot;&gt;post_blogComment&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Factory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;comment_paragraph&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; faker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Again, to highlight the effects of serializers on the attribute names, notice that in the code above the casing for each attribute is mixed. You can see we&apos;re using a library called &lt;code class=&quot;language-text&quot;&gt;faker&lt;/code&gt; to generate random data to populate the models attributes.&lt;/p&gt;
&lt;p&gt;To make the outputs comparable across serializers, the example responses that we provide are the result of fetching a request for all &lt;code class=&quot;language-text&quot;&gt;blogPosts&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;blogPosts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;data-attributes-on-all-serializers&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#data-attributes-on-all-serializers&quot; aria-label=&quot;data attributes on all serializers permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Data attributes on all serializers&lt;/h2&gt;
&lt;p&gt;Before getting into the specific serializers, let’s address first a peculiarity about attributes that all Mirage serializers share. As it turns out, Mirage doesn’t serialize all the attributes of a response evenly.&lt;/p&gt;
&lt;p&gt;When we fetch all the blog posts with &lt;code class=&quot;language-text&quot;&gt;schema.blogPosts.all( )&lt;/code&gt; we&apos;ll get all the records for blogs posts. If we configure the serializer to &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; relationships, we can expect the authors and comments from such blog posts too. The following diagram illustrates the relationships between blog posts, authors, and comments.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2020-08-21-mirage-relationships.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Diagram: Blog Post has a belongsTo relationship with Author and a hasMany relationship with comments&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Because we’re using &lt;code class=&quot;language-text&quot;&gt;schema.blogPosts.all( )&lt;/code&gt; to get these blog posts, we’ll say that blog posts are the &lt;em class=&quot;blog-post-highlight blog-post-highlight__pink&quot;&gt;queried records&lt;/em&gt;. As mentioned, included in that response we’d have the author of the blog post (through &lt;em class=&quot;blog-post-highlight blog-post-highlight__navy&quot;&gt;belongsTo&lt;/em&gt;). Additionally, we’ll get the blog post comments (through &lt;em class=&quot;blog-post-highlight blog-post-highlight__sky&quot;&gt;hasMany&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Serialization on &lt;em class=&quot;blog-post-highlight blog-post-highlight__pink&quot;&gt;queried records&lt;/em&gt;: attribute names are transformed&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Serializers will only transform the attribute names of the queried records. The transformations applied vary from serializer to serializer; you’ll find the specifics in the sections below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Records from &lt;em class=&quot;blog-post-highlight blog-post-highlight__navy&quot;&gt;belongsTo&lt;/em&gt;: attribute names are not transformed&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Counterintuitively, the serializers in Mirage will not apply any transform to the attribute names of the records coming from a &lt;code class=&quot;language-text&quot;&gt;belongsTo&lt;/code&gt; relationship. This means that the inconsistent attribute name we included in our authors factory will remain as it was declared, &lt;code class=&quot;language-text&quot;&gt;author_emailAddress&lt;/code&gt; no matter which serializer you use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Records from &lt;em class=&quot;blog-post-highlight blog-post-highlight__sky&quot;&gt;hasMany&lt;/em&gt;: attributes are not included&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Perhaps to avoid loading large amounts of data, Mirage does not include the attributes of any record that has been loaded due to a hasMany relationship. This means that although we’ll get a list of the comments associated to the blog post we queried, we will not be able to get any of their attributes.&lt;/p&gt;
&lt;h2 id=&quot;json-api-serializer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#json-api-serializer&quot; aria-label=&quot;json api serializer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;JSON API Serializer&lt;/h2&gt;
&lt;p&gt;This serializer follows the &lt;a href=&quot;https://jsonapi.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;JSON API&lt;/a&gt; specification. A fetch for &lt;code class=&quot;language-text&quot;&gt;blogPosts&lt;/code&gt; with this serializer will return the following response format:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;blog-posts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;attributes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;blog-post-title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;A blog post&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;relationships&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ...
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;included&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;field-names-format-dashes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#field-names-format-dashes&quot; aria-label=&quot;field names format dashes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Field names format: dashes&lt;/h3&gt;
&lt;p&gt;In compliance with JSON API conventions, all field names are changed to use dashes. As you can see in the example, the names that were inconsistently cased are all dasherized now; for instance, &lt;code class=&quot;language-text&quot;&gt;blogPost_title&lt;/code&gt; becomes &lt;code class=&quot;language-text&quot;&gt;blog-post-title&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;response-structure-fixed-top-level-elements&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#response-structure-fixed-top-level-elements&quot; aria-label=&quot;response structure fixed top level elements permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Response structure: fixed top level elements&lt;/h3&gt;
&lt;p&gt;There are two top level keys for the JSON API response: &lt;code class=&quot;language-text&quot;&gt;data&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;included&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The main part of the response is &lt;code class=&quot;language-text&quot;&gt;data&lt;/code&gt;, an array of entries that answer to the query issued. In this case, it&apos;s providing all the blog posts available.&lt;/p&gt;
&lt;p&gt;The other key, &lt;code class=&quot;language-text&quot;&gt;included&lt;/code&gt; will have the record information from the references related to the entries in &lt;code class=&quot;language-text&quot;&gt;data&lt;/code&gt;. By default, &lt;code class=&quot;language-text&quot;&gt;included&lt;/code&gt; is empty on Mirage.&lt;/p&gt;
&lt;h3 id=&quot;relationships-reference-objects&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#relationships-reference-objects&quot; aria-label=&quot;relationships reference objects permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Relationships: reference objects&lt;/h3&gt;
&lt;p&gt;Each record on &lt;code class=&quot;language-text&quot;&gt;data&lt;/code&gt; can have a &lt;code class=&quot;language-text&quot;&gt;relationships&lt;/code&gt; key. In our example, the blog post &lt;code class=&quot;language-text&quot;&gt;belongsTo&lt;/code&gt; an author and &lt;code class=&quot;language-text&quot;&gt;hasMany&lt;/code&gt; blog post comments. By default, the relationships are not included in Mirage by the JSON API serializer.&lt;/p&gt;
&lt;p&gt;To include the relationships, we can &lt;a href=&quot;https://miragejs.com/api/classes/serializer/#include&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;configure the &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; option&lt;/a&gt; in the JSON API serializer. In that case, we&apos;ll get a &lt;code class=&quot;language-text&quot;&gt;relationships&lt;/code&gt; key inside each record from &lt;code class=&quot;language-text&quot;&gt;data&lt;/code&gt; with references to what those authors or comments are.&lt;/p&gt;
&lt;p&gt;Below you can see how a single record looks like when the relationship references are included:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;blog-posts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;attributes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;blog-post-title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;A blog post&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;relationships&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;authors&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;post-blog-comments&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;post-blog-comments&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice that in JSON API Serializer, types are all dasherized and pluralized, and that they are used in every record. For instance, a single author has a type &lt;code class=&quot;language-text&quot;&gt;authors&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, all the records referenced in all the &lt;code class=&quot;language-text&quot;&gt;relationships&lt;/code&gt; key will be loaded in the &lt;code class=&quot;language-text&quot;&gt;included&lt;/code&gt; key of the response.&lt;/p&gt;
&lt;p&gt;Alternatively, we can &lt;a href=&quot;https://miragejs.com/api/classes/jsonapi-serializer/#always-include-linkage-data&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;set the &lt;code class=&quot;language-text&quot;&gt;alwaysIncludeLinkageData&lt;/code&gt; option&lt;/a&gt; to true on the JSON API serializer, with which we&apos;d get the relationship information on the data records, but those related records will not be included in the &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; array.&lt;/p&gt;
&lt;h3 id=&quot;more-details&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#more-details&quot; aria-label=&quot;more details permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More details&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://miragejs.com/api/classes/jsonapi-serializer/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;JSON API Serializer documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/miragejs/miragejs/blob/master/lib/serializers/json-api-serializer.js&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;JSON API Serializer&lt;/code&gt; Source code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;active-model-serializer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#active-model-serializer&quot; aria-label=&quot;active model serializer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Active Model Serializer&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://guides.rubyonrails.org/active_model_basics.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Active Model&lt;/a&gt; is the standard format for Rails APIs responses. Chances are if you don&apos;t already know whether or not you need to use this serializer, you most likely don&apos;t need this one. But let&apos;s still have a look at how this one handles its response. We&apos;ll be evoking the same fetch as the one we used for the JSON API Serializer. This is how the response with the Active Model Serializer would look:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;blog_posts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;blog_post_title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;A blog post&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;author_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;post_blog_comments_ids&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;field-names-format-under_scored&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#field-names-format-under_scored&quot; aria-label=&quot;field names format under_scored permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Field names format: under_scored&lt;/h3&gt;
&lt;p&gt;The Active Model Serializer changes the caps to be under_scored no matter how the original model name was configured. As you can see in the example, the attribute names that were inconsistently cased are all under_scored now; for instance, &lt;code class=&quot;language-text&quot;&gt;blogPost_title&lt;/code&gt; becomes &lt;code class=&quot;language-text&quot;&gt;blog_post_title&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;response-structure-top-level-types&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#response-structure-top-level-types&quot; aria-label=&quot;response structure top level types permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Response structure: top level types&lt;/h3&gt;
&lt;p&gt;The Active Model Serializer presents the entity types on the top level arrays, where the type name is pluralized. Unlike the JSON API Serializer the data is not nested under &lt;code class=&quot;language-text&quot;&gt;data&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;included&lt;/code&gt; objects. You can think of the response having lists of records grouped by type on the top level. In this example, &lt;code class=&quot;language-text&quot;&gt;blog_posts&lt;/code&gt; is the type of the queried objects and it&apos;s at the top level.
Relationships: &lt;code class=&quot;language-text&quot;&gt;_id&lt;/code&gt; suffixed reference (or embedded)&lt;/p&gt;
&lt;p&gt;By default, relationships are not resolved for this serializer. However, we can &lt;a href=&quot;https://miragejs.com/api/classes/serializer/#include&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;configure the &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; option&lt;/a&gt; for the Active Model Serializer and then we&apos;ll receive them as references but in a different format than JSON API.&lt;/p&gt;
&lt;p&gt;If &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; is configured, the records of the related fields in a relationship are also loaded at the top level of the JSON with their type names. In the target object, the reference to that related object is only an &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The field name of the relationship will be appended &lt;code class=&quot;language-text&quot;&gt;_id&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;token property&quot;&gt;&quot;blog_posts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;author_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;authors&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mika&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Additionally, you can decide to &lt;a href=&quot;https://miragejs.com/api/classes/serializer/#embed&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;configure the &lt;code class=&quot;language-text&quot;&gt;embed&lt;/code&gt; option&lt;/a&gt; to nest the relationship object instead of having a reference:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;token property&quot;&gt;&quot;blog_posts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mika&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;more-details-1&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#more-details-1&quot; aria-label=&quot;more details 1 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More details&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/miragejs/miragejs/blob/master/lib/serializers/active-model-serializer.js&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Active Model Serializer&lt;/code&gt; Source code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;rest-serializer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#rest-serializer&quot; aria-label=&quot;rest serializer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Rest Serializer&lt;/h2&gt;
&lt;p&gt;The Rest Serializer is almost identical to the Active Model Serializer except that it transforms names to camelCase instead of under_score. Let&apos;s look at the example output for Rest Serializer:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;blogPosts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;blogPostTitle&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;A blog post&quot;&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;postBlogComments&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;field-names-format-camelcase&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#field-names-format-camelcase&quot; aria-label=&quot;field names format camelcase permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Field names format: camelCase&lt;/h3&gt;
&lt;p&gt;The Rest Serializer changes the caps to use camelCase no matter how the original attribute name was configured. As you can see in the example, the names that were inconsistently cased are all camelCased now; for instance, &lt;code class=&quot;language-text&quot;&gt;blogPost_title&lt;/code&gt; becomes &lt;code class=&quot;language-text&quot;&gt;blogPostTitle&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;response-structure-top-level-types-1&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#response-structure-top-level-types-1&quot; aria-label=&quot;response structure top level types 1 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Response structure: top level types&lt;/h3&gt;
&lt;p&gt;The Rest Serializer presents the entity types on the top level, in the same way Active Model Serializer does: the top level keys are pluralized camelCase types.
Relationships: no-suffix id reference (or embedded)&lt;/p&gt;
&lt;p&gt;By default, relationships are not resolved for this serializer. However, we can &lt;a href=&quot;https://miragejs.com/api/classes/serializer/#include&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;configure the &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; option&lt;/a&gt; for the serializer and then we&apos;ll receive them as references.&lt;/p&gt;
&lt;p&gt;If &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; is configured, the records of the related fields in a relationship are also loaded at the top level of the JSON with their type names. In the target object, the reference to that related object is only an &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt;. The field name of the relationship will not be suffixed with anything:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;token property&quot;&gt;&quot;blogPosts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;authors&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mika&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Additionally, you can decide to &lt;a href=&quot;https://miragejs.com/api/classes/serializer/#embed&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;configure the &lt;code class=&quot;language-text&quot;&gt;embed&lt;/code&gt; option&lt;/a&gt; to nest the relationship object instead of having a reference:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;token property&quot;&gt;&quot;blogPosts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mika&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;more-details-2&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#more-details-2&quot; aria-label=&quot;more details 2 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More details&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/miragejs/miragejs/blob/master/lib/serializers/rest-serializer.js&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Rest Serializer&lt;/code&gt; Source code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;serializer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#serializer&quot; aria-label=&quot;serializer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Serializer&lt;/h2&gt;
&lt;p&gt;Last but not least is the barebone &lt;code class=&quot;language-text&quot;&gt;Serializer&lt;/code&gt; which MirageJS describes as basic. Its behavior is quite similar to Rest Serializer, with the only difference lying in how the relationship references are suffixed.&lt;/p&gt;
&lt;p&gt;Let&apos;s check out the output for Serializer:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;blogPosts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;blogPostTitle&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;A blog post&quot;&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;authorId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;postBlogCommentsIds&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;field-names-format-camelcase-1&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#field-names-format-camelcase-1&quot; aria-label=&quot;field names format camelcase 1 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Field names format: camelCase&lt;/h3&gt;
&lt;p&gt;This serializer changes the caps to use camelCase, no matter how the original attribute name was configured. As you can see in the example, the names that were inconsistently cased are all camelCased now; for instance, &lt;code class=&quot;language-text&quot;&gt;blogPost_title&lt;/code&gt; becomes &lt;code class=&quot;language-text&quot;&gt;blogPostTitle&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;response-structure-top-level-types-2&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#response-structure-top-level-types-2&quot; aria-label=&quot;response structure top level types 2 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Response structure: top level types&lt;/h3&gt;
&lt;p&gt;The Serializer presents the entity types on the top level, in the same way Active Model Serializer does: the top level keys are pluralized camelCase types.
Relationships: &lt;code class=&quot;language-text&quot;&gt;Id&lt;/code&gt; suffix reference (or embedded)&lt;/p&gt;
&lt;p&gt;By default, relationships are not resolved for this serializer. However, we can &lt;a href=&quot;https://miragejs.com/api/classes/serializer/#include&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;configure the &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; option&lt;/a&gt; for this serializer and then we&apos;ll receive them as references.&lt;/p&gt;
&lt;p&gt;If &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; is configured, the records of the related fields in a relationship are also loaded at the top level of the JSON response with their type names. In the target object, the reference to that related object is only an &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The field name of the relationship will be appended &lt;code class=&quot;language-text&quot;&gt;Id&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;token property&quot;&gt;&quot;blogPosts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;authorId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;authors&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mika&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Additionally, you can decide to &lt;a href=&quot;https://miragejs.com/api/classes/serializer/#embed&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;configure the &lt;code class=&quot;language-text&quot;&gt;embed&lt;/code&gt; option&lt;/a&gt; to nest the relationship object instead of having a reference:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;token property&quot;&gt;&quot;blogPosts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mika&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;more-details-3&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#more-details-3&quot; aria-label=&quot;more details 3 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More details&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/miragejs/miragejs/blob/master/lib/serializer.js&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Serializer&lt;/code&gt; Source code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;cheat-sheet&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cheat-sheet&quot; aria-label=&quot;cheat sheet permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cheat sheet&lt;/h2&gt;
&lt;table class=&quot;blog-cheat-sheet&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;JSON API Serializer&lt;/th&gt;
      &lt;th&gt;Active Model Serializer&lt;/th&gt;
      &lt;th&gt;Rest Serializer&lt;/th&gt;
      &lt;th&gt;Serializer&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td class=&quot;row-heading&quot;&gt;Response structure&lt;/td&gt;
      &lt;td&gt;
        Top level &lt;code class=&quot;language-text&quot;&gt;data&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;included&lt;/code&gt; keys.&lt;br/&gt;
        Every type-name is used in plural in each record.
      &lt;/td&gt;
      &lt;td&gt;Top level keys by pluralized type_name.&lt;/td&gt;
      &lt;td&gt;Top level keys by pluralized typeName&lt;/td&gt;
      &lt;td&gt;Top level keys by pluralized typeName&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td class=&quot;row-heading&quot;&gt;Casing transforms&lt;/td&gt;
      &lt;td&gt;dasherized&lt;/td&gt;
      &lt;td&gt;under_score&lt;/td&gt;
      &lt;td&gt;camelCase&lt;/td&gt;
      &lt;td&gt;camelCase&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td class=&quot;row-heading&quot;&gt;Relationships included in response?&lt;/td&gt;
      &lt;td&gt;No, unless &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; is configured.   Option for &lt;code class=&quot;language-text&quot;&gt;alwaysIncludeLInkageData&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;No, unless &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; is configured&lt;/td&gt;
      &lt;td&gt;No, unless &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; is configured&lt;/td&gt;
      &lt;td&gt;No, unless &lt;code class=&quot;language-text&quot;&gt;include&lt;/code&gt; is configured&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td class=&quot;row-heading&quot;&gt;Relationship reference in record&lt;/td&gt;
      &lt;td&gt;
        &lt;code class=&quot;language-text&quot;&gt;relationships&lt;/code&gt; key with reference object. &lt;br/&gt;  
        ex.&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&quot;relationships&quot;: {
  &quot;author&quot;: {
    &quot;type&quot;: &quot;authors&quot;,
    &quot;id&quot;: &quot;5&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
      &lt;/td&gt;
      &lt;td&gt;Name of attribute suffixed with &lt;code class=&quot;language-text&quot;&gt;_id&lt;/code&gt; &lt;br&gt;  ex: &lt;code class=&quot;language-text&quot;&gt;&quot;author_id&quot;: &quot;5&quot;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Name of attribute with no suffic  &lt;br&gt;  ex:  &lt;code class=&quot;language-text&quot;&gt;&quot;author&quot;: &quot;5&quot;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Name of attribute suffixed with &lt;code class=&quot;language-text&quot;&gt;Id&lt;/code&gt;  &lt;br&gt;  ex:  &lt;code class=&quot;language-text&quot;&gt;&quot;authorId&quot;: &quot;5&quot;&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;aside class=&quot;posts-list-list&quot;&gt;
  &lt;h2&gt;Related article:&lt;/h2&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2020-07-29-decoupling-teams-through-simulation/&quot;&gt;
        Beyond Mocking: Decoupling teams through Simulation
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      Decoupling front-end and mobile teams from the back-end makes organizations more effective. In this article we explain why using simulation is an ideal strategy for this purpose, and present important considerations for adopting such practices.
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2020-07-29-decoupling-teams-through-simulation/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/aside&gt;</content:encoded><media:content url="https://frontside.com/static/d4e278e50eadb083bc7d0048fa835d4d/2a4de/2020-07-29-mirage-social.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Beyond Mocking: Decoupling teams through Simulation]]></title><description><![CDATA[Decoupling front-end and mobile teams from the back-end makes organizations more effective. In this article we explain why using simulation is an ideal strategy for this purpose, and present important considerations for adopting such practices.]]></description><link>https://frontside.com/blog/2020-07-29-decoupling-teams-through-simulation/</link><guid isPermaLink="false">https://frontside.com/blog/2020-07-29-decoupling-teams-through-simulation/</guid><category><![CDATA[simulation]]></category><category><![CDATA[best-practices]]></category><category><![CDATA[dx]]></category><dc:creator><![CDATA[Charles Lowell, Jorge Lainfiesta]]></dc:creator><pubDate>Wed, 29 Jul 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Working across teams is challenging. It gets especially tricky when one team depends on another to make progress on their own tasks. For instance, take an all-time classic: the front-end team needs the back-end team to provide them with APIs to advance the UI. Both parts are working towards a common goal, but their dependency may create tensions and frustration, which compromise the quality they would otherwise deliver.&lt;/p&gt;
&lt;p&gt;In Frontside’s experience, the most effective solution to this kind of collaboration problem is to decouple the teams through a simulator. The simulator must accurately reflect what the back-end team is building, such that the front-end can rely on it without future headaches. Those developers tasked with creating the UI should be able to flawlessly switch between the simulator and the real back-end without effort.&lt;/p&gt;
&lt;p&gt;An effective and useful simulator is not merely a collection of JSONs that reflect the structure of server responses. It also emulates errors and relationships between endpoints in order to capture the inner state of the backend service. Yet just as crucial as the simulator are the practices adopted by the team to keep it useful and reliable.&lt;/p&gt;
&lt;p&gt;In this article, we’ll start by exploring why decoupling front-end and mobile teams from the back-end is valuable. Then we’ll jump into what a good simulator does and how it critically differs from using mocks and stubs. Afterward, we’ll outline the key steps you need to take if you adopt a simulation strategy.&lt;/p&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;
  &lt;h2&gt;Decoupling teams through simulation:&lt;/h2&gt;
  &lt;ul&gt;
      &lt;li&gt;
          &lt;a href=&apos;#why-you-should-consider-decoupling&apos;&gt;Why you should consider decoupling&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&apos;#what-is-a-simulator&apos;&gt;What is a simulator?&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;a href=&apos;#state-and-relationships-bring-life-to-simulators&apos;&gt;State and relationships bring life to simulators&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&apos;#adopting-a-simulation-strategy&apos;&gt;Adopting a simulation strategy&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&apos;#conclusion-3&apos;&gt;Conclusion&lt;/a&gt;
      &lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;
&lt;h2 id=&quot;why-you-should-consider-decoupling&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-you-should-consider-decoupling&quot; aria-label=&quot;why you should consider decoupling permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why you should consider decoupling&lt;/h2&gt;
&lt;p&gt;Implementing decoupled modules when developing software creates a more robust and resilient system. Within a decoupled architecture, specialized layers in the system are optimized, modules can swiftly be changed for newer ones, and one-point failures are avoided altogether.&lt;/p&gt;
&lt;p&gt;In the same fashion, decoupled teams create a flexible and robust organization. More often than not tightly coupled teams lead to low productivity and high frustration. When you force two (or more) teams to be dependent on each other, you are potentially wasting the energy of both and ignoring their unique challenges.
Each team has its own people with their own capabilities. Successful managers recognize each team’s virtues and use them to improve the team’s performance and morale. However, leveraging the skills and motivation of each team becomes difficult when two different teams become each other’s blocker. In that situation, what could have been synergy becomes friction.&lt;/p&gt;
&lt;p&gt;When you run tightly coupled teams, it’s not simply that problems in which each team runs into impact both teams, magnifying each delay and obstacle and impacting the organization as a whole. It’s that in not addressing the issue you essentially communicate that you don’t respect each team’s most valuable asset: time.
From a project management perspective, teams reap considerable benefits from decoupled cadences when they run into bottlenecks or have a disparity in their respective priorities.&lt;/p&gt;
&lt;p&gt;For example, let’s say new data protection practices are set to be adopted in the organization. The back-end team then has to prioritize the revision of a large set of endpoints and halt all forward progress on new features till data protection issues are resolved. The new requirements don’t show up in the UI so the front-end team doesn’t have to deliver anything. They’d like to continue working on the UI for the new features, but now are stuck because the back-end team is unavailable and thus cannot deliver the APIs that the front end team needs to tackle to complete its tasks.&lt;/p&gt;
&lt;p&gt;In cases like these, it would be easier for both teams to run at their own speed according to their particular needs and requirements instead of strictly forcing both to adhere to an artificial cadence so that they can stay coupled. Respecting the time of both teams means the correct solution is decoupling.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-simulator&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-a-simulator&quot; aria-label=&quot;what is a simulator permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is a simulator?&lt;/h2&gt;
&lt;p&gt;No discussion of a simulator is complete without reference the film The Matrix, so let’s start there. The movie shows a world in which humans live in a computer simulation that is very different from their actual physical existence. This simulation is not merely a collection of inert pictures flashing before their eyes—an interface that you passively interact with. It is instead a fully immersive experience that you actively engage—a world so alive don’t notice you’re within it because it feels real.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2020-07-29-simulator-matrix.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Morpheus, from the movie The Matrix (1999), sitting in a couch&lt;/figcaption&gt;&lt;/figure&gt;
&lt;em&gt;Morpheus, from the The Matrix (1999)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To truly be effective, the simulator software developers use has to be alive and dynamic
like the Matrix. Indeed, that’s the problem with mocks and stubs—no matter how realistic they look, in the end they are like two-dimensional photographs—dead and static. Contrary to mocks and stubs that decay rapidly and become useless, a simulator can be updated and stay evergreen.&lt;/p&gt;
&lt;p&gt;The proof is in the pudding as they say, and all you need to do is return to mocks or stubs that were written only a month prior. Being hard-coded they become obsolete fast, and after 4 weeks feel rickety and not up to the task. While they may help hold things together for a short time, so does duct tape – neither is a long-term solution. Mocks and stubs instead rapidly become a problem for the codebase.&lt;/p&gt;
&lt;h2 id=&quot;state-and-relationships-bring-life-to-simulators&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#state-and-relationships-bring-life-to-simulators&quot; aria-label=&quot;state and relationships bring life to simulators permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;State and relationships bring life to simulators&lt;/h2&gt;
&lt;p&gt;We have described mocks and stubs as dead vs. simulators as alive, but to what does that translate to in technical terms? The key lies in state and relationships. Mocks and stubs merely reflect the response structure of an API response, while simulators map the APIs behavior and relationships and from there outputs appropriately formatted responses.&lt;/p&gt;
&lt;p&gt;That turns out to be a huge difference. Real APIs are not static JSON objects independent from one another like in a mock or stub. APIs interact among each other, depend on each other, and even consume each other in the back-end. Moreover, each endpoint has errors, tokens, metadata, and side effects. None of that is reflected in a static mock or stub. And after all, how could it? JSON is merely the format over which all the information from the back-end is communicated. The format is not a crucial part of an API, and therefore it is not uncommon to see it change and evolve. But that means the mocks and stubs become quickly outdated in addition to lacking the dynamic character of real APIs.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2020-07-29-simulator-browser.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Screenshot of Network tab on Firefox&apos;s Web Inspector&lt;/figcaption&gt;&lt;/figure&gt;
&lt;em&gt;Focusing on the responses&apos; format is important, but it&apos;s helpful to be aware of what it represents in the back&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A simulator is designed to accurately represent the API’s inner state, which is reflected in the interactions and relationships between endpoints. For instance, if you edit the user’s name through the UI, the endpoint that returns the user data would reflect such change, although it was introduced as an effect of calling a different endpoint.&lt;/p&gt;
&lt;p&gt;With mocks and stubs, you can replicate the structure of a response provided by an API. It may even appear suitable for simple features. You just add a file with a JSON to your codebase and consume it as a response for your API request; no annoying extra libraries or setups. But the problem is that APIs seldom are simple. Sooner than later, you’ll be dealing with authentication tokens, form validations, file uploads, and more. API complexity scales up rather quickly in most applications. That’s when you see the real value of simulation.&lt;/p&gt;
&lt;h2 id=&quot;adopting-a-simulation-strategy&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#adopting-a-simulation-strategy&quot; aria-label=&quot;adopting a simulation strategy permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adopting a simulation strategy&lt;/h2&gt;
&lt;p&gt;Opting for a simulation strategy will directly impact your overall development process. That’s why a simulation strategy must be a team decision and effort. You have to invest in understanding your back-end, research libraries for simulation, implement the simulator, and maybe most important of all, socialize and maintain the simulator’s accuracy.&lt;/p&gt;
&lt;p&gt;The first step is understanding how your back-end is provisioned. You might find yourself getting into a rabbit hole when exploring how different teams in your organization provide their services and how they interact (or not) with each other. Broader issues may often come up, such as the opportunity to consolidate the services architecture with better-aligned practices across teams or through a federated schema.&lt;/p&gt;
&lt;p&gt;The next priority is researching and then choosing the most suitable simulation tool. For back-ends over HTTP, we’ve had good experiences with &lt;a href=&quot;https://miragejs.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Mirage.js&lt;/a&gt;. But you might find out that it’s not sufficient to cover your use cases, so you may need to invest in extending tools or even creating your own (beware: this introduces greater risk and maintenance costs in your simulator). When a simulator doesn’t exist for what you need, you can consider &lt;a href=&quot;https://frontside.com/blog/2019-12-11-case-study-bluetooth-simulation/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;cooperating with open source projects&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once you have decided on which libraries and tools and have a sufficient understanding of your back-end, you can start implementing your simulator. We recommend approaching the task from an experience-first perspective instead aiming to achieve endpoint parity. Focus on a UI segment that you know well and simulate the endpoints that it needs. Try experimenting on how responses with errors, latency, and other parameters look like. It will most likely take a few iterations before you develop to the best patterns to follow for all the APIs you want to implement.&lt;/p&gt;
&lt;p&gt;Finally, socializing simulation practices is essential for maintaining its reliability, accuracy and effectiveness. Developers will have to extend the APIs according to their needs. But because those needs may be redundant (or in conflict) with other data requirements, an effective process for extending the data schema is needed. That’s why the simulation adoption must include a comprehensive plan for discussing and curating the evolution of APIs to keep the simulator evergreen. This benefits not only the simulator but the sustainable growth of the organization’s data management. This process is typically overseen by one or more developers who takes on the role of data field owner.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Implementing a simulation strategy takes resources: very tangible time and money. It requires developers to research, experiment, and adopt new practices. It’s not easy to come to your boss and say, “Hey, I’ll be working on a simulator, so don’t count on me. See you in a month or two!”
Because simulation has concrete costs and requires specific resources, it is easy for decision-makers to take that number, compare it with other expenses, and even reject it as an option because it is a “non-feature.”&lt;/p&gt;
&lt;p&gt;But what is often overlooked in that decision is the cost of the solution used instead of a simulator. While not nearly as quantifiable as building a simulator, the cost is real, and quite arguably much more than what it would take to adopt the simulator solution. To be sure there’s the technical debt costs of the multiple mocks and stubs accumulating untamed in the codebase, but both literally and rhetorically you can’t put a price tag on the lost time and productivity due to blocked teams. And as the project scales up, there’s the problem of the need for automated tests and slow or even flaky results if run against remote back-ends. Creating ad-hoc mocks and stubs to “get through” the features only results in long-term liabilities in your codebase.&lt;/p&gt;
&lt;p&gt;Or you could address all these issues in one fell swoop by using a simulator. To be sure, adopting a simulation strategy requires thoughtful considerations and efforts from the team to adopt new practices. But the benefits that flow from decoupling teams through simulation – more effective development cycles and a better directed collaboration – by far outweigh the problems caused by mocks and stubs.&lt;/p&gt;
&lt;p&gt;In The Matrix the main character Neo initially doesn’t trust the simulation but eventually comes to recognize the power inherent in using it to achieve his ends. Maybe it’s time for you to “take the red pill” like Neo did and convince your company to do the same. Feel free to &lt;a href=&quot;https://frontside.com/contact&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;reach out to us&lt;/a&gt; if you want help or ideas :)&lt;/p&gt;
&lt;aside class=&quot;posts-list-list&quot;&gt;
  &lt;h2&gt;Related article:&lt;/h2&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2020-08-31-mirage-serializers/&quot;&gt;
        MirageJS: Choosing the right Serializer 
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      Mirage is a great library for implemnting HTTP simulation. In this blog post, we overview the basics of serializers in Mirage, and examine in detail the specific format of each JSON API, Active Model, Rest and generic serializers.
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2020-08-31-mirage-serializers/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/aside&gt;</content:encoded><media:content url="https://frontside.com/static/2c1fe6c214acbe17dd3db9dfd6237dd3/2a4de/2020-07-29-simulator-social.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[The Lesson of BigTest Interactors: never write a flaky test again!]]></title><description><![CDATA[To prevent flaky tests, BigTest introduces the Interactor API, designed around the lessons learned in Capybara. This article introduces the benefits of Interactors in BigTest and how to use them to write reliable tests. ]]></description><link>https://frontside.com/blog/2020-07-16-the-lesson-of-bigtest-interactors/</link><guid isPermaLink="false">https://frontside.com/blog/2020-07-16-the-lesson-of-bigtest-interactors/</guid><category><![CDATA[testing]]></category><category><![CDATA[bigtest]]></category><dc:creator><![CDATA[Jonas Niklas]]></dc:creator><pubDate>Thu, 16 Jul 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Testing the frontend of complex applications is often associated with nightmarishly inconsistent test suites, where seemingly random failures cast doubt on the value of the tests themselves and frustrate developers to no end. Our mission with BigTest has been to eliminate flakiness in tests altogether and provide the most stable, easy to use, and best performing test framework out there.&lt;/p&gt;
&lt;p&gt;As the original author of Capybara, an acceptance test framework written in Ruby which has a reputation of being incredibly solid and resistant to flakiness, I know all about how to avoid random test failures. We have taken all of the lessons learned from tweaking Capybara over years and applied them to build BigTest’s Interactor API—a powerful way of defining interactions with your application which allows you to write tests which are even more solid than what Capybara can provide.&lt;/p&gt;
&lt;p&gt;We&apos;ll be ready to share more about BigTest soon, but for the moment I want to talk about the overarching approach Frontside takes to eliminate flakiness, and what you need to know to write tests which are rock solid and never fail randomly. While there will be significant gains to be had in using Frontside&apos;s BigTest, the principles guiding its development are what I want to talk about here: eliminating ambiguities when writing tests in order to ensure stability. Let&apos;s see how BigTest is designed to do just that and then apply those insights to test writing in general.&lt;/p&gt;
&lt;h2 id=&quot;the-convergence-strategy&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-convergence-strategy&quot; aria-label=&quot;the convergence strategy permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Convergence Strategy&lt;/h2&gt;
&lt;p&gt;The approach BigTest uses is sophisticated in its execution but fundamentally simple in its design: for any interaction we want to perform, or any assertion we want to check, we try it and see if it succeeds; if not we wait and try again. We keep doing this until we either succeed, or some set amount of time has expired and declare the test a failure.&lt;/p&gt;
&lt;p&gt;We call this strategy &quot;convergence&quot; and functions which exhibit this waiting behavior “convergent.&quot; In order to create convergences in a web UI, we must be able to keep reliable references to the elements we want to act and assert on, which is possible in BigTest through having control over the event loop of the browser.&lt;/p&gt;
&lt;h3 id=&quot;retaining-references&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#retaining-references&quot; aria-label=&quot;retaining references permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Retaining references&lt;/h3&gt;
&lt;p&gt;The most important detail is that an interaction or assertion must fully capture all of the work that it needs to perform and perform all the same work again and again in the retry loop. The test in other words must run on the same content each and every time. To ensure this, BigTest never uses any outdated references to elements, and everything is always run against the actual DOM.&lt;/p&gt;
&lt;p&gt;For example, let&apos;s imagine we have a field for a name and this field is within a form. With BigTest interactors we could set the value of this field to look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;byId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;login&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TextField&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;byId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Jonas&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can think of this as roughly performing three steps under the hood:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; form &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;#login&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// step 1&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; textField &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;#name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// step 2&lt;/span&gt;
textField&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Jonas&apos;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// step 3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now just re-running step 3 over again and again is not enough. The form element or text field could change, and either of those changes could cause us to retry something which would never work. In order to make this as stable as possible we need to re-run all of the steps every time.&lt;/p&gt;
&lt;p&gt;A very simplified algorithm for how this would work looks roughly like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; startTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Run our actual interaction code&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; form &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;#login&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// step 1&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; textField &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;#name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// step 2&lt;/span&gt;
    textField&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Jonas&apos;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// step 3&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// if it fully succeeds, break out of the loop&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// if there was an error, check if we&apos;ve already been trying for too long&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; startTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MAX_WAIT_TIME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// wait a little while&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now what BigTest&apos;s API interactors do is automatically transform the following much simpler instructions into the above algorithm for you:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;byId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;login&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TextField&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;byId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Jonas&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Of course there are a number of details that are omitted in the simplified code above. For example, each interactor must be specific enough to match a single element on the page. If there were multiple fields with the id &lt;code class=&quot;language-text&quot;&gt;name&lt;/code&gt; then the interaction above would fail. Designing BigTest this way forces the writer to be specific so that they don&apos;t end up interacting with a random element on the page. Otherwise layout changes where the order of elements is altered might lead to broken tests.&lt;/p&gt;
&lt;h3 id=&quot;taming-the-event-loop&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#taming-the-event-loop&quot; aria-label=&quot;taming the event loop permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Taming the event loop&lt;/h3&gt;
&lt;p&gt;One huge advantage that BigTest has over Capybara is that since we are running tests directly in the browser, we can leverage the event loop and ensure that our interactions run fully within the same tick of the loop. This eliminates quite a number of problems that plague Capybara and similar Selenium-based frameworks and tools. By running within the event loop and ensuring that we never release it, we can guarantee that our elements are never stale.&lt;/p&gt;
&lt;p&gt;Frameworks that do not have direct access to the event loop often get errors because the elements they were looking for stop “existing” for one reason or another. This loss of reference could happen because the user, the browser, or an external script triggered a change that made the reference disappear. Capybara goes to great lengths to avoid the dreaded &lt;code class=&quot;language-text&quot;&gt;StaleReferenceError&lt;/code&gt;, but BigTest simply avoids the issue altogether. That is because getting a hold of the event loop guarantees that we can run assertions when elements in the page are ready, and before they are changed by other elements.&lt;/p&gt;
&lt;p&gt;The Interactors API reflect their event-loop synced nature. Consider, for example, a &lt;code class=&quot;language-text&quot;&gt;TextField&lt;/code&gt; interactor:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; TextField &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;createInteractor&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HTMLInputElement&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;text field&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;input&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  locators&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;byId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;element&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; element&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  actions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;fillIn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;element&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; element&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In most test frameworks, actions such as &lt;code class=&quot;language-text&quot;&gt;fillIn&lt;/code&gt;, would have been asynchronous. But in BigTest both the locator and action functions are synchronous, which means that they do not release the event loop. This allows us to transform them into convergent functions, which can find the element and perform the action using the same reliable reference.&lt;/p&gt;
&lt;p&gt;BigTest will also ship with a rich library of interactors already built in, for all of the most common interface elements in web applications, so most users never have to define their own interactors if they don&apos;t want to. And yes, all our interactors are fully typesafe because BigTest is written in TypeScript.&lt;/p&gt;
&lt;h2 id=&quot;waiting-is-not-enough-flakiness-through-ambiguities&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#waiting-is-not-enough-flakiness-through-ambiguities&quot; aria-label=&quot;waiting is not enough flakiness through ambiguities permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Waiting is not enough: flakiness through ambiguities&lt;/h2&gt;
&lt;p&gt;We have claimed that our convergence strategy is enough to eliminate flakiness, but as we mentioned as well, having a solid strategy is only part of the solution, the other half of the solution is writing the tests in such a way that they make maximal usage of this solution and avoid inherent
ambiguities that we cannot otherwise resolve.&lt;/p&gt;
&lt;p&gt;Let&apos;s illustrate what we mean by this with an example: Imagine we have a paginated list with a &apos;Next&apos; link at the bottom. Whenever we press the next link we will load a new set of rows, and we also update the &lt;code class=&quot;language-text&quot;&gt;href&lt;/code&gt; attribute of the next link to point to the next page.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2020-07-16-interactors-next.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Image of a page showing a list and &quot;Previous&quot; and &quot;Next&quot; buttons&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Now imagine a written a test written like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Next&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Next&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which page will we end up on? Intuitively we would say that we should end up on the &lt;em&gt;third&lt;/em&gt; page, but unfortunately the actual answer is &quot;it depends&quot;. The first click on &lt;code class=&quot;language-text&quot;&gt;Next&lt;/code&gt; will start a request to the server which will complete after some time, and this will change the &lt;code class=&quot;language-text&quot;&gt;href&lt;/code&gt; of the link. But if our second click happens &lt;em&gt;before&lt;/em&gt; the request completes, we will navigate to the second page &lt;em&gt;twice&lt;/em&gt;, and we actually end up on the &lt;em&gt;second&lt;/em&gt; page.&lt;/p&gt;
&lt;h3 id=&quot;a-naïve-solution-guessing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-na%C3%AFve-solution-guessing&quot; aria-label=&quot;a naïve solution guessing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A naïve solution: Guessing&lt;/h3&gt;
&lt;p&gt;A common way to work around this issue is to try and guess when an interaction is &quot;done&quot; – for example, by checking if there are any active requests to the server and waiting for those to complete. This was the original strategy used in Capybara, but we realized that this strategy has a fatal flaw and moved away from it. Here’s the problem:&lt;/p&gt;
&lt;p&gt;Let&apos;s imagine that the event loop is released between the request completing and the DOM being updated. Our second click could now occur in this small window of time. What we have done is made the window of time for flakiness to occur smaller, but we have not eliminated it. This still might seem like a win on the surface, but in fact making the window smaller is actually &lt;em&gt;worse&lt;/em&gt;, because it means that this issue will occur more rarely, and therefore in actuality will be harder to track down and fix.&lt;/p&gt;
&lt;h3 id=&quot;a-better-solution-anchoring&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-better-solution-anchoring&quot; aria-label=&quot;a better solution anchoring permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A better solution: Anchoring&lt;/h3&gt;
&lt;p&gt;A better solution would be to &quot;anchor&quot; the second interaction by adding an assertion which ensures we have transitioned to the second page beforehand:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Next&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ListItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;This item is on the second page&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Next&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can now be sure that we have transitioned to the second page. It is unlikely that the modifications to the DOM of rendering the second page and updating the link will occur in separate ticks of the event loop, so most likely this will be enough to eliminate the problem.&lt;/p&gt;
&lt;h3 id=&quot;the-best-solution-fixing-the-ui&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-best-solution-fixing-the-ui&quot; aria-label=&quot;the best solution fixing the ui permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The best solution: Fixing the UI&lt;/h3&gt;
&lt;p&gt;But there&apos;s an even better solution. The problem stems from the fact that the UI itself is ambiguous. If the user of the application did hit the &apos;Next&apos; link twice in rapid succession, what would happen? The result is as equally undefined as the result of the test is.&lt;/p&gt;
&lt;p&gt;If we fix the UI to disable the &apos;Next&apos; link while the request for the second page is loading, we don&apos;t need to change our test at all. When the request completes and updates the &lt;code class=&quot;language-text&quot;&gt;href&lt;/code&gt;, it will also enable the link again, and since we will keep retrying to find and click the link, we will then see the newly enabled link and click it.&lt;/p&gt;
&lt;p&gt;By making our UI less ambiguous we have also made our tests more stable. We have effectively discovered a flaw in our UI and fixed it, made our application better, and fixed our test in the process.&lt;/p&gt;
&lt;p&gt;Of course we don&apos;t always have control over our application or the ability to make this type of tweak. In those cases &quot;anchoring&quot; is a good alternative.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Strategies like these are why BigTest is going to be such a significant step forward in test design. BigTest’s Interactor API will make it as easy as possible to write stable tests, but in the meantime we are committed to providing explanations like these to help you understand how to achieve similar results.&lt;/p&gt;
&lt;p class=&quot;blog-post--guest-intro&quot;&gt;
  Jonas Nicklas is the original author of &lt;a href=&quot;https://github.com/teamcapybara/capybara&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt;Capybara&lt;/a&gt;, Ruby’s most popular framework for testing web applications. He is based in Sweden and has been working on BigTest since 2019
&lt;/p&gt;
&lt;aside class=&quot;posts-list-list&quot;&gt;
  &lt;h2&gt;Related article:&lt;/h2&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2020-triple-threat-to-testing-part-2-reliability/&quot;&gt;
        The Triple Threat to Testing — Part 2: Reliability
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      Flakiness: one of the biggest pain-points of any test suite. From app complexity to incident management, we explore some of the most common causes of unreliable tests.
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2020-triple-threat-to-testing-part-2-reliability/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/aside&gt;</content:encoded><media:content url="https://frontside.com/static/6deea28b3286095fb4b24d9ec4cd1911/2a4de/2020-07-16-interactors-social.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Github Actions: a deep dive into pull_request]]></title><description><![CDATA[We have put together specific behaviors and information that you’ll need to use pull_request as a trigger for your Github Actions workflow.]]></description><link>https://frontside.com/blog/2020-05-26-github-actions-pull_request/</link><guid isPermaLink="false">https://frontside.com/blog/2020-05-26-github-actions-pull_request/</guid><category><![CDATA[github-actions]]></category><category><![CDATA[continuous-delivery]]></category><dc:creator><![CDATA[Min Kim]]></dc:creator><pubDate>Tue, 26 May 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Github Actions is an exciting feature that enables teams to construct workflows based on webhook events. It unlocks new possibilities for teams that neatly integrate it into their development flow.&lt;/p&gt;
&lt;p&gt;For example, you can use Github Actions to automatically run tests, generate a preview app, and send a follow-up notification every time somebody opens a pull request. Presuming you&apos;re familiar with writing &lt;a href=&quot;https://help.github.com/en/actions/configuring-and-managing-workflows&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Github Actions workflows&lt;/a&gt;, let’s take a closer look at some aspects of that process.&lt;/p&gt;
&lt;p&gt;At Frontside we use Github Actions extensively to make the development process of our clients both simpler and more inclusive for non-technical stakeholders. This is possible because Github Actions offers a rich API that allows us to build flexible and highly-specific workflows.&lt;/p&gt;
&lt;p&gt;In this article, we have put together specific behaviors and information that you’ll need to use &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; as a trigger for your Github Actions workflow. First we’ll take a look at how the workflow is actually triggered &lt;code class=&quot;language-text&quot;&gt;on: pull_request&lt;/code&gt;; then we’ll examine the information provided to the workflow when triggered by a &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt;; and finally we’ll look at how &lt;code class=&quot;language-text&quot;&gt;@actions/checkout&lt;/code&gt; reacts to &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt;.&lt;/p&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;
  &lt;h2&gt;All you need to know about pull_request:&lt;/h2&gt;
  &lt;ul&gt;
      &lt;li&gt;
          &lt;a href=&apos;#how-do-workflows-trigger-on-pull_request&apos;&gt;Activities that trigger pull_request&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&apos;#what-information-is-available-from-a-workflow&apos;&gt;Information available to the workflow&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&apos;#how-does-pull_request-affect-actionscheckout&apos;&gt;Effects on @action/checkout&lt;/a&gt;
      &lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;
&lt;h2 id=&quot;how-do-workflows-trigger-on-pull_request&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-do-workflows-trigger-on-pull_request&quot; aria-label=&quot;how do workflows trigger on pull_request permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How do workflows trigger on &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;When a Github Actions workflow is configured to run on pull requests, by default it will be triggered on three different types of activities: &lt;code class=&quot;language-text&quot;&gt;opened&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;synchronize&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;reopened&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Pull Request Workflow
&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pull_request&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p class=&quot;blog-post--caption&quot;&gt;Basic &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; usage.&lt;/p&gt;
&lt;p&gt;If you need your workflow to run on any of the other types you will need to specify them. And if you wish to run those types in addition to the default types, you will need to manually add those too because once you configure &lt;code class=&quot;language-text&quot;&gt;types&lt;/code&gt; the default values are no longer provided:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Pull Request Workflow
&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;pull_request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;types&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; assigned&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; opened&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; synchronize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reopened &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p class=&quot;blog-post--caption&quot;&gt;We have to explicitely set every action type if we customize them. &lt;br /&gt; The defaults will not be preserved automatically.&lt;/p&gt;
&lt;p&gt;Although the names of these types are pretty self-explanatory, we have gone ahead and double-checked each one of them to confirm our assumptions:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;assigned&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a user is assigned to the pull request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;unassigned&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a user is unassigned from the pull request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;labeled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a label is applied to the pull request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;unlabeled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a label is removed from the pull request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;opened&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pull request is created&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;edited&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;title, body, or the base branch of the PR is modified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;closed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pull request is closed (as opposed to merged)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;reopened&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;closed pull request is reopened&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;synchronize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;commit(s) pushed to the pull request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;ready_for_review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pull request is taken out from draft mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;locked&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pull request is locked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;unlocked&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pull request is unlocked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;review_requested&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;request a user for review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;review_request_removed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;remove request from user for review&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;blog-post--caption&quot;&gt;For a complete list of activity types, checkout &lt;a href=&quot;https://help.github.com/en/actions/reference/events-that-trigger-workflows&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt;Github&apos;s Events-that-trigger-workflows page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One thing to note is that when you configure your &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; workflow to be triggered on &lt;code class=&quot;language-text&quot;&gt;labeled&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;unlabeled&lt;/code&gt; and you add/remove multiple labels at the same time, the event of each label will trigger its own workflow run. It also works the same way for &lt;code class=&quot;language-text&quot;&gt;assigned&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;unassigned&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;review_requested&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;review_request_removed&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-information-is-available-from-a-workflow&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-information-is-available-from-a-workflow&quot; aria-label=&quot;what information is available from a workflow permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What information is available from a workflow?&lt;/h2&gt;
&lt;p&gt;You can find the payload of each run of a workflow inside &lt;code class=&quot;language-text&quot;&gt;workflow/event.json&lt;/code&gt; which is accessible with the &lt;code class=&quot;language-text&quot;&gt;github_event_path&lt;/code&gt; environment variable. The payload contains the POST data of the webhook event that triggered the workflow, such as the action type, the commit before and after the action was triggered, the sender, etc.&lt;/p&gt;
&lt;p&gt;Here is an example of a payload from a workflow triggered by &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; on &lt;code class=&quot;language-text&quot;&gt;synchronize&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;synchronize&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;after&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;abcdefg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// most recent commit of this push&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;before&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1234567&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// latest commit prior to this push&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// pull request number&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;pull_request&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// pull request metadata&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;repository&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// owner, description, git_url ...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;sender&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// information of user who triggered this event&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can do all sorts of useful things with the data provided from this payload. For example, you could compare the &lt;code class=&quot;language-text&quot;&gt;repo.url&lt;/code&gt; property of &lt;code class=&quot;language-text&quot;&gt;pull_request.head&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;pull_request.base&lt;/code&gt; to determine if the pull request was created from a forked repository against the original, and if so you could &lt;code class=&quot;language-text&quot;&gt;console.log(&quot;Thank you for your interest in our open source project!&quot;)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The information in the payload will vary depending on the webhook event and the activity type which caused the trigger. By way of comparison, here’s the payload from a &lt;code class=&quot;language-text&quot;&gt;push&lt;/code&gt; webhook workflow triggered by the same commit as the example above (note that the actual payload will have more information):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;after&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;abcdefg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;before&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1234567&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;commits&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;forced&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;repository&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;sender&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see the payload is different from that of a pull request. On &lt;code class=&quot;language-text&quot;&gt;push&lt;/code&gt; we have less information, namely we lack &lt;code class=&quot;language-text&quot;&gt;activity&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;number&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; from the payload. Note that even if you are pushing this particular commit to a pull request, if the workflow was triggered on &lt;code class=&quot;language-text&quot;&gt;push&lt;/code&gt;, it will not have any of the &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; properties in the payload.&lt;/p&gt;
&lt;p&gt;Now that we have compared how a &lt;code class=&quot;language-text&quot;&gt;push&lt;/code&gt; payload differs from a &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; payload, let&apos;s take a closer look at how the payload varies on different activity types of &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;opened&lt;/code&gt;: Here is an example of a payload that does not have anything specific to its activity type, so the properties you see will be available on all pull request payloads:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;opened&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;pull_request&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;repository&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;sender&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;edited&lt;/code&gt;: This activity type offers information on the property of the pull request the user has edited.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;synchronize&lt;/code&gt;: As seen above, this activity includes &lt;code class=&quot;language-text&quot;&gt;before&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;after&lt;/code&gt; commit SHAs. The &lt;code class=&quot;language-text&quot;&gt;synchronize&lt;/code&gt; activity type is triggered &lt;em&gt;per-push&lt;/em&gt;, so if a single push has multiple commits, the workflow will only run once. The &lt;code class=&quot;language-text&quot;&gt;before&lt;/code&gt; pinpoints the most recent commit &lt;em&gt;prior&lt;/em&gt; to the push, such that if you have commits &lt;code class=&quot;language-text&quot;&gt;A-B-C&lt;/code&gt; and you push &lt;code class=&quot;language-text&quot;&gt;D-E-F&lt;/code&gt;, the workflow will be comparing commit &lt;code class=&quot;language-text&quot;&gt;F&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;C&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;labeled&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;unlabeled&lt;/code&gt;: These include the metadata of the label that triggered the workflow:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;unlabeled&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token string-property property&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  	&lt;span class=&quot;token string-property property&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  	&lt;span class=&quot;token string-property property&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  	&lt;span class=&quot;token string-property property&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Something isn&apos;t working&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  	&lt;span class=&quot;token string-property property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bug&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;assigned&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;unassigned&lt;/code&gt;: These are similar to &lt;code class=&quot;language-text&quot;&gt;labeled&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;unlabeled&lt;/code&gt; and the workflow will include the payload data of the added or removed assignee.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;review_requested&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;review_requested_removed&lt;/code&gt;: as odd as it seems, neither of these provides the data of which reviewer changed, and so the payload structure for these actions is identical to &lt;code class=&quot;language-text&quot;&gt;opened&lt;/code&gt;. You are able to find the list of reviewers from within the &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; portion of the payload, but it does not explicitly tell you which addition or removal of a reviewer triggered the workflow.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-does-pull_request-affect-actionscheckout&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-does-pull_request-affect-actionscheckout&quot; aria-label=&quot;how does pull_request affect actionscheckout permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How does &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; affect &lt;code class=&quot;language-text&quot;&gt;@actions/checkout&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;When you use &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt;, &lt;a href=&quot;https://github.com/actions/checkout&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@actions/checkout&lt;/code&gt;&lt;/a&gt; will perform a &lt;code class=&quot;language-text&quot;&gt;git checkout&lt;/code&gt; to the &lt;code class=&quot;language-text&quot;&gt;github.ref&lt;/code&gt; environment variable. Note that &lt;code class=&quot;language-text&quot;&gt;git checkout&lt;/code&gt; is not applied to the commit, as it would have been the case when using &lt;code class=&quot;language-text&quot;&gt;push&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This difference means that a &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; workflow &lt;code class=&quot;language-text&quot;&gt;ref&lt;/code&gt; would look like &lt;code class=&quot;language-text&quot;&gt;refs/remotes/pull/##/merge&lt;/code&gt; whereas a &lt;code class=&quot;language-text&quot;&gt;push&lt;/code&gt; workflow would be &lt;code class=&quot;language-text&quot;&gt;refs/heads/branch_name&lt;/code&gt;. This explains why the SHA of a &lt;code class=&quot;language-text&quot;&gt;push&lt;/code&gt; workflow matches the commit that triggered the workflow, whereas the SHA of a &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; workflow does not; instead the SHA of the &lt;code class=&quot;language-text&quot;&gt;pull_request&lt;/code&gt; is the resulting commit that was created from merging the base to the head.&lt;/p&gt;
&lt;p&gt;You could configure the checkout action with the &lt;code class=&quot;language-text&quot;&gt;ref&lt;/code&gt; argument to be more explicit with what you want to check out. For instance, if you want to checkout the head commit instead of using the default merge ref, you could pass in &lt;code class=&quot;language-text&quot;&gt;github.event.pull_request.head.sha&lt;/code&gt; as the argument (or &lt;code class=&quot;language-text&quot;&gt;github.event.pull_request.head.ref&lt;/code&gt; if you are using &lt;code class=&quot;language-text&quot;&gt;v1&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v2
  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; github.event.pull_request.head.sha &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p class=&quot;blog-post--caption&quot;&gt;Checking out head commit using &lt;code class=&quot;language-text&quot;&gt;checkout@v2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Opting out from the default checkout to specify the head ref might be useful for any number of reasons. For example, if you have an action that relies on the output of &lt;code class=&quot;language-text&quot;&gt;git log&lt;/code&gt;, the merge commit would offset your results. Or merging with the base ref might introduce features that conflict with the head and possibly even go unnoticed. A third reason could be as follows: suppose your tests are comprehensive and catches those conflicts. A user might be confused as to why the tests are failing in CI but passing locally, especially if they are not familiar with how the checkout action works. Specifying the head ref allows you to have more granular control. In any case, a better understanding of how the checkout action works will allow you to troubleshoot effectively.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Did we miss anything? Reach out via &lt;a href=&quot;https://twitter.com/thefrontside&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Twitter&lt;/a&gt; and we&apos;ll gladly add it to the discussion! And let us know what cool things you&apos;re doing with Github Actions through Frontside’s &lt;a href=&quot;https://discord.gg/r6AvtnU&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Discord&lt;/a&gt; community (where we hang out and talk about these topics).&lt;/p&gt;
&lt;aside class=&quot;posts-list-list&quot;&gt;
  &lt;h2&gt;Related article:&lt;/h2&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2020-7-reasons-for-good-pull-request-descriptions/&quot;&gt;
        7 reasons to write good Pull Request descriptions
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      A good Pull Request description can lead to better reviews, improved solutions, better documentation, and more. In this article, Taras surveys seven big wins of PR descriptions.
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2020-7-reasons-for-good-pull-request-descriptions/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/aside&gt;</content:encoded><media:content url="https://frontside.com/static/2d452ef827f60fa2a3489aaf129ac06b/2a4de/2020-05-26-github-actions-pull_request-social-media.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[The Triple Threat to Testing — Part 2: Reliability]]></title><description><![CDATA[Flakiness: one of the biggest pain-points of any test suite. From app complexity to incident management, we explore some of the most common causes of unreliable tests.]]></description><link>https://frontside.com/blog/2020-04-30-triple-threat-to-testing-part-2-reliability/</link><guid isPermaLink="false">https://frontside.com/blog/2020-04-30-triple-threat-to-testing-part-2-reliability/</guid><category><![CDATA[testing]]></category><category><![CDATA[dx]]></category><dc:creator><![CDATA[Robbie Pitts, Taras Mankovski, Jeffrey Cherewaty, Charles Lowell, Jorge Lainfiesta]]></dc:creator><pubDate>Thu, 30 Apr 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Imagine you have agreed to carpool with a friend. The first couple of weeks it’s all good: you go to their place to pick them up, the next time they pick you up. But one day you’re waiting in front of your building and it’s getting late. You decide to call your friend and hear them say: “Oh, I’ve been waiting too. I thought it was your turn.” You’re both frustrated with each other, and if this happens a few more times, you know you’ll drop carpooling entirely. But since you want to reduce your carbon footprint, you come up with solutions to try to make it work. Perhaps you set up a shared calendar, or create alarms on each other’s phones, or create a text message strategy. Even if your strategies aren’t foolproof, there are actionable steps you can take to significantly increase the reliability of your carpooling partner.&lt;/p&gt;
&lt;aside class=&quot;blog-post--saga-box&quot;&gt;
This article is the second one in our &lt;em&gt;Triple Threat to Testing&lt;/em&gt; saga. If you haven&apos;t, check out the first part about &lt;a href=&quot;https://frontside.com/blog/2020-triple-threat-to-testing-part-1-speed/&quot; target=&quot;_blank&quot;&gt;Speed as a make-or-break factor of any test suite&lt;/a&gt; and tips to improve it.
&lt;/aside&gt;
&lt;p&gt;More often than not, test suites are like that unreliable friend. Almost every developer has encountered a test that passes several times and then unpredictably fails without having made any change in your codebase. It turns out test flakiness affects practically every team, even those with robust test suites. For instance, &lt;a href=&quot;https://testing.googleblog.com/2016/05/flaky-tests-at-google-and-how-we.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;in 2016 Google reported&lt;/a&gt; an average of 1.5% of flaky tests on their suites despite their constant efforts to fight them. And test flakiness remains one of the top concerns of developers according to &lt;a href=&quot;https://static1.smartbear.co/smartbearbrand/media/pdf/third-annual-testing-community-survey-report.pdf&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The State of Testing 2019&lt;/a&gt; survey.&lt;/p&gt;
&lt;p&gt;The level of trust that your test suite brings to you and your team is directly proportional to its value. When your test suite is reliable, you can move forward confidently after you see all the green checks in your Pull Request. There’s no need for you or your colleagues to manually check the whole application each time someone makes a change. That lets you iterate faster and focus the conversation on improving the quality of your app instead of wondering if the new code works at all.&lt;/p&gt;
&lt;p&gt;Conversely, once flaky tests start to become normalized, it’s a short step to the health of the test suite progressively being abandoned. Developers begin to view writing tests as a burden that makes them less productive. But if test unreliability becomes normalized, teams wind up treating as unimportant the thing the suite was testing for. Developers thus risk putting less attention on the potential issues that the test suite should be discovering—issues that were important enough to check for in the first place.&lt;/p&gt;
&lt;p&gt;The impact of flaky tests is not unlike the sensation of being stuck back in high school on an endless treadmill of ultimately meaningless tests. The problems run deeper than simply the lost time having to re-run tests after one fails to deliver an actionable outcome. It’s built into the DNA of developers to be problem-solvers, but flaky tests causes everybody to frustrated and annoyed at just another pointless exercise – and that robs your team of critical momentum and energy that could be directed at productively solving the issue.&lt;/p&gt;
&lt;h2 id=&quot;whats-causing-flaky-tests&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-causing-flaky-tests&quot; aria-label=&quot;whats causing flaky tests permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What’s causing flaky tests?&lt;/h2&gt;
&lt;p&gt;All developers have experienced flaky tests. But understanding why tests are unreliable goes a long way to solving the issue. Flaky tests can be diagnosed, handled, and in many cases prevented. In this section, we’ll have a look at common sources of flakiness and strategies to make tests less prone to be unstable.&lt;/p&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;
  &lt;h2&gt;Common sources of flakiness:&lt;/h2&gt;
  &lt;ul&gt;
      &lt;li&gt;
          &lt;a href=&apos;#complexity-and-test-size&apos;&gt;Complexity and test size&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&apos;#asynchrony-in-the-app&apos;&gt;Asynchrony in the app&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&apos;#environment-and-preconditions&apos;&gt;Environment and Preconditions&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;a href=&apos;#unmanaged-tests&apos;&gt;Unmanaged tests&lt;/a&gt;
      &lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;
&lt;h3 id=&quot;complexity-and-test-size&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#complexity-and-test-size&quot; aria-label=&quot;complexity and test size permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Complexity and test size&lt;/h3&gt;
&lt;p&gt;Web applications are part of sophisticated systems. Long gone are the times of &lt;code class=&quot;language-text&quot;&gt;&amp;lt;marquee&gt;&lt;/code&gt; where the web was composed of single html files with table-based layouts. Even the now trendy simple-looking JAMStack is backed by advanced infrastructure. But with the ever-increasing complexity of codebases comes difficulty in determining precisely why a test is failing to produce a result. An end-to-end test will touch on many layers of an application, and while a positive result means that the application is working, a negative result might mean anything from a dropped internet connection to the server restarting.&lt;/p&gt;
&lt;p&gt;The bigger the test—in the sense of how much of the application stack it touches—the more unpredictable it becomes. For example, several routes to an e-commerce application will be visited and large portions of the code exercised in executing a test that evaluates the whole shopping experience. Compared to a small test that checks if a single button works, the uncertainty introduced by a big test like for the shopping experience is orders of magnitude higher. Don’t take our word for it: &lt;a href=&quot;https://testing.googleblog.com/2017/04/where-do-our-flaky-tests-come-from.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Jest Listfield at Google&lt;/a&gt; found a strong correlation between test size and the resources required to run it with flakiness.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Right now you can do the following in order to manage non-determinism caused by complexity&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prioritize which results matter most to your team&lt;/strong&gt;: if you work on a frontend team, you most likely won’t get much value of tests failing over network errors or QA environments set up by other teams. Instead, you may find more valuable assessing that your work is correct, even if that implies opening the risk of a ‘false positive.’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coordinate testing strategies with other teams&lt;/strong&gt;: If the back-end team has a great test suite that covers their endpoints, the front-end team should focus on tests that do not touch on the real back-end. Bigger tests that involve both ends can be maintained independently, so their inherent non-determinism doesn’t interrupt the other end team.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simulate parts of your stack&lt;/strong&gt;: Simulation is a great way of removing complexity from your test without compromising a realistic outcome. We have had good results by investing in simulators for RESTful and GraphQL back-ends as well as Bluetooth devices.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;asynchrony-in-the-app&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#asynchrony-in-the-app&quot; aria-label=&quot;asynchrony in the app permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Asynchrony in the app&lt;/h3&gt;
&lt;p&gt;Web applications put together many moving pieces: browser renderings, APIs loading, events triggering, loggers recording, and more. It’s therefore not a trivial thing to be precise about when to run an assertion for a test. Sometimes you wait too long, other times not long enough. In both cases we not only &lt;a href=&quot;https://frontside.com/blog/2020-triple-threat-to-testing-part-1-speed/#waiting-too-much-waiting-too-little&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;compromise the speed of our test&lt;/a&gt;, but we can end up having a flaky test suite.&lt;/p&gt;
&lt;p&gt;It is at the level of browser asynchrony where testing tools often promise “flake free” experiences. Testing tools do a great job at detecting when changes are done in the DOM, but have a harder time dealing with pending promises and relevant network requests. It’s not surprising when we eventually get non-deterministic requests within the UI.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Right now you can do the following in order to reduce flakiness induced by asynchrony in the app&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Avoid fixed waiting times&lt;/strong&gt;: if you have any &lt;code class=&quot;language-text&quot;&gt;wait(500ms)&lt;/code&gt; in your test, you’re bounding your assertions to something that may fail. Oftentimes using wait is a desperate measure that slows down test suites and leads to non-deterministic outcomes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Investigate poll-based waiting&lt;/strong&gt;: Consider instead waiting until a specific criterion is met like a selector appearing on the DOM. For example, in &lt;a href=&quot;https://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Finders&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Capybara&lt;/a&gt;, you can &lt;code class=&quot;language-text&quot;&gt;find&lt;/code&gt; an element and provide additional information on what exact match you’re waiting for, while &lt;a href=&quot;https://testing-library.com/docs/dom-testing-library/api-async&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;TestingLibrary&lt;/a&gt; provides mutation-based waiting through &lt;code class=&quot;language-text&quot;&gt;waitFor&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Analyze API request waiting options&lt;/strong&gt;:  HTTP requests are one of the most significant sources of test flakiness, but how to handle it depends on how you’re setting up the API layer in your tests. For example, if you use &lt;a href=&quot;https://docs.cypress.io/api/commands/wait.html#Arguments&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Cypress&lt;/a&gt; to simulate requests, their library provides &lt;code class=&quot;language-text&quot;&gt;wait(alias)&lt;/code&gt;, which allows you to wait for an HTTP request to be ready instead of having to rely on UI effects to know if the request is done loading.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Opt for framework-native waiting&lt;/strong&gt;: Check for smarter ways that your library offers to wait. Some tools, provide functions that reach into internal framework functionality to achieve more efficient waiting. React offers &lt;a href=&quot;https://reactjs.org/docs/test-utils.html#act&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;act&lt;/code&gt;&lt;/a&gt;, while Ember resolves &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt; &lt;a href=&quot;https://guides.emberjs.com/release/testing/testing-components/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;smartly by default&lt;/a&gt; with &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;environment-and-preconditions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#environment-and-preconditions&quot; aria-label=&quot;environment and preconditions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Environment and Preconditions&lt;/h3&gt;
&lt;p&gt;Let’s say you’re looking to find the new hip café in a part of town you’re not familiar with. Your phone’s navigation is not behaving now: time for some old-school navigation. You ask a seemingly friendly person for directions. “Oh sure, turn left in the next block, and you’ll see it.” You easily find the café. But if you were not standing at the location where you were given the directions, “turn left in the next block” would have led you somewhere else entirely. Similarly, if a test executes actions starting from a different initial state, its results will most likely differ from what you intended. This is a common cause for flaky tests: non-deterministic initial states, often caused by state changes leaking from other tests.&lt;/p&gt;
&lt;p&gt;Ideally each test should be self-contained, as you want to be able to get the same results from tests regardless of the order in which you run them, or whether you run all your tests or just a subset. But changes in the application state tend to slip through the thinnest cracks: databases, local storages, application data, sessions, and other forms of data persistence.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Right now you can do the following in order to reduce the chances of non-determinism caused by polluted preconditions or global variables&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Determine if you have interdependent tests&lt;/strong&gt;: Look for tests that require being run in a particular order (deliberately or by chance) as this kind of interdependence may cause headaches sooner than you think. Reconsider if you can write your tests in a different way so each of them is self-sufficient.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Experiment with a randomized order&lt;/strong&gt;: Some tools allow you to run your tests in a random order to test the isolation of your tests. For example, in Jest you can configure a &lt;a href=&quot;https://jestjs.io/docs/en/configuration#testsequencer-string&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;testSequencer&lt;/a&gt; to run tests in a random order.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reset your data sources&lt;/strong&gt;: Find out what’s the most reliable (and fast) way to return your data storages to a default state after each test. For instance, Jest can monkey patch modules so that if they have shared global state they won’t leak between tests; in Ruby on Rails you can use a &lt;a href=&quot;https://github.com/DatabaseCleaner/database_cleaner&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;DatabaseCleaner&lt;/a&gt; to reset the state explicitly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;unmanaged-tests&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#unmanaged-tests&quot; aria-label=&quot;unmanaged tests permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Unmanaged tests&lt;/h3&gt;
&lt;p&gt;Flaky tests are like invasive weeds in your garden. They will keep popping up despite your best efforts. Yet if you stop plucking them out regularly, they threaten your precious vegetables because they will consume many resources. Similarly, if you don’t manage your flaky tests effectively, they will accumulate rapidly and compromise the entire test suite’s value. For this reason, it is important for your team to have an effective process to keep tests effective and flake-free.&lt;/p&gt;
&lt;p&gt;Of course if unreliable tests are so damaging, why haven’t more resources been poured into making them more effective? The main reason is that flakiness is a symptom of other problems in the application and test suite. Flakiness can come from application code, dependencies, environments, or tools. Figuring out what’s causing the issue can be time consuming, which it is common to “temporarily” sweep issues under the &lt;code class=&quot;language-text&quot;&gt;skip&lt;/code&gt; rug. But dead tests silently increase the test suite liability, and without a defined process on how to handle skipped tests, the opportunity to improve the app is lost.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Right now you can do the following in order to manage your test suite&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Automate the identification of flaky tests&lt;/strong&gt;: Some companies like Google and Facebook automate detection by logging every single test run in their CI system so they can flag tests as non-deterministic. While useful, it is unlikely that this strategy alone can help during active development or when preparing a Pull Request. For this reason, &lt;a href=&quot;https://labs.spotify.com/2019/11/18/test-flakiness-methods-for-identifying-and-dealing-with-flaky-tests/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Spotify introduced FlakyBot&lt;/a&gt;, which developers can invoke in their PR to generate a report on the reliability of the test suite.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handle flaky tests as issues&lt;/strong&gt;: For instance, when you detect a test is non-deterministic, you (or your bot) can create a ticket explaining what is known about that test, and flag it in your test suite as it may be necessary to skip it during the normal test runs until it is fixed. Your team should then develop a plan to deal with tests that have been reported as flaky, checking on such open tickers at least quarterly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learn and Prevent&lt;/strong&gt;: As you encounter more flaky tests, your team&apos;s understanding of what causes them grows. Prevention is the distilled result of managing your tests methodologically, so document the findings that come out of dealing with flaky tests to identify the patterns used by the team in a specific area or to flag a certain technology as unreliable.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;Carpooling is a great solution when it’s designed to work, and at Frontside we think that everyone should feel the same way about tests. By checking for complexity, addressing asynchronicity, investigating preconditions, and managing their tests, developers can effectively strategize to minimize the impact of flaky tests and return them to their rightful status during the development process as a useful tool rather than an obstacle to be overcome.&lt;/p&gt;
&lt;p&gt;As &lt;a href=&quot;https://hackernoon.com/flaky-tests-a-war-that-never-ends-9aa32fdef359&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Coding Gang says&lt;/a&gt;, flakiness is a war you can&apos;t win, and non-determinism will appear from time to time. But we think teams can work to make these scenarios the exception rather than the rule, and learn valuable lessons when non-determinism appears to minimize the impact of flaky tests moving forward.&lt;/p&gt;
&lt;h3 id=&quot;up-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#up-next&quot; aria-label=&quot;up next permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Up next...&lt;/h3&gt;
&lt;p&gt;Like speed, reliability is essential to a test suite, but you need to address all three legs of the testing threat in order to develop a balanced response. That means we need to talk about the final essential make-or-break factor in testing: relevance. With limited tooling to manage it, relevance relies almost entirely in human judgment, but there are steps you can take to avoid wasting resources in tests that don’t yield any value for your team.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;At Frontside, we think effective testing is vital for successful software teams. We can help your team develop testing best-practices so they can deliver features confidently. &lt;a href=&quot;https://frontside.com/contact&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Give us a shout if you’d like to work with us&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/0c348234dc6ef8d5091787a60860fa75/2a4de/2020-triple-threat-to-testing-part-2-reliability-social.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[7 reasons to write good Pull Request descriptions]]></title><description><![CDATA[A good Pull Request description can lead to better reviews, improved solutions, better documentation, and more. In this article, Taras surveys seven big wins of PR descriptions.]]></description><link>https://frontside.com/blog/2020-04-15-7-reasons-for-good-pull-request-descriptions/</link><guid isPermaLink="false">https://frontside.com/blog/2020-04-15-7-reasons-for-good-pull-request-descriptions/</guid><category><![CDATA[best-practices]]></category><category><![CDATA[dx]]></category><dc:creator><![CDATA[Taras Mankovski]]></dc:creator><pubDate>Wed, 15 Apr 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In large open-source projects writing a good description in a Pull Request (PR) can be the difference between your changes being merged or ignored. These projects essentially necessitate the creation of PR descriptions, as development practices are strictly enforced by tooling and the culture of collaboration. These practices dramatically help improve the quality of the overall project.&lt;/p&gt;
&lt;p&gt;But in closed source enterprise projects, the pressure of deadlines and insufficient or inconsistent development practices limit the attention developers can spend on crafting descriptions for PRs. It is not unusual to stumble across private repositories with numerous PRs that have no description for them whatsoever. Part of the problem is that most development environments treat Pull Requests as merge demands rather than a genuine request like they are in the Open Source community.&lt;/p&gt;
&lt;p&gt;Yet adopting some open-source practices around PR descriptions would be a good thing even in closed environments. Without a meaningful explanation of why or how the code changes were introduced into the code base, unpleasant effects like rubber stamping, unnecessary abstractions, and knowledge silos are introduced. As such mistakes weave their way through the development process, they add up and eventually compromise the long-term success of an organization’s software.&lt;/p&gt;
&lt;p&gt;For me, descriptions are a critical part of Pull Requests. In case you’re not fully convinced of the value of Pull Request descriptions, let me give you a fistful of reasons why you should never merge a PR without a good accompanying description.&lt;/p&gt;
&lt;h2 id=&quot;1-they-capture-context&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-they-capture-context&quot; aria-label=&quot;1 they capture context permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. They capture context&lt;/h2&gt;
&lt;p&gt;By definition, a Pull Request is a proposal to change code in a particular way. If your change is correct, then your code will likely live in the application for a long time. You will always be able to go back and look at the result of merging the pull request. But what you will not find in the source code is why the change was made. What prompted the change? Were you under pressure to fix a bug? Was this change a team decision that you implemented? All of this information is context. It provides the answer, and sometimes is the only defense against the inevitable question that gets asked: Why on earth is this code even here?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2020-7-reasons-for-good-pull-request-descriptions-empty-pr.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;A PR with no description has no context&lt;/figcaption&gt;&lt;/figure&gt;
&lt;em&gt;A Pull Request with no description lacks important context. For example, why did this PR change 53 files at once? Refactoring? New feature? Hard to tell at a glance.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;2-descriptions-prevent-unnecessary-code&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-descriptions-prevent-unnecessary-code&quot; aria-label=&quot;2 descriptions prevent unnecessary code permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. Descriptions prevent unnecessary code&lt;/h2&gt;
&lt;p&gt;Every line of code increases your organization’s liability. Even your best code will become someone’s WTF moment. Think back to the last time that you swore at a piece of code, and moments later realize that you are the author. The best PRs remove source code. The second best are those that never get merged because they turn out to be unnecessary. But without a description such unmerged PRs are likely never to happen, resulting in code that is heavier than it needs to be.&lt;/p&gt;
&lt;p&gt;For example, suppose you want to introduce an abstraction to the code that already exists but you were not aware of. You’d be introducing unnecessary complexity by adding a code path for something that already exists in the source code. If you don’t write a pull request description that explains what your abstraction does, you’ll miss out on the opportunity to learn that a similar abstraction already exists. Even a few un-merged pull requests per quarter can add up to a lot of code that you don’t need to worry about and maintain down the line.&lt;/p&gt;
&lt;h2 id=&quot;3-descriptions-identify-the-right-change-increment&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-descriptions-identify-the-right-change-increment&quot; aria-label=&quot;3 descriptions identify the right change increment permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. Descriptions identify the right change increment&lt;/h2&gt;
&lt;p&gt;All programmers strive to write great code, but often this leads to making (a lot) more changes in a single Pull Request than originally intended. If you think this doesn’t apply to you, try making a bullet point list of all of the changes that you introduced in a recent Pull Request. You’ll quickly find that you made numerous changes after running across mixed whitespaces, improperly formatted blocks of code, or a missing null check that were not relevant to the main concern of your PR.&lt;/p&gt;
&lt;p&gt;These kinds of side changes are surprisingly devious. They can slow down code reviews because your changes were unexpectedly more controversial than expected, introducing bugs that you didn’t even think of. Yet without a PR description they are fiendishly difficult to undo. By introducing the practice of describing the changes that your PR makes, you force yourself to reflect if all the changes you are making should be part of the same Pull Request. When your description has a big list of changes, it often alerts you to the fact that the PR should be split up into (several) smaller ones and merged separately.&lt;/p&gt;
&lt;h2 id=&quot;4-descriptions-lead-to-better-solutions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#4-descriptions-lead-to-better-solutions&quot; aria-label=&quot;4 descriptions lead to better solutions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;4. Descriptions lead to better solutions&lt;/h2&gt;
&lt;p&gt;Especially on large projects it’s not possible to always come up with the best available solution on your own. In most cases there will always be someone who will know an area of source code better than you. In other cases you are that person for a particular stretch of code, yet others are making imperfect changes to it. Given the constant churn and evolution of the programming ecosystems and it’s not hard to see why it’s simply impossible to always coming up with the best possible solution when making a PR. Yet it is also in everyone’s interest that others have an opportunity to suggest alternative and possibly better solutions to what was suggested in a PR. Without a description that draws the reviewer’s attention to the approach, you’re significantly reducing the chances that a better solution will emerge through code reviews.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2020-7-reasons-for-good-pull-request-descriptions-long-responses.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Recording of a long discussion on a PR&lt;/figcaption&gt;&lt;/figure&gt;
&lt;em&gt;A good description can lead to great discussion on a PR. I recently experienced it when contributing to Ink.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;5-descriptions-makes-reviewing-easier&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-descriptions-makes-reviewing-easier&quot; aria-label=&quot;5 descriptions makes reviewing easier permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5. Descriptions makes reviewing easier&lt;/h2&gt;
&lt;p&gt;Code reviews reduce the number of incomplete, poorly tested, and incorrect changes introduced into your codebase. They are a critical part of every effective development process to ensure that your solution matches your original intention, but can be time consuming. A good pull request description prepares the reviewer for what they’ll find during the code review. They can tell the reviewer where to focus their attention by highlighting areas that you’re not sure about as well as areas that you’re proud of. This makes it easier to process PRs during code reviews and quickly provide meaningful feedback.&lt;/p&gt;
&lt;h2 id=&quot;6-descriptions-are-a-great-source-of-knowledge&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#6-descriptions-are-a-great-source-of-knowledge&quot; aria-label=&quot;6 descriptions are a great source of knowledge permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;6. Descriptions are a great source of knowledge&lt;/h2&gt;
&lt;p&gt;Most changes require some kind of research. You might have found a solution on StackOverflow, a blog post, or in the documentation. To get the answer, you would have to read a bunch of sources, match an approach to your problem, attempt the solution, and observe the result. This process is enlightening but also time-consuming. It’s important therefore to document your thinking in case someone else has to recreate it, but also because everyone can learn from it.&lt;/p&gt;
&lt;p&gt;When you’re writing a PR description, all of this learning is fresh in your mind. It’s the best time to synthesize what you learned and share it with your team without the overhead of writing a blog post. Including lessons learned in your PR description will allow you to better remember the information that you learned and highlight what you learn for others on your team to benefit.&lt;/p&gt;
&lt;h2 id=&quot;7-descriptions-make-you-invaluable&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#7-descriptions-make-you-invaluable&quot; aria-label=&quot;7 descriptions make you invaluable permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;7. Descriptions make you invaluable&lt;/h2&gt;
&lt;p&gt;Most of our days as developers are spent finding solutions to problems. A PR description is equivalent to providing a great unboxing experience for your solution. If you spent a week working on a problem, spending an hour to write a detailed Pull Request description will make your solution look that much better because it’ll allow your teammates to understand why this problem was complicated and required a week of work.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Open source communities have a reputation for having great source code. It’s not a coincidence that they tend to have some of the strictest requirements dictating the quality of PR descriptions. Enterprise teams can learn a lot from the best practices of how open source communities write great software, starting with pull requests.&lt;/p&gt;
&lt;p&gt;Requiring a good PR description is a small investment that pays big dividends. Give it a shot for a few months and encourage the same of your fellow developers. You might find yourself never going back, and emerge as a stronger and more valuable team member as a result.&lt;/p&gt;
&lt;aside class=&quot;posts-list-list&quot;&gt;
  &lt;h2&gt;Related article:&lt;/h2&gt;
  &lt;div class=&quot;posts-list-entry&quot;&gt;
    &lt;h3 class=&quot;posts-list-title&quot;&gt;
      &lt;a href=&quot;/blog/2020-05-25-github-actions-pull_request/&quot;&gt;
        Gihub Actions: a deep dive into pull_request
      &lt;/a&gt;
    &lt;/h3&gt;
    &lt;p&gt;
      We have put together specific behaviors and information that you’ll need to use pull_request as a trigger for your Github Actions workflow.
    &lt;/p&gt;
    &lt;a href=&quot;/blog/2020-05-25-github-actions-pull_request/&quot; class=&quot;post-link&quot;&gt;
      Continue reading
      &lt;span class=&quot;post-link--arrow&quot;&gt;→&lt;/span&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/aside&gt;</content:encoded><media:content url="https://frontside.com/static/0bab407c201b2dec75d66de622ff5789/2a4de/2020-7-reasons-for-good-pull-request-descriptions-social.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[The Triple Threat to Testing — Part 1: Speed]]></title><description><![CDATA[Speed, reliability, and relevance constitute the mains pillars of a robust testing strategy. The faster a test suite can diagnose an issue in its application, the more value it renders. In this article, we navigate through the most significant causes of slow tests and suggest ideas to deal with them.]]></description><link>https://frontside.com/blog/2020-04-06-triple-threat-to-testing-part-1-speed/</link><guid isPermaLink="false">https://frontside.com/blog/2020-04-06-triple-threat-to-testing-part-1-speed/</guid><category><![CDATA[testing]]></category><category><![CDATA[dx]]></category><dc:creator><![CDATA[Charles Lowell, Robbie Pitts, Taras Mankovski, Jeffrey Cherewaty, Jorge Lainfiesta]]></dc:creator><pubDate>Mon, 06 Apr 2020 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Writing tests is like paying taxes. And much like how attitudes vary towards paying taxes, attitudes diverge widely in development circles about writing tests. Some people dread paying their taxes; much in the same way as some developers would rather cut off their arm than spend time testing an app. Other people willingly pay their taxes because of the benefits they confer, like drivable roads, health care and national defense. In similar fashion there are those developers that look forward to testing because of the protection in gives against regressions and the confidence it inspires when making changes. You&apos;ll even find people who argue that there’s something inherently good in paying taxes and writing tests—a moral obligation if you will.&lt;/p&gt;
&lt;p&gt;But just like people debate the merits of taxes, developers argue over the value of tests. Some claim that they don’t need tests while others think they are so important you should write them before anything else. There’s no consensus in part because tests vary widely across technologies, projects, teams, and organizations. One thing is for certain, however; just like taxes take money out of your pocket, testing imposes a variety of costs on your organization and your development team.&lt;/p&gt;
&lt;p&gt;We’re not writing to convince you about the value of testing any more than we’re here to convince you to pay your taxes. But I think we can all agree, that if you &lt;em&gt;are&lt;/em&gt; going to pay taxes, then you should expect the &lt;em&gt;best governance&lt;/em&gt; in return. So when it comes to testing, our experience has show us that if you &lt;em&gt;are&lt;/em&gt; going to invest in tests, there are three essential make-or-break factors that will dramatically affect how much benefit they will bring in exchange for how much burden they pose.&lt;/p&gt;
&lt;p&gt;The first factor is the most obvious: speed. Slow tests are literally a drag on teams and organizations.&lt;/p&gt;
&lt;aside class=&quot;blog-post--saga-box&quot;&gt;
The second part is out! Check out how &lt;a href=&quot;https://frontside.com/blog/2020-triple-threat-to-testing-part-2-reliability/&quot; target=&quot;_blank&quot;&gt;Reliability directly impacts your test suite&lt;/a&gt;, as well as common causes of test flakiness.
&lt;/aside&gt;
&lt;h2 id=&quot;why-speed-matters&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-speed-matters&quot; aria-label=&quot;why speed matters permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why Speed Matters&lt;/h2&gt;
&lt;p&gt;In the stock market, information services offer different pricing schemes around speed. You can wait and get information for free in a minute or pay to get data within seconds. But if you want information with minimum latency the price tag goes through the roof. Why? The infrastructure to make this possible is more expensive and the value of knowing something before others is very high.&lt;/p&gt;
&lt;p&gt;Speed gives brokers a competitive advantage, and the same is true when it comes to testing. How rapidly a test can diagnose issues in your application can make all the difference. Because tests determine the minimum rhythm at which developers can discuss the results of their code, the speed of a test suite scales up to affect the entire organization. A Pull Request whose test suite takes 1 hour to run sets a plodding pace not just for the development team but product and design teams as well.&lt;/p&gt;
&lt;p&gt;What’s worse is that when tests don’t deliver results fast enough, a developer working on a feature loses the thread of the problem the test was intended to help solve. This dynamic quickly leads to frustration and causes developers—who are inherently problem-solvers—to find work-arounds that essentially avoid testing altogether. Whatever you think about testing, we can all agree that a test suite should be fast enough not to break the context under which it’s being run. An unused test suite isn’t a test suite at all.&lt;/p&gt;
&lt;p&gt;With this level of dysfunction you’d think that improving test speed would be at the top of everyone’s to-do list. Yet if you ask around it seems like we have just accepted that tests are slow and have learned to adapt to their plodding pace. Some teams decide to run only a few tests on every PR through CI, reserving the whole suite for ‘important’ builds. Other teams choose from time to time to not even bother running tests locally.&lt;/p&gt;
&lt;p&gt;These reactions are typical and even make sense: waiting for a test suite to run is boring and non-productive, like standing in line at the Department of Motor Vehicles. What’s worse is that you have to go to the back of the line time and time again when the scripts you are running produce results that are flaky. It’s depressing when the development process—which at its core is an essentially creative process—has come to feel bureaucratic as a result of testing.&lt;/p&gt;
&lt;h2 id=&quot;whats-slowing-down-the-test-suite&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-slowing-down-the-test-suite&quot; aria-label=&quot;whats slowing down the test suite permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What’s slowing down the test suite?&lt;/h2&gt;
&lt;p&gt;We have all experienced slow test suites. Maybe you’re even reading this article while your PR is running tests. Understanding why tests take the time they do allows developers to pre-emptively act and make them more effective and useful while also making them faster. In fact here are things developers can do right now both application-wise and with regard to test strategies to improve the speed of tests.&lt;/p&gt;
&lt;h3 id=&quot;slow-front-end-apps&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#slow-front-end-apps&quot; aria-label=&quot;slow front end apps permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&quot;Slow&quot; Front-end Apps&lt;/h3&gt;
&lt;p&gt;User interfaces are supposed to be used by humans, but when a machine uses them they reveal their underlying performance issues. A person furiously tapping your app buttons as fast as they can will not match the speed of a machine. Not even developers themselves – who know exactly where each button is located – can assert the state of the app as fast as a script. That’s why slow loading and reacting UI elements are invisible to us most of the time.&lt;/p&gt;
&lt;p&gt;When you run a test the machine will always be limited by the speed of the application. On every simulated interaction and on every assertion, the test runner waits: it waits for code to be loaded and parsed, for elements to appear, for APIs to load, or for interactions to happen. Repetition scales up the natural latency of an app until it becomes noticeable.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Right now you can do the following in order to streamline front-end apps&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Check the &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Time to Interactive&lt;/a&gt; of your application&lt;/strong&gt; You may be loading too many things on the entry point of your app: user profile, dynamic navigation segments, analytics scripts, and more. Consider if there’s something you shouldn’t be using within the test context (like pixel scripts for marketing).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disable non-test-related latency&lt;/strong&gt;: for example, unless you’re testing the animation itself, you can consider disabling animations in the testing context. Animations just mean waiting time for the test runner in most cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Evaluate the overall performance of your app&lt;/strong&gt;: this seems obvious, but sometimes it pays to stop and contemplate what&apos;s right in front of you. If the test are painfully slow, then perhaps your app is slow, and an investment in making it more peppy will yield dividends for both your developers and your users.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;slow-build-times&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#slow-build-times&quot; aria-label=&quot;slow build times permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Slow Build times&lt;/h3&gt;
&lt;p&gt;The first step of a test suite usually involves generating a fresh build of your app in the context that you choose. Although this is a time cost that the test suite generally only has to pay once, it is still a major factor in how soon developers can get test results. A fresh build can take up to several minutes – the equivalent of eons in computer time.&lt;/p&gt;
&lt;p&gt;Most applications today use a bundler like webpack to take the application code (and its libraries) and transpile it, minimize it, optimize it, modularize it, and do whatever other cool process the development team has chosen. As the application grows, the build time may grow non-linearly if they are not mindful of how they create the bundle itself. And if running a test requires spinning off a Kubernetes instance or installing a full-blown database, you can expect even longer wait times before you get any results from your test suite.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Right now you can do the following in order to speed up build times&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Budget for performance improvements&lt;/strong&gt;: build times tend to be a boiling problem: as features are constantly added, the time increases without anybody noticing. Performance improvements are typically triggered only after somebody complains about the tools being too slow. We recommend having a performance budget to proactively improve the build times; otherwise you might find yourself returning to re-write the build script again and again.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Evaluate your test environment&lt;/strong&gt;: check with your team if you can simulate parts of the test environment (for instance, use a tool like &lt;a href=&quot;https://miragejs.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Mirage.js&lt;/a&gt; instead of using a real database).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;not-specific-enough-entry-points&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#not-specific-enough-entry-points&quot; aria-label=&quot;not specific enough entry points permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Not specific enough entry points&lt;/h3&gt;
&lt;p&gt;Web applications are attractive because you don’t need to install anything to use them: you just hit a URL and you’re ready to do what you want. The URL is the entry point for a web application. Most people access the app through the root &lt;code class=&quot;language-text&quot;&gt;/&lt;/code&gt; and then navigate their way around. Advanced users may even know the URLs they care about and go straight to it (&lt;code class=&quot;language-text&quot;&gt;/p/{my-crush}&lt;/code&gt; or even &lt;code class=&quot;language-text&quot;&gt;/p/{my-crush}/photos&lt;/code&gt;). Using more specific entry points saves time of navigation to users, and can save time when testing.&lt;/p&gt;
&lt;p&gt;Let’s imagine a developer wants to test a confirmation modal that shows up after a user attempts to change their Address in the user Profile, under the Personal Details tab. If, you have to manually follow all the interactions from the homepage to check if that the modal appears (as in the code below) your tests will take longer.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[navigation-login-button&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;waitFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[login-form&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fillIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[login-username]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;username&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fillIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[login-password]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;password&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[login-submit&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;waitFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[logged-in-user]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[navigation-my-profile]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;waitFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[profile-navigation]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[profile-navigation-personal-details]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;waitFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[personal-details-form]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Now we are finally ready to test what we care about&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fillIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[personal-details-form-address]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[personal-details-form-submit]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
assert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[personal-details-confirm-modal]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s a lot of actions for one assertion – 10 that are unrelated to the test, and several of them involve waiting. If there are four scenarios you want to test about the behavior of that model, that’s 40 time-consuming and unnecessary actions.&lt;/p&gt;
&lt;p&gt;Instead you can make use of your router and set up an authentication mechanism that allows you to easily set the application in an authenticated state. Then your test would be simplified and much faster:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;simulateAuth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;user&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/profile/personal-details&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;fillIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[personal-details-form-address]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[personal-details-form-submit]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
assert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[personal-details-confirm-modal]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Right now you can do the following in order to improve entry points&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Evaluate your routing strategy&lt;/strong&gt;: in many cases using more routes with specific contents is not only good for tests but also helps deliver a better user experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simulate authentication&lt;/strong&gt;: discuss with your team the best strategy to simulate authentication in your application, from using a framework specific tool to manipulating local storage directly (while not forgetting to take security considerations into account).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;waiting-too-much-waiting-too-little&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#waiting-too-much-waiting-too-little&quot; aria-label=&quot;waiting too much waiting too little permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Waiting too much, waiting too little&lt;/h3&gt;
&lt;p&gt;Asserting the state of a web application is like playing the street basketball game 21. The first team to score exactly 21 points wins; but if they go over their score is reduced by 11. Assertions are similar in that you must make them at a specific moment in time: if you don’t hurry up you lose precious time, but if you miss the mark you’re stuck with more waiting and have to try again.&lt;/p&gt;
&lt;p&gt;Web applications perform a lot of tasks asynchronously: loading files, fetching images, calling APIs and recording analytics to name a few. That’s why waiting is such a tricky part of testing user interfaces. There’s no exact fixed time intervals in the way elements are rendered because they depend on many other elements and which client is being used. There’s also external dependencies like server requests that may take variable amounts of time.&lt;/p&gt;
&lt;p&gt;Sometimes developers can set tests to wait too much. For example, to make sure an element was rendered in the page we can make our test wait for a fixed time interval like &lt;code class=&quot;language-text&quot;&gt;wait(‘500ms’)&lt;/code&gt;. But if that element appears in &lt;code class=&quot;language-text&quot;&gt;25ms&lt;/code&gt;, we would be wasting &lt;code class=&quot;language-text&quot;&gt;475ms&lt;/code&gt; which add up rapidly through the whole test suite. Other times developers can waste time setting the test to wait on the wrong element, which could imply waiting longer than the minimum required for what we care about for a particular assertion.&lt;/p&gt;
&lt;p&gt;Of course other times developers wait for too little time, using a fixed time interval that simply wasn’t long enough to render the element and causing an error when interacting with it. Depending on the tool we’re using, we can try again and re-run the waiting or get a test failure. In both cases we lose time because of inadequate waiting.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Right now you can do the following in order to find the sweet spot for waiting&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Check for fixed waiting times in your test suite&lt;/strong&gt;: try to replace fixed waiting times for other heuristics that can be resolved earlier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discourage arbitrary waiting via tooling&lt;/strong&gt;: you can set up linting rules to warn developers when they try to use fixed waiting functions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Understand how your test runner handles waiting&lt;/strong&gt;: you may have quick wins available by leveraging the waiting strategies your test runner is built for. For example, Cypress offers &lt;a href=&quot;https://docs.cypress.io/guides/guides/network-requests.html#Waiting&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;route aliases&lt;/a&gt; to help you wait precisely for API responses.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;resource-intensive-testing-scenarios&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#resource-intensive-testing-scenarios&quot; aria-label=&quot;resource intensive testing scenarios permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Resource-intensive testing scenarios&lt;/h3&gt;
&lt;p&gt;You can vary just how close to reality you test a web application in. For example, to provide data to the app, you can use an API deployed on a QA environment, or spin-off a local database seeded with data samples, or even pack mocks as part of the test. The closer to production that we emulate the testing scenario, the more resources – and time – will be needed.&lt;/p&gt;
&lt;p&gt;The most significant advantage of getting a test environment closer to production is that you gain confidence that your tests are diagnosing your application realistically. However, running a test suite against real APIs represents a major challenge in terms of time and cohesiveness. The same can be said of other external dependencies (like Bluetooth connectivity) for your application.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Right now you can do the following in order to select the right testing scenario:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Assess the level of realness your team needs&lt;/strong&gt;: perhaps your data needs are not too complex, and your application doesn’t handle critical operations, so mocks would suffice. If your business requires more sophisticated data management, you may need to invest in tools that can help you ensure your tests cover such cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consider simulation&lt;/strong&gt;: simulation is an intermediate point between mocks and real APIs that provides the velocity of mocks with the complexity of real backends. You can simulate database queries, as well as errors, using tools like &lt;a href=&quot;https://miragejs.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Mirage.js&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;Everybody feels better about paying taxes when they can see results. At Frontside we think everyone would feel better about tests if they could see their results faster. By addressing both application concerns (time to interactive, build time, routing granularity) and testing strategies (waiting precision, realness) developers right now can win back precious seconds, minutes, and even hours of time spent on slow tests.&lt;/p&gt;
&lt;p&gt;We think it’s worth the effort to improve testing, as speedy test suites shorten feedback loops and add up to increase the organization’s velocity. And that maximizes the dividend you get for your investment in tests.&lt;/p&gt;
&lt;h3 id=&quot;up-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#up-next&quot; aria-label=&quot;up next permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Up next...&lt;/h3&gt;
&lt;p&gt;Speed is critical to a healthy testing strategy, but it won&apos;t work without the other pillars of the testing triple threat. Next we focus on the second essential make-or-break factor in testing: reliability. Tests can be flaky, but there are strategies you can take now to detect, fix, and even prevent having non-deterministic tests in your application.&lt;/p&gt;
&lt;p&gt;Keep on reading, &lt;a href=&quot;/blog/2020-triple-threat-to-testing-part-2-reliability/&quot;&gt;The Triple Threat to Testing — Part 2: Reliability&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;At Frontside, we think effective testing is vital for successful software teams. We can help your team develop testing best-practices so they can deliver features confidently. &lt;a href=&quot;https://frontside.com/contact&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Give us a shout if you’d like to work with us&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/5d8e78dfbc7420388c279a10bb5c91ef/2a4de/2020-triple-threat-to-testing-part-1-speed.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Case study — Facilitating the next generation of Bluetooth-connected apps]]></title><description><![CDATA[More and more teams are using Bluetooth for innovative products, but developing UIs for connected devices can be challenging: limited physical devices slow down development and make it nearly impossible to keep up a strong test suite. Our solution is simulation and Open Source power.  ]]></description><link>https://frontside.com/blog/2019-12-11-case-study-bluetooth-simulation/</link><guid isPermaLink="false">https://frontside.com/blog/2019-12-11-case-study-bluetooth-simulation/</guid><category><![CDATA[oss]]></category><category><![CDATA[case-study]]></category><category><![CDATA[simulation]]></category><dc:creator><![CDATA[Taras Mankovski]]></dc:creator><pubDate>Wed, 11 Dec 2019 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today Bluetooth is among the most widely adopted wireless communication technologies, and the popularity of Bluetooth enabled devices shows no signs of warning. With an anticipated annual growth rate of 8% through 2023 [1], it’s no surprise that more organizations than ever before are developing software to connect to and communicate over Bluetooth.&lt;/p&gt;
&lt;p&gt;However, developing for Bluetooth can be cumbersome. The typical process begins with the frontend team being blocked until they receive the physical devices, and engineers having to wait to try out their work due to limited hardware. To show their progress, every month or two teams have to drop everything to invest at least a week’s time setting up a demo.&lt;/p&gt;
&lt;p&gt;This rhythm makes course corrections from the VP of Product expensive, forcing the UX team to design some experiences as an after-thought. No less important is the emergence of a demo-driven culture that undermines everyone’s morale. And worst of all is the fact that it’s virtually impossible to have a fully automated test suite, dramatically increasing risks in the development pipeline.&lt;/p&gt;
&lt;p&gt;When Resideo came to Frontside with these concerns, we partnered with Polidea—a development studio based in Warsaw, Poland—to implement a Bluetooth simulator. By creating virtual representations of Bluetooth peripherals, developers can keep working despite the unavailability of physical devices, designers can get early feedback of the application UX, and managers can get a solid sense of the progress of the project. Adopting this approach has the twin virtues of both easing developmental bottlenecks and enabling automated testing.&lt;/p&gt;
&lt;p&gt;This case study provides an overview of the advantages of Bluetooth simulation and Frontside’s approach to open source collaboration with Polidea and Resideo.&lt;/p&gt;
&lt;h2 id=&quot;why-use-bluetooth-simulation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-use-bluetooth-simulation&quot; aria-label=&quot;why use bluetooth simulation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why use Bluetooth Simulation?&lt;/h2&gt;
&lt;p&gt;The idea of creating a Bluetooth simulator emerges from Frontside’s guiding philosophy of  &lt;em&gt;transparent development&lt;/em&gt;. It’s our belief that the impact of every change to the codebase can and should be tracked and be visible to both technical and non-technical stakeholders. &lt;a href=&quot;/services&quot;&gt;We help organizations establish tooling and practices that enable them to get a real sense of their product &lt;em&gt;as they build it&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That means that applications that connect to Bluetooth peripherals should follow transparent practices. Every pull request should be thoroughly tested, including the application’s connections to Bluetooth under varied circumstances and multiple configurations. And any stakeholder should be able to preview and experience every change in the codebase without particular setups or configs, just as a user would in production.&lt;/p&gt;
&lt;p&gt;Relying on physical devices to achieve transparent development is not a viable option as they impose several restraints on teams. Their limited numbers force developers to share devices, limiting their capability to work concurrently. Testing the application with every supported device is a monumental task on its own. Moreover, visibility on the project is compromised because setting up demos demands significant effort.&lt;/p&gt;
&lt;p&gt;But thanks to Bluetooth simulation, the VP of Product in San Francisco can test work delivered by the team in London and perform course corrections on the spot. The UX designer can adjust the connection drop-out experience from their home after reviewing the work done by a consultant in Stockholm while they were sleeping. No less important is the fact that everybody on the team rests easy knowing that thanks to automated testing the product works with every possible device configuration.&lt;/p&gt;
&lt;h2 id=&quot;a-win-win-win-open-source-strategy&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-win-win-win-open-source-strategy&quot; aria-label=&quot;a win win win open source strategy permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A win-win-win Open Source strategy&lt;/h2&gt;
&lt;p&gt;With Frontside’s approach to Open Source, companies, contributors, and the community all benefit. For this project, Frontside identified the need for a Bluetooth simulator as a key need for Resideo and saw the opportunity that creating one represented for the open source community. Polidea was commissioned to develop the Bluetooth simulator, Resideo provided financial support, and Frontside contributed architectural guidance to make the most out of the library.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2019-12-11-case-study-bluetooth-simulation-partners.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Resideo, Polidea, and the Open Source community benefit from BLEmulator&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resideo Wins&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;A library made by the best team for the job&lt;/em&gt;: by researching open source projects in the technologies relevant to Resideo, Frontside found Polidea, who had a proven track record of working with Bluetooth and experience in maintaining open source projects.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Access to highly-specialized experts on demand&lt;/em&gt;: corporations would typically be unable to hire smaller teams or experts to develop targeted solutions for precise pieces of the puzzle because of the associated transaction costs.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Reduced costs of ownership&lt;/em&gt;: now that the Bluetooth simulator is created, the maintenance costs and effort are shared by other contributors using the library.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Polidea Wins&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Financial support&lt;/em&gt;: Polidea already had plans for expanding its open source portfolio out of its own budget, but Frontside’s collaboration reduces this expense, enabling Polidea to focus on creating high-quality open source code.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Architectural insights&lt;/em&gt;: Frontside provided use-cases and architectural advice to make the Bluetooth simulator a tool that could be deployed independently of Polidea’s own libraries.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Community Wins&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;A polished open source Bluetooth library&lt;/em&gt;: characterized by the rigor and quality of Frontside’s code and the extensive experience of Polidea, the community can now count on a more complete Bluetooth library in the Flutter space&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Proved abstractions&lt;/em&gt;: Frontside and Polidea invested significant effort to create lean low-level abstractions that produce effective developer ergonomics for working with Bluetooth.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;whats-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-next&quot; aria-label=&quot;whats next permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What’s Next&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2019-12-11-case-study-bluetooth-simulation-blemulator.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;BLEmulator logo&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Currently Polidea’s Bluetooth simulator BLEmulator only works with projects that have chosen FlutterBLE as the Bluetooth interactor. But Frontside aspires to maximize the value and impact of its software collaborations. That’s why BLEmulator is designed to be decoupled from FlutterBLE so the library may become independent and be more widely adopted. It features low-level abstractions using native implementations under the hood that enable API consistency with platforms like iOS and Android.&lt;/p&gt;
&lt;p&gt;Learn more about &lt;a href=&quot;https://www.polidea.com/blog/bluetooth-low-energy-simulator-a-new-hope-in-iot-development/?utm_source=Backlinking&amp;utm_medium=Npaid&amp;utm_campaign=Blog&amp;utm_term=Article&amp;utm_content=BL_NOP_BLG_ART_Front001&quot; target=&quot;_blank&quot;&gt;BLEmulator from Polidea’s technical release&lt;/a&gt; and the project’s &lt;a href=&quot;https://github.com/Polidea/blemulator_flutter&quot; target=&quot;_blank&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;[1] Bluetooth SIG, Inc. (2019). “Bluetooh Market Update.” Available online at &amp;#x3C; &lt;a href=&quot;https://3pl46c46ctx02p7rzdsvsg21-wpengine.netdna-ssl.com/wp-content/uploads/2018/04/2019-Bluetooth-Market-Update.pdf&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://3pl46c46ctx02p7rzdsvsg21-wpengine.netdna-ssl.com/wp-content/uploads/2018/04/2019-Bluetooth-Market-Update.pdf&lt;/a&gt; &gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/a1ca5a71ca3d9757bb6c1e59eb58c9ea/2a4de/2019-12-11-case-study-bluetooth-simulation.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Build a Family Tree maker using React Hooks and Microstates]]></title><description><![CDATA[If you use React, you probably know about the React Hooks RFC that was introduced at ReactConf. It’s an exciting proposal because it promises to bring the power of class components to function components. It also a convention for creating React extensions that feel like first-class APIs in the React ecosystem. React Hooks API and Microstates bring expressiveness of React function components to a whole new level. ]]></description><link>https://frontside.com/blog/2018-11-06-build-a-family-tree-maker-using-react-hooks-and-microstates/</link><guid isPermaLink="false">https://frontside.com/blog/2018-11-06-build-a-family-tree-maker-using-react-hooks-and-microstates/</guid><category><![CDATA[javascript]]></category><category><![CDATA[microstates]]></category><category><![CDATA[react]]></category><dc:creator><![CDATA[Taras Mankovski]]></dc:creator><pubDate>Tue, 06 Nov 2018 05:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2018-11-06-build-a-family-tree-maker-using-react-hooks-and-microstates_family-builder.gif&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Demo of Family Builder Component&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;In this tutorial, we will create a Family Tree marker component using React Hooks and Microstates. The Family Tree maker will allow the user to enter their name, then their parent’s names, their parent’s parent’s names and their parent’s parent’s parent’s names, as far back as they can remember.&lt;/p&gt;
&lt;p&gt;To do this, we’ll follow the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new project and install Microstates&lt;/li&gt;
&lt;li&gt;Build recursive Family Tree maker component&lt;/li&gt;
&lt;li&gt;Persist component state in LocalStorage&lt;/li&gt;
&lt;li&gt;Optimize re-rendering of our component&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let’s get started.&lt;/p&gt;
&lt;h2 id=&quot;create-a-new-project-and-install-microstates&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#create-a-new-project-and-install-microstates&quot; aria-label=&quot;create a new project and install microstates permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create a new project and install Microstates&lt;/h2&gt;
&lt;p&gt;Let’s create a new app using &lt;strong&gt;create-react-app&lt;/strong&gt;. If you don’t have &lt;strong&gt;create-react-app&lt;/strong&gt; installed, you can install it by following instructions on &lt;a href=&quot;https://facebook.github.io/create-react-app/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;create-react-app website&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;create-react-app family-tree-app
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; family-tree-app &lt;span class=&quot;token comment&quot;&gt;# go into created directory&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then add &lt;code class=&quot;language-text&quot;&gt;@microstates/react&lt;/code&gt; &amp;#x26; &lt;code class=&quot;language-text&quot;&gt;microstates&lt;/code&gt; to your project.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;npm install --save microstates @microstates/react&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You should be able to start the server using &lt;code class=&quot;language-text&quot;&gt;npm start&lt;/code&gt; and see the React logo when you go to &lt;code class=&quot;language-text&quot;&gt;http://localhost:3000/&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;build-recursive-family-tree-builder-component&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#build-recursive-family-tree-builder-component&quot; aria-label=&quot;build recursive family tree builder component permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Build recursive Family Tree builder component&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2018-11-06-build-a-family-tree-maker-using-react-hooks-and-microstates_family-builder.gif&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Demo of Family Builder Component&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Our component will allow the user to enter their name. When the name is entered, they’ll see an input field to enter names of their mother and father. When a parent’s name is entered, we’ll show input fields for parent’s parents. This will work recursively as deeply as the user has patience to enter.&lt;/p&gt;
&lt;p&gt;State management is usually the most difficult part of building this kind of component. Luckily, Microstates will make this very easy. All we need to do is create a type that will allow us to store a name for a person, a mother and a father with their names. It needs to be recursive, just like our component. Microstates makes it very easy.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// name of the person &lt;/span&gt;
  mother &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Person&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// mother is of type Person&lt;/span&gt;
  father &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Person&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// father is of type Person&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our type is complete. This is everything that we need to create a recursive data structure. Microstates will take care of proving us with transitions and handle the immutability of this recursive data structure. Now, we just need to write the component that will use our &lt;code class=&quot;language-text&quot;&gt;Person&lt;/code&gt; type and &lt;code class=&quot;language-text&quot;&gt;useType&lt;/code&gt; hook. Let’s begin by creating the state and passing it to our future &lt;code class=&quot;language-text&quot;&gt;FamilyTree&lt;/code&gt; component.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; useType &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@microstates/react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; person &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Person&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FamilyTree&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We need to actually write our &lt;code class=&quot;language-text&quot;&gt;FamilyTree&lt;/code&gt; component. The component is going to show an input field for the name. When the name is not empty the component will render a &lt;code class=&quot;language-text&quot;&gt;FamilyTree&lt;/code&gt; component for the mother and the father.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FamilyTree&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; person&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token attr-name&quot;&gt;onChange&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
			&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
				Father: &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FamilyTree&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;father&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
				&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;br&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
				Mother: &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FamilyTree&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mother&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
			&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
        )}
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
	)
}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That should do it. Look at the onChange handler of the input. Notice the &lt;code class=&quot;language-js&quot;&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt; transition. It’s similar to a reducer that changes the name of the node, but Microstates handles immutably updating the value and causing our component to update via our &lt;code class=&quot;language-text&quot;&gt;useType&lt;/code&gt; hook. Let’s use another hook to persist our input in LocalStorage.&lt;/p&gt;
&lt;h2 id=&quot;persist-component-state-in-localstorage&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#persist-component-state-in-localstorage&quot; aria-label=&quot;persist component state in localstorage permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Persist component state in localStorage&lt;/h2&gt;
&lt;p&gt;Every transition creates a new value that we can serialize and later use to restore the state. We can use this to persist the state in LocalStorage. When the user refreshes their page, the family tree will be restored from LocalStorage. To do this, we’ll need to change a few things.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Restore state from localStorage&lt;/li&gt;
&lt;li&gt;Create the microstate with restored state&lt;/li&gt;
&lt;li&gt;Persist the state in localStorage&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;restore-state-from-localstorage&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#restore-state-from-localstorage&quot; aria-label=&quot;restore state from localstorage permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Restore state from localStorage&lt;/h3&gt;
&lt;p&gt;When the component is being rendered, we need to grab a key from localStorage and parse it with &lt;code class=&quot;language-text&quot;&gt;JSON.parse&lt;/code&gt;. This part is not unique to React Hooks or Microstates.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; initial &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;family-tree&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice the string wrapping an object &lt;code class=&quot;language-text&quot;&gt;”{}&quot;&lt;/code&gt; That’s an empty object that was serialized. I’m using this to ensure that there will be a value even when localStorage doesn’t have anything. This will happen on first rendering the component.&lt;/p&gt;
&lt;h3 id=&quot;create-the-microstate-with-restored-state&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#create-the-microstate-with-restored-state&quot; aria-label=&quot;create the microstate with restored state permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create the microstate with restored state&lt;/h3&gt;
&lt;p&gt;Once we have the initial state from localStorage, we can pass it to our &lt;code class=&quot;language-text&quot;&gt;App&lt;/code&gt; component and create the microstate with the passed in value.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; initial &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;family-tree&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; initial &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; person &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Person&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; initial&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FamilyTree&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;App&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;initial&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;initial&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;root&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will allow us to deserialize the value, but what about saving the value into localStorage? We’ll do that next, it’ll require that we use another hook.&lt;/p&gt;
&lt;h3 id=&quot;persist-the-state-in-localstorage&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#persist-the-state-in-localstorage&quot; aria-label=&quot;persist the state in localstorage permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Persist the state in localStorage&lt;/h3&gt;
&lt;p&gt;We want the state of the family tree to be saved in localStorage. To do this, we need to extract serializable state from the microstate. We can use &lt;code class=&quot;language-text&quot;&gt;valueOf&lt;/code&gt; function to get a value that we can store in localStorage.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; valueOf &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;microstates&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; initial &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; person &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Person&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; initial&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FamilyTree&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once we have the value from the microstate, we can use &lt;code class=&quot;language-text&quot;&gt;useEffect&lt;/code&gt; hook to queue up the &lt;code class=&quot;language-text&quot;&gt;localStorage.setItem&lt;/code&gt; operation. &lt;code class=&quot;language-text&quot;&gt;useEffect&lt;/code&gt; hook is executed after the render is complete, which allows you to perform potentially slow operation without slowing down rendering. It also allows you to prevent unnecessary invocations of this effect by declaring the value as a dependant value. Here is what that looks like,&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useEffect &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; valueOf &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;microstates&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; initial &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; person &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Person&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; initial&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; serialized &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;family-tree&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; serialized&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FamilyTree&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this section, we added the ability to store user’s input in localStorage to allow us to restore their input when the user returns to the page. We used &lt;code class=&quot;language-text&quot;&gt;valueOf&lt;/code&gt; to extract value from the microstate and &lt;code class=&quot;language-text&quot;&gt;useEffect&lt;/code&gt; hook to ensure that calling our persist operation does not block rendering. In the last part of this tutorial, we’ll optimize the component to ensure that it doesn’t re-renders parts of the tree where state did not change.&lt;/p&gt;
&lt;h2 id=&quot;optimize-re-rendering-of-our-component&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#optimize-re-rendering-of-our-component&quot; aria-label=&quot;optimize re rendering of our component permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Optimize re-rendering of our component&lt;/h2&gt;
&lt;p&gt;It’s not unusual for performance improvements to be left until the end of the project, but unusual for performance tweaking to be easy. Fortunately, Microstates was designed in a way that makes optimizing performance with React easy. In this section, I’ll show you how to optimize the component to ensure that only parts that changed actually re-render.&lt;/p&gt;
&lt;p&gt;The key to optimizing React rendering is to ensure that only components that changed get re-rendered. React Devtools has a feature called “Highlight Updates” that makes it easy to see which components get re-rendered when you interact with the application.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2018-11-06-build-a-family-tree-maker-using-react-hooks-and-microstates_family-builder-unoptimized.gif&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Demo of Family Builder Component before optimization&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;When “Highlight Updates” is turned on, the DevTools will highlight areas of the component tree that are being updated. If you look at the example above, you can see that every keystroke causes every component to re-render. This is a lot of unnecessary re-renders.&lt;/p&gt;
&lt;p&gt;What we need to do is to only re-render children when the state of children has changed. We can use the fact that Microstates are immutable as a guarantee that microstates will only change their references when their value has changed. If they value did not change, then the same microstate will be reused.&lt;/p&gt;
&lt;p&gt;We can combine this reference guarantee with the &lt;code class=&quot;language-text&quot;&gt;useMemo&lt;/code&gt; hook to memoize components based on the microstate that they consume. This will ensure that memoization will be invalidated when the dependant microstate changes. Let’s modify our component to memoize parent’s components based on their microstates.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FamilyTree&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; person &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; father &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useMemo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FamilyTree&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;father&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;father
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mother &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useMemo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;FamilyTree&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mother&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mother
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;onChange&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Father: &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;father&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Mother: &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;mother&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After we make this change, we can check the result and see if we made an improvement. Now when you edit an input field, it’s only changing components above the component that you edited because their microstates were changed.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2018-11-06-build-a-family-tree-maker-using-react-hooks-and-microstates_family-builder-optimized.gif&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Demo of Family Builder Components after optimizations&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;It’s worth noting that we only change the input in one component but all of the parent components are marked as changing. This is because when a nested microstate changes, the parents of that microstate have to be re-created as per rules of immutability.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, use used &lt;code class=&quot;language-text&quot;&gt;useType&lt;/code&gt; hoook to create a recursive component using Microstates, stored our state in localStorage and optimize re-rendering of our components.&lt;/p&gt;
&lt;p&gt;If you thought that this was easy, then consider how much we were able to do with Microsates and React in 80 lines of code. You can see the final result in &lt;a href=&quot;https://github.com/taras/microstates-use-state&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GitHub Repo&lt;/a&gt; and &lt;a href=&quot;http://codesandbox.io/s/github/taras/microstates-use-state&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;CodeSandbox&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you thought this was difficult, please &lt;a href=&quot;https://github.com/taras/microstates-use-state&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;file an issue&lt;/a&gt; and describe what you found difficult.&lt;/p&gt;
&lt;p&gt;Regardless, tweet me &lt;a href=&quot;http://twitter.com/tarasm&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@tarasm&lt;/a&gt; and let me know what you think about Microstates and &lt;code class=&quot;language-text&quot;&gt;useType&lt;/code&gt; hook. If you’re looking for help building large applications, consider hiring Frontside to help you build your app.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/7e5c20fcd943e76e94d77a4566eaa74d/4fe8c/2018-06-14-what-is-new-in-wcag-2-1_wcag-2-1-image.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Four reasons to use append() instead of Object.assign() and Object spread]]></title><description><![CDATA[Object.assign is just a special case of a universal concept in functional programming. By opting to use a universal function to back this universal concept, you can inherit all kinds of awesome for free.]]></description><link>https://frontside.com/blog/2018-09-18-four-reasons-to-use-append-instead-of-object-assign-and-object-spread/</link><guid isPermaLink="false">https://frontside.com/blog/2018-09-18-four-reasons-to-use-append-instead-of-object-assign-and-object-spread/</guid><category><![CDATA[javascript]]></category><category><![CDATA[functional-programming]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Tue, 18 Sep 2018 21:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Warning! This post was manufactured in a facility that also processes Monoids and may contain traces of functional programming.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&apos;d like to share with you what is easily one of my top 5 favorite discoveries in programing during the last year: The &lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; operation for JavaScript Objects. Before you go looking in the API docs: no, this is not part of the official ECMA Script specification. It&apos;s a pattern that I found on the internet and implemented in &lt;a href=&quot;https://github.com/cowboyd/funcadelic.js&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;funcadelic.js&lt;/a&gt;. You can use my implementation, or you can write your own, but either way, once you experience how much better &lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; tastes than its analogues in vanilla JavaScript, you&apos;ll have a really hard time going back.&lt;/p&gt;
&lt;p&gt;The TL;DR is that you can use &lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; anywhere that you would use &lt;code class=&quot;language-text&quot;&gt;Object.assign&lt;/code&gt; or the &lt;a href=&quot;https://redux.js.org/recipes/usingobjectspreadoperator&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;object spread operator&lt;/a&gt; except it&apos;s more awesome. How? Well I&apos;m glad you asked.&lt;/p&gt;
&lt;h3 id=&quot;append-is-immutable&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#append-is-immutable&quot; aria-label=&quot;append is immutable permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; is immutable.&lt;/h3&gt;
&lt;p&gt;It never changes any of its arguments, only ever creates new objects that are derived from the objects that you give it.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; ingredients &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;eggs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;mushrooms&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; { eggs: 2, mushrooms: 10 }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I&apos;ll not try to convince you of the benefits of immutability here, only say that as programmers, we truck in that most precious of resources: &lt;em&gt;information&lt;/em&gt;. Why willingly destroy it unless absolutely necessary?&lt;/p&gt;
&lt;p&gt;When you use &lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; instead of &lt;code class=&quot;language-text&quot;&gt;Object.assign&lt;/code&gt;, you&apos;ll never have to pay the overhead of that decision, or worse, accidentally mutate some object you never intended to.&lt;/p&gt;
&lt;h3 id=&quot;append-preserves-type&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#append-preserves-type&quot; aria-label=&quot;append preserves type permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; preserves type.&lt;/h3&gt;
&lt;p&gt;Every JavaScript object has a runtime type. This lets us define custom properties and operations on it. Unfortunately, if we&apos;re making an immutable transformation using &lt;code class=&quot;language-text&quot;&gt;Object.assign&lt;/code&gt; or Object spread, that type information is erased and no matter what we started out with we revert to a plain old JavaScript object.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;firstName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lastName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;firstName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; firstName&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lastName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; lastName&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;firstName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;lastName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; misspelled &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Tony&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Stork&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; corrected &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;misspelled&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Stark&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Object { firstName: &quot;Tony&quot;, lastName: &quot;Stark&quot; }&lt;/span&gt;

corrected&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fullName
&lt;span class=&quot;token comment&quot;&gt;//=&gt; undefined&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice how the fact that we&apos;re work working with a &lt;code class=&quot;language-text&quot;&gt;Person&lt;/code&gt; object is just thrown into the dumpster? By contrast, &lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; always preserves type of object that we were working with before.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; misspelled &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Tony&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Stork&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; corrected &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;misspelled&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Stark&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Person { firstName: &quot;Tony&quot;, lastName: &quot;Stark&quot; }&lt;/span&gt;
corrected&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fullName &lt;span class=&quot;token comment&quot;&gt;//=&gt; &quot;Tony Stark&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I mean you &lt;em&gt;could&lt;/em&gt; throw away the type by default, but why?&lt;/p&gt;
&lt;h3 id=&quot;append-is-lazy&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#append-is-lazy&quot; aria-label=&quot;append is lazy permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; is lazy&lt;/h3&gt;
&lt;p&gt;JavaScript has a really nice feature called &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;getters&lt;/a&gt; or &quot;computed properties&quot; that lets you defer evaluating a property&apos;s value until it&apos;s actually needed. This can be a great way to avoid computing a property if the dependencies required won&apos;t be available until later, or you&apos;d just rather not pay the cost of evaluation until you absolutely need to.&lt;/p&gt;
&lt;p&gt;Unfortunately, whatever your reasons, both &lt;code class=&quot;language-text&quot;&gt;Object.assign&lt;/code&gt; and Object spread will interfere with them because they eagerly evaluate each property of the objects being copied over into the result. For example, let&apos;s look at these two objects that have computed properties:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; left &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;thousand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;calculating 1000 in a really expensive way&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; right &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hundred&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;calculating 100 in a really expensive way&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let&apos;s see what happens when we combine them with Object spread:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; both &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;right&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [LOG] calculating 1000 in a really expensive way&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [LOG] calculating 100 in a really expensive way&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or how about &lt;code class=&quot;language-text&quot;&gt;Object.assign&lt;/code&gt;?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; both &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; right&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [LOG] calculating 1000 in a really expensive way&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [LOG] calculating 100 in a really expensive way&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But we made those properties lazy for a reason! Just because I&apos;m deriving a new object based off of those properties, doesn&apos;t mean I should have to evaluate them! Well with &lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; you don&apos;t. It will follow the guidelines laid down by each object&apos;s original creator and keep normal properties normal, and computed properties computed.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; both &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; right&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// nothing printed, because nothing evaluated!&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// only when we access the properties does the computation run.&lt;/span&gt;

both&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;thousand &lt;span class=&quot;token comment&quot;&gt;//=&gt; 1000&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [LOG] calculating 1000 in a really expensive way&lt;/span&gt;

both&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hundred &lt;span class=&quot;token comment&quot;&gt;//=&gt; 100&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [LOG] calculatingc 100 in a really expensive way&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;append-is-a-universal-interface&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#append-is-a-universal-interface&quot; aria-label=&quot;append is a universal interface permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; is a universal interface.&lt;/h3&gt;
&lt;p&gt;Remember when I said that I found &lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; on the internet? That was true, but it also wasn&apos;t the full story. What I &lt;em&gt;actually&lt;/em&gt; found on the internet was something far more powerful: the concept of a &lt;em&gt;semigroup&lt;/em&gt;. A semigroup is (roughly) a type; any two of whose values can be combined with each other to produce a new value of the same type. For example, JavaScript &lt;code class=&quot;language-text&quot;&gt;Array&lt;/code&gt; is a semigroup. I can combine or &quot;append&quot; any two &lt;code class=&quot;language-text&quot;&gt;Array&lt;/code&gt; objects together to produce a single new &lt;code class=&quot;language-text&quot;&gt;Array&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; [1, 2, 3, 4]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;JavaScript &lt;code class=&quot;language-text&quot;&gt;String&lt;/code&gt; is a semigroup too!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Hello&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos; World!&apos;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; Hello World&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This got me to thinking: what would a semigroup for object look like? What would it mean to take two &lt;code class=&quot;language-text&quot;&gt;Object&lt;/code&gt;s and combine them to produce another &lt;code class=&quot;language-text&quot;&gt;Object&lt;/code&gt;, and the &lt;code class=&quot;language-text&quot;&gt;append()&lt;/code&gt; function that I&apos;ve been talking about was the inevitable consequence:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Immutable&lt;/em&gt; because this is functional programming, and that&apos;s really just a given.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Type-preserving&lt;/em&gt;: because the append operation of Semigroup must return the same type as its arguments.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lazy&lt;/em&gt;: This isn&apos;t &lt;em&gt;strictly&lt;/em&gt; a requriment, but as long as we&apos;re building an amped up version of &lt;code class=&quot;language-text&quot;&gt;Object.assign&lt;/code&gt; we might as well respect object property semantics, no?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is all to say that using &lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; &lt;em&gt;normalizes&lt;/em&gt; this operation to a shared understanding of what a Semigroup is. And in fact, in funcadelic.js, the &lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; operation will work on all these types.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; [1, 2, 3, 4]&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Hello&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos; World!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; &apos;Hello World!&apos;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;eggs&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;bacon&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; { eggs: 2, bacon: 2 }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One concept, one function, lots and lots of different scenarios. And that&apos;s why I started using &lt;code class=&quot;language-text&quot;&gt;append&lt;/code&gt; and haven&apos;t looked back since.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/ffe8863c073fd4b2e4ba00507530a5db/2a4de/2018-09-18-four-reasons-to-use-append-instead-of-object-assign-and-object-spread_merge-sign.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Kubernetes for the Kubernewbie - The Journey]]></title><description><![CDATA[Learning Kubernetes, especially with no background in Ops, is challenging but full of reward. This will take you along the journey of our k8s enlightenment and deployment]]></description><link>https://frontside.com/blog/2018-08-09-kubernetes-for-the-kubernewbie/</link><guid isPermaLink="false">https://frontside.com/blog/2018-08-09-kubernetes-for-the-kubernewbie/</guid><category><![CDATA[kubernetes]]></category><category><![CDATA[devops]]></category><category><![CDATA[microservices]]></category><dc:creator><![CDATA[Elrick Ryan]]></dc:creator><pubDate>Thu, 09 Aug 2018 21:00:00 GMT</pubDate><content:encoded>&lt;p&gt;‘It’s not how you start it’s how you finish’, is a phrase you may hear a coach
utter to his team but it is surprisingly applicable in the Tech industry as
well. All of us were newbies at some point in time. We’ve all faced challenges
while trying to learn something new. However, reaching the end of the road to
proficiency requires you to push through those tough times and I am here to let
you know that it is possible even when entering Kubernetes (k8s) as a
Kubernewbie. My background prior this undertaking was Design and Development
(DevSigner), and not Ops. However, by the end of this journey I made the
transition and gained a new moniker, DevOpsSigner.&lt;/p&gt;
&lt;p&gt;Initially, this blog post was going to serve as a comprehensive intro to
Kubernetes but, after some thought (and a few rewrites), I realized that this
would not be possible in a single post. It was better to approach this post from
the angle of what this is not meant to be. This post is not a comprehensive
introduction to Kubernetes, nor is it a tutorial or even a guide. It is more
akin to a testimonial, a recap of our experience coming into Kubernetes and how
we went from Kubernewbies to a fully deployed production application in a
Kubernetes cluster in a few weeks.&lt;/p&gt;
&lt;p&gt;With no prior experience with Kubernetes or Devops it made the process of
learning and ramping up even more challenging. When entering a new domain, like
Devops, there is a load of domain specific knowledge (DSK) you do not possess
that others have acquired over time. That DSK is what you use to evaluate,
explore, build solutions and use technologies in that domain. Without it you
could go down a path of reinventing the wheel. Every domain has very complex
problems that people are trying to solve, have solved or are improving on.
Fortunately for us and you that solution maybe primed and applicable to the need
/ issue / requirement that you have. Kubernetes was that soltion for us.&lt;/p&gt;
&lt;p&gt;Kubernetes is a solution to a complex problem in its domain and by using
Kubernetes you cut a chunk of complexity in this initial DSK acquisition and can
start your Kubernewbie and Devops journey, ‘standing on the shoulders of
giants’. Kubernetes gifts you a system with a set of primitives, an API, and a
set of hooks to build and focus on things unique to your needs. Joe Beda said it
best in that ‘Kubernetes gives you a Platform to make a Platform’. We will talk
about how we used this ‘Platform Builder’ (Kubernetes) if you will, later, but
first let us define what Kubernetes is in general.&lt;/p&gt;
&lt;h2 id=&quot;what-is-kubernetes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-kubernetes&quot; aria-label=&quot;what is kubernetes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is Kubernetes?&lt;/h2&gt;
&lt;p&gt;Kubernetes.io introduces Kubernetes as “an open-source system for automating
deployment, scaling, and management of containerized applications.” Kubernetes
builds upon 15 years of experience of running production workloads at Google
which was influenced by Google’s internal systems Borg &amp;#x26; Omega. So what does
Google know about production workloads you ask? Well around 2015, Google was
spinning up approximately 2 billion containers per week. Yes, you read that
correctly, 2 billion per week. I don’t know about you, but I have not seen 2
billion of anything in even a year.&lt;/p&gt;
&lt;p&gt;So, it is fair to say that Google has a tremendous amount of experience
utilizing containers in production. Fortunately, some brave souls started to
open-source that expertise. Harnessing that experience, then Google employees Joe
Beda, Brendan Burns andCraig McLuckie took on the challenge. Brendan Burns
started the initial prototypes which, combined with work from Joe Beda and Craig
McLuckie, resulted in the first commit to the Kubernetes repo in 2014.&lt;/p&gt;
&lt;p&gt;Kubernetes was created to bring the idea of dynamic, container-centric, managed,
scheduled-cluster thinking outside of Google. With the exponential growth and
usage of containers globally, Kubernetes strives to give everyone a production
level solution fashioned from Google itself. There is no denying Google’s
experience with containers and containerized applications. But what is a
container and what does a containerized application mean in this context?&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-containerized-application&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-a-containerized-application&quot; aria-label=&quot;what is a containerized application permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is a containerized application?&lt;/h2&gt;
&lt;p&gt;For now, let’s say that a containerized application is an application that is
within a container. A container, by definition from Webster’s Dictionary, is “an
object that can be used to hold or transport something.” In relation to
technology, that “something” is everything that a piece of software needs to run
in a particular environment, such as application code, utilities, configuration
and dependencies. So a proposed Tech definition is: a container is an
abstraction: an Operating-system-level-virtualization that allows you to run an
application and its dependencies in resource-isolated processes.&lt;/p&gt;
&lt;p&gt;Diving even deeper into this tech definition, an Operating-system-level
virtualization, also known as containerization (containerized application),
refers to an operating system feature in which the kernel allows the existence
of multiple resource-isolated user-space instances. Those instances are the
containers that and share one Host Operating system across them. Since the
containers encapsulate everything an application needs to run this makes moving
and running the software in different environments possible. So with all these
definitions in hand, my final description of a container would be: a Container
is a isolated-resource that is used to transport everything an application needs
to run.&lt;/p&gt;
&lt;p&gt;That was an intense explanation of what a container is, but container technology
is a fundamental technology and a catalyst for the building of Kubernetes.
Kelsey Hightower said, “People will soon learn that containers only solve the
software packaging and distribution problem. Containers don&apos;t manage anything;
they need to be managed”. Kubernetes presents a management solution for
containers. Lets now assume you have some containers built and ready for use,
you can have anywhere from one to one-thousand of them to deploy -- and you’ll
need a way to deploy, manage and even scale the system using these containers.&lt;/p&gt;
&lt;p&gt;That was the position we found ourselves in with a new project that we were
hired to develop. We were hired to build a React application and a backend
application. The backend application was developed using Ruby, which would be a
Microservice / module living in an overall system of modules, powered by an
API-Gateway called Okapi. We needed our own production and sandbox environments
that were fully functional versions of the overall Microservice Architecture.
Having this would allow us rapid development and iteration on our module, a
place to demo all the new features we would be implementing, and a sandbox
location for experimentation. Since our module was going to be part of a larger
system made up of multiple modules/containers we needed a deployment and
management solution. Enter Kubernetes.&lt;/p&gt;
&lt;h2 id=&quot;why-did-we-need-and-settle-on-kubernetes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-did-we-need-and-settle-on-kubernetes&quot; aria-label=&quot;why did we need and settle on kubernetes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why did we need and settle on Kubernetes?&lt;/h2&gt;
&lt;p&gt;We researched a few options for a container management solution prior to
settling on Kubernetes. Many of which are capable of being a solution to
container management but ultimately we went with Kubernetes because of a few
things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Documentation. The Kubernetes documentation is extensive.&lt;/li&gt;
&lt;li&gt;Self Healing. An essential feature of Kubernetes is ‘self-healing’, the system
will always try to keep your cluster of deployed pods ( which hold containers)
running at the desired scale you define. Yes, you can ‘set it and forget it’
in Tech.&lt;/li&gt;
&lt;li&gt;Declarative. Kubernetes is a declarative system and uses files written in YAML
or JSON to define how you want the various parts of the system to look. There
are more advanced solutions, rather than hand rolling and editing multiple
YAML files, but these are used at the basic level.&lt;/li&gt;
&lt;li&gt;Community. There were several members from the Kubernetes community who were
extremely helpful and receptive to answering questions as we ramped up our
experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;managed-or-unmanaged-hosting&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#managed-or-unmanaged-hosting&quot; aria-label=&quot;managed or unmanaged hosting permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Managed or unmanaged hosting?&lt;/h3&gt;
&lt;p&gt;Now that we’d settled on using Kubernetes, we needed to decide on where to host
our Kubernetes clusters, and whether we wanted to go with a managed or unmanaged
Kubernetes hosting solution. A managed solution has Provisioning, Security, Load
Balancing, Upgrading, and Monitoring that is handled by them. An unmanaged
solution will require you to do more of the leg work to setup all the previously
mentioned points. However, not all managed Kubernetes hosting solutions are the
same, so we researched a few. One that was pretty awesome was Platform9, which
is a good turn key managed solution, but we ended up going with Google
Kubernetes Engine (previously Google Container Engine).&lt;/p&gt;
&lt;p&gt;Google Kubernetes Engine (GKE) is a managed solution that abstracts away the
aforementioned Provisioning, Security, Load Balancing, Upgrading, and Monitoring
of running a Kubernetes cluster, but not so much that you cannot configure (and
even swap) an alternate technology for one of those parts. However, staying as
close as you can in the GKE system and using all the features within GKE will
make your life much easier. Now that we’ve decided on using Kubernetes for
orchestration, and GKE as the managed solution for hosting the cluster, let’s
Ship it. Well, not so fast.&lt;/p&gt;
&lt;h2 id=&quot;tools-within-the-kubernetes-ecosystem-we-use-and-building-our-platform&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#tools-within-the-kubernetes-ecosystem-we-use-and-building-our-platform&quot; aria-label=&quot;tools within the kubernetes ecosystem we use and building our platform permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tools within the Kubernetes ecosystem we use and building our platform.&lt;/h2&gt;
&lt;p&gt;Before we actually shipped to GKE, we flexed our Kubernetes muscles and
experimented with Kubernetes using Minikube. The Minikube readme says that,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Minikube is a tool that makes it easy to run Kubernetes locally. Minikube runs&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;a single-node Kubernetes cluster inside a VM on your laptop for users looking to
try out Kubernetes or develop with it day-to-day,”.&lt;/p&gt;
&lt;p&gt;We used Minikube to initially test standing up and deploying all the modules.
Minikube allowed us to get familiar with certain parts of Kubernetes, known as
Resource Types such as Pods, Services, Replica Sets, Deployments, Config Maps
etc and go through some of the examples in the Kubernetes documentation and
around the web.&lt;/p&gt;
&lt;p&gt;During this k8s exploration period using MiniKube we became very familiar with
using another tool called &apos;kubectl&apos;. kubectl is a command-line interface (CLI)
for executing commands against a running Kubernetes cluster in this case the
running cluster was the single-node Minikube instance but could be any running
k8s cluster. kubectl has a laundry list of commands but our initial use was to
‘apply’ our YAML files and as time progress we started to use more of the
advanced commands of kubectl. One resource that I wish I had during this
exploration phase was a book called &lt;a href=&quot;https://twitter.com/kelseyhightower/status/738795057801625601?lang=en&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;‘Kubernetes Up and Running’&lt;/a&gt; which I read
later but would suggest it to anyone that is new to k8s. Despite not having the
book at the time this step was crucial to gaining a basic understanding of
Kubernetes and standing up a cluster before shipping the full ancolata to GKE,
which we did soon thereafter.&lt;/p&gt;
&lt;p&gt;We popped some champagne and celebrated the win of successfully standing up a
Kubernetes cluster with a fully functional API-Gateway and modules (including
our module). Our clusters were running great, but after a few weeks and having
to swap out and redeploy parts of it (and on occasion having to redeploy the
entire cluster), we needed to find a solution to automate the process of tearing
down and standing up our cluster. Again, we did some market research, but we
couldn’t find anything that would fit our needs at the time; so we ended up
building &lt;a href=&quot;https://github.com/thefrontside/folio-deployment&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Okubi&lt;/a&gt;, as mentioned earlier using the ‘Platform to build a Platform’.
Okubi gives us a command line interface for tearing down and standing up our
cluster.&lt;/p&gt;
&lt;p&gt;We use Okubi for things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Generating module YAML files from a template.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Changing configuration values foreach environment from a configuration file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setting priority level to modules.This will allow explicit ordering of when certain modules are deployed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Order the deployment of the certain parts of the system to the cluster.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run execution steps during the standup specific to this infrastructure.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Okubi is great, but it took hitting the pain points of doing all this manually
before we found a solution that worked for us and built an abstraction.
Definitely have to give a big shout out to &lt;a href=&quot;https://twitter.com/salsanotsalsa&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Joe
LaSala&lt;/a&gt; for all his hardwork in Okubi. We
have some enhancements that we will like to introduce within Okubi but currently
it is serving us well with cluster deployment. While having to redeploy modules
in the cluster or redeploy the cluster we often found ourselves debugging
containers.&lt;/p&gt;
&lt;h3 id=&quot;debugging-containers&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#debugging-containers&quot; aria-label=&quot;debugging containers permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Debugging Containers&lt;/h3&gt;
&lt;p&gt;To debug containers one method that we use was to tail the logs of the
container. Which essentially watches the logs and prints them to the terminal.
Though you can run a command in kubectl to tail the log of a container. We
started to use &lt;a href=&quot;https://github.com/wercker/stern&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Stern&lt;/a&gt; because of some added features. Stern simply describes
itself as Multi pod container log tailing for Kubernetes. This was a feature
that we used  along with tailing multiple containers within a Kubernetes “Pod”.
It maybe possible to do the same with kubectl but do not quote me. However,
using Stern made this task fairly simple with easy to remember CLI commands.&lt;/p&gt;
&lt;p&gt;Tailing logs is very useful but then we wondered if we could somehow interact
with the code while it was running in the cluster. Then we found &lt;a href=&quot;https://github.com/datawire/telepresence&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Telepresence&lt;/a&gt;.
Telepresence is an open source tool that lets you run a single service locally,
while connecting that service to a remote Kubernetes cluster. So, by using
Telepresence we were able to change the reality in your running cluster and
tests code locally as though our local code was running in the cluster. In
addition, we were able to find usage for Telepresence during active feature
development. Yes, this all sounds quite magical and it did to me as first so let
me try to explain how we used it.&lt;/p&gt;
&lt;p&gt;First, use case was when we saw some buggy behavior and wanted to debug that
code. We would then switch to our sandbox cluster context utilizing another tool
called Kubectx. Kubectx says it is a way to switch between clusters and
namespaces in kubectl and that is exactly right. Since our sandbox mirrors our
production cluster we would then Telepresence into the sandbox cluster and then
set debuggers within our local in order to step through the code during
execution. Once we found the offending code that was causing the bug we would
then create a PR with the fix.&lt;/p&gt;
&lt;p&gt;Second use-case as I mentioned earlier was the usage of Telepresence during
active feature development. This is one usage that came in handy for me several
times. Let’s say I was task with developing a feature in the module. That new
feature would then be consumed by the React frontend that I aforementioned React
application that we had underdevelopment as well. Now, call me crazy but even
though I have all these awesome testing tools at my disposal and full test
coverage around my code because we do not ship code without tests. I still want
to test it live. Hooray for Telepresence.&lt;/p&gt;
&lt;p&gt;I would follow the same steps of making sure I was in the correct sandbox
context and then Telepresence in that cluster. In addition, I would then spin up
the React application locally and make sure it was making it calls to the
sandbox URL. This would give me a live React, a Telepresenced Ruby Module and a
fully running Kubernetes cluster. I could manually test out what I was
developing and perform a full end to end test before I pushed to out a PR. I did
not use this all the time but on the occasions when I had to reach for this
technique it was worth its weight in Gold.&lt;/p&gt;
&lt;h2 id=&quot;in-closing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#in-closing&quot; aria-label=&quot;in closing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;In closing&lt;/h2&gt;
&lt;p&gt;Well, that is all that I have for this post. Honestly, I could keep writing but
this is supposed to be a blogPost and not a blogBook. So, I will keep the
additional topics for another blogPost. Overall, I would say that the journey
from a Kubernewbie was very challenging and extremely rewarding. You have to
push your limits and go into uncharted territory in order to grow. Have faith in
your abilities, ask questions and don’t get discouraged when you can’t figure
something out. There is still much to learn but that is nature of the Beast
which we call technology. If you have any question you can always hit me on
twitter at &lt;a href=&quot;https://twitter.com/elrickvm&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@elrickvm&lt;/a&gt; or &lt;a href=&quot;https://frontside.com/contact&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;send an
email&lt;/a&gt;. Be blessed and happy coding!&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/photos/Q4bmoSPJM18&quot;&gt;chuttersnap &lt;/a&gt; on
Unsplash.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#further-reading&quot; aria-label=&quot;further reading permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/img/2018/06/06/4-years-of-k8s/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Birth of Kuberentes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kubernetes documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youtu.be/9aPtucV0Ke0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kubernetes for the Kubernewbie: Frontside -- Lunch &amp;#x26;
Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/reference/kubectl/overview/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kubectl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/kelseyhightower/status/738795057801625601?lang=en&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Kubernetes up and running
(Book)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/wercker/stern&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Stern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/datawire/telepresence&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Telepresence&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[JSConf 2018 Recap]]></title><description><![CDATA[JSConfUS is back after a three-year hiatus and Robert had the chance to attend. He covers his favorite talks he saw while there!]]></description><link>https://frontside.com/blog/2018-08-05-jsconf-2018-recap/</link><guid isPermaLink="false">https://frontside.com/blog/2018-08-05-jsconf-2018-recap/</guid><category><![CDATA[conferences]]></category><category><![CDATA[jsconf]]></category><category><![CDATA[recap]]></category><dc:creator><![CDATA[Robert DeLuca]]></dc:creator><pubDate>Sun, 05 Aug 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;JSConfUS has officially made a come back after &lt;a href=&quot;http://lastcall.jsconf.us/about.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;a three-year
hiatus.&lt;/a&gt; I’d like to take this
moment to thank &lt;a href=&quot;https://twitter.com/voodootikigod&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Chris&lt;/a&gt; &amp;#x26; &lt;a href=&quot;https://twitter.com/lwilliams&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Laura
Williams&lt;/a&gt; for all of the work that they
put into building such an awesome &amp;#x26; welcoming community. I’d also like
to &lt;a href=&quot;https://2018.jsconf.us/team/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;thank the new organizers&lt;/a&gt; that
brought JSConfUS back! This year was exceptional, as you’d expect from
a JSConf!&lt;/p&gt;
&lt;p&gt;I had the pleasure to attend JSConf 2015 along with this most recent
JSConf. This year JSConfUS was held in sunny San Diego. I prefer the
resort in FL simply because there was direct beach access. Let’s be
honest, that’s a total nitpick. 😆&lt;/p&gt;
&lt;p&gt;One of the new twists to JSConf this year was the addition of a first
come, first speak format. This allowed anyone to sign up and give a
talk in Track B, &lt;a href=&quot;https://2018.jsconf.us/speakers/robert-deluca/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;which is exactly what I
did!&lt;/a&gt; I wasn’t
selected to be apart of the main track but that didn’t stop me from
giving my talk on &lt;a href=&quot;https://bigtestjs.io&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;BigTest.&lt;/a&gt;  I &lt;em&gt;love&lt;/em&gt; this idea
so much. There were a ton of interesting talks that came from Track B
&amp;#x26; it allowed some to speak for the first time.&lt;/p&gt;
&lt;h2 id=&quot;my-favorite-seven-talks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#my-favorite-seven-talks&quot; aria-label=&quot;my favorite seven talks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;My favorite seven talks&lt;/h2&gt;
&lt;p&gt;It would take me forever to recap each talk, so I’m going to narrow
the field down to my favorite seven. Turns out when all the talks are
good it makes it really hard to pick your favorite seven, but I’ll try
anyway!&lt;/p&gt;
&lt;h3 id=&quot;i-see-overcoming-challenges-in-software-development&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#i-see-overcoming-challenges-in-software-development&quot; aria-label=&quot;i see overcoming challenges in software development permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;I See: Overcoming Challenges In Software Development&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://2018.jsconf.us/speakers/kevin-oneil/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;By Kevin O’Neil&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this talk, Kevin covers all of the challenges he’s overcame to be a
front-end developer with a visual impairment. He covered a range of
challenges like finding a job in a city that had good public transit
since most jobs required him to be in office when he can’t drive. This
is ultimately why Kevin, a San Diego native, ended up in Tokyo!&lt;/p&gt;
&lt;p&gt;He also covered the challenges he faces when trying to do pixel
perfect front-end development and the different browser extensions &amp;#x26;
tools he uses to get the job done, which I found fascinating. Tools
like &lt;a href=&quot;https://teletype.atom.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Atoms Telatype&lt;/a&gt; allowed him to pair
with his coworkers without having to adjust a ton of settings.&lt;/p&gt;
&lt;p&gt;I had the pleasure of sitting at the same table with Kevin before and
after his talk. Once he was finished with his talk, one of the coolest
things happened. A PM from the Firefox dev tools team came over and
asked if there was anything they could do with their dev tools to help
improve Kevin’s development experience. Which got me thinking… We put
effort into making the experiences we’re building accessible but
rarely give thought to accessible developer experiences.&lt;/p&gt;
&lt;h3 id=&quot;es6-in-practice&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#es6-in-practice&quot; aria-label=&quot;es6 in practice permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;ES6 In Practice&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://2018.jsconf.us/speakers/tim-doherty/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;By Tim Doherty&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I wasn’t sure what to expect when I sat down to watch this talk. My
initial reaction was “I’ve been writing ES6 since 2015, what could I
take away from this?”. I’m happy I did attend and didn’t judge purely
from the title. Tim had a pretty awesome presenting style that I
enjoyed. It kept me engaged and entertained as we took a tour through
where ES6 came from, what actually made it into ES6, and what followed
in ES2016-18.&lt;/p&gt;
&lt;p&gt;This is a great refresher talk for anyone that has been using ES6 for
a while as well as a great intro talk for those who are still looking
to dip their toes into the new language features.&lt;/p&gt;
&lt;h3 id=&quot;please-dont-mock-me&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#please-dont-mock-me&quot; aria-label=&quot;please dont mock me permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Please Don’t Mock Me&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://2018.jsconf.us/speakers/justin-searls/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;By Justin Searls&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I had the chance to see this talk earlier in the year at &lt;a href=&quot;https://www.assertjs.com/schedule/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Assert
js&lt;/a&gt;, which blew me away. Justin is
an excellent conference speaker with a ton of experience. This talk
had something like 725 slides! I thought I had a ton at 250. This talk
was slightly different from the one he gave at Assert. The main
differences I can pick out are tweaked examples and a little more fine
tuning on the message.&lt;/p&gt;
&lt;p&gt;This talk was pretty damn awesome &amp;#x26; a ton of information was thrown
out there at a rapid pace. The main takeaway is: mocking in unit tests
is supposed to help shape the design of your program rather than
punching holes, in reality, to make it easier for you to test. It
helps you figure out when and where the right time to mock in your
unit tests.&lt;/p&gt;
&lt;p&gt;This might have been the best talk from JSConf, but it’s so hard to
declare that with all of the other amazing content. Lastly, I’m super
impressed with the closed captioning service at JSConf. They were able
to keep up with Justin and nailed it.&lt;/p&gt;
&lt;h3 id=&quot;adventures-in-ethical-computing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#adventures-in-ethical-computing&quot; aria-label=&quot;adventures in ethical computing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adventures In Ethical Computing&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://2018.jsconf.us/speakers/myles-borins/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;By Myles Borins&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This talk by Myles wasn’t technical but it was by far the most
thought-provoking one I saw. He covered different ways bias works its
way into the programs we write — whether we like it or not. We work
our own biases in when we create. It’s up to you to recognize your
bias and actively challenge them.&lt;/p&gt;
&lt;p&gt;Myles gave a couple of solid examples to demonstrate these biases. My
main takeaway from this talk is to always keep looking at and digging
into the data you have. Is it fully formed? Where is the inherent bias
in it? What can you do to challenge that and create a better data
model?&lt;/p&gt;
&lt;p&gt;This is one that you’ll want to watch once the video drops. 🔥&lt;/p&gt;
&lt;h3 id=&quot;exploring-webusb-and-its-exciting-potential&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#exploring-webusb-and-its-exciting-potential&quot; aria-label=&quot;exploring webusb and its exciting potential permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Exploring WebUSB And Its Exciting Potential&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://2018.jsconf.us/speakers/suz-hinton/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;By Suz Hinton&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As a part-time IOT nerd who is always looking for ways to automate my
house, this talk from Suz was a lot of fun and super informative. Also
big kudos to her for coming straight off a vacation and filling a
speaker role that opened up in a weeks time. 👏🏼&lt;/p&gt;
&lt;p&gt;Suz covered how the browser &lt;em&gt;used&lt;/em&gt; to interact with physical devices
connected via USB, what changed, and what’s coming down the pike. She
had a live demo on stage, which is gutsy! But totally worth it because
it was neat to see a full end-to-end demo. She plugged in an Arduino,
allowed the browser to connect to the device,  drew a message in the
browser, and then sent it to the Arduino.&lt;/p&gt;
&lt;p&gt;If you have any interest in IOT &amp;#x26; controlling those devices visa USB
through the browser, this talk is for you!&lt;/p&gt;
&lt;h3 id=&quot;a-quest-to-be-a-webmaster-how-do-you-go-from-simple-code-to-building-great-web-experience&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-quest-to-be-a-webmaster-how-do-you-go-from-simple-code-to-building-great-web-experience&quot; aria-label=&quot;a quest to be a webmaster how do you go from simple code to building great web experience permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A Quest To Be A (Web)Master: How Do You Go From Simple Code To Building Great Web Experience?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://2018.jsconf.us/speakers/mariko-kosaka/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;By Mariko Kosaka&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The best way I can sum up this amazing talk from Mariko is it covers
all of the things Google engineers have been yelling at me for. But
she did it in an awesomely informative way. I learned so much about
how the browser works.&lt;/p&gt;
&lt;p&gt;Her slides and diagrams explaining how the browser offloads different
process to the GPU or other threads were SUPER helpful. If you’re
struggling with getting silky smooth 60fps animations without page
jank, I highly recommend checking this talk out. It made a murky
picture pretty clear for me!&lt;/p&gt;
&lt;h3 id=&quot;discovering-the-true-identity-of-horse_js-using-machine-learning&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#discovering-the-true-identity-of-horse_js-using-machine-learning&quot; aria-label=&quot;discovering the true identity of horse_js using machine learning permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Discovering The True Identity Of @Horse_JS Using Machine Learning&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://2018.jsconf.us/speakers/burke-holland-and-jasmine-greenway/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;By Burke Holland and Jasmine Greenway&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This was probably the most fun talk at JSConf and they saved it for
last! Burke &amp;#x26; Jasmine detailed their experience trying to parse
&lt;code class=&quot;language-text&quot;&gt;@horse_js&lt;/code&gt;’s tweets to figure out who &lt;code class=&quot;language-text&quot;&gt;@horse_js&lt;/code&gt; really is.&lt;/p&gt;
&lt;p&gt;Turns out they weren’t really able to use machine learning too much to
help them with this, but they did learn a lot about different data
crunching techniques. There were a lot of hilarious jokes &amp;#x26; puns
sprinkled throughout the talk, which made it great to end the conf
on.&lt;/p&gt;
&lt;p&gt;They ended up narrowing horse down to 4 different possible people (who
were never exposed, for good reasons!). One in ATX and three in
NYC. Am I horse JS? 🤔 They never said who it was… the mystery will
never be solved!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;JSConfUS 2018 was amazing as all other JSConfs usually are. The new
organizers did a great job making sure everyone felt welcomed and were
super responsive to any questions I had. It was one of those
conferences where the organization was done so well it fell away and
was out of sight.&lt;/p&gt;
&lt;p&gt;I tried my best to narrow my favorite talks down, but let’s be honest,
all of the talks were amazing. If you have spare time when the videos
come out I recommend watching all of them. They were diverse and full
of super interesting information!&lt;/p&gt;
&lt;p&gt;I can’t wait for JSConfUS 2019! My checkbook is waiting…&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/768f5ea464ec55e98c7ff645e57f69d7/4fe8c/2018-09-04-jsconf-2018-recap_js-conf-recap.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[WCAG 2.1: What does it actually mean?]]></title><description><![CDATA[WCAG 2.1 has officially been put in place as a standard but what does that mean? What was added? How does this impact my site or app? In this post we break down everything new in WCAG 2.1 and put in simple terms so you can walk away armed with the knowledge of making your site more accessibile.]]></description><link>https://frontside.com/blog/2018-07-14-what-is-new-in-wcag-2-1/</link><guid isPermaLink="false">https://frontside.com/blog/2018-07-14-what-is-new-in-wcag-2-1/</guid><category><![CDATA[accessibility]]></category><category><![CDATA[web standards]]></category><dc:creator><![CDATA[Robert DeLuca]]></dc:creator><pubDate>Sat, 14 Jul 2018 16:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Publication as a W3C Recommendation finalizes the development process and indicates that the W3C considers the updated guidelines ready for implementation on web content.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Last week WCAG 2.1 (Web Content Accessibility Guidelines)&lt;/a&gt; was recommended by the W3C, which means they have finished it and it’s ready for everyone to start implementing.&lt;/p&gt;
&lt;p&gt;WCAG 2.0 was completed in 2008, back when touch devices were not as popular and tablets didn&apos;t exist yet. Since 2008 these devices have become the most prevalent way to access the web, but there were no success criteria that addressed accessibility for this input type.  That is the main theme of WCAG 2.1: take into account touch devices.  There are also a lot of new success criteria that address cognitive limitations too.&lt;/p&gt;
&lt;p&gt;Within WCAG there are three levels to conform to: A, AA, and AAA. Level A is the lowest bar of conformance and level AAA is the highest. These WCAG levels cascade, so if your app conforms to WCAG AA, it also conforms to WCAG A. Most companies shoot for AA since AAA has success criteria that are a little hard to reach and not all content can conform to AAA.&lt;/p&gt;
&lt;p&gt;In WCAG 2.1 there are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;5 new A success criteria&lt;/li&gt;
&lt;li&gt;7 new AA success criteria&lt;/li&gt;
&lt;li&gt;5 new AAA success criteria&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&apos;s go over all &lt;a href=&quot;https://www.w3.org/TR/WCAG21/#new-features-in-wcag-2-1&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;17 new success criteria&lt;/a&gt; to see what they are meant to solve and what it means for you. If you read the details for each of those success criteria some of them are straightforward and others aren’t. So I’m going to give &lt;em&gt;my&lt;/em&gt; TL;DR version of the success criteria.&lt;/p&gt;
&lt;h2 id=&quot;level-a&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#level-a&quot; aria-label=&quot;level a permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Level A&lt;/h2&gt;
&lt;p&gt;There are five new success criteria for level A, which is the lowest level of conformance you can achieve (aka the easiest). The new success criteria are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#character-key-shortcuts&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.1.4 Character Key Shortcuts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#pointer-gestures&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.5.1 Pointer Gestures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#pointer-cancellation&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.5.2 Pointer Cancellation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#label-in-name&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.5.3 Label in Name&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#motion-actuation&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.5.4 Motion Actuation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;214-character-key-shortcuts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#214-character-key-shortcuts&quot; aria-label=&quot;214 character key shortcuts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.1.4 Character Key Shortcuts&lt;/h3&gt;
&lt;p&gt;Assistive tech users have a lot of their own key combos for navigating and interaction. This success criterion is to ensure you don’t implement keyboard shortcuts that would prevent their functionality.&lt;/p&gt;
&lt;p&gt;If you have any custom keyboard shortcuts implemented, &lt;strong&gt;one&lt;/strong&gt; of the following need to be true:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The ability to turn off the shortcut&lt;/li&gt;
&lt;li&gt;The ability to remap the shortcut to something different&lt;/li&gt;
&lt;li&gt;The keyboard shortcut is only present if the component is focused&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/character-key-shortcuts.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;251-pointer-gestures&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#251-pointer-gestures&quot; aria-label=&quot;251 pointer gestures permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.5.1 Pointer Gestures&lt;/h3&gt;
&lt;p&gt;Since the last WCAG spec release there has been a lot of innovation on the web regarding touch devices. For example, with Google Maps you can use multi-touch gestures to pinch and zoom around the map.&lt;/p&gt;
&lt;p&gt;This success criterions says if there are multi-touch or slide gestures present, there must be a single input method also available.  To keep with the maps example, there should be &lt;code class=&quot;language-text&quot;&gt;+&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;-&lt;/code&gt; buttons available to provide non-pointer gesture interactions for this success criterion to pass.&lt;/p&gt;
&lt;p&gt;If the gesture is “essential” you may not need to worry about this one. They define “essential” as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If removed, would fundamentally change the information or functionality of the content, and information and functionality cannot be achieved in another way that would conform&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/pointer-gestures.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;252-pointer-cancellation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#252-pointer-cancellation&quot; aria-label=&quot;252 pointer cancellation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.5.2 Pointer Cancellation&lt;/h3&gt;
&lt;p&gt;For interactions that can be done with a single pointer (clicks, single taps, long presses, etc.), you must provide a way to cancel it. &lt;strong&gt;One&lt;/strong&gt; of the following must be true:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Don’t use the &lt;code class=&quot;language-text&quot;&gt;down&lt;/code&gt; event (&lt;code class=&quot;language-text&quot;&gt;touchstart&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;mousedown&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;You have a way to undo the action&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;language-text&quot;&gt;up&lt;/code&gt; event cancels the &lt;code class=&quot;language-text&quot;&gt;down&lt;/code&gt; event (this is like clicking a link, moving your cursor, and releasing)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/pointer-cancellation.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;253-label-in-name&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#253-label-in-name&quot; aria-label=&quot;253 label in name permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.5.3 Label in Name&lt;/h3&gt;
&lt;p&gt;Say you have an input with the visible label as “Name” and an &lt;code class=&quot;language-text&quot;&gt;aria-label&lt;/code&gt; as “Enter First Name”, this success criterion would fail.  This is because speech input users navigate by saying the visible label. If the visible label doesn’t match the programmatic name (or accessible name) it will fail to navigate.&lt;/p&gt;
&lt;p&gt;To drill it home with code, here’s two examples:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Bad --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;First Name&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Enter your first name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Good --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;First Name&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/label-in-name.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;254-motion-actuation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#254-motion-actuation&quot; aria-label=&quot;254 motion actuation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.5.4: Motion Actuation&lt;/h3&gt;
&lt;p&gt;If you have an action that is triggered by motion, there must be a control on screen that performs the same action. For example, if you shake the device to undo text in an input, there should be a clear button available for single pointer devices to activate.&lt;/p&gt;
&lt;p&gt;Another example would be images you interact with by tilting your phone around. There should be buttons available that pan / tilt the picture too.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/motion-actuation.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;level-aa&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#level-aa&quot; aria-label=&quot;level aa permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Level AA&lt;/h2&gt;
&lt;p&gt;There are seven new success criteria for level AA, which is the mid-level conformance you can achieve. The new success criteria are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#orientation&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;1.3.4 Orientation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#identify-input-purpose&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;1.3.5 Identify Input Purpose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#reflow&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;1.4.10 Reflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#non-text-contrast&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;1.4.11 Non-Text Contrast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#text-spacing&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;1.4.12 Text Spacing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#content-on-hover-or-focus&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;1.4.13 Content on Hover or Focus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#status-messages&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;4.1.3 Status Messages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;134-orientation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#134-orientation&quot; aria-label=&quot;134 orientation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1.3.4 Orientation&lt;/h3&gt;
&lt;p&gt;Your site or app should work in either orientation: landscape and portrait. Unless it’s deemed to be “essential” to the function of your app:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Examples where a particular display orientation may be essential are a bank check, a piano application, slides for a projector or television, or virtual reality content where binary display orientation is not applicable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/orientation.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;135-identify-input-purpose&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#135-identify-input-purpose&quot; aria-label=&quot;135 identify input purpose permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1.3.5 Identify Input Purpose&lt;/h3&gt;
&lt;p&gt;The inputs on your page should fill in metadata to help the user better understand the intention of the form inputs. You can do this by adding &lt;a href=&quot;https://www.w3.org/TR/html52/sec-forms.html#sec-autofill&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;autocomplete&lt;/code&gt; attributes to your inputs.&lt;/a&gt; This is a &lt;a href=&quot;https://www.w3.org/TR/WCAG21/#input-purposes&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;full list of input purposes.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/identify-input-purpose.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;1410-reflow&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1410-reflow&quot; aria-label=&quot;1410 reflow permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1.4.10 Reflow&lt;/h3&gt;
&lt;p&gt;This might be my favorite new success criterion! It essentially means your site or app should be responsive. If you can’t make your site or app responsive an alternative could be providing a fixed &lt;code class=&quot;language-text&quot;&gt;320px&lt;/code&gt;width version.&lt;/p&gt;
&lt;p&gt;The explainer document linked below goes into &lt;em&gt;great&lt;/em&gt; detail about why this decision was made and is a great resource for understanding how to pass this success criterion. I recommend reading through this one!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/reflow.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;1411-non-text-contrast&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1411-non-text-contrast&quot; aria-label=&quot;1411 non text contrast permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1.4.11 Non-Text Contrast&lt;/h3&gt;
&lt;p&gt;UI components and meaningful graphics must have a color contrast ratio of 3:1 to adjacent elements. This includes all states UI components can have (except the disabled state, &lt;a href=&quot;https://twitter.com/robdel12/status/1005108800465068034&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;which is confusing to me&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For example, a button’s hover, active, and focus states must all pass the 3:1 color contrast ratio. This does not apply to inactive elements (like a disabled button).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;1412-text-spacing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1412-text-spacing&quot; aria-label=&quot;1412 text spacing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1.4.12 Text Spacing&lt;/h3&gt;
&lt;p&gt;Content on your site or app must be able to &lt;em&gt;expand&lt;/em&gt; to the following requirements without any loss of content or functionality:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Line height (line spacing) to at least 1.5 times the font size&lt;/li&gt;
&lt;li&gt;Spacing following paragraphs to at least 2 times the font size&lt;/li&gt;
&lt;li&gt;Letter spacing (tracking) to at least 0.12 times the font size&lt;/li&gt;
&lt;li&gt;Word spacing to at least 0.16 times the font size&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That does &lt;em&gt;not&lt;/em&gt; mean that your site or app has to implement the above requirements as a baseline. But it should be able to scale to those requirements without losing functionality or readability.&lt;/p&gt;
&lt;p&gt;This success criterion helps those who have low vision or dyslexia since they may override the default content styles to help reduce confusion while reading.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/text-spacing.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;1413-content-on-hover-or-focus&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1413-content-on-hover-or-focus&quot; aria-label=&quot;1413 content on hover or focus permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1.4.13 Content on Hover or Focus&lt;/h3&gt;
&lt;p&gt;Any content that shows or hides from hover or focus needs to be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dismissable: a way to dismiss the content without moving the pointer or keyboard focus.&lt;/li&gt;
&lt;li&gt;Hoverable: the shown content should be able to be hovered and not dismiss.&lt;/li&gt;
&lt;li&gt;Persistent: the shown content remains visible until the &lt;strong&gt;user&lt;/strong&gt; dismisses, focus trigger is removed, or the information is no longer valid.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key takeaway here is if you have content that appears due to an action, the user must have control over that content being shown or hidden. It can’t disappear without a explicit dismiss action from the user.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;413-status-messages&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#413-status-messages&quot; aria-label=&quot;413 status messages permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;4.1.3 Status Messages&lt;/h3&gt;
&lt;p&gt;The main focus of this success criterion is for screen reader users. When there is a change in content that does not change focus you should provide a status message to the screen reader. This is commonly known as the announcer pattern. I’ve written an &lt;a href=&quot;https://github.com/ember-a11y/a11y-announcer&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ember addon for this&lt;/a&gt; and there is a &lt;a href=&quot;https://github.com/AlmeroSteyn/react-aria-live&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;react component that does this&lt;/a&gt; too.&lt;/p&gt;
&lt;p&gt;An example of this might be when an error on a form is displayed in a banner it should also announce that message to the screen reader through &lt;code class=&quot;language-text&quot;&gt;aria-live&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;role=“alert”&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Pro-tip: be careful when implementing this in your site or app. It’s &lt;em&gt;very&lt;/em&gt; easy to get multiple announcers on the page that could announce over each other at any given time. I recommend having &lt;strong&gt;one&lt;/strong&gt; announcer component that serves the entire application. That way there can only be one announcement at a given time.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/status-messages.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;level-aaa&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#level-aaa&quot; aria-label=&quot;level aaa permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Level AAA&lt;/h2&gt;
&lt;p&gt;There are five new success criteria for level AAA, which is the highest conformance you can achieve. The new success criteria are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#identify-purpose&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;1.3.6 Identify Purpose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#re-authenticating&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.2.5 Re-authenticating&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#timeouts&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.2.6 Timeouts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#animation-from-interactions&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.3.3 Animation from Interactions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#target-size&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.5.5 Target Size&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/#concurrent-input-mechanisms&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.5.6 Concurrent Input Mechanisms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Level AAA is the least common level of conformance but I still think there are success criteria here that should be implemented. Things like re-auth, timeouts, and target size aren’t that hard to implement and probably are already implemented in your app since these are solid UX patterns.&lt;/p&gt;
&lt;h3 id=&quot;136-identify-purpose&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#136-identify-purpose&quot; aria-label=&quot;136 identify purpose permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1.3.6 Identify Purpose&lt;/h3&gt;
&lt;p&gt;This success criterion looks hard to implement properly. The intent is for your site or app to support personalization and preferences. Here are the examples they give in the understanding document:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A website uses ARIA landmarks to identify the regions of the page, and users can hide areas that are not the &apos;main&apos;.&lt;/li&gt;
&lt;li&gt;The links in the navigation of a website are marked-up so that users can add their own icons.&lt;/li&gt;
&lt;li&gt;Icons on a website use are marked-up so that the user can substitute their own icon set into the page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can see how this one might be pretty hard to do right.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/identify-purpose.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;225-re-authenticating&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#225-re-authenticating&quot; aria-label=&quot;225 re authenticating permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.2.5 Re-authenticating&lt;/h3&gt;
&lt;p&gt;When an authenticated session expires, the user can continue the activity without loss of data after re-authenticating.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/re-authenticating.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;226-timeouts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#226-timeouts&quot; aria-label=&quot;226 timeouts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.2.6 Timeouts&lt;/h3&gt;
&lt;p&gt;If there is a timeout present on the page, there should be a warning shown before the session ends. You should provide a warning for anything that might cause data loss due to the session ending.&lt;/p&gt;
&lt;p&gt;These are usually implemented with a modal that pops up warning you that time is running out. Make sure that modal is accessibile too!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/timeouts.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;233-animation-from-interactions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#233-animation-from-interactions&quot; aria-label=&quot;233 animation from interactions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.3.3 Animation from Interactions&lt;/h3&gt;
&lt;p&gt;If you have animations on your site the user should able to be disable them. Unless they are essential. What WCAG defines as an “essential” animation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A web application provides a feature to author animated sequences. As part of this tool, the author needs to preview the animation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/animation-from-interactions.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;255-target-size&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#255-target-size&quot; aria-label=&quot;255 target size permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.5.5 Target Size&lt;/h3&gt;
&lt;p&gt;The target size of pointer inputs (mouse, pen, touch contact) should be a minimum &lt;code class=&quot;language-text&quot;&gt;44px&lt;/code&gt; by &lt;code class=&quot;language-text&quot;&gt;44px&lt;/code&gt; &lt;strong&gt;unless&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Equivalent: there is another target on the same page that provides the same action that meets this success criterion.&lt;/li&gt;
&lt;li&gt;Inline: the target is in a sentence or block of text&lt;/li&gt;
&lt;li&gt;User Agent Control: the size of the target is controlled by the user agent &amp;#x26; is not modified.&lt;/li&gt;
&lt;li&gt;Essential: the specific presentation is &lt;em&gt;required&lt;/em&gt; for the target to function.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/target-size.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;256-concurrent-input-mechanisms&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#256-concurrent-input-mechanisms&quot; aria-label=&quot;256 concurrent input mechanisms permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2.5.6 Concurrent Input Mechanisms&lt;/h3&gt;
&lt;p&gt;I really like this addition to WCAG. This success criterion says you should make sure your content can be interacted with through different modes of input.&lt;/p&gt;
&lt;p&gt;The easiest example to give would be making sure your site or app works if someone pairs a wireless keyboard to their phone to navigate. Another example would be making sure your site can be interacted with from a laptop with a touchscreen. &lt;a href=&quot;https://twitter.com/appsforartists/status/1005597722370564096&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;This exact example came up on Twitter over the weekend too!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I like this one because my mom is 100% blind and uses her iPhone with a keyboard a lot of the time. It’s just easier than swiping sometimes.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/concurrent-input-mechanisms.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;You can read the reasoning for it and &lt;em&gt;many&lt;/em&gt; more details here.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#wrap-up&quot; aria-label=&quot;wrap up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wrap up&lt;/h2&gt;
&lt;p&gt;Whew! That was a lot to unpack. One of the biggest struggles I had when getting started in accessibility was finding resources that digested the WCAG spec into more concrete examples. Jumping right into specifications as a first step can be daunting. With that said I hope this post was enough for you to get familiar with the changes to WCAG and what they mean in simple terms.&lt;/p&gt;
&lt;p&gt;I think it is worthwhile for you to spend some time reading through a couple of the documents that explain the reasoning for these success criteria. One of the realizations I’ve had when reading through the spec is WCAG is a set of guidelines for improving your site’s UX. Accessibility really is all about making sure your site or app can be used by &lt;em&gt;anyone&lt;/em&gt;, which serves as an excellent foundation to build upon for your site’s UX.&lt;/p&gt;
&lt;p&gt;If you or your team need any help getting up to speed with WCAG 2.1 &lt;a href=&quot;https://frontside.com/contact&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;reach out to us!&lt;/a&gt; If you would like to ask any questions or continue this conversation feel free to &lt;a href=&quot;https://twitter.com/robdel12&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;reach out to me on Twitter&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/7e5c20fcd943e76e94d77a4566eaa74d/4fe8c/2018-06-14-what-is-new-in-wcag-2-1_wcag-2-1-image.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Functional Rephrasing Using an Async Function Functor]]></title><description><![CDATA[Once you know that they're there, Functors pop up in all kinds of surprising places. Here we take a simple exploration of how the JavaScript async function construct is actually a Functor and how we can use that for great good.]]></description><link>https://frontside.com/blog/2018-07-03-functional-rephrasing-using-an-async-function-functor/</link><guid isPermaLink="false">https://frontside.com/blog/2018-07-03-functional-rephrasing-using-an-async-function-functor/</guid><category><![CDATA[functional-programming]]></category><category><![CDATA[functor]]></category><category><![CDATA[funcadelic]]></category><category><![CDATA[TIL]]></category><category><![CDATA[javascript]]></category><category><![CDATA[typeclasses]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Tue, 03 Jul 2018 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of my favorite things about the &lt;a href=&quot;https://frontside.com/img/2018/02/19/math-is-just-another-framework.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;the math framework&lt;/a&gt; is that it
helps you look for (and also find) patterns of composability around
you in your programming world. At the time I wrote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As you start to perceive the common nature in things like Promise, Array, and Observable, you begin to re-perceive all of the objects in your world through this new prism. You ask yourself “Is this a Functor?” and you’re shocked by how often the answer is yes. Plain JS Object? Yes. DOM Element? Yes. Express middleware? Yes. React Component? Also yes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It turns out that Functors are everywhere, and armed with
&lt;a href=&quot;https://github.com/cowboyd/funcadelic.js&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;funcadelic.js&lt;/a&gt; at your side, you stand ready to harness their power. In
fact, just yesterday I found just such a one: The JavaScript
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;AsyncFunction&lt;/code&gt;&lt;/a&gt;. And today, I&apos;m going to show you how we can use the
fine fact that async functions are Functors in order to refactor some
code to be more composable. In other words, we&apos;ll functionally
rephrase it as a Functor.&lt;/p&gt;
&lt;p&gt;Let&apos;s say we have an async function that fetches a url for us:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now we want to assemble a data transformation pipeline around
it. For argument&apos;s sake, let&apos;s say our process will look like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;-&gt; get the data
-&gt; parse as JSON
-&gt; normalize the keys in the resulting json
-&gt; look up the canonical model in a local data store.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As a first pass, we could write a transform function that takes the
url and applies each of these steps.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; normalizedKeys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeKeys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; model &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lookup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;normalizedKeys&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And if we wanted to stop there, life would go on. However, we could
also declare that &lt;code class=&quot;language-text&quot;&gt;AsyncFunction&lt;/code&gt; is a Functor and leverage the
flexibility that it provides. Here is the definition of the Functor
instance for async functions.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Functor &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;funcadelic&apos;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// AsyncFunction is not currently a global object. :/&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; AsyncFunction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;constructor

Functor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;AsyncFunction&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; asyncFn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;asyncFn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What this says is: whenever you map a function &lt;code class=&quot;language-text&quot;&gt;fn&lt;/code&gt; over an async
function, what you get is a &lt;em&gt;new&lt;/em&gt; async function that just invokes the
old async function, awaits its return value, and then applies &lt;code class=&quot;language-text&quot;&gt;fn&lt;/code&gt; to
it before returning.&lt;/p&gt;
&lt;p&gt;Using the &lt;a href=&quot;https://github.com/cowboyd/funcadelic.js#chaining-api&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;funcadelic chaining syntax&lt;/a&gt; this let&apos;s us define the
&lt;code class=&quot;language-text&quot;&gt;transform&lt;/code&gt; method, not as a monolithic function, but as the
combination of a bunch of smaller functions.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; chain &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; $ &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;funcadelic&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transform &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nomalizeKeys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;normalized&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lookup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;normalized&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We start with the first async function &lt;code class=&quot;language-text&quot;&gt;get&lt;/code&gt;, and then map a plain function
over it that takes the response and returns its text. The result of
that is an async function over which we can then map a plain function
that just parses the JSON. The result of that is another async
function over which we can map key normalization, and so on....&lt;/p&gt;
&lt;p&gt;Just as when we declared it explicitly, &lt;code class=&quot;language-text&quot;&gt;transform&lt;/code&gt; is an async
function because the result of mapping an async function &lt;em&gt;always
returns another async function&lt;/em&gt;. That&apos;s &lt;a href=&quot;https://github.com/cowboyd/funcadelic.js#functor&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;just how Functors work&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Notice also that for our mapping functions that just invoke single argument
functions, we can even leave out the arguments:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transform &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nomalizeKeys&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lookup&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which ever style you choose, the neat thing is that we&apos;re building up
an async function out of a bunch of regular plain-old JavaScript
functions with nothing async about them. This gives us a lot of
flexibility if, for example, we want to &lt;em&gt;add a step to the
pipline&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Let&apos;s say that we want to add a de-duping function in
between the key normalization and the lookup from the data store. All
we have to do is insert it into our pipeline.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transform &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nomalizeKeys&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dedupe&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lookup&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pretty neat! But there&apos;s one more thing I have to show you, and I
think you&apos;re going to like it..&lt;/p&gt;
&lt;p&gt;We can use the Functor law which basically says that you can either
map each function individually, or you can compose them all together
and map that function once. In other words:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; map &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;funcadelic&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; pipe &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ramda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; pipline &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token parameter&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parse&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  normalizeKeys&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  dedupe&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  lookup
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transform &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pipeline&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; get&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is all not to say that there&apos;s a single way to do it. Far from
it! But with the AsyncFunction Functor in your pocket, you&apos;ve got options on your side!&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/photos/Opit9xvZDP0?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Jason Blackeye&lt;/a&gt; on &lt;a href=&quot;/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/5c83db51eae5499a9c56557f45581b9a/4fe8c/2018-07-03-functional-rephrasing-using-an-async-function-functor_starry-night.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Big Testing in React]]></title><description><![CDATA[When we write and develop our applications, it's with the intent that somebody will use it. We write tests so we can be assured that everything in our app works as expected and is bug free. But how confident are you in your tests?]]></description><link>https://frontside.com/blog/2018-06-13-big-testing-in-react/</link><guid isPermaLink="false">https://frontside.com/blog/2018-06-13-big-testing-in-react/</guid><category><![CDATA[react]]></category><category><![CDATA[open source]]></category><category><![CDATA[bigtest]]></category><category><![CDATA[testing]]></category><dc:creator><![CDATA[Wil Wilsman]]></dc:creator><pubDate>Wed, 13 Jun 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;does-my-application-work-in-real-life&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#does-my-application-work-in-real-life&quot; aria-label=&quot;does my application work in real life permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Does my application work in real life?&lt;/h2&gt;
&lt;p&gt;This is a big question, and big questions need big answers. How &lt;em&gt;do&lt;/em&gt;
we answer that question, though? With &lt;strong&gt;big tests&lt;/strong&gt;. When we write and
develop our applications, it&apos;s with the intent that somebody will use
it. We write tests so we can be assured that everything in our app
works as expected and is bug free. But how confident are you in your
tests?&lt;/p&gt;
&lt;p&gt;A real person using your app is going to use a real browser; do your
tests test your app in a real browser? And not everybody uses the same
browser; do your tests test your app across multiple, different
browsers and devices? What about the network? Chances are your app
talks to the network, and your tests should account for this too,
right? Not to mention a person isn&apos;t going to interact with your app
on a component level. They&apos;re consuming &lt;em&gt;the entire app&lt;/em&gt; , using all
of it together. All of your components working with each other to
create an &lt;em&gt;experience&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If your tests don&apos;t test the app in the same way a person would use
it, how confident can you really be in them?&lt;/p&gt;
&lt;p&gt;Where do we even begin to test our apps like this? There are tools
like &lt;a href=&quot;https://facebook.github.io/jest/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Jest&lt;/a&gt;, but those tests don&apos;t
run in a real browser. There&apos;s also &lt;a href=&quot;https://cypress.io&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Cypress&lt;/a&gt;, but
as of this writing, you currently &lt;a href=&quot;https://github.com/cypress-io/cypress/issues/310&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;can&apos;t use it outside of
Chrome&lt;/a&gt;. There&apos;s
also a looming thought that &quot;user tests are slow.&quot; Do they have to be?&lt;/p&gt;
&lt;h2 id=&quot;anatomy-of-a-big-test&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#anatomy-of-a-big-test&quot; aria-label=&quot;anatomy of a big test permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Anatomy of a Big Test&lt;/h2&gt;
&lt;p&gt;When we talk about testing the entire app in a way that a person would
interact with it, we&apos;re of course talking about &lt;em&gt;acceptance tests&lt;/em&gt;, or
&lt;em&gt;user tests&lt;/em&gt;, or &lt;em&gt;end-to-end tests&lt;/em&gt;. These types of tests have many
names, but it all refers to the same process of testing your app as if
you were an actual user.&lt;/p&gt;
&lt;p&gt;The life of an acceptance test is pretty simple. First, our app is
mounted and we wait for it to load. Then, some interaction is
performed, such as filling out a form, or clicking a button; something
a person would actually do in our app. Finally, we make some
expectations about the state of our app after the interaction is
performed. Maybe this is a success message, or some other
confirmation. If a user does something in our app, they probably
received some feedback. We want to test this interaction and ensure
that it works as &lt;em&gt;they&lt;/em&gt; would expect it too.&lt;/p&gt;
&lt;p&gt;When a person is interacting with your app, they&apos;re using their mouse
and keyboard which is translating to browser events that your app
responds to. They&apos;re not calling methods and expecting them to return
certain values, they&apos;re actually clicking things and expecting to
achieve results. This is what our app&apos;s tests should do too: &lt;em&gt;send
browser events and assert that there was feedback&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But how do we actually &lt;strong&gt;do&lt;/strong&gt; all of this?&lt;/p&gt;
&lt;h2 id=&quot;the-big-setup&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-big-setup&quot; aria-label=&quot;the big setup permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Big Setup&lt;/h2&gt;
&lt;p&gt;Luckily, it&apos;s not nearly as hard as it sounds. How we interact with
our app should be so identical to how our tests interact with our app
that the only difference is the entry point.&lt;/p&gt;
&lt;p&gt;In development, our entry point imports our app, mounts it, and that&apos;s
it! The app is ready for us to start interacting with. If we&apos;re
working on a certain feature, we navigate directly to the part of our
app containing it.&lt;/p&gt;
&lt;p&gt;In testing, our entry point imports all of our tests and runs
them. It&apos;s each test that mounts and interacts with our app. But from
our app&apos;s point of view, nothing is any different than if it were
being interacted with by a person. Only, in our tests, we can reset
our app when necessary to make sure we&apos;re working with a clean state.&lt;/p&gt;
&lt;p&gt;Let&apos;s get to some actual code! For example&apos;s sake, let&apos;s say our app
is built using &lt;a href=&quot;https://reactjs.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;React&lt;/a&gt; and
&lt;a href=&quot;https://webpack.js.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Webpack&lt;/a&gt; with &lt;a href=&quot;https://&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;babel-loader&lt;/a&gt;,
&lt;a href=&quot;https://github.com/webpack-contrib/style-loader&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;style-loader&lt;/a&gt;, and
&lt;a href=&quot;https://github.com/jantimon/html-webpack-plugin&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;html-webpack-plugin&lt;/a&gt;. We&apos;ll
also be using &lt;a href=&quot;https://mochajs.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Mocha&lt;/a&gt; and
&lt;a href=&quot;http://www.chaijs.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Chai&lt;/a&gt; to write our tests. The app in our
example is a simple countdown app that accepts a date input through
some custom spinner inputs and displays the time until or elapsed
since the specified date.&lt;/p&gt;
&lt;p&gt;Here&apos;s a quick look at our example app in action (&lt;a href=&quot;https://bigtestjs-countdown.surge.sh/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;direct
link&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;website-embed&quot;&gt;
  &lt;iframe src=&quot;https://bigtestjs-countdown.surge.sh/&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Our application&apos;s entry point looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/index.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; render &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react-dom&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; App &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./app&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;App &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;root&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you have other necessary app code in your entry point, consider
moving it into a reusable module. You could even have a &lt;code class=&quot;language-text&quot;&gt;Root&lt;/code&gt;
component with the logic written in lifecycle hooks. The point is:
during development, or in production, our app is only mounted once;
for our tests, we need to be able to remount our app before each
scenario.&lt;/p&gt;
&lt;p&gt;Our testing entry point will look something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// tests/index.js&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// mocha doesn&apos;t support es modules, so we import the pre-compiled assets&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;mocha/mocha.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;mocha/mocha.css&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// other setup could be done here too, such as registering chai helpers&lt;/span&gt;
mocha&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;bdd&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// we import our tests using webpack&apos;s require.context&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// if we just use `import`, it will be hoisted above mocha&apos;s bdd setup&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; requireTest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; require&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;-test&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
requireTest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;requireTest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// run mocha&lt;/span&gt;
mocha&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It&apos;s each test&apos;s job to mount and interact with the app, so all we
need to do here is import all of our tests and run them. We&apos;ll go over
what our tests will actually look like in just a minute. For now,
let&apos;s pretend that our tests just do their aforementioned jobs. You
might be able to figure out where I&apos;m going since I&apos;ve been mentioning
&lt;em&gt;entry points&lt;/em&gt;. We&apos;re going to use our existing Webpack config to
bundle our tests.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// webpack.config.js&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;testing &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./tests/index.js&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./src/index.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ... other webpack config&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&apos;re using Webpack v4, which allows us to [export our config as a
function]([Configuration
&lt;a href=&quot;https://webpack.js.org/configuration/configuration-types/#exporting-a-function&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://webpack.js.org/configuration/configuration-types/#exporting-a-function&lt;/a&gt;). The
first argument of this function, &lt;code class=&quot;language-text&quot;&gt;env&lt;/code&gt;, is populated by the &lt;a href=&quot;https://webpack.js.org/api/cli/#environment-options&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;CLI
argument&lt;/a&gt; of the
same name. This way, when we start our app, we can just call &lt;code class=&quot;language-text&quot;&gt;yarn
start --env.testing&lt;/code&gt; to switch to our testing index. This new bundle
will run all of our tests for us, and we can open this bundle in any
browser on any device to run our tests there as well!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: in our specific case, Mocha&apos;s HTML reported requires a
&lt;code class=&quot;language-text&quot;&gt;#mocha&lt;/code&gt; container in the DOM to output it&apos;s report. We&apos;re using
&lt;a href=&quot;https://github.com/jantimon/html-webpack-plugin&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;html-webpack-plugin&lt;/a&gt;
along with
&lt;a href=&quot;https://github.com/jaketrent/html-webpack-template&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;html-webpack-template&lt;/a&gt;,
so we can just change the &lt;code class=&quot;language-text&quot;&gt;appMountId&lt;/code&gt; of the template when we&apos;re in a
testing environment.&lt;/p&gt;
&lt;p&gt;Okay, so we know how to &lt;em&gt;bundle&lt;/em&gt; our tests, but how do we actually
&lt;em&gt;write&lt;/em&gt; them?&lt;/p&gt;
&lt;h2 id=&quot;writing-big-tests&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#writing-big-tests&quot; aria-label=&quot;writing big tests permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Writing Big Tests&lt;/h2&gt;
&lt;p&gt;If we reflect back on our anatomy lesson, our tests do three important
things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mount/Remount our app&lt;/li&gt;
&lt;li&gt;Interact with our app in a meaningful way&lt;/li&gt;
&lt;li&gt;Assert that something happened&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To successfully do all of these things, we&apos;ll be using a set of
libraries developed specifically for testing big. The
&lt;a href=&quot;https://bigtestjs.io&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;BigTest&lt;/a&gt; suite of libraries and framework
extensions help to answer the big question: &lt;em&gt;does my application work
in real life?&lt;/em&gt; We&apos;ll touch on a few of those libraries in the rest of
this article, but there are some we won&apos;t get to, and more planned for
development.&lt;/p&gt;
&lt;h3 id=&quot;mounting-our-app&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#mounting-our-app&quot; aria-label=&quot;mounting our app permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Mounting Our App&lt;/h3&gt;
&lt;p&gt;First, to mount our app we can just use &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt; from &lt;code class=&quot;language-text&quot;&gt;react-dom&lt;/code&gt;. But
according to the docs: &quot;If the React element was previously rendered
into the container, this will perform an update on it and only mutate
the DOM as necessary to reflect the latest React element.&quot; However,
this is not &lt;em&gt;exactly&lt;/em&gt; what we want. While this does mount our app, we
actually want to mount a &lt;em&gt;fresh instance&lt;/em&gt; of our app every time. To do
this we can combine &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;unmountComponentAtNode&lt;/code&gt;, which will
completely remove a component from the DOM after calling the
appropriate lifecycle hooks.&lt;/p&gt;
&lt;p&gt;This is pretty simple to do ourselves in our own &lt;code class=&quot;language-text&quot;&gt;mount&lt;/code&gt; helper, but
to spare us from even more DIY architecture, we can just utilize the
helpers from &lt;a href=&quot;https://github.com/bigtestjs/react&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@bigtest/react&lt;/code&gt;&lt;/a&gt;
which already do this. It also provides some other useful things, such
as setting up an in-memory &lt;code class=&quot;language-text&quot;&gt;history&lt;/code&gt; object for our app to provide to
&lt;a href=&quot;https://github.com/ReactTraining/react-router&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;React Router&lt;/a&gt;, and
binding this history object to other helpers that allow us to navigate
our app from within our tests.&lt;/p&gt;
&lt;p&gt;This is how we would use &lt;code class=&quot;language-text&quot;&gt;@bigtest/react&lt;/code&gt; to mount our app and visit a
route:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; setupAppForTesting&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; visit &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@bigtest/react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; expect &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;chai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; App &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../src/app&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;mounting our app and visiting a route&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setupAppForTesting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;App&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/2019/01/01&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;shows the date&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; $date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[data-test-countdown-target]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;January 1st, 2019&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can reduce some boilerplate for all of our tests by creating a
helper file and combining the React helpers with Mocha hooks. This way
we also won&apos;t have to import our app into every test file.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// tests/helpers.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; setupAppForTesting &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@bigtest/react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; App &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../src/app&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; visit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; location &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@bigtest/react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setupApplicationForTesting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setupAppForTesting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;App&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We could have other helpers in this file, or do further setup such as
creating a mock server. Once we have an easy way for our tests to
mount our app on demand, we can interact with it.&lt;/p&gt;
&lt;h3 id=&quot;interacting-with-our-app&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#interacting-with-our-app&quot; aria-label=&quot;interacting with our app permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Interacting With Our App&lt;/h3&gt;
&lt;p&gt;Again, we&apos;re not testing that some function returns some value or
calls some other function. &lt;strong&gt;We want to interact with our app like a
real person would.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To do this, we&apos;re going to use
&lt;a href=&quot;https://github.com/bigtestjs/interactor&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@bigtest/interactor&lt;/code&gt;&lt;/a&gt; to
send real browser events to our app. I won&apos;t go into too much detail
here, but interactors are a very powerful, composable, way to interact
with the DOM. Interactors will wait for elements to exist before
interacting with them, so we don&apos;t have to worry about timing our
tests correctly to sync up with any run loops.&lt;/p&gt;
&lt;p&gt;If you&apos;re familiar with the &lt;a href=&quot;https://martinfowler.com/bliki/PageObject.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;page object
pattern&lt;/a&gt;, you&apos;ll know
that they can abstract the internal structure of a page away from the
user-facing functionality. They also reduce a lot of boilerplate
around the UI in our tests, so that if changes are necessary, only the
page objects need to be updated. You can think of interactors as
composable page objects for modern components.&lt;/p&gt;
&lt;p&gt;Let&apos;s create an interactor for the custom spinner input in our app:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// tests/interactors/spinner.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; interactor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; clickable&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@bigtest/interactor&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; @interactor &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SpinnerInteractor&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// common helpers provide easy to define interactions&lt;/span&gt;
  prev &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clickable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[data-test-spinner-prev]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  next &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clickable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[data-test-spinner-next]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;input&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// complex interactions can be expressed as methods&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;option&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; self &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// for each letter in `option`, send a keypress event&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// that will trigger the spinner&apos;s typeahead feature&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; option&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      self &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;keypress&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;charCode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;charCodeAt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// methods that return a new instance of itself are chainable&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we can use this interactor like so:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// interactors are lazy, so we can initialize them without anything&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// actually existing in the DOM yet&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; year &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SpinnerInteractor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[data-test-year-field]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// when accessing properties, an error might be thrown if the element does&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// not exist; this can be more useful than typical expectation failures&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;year&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;2019&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//=&gt; Error: unable to find &quot;[data-test-year-field]&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// methods return new interactors that can then be chained from one another&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; selectYear &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; year&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;2019&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; selectYearThenPrev &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; selectYear&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;prev&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// interactions do not start until `interactor.run()` is called, or when&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// used with the async/await syntax; they will resolve once the element&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// exists and has been interacted with, or when the timeout ellapses&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; selectYearThenPrev&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; year&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can then take these smaller interactors and compose them to create
more complex interactions.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// tests/interactors/form.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; interactor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; scoped &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@bigtest/interactor&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; SpinnerInteractor &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./spinner&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; @interactor &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DateFormInteractor&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// the default scope allows us to omit the selector when calling `new`&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; defaultScope &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;[data-test-date-form]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// interactors are composable and nested methods return an instance&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// of the top-most interactor for chaining&lt;/span&gt;
  year &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scoped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[data-test-year-field]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SpinnerInteractor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  month &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scoped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[data-test-month-field]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SpinnerInteractor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  day &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scoped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[data-test-day-field]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SpinnerInteractor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  hour &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scoped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[data-test-hour-field]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SpinnerInteractor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  minute &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scoped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[data-test-minute-field]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SpinnerInteractor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  submit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scoped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;button[type=&quot;submit&quot;]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// getters can also be used for computed properties&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;year&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;month&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;day&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; time &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hour&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;minute&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;date&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;time&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You&apos;ll notice our use of &lt;code class=&quot;language-text&quot;&gt;data-test-*&lt;/code&gt; attributes. This is because, if
using element IDs or CSS selectors, updates to the app&apos;s design or
markup mean your tests will most likely break. By using data
attributes, we can make our tests and interactors resilient to future
changes. We can also use a babel transform like
&lt;a href=&quot;https://github.com/wireapp/babel-plugin-remove-jsx-attributes&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;babel-plugin-remove-jsx-attributes&lt;/code&gt;&lt;/a&gt;
to remove our testing attributes in production.&lt;/p&gt;
&lt;p&gt;Now that we&apos;ve successfully set up some interactors, we can use them
to start interacting with our app in our tests.&lt;/p&gt;
&lt;h3 id=&quot;making-assertions-about-our-app&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#making-assertions-about-our-app&quot; aria-label=&quot;making assertions about our app permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Making Assertions About Our App&lt;/h3&gt;
&lt;p&gt;Making assertions sounds pretty straightforward, but since real apps
typically have some async operations associated with them, making
assertions at the correct time can be cumbersome and
headache-inducing.&lt;/p&gt;
&lt;p&gt;For example, let&apos;s say we need to test that when a user clicks a
button they are shown a random message. When does the message appear
in the DOM so that we can make an assertion about it? After the user
clicks, sure, but how long after the user clicks? In React, it&apos;s
whenever the render loop gets around to rendering that specific
message. What if the app makes a network request for this message
first? Well, now we need to also wait for a response before making our
assertion.&lt;/p&gt;
&lt;p&gt;Interactors wait for elements to exist in the DOM before interacting
with them, but can we do the same thing with our assertions? Well, yes
we can! Interactors use
&lt;a href=&quot;https://github.com/bigtestjs/convergence&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@bigtest/convergence&lt;/code&gt;&lt;/a&gt;
under the hood, and we can utilize convergences for assertions too.&lt;/p&gt;
&lt;p&gt;What&apos;s a convergence? To put it simply, it&apos;s a pure assertion that can
run repeatedly until either it passes, or a timeout has been
exceeded. And pure assertions are expectations that do not cause side
effects.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; when &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@bigtest/convergence&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// will only continue once the expectation is true&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isLoading&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// works when throwing errors as well&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;foo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;bar&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;baz&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;be&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;undefined&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Convergent assertions will be called several, maybe even hundreds of
times, depending on the timeout and if the assertion ever passes. So
having side effects in our assertions could cause unintended behavior
that may also result in some serious slowdown.&lt;/p&gt;
&lt;p&gt;In regard to our tests, if we make sure all of our assertions are all
pure by keeping our interactions inside of hooks, we can use
&lt;a href=&quot;https://github.com/bigtestjs/mocha&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@bigtest/mocha&lt;/code&gt;&lt;/a&gt; to
automatically turn all of our &lt;code class=&quot;language-text&quot;&gt;it&lt;/code&gt; statements into convergences for
us.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; describe&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; beforeEach&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; it &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@bigtest/mocha&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; expect &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;chai&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; setupApplicationForTesting&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; location &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./helpers&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; DateFormInteractor &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./interactors/form&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Date Picker&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; form &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DateFormInteractor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// for our example app, this function also stubs the date to a constant value&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setupApplicationForTesting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;defaults to the current date&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;2018/1/1@0:0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;submitting a date and time&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; form
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;year&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;2019&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hour&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;12&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;minute&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;30&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;submit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// if this fails, @bigtest/mocha&apos;s `it` will keep rerunning until it&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// passes or a timeout has been exceeded&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;goes to the date countdown&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/2019/01/01/12:30&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And there we go! We&apos;ve officially written some big tests that properly
interact with our app how a user would.&lt;/p&gt;
&lt;h2 id=&quot;the-big-finale&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-big-finale&quot; aria-label=&quot;the big finale permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Big Finale&lt;/h2&gt;
&lt;p&gt;Alright, so we&apos;ve written our tests and we can run them just by
running our app in a testing environment. Our tests interact with our
app just how a user would, and all of our tests pass with flying
colors. But we have real projects with CI/CD pipelines and these tests
need to be automatically run, reported, and tracked for us.&lt;/p&gt;
&lt;p&gt;Thankfully again, we don&apos;t have to do this
ourselves. &lt;a href=&quot;https://github.com/karma-runner/karma&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Karma&lt;/a&gt; is a
framework agnostic test runner that can automatically launch browsers
and generate reports for us. It has plenty of plugins to work with the
browsers and frameworks we&apos;re already using. For our test suite, we&apos;re
going to be using
&lt;a href=&quot;https://github.com/webpack-contrib/karma-webpack&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;karma-webpack&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;https://github.com/karma-runner/karma-mocha&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;karma-mocha&lt;/code&gt;&lt;/a&gt;, and
&lt;a href=&quot;https://github.com/litixsoft/karma-mocha-reporter&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;karma-mocha-reporter&lt;/code&gt;&lt;/a&gt;. To
launch our browser, we&apos;ll use
&lt;a href=&quot;https://github.com/karma-runner/karma-chrome-launcher&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;karma-chrome-launcher&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are a couple things we need to change first to get our Karma
plugins working smoothly:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;karma-webpack&lt;/code&gt; takes a Webpack config, but will disregard our
&lt;code class=&quot;language-text&quot;&gt;entry&lt;/code&gt; and use the file defined in our Karma config instead. This
means some of the testing setup we did in our Webpack config won&apos;t
be necessary anymore.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;karma-mocha&lt;/code&gt; will automatically set up Mocha and run our tests for
us, so we&apos;ll need to remove the Mocha imports and initialization we
manually did in our testing index.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Our new testing index will now look something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// tests/index.js&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// other setup could be done here too, such as registering chai helpers&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; requireTest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; require&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;-test&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
requireTest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;requireTest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And our Karma config will look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;frameworks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;mocha&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// sets up the Mocha framework automatically&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;reporters&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;mocha&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// reports back to the CLI formatted like Mocha&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;browsers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Chrome&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// automatically launches chrome to run our tests&lt;/span&gt;

    &lt;span class=&quot;token literal-property property&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// karma-webpack will watch our files&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tests/index.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;watched&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token literal-property property&quot;&gt;preprocessors&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// tells Karma that we&apos;ll be using Webpack to process this file&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;tests/index.js&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;webpack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Mocha reporter options&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;mochaReporter&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;showDiff&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// our webpack config exports a function&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;webpack&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./webpack.config&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// webpack dev middleware options&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;webpackMiddleware&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;stats&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;minimal&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// for more Karma config options, check out the documentation&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// http://karma-runner.github.io/2.0/config/configuration-file.html&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With all of that set up, we can run &lt;code class=&quot;language-text&quot;&gt;karma start&lt;/code&gt; to launch our
browser and automatically start our tests! For our CI/CD integration,
we can add the flag &lt;code class=&quot;language-text&quot;&gt;--single-run&lt;/code&gt; to exit after running our tests in
the specified browsers. To add other browsers, we simple just have to
install other launchers like
&lt;a href=&quot;https://github.com/karma-runner/karma-firefox-launcher&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;karma-firefox-launcher&lt;/code&gt;&lt;/a&gt;
or
&lt;a href=&quot;https://github.com/karma-runner/karma-safari-launcher&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;karma-safari-launcher&lt;/code&gt;&lt;/a&gt;. We
could even use any of the browsers and devices available on
BrowserStack via
&lt;a href=&quot;https://github.com/karma-runner/karma-browserstack-launcher&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;karma-browserstack-launcher&lt;/code&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;With a little bit of manual setup, and through testing big, we&apos;ve
answered the question: &lt;em&gt;Does my application work in real life?&lt;/em&gt;
However, we&apos;ve only scratched the surface in this article. We glossed
over some things like convergences and interactors, and we didn&apos;t even
get to touch on server mocking with
&lt;a href=&quot;https://github.com/bigtestjs/mirage&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@bigtest/mirage&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Our countdown app lives in the &lt;a href=&quot;https://github.com/bigtestjs/examples/tree/master/react/countdown&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;BigTest examples
repository&lt;/a&gt;
where you can check out the rest of our tests and the entirety of our
configuration files. There will be more examples to come, including
other frameworks and more complicated test setups. Keep an eye out in
the future for more BigTest blog posts and guides, and feel free to
follow and contribute to all of the projects over at the &lt;a href=&quot;https://github.com/bigtestjs&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;BigTest
GitHub organization&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/6b456f27c574350fa94dd270fff6d243/4fe8c/2018-06-13-big-testing-in-react_bigtest.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Connecting a Slack Channel to Gitter]]></title><description><![CDATA[Slack communities for open source projects have become very popular over the past couple years. Slack has taken hold because it makes collaborative chat really easy and accessible for the masses. Something IRC wasn’t able to achieve.]]></description><link>https://frontside.com/blog/2018-04-30-connecting-a-slack-channel-to-gitter/</link><guid isPermaLink="false">https://frontside.com/blog/2018-04-30-connecting-a-slack-channel-to-gitter/</guid><category><![CDATA[open source]]></category><category><![CDATA[community]]></category><category><![CDATA[collaboration]]></category><category><![CDATA[slack]]></category><category><![CDATA[gitter]]></category><dc:creator><![CDATA[Robert DeLuca]]></dc:creator><pubDate>Mon, 30 Apr 2018 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Slack communities for open source projects have become very popular
over the past of couple years. Slack has taken hold because it makes
collaborative chat really easy and accessible for the
masses, something IRC wasn’t able to achieve.&lt;/p&gt;
&lt;p&gt;Slack is amazing for teams working together but there are
downsides to using it for open source communities. One of those
downsides is they’re closed off to search engines. When someone
gets help with an issue it’s forgotten about. Another issue is that
they are usually free Slack communities, which means they have limited
archives. Once the limit is reached, messages are deleted.&lt;/p&gt;
&lt;p&gt;Recently we have started looking into ways to make sure we’re available to
the community for our open source projects. One of the ideas
was to have Slack channels where we could collaborate with the
community, but considering the limitations stated above, we couldn’t
pick Slack.&lt;/p&gt;
&lt;p&gt;In our search for something with Slack-like qualities, we found
&lt;a href=&quot;https://gitter.im/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Gitter&lt;/a&gt;, which checks pretty much all of the
boxes! One problem though: we knew that if we had two different chat apps
we would end up forgetting about one (and it was going to be Gitter). If
only there were a way to combine them…&lt;/p&gt;
&lt;h2 id=&quot;what-if-they-could-both-be-the-sameroom&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-if-they-could-both-be-the-sameroom&quot; aria-label=&quot;what if they could both be the sameroom permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What if they could both be the Sameroom?&lt;/h2&gt;
&lt;p&gt;There’s a service out there that allows you to connect one chat app to
another called &lt;a href=&quot;https://sameroom.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Sameroom&lt;/a&gt; (see what I did there?
(☞ﾟヮﾟ)☞). We decided to give it a shot and, I have to say, it’s pretty
damn neat. We connected our internal open source Slack channels to the
Gitter chatrooms we set up. Now we will get messages posted in our
Slack channel whenever someone posts in our Gitter chatroom.&lt;/p&gt;
&lt;p&gt;We decided to only have the chat go one way. The internal Slack chat
won’t post to Gitter because we’re not crazy about the way it
integrates. Every post in our Slack channel comes from Sameroom bot in
the Gitter chat. If it was easier to distinguish &lt;em&gt;who&lt;/em&gt; those posts
were coming from we’d absolutely enable it. &lt;a href=&quot;https://sameroom.io/blog/introducing-bridgebots/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Gitter covers this
limitation in this blog
post.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Other than that one issue, this integration seems to work pretty well!
We’ve set it up for two of our projects and are looking to add more in
the future. Come chat with us in the
&lt;a href=&quot;https://gitter.im/thefrontside/frontmacs&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Frontmacs&lt;/a&gt; or
&lt;a href=&quot;https://gitter.im/thefrontside/bigtest&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;BigTest&lt;/a&gt; Gitter!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Math is Just Another Framework]]></title><description><![CDATA[Functional programming with typeclasses rooted in category theory may seem like some esoteric practice reserved for the truly pointy-haired. But guess what? You do it every day.]]></description><link>https://frontside.com/blog/2018-02-19-math-is-just-another-framework/</link><guid isPermaLink="false">https://frontside.com/blog/2018-02-19-math-is-just-another-framework/</guid><category><![CDATA[javascript]]></category><category><![CDATA[functional programming]]></category><category><![CDATA[typeclasses]]></category><category><![CDATA[convention over configuration]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 19 Feb 2018 13:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Monads. Amirite?&lt;/p&gt;
&lt;p style=&quot;clear: both&quot;/&gt;
&lt;p style=&quot;clear:both;&quot;&gt;And Ugh... Monoids? 🙄 please 🙄&lt;/p&gt;
&lt;p&gt;What a bunch of complicated gobbledygook. I mean first off, you have
to have like, a PhD in mathematics just in order to get started with
crap like that, and then if you &lt;em&gt;do&lt;/em&gt; decide to put in the work, what&apos;s
the payoff? Look, I just make webapps here. The only return I&apos;d
ever see on that type of investment is maaaayybe the dubious honor of
hanging out with developer cliques that fetishize abstruse words like
&quot;Endofunctor&quot; and &quot;Isomorphism.&quot; They&apos;re so exclusive anyway, and
that&apos;s not what I&apos;m about. I build &lt;em&gt;real&lt;/em&gt; things, and so this isn&apos;t
for me.&lt;/p&gt;
&lt;p&gt;Does any of that sound like an internal dialogue you may have had with
yourself at some point in the last few years? I know it certainly
captures the color of my thinking on the subject of formal functional
programming during that time. Sure, I took half-hearted swipes at
understanding things like Monads here and there, but it never really
stuck. And more often than not, I was inclined to chalk it all up to
sour grapes... That is, of course, until I realized something
amazing. I realized that contrary to what I was brought up to believe,
formal FP wasn&apos;t something that would forever lie just beyond my
reach.&lt;/p&gt;
&lt;p&gt;Imagine my surprise in realizing that not only was this &lt;em&gt;not&lt;/em&gt; true, but in
realizing that I had actually been an FP super hero all along;
descended from a long line of FP super heroes. And do you know what
the most amazing thing is? Whether you know it or not, you are
too. Don&apos;t believe me? Just listen.&lt;/p&gt;
&lt;h3 id=&quot;it-all-began-with-a-functor&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#it-all-began-with-a-functor&quot; aria-label=&quot;it all began with a functor permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;It all began with a Functor&lt;/h3&gt;
&lt;p&gt;A Functor? Are you kidding me?&lt;/p&gt;
&lt;p&gt;I know, I know. Even now just saying it still makes me want to
giggle. But if you&apos;re still doubting your own powers, then Functor
is where the journey begins. That&apos;s where it began for me. Because you
know what? If you code for a living, then odds are you use Functors
every coding minute of every coding day. You just haven&apos;t realized it
yet.&lt;/p&gt;
&lt;p&gt;So Functor is the name, and the concept it references is
&quot;mapping over a structure&quot;. There&apos;s nothing more to it than that. Functors are things
that can be mapped. End of story. &lt;a href=&quot;http://127.0.0.1:59477/Dash/wbiryrnu/developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Array/map.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Arrays can be mapped&lt;/a&gt;: Arrays
are Functors. &lt;a href=&quot;http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-map&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Observables can be mapped&lt;/a&gt;: Obvservables are
Functors. So guess what? Like it or not, if you are comfortable mapping Arrays,
then you are &lt;em&gt;also&lt;/em&gt; comfortable working with Functors.&lt;/p&gt;
&lt;p&gt;Mapping an Array always returns an Array of the same length, but with
different values at every index. Mapping an Observable always
returns an Observable with the exact same sequence and timing of
states, but with different values inhabiting each state. The general
pattern is that mapping doesn&apos;t change the object&apos;s structure.&lt;/p&gt;
&lt;p&gt;At its core, an Array is nothing but a sequence of indexed placeholders
that contain values. &lt;em&gt;That&lt;/em&gt; is its structure, and that&apos;s exactly what
doesn&apos;t change when you map it. The structure of observables is the timing
and sequence of states coming through a stream, so it&apos;s the same
timing sequence that remains intact when you map it. So no matter the
Functor, when you map it, it returns a new Functor with the exact same
structure. In other words:  &lt;code class=&quot;language-text&quot;&gt;S -&gt; S&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But you knew already that mapping an Array of the same length always
returns an Array of the same length because you&apos;ve been working with
them for as long as you&apos;ve been writing code.&lt;/p&gt;
&lt;h3 id=&quot;crouching-promise-hidden-functor&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#crouching-promise-hidden-functor&quot; aria-label=&quot;crouching promise hidden functor permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Crouching Promise, Hidden Functor.&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;So yeah. I know how to map Arrays. Big deal. How does assigning some
new name to what I&apos;m already doing actually help me in any
tangible way? It seems an awful lot like some boring thing to
remember.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, this is where the plot takes an unexpected turn. This is the part
in the story where a chance encounter with a secret Functor plants the
suspicion that perhaps you&apos;ve been lied to your entire life by the
ones that raised you. Sure, they meant well, and all they ever really
wanted to do was to save you sweat and tears, but in the end the only
thing they actually accomplished was to delay your inevitable
confrontation with destiny.&lt;/p&gt;
&lt;p&gt;Here&apos;s your first clue: Have you used and/or thought about Promises
lately?&lt;/p&gt;
&lt;p&gt;Promises don&apos;t have a &lt;code class=&quot;language-text&quot;&gt;map&lt;/code&gt; method, and yet they are nevertheless
Functors. They&apos;re the functoriest of Functors that ever were, and
their functorality is as constant and sure as the sun rising in the
east and setting in the west. But how can this be if there isn&apos;t any
way to map them? The answer is of course that you &lt;em&gt;can&lt;/em&gt; map them. You
just have to use the &lt;code class=&quot;language-text&quot;&gt;then&lt;/code&gt; method to do it. It&apos;s this alternatively
named mapping function that makes Promise a secret Functor.&lt;/p&gt;
&lt;p&gt;It makes sense when you think about how &lt;code class=&quot;language-text&quot;&gt;then&lt;/code&gt; works. You start with a
Promise of some value that will resolve at some later time, and you
end up with another Promise that has the exact same structure as the
original in that it will &lt;em&gt;also&lt;/em&gt; resolve at the exact same time as the
first. The only difference is that the value has been transformed by
the passed in function. Once you come to recognize it, you see that
it&apos;s a clear stamp out of the Functor pattern, and that the method
might as well have been called &lt;code class=&quot;language-text&quot;&gt;map&lt;/code&gt; instead of &lt;code class=&quot;language-text&quot;&gt;then&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And that&apos;s when you begin to wonder &quot;what if it &lt;em&gt;had&lt;/em&gt; been named &lt;code class=&quot;language-text&quot;&gt;map&lt;/code&gt;
instead of &lt;code class=&quot;language-text&quot;&gt;then&lt;/code&gt;, and explicitly identified as a Functor from the
get-go?&quot; Learning to work with Promises was tricky enough, but what if
you&apos;d been able to leverage the fact that the greater part of working
with them was &lt;em&gt;strongly analogous&lt;/em&gt; to working with Arrays? What if
you&apos;d been able to apply everything you knew about mapping Arrays and
bring it to bear on Promises? How much time and mental exhaustion
would it have saved? Looking back at my own experience, it would have
been extraordinarily helpful to have sidestepped the process of trial
and error that happened as my brain settled around the semantics of
Promise.&lt;/p&gt;
&lt;p&gt;Here&apos;s the rub. The method name &lt;code class=&quot;language-text&quot;&gt;then&lt;/code&gt; is a reference to the timing of
Promise resolution, which of course seems reasonable at first. After
all, it&apos;s a good thing for an API to be concrete and descriptive
right? The hidden tradeoff is that the name &lt;code class=&quot;language-text&quot;&gt;then&lt;/code&gt; orients the
API around what makes Promise unique, instead of what makes Promise
&lt;em&gt;literally like every other Functor&lt;/em&gt;. And there are thousands of
them.&lt;/p&gt;
&lt;p&gt;They inhabit so many of the programming structures that
you use every single day, that once you&apos;re aware of them, they will
begin to reveal themselves to you. As you start to perceive the common
nature in things like Promise, Array, and Observable, you begin to
re-perceive &lt;em&gt;all&lt;/em&gt; of the objects in your world through this new prism. You ask
yourself &quot;Is this a Functor?&quot; and you&apos;re shocked by how often
the answer is yes. Plain JS Object? Yes. DOM Element? Yes. Express
middleware? Yes. React Component? Also yes.&lt;/p&gt;
&lt;p&gt;And then it hits you.&lt;/p&gt;
&lt;h3 id=&quot;math-is-just-another-framework&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#math-is-just-another-framework&quot; aria-label=&quot;math is just another framework permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Math is Just Another Framework&lt;/h3&gt;
&lt;p&gt;If you&apos;re using Ruby on Rails, and someone tells you about a
&lt;code class=&quot;language-text&quot;&gt;Controller&lt;/code&gt;, it doesn&apos;t matter if it&apos;s a controller for products, or
users, or blog posts. The mere fact that it&apos;s a &lt;code class=&quot;language-text&quot;&gt;Controller&lt;/code&gt; gives you
most of what you need to know about its role and how you can set to
work with it to build the larger application. By the same token, if
someone tells you that some object is a Functor, it doesn&apos;t matter if
it&apos;s a list, or a tree, or a stream. The mere fact that it&apos;s a Functor
gives you most of what you need to know about its role and how you can
set to work with it to compose it into larger structures.&lt;/p&gt;
&lt;p&gt;I use Ruby on Rails as an example to illustrate this point because the
framework is synonymous with the concept of &lt;a href=&quot;http://rubyonrails.org/doctrine/#convention-over-configuration&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;convention over
configuration&lt;/a&gt;, and that&apos;s the fundamental dynamic at play here. But
whereas Ruby on Rails is a framework for web applications, formal FP
grounded in Category Theory is a framework for composable APIs.&lt;/p&gt;
&lt;p&gt;Like learning any new framework it&apos;s an investment. There are patterns
to internalize and there is abitrary jargon to become acquainted with, but
don&apos;t be intimidated. Every framework has its concepts that
seem opaque at first, but you can learn them all one piece at a
time. And once you&apos;re familiar with them, the big return is that you
can quickly use typeclasses like Functor to build APIs that compose
well with each other out-of-the-box at zero extra cost. And the best
part is that it&apos;s a framework that&apos;s 100% portable across
runtimes. Whether you&apos;re using JavaScript, Ruby or Python it &quot;just
works&quot; every time.&lt;/p&gt;
&lt;p&gt;If you do happen, however, to be working in JavaScript, you&apos;re in
luck. I wrote a library just for you called &lt;a href=&quot;https://github.com/cowboyd/funcadelic.js&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;funcadelic.js&lt;/a&gt; that
brings the magic of typeclasses into the reality of everyday JavaScript
development.&lt;/p&gt;
&lt;p&gt;Because Functor is just the beginning. Like a programmer
learning Ruby on Rails can start with &lt;code class=&quot;language-text&quot;&gt;Controller&lt;/code&gt; first, and then
move on to &lt;code class=&quot;language-text&quot;&gt;Router&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Model&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;Middleware&lt;/code&gt;, so you can you move on
from Functor (at your very own pace) to using Applicatives, Monads, and
Monoids.&lt;/p&gt;
&lt;p&gt;So go for it! I remember the first time I took a tree class I&apos;d been
working with and started thinking of it as a Functor. All of a sudden,
the brain-hurty, recursive aspects of the tree were abstracted into
the map method and I was able to relate entire trees to each other
with nothing more than a simple function. I cannot describe the feeling other than
it felt like flying. The ground below was all very familiar because I&apos;d
walked it back and forth many times over the years. The only
difference was that now I had the perspective of ten thousand feet and
the airspeed of a jetliner.&lt;/p&gt;
&lt;p&gt;You know the ground too. You walk it every day, and if you&apos;re willing
to learn the math framework, the same feeling is waiting for you.&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;I’m Charles Lowell, and I build UI for a living at &lt;a href=&quot;https://frontside.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Frontside&lt;/a&gt;. If
you enjoyed this post, I’d love to hear from you. You can give me a
shout on Twitter where I&apos;m &lt;a href=&quot;https://twitter.com/cowboyd&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@cowboyd&lt;/a&gt;, or drop me a line at
&lt;a href=&quot;mailto:cowboyd@frontside.com&quot;&gt;cowboyd@frontside.com&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/c144534e4c0964a999b59b2abc61db23/4fe8c/2018-02-19-math-is-just-another-framework_graphs.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Quickly Build Component Libraries with Storybook]]></title><description><![CDATA[Design systems have become an effective way to maintain consistency and improve feature delivery time. What can developers on smaller teams do to apply design system concepts?]]></description><link>https://frontside.com/blog/2017-12-29-quickly-build-component-libraries-with-storybook/</link><guid isPermaLink="false">https://frontside.com/blog/2017-12-29-quickly-build-component-libraries-with-storybook/</guid><category><![CDATA[design systems]]></category><category><![CDATA[component library]]></category><category><![CDATA[style guide]]></category><category><![CDATA[storybook]]></category><dc:creator><![CDATA[Jeffrey Cherewaty]]></dc:creator><pubDate>Fri, 29 Dec 2017 23:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As long as humans have been building things, we&apos;ve tried to break up the work. When we can carve out smaller tasks, we can share the work among more people and focus on the quality of each little piece.&lt;/p&gt;
&lt;p&gt;Tools and technologies have reached a point where nearly everyone building for the web is thinking in components. But when you&apos;ve got a large team all creating and using components, how do you keep the usage consistent? Designers have had a tool for that problem for decades. Style guides set down rules and guidelines for projects, so they spoke with a consistent look and voice.&lt;/p&gt;
&lt;p&gt;By combining a style guide with a library of components, you can create a comprehensive design system.&lt;/p&gt;
&lt;h2 id=&quot;enter-storybook&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#enter-storybook&quot; aria-label=&quot;enter storybook permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Enter Storybook&lt;/h2&gt;
&lt;p&gt;Prominent companies that have built large design systems usually have to build all new tools for their component libraries. When you have multiple templating languages to deal with and dozens of different product teams, your design system has constraints that no out-of-the-box solution provides.&lt;/p&gt;
&lt;p&gt;At Frontside, we&apos;re frequently working on brand-new projects instead, so we push open-source solutions that let developers immediately focus on delivering features. For component libraries featuring Vue or React, there&apos;s now a one-size-fits-most tool: &lt;a href=&quot;https://storybook.js.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Storybook&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;writing-stories&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#writing-stories&quot; aria-label=&quot;writing stories permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Writing Stories&lt;/h2&gt;
&lt;p&gt;With Storybook, developers create &quot;stories&quot; that illustrate and describe different versions of each component. In practice, it feels a lot like writing tests: what are all the possible iterations of this component? Because it aligns with test-driven development philosophy, Storybook makes a great base for adding visual regression testing.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import React from &apos;react&apos;;
import { storiesOf } from &apos;@storybook/react&apos;;
import Checkbox from &apos;./Checkbox&apos;;

storiesOf(&apos;Checkbox&apos;, module)
  .add(&apos;Basic Usage&apos;, () =&gt; (
    &amp;lt;Checkbox
      onChange={() =&gt; {}}
      checked=true
      label=&apos;Check Me&apos;
    /&gt;
  ));&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://storybook.js.org/basics/writing-stories/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Storybook Docs: Writing Stories&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;addons&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#addons&quot; aria-label=&quot;addons permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Addons&lt;/h2&gt;
&lt;p&gt;Storybook&apos;s addon architecture is where the benefits of having an open-source project really pay off. There&apos;s a whole ecosystem of pre-built addons, along with the ability to create your own.&lt;/p&gt;
&lt;h3 id=&quot;readme-addon&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#readme-addon&quot; aria-label=&quot;readme addon permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;README addon&lt;/h3&gt;
&lt;p&gt;The codebase we&apos;re working with already had great documentation for many of its components. With &lt;a href=&quot;https://github.com/tuchk4/storybook-readme&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;storybook-readme&lt;/code&gt;&lt;/a&gt;, just a couple lines of configuration had each component&apos;s README appear in the Storybook environment&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import Readme from &apos;./README.md&apos;;

storiesOf(&apos;Checkbox&apos;, module)
  .addDecorator(withReadme(Readme))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;add-a-knob&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#add-a-knob&quot; aria-label=&quot;add a knob permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add a knob&lt;/h3&gt;
&lt;p&gt;Another useful Storybook addon: &lt;a href=&quot;https://github.com/storybooks/storybook/tree/master/addons/knobs&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;storybook-knobs&lt;/code&gt;&lt;/a&gt;. Component props can be edited within the Storybook UI.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import { withKnobs, text } from &apos;@storybook/addon-knobs&apos;;

storiesOf(&apos;Checkbox&apos;, module)
  .addDecorator(withKnobs)
  .add(&apos;Basic Usage&apos;, () =&gt; (
    &amp;lt;Checkbox
      onChange={() =&gt; {}}
      checked=true
      label={text(&apos;Label&apos;, &apos;Check Me&apos;)}
    /&gt;
  );&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;add-an-action&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#add-an-action&quot; aria-label=&quot;add an action permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add an action&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/storybooks/storybook/tree/master/addons/actions&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;storybook-actions&lt;/code&gt;&lt;/a&gt; help drive component action development. Component actions get stubs that show up in the Storybook UI.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;import { action } from &apos;@storybook/addon-actions&apos;;

storiesOf(&apos;Checkbox&apos;, module)
  .add(&apos;Basic Usage&apos;, () =&gt; (
    &amp;lt;Checkbox
      onChange={ action(&apos;checkbox-toggle&apos;) }
      checked=true
      label=&apos;Check Me&apos;
    /&gt;
  );&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;evolving-tools&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#evolving-tools&quot; aria-label=&quot;evolving tools permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Evolving Tools&lt;/h2&gt;
&lt;p&gt;Storybook is a big landmark for developing component libraries for the web, and we&apos;re looking forward to its evolution, and eventually the next set of tools for design systems.&lt;/p&gt;
&lt;p&gt;Check out this &lt;a href=&quot;https://youtu.be/RHacQsTxnQ4&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Lunch and Learn&lt;/a&gt; to see Storybook in action.&lt;/p&gt;
&lt;p&gt;Need help creating your own design system? &lt;a href=&quot;https://frontside.com/contact/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Reach out to Frontside.&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/4ae1eef3bb398cdd942eab6b3d29e702/4fe8c/2017-12-29-quickly-build-component-libraries-with-storybook_storybook.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[How Healthy Is Your Build?]]></title><description><![CDATA[Staying healthy is a lot of work.  Maybe you hit the treadmill before going into the office, and then on the way home you pick up some organic groceries.  But be honest, you probably don't.  Thankfully, maintaining your web application's build health is much easier, and the rewards can be huge!  Take a few minutes to check your build health today: you might regret it if you don't.]]></description><link>https://frontside.com/blog/2017-08-04-the-importance-of-build-health/</link><guid isPermaLink="false">https://frontside.com/blog/2017-08-04-the-importance-of-build-health/</guid><category><![CDATA[continuous]]></category><category><![CDATA[integration]]></category><category><![CDATA[deploy]]></category><category><![CDATA[ci]]></category><category><![CDATA[cd]]></category><category><![CDATA[build]]></category><category><![CDATA[test]]></category><dc:creator><![CDATA[Joe LaSala, Ginger Whalen, Elrick Ryan]]></dc:creator><pubDate>Fri, 04 Aug 2017 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When’s the last time you went in for a checkup with your family doctor?  Do you know what your cholesterol level is?  Your blood pressure?  It’s unfortunate that many people can’t answer those questions quickly and honestly.  It usually takes a health scare to prompt people towards that dreaded waiting room with the stale air and old magazines.&lt;/p&gt;
&lt;p&gt;Regular checkups are an essential part of healthy living, so why do we put them off?  Why do we ignore symptoms?  Is it because we’re too busy?  Are we afraid of what we might find out?&lt;/p&gt;
&lt;p&gt;We all know what it takes to stay healthy:  be proactive,  practice good habits, monitor your health closely.  We also know that these things are much easier said than done.  I mean, come on!  Who has time to take care of every little wrinkle in the moment, right?  Thankfully, applying these healthy practices to your application’s build health is far less arduous.  That you can handle, and we can show you why it’s worth it.  Let’s get out of the red and into the green!&lt;/p&gt;
&lt;p&gt;Our goal?  Master builds that are validated by a comprehensive test suite and pass 100% of the time. In other words, a perfect world.  But hey, it’s easier than eating more kale, cutting out the bacon, and exercising three times a week.&lt;/p&gt;
&lt;p&gt;So, let’s do a quick checkup.  Don’t worry, no stethoscopes: this is a build check up.  Off the top of your head, do you know how many times your application failed to build last week?  If that number is greater than zero then you just failed your checkup.  If you don’t know the number, you may need to see a specialist.&lt;/p&gt;
&lt;p&gt;Fear not!  We can write you a prescription that will get that number out of the danger zone.  Side effects may include happier engineers, happier users, and an increase in code and product quality.&lt;/p&gt;
&lt;p&gt;In order to make a diagnosis, we first have to ask you some questions...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;About your test suite...&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is your current test coverage?  Do you enforce a coverage threshold?&lt;/li&gt;
&lt;li&gt;Are you writing good tests?  There are many articles devoted to the finer points of what makes a test “good”, so we’ll leave it up to you to find a definition that makes sense for your team.  Whatever that definition ends up being, make sure you question it regularly and revise it if necessary.&lt;/li&gt;
&lt;li&gt;Are you writing appropriate tests? Do you understand the difference between unit tests, integration tests and acceptance tests?  What about “end-to-end” tests or “smoke” tests?  The nomenclature around these concepts is often overloaded and the concepts themselves are frequently conflated.  Try not to get lost in the woods.&lt;/li&gt;
&lt;li&gt;Are you testing your own code, or vendor code?  Think about it.  You may be surprised.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hmm, OK.  I see.  Moving on...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How about your testing strategy?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do you have one? What is it?&lt;/li&gt;
&lt;li&gt;Is it just a concept in your procedures manual, or is it a reality every time new functionality is added to your application?&lt;/li&gt;
&lt;li&gt;How often do you revise your strategy?  How often do you set aside time to discuss it with your team?  Is your testing process as important as development process?&lt;/li&gt;
&lt;li&gt;How often does automated testing take a backseat to feature deadlines?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OK.  Let me just mark that last bit in my chart...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Finally, with regard to continuous integration and deployment...&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How often do you push new code to your production environment?&lt;/li&gt;
&lt;li&gt;When you do push to production, how do you do it?  Is there a clear process in place?  How much of that process is handled manually?  Every manual step in your deployment is susceptible to human error.&lt;/li&gt;
&lt;li&gt;Does your deployment pipeline include a CI/CD service like Jenkins, CircleCI or TravisCI?&lt;/li&gt;
&lt;li&gt;Is your CI/CD environment in relative parity with your development environments?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alright, that should do it!  Thanks for your honesty.  Well, reader, if any of these points gave you pause, then I regret to inform you that your build may be in poor health!  Luckily we caught it early.  You can address this problem now by making a few lifestyle changes.&lt;/p&gt;
&lt;p&gt;Good build health starts with a goode test suite.  “System Integration Tests”, “User Acceptance Tests”, “Deployment Pipelines”... if you&apos;re not a software developer these terms might as well be medical jargon.  For now we&apos;ll just give you the big picture: you have an application, people use the application.  Your test suite needs to account for both sides of that relationship.&lt;/p&gt;
&lt;p&gt;We recommend that you pay special attention to acceptance tests, which are tests intended to mimic real user interaction with the application.  Why?  While the benefits of simulating realistic user interaction should be obvious, somehow acceptance tests often get overlooked.  For example, &lt;a href=&quot;https://embersurvey.typeform.com/report/GmJTvy/S9Nt&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;this survey&lt;/a&gt; showed that only &lt;em&gt;24%&lt;/em&gt; of respondents were testing their Ember addons with acceptance tests.  That number should shock you.  Out of all the varieties of tests that a developer can write, acceptance tests are those that most closely mimic user interaction.  What’s more important than the real-world user interaction?&lt;/p&gt;
&lt;p&gt;Finally, remember that a good test suite will benefit your employees, your users, and your stakeholders.  In fact, an automated test suite is really just one expression of a concept that probably permeates your organization more than you realize.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a product manager writes requirements for a new feature based on customer feedback, they’re writing &quot;acceptance criteria&quot;.  What are acceptance criteria if not a human-readable test suite?&lt;/li&gt;
&lt;li&gt;When the engineer sits down to write the feature, the corresponding acceptance tests should closely resemble the acceptance criteria laid out by the product manager.&lt;/li&gt;
&lt;li&gt;A QA specialist can use these specifications as a roadmap for testing the feature manually.&lt;/li&gt;
&lt;li&gt;A technical writer can use this outline as a jumping-off point for user-facing help documents.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This same pattern appears, in one form or another, at nearly every level of the modern software development workflow.  If you can understand this pattern as a “common language” between your departments, you will also understand how much the individual units of your team depend on each other.  That means that a healthy build can lead to increased efficiency across the board, but neglecting your application’s build health can jeopardize your product at many levels.&lt;/p&gt;
&lt;p&gt;Nobody likes surprises.  Not at the doctor’s office, and not when deploying an application.  So get on the right track to good build health today!  Say goodbye to white-knuckle releases and on-call experts.  Imagine the peace of mind that comes with comprehensive test coverage.  Imagine all the time you&apos;ll save with a realiable, automated deployment pipeline!  That’s time that you could use to maintain your &lt;em&gt;actual&lt;/em&gt; health.  Take this advice and you’ll be able to hit that &lt;em&gt;merge&lt;/em&gt; button with confidence, then hit the treadmill while your application hits the web.&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;Interested in talking more with us build health, or anything else software related? Get in touch &lt;a href=&quot;/contact&quot;&gt;on our website&lt;/a&gt;, or reach out to us on twitter at &lt;a href=&quot;https://twitter.com/thefrontside&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@thefrontside&lt;/a&gt;. We&apos;d love to hear from you!&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/96f6a5099095ea6b6f569f3e599c513b/70169/2017-08-04-the-importance-of-build-health_creative-commons-heart.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[One Helpful Way to Think About JavaScript Decorators]]></title><description><![CDATA[JavaScript decorators are coming, but what are the class of problems which they're useful for? In this brief tour of decorators, we'll try to answer that question by contrasting them with comparable technology from other languages.]]></description><link>https://frontside.com/blog/2017-06-01-one-helpful-way-to-think-about-javascript-decorators/</link><guid isPermaLink="false">https://frontside.com/blog/2017-06-01-one-helpful-way-to-think-about-javascript-decorators/</guid><category><![CDATA[javascript]]></category><category><![CDATA[clojure]]></category><category><![CDATA[macros]]></category><category><![CDATA[decorators]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Thu, 01 Jun 2017 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Why Decorators?&lt;/p&gt;
&lt;p&gt;It is an important question; one many tutorials rush past in their hurry to talk about the &lt;em&gt;what&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt;. Of course, after being exposed to enough doses of &lt;em&gt;what&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt;, you can usually piece together &lt;em&gt;why&lt;/em&gt;, but in my experience it saves time to just hear it up front. I&apos;d like to share one of the ways I&apos;ve come to think about decorators and how it&apos;s helped me think about when to use them.&lt;/p&gt;
&lt;p&gt;So like every good meta-discussion of JavaScript, let&apos;s start by
talking about Clojure. Don&apos;t sweat it if you don&apos;t know Clojure,
that&apos;s totally &lt;em&gt;ok&lt;/em&gt;. The examples are very simple and only there to
illustrate a bigger point.&lt;/p&gt;
&lt;p&gt;Anyway, back to Clojure...&lt;/p&gt;
&lt;p&gt;In Clojure, one way to associate a name with a value is to use the &lt;code class=&quot;language-text&quot;&gt;def&lt;/code&gt; form:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;clojure&quot;&gt;&lt;pre class=&quot;language-clojure&quot;&gt;&lt;code class=&quot;language-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; message &lt;span class=&quot;token string&quot;&gt;&quot;hello computer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After that declaration, subsequent code can refer to the string &lt;code class=&quot;language-text&quot;&gt;&quot;hello computer&quot;&lt;/code&gt; just by using the symbol &lt;code class=&quot;language-text&quot;&gt;message&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;The ability to associate names and values is a pretty handy thing in programmming, and it turns out you can do something very similar in JavaScript too. You might write something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; message &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hello computer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another thing that Clojure has support for is function values:
functions that can be passed as either an argument to, or the return
value from, another function. You can declare a function value that
adds its operands together with the following syntax.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;clojure&quot;&gt;&lt;pre class=&quot;language-clojure&quot;&gt;&lt;code class=&quot;language-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;x y&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;+&lt;/span&gt; x y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not to be outdone though, JavaScript also has support for first class functions, and it&apos;s syntax is even a little more concise than Clojure&apos;s too! This is it here.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Both of these are examples of &lt;em&gt;anonymous functions&lt;/em&gt;. Function values that can be passed around as one-offs to other functions. It&apos;s handy, but sometimes it&apos;s not enough.&lt;/p&gt;
&lt;p&gt;Often what we want is to associate a name with a function so that we
can call it again and again. In the same way we associated the name
&lt;code class=&quot;language-text&quot;&gt;message&lt;/code&gt; with the string value &lt;code class=&quot;language-text&quot;&gt;&quot;hello computer&quot;&lt;/code&gt; so that we could
access it repeatedly just by referring to &lt;code class=&quot;language-text&quot;&gt;message&lt;/code&gt;, we can associate
a function value with a symbol so that we can reach for it over and
over just by remembering its name. To do that, we use the two
constructs just introduced (&lt;code class=&quot;language-text&quot;&gt;def&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;fn&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;clojure&quot;&gt;&lt;pre class=&quot;language-clojure&quot;&gt;&lt;code class=&quot;language-clojure&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;;; associate the symbol `add` with the function to add&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; add &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;x y&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;+&lt;/span&gt; x y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;;; and now we can call it by name.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;;;=&gt; 2&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;;;=&gt; 7&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Just like before, a parallel construct exists in JavaScript. No suprises there.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// associate the symbol `add` with the function to add&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// and now we can call it by name.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 2&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; 7&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But of course, this pattern of associating a name with a function is so prevalent that both Clojure and JavaScript have a special syntax to both declare a function &lt;em&gt;and&lt;/em&gt; associate it with a name in one fell swoop. In Clojure you use &lt;code class=&quot;language-text&quot;&gt;defn&lt;/code&gt; (literally the conjuction of &lt;code class=&quot;language-text&quot;&gt;def&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;fn&lt;/code&gt;)&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;clojure&quot;&gt;&lt;pre class=&quot;language-clojure&quot;&gt;&lt;code class=&quot;language-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; add &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;x y&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;+&lt;/span&gt; x y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And you&apos;re probably already familiar with how it&apos;s done in JavaScript with a &lt;code class=&quot;language-text&quot;&gt;function&lt;/code&gt; declaration.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;theres-a-point-to-this-i-promise&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#theres-a-point-to-this-i-promise&quot; aria-label=&quot;theres a point to this i promise permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;There&apos;s a point to this. I promise.&lt;/h2&gt;
&lt;p&gt;So I just explained named functions in both Clojure and JavaScript. Big
whoop.&lt;/p&gt;
&lt;p&gt;It&apos;s such a simple idea and an equally simple mechanism. And on the surface they seem equivalent in both languages, but there&apos;s one key difference between the way the named function syntax works in JavaScript and the way it works in Clojure. Both syntaxes declare a function value, and both associate that function value with a name so that it can be referred to later.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;difference&lt;/em&gt; is that in JavaScript the syntax is implemented by the JavaScript parser and interpreter, whereas in Clojure the syntax is implemented in Clojure.&lt;/p&gt;
&lt;h2 id=&quot;a-macro-says-what&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-macro-says-what&quot; aria-label=&quot;a macro says what permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A Macro Says What?&lt;/h2&gt;
&lt;p&gt;That bears repeating. In JavaScript, the syntax is implemented by the
JavaScript parser and interpreter. More than likely that means baked
in with some C or C++ code somewhere. Beyond the implementation, it
means that there needs to be a
&lt;a href=&quot;http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;specification for the syntax as part ECMA standard&lt;/a&gt;
so that any of the multiple engines can be sure to get it right.&lt;/p&gt;
&lt;figure class=&quot;figure&quot; alt=&quot;a picture of the twenty seven line specification of function syntax in BNF format on the Ecma website&quot;&gt;
  &lt;img class=&quot;figure-img img-fluid&quot; src=&quot;/img/2017-06-01-one-helpful-way-to-think-about-javascript-decorators_function-syntax.png&quot;&gt;
  &lt;figcaption class=&quot;figure-caption&quot;&gt; &lt;em&gt;&lt;strong&gt;Figure 1:&lt;/strong&gt; Put this in your C++ and smoke it&lt;/em&gt;&lt;/caption&gt;
&lt;/figure&gt;
&lt;p&gt;Contrast this to Clojure in which the named function syntax is nothing but more Clojure code. It&apos;s easy to understand not only for programmers, but also for any alternative implementation of Clojure (such as clojurescript). It&apos;s a nifty trick that saves time, adds clarity and eliminates ambiguity. How does it work? The answer is macros.&lt;/p&gt;
&lt;p&gt;Macros are powerful, but they aren&apos;t fancy. A macro is just a function like any other function, and if you can work with functions, then you can work with macros.&lt;/p&gt;
&lt;p&gt;There are two things that make a macro function special though. The
first is that the type of its arguments and the type it returns are
not general values &lt;em&gt;but source code&lt;/em&gt;. That means it takes code in as
its input, and returns code as it&apos;s output. Here&apos;s a couple of
familiar functions along with their (pseudo) types for comparison. &lt;code class=&quot;language-text&quot;&gt;map&lt;/code&gt; takes an array as its input, and returns another array. &lt;code class=&quot;language-text&quot;&gt;sum&lt;/code&gt; takes an array as input, and returns a number. &lt;code class=&quot;language-text&quot;&gt;defn&lt;/code&gt; takes code input and returns more code.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;map :: Array -&gt; Array
sum :: Array -&gt; Number
defn :: Code -&gt; Code&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The second thing that makes a macro function special is that it doesn&apos;t run when the rest of your program does; it runs when your program is being compiled. When the compiler encounters a macro, it calls it, and then replaces the macro with the code that got returned.&lt;/p&gt;
&lt;figure class=&quot;figure&quot; alt=&quot;the arguments to a macro function are the unevaluated source code&quot;&gt;
  &lt;img class=&quot;figure-img img-fluid&quot; src=&quot;/img/2017-06-01-one-helpful-way-to-think-about-javascript-decorators_defn-arguments.png&quot;&gt;
  &lt;figcaption class=&quot;figure-caption&quot;&gt; &lt;em&gt;&lt;strong&gt;Figure 2:&lt;/strong&gt; The arguments to a macro function are unevaluated source code&lt;/em&gt;&lt;/caption&gt;
&lt;/figure&gt;
&lt;p&gt;In fact, this is how the &lt;code class=&quot;language-text&quot;&gt;defn&lt;/code&gt; macro works. It literally replaces&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;(defn add [x y] (+ xy))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;with&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;(def add (fn [x y] (+ x y)))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;figure class=&quot;figure&quot; alt=&quot;defn consumes its arguments and returns
  new source code containing those arguments&quot;&gt;
  &lt;img class=&quot;figure-img img-fluid&quot; src=&quot;/img/2017-06-01-one-helpful-way-to-think-about-javascript-decorators_defn-mapping.png&quot;&gt;
  &lt;figcaption class=&quot;figure-caption&quot;&gt; &lt;em&gt;&lt;strong&gt;Figure 3:&lt;/strong&gt;
  The defn macro takes code as arguments and returns more code&lt;/em&gt;&lt;/caption&gt;
&lt;/figure&gt;
&lt;p&gt;The point here is not to geek out too hard on Clojure macros, but to
show just how much more you can do with so much less when your
language has first class support for transforming code into other
code. Large swaths of what we think of as Clojure syntax is actually
defined with Clojure. The syntax it does have baked in works
harder. There&apos;s no need to change the way the compiler works, and
&lt;em&gt;certainly&lt;/em&gt; no slog through a potentially contentious
&lt;a href=&quot;https://github.com/tc39/ecma262#ecmascript&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;specification by committee&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Wouldn&apos;t it be nice if JavaScript let us do something similar? Wouldn&apos;t it be nice if we could extend JavaScript syntax with just a few lines of JavaScript code instead of years spent shit-posting on the internet?&lt;/p&gt;
&lt;h2 id=&quot;decorators-to-the-rescue&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#decorators-to-the-rescue&quot; aria-label=&quot;decorators to the rescue permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Decorators to the rescue&lt;/h2&gt;
&lt;p&gt;The answer is that with decorators we can... almost. To be clear, decorators are &lt;em&gt;not&lt;/em&gt; lisp macros. They&apos;re less powerful and they operate in a much smaller niche. But even so, they&apos;re an exciting development because there is just enough overlap with macros to make them helpful in the same kinds of situations.&lt;/p&gt;
&lt;p&gt;That&apos;s because, like a macro, a decorator is also &lt;em&gt;just a function&lt;/em&gt;. And also like a macro, it&apos;s a function that operates on code &lt;em&gt;before&lt;/em&gt; the rest of your program sees it.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@decorator :: Code -&gt; Code&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Like a macro, we can use this to add the new syntax we always wanted to our JavaScript classes.&lt;/p&gt;
&lt;p&gt;For example, I&apos;ve often wished that there were an &lt;code class=&quot;language-text&quot;&gt;immutable&lt;/code&gt; keyword in JavaScript that made it impossible to change member data of an instance once it was constructed. Wouldn&apos;t it be great if you write a class like this?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;immutable &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Circle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; radius&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;area&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; circle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Circle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
circle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;area &lt;span class=&quot;token comment&quot;&gt;//=&gt; 25π&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// can&apos;t do this!&lt;/span&gt;
circle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; Error!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I think that would be awesome, and if you feel the way I do, then you&apos;ve got two options:&lt;/p&gt;
&lt;p&gt;A. Begin your submission to the TC39 (you&apos;d better get on it if you
want to hit your deadline in three weeks!)&lt;/p&gt;
&lt;p&gt;B. Do it now with decorators.&lt;/p&gt;
&lt;p&gt;Decorators can help us get the syntax we want today because they let
you transparently transform the code that you &lt;em&gt;see&lt;/em&gt; into the code that
you &lt;em&gt;want&lt;/em&gt;. In the case of our &lt;code class=&quot;language-text&quot;&gt;immutable&lt;/code&gt; keyword, the code is a
class. In other words, we want to take the class that we &lt;em&gt;see&lt;/em&gt;
(mutation allowed) and convert it into the class we &lt;em&gt;want&lt;/em&gt; (no
mutation allowed)&lt;/p&gt;
&lt;p&gt;The class we &lt;em&gt;see&lt;/em&gt; has this constructor:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Circle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; radius&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But the class we &lt;em&gt;want&lt;/em&gt; has this constructor:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Circle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; radius&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;freeze&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we can write a function that takes the former and returns the latter, then we&apos;re in business. Luckily, this is pretty straightforward. In order to make an immutable version of any given class, we can extend it, and then make a call to &lt;code class=&quot;language-text&quot;&gt;Object.freeze&lt;/code&gt; after invoking the original constructor.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// @immutable :: Class -&gt; Class&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;immutable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImmutableVersion&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Class&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;freeze&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; ImmutableVersion&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We now have a function that returns an immutable version of any class, and so now we can just use it as a decorator; almost like we were creating our own syntax.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;@immutable &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Circle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; radius&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;area&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our JavaScript interpreter will see this and transparently convert the &lt;code class=&quot;language-text&quot;&gt;Circle&lt;/code&gt; class that we see into a different one; one that prohibits any mutation of its member data after construction.&lt;/p&gt;
&lt;p&gt;Decorators aren&apos;t just for entire classes. They can be used to enhance individual members of as class as well and transform them transparently into something more powerful. For example, since the &lt;code class=&quot;language-text&quot;&gt;area&lt;/code&gt; of the circle is a computed property, it won&apos;t be enumerable by default.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Circle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; [&apos;radius&apos;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That doesn&apos;t seem quite right. Shouldn&apos;t &lt;code class=&quot;language-text&quot;&gt;area&lt;/code&gt; be in there too?&lt;/p&gt;
&lt;p&gt;What would be really nice if if JavaScript had a keyword to make any property enumerable. E.g.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  enumerable &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;area&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It doesn&apos;t of course, but with decorators we can change that. We&apos;ll
just write a member decorator: a decorator that operates on
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;property descriptors&lt;/a&gt;
instead of classes. We can write an &lt;code class=&quot;language-text&quot;&gt;enumerable&lt;/code&gt; function to take the property descriptor we &lt;em&gt;see&lt;/em&gt; (non-enumerable) and return the property descriptor we &lt;em&gt;want&lt;/em&gt; (enumerable). This is accomplished simply enough by returning a new descriptor exactly like the old one, except with the enumerable key of the descriptor set to &lt;code class=&quot;language-text&quot;&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// @enumerable :: Property -&gt; Property&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;enumerable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; descriptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;descriptor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;enumerable&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With this in hand, we can mark the &lt;code class=&quot;language-text&quot;&gt;area&lt;/code&gt; property as enumerable, just as though the syntax had existed the whole time.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;@immutable &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Circle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; radius&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  @enumerable &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;area&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Declared this way, circles will let you know that they have an area in addition to a radius:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Circle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//=&gt; [&apos;radius&apos;, &apos;area&apos;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Easy!&lt;/p&gt;
&lt;h2 id=&quot;decorators-ftw&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#decorators-ftw&quot; aria-label=&quot;decorators ftw permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Decorators FTW&lt;/h2&gt;
&lt;p&gt;And that&apos;s it! My goal with this brief tour of decorators isn&apos;t to
show you the ins and outs of how they work, but to share a helpful way
to think about them and when they might be the right tool to reach
for. While decorators are not lisp macros, it&apos;s useful to think about
them as a spiritual grandchild in the sense that their biggest power
is to &lt;em&gt;transform the primary artifacts of your code before the rest of
your program sees them&lt;/em&gt;. Rather being locked into a given syntax, the
interpreter is open to extension, and you can negotiate with it for a
new set of semantics.&lt;/p&gt;
&lt;p&gt;In a way, by including decorators and allowing them to stand in for
many of the use-cases where a new syntax might otherwise be desirable,
the ECMAScript specification is firing itself from its primary
responsibility of evolving the core language. What previously might
have taken months or years, can now be done in a matter of minutes or
hours; a huge roadblock gone that has historically stood in the way of progress.&lt;/p&gt;
&lt;p&gt;For individual developers, decorators let us work with a lighter touch; applying just a little bit of new syntax to make big transformations, but all the while preserving the core intent and readability of our code.&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;I’m Charles Lowell (&lt;a href=&quot;https://twitter.com/cowboyd&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@cowboyd&lt;/a&gt; on twitter), and I build UI for a
living at &lt;a href=&quot;http://frontside.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Frontside&lt;/a&gt;. If you enjoyed this, I’d love to hear
from you. We&apos;re always &lt;a href=&quot;http://frontside.com/careers/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;hiring&lt;/a&gt; and
looking for &lt;a href=&quot;http://frontside.com/services/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;exciting new work&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/5bdaef2c99b94bac1ebfbfce229c49b9/4fe8c/2017-06-01-one-helpful-way-to-think-about-javascript-decorators_russian-dolls.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[React Native and Chill: A tale of stupid made fast]]></title><link>https://frontside.com/blog/2017-01-16-react-native-and-chill-a-tale-of-stupid-made-fast/</link><guid isPermaLink="false">https://frontside.com/blog/2017-01-16-react-native-and-chill-a-tale-of-stupid-made-fast/</guid><category><![CDATA[react native]]></category><category><![CDATA[react]]></category><category><![CDATA[tvOS]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 16 Jan 2017 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The instant she told me, I knew with the feeling of faith that it was
true. &quot;Charles,&quot; she said gravely &quot;You&apos;ve got to build something
&lt;em&gt;stupid&lt;/em&gt;, and you&apos;ve got to do it really soon.&quot;&lt;/p&gt;
&lt;p&gt;Of course! Something stupid. Why didn&apos;t I think of that.&lt;/p&gt;
&lt;p&gt;It was so obvious why not: I was too busy thinking about
biznazz; too busy thinking about &lt;em&gt;sales&lt;/em&gt;; too busy thinking
about &lt;em&gt;accounting&lt;/em&gt;. Too busy thinking about things like &lt;em&gt;office
furniture&lt;/em&gt; and  &lt;em&gt;hiring practices&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;These are all things that are well and proper to think about...
necessary even. They are the things that every voice I trust in my life
admonishes me to concentrate on exclusively, my own loudest among them.&lt;/p&gt;
&lt;p&gt;But listen &lt;em&gt;too much&lt;/em&gt; to these voices and they&apos;ll have you piling the
work-cart high with sundry projects and tasks. Now
you spend every waking moment watching it teeter back and forth making
sure it doesn&apos;t dump over and lose everything. Where is the
inspiration in &lt;em&gt;that&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Nope, time to set that cart down and do something stupid.&lt;/p&gt;
&lt;p&gt;Luckily, fortune favors the stupid, and if you&apos;ve set your mind to finding
something idiotic to do, you&apos;re bound to succeed (based on the
abundance of stupid things to do in the universe).&lt;/p&gt;
&lt;p&gt;For me it happened the very next day.&lt;/p&gt;
&lt;h1 id=&quot;a-dumb-idea&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-dumb-idea&quot; aria-label=&quot;a dumb idea permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A dumb idea&lt;/h1&gt;
&lt;p&gt;As a statement of fact rather than complaint, the end of
2016 and the beginning of 2017 has been a preternaturally stressful
time. I know that this is what the internet has been droning on about
lately, but in my case it&apos;s really true! I seriously don&apos;t remember a
time in my life that was any trickier to navigate or that has required
such sustained mental concentration.&lt;/p&gt;
&lt;p&gt;Of course I have several coping mechanisms on hand, including Rye
Whiskey, but one of the simplest and most effective ones that has
come to my aid on more occasions that I can count
is &lt;a href=&quot;http://chillestmonkey.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Chillest Monkey&lt;/a&gt;. For me, I need only glance at his picture
for a few moments before experiencing a &lt;em&gt;physical sensation of relaxation&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;His detached gaze sees through the edifice of anxieties I&apos;ve built
and twisted around myself. The low-frequency waves of tranquility
emanating from his placid countenance dissolve and disippate it like a
grease stain before a flow of warm detergent.&lt;/p&gt;
&lt;p&gt;I was sharing this personal treasure with my co-workers when &lt;a href=&quot;http://robert-deluca.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Rob&lt;/a&gt;
exclaimed something to the effect of &quot;We need to put this on the Apple
TV!&quot;&lt;/p&gt;
&lt;p&gt;&quot;Yes!&quot; I thought. &quot;Yes! we do!&quot; We should have the power to behold the
Chillest Monkey on an whim! And why stop with the TV? Shouldn&apos;t he be
on the Watch and the iPhone as well?&lt;/p&gt;
&lt;p&gt;I could almost feel the relief. &quot;ZOMG!&quot; I thought, &quot;My life would be
demonstrably better if this were the case.&quot;&lt;/p&gt;
&lt;h2 id=&quot;be-bold-and-mighty-forces-will-come-to-your-aid&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#be-bold-and-mighty-forces-will-come-to-your-aid&quot; aria-label=&quot;be bold and mighty forces will come to your aid permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Be bold, and mighty forces will come to your aid&lt;/h2&gt;
&lt;p&gt;The timing was fortititous: Apple TV support for React Native had
just &lt;a href=&quot;https://github.com/facebook/react-native/commit/c92ad5f6ae74c1d398c7cd93d5c4c50da0ca0430&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;landed on master only a few short weeks ago&lt;/a&gt;. Clearly this was
a sign from God that the moment to act was now. And indeed, with
powerful allies like Robert Deluca, and Amazon Prime Now, how could I
possibly fail?&lt;/p&gt;
&lt;p&gt;So after building &lt;code class=&quot;language-text&quot;&gt;react-native&lt;/code&gt; from master to get tvOS support, and
spending an afternoon with Rob hacking to make the chillest monkey layout
properly on the Apple TV screen..... and yet a few more hours fiddling
with XCode to install onto a physical device that Amazon had delivered
just minutes before, the mountain was summited. His face expanded in
animation to almost six feet across as the app opened up onto the
projection screen. The feeling of tranquil gratification was
palpable.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://media.giphy.com/media/rMN2jzHjzcO6k/giphy.gif&quot; alt=&quot;Gif demo of the Chillest Monkey Apple TV app&quot;&gt;&lt;/p&gt;
&lt;p&gt;It&apos;s so comforting for me to know now that he&apos;s there; to know that
all I have to do is pick up the Apple TV remote and conjure him with a
gesture. But what kind of citizen of humanity would I be if I hoarded his
boundless beneficence to myself?&lt;/p&gt;
&lt;p&gt;The Chillest Monkey should be for &lt;em&gt;anyone&lt;/em&gt;, and anybody that wants to
include him in their apps and share his bounty with their users should
be empowered to do so. That&apos;s why I created &lt;a href=&quot;https://www.npmjs.com/package/react-native-chillest-monkey&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;an extension&lt;/a&gt; that
allows you to do just that: embed this most chill of primates into &lt;em&gt;any&lt;/em&gt;
application, on &lt;em&gt;any&lt;/em&gt; device that React Native supports.&lt;/p&gt;
&lt;h2 id=&quot;hard-made-easy&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#hard-made-easy&quot; aria-label=&quot;hard made easy permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hard made easy&lt;/h2&gt;
&lt;p&gt;I glossed over a lot of the yaks that needed to be
shaved in order to achive the end result (and there were many). I
learned about tvOS. I learned a lot about React
Native and how to package components to share them between applications, but
learning was never the point. And it didn&apos;t feel anything remotely like
study. If anything, the sensation throughout was one of &lt;em&gt;lightening&lt;/em&gt; my load,
even as I was in the act of lugging a yard full of knowledge onto the ship.&lt;/p&gt;
&lt;p&gt;And how about that?!? You trade in your worries and in exchange you
receive new insights and skills. Now &lt;em&gt;that&lt;/em&gt; seems like a good
transaction if I ever heard of one... an arbitrage of the spirit you
might say. Now remind me why I don&apos;t do this more often?&lt;/p&gt;
&lt;p&gt;I don&apos;t think I&apos;ll need reminding of it in the future though. I also
hope that whether it&apos;s using the Chillest Monkey in your own apps or
something different altogether, you do something silly soon; something
for which the payoff is dubious, but the downside doesn&apos;t exist.&lt;/p&gt;
&lt;p&gt;I did, and it felt stupendous.&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;I’m Charles Lowell (&lt;a href=&quot;https://twitter.com/cowboyd&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@cowboyd&lt;/a&gt; on twitter), and I build UI for a living at &lt;a href=&quot;http://frontside.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Frontside&lt;/a&gt;. If you enjoyed this, I’d love to hear from you.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/f7ad1245a99acd62791010701a06b7e6/b20de/2017-01-16-react-native-and-chill-a-tale-of-stupid-made-fast_monkey.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Building infinite scroll in React Native]]></title><description><![CDATA[Tackling infinite scroll can be hard on any platform. But thankfully React Native allows you to use base JavaScript libraries to solve problems in native apps. We're going to take Impagination.js and build an infinite scrolling list that is silky smooth and painless data management.]]></description><link>https://frontside.com/blog/2016-12-15-building-infinite-scroll-in-react-native/</link><guid isPermaLink="false">https://frontside.com/blog/2016-12-15-building-infinite-scroll-in-react-native/</guid><category><![CDATA[react native]]></category><category><![CDATA[react]]></category><category><![CDATA[infinite scroll]]></category><category><![CDATA[impagination]]></category><dc:creator><![CDATA[Robert DeLuca]]></dc:creator><pubDate>Thu, 15 Dec 2016 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In high school, I spent a long time trying to learn how to build iOS
apps. After many months of attempting what seemed impossible at the time,
I decided to throw in the towel. So I gave up and to went to design,
which ultimately led to web work.&lt;/p&gt;
&lt;p&gt;That desire to build native mobile apps &lt;em&gt;never&lt;/em&gt; went away for me. But learning
an entirely new language and ecosystem wasn&apos;t something that I could do
in my spare time. So when React Native busted onto the scene in 2015
it caught my attention. Since it&apos;s written in JavaScript, React Native
allows you (the JS dev) to use technologies you&apos;re already familiar
with to build truly native apps.&lt;/p&gt;
&lt;p&gt;Around the same time at The Frontside we started to write most of
our libraries in pure JavaScript. This allowed us to wrap those libraries in
whatever framework we happened to be working in at the time. That means
we can take problems we&apos;ve solved in Ember apps and use them in a React Native
project. Which is exactly what we&apos;re going to do today!&lt;/p&gt;
&lt;h3 id=&quot;introduction&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#introduction&quot; aria-label=&quot;introduction permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Introduction&lt;/h3&gt;
&lt;p&gt;The purpose of this post is to build an infinite scroll component for
React Native based
on
&lt;a href=&quot;https://github.com/flexyford/impagination&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Impagination.js&lt;/a&gt;. We&apos;ll
talk more about Impagination a little later but for now, just know
Impagination is a lazy data layer for your paged records.&lt;/p&gt;
&lt;p&gt;We&apos;re also going to lean on &lt;a href=&quot;http://nativebase.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;NativeBase&lt;/a&gt; for
nice prestyled native looking components. If you&apos;re coming from the
web think of NativeBase like Bootstrap. The main difference is the
styling will be tailored to the OS running the app. So in iOS, you&apos;re going
to get iOS styled elements and in Android, you&apos;ll get Android styled
elements.&lt;/p&gt;
&lt;p&gt;The API we will be using is a Rails app that returns paginated data
which is generated from the &lt;a href=&quot;https://github.com/stympy/faker&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;faker&lt;/a&gt;
gem. Impagination will work with any paginated API, so if you would
like you can sub in your own API here.&lt;/p&gt;
&lt;p&gt;Here&apos;s an iOS screenshot of what we&apos;re going to build:&lt;/p&gt;
&lt;p&gt;&lt;img
src=&quot;/img/2016/12/15/building-infinite-scroll-in-react-native/impagination-react-native-ios.png&quot;
alt=&quot;iOS Screenshot of the app we will be building&quot;
style=&quot;width: 80%;&quot;
/&gt;&lt;/p&gt;
&lt;p&gt;You can also check out the repo for what we&apos;re &lt;a href=&quot;https://github.com/Robdel12/robotImpagination&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;going to
build here&lt;/a&gt;. If you
haven&apos;t set up React Native on your machine yet, you should take a moment
and do that. The getting started docs are a
&lt;a href=&quot;https://facebook.github.io/react-native/docs/getting-started.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;great resource.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To sum up our goals for this post into a list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduce Impagination&lt;/li&gt;
&lt;li&gt;Create the React Native app&lt;/li&gt;
&lt;li&gt;Create a component that will be shared in iOS and Android&lt;/li&gt;
&lt;li&gt;Use NativeBase for styling&lt;/li&gt;
&lt;li&gt;Create an Impagination dataset&lt;/li&gt;
&lt;li&gt;Render that dataset to the app screen&lt;/li&gt;
&lt;li&gt;Listen for scroll events to request new data&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;hello-impagination&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#hello-impagination&quot; aria-label=&quot;hello impagination permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hello Impagination&lt;/h3&gt;
&lt;p&gt;Before we start actually building our app I want to take second to
talk about Impagination. Like I said earlier, Impagination is a lazy
data layer for your paged records. All you provide Impagination is the
logic to fetch a single page, plus how many records you want it to
pre-fetch ahead of you. Impagination will handle the rest for you.&lt;/p&gt;
&lt;p&gt;Impagination is built using an event-driven immutable style and
has zero dependencies. That means you can use it anywhere that JS
can run! From the server to the client, it doesn&apos;t matter as long as
it&apos;s JS.&lt;/p&gt;
&lt;p&gt;There are two required attributes for creating an Impagination
dataset: &lt;code class=&quot;language-text&quot;&gt;fetch&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;pageSize&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;fetch&lt;/code&gt; is a function that will tell Impagination how to go get the
data you are requesting as you scroll through the infinite
list.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;pageSize&lt;/code&gt; is an integer that tells Impagination how many
records are in each page.&lt;/p&gt;
&lt;p&gt;Okay, that&apos;s enough of an introduction to Impagination. As we build
our app I will stop and explain more of Impagination as we build
the app.&lt;/p&gt;
&lt;h3 id=&quot;creating-the-app&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#creating-the-app&quot; aria-label=&quot;creating the app permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Creating the app&lt;/h3&gt;
&lt;p&gt;Let&apos;s start creating our React Native app! I&apos;m going to call this app
&lt;code class=&quot;language-text&quot;&gt;robotImpagination&lt;/code&gt; since the gem generating our fake data uses a bunch of
different robots for images. Feel free to name your app whatever you like.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;react-native init robotImpagination&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will create a hello world react native app. If you cd into that
directory and run &lt;code class=&quot;language-text&quot;&gt;react-native run-ios&lt;/code&gt; (or &lt;code class=&quot;language-text&quot;&gt;react-native
run-android&lt;/code&gt;) it should start the React Native packager, build the iOS
app, and launch the simulator.&lt;/p&gt;
&lt;p&gt;Now that we have confirmed that the app will build, shut it all
down. We need to install a couple dependencies to build our infinite scroll.
Let&apos;s install NativeBase first: &lt;code class=&quot;language-text&quot;&gt;yarn add native-base&lt;/code&gt;.
Then Impagination: &lt;code class=&quot;language-text&quot;&gt;yarn add impagination&lt;/code&gt;. You should now
see both of those libraries in your &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; file.&lt;/p&gt;
&lt;h3 id=&quot;no-place-like-home&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#no-place-like-home&quot; aria-label=&quot;no place like home permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;No place like Home&lt;/h3&gt;
&lt;p&gt;Make your way to the &lt;code class=&quot;language-text&quot;&gt;index.ios.js&lt;/code&gt; (or &lt;code class=&quot;language-text&quot;&gt;index.android.js&lt;/code&gt; if you&apos;re
doing android dev). You should see a couple imports and then a class
that&apos;s extending &lt;code class=&quot;language-text&quot;&gt;Component&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;robotImpagination&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;View style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;container&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;welcome&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          Welcome to React Native&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instructions&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          To &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; started&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; edit index&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;android&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instructions&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          Double tap &lt;span class=&quot;token constant&quot;&gt;R&lt;/span&gt; on your keyboard to reload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;\n&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          Shake or press menu button &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; dev menu
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;View&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Delete everything inside of the render method. We&apos;re going to replace
that with a &lt;code class=&quot;language-text&quot;&gt;&amp;lt;Home /&gt;&lt;/code&gt; component. This component will be used in both
the &lt;code class=&quot;language-text&quot;&gt;index.ios.js&lt;/code&gt; &amp;#x26; &lt;code class=&quot;language-text&quot;&gt;index.android.js&lt;/code&gt; files.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;robotImpagination&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Home &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you tried to run this right now, it wouldn&apos;t work. We still need to
create that component and import it. For smaller projects, I like to
put my components in a &lt;code class=&quot;language-text&quot;&gt;components&lt;/code&gt; folder. You can name it and place
it where ever you would like. For me it&apos;s &lt;code class=&quot;language-text&quot;&gt;components&lt;/code&gt; in the root of the
project: &lt;code class=&quot;language-text&quot;&gt;robotImpagination/components/Home.js&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Inside of &lt;code class=&quot;language-text&quot;&gt;Home.js&lt;/code&gt; we should import React, the &lt;code class=&quot;language-text&quot;&gt;Text&lt;/code&gt; component from
React Native, and create a component that returns &quot;Hello!&quot;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Component &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Text &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react-native&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we&apos;ve actually created the &lt;code class=&quot;language-text&quot;&gt;&amp;lt;Home /&gt;&lt;/code&gt; component we can import
and use it in both of our index files (&lt;code class=&quot;language-text&quot;&gt;index.ios.js&lt;/code&gt; &amp;#x26; &lt;code class=&quot;language-text&quot;&gt;index.android.js&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Your index files should look something like this now:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Component &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  AppRegistry&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react-native&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Home &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./components/Home&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;robotImpagination&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Home &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

AppRegistry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;robotImpagination&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; robotImpagination&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Awesome! If you refresh your simulator you should now see a poorly styled
&quot;Hello!&quot;.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;Home /&gt;&lt;/code&gt; will be the main component we will be working out
of. This is so our code will run on both iOS &amp;#x26; Android. Write once,
compile to both!&lt;/p&gt;
&lt;h3 id=&quot;furnishing-our-home&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#furnishing-our-home&quot; aria-label=&quot;furnishing our home permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Furnishing our Home&lt;/h3&gt;
&lt;p&gt;We now have an app that&apos;s uglier than what we started with. Don&apos;t
fret, we&apos;re going to call on NativeBase to make everything look nice
and clean. Inside of &lt;code class=&quot;language-text&quot;&gt;Home.js&lt;/code&gt; lets import four components:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Native base for nice prestyled components&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  Header&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Container&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Title&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;native-base&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These components will provide the structure &amp;#x26; styling going forward. I
recommend taking 10 minutes to review
the &lt;a href=&quot;http://nativebase.io/docs/v0.5.13/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;NativeBase docs&lt;/a&gt;. Now we can
make our lonely &quot;Hello!&quot; text look much better:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// imports here&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Robot Impagination&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This should give you a styled header with bold text inside of it and our
&quot;Hello!&quot; text isn&apos;t in the very top left of the device. Nice!&lt;/p&gt;
&lt;p&gt;Next, we should create at least one &quot;card&quot; where we will be rendering the
content of each record into. Later on we will iterate over an array
returning many of these, but for now, we&apos;re only going to create one card.&lt;/p&gt;
&lt;p&gt;Thankfully we don&apos;t have to style this ourselves since NativeBase has
a
&lt;a href=&quot;http://nativebase.io/docs/v0.5.13/components#card&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;card component&lt;/a&gt;. We
need to import two more components from NativeBase:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Native base for nice prestyled components&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  Header&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Container&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Title&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Card&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  CardItem
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;native-base&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And additionally the &lt;code class=&quot;language-text&quot;&gt;Image&lt;/code&gt; component from &lt;code class=&quot;language-text&quot;&gt;react-native&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  Image&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react-native&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we have access to these components lets fill it in:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// imports here&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Robot Impagination&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Card style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Image style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;resizeMode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cover&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; source&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://placekitten.com/640/440&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Item description&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Card&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our app should look something like this:&lt;/p&gt;
&lt;p&gt;&lt;img
src=&quot;/img/2016-12-15-building-infinite-scroll-in-react-native_card-component-ios-screenshot.png&quot;
alt=&quot;iOS Screenshot of the new card component styling&quot;
style=&quot;width: 80%;&quot;
/&gt;&lt;/p&gt;
&lt;p&gt;We have a nicely styled app with styled cards, lets start scrolling through
paginated data!&lt;/p&gt;
&lt;h3 id=&quot;creating-an-impagination-dataset&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#creating-an-impagination-dataset&quot; aria-label=&quot;creating an impagination dataset permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Creating an Impagination dataset&lt;/h3&gt;
&lt;p&gt;The first thing we have to do is import Impagination into &lt;code class=&quot;language-text&quot;&gt;Home.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Dataset &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;impagination&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now create a method called &lt;code class=&quot;language-text&quot;&gt;setupImpagination&lt;/code&gt; inside of our Home
component. &lt;code class=&quot;language-text&quot;&gt;setupImpagination&lt;/code&gt; is where we&apos;re going to create a new
instance of Impagination, set the pageSize, and set the dataset on the
components local state. Earlier I mentioned that there are two
required params from Impagination to work. Let&apos;s start by filling in
those two params.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; dataset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Dataset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;pageSize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Where to fetch the data from.&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;pageOffset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pageSize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stats&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://serene-beach-38011.herokuapp.com/api/faker?page=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;pageOffset &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;per_page=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;pageSize&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;fetch&lt;/code&gt; function is where Impagination will hit your API to get
more pages. There are three arguments passed to the fetch function:
&lt;code class=&quot;language-text&quot;&gt;pageOffset&lt;/code&gt; which is the current page it&apos;s going to fetch, &lt;code class=&quot;language-text&quot;&gt;pageSize&lt;/code&gt;
which is a number of records in a page, and &lt;code class=&quot;language-text&quot;&gt;stats&lt;/code&gt; which can hold
&lt;code class=&quot;language-text&quot;&gt;totalPages&lt;/code&gt; if your API supports it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; you may need to add one to &lt;code class=&quot;language-text&quot;&gt;pageOffset&lt;/code&gt; since it&apos;s zero
based.&lt;/p&gt;
&lt;p&gt;This looks great! But we still have some work to do in order for it to
work. We currently have no way of accessing the data that is emitted by
Impagination.&lt;/p&gt;
&lt;p&gt;Impagination has two different objects you will work with. One is
&lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt; which holds all of the current records and the current state
regarding that data. The other is the &lt;code class=&quot;language-text&quot;&gt;dataset&lt;/code&gt; which allows you to
call Impagination methods like &lt;code class=&quot;language-text&quot;&gt;setReadOffset&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A new &lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt; is emitted every single time the data has changed. We can
listen for these changes using Impagination&apos;s &lt;code class=&quot;language-text&quot;&gt;observe&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; dataset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Dataset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;pageSize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Anytime there&apos;s a new state emitted, we want to set that on&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// the componets local state.&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;datasetState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;datasetState&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Where to fetch the data from.&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;pageOffset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pageSize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stats&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://serene-beach-38011.herokuapp.com/api/faker?page=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;pageOffset &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;per_page=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;pageSize&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we&apos;re
&lt;a href=&quot;https://facebook.github.io/react/docs/react-component.html#setstate&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;calling
&lt;code class=&quot;language-text&quot;&gt;setState&lt;/code&gt;&lt;/a&gt; we
have to create our state object in the component constructor:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;datasetState&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While we&apos;re here we&apos;ll also add &lt;code class=&quot;language-text&quot;&gt;dataset&lt;/code&gt; into our state object.&lt;/p&gt;
&lt;p&gt;To pull all of this together and start fetching data we need to set the
dataset on the components local state. Then we need to set the
&lt;code class=&quot;language-text&quot;&gt;readOffset&lt;/code&gt; to record &lt;code class=&quot;language-text&quot;&gt;0&lt;/code&gt;. This is so Impagination knows exactly what
record you are on when scrolling through the list. If we get close to
the end it will automatically fetch new records. You can read more
about &lt;a href=&quot;https://github.com/flexyford/impagination#load-horizon&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;how this all
works here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The final look of our &lt;code class=&quot;language-text&quot;&gt;setupImpagination&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; dataset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Dataset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;pageSize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Anytime there&apos;s a new state emitted, we want to set that on&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// the componets local state.&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;datasetState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;datasetState&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Where to fetch the data from.&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;pageOffset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pageSize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stats&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://serene-beach-38011.herokuapp.com/api/faker?page=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;pageOffset &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;per_page=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;pageSize&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Set the readOffset to the first record in the state&lt;/span&gt;
    dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setReadOffset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, as soon as the component starts to mount we want to setup our
data store. In &lt;code class=&quot;language-text&quot;&gt;componentWillMount&lt;/code&gt; lets call &lt;code class=&quot;language-text&quot;&gt;setupImpagination&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;componentWillMount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Bam! Now when the app loads it will go off and fetch the first 15
records from the API and set it on the local state of the
component. You can now access these records by doing
&lt;code class=&quot;language-text&quot;&gt;this.state.datasetState&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;looping-over-the-datasetstate&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#looping-over-the-datasetstate&quot; aria-label=&quot;looping over the datasetstate permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Looping over the datasetState&lt;/h3&gt;
&lt;p&gt;With the styling and data now in place lets render it to the
screen. &lt;code class=&quot;language-text&quot;&gt;this.state.datasetState&lt;/code&gt; is an array-like object. This means we can
iterate over the state while still being able to access getters like
&lt;code class=&quot;language-text&quot;&gt;this.state.datasetState.readOffset&lt;/code&gt; (which returns the current
&lt;code class=&quot;language-text&quot;&gt;readOffset&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;We&apos;re going to map over the Impagination &lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt; and return a card:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;componentWillMount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Robot Impagination&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;datasetState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Card style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Image style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;resizeMode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cover&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; source&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://placekitten.com/640/440&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Item description&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Card&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you refresh your simulator you should now see 15 kittens. But it&apos;s
15 cards with same text over and over again. We can start to pull
information from each record we&apos;re iterating over:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;componentWillMount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Robot Impagination&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;datasetState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Card style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Image style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;resizeMode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cover&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; source&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Card&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Refreshing your simulator should bring up an error message that says
&lt;code class=&quot;language-text&quot;&gt;Cannot read property &apos;title&apos; of null&lt;/code&gt;. This is because Impagination
emits an array with 15 items as soon as it&apos;s instantiated. Each record
in the array has five state properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;isRequested&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;isSettled&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;isPending&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;isResolved&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;isRejected&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these properties, we can tell exactly what state each record is
in. This allows us to display different UI for each individual record
if we please. In this case, we&apos;re going to show a loading spinner if
the record hasn&apos;t settled yet.&lt;/p&gt;
&lt;p&gt;Import the spinner component from NativeBase:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Native base for nice prestyled components&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  Header&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Container&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Title&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Card&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  CardItem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Spinner&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;native-base&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then add a conditional inside the map function that returns different
JSX:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;componentWillMount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Robot Impagination&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;datasetState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isSettled&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Spinner key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Card style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cardContainer&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Image style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;resizeMode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cover&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; source&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Card&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is great! It now will render each record with their own
content. But it&apos;s pretty hard to read that &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt; method, we should
refactor the card into its own presentation component. Create another
component in the &lt;code class=&quot;language-text&quot;&gt;components&lt;/code&gt; folder called &lt;code class=&quot;language-text&quot;&gt;RobotItem.js&lt;/code&gt;. Then copy
and paste the card component code from &lt;code class=&quot;language-text&quot;&gt;Home.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Component &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  Text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Image&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react-native&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  Card&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  CardItem&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;native-base&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RobotItem&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recordData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Card style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recordData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Image style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;resizeMode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cover&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; source&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recordData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recordData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CardItem&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Card&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also create a little shorthand in the constructor so we don&apos;t have
to type &lt;code class=&quot;language-text&quot;&gt;this.props.record.content&lt;/code&gt; each time we have to access
data.&lt;/p&gt;
&lt;p&gt;There&apos;s still a little bit of refactoring left in &lt;code class=&quot;language-text&quot;&gt;Home.js&lt;/code&gt;. We&apos;re
going to pull the map out of the render function and put it into its
own method called &lt;code class=&quot;language-text&quot;&gt;renderItem&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;componentWillMount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;renderItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;datasetState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isSettled&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Spinner key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;RobotItem record&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Robot Impagination&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Don&apos;t forget to prune the imports we&apos;re no longer using at the top of
&lt;code class=&quot;language-text&quot;&gt;Home.js&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;putting-the-infinite-in-scroll&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#putting-the-infinite-in-scroll&quot; aria-label=&quot;putting the infinite in scroll permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Putting the &quot;infinite&quot; in scroll&lt;/h3&gt;
&lt;p&gt;We&apos;re so close! It&apos;s now rendering all 15 items in our first page but
we&apos;re not able to scroll to the bottom and retrieve new records. Why?
It&apos;s because as we scroll we have to set Impagination&apos;s
&lt;code class=&quot;language-text&quot;&gt;readOffset&lt;/code&gt;. Basically, we have to tell Impagination which record is
currently being viewed by the user.&lt;/p&gt;
&lt;p&gt;As we progress through the list of records Impagination will fetch more pages
if &lt;a href=&quot;https://github.com/flexyford/impagination#load-horizon&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;we&apos;re within the &lt;code class=&quot;language-text&quot;&gt;loadHorizon&lt;/code&gt;.&lt;/a&gt;
By default, the &lt;code class=&quot;language-text&quot;&gt;loadHorizon&lt;/code&gt; is the same as the page size. This means
Impagination is constantly keeping track of where we&apos;re at so it can
smartly fetch new records as needed. If you up the &lt;code class=&quot;language-text&quot;&gt;loadHorizon&lt;/code&gt; to 30
it&apos;ll load even more pages ahead of the current scroll position.&lt;/p&gt;
&lt;p&gt;In order to set the &lt;code class=&quot;language-text&quot;&gt;readOffset&lt;/code&gt; we&apos;re going to hook into the
&lt;code class=&quot;language-text&quot;&gt;onScroll&lt;/code&gt; event on the &lt;code class=&quot;language-text&quot;&gt;&amp;lt;Content&gt;&lt;/code&gt; component. The &lt;code class=&quot;language-text&quot;&gt;&amp;lt;Content&gt;&lt;/code&gt;
component descends from React Natives &lt;code class=&quot;language-text&quot;&gt;ScrollView&lt;/code&gt; component, so if
you&apos;re not using NativeBase you can still use this same method.&lt;/p&gt;
&lt;p&gt;Let&apos;s create a method called &lt;code class=&quot;language-text&quot;&gt;setCurrentReadOffset&lt;/code&gt; and then call that
anytime the scroll event is called.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;componentWillMount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;renderItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function-variable function&quot;&gt;setCurrentReadOffset&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Log the current scroll position in the list in pixels&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nativeEvent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contentOffset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Robot Impagination&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Content onScroll&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;setCurrentReadOffset&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you refresh your simulator, enable remote JS debugging, scroll the
list, and then look in the JS console you should see a bunch of logs
with numbers. This is the current scroll position of the list in
pixels. We&apos;re going to use &lt;code class=&quot;language-text&quot;&gt;contentOffset.y&lt;/code&gt; to help calculate what
record we&apos;re seeing in the viewport.&lt;/p&gt;
&lt;p&gt;Since this list is rendering items with the &lt;em&gt;exact&lt;/em&gt; same height each
time it&apos;s pretty easy for us to figure out what item is currently
scrolled into view. You take the &lt;code class=&quot;language-text&quot;&gt;currentOffset.y&lt;/code&gt; and divide it by the
items height. That&apos;s your current &lt;code class=&quot;language-text&quot;&gt;readOffset&lt;/code&gt; (aka the current record
in view).&lt;/p&gt;
&lt;p&gt;Finally, we should throttle the amount of times &lt;code class=&quot;language-text&quot;&gt;setCurrentReadOffset&lt;/code&gt;
is called. As of right now it&apos;s called every single time there&apos;s a
scroll event, which is extremely noisy. We&apos;ll cut this down by
setting &lt;code class=&quot;language-text&quot;&gt;scrollEventThrottle&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;300&lt;/code&gt; (ms).&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;componentWillMount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;renderItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function-variable function&quot;&gt;setCurrentReadOffset&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; itemHeight &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;402&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; currentOffset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nativeEvent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contentOffset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; currentItemIndex &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ceil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;currentOffset &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; itemHeight&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setReadOffset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;currentItemIndex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Robot Impagination&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Content scrollEventThrottle&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; onScroll&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;setCurrentReadOffset&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Go ahead, refresh your simulator and scroll through that list! The API
only has 100 records seeded to the DB so don&apos;t expect it to be
&lt;em&gt;truly&lt;/em&gt; infinite. Here&apos;s a GIF of what we&apos;ve built together:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/2016/12/15/building-infinite-scroll-in-react-native/finished-robotImpagination-app.gif&quot; alt=&quot;GIF demo of the app we just built together&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-ZjTOxpVwQfY/VapQ75EsTAI/AAAAAAAABd4/7KWaSGgYWtQ/s1600/image002.gif&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;It&apos;s so beautiful.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;one-last-optimization&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#one-last-optimization&quot; aria-label=&quot;one last optimization permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;One last optimization&lt;/h3&gt;
&lt;p&gt;Using a &lt;code class=&quot;language-text&quot;&gt;ScrollView&lt;/code&gt; for something that is truly infinate might not be
the best idea but you can add one property to the &lt;code class=&quot;language-text&quot;&gt;ScrollView&lt;/code&gt;
significantly cut the memory usage: &lt;code class=&quot;language-text&quot;&gt;removeClippedSubviews&lt;/code&gt;. Since
NativeBase&apos;s &lt;code class=&quot;language-text&quot;&gt;Content&lt;/code&gt; component is backed by a &lt;code class=&quot;language-text&quot;&gt;ScrollView&lt;/code&gt; we can
use this same property. &lt;code class=&quot;language-text&quot;&gt;removeClippedSubviews&lt;/code&gt; will take the off
screen cards and remove them from the native backing superview.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Home&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setupImpagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;componentWillMount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;renderItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function-variable function&quot;&gt;setCurrentReadOffset&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//... }&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Robot Impagination&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Title&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Header&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Content scrollEventThrottle&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; onScroll&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;setCurrentReadOffset&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; removeClippedSubviews&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Content&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Container&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;First off, great job! You have just built infinite scroll in React
Native from scratch, which isn&apos;t an easy task. In about an hour we were
able to take a library that was originally written to solve a problem
in Ember.js and apply it to a React Native Project.&lt;/p&gt;
&lt;p&gt;I think this speaks volumes about the power of writing libraries in
plain old JavaScript. Not only can this library be used in any type
JavaScript project, it will have access to a broader community. This is because
any JavaScript developer can jump in and contribute back to the
project.&lt;/p&gt;
&lt;p&gt;For me, this means I can finally realize my childhood dream of building
an iOS app. I don&apos;t have to relearn an entire development
ecosystem. Sure you&apos;ll have to learn new things about native
development but the barrier to entry is tremendously lower.&lt;/p&gt;
&lt;p&gt;Here&apos;s my hot take on where React Native fits into the JS ecosystem.
React Native has hit the sweet spot that Cordova and PhoneGap has been
trying to hit for years: you can write native apps in JavaScript with
no performance implications. As we’ve seen, it’s easy to share the
same JavaScript libraries from the web and node (if that’s your
thing), to your native app. Now that’s amazing.&lt;/p&gt;
&lt;p&gt;Web developers have been trying to recreate &quot;that native experience&quot; in
the browser for years. But here&apos;s the thing: native is a moving
target. So if you can&apos;t keep up, why not join them? But join them with
your existing JavaScript knowledge. Sounds like the best of both
worlds to me!&lt;/p&gt;
&lt;p&gt;Once again if you would like to take a look at the completed app &lt;a href=&quot;https://github.com/Robdel12/robotImpagination&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&apos;s
the GitHub repo.&lt;/a&gt; If
you have any questions, comments, or feedback I&apos;m always available on
&lt;a href=&quot;https://twitter.com/robdel12&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Twitter @robdel12&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.hutui6.com/atom-wallpapers/67525236.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Image credit&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/92286829eefe2ccc5def3aff56b4c1f7/4fe8c/2016-12-15-building-infinite-scroll-in-react-native_react-native-header.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[The Ruby DCamp Experience]]></title><link>https://frontside.com/blog/2016-10-27-the-ruby-dcamp-experience/</link><guid isPermaLink="false">https://frontside.com/blog/2016-10-27-the-ruby-dcamp-experience/</guid><category><![CDATA[ruby]]></category><category><![CDATA[dcamp]]></category><category><![CDATA[programming]]></category><category><![CDATA[inclusiveness]]></category><dc:creator><![CDATA[Stephanie Riera]]></dc:creator><pubDate>Thu, 27 Oct 2016 12:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;downfall-of-2016&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#downfall-of-2016&quot; aria-label=&quot;downfall of 2016 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Downfall of 2016&lt;/h2&gt;
&lt;p&gt;It&apos;s Fall season but with the current state of the world, it certainly feels like an extinction event is just around the corner. Clowns, Hurricane Matthew, and our country&apos;s infamous election has created a cold front of fear. Our social media feeds have been inundated in divisiveness and negativity. In the midst of this dark season, I had registered for Ruby DCamp and was ecstatic to disconnect from it all and attend my first DCamp experience.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://rubydcamp.org/about.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Ruby DCamp&lt;/a&gt; (@ruby_dcamp) is a 3 day programming unconference in the forest where roughly 72 web developers from everywhere meet to bond over code and much more. Evan Light (@elight), a developer himself, founded the retreat dedicated to &quot;&lt;em&gt;knowledge, connection, and compassion&lt;/em&gt;&quot; back in 2008. DCamp has been going strong ever since.&lt;/p&gt;
&lt;h2 id=&quot;a-time-to-retreat&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-time-to-retreat&quot; aria-label=&quot;a time to retreat permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A time to retreat&lt;/h2&gt;
&lt;p&gt;It all takes place in Prince William Forest Park located one hour south of Washington D.C. tucked away in Virginia. The forest is part of the U.S. National Park Service with several campgrounds and trails to hike. If you&apos;re a nature enthusiast, you&apos;ll find the vegetation breathtaking and its lack of noise immediately calms the soul.&lt;/p&gt;
&lt;figure alt=&quot;Outside the mess hall cabin&quot;&gt;
&lt;img src=&quot;/img/2016-10-27-the-ruby-dcamp-experience_cabins.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Attendees lodge in one of the several wooden cabins that were built in the 1930&apos;s and spend most of the day convened in the mess hall. The day&apos;s activities take place in the mess hall which also has a large kitchen. Everyone pitches in with cooking and cleaning, it&apos;s essentially communal living. There is no wifi and cellphone signal is spotty which makes you feel truly disconnected from the outside world.&lt;/p&gt;
&lt;h2 id=&quot;the-lone-developer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-lone-developer&quot; aria-label=&quot;the lone developer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The lone developer&lt;/h2&gt;
&lt;p&gt;In a competitive industry of &quot;fake it til you make it&quot; and &quot;&lt;em&gt;Whoa&lt;/em&gt;, you&apos;ve never heard of Yarn?! &lt;em&gt;Wow&lt;/em&gt;, ok, uhm....&quot;- the act of speaking openly can feel awkward. People new to programming can feel intimidated attending hackathons or meetups and while they attempt to network, ultimately one feels like they&apos;re on this journey alone. Non junior developers can also relate to the isolation, simply ask them to write a blog post about the &lt;a href=&quot;https://hackernoon.com/how-it-feels-to-learn-javascript-in-2016-d3a717dd577f#.smenog2ag&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;current state of JavaScript&lt;/a&gt;. The interwebz has no chill.&lt;/p&gt;
&lt;p&gt;Learning to program is hard as it is and it doesn&apos;t need to be complicated by the inability to speak openly about fears of living up to expectations, handling imposter syndrome, or simply admitting what you know and don&apos;t know which is crucial for learning. DCamp actively fosters an environment that embraces vulnerability, which enables everyone to be sincere with one another. This habitat produces some deep conversations that make you realize, no, you&apos;re not alone. DCamp is essentially a sanctuary where you can exist and grow in an inclusive environment.&lt;/p&gt;
&lt;h2 id=&quot;code-dialogue-and-playtime&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#code-dialogue-and-playtime&quot; aria-label=&quot;code dialogue and playtime permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Code, dialogue, and playtime&lt;/h2&gt;
&lt;p&gt;The excitement is palpable on day one between the bustle of new attendees getting settled in and old friends coming together. Although DCamp is centered around the Ruby programming language, not all developers use Ruby as their primary language or even know it. The group is a diverse bunch with a spectrum of developers from junior to 20+ years experience. On day one, a coding challenge is explained and you are given 15 minutes to pair with a stranger and see how far you can get. The catch is, after the time is up, you have to clear your code, find a new partner and start again. The objective is not to finish the challenge but to see the different ways one can architect the solution.&lt;/p&gt;
&lt;figure alt=&quot;Outside the mess hall cabin&quot;&gt;
&lt;img src=&quot;/img/2016-10-27-the-ruby-dcamp-experience_wall.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;The sessions were fun icebreakers and some of us found ourselves leaning on our JavaScript expertise or other languages to accomplish the same goal. Breaks, lunch, and dinner split the pairing sessions and before you know it, day one has passed. Day two and three are centered around unconference talks. That means the attendees themselves lead 45 minute discussions around topics of their choosing. Topics are posted on the main wall of the cabin, and you can cast 3 votes for your favorite talks.&lt;/p&gt;
&lt;p&gt;The topics with the highest number of votes are selected and a schedule for the day is born. The talks are split equally between technical topics and nontechnical (people). Some of the technical talks focused on Ruby, Elixir, JavaScript, and sharing resources like websites, books, and podcasts. The nontechnical discussions varied from advice on pair programming, how to get your first programming job, to dealing with contempt culture.&lt;/p&gt;
&lt;figure alt=&quot;Outside the mess hall cabin&quot;&gt;
&lt;img src=&quot;/img/2016-10-27-the-ruby-dcamp-experience_advice.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;It was humbling to sit in a circle of developers that admitted their struggle with accepting a compliment or shared the feeling of perpetual confusion and discomfort with programming. These sessions helped me see that we all share the same fears and that we all want a sense of belonging. Largely ignored, Ada Lovelace&apos;s published work fell on deaf ears until a century later when Turing rediscovered it. I sometimes wonder what technological advances we&apos;d have today if both Lady Lovelace and Alan Turing had been accepted as people and had lived out their lives to old age.&lt;/p&gt;
&lt;p&gt;If you feel accepted and safe to contribute in your team, you&apos;ll be less likely to avoid pushing code because you&apos;re embarrassed or fear someone making fun of your code or you as a developer. On the contrary, you should be sharing your code (no matter the quality), so that you can receive the feedback that will help you grow.&lt;/p&gt;
&lt;p&gt;After dinner, the board and card games came out. There&apos;s nothing better than blowing off steam over some intense Secret Hitler and Werewolf games next to the fireplace. I enjoyed playing games but I ended up spending the last night from 8 pm til 3 am trying to solder a NodeMCU with built in Wifi that you can program in JavaScript, Python, or Lua. Mind you, I know nothing about hardware and have never soldered in my life.&lt;/p&gt;
&lt;figure alt=&quot;Outside the mess hall cabin&quot;&gt;
&lt;img src=&quot;/img/2016-10-27-the-ruby-dcamp-experience_hardware.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;It was amazing to see everyone sharing tools, collaborating, and teaching each other concepts they&apos;d just learned. Shout out to Lance Gleason (@lgleasain) for purchasing &amp;#x26; traveling with all the kits and tools for everyone to play with. &lt;em&gt;Note to self:&lt;/em&gt; don&apos;t solder when it&apos;s 3 am, you&apos;ll find all the incorrect ways to attach wires in your exhausted stupor.&lt;/p&gt;
&lt;h2 id=&quot;mindfulness&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#mindfulness&quot; aria-label=&quot;mindfulness permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Mindfulness&lt;/h2&gt;
&lt;p&gt;One of my favorite aspects of the retreat was the focus on mindfulness. Everyday before starting the main activities, Evan would lead a short meditation. Pausing to take a moment to reflect, take a breath, and wish those around you well can sound corny but don&apos;t shoot it down if you haven&apos;t tried it. Studies have shown the benefits of meditation and I&apos;ve seen first hand how a room of 72+ people can reach a state of relaxation you never knew was possible without music or drugs.&lt;/p&gt;
&lt;figure alt=&quot;Outside the mess hall cabin&quot;&gt;
&lt;img src=&quot;/img/2016-10-27-the-ruby-dcamp-experience_notes.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Spreading kindness, having empathy, and being self aware of our actions can make all the difference not only in your team but in how you interact with the world. If you&apos;re unaware of your facial expressions or tone of voice, you might not realize you&apos;re making someone inferior when you had no intention of doing so.&lt;/p&gt;
&lt;p&gt;These moments of reflection helped me realize several things, one of which I&apos;ll share. An app essential for work communication like Slack actually hinders my productivity and  I&apos;d like to limit similar distractions in my life. I estimated (personally) 40% of conversations are of substance and the other 60% is just noise. I now check it when I get a ping but no longer go to it when I&apos;m bored or stuck on a bug. I catch myself when I&apos;m about to waste time going to Slack or Twitter, you&apos;d be surprised to know it happens more often than you think.&lt;/p&gt;
&lt;figure alt=&quot;Outside the mess hall cabin&quot;&gt;
&lt;img src=&quot;/img/2016-10-27-the-ruby-dcamp-experience_outside.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;During the end of my retreat I was full of these mini epiphanies and felt mentally refreshed. I gained new experiences, interpersonal skills, and technical knowledge. Best of all, I made friends that were strangers merely a couple days before. People were tweeting about returning to real life as if they&apos;d just left Burning Man. DCamp has left a beautiful memory in my heart and I hope every developer gets the opportunity to experience it at least once.&lt;/p&gt;
&lt;p&gt;I’m Stephanie Riera, I build web applications for a living at The Frontside, you can find me on Twitter (@stefriera). If you enjoyed this, I’d love to hear from you.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/8aefde2d15af2d6c4f8e5aba1ec1dd94/4fe8c/2016-10-27-the-ruby-dcamp-experience_outside.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[The Conjoined Triangles of Senior-Level Development]]></title><link>https://frontside.com/blog/2016-07-07-the-conjoined-triangles-of-senior-level-development/</link><guid isPermaLink="false">https://frontside.com/blog/2016-07-07-the-conjoined-triangles-of-senior-level-development/</guid><category><![CDATA[hiring]]></category><category><![CDATA[senior developers]]></category><category><![CDATA[frontside]]></category><dc:creator><![CDATA[Brandon Hays]]></dc:creator><pubDate>Thu, 07 Jul 2016 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2016-07-07-the-conjoined-triangles-of-senior-level-development_sv-conjoined.jpg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Stephen Tobolowsky expalining the cojoined triangles&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;em&gt;My man Stephen Tobolowsky lays down the conjoined triangles.&lt;/em&gt;&lt;/div&gt;
&lt;h3 id=&quot;this-actually-makes-me-feel-less-confident-about-my-role-here-if-we-cant-define-what-we-think-senior-is-how-am-i-supposed-to-know-if-im-working-toward-it&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#this-actually-makes-me-feel-less-confident-about-my-role-here-if-we-cant-define-what-we-think-senior-is-how-am-i-supposed-to-know-if-im-working-toward-it&quot; aria-label=&quot;this actually makes me feel less confident about my role here if we cant define what we think senior is how am i supposed to know if im working toward it permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&quot;This actually makes me feel less confident about &lt;em&gt;my&lt;/em&gt; role here. If we can’t define what we think senior is, how am I supposed to know if I’m working toward it?&quot;&lt;/h3&gt;
&lt;p&gt;At Frontside, we gather every Tuesday afternoon for our company meeting, where we talk through our accomplishments and plans for the coming week.&lt;/p&gt;
&lt;p&gt;In a recent meeting, we talked about our search for a senior developer to join the team, and you could see passions flare. No decision we can make impacts the company quite like bringing on a new team member, so naturally we all had strong opinions about the qualifications we were looking for.&lt;/p&gt;
&lt;p&gt;However, &lt;em&gt;not one person&lt;/em&gt; in the room could crystallize our thoughts on what qualifies as “senior” above a general gut feeling.&lt;/p&gt;
&lt;p&gt;One person chimed in with the quote above, and I realized that we&apos;d stumbled onto one of the biggest problems in our entire company: &lt;strong&gt;we had no idea how to define the role we&apos;re trying to hire for and grow our developers toward.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-problem-of-defining-senior-developer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-problem-of-defining-senior-developer&quot; aria-label=&quot;the problem of defining senior developer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The problem of defining &quot;Senior Developer&quot;&lt;/h2&gt;
&lt;p&gt;For my part, I&apos;ve come to distrust the term &quot;Senior Developer&quot;, particularly after being given that title after 9 months of professional programming experience to fit into a salary band.&lt;/p&gt;
&lt;p&gt;In fact, &lt;strong&gt;if you ask two experienced developers to specify their definition of &quot;senior&quot;, I guarantee you will find serious conflicts between their answers.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The question of what qualifies as a “Senior Developer” is both context-dependent and so malleable that our industry squishes it into whatever shape fits their current needs.&lt;/p&gt;
&lt;p&gt;Here are some actual, real-world definitions I&apos;ve seen used to justify the label &quot;Senior Developer&quot;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;15+ years of programming experience&lt;/li&gt;
&lt;li&gt;2 years of programming experience and decent leverage&lt;/li&gt;
&lt;li&gt;1 year of experience in a hot new 1-year-old framework&lt;/li&gt;
&lt;li&gt;Having authored a technical book&lt;/li&gt;
&lt;li&gt;Writing Comp Sci algorithms on a whiteboard&lt;/li&gt;
&lt;li&gt;Writing an open source library used within the company&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&apos;s a pretty broad range of definitions. But lots of stuff in life is hard to define, so what&apos;s the problem?&lt;/p&gt;
&lt;h2 id=&quot;why-bother-defining-it-whats-wrong-with-a-gut-feeling&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-bother-defining-it-whats-wrong-with-a-gut-feeling&quot; aria-label=&quot;why bother defining it whats wrong with a gut feeling permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why bother defining it? What&apos;s wrong with a gut feeling?&lt;/h2&gt;
&lt;p&gt;In our meeting, when our team member pointed out their confusion, they were pointing out that we are hiring, firing, and promoting people based on criteria we can’t define or defend. They&apos;re right, that is &lt;em&gt;bananas&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Worse, we were &lt;em&gt;failing at our core mission&lt;/em&gt; of growing developers by not clearly marking the path we&apos;re trying to help them travel.&lt;/p&gt;
&lt;p&gt;There&apos;s another, larger problem with &quot;I&apos;ll know a senior developer when I see one&quot;: &lt;strong&gt;&quot;Senior Developer&quot; is a profoundly effective vector for bias.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;senior-developer-as-a-way-to-enshrine-bias&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#senior-developer-as-a-way-to-enshrine-bias&quot; aria-label=&quot;senior developer as a way to enshrine bias permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&quot;Senior Developer&quot; as a way to enshrine bias&lt;/h2&gt;
&lt;p&gt;When we picture a wise senior developer, we each have our own experiences and preferences that color this picture in for us. That means the term is already spring-loaded with a bunch of our own baggage.&lt;/p&gt;
&lt;p&gt;When we take a &quot;gut feeling&quot; sense of someone&apos;s seniority without specific criteria, there is basically no way to counteract our own biases, but we still make a judgement. &lt;strong&gt;It&apos;s completely possible for a person applying to multiple dev jobs to be evaluated as junior at one, mid-level at another, and even senior at another, with very little feedback as to why.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And as hiring managers, we all feel correct when making these judgements, even as we reach vastly different conclusions.&lt;/p&gt;
&lt;p&gt;The result is a reinforcement of existing biases that keeps some people from progressing, while resulting in &quot;title inflation&quot; for others. Since &lt;strong&gt;existing biases in tech are strongly and undeniably tilted toward white males&lt;/strong&gt;, the existing &quot;gut feeling&quot; system disproportionately harms women and people of color.&lt;/p&gt;
&lt;h2 id=&quot;why-havent-we-solved-this&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-havent-we-solved-this&quot; aria-label=&quot;why havent we solved this permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why haven&apos;t we solved this?&lt;/h2&gt;
&lt;p&gt;This definition is an extremely hard problem, since it&apos;s heavily dependent on the context of the work environment. Most business owners are just making this stuff up as they go along, and the solution we tend to wind up with seems to be &quot;good enough&quot;.&lt;/p&gt;
&lt;p&gt;There&apos;s also no incentive, because &lt;strong&gt;defining criteria takes a lot of the &quot;gut decision&quot; power away from founders/owners and adds accountability.&lt;/strong&gt; Who sits around asking for less power and more accountability for themselves?&lt;/p&gt;
&lt;h2 id=&quot;injecting-accountability&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#injecting-accountability&quot; aria-label=&quot;injecting accountability permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Injecting accountability&lt;/h2&gt;
&lt;p&gt;I like accountability. I take comfort in it. I&apos;ve learned that being held accountable for something is quite liberating. For instance, being clear about the criteria we use to hire someone leads to less regret than &quot;going with my gut&quot;, &lt;strong&gt;which can be affected by everything from someone&apos;s ability to riff on Simpsons quotes with me to whether I skipped breakfast that day.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Accountability also opens the door for improvement. As the hiring manager, I&apos;m responsible for fostering a safe, capable, happy, diverse team. Improving and working toward those goals can either happen by gut feelings and dumb luck, or we can define, measure, and hold ourselves accountable for iterating toward those goals.&lt;/p&gt;
&lt;p&gt;Accountability moves us from being passengers to drivers of our own future.&lt;/p&gt;
&lt;h2 id=&quot;it-starts-with-responsibilities&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#it-starts-with-responsibilities&quot; aria-label=&quot;it starts with responsibilities permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;It starts with responsibilities&lt;/h2&gt;
&lt;p&gt;The question becomes: &lt;strong&gt;How can we create and use quantifiable criteria for seniority without creating a deeply flawed, highly game-able system?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The only fair way I can think of to judge a candidate is asking a few key questions: &lt;em&gt;What are this person&apos;s responsibilities? How likely are they to be able to fulfill them? How much help will they need?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We started by defining our environment. When we examine the key attributes of the environment at Frontside, it starts to become clear:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Being small means that people need to take the lead in several roles to solve problems from start to finish. There are no &quot;cogs&quot; in this machine.&lt;/li&gt;
&lt;li&gt;We rely and build on the strength of our internal community and the larger communities we participate in, particularly in open source.&lt;/li&gt;
&lt;li&gt;We have extremely ambitious technical goals and standards for the maintainability and usability of the code we write.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The resulting responsibilities are then pretty easy to determine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Provide clear technical and project guidance for their teammates and our clients&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mentor, teach, and contribute internally and in larger programming communities&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ship software that is a joy to its users and to the developers who extend and maintain it&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, these responsibilities form the basis of the criteria we use to assess seniority.&lt;/p&gt;
&lt;h2 id=&quot;the-conjoined-triangles-the-simple-explanation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-conjoined-triangles-the-simple-explanation&quot; aria-label=&quot;the conjoined triangles the simple explanation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Conjoined Triangles: The simple explanation&lt;/h2&gt;
&lt;p&gt;I recently had a chance to dig into the definition of &quot;senior&quot; at a number of companies, large and small, and came away with only one common denominator.&lt;/p&gt;
&lt;p&gt;The simplest explanation of seniority across companies is this: &lt;strong&gt;How much direction will this person need, and how much will they be able to provide to others?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2016-07-07-the-conjoined-triangles-of-senior-level-development_conjoined.jpg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Graph that shows a linear relationship of what is provided by seniority&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;I stand by the Conjoined Triangles of Senior-Level Development as a nice idea, but like Action Jack’s &quot;Conjoined Triangles of Success&quot;, it’s enough of an oversimplification to shed its intrinsic meaning.&lt;/p&gt;
&lt;p&gt;Even with this understanding, the door is wide open to inject bias, miss important criteria, and overvalue higher-visibility things like public notoriety or the ability to speak computer science lingo.&lt;/p&gt;
&lt;h2 id=&quot;in-the-meeting-a-new-framework-emerges&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#in-the-meeting-a-new-framework-emerges&quot; aria-label=&quot;in the meeting a new framework emerges permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;In the meeting, a new framework emerges&lt;/h2&gt;
&lt;p&gt;A really cool thing happened during the heated meeting. As I was describing this simple &quot;unified field theory&quot;, another employee put forward a new mental model to organize our thinking around this.&lt;/p&gt;
&lt;p&gt;She described the framework we use to determine seniority at Frontside as a Venn diagram, the intersection of how well a person works independently and leads, how technically capable they are, and how well they connect and contribute to a larger community.&lt;/p&gt;
&lt;h2 id=&quot;the-venn-diagram-the-more-complex-explanation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-venn-diagram-the-more-complex-explanation&quot; aria-label=&quot;the venn diagram the more complex explanation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Venn diagram: The more complex explanation&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/2016-07-07-the-conjoined-triangles-of-senior-level-development_venn.jpg&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Venn diagram relating Connectendess, Technical Capability, and Leadership&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Our evaluation of seniority does, in fact, roll up to the higher definition: &lt;em&gt;“How much direction will this person need, and how much will they be able to provide to others?”&lt;/em&gt; But as our employees pointed out, when we stop there, there’s a ton of room for confusion.&lt;/p&gt;
&lt;p&gt;So how can we decide how well a candidate is likely to perform their responsibilities? &lt;strong&gt;How do we anchor our evaluation criteria to something concrete, without killing it by turning it into a mathematical formula?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When we boiled down what we’re looking for, we came away with 12 traits that divide pretty cleanly along those three areas of responsibility: &lt;strong&gt;technical capability&lt;/strong&gt;, &lt;strong&gt;leadership&lt;/strong&gt;, and &lt;strong&gt;community&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I&apos;ll break the 12 traits down in detail in the next post, but for now, we&apos;ll just hit the high points.&lt;/p&gt;
&lt;h2 id=&quot;the-tracks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-tracks&quot; aria-label=&quot;the tracks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The tracks&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Technical capability:&lt;/strong&gt; A person with high technical capability is technically curious, tackles problems without giving up, and produces solutions that less-experienced folks can use, maintain, and learn from.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Leadership:&lt;/strong&gt; A person with leadership skills knows how to develop and follow a sense of purpose, in themselves and in others. They are willing to point out, own, and fix things that are broken about our company and in their own career tracks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Community/Connectedness:&lt;/strong&gt; A person with community skills has a sense of being part of a larger whole, a desire to contribute, a sense that the other people (i.e. coworkers, users, clients) are not simply characters in his or her own movie, but fully-realized individuals.&lt;/p&gt;
&lt;h2 id=&quot;what-about-culture-fit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-about-culture-fit&quot; aria-label=&quot;what about culture fit permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about &quot;culture fit&quot;?&lt;/h2&gt;
&lt;p&gt;We initially almost called the Community &amp;#x26; Connectedness track “culture fit”, but I have come to be highly suspicious that this term is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Clich%C3%A9#Thought-terminating_clich.C3.A9&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;thought-terminating cliché&lt;/a&gt;. &lt;strong&gt;“Culture fit” is a junk drawer&lt;/strong&gt; for all the stuff you want to see in a developer that you can’t otherwise define, and it’s an ideal hiding place for intrinsic biases.&lt;/p&gt;
&lt;p&gt;When we defined the criteria that make Frontside’s culture unique, the common trait is the idea of connectedness as defined above.&lt;/p&gt;
&lt;h2 id=&quot;measuring-seniority-across-3-disparate-tracks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#measuring-seniority-across-3-disparate-tracks&quot; aria-label=&quot;measuring seniority across 3 disparate tracks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Measuring seniority across 3 disparate tracks&lt;/h2&gt;
&lt;p&gt;Remember the three areas, &lt;strong&gt;technical capability&lt;/strong&gt;, &lt;strong&gt;leadership&lt;/strong&gt;, and &lt;strong&gt;community&lt;/strong&gt;? Each of these tracks has a junior-to-senior path all its own.&lt;/p&gt;
&lt;p&gt;It’s now common for a person to switch careers and come out of a code bootcamp with seniority in leadership and connectedness, while being junior in technical capability. Conversely, a skilled, formally-trained technician may be missing experience in both leadership and connectedness.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Very few qualify as senior in all three categories.&lt;/strong&gt; In fact, &lt;em&gt;it&apos;s unlikely a person will even be interested&lt;/em&gt; in becoming senior in all three categories. At Frontside, we define seniority as a blend of these tracks and work to help people level up where they feel like they want to improve.&lt;/p&gt;
&lt;h2 id=&quot;artifacts-the-only-measuring-tape-youve-got&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#artifacts-the-only-measuring-tape-youve-got&quot; aria-label=&quot;artifacts the only measuring tape youve got permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Artifacts: The only measuring tape you&apos;ve got&lt;/h2&gt;
&lt;p&gt;The measure of seniority in each track requires evidence. If you&apos;ve done something, you likely have some kind of artifact as a result.&lt;/p&gt;
&lt;p&gt;The 12 traits we&apos;ll discuss in the next post each come with concrete artifacts a candidate can point to to show that yes, they have developed those traits over time and with practice.&lt;/p&gt;
&lt;p&gt;But taken as a whole, &lt;strong&gt;a couple of well-developed and deeply-practiced traits in an area are likely to qualify a person as senior in that area.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For instance, if a person can talk you through the code they&apos;ve written across various programming languages, they probably peg the &quot;curiosity&quot; trait pretty high. Combine that with the rigor to write thorough, high-quality tests for the majority of their projects and hook it up to Continuous Integration, you&apos;re probably looking at someone we&apos;d consider technically senior.&lt;/p&gt;
&lt;p&gt;Or, if someone has a long history of mentoring others, organizing meetups, or creating tools that make others&apos; lives easier, it&apos;s likely we&apos;d consider them senior on the community track.&lt;/p&gt;
&lt;p&gt;If a person has managed a few teams before, they have likely learned and developed processes to handle the very real challenges there. Combine that with the ability to get to the purpose or root of an issue, and you have someone we&apos;d call senior on the leadership track.&lt;/p&gt;
&lt;h2 id=&quot;how-we-define-senior&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-we-define-senior&quot; aria-label=&quot;how we define senior permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How we define &quot;Senior&quot;&lt;/h2&gt;
&lt;p&gt;Our measure is that if someone is senior on the technical track and either the leadership or community track, they&apos;re senior to us. We can help level them up on the remaining track if they want.&lt;/p&gt;
&lt;p&gt;If they&apos;re senior on the community and leadership side, we consider them senior if they are high-mid-level on the technical track.&lt;/p&gt;
&lt;p&gt;As a real-life example: About a year ago, we hired a new employee as a junior developer, because we knew on the technical side they needed a ton of direction for at least the first six months.&lt;/p&gt;
&lt;p&gt;At six months, they were solidly mid-level technically, and within their first year, by our estimation, they were already senior. I can say this with confidence because when they left, we realized that to fulfill their job functions, we&apos;d need to hire a senior developer.&lt;/p&gt;
&lt;p&gt;This happened because when they started with us, they were already senior on the community and leadership tracks, so &lt;strong&gt;all they needed was a boost on the technical side&lt;/strong&gt; to perform the job of a senior dev on our team.&lt;/p&gt;
&lt;h2 id=&quot;technical-skills-arent-enough&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#technical-skills-arent-enough&quot; aria-label=&quot;technical skills arent enough permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Technical skills aren&apos;t enough&lt;/h2&gt;
&lt;p&gt;For someone with technical skills but little experience in community or leadership, &lt;em&gt;&quot;You don&apos;t qualify as senior by our standards&quot;&lt;/em&gt; is not music to their ears. But for the job responsibilities they&apos;ll have with us, we would consider that person mid-level until we can help strengthen one or both of the remaining tracks for them.&lt;/p&gt;
&lt;p&gt;Many shops only measure along the technical axis, but it simply doesn&apos;t work for a company of our small size and collaborative work style. I also worry that those who only measure technical skill are buying into the dangerous &quot;lone genius developer&quot; myth, cheating the developer out of the serious boost they&apos;d gain by adding leadership or community-oriented skills to their technical savvy.&lt;/p&gt;
&lt;p&gt;Even in larger companies with more focused roles, &lt;strong&gt;I&apos;d like to see a broader definition of &quot;Senior Developer&quot; that encompasses the code and non-code skills we use&lt;/strong&gt; and that allow us to work effectively, particularly in teams and with real customers.&lt;/p&gt;
&lt;h2 id=&quot;how-long-does-it-take-to-become-senior&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-long-does-it-take-to-become-senior&quot; aria-label=&quot;how long does it take to become senior permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How long does it take to become senior?&lt;/h2&gt;
&lt;p&gt;Does “Senior developer” mean “X years of experience”? Well, I don&apos;t see it happening inside of 5 years for anyone. It would be difficult or impossible to develop the traits needed to reach senior-level in any of these tracks in less than several years, much less along multiple tracks.&lt;/p&gt;
&lt;p&gt;But “5 years of experience” doesn’t necessarily mean “5 years of software development experience”. A person who has already climbed the Leadership and/or Connectedness tracks need only hook that up to their increasing technical skills to provide a tremendous amount of value as a software developer.&lt;/p&gt;
&lt;p&gt;Our hiring &quot;secret sauce&quot; largely stems from the fact that &lt;strong&gt;it seems to take significantly less time for someone with leadership and community skills to develop technical skills than the other way around.&lt;/strong&gt; I&apos;m seeing a large number of people who graduated from code bootcamps 3 and even 2 years ago now handily and gracefully filling the role of senior developer.&lt;/p&gt;
&lt;h2 id=&quot;theres-more-to-discuss&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#theres-more-to-discuss&quot; aria-label=&quot;theres more to discuss permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;There&apos;s more to discuss&lt;/h2&gt;
&lt;p&gt;This leaves many questions unanswered. What are the specific artifacts we use to evaluate skills and traits in the three areas? How can you evaluate for these before and during an interview? How do we tie these evaluations to something as concrete as someone&apos;s salary?&lt;/p&gt;
&lt;p&gt;How does this framework apply to non-senior developers? How and when do developers advance? What&apos;s the difference between a Junior, Mid, and Senior? What exists between them? &lt;strong&gt;Are these terms devoid of meaning and in need of replacement?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lastly, how does this framework apply (if it applies at all) to other companies with vastly different cultures and needs from Frontside?&lt;/p&gt;
&lt;p&gt;In the next post, we&apos;ll dive into specifics to answer these.&lt;/p&gt;
&lt;h2 id=&quot;moving-past-gut-feelings&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#moving-past-gut-feelings&quot; aria-label=&quot;moving past gut feelings permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Moving past &quot;gut feelings&quot;&lt;/h2&gt;
&lt;p&gt;Defining &quot;senior&quot; is an ongoing and surprisingly difficult process, but we do it because it&apos;s business-critical for us. Without a clear definition of “senior developer&quot;, we have no clear path for our own employees to get there. We have no concrete way to evaluate people joining the team, no way to hold ourselves accountable, and no way of improving the process.&lt;/p&gt;
&lt;p&gt;As an industry, it&apos;s time to graduate from the “I’ll know it when I see it” definition toward something we can define and share. &lt;strong&gt;Let&apos;s bring open source thinking to how we hire and grow our people.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I hope to answer the major lingering questions in the next post. If you have questions or a different definition, you can find me on Twitter (&lt;a href=&quot;http://twitter.com/tehviking&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@tehviking&lt;/a&gt;) or better yet, write a post with your own thoughts and I’ll link to it.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Accessibility & Why it Matters]]></title><link>https://frontside.com/blog/2016-05-19-accessibility-why-it-matters/</link><guid isPermaLink="false">https://frontside.com/blog/2016-05-19-accessibility-why-it-matters/</guid><category><![CDATA[code]]></category><category><![CDATA[frontside]]></category><category><![CDATA[accessibility]]></category><category><![CDATA[web accessibility]]></category><category><![CDATA[disability]]></category><category><![CDATA[gaad]]></category><category><![CDATA[ember-a11y]]></category><dc:creator><![CDATA[Stephanie Riera]]></dc:creator><pubDate>Thu, 19 May 2016 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In honor of &lt;a href=&quot;http://www.globalaccessibilityawarenessday.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GAAD&lt;/a&gt; (Global Accessibility Awareness Day), I interviewed a developer who is active in the accessibility community to gain some insights on the importance of web accessibility.&lt;/p&gt;
&lt;p&gt;Applying for jobs, registering your vehicle, selecting classes for the next school semester, and other tasks can become close to impossible if you have no access to the internet. Imagine for a second that you had no access to Google, Netflix, and dank memes. This sucks. Now let&apos;s imagine you couldn&apos;t use your computer&apos;s mouse or trackpad. How would you navigate the page or click on an image? Life would suck, royally. This is the reality for a population of internet users.&lt;/p&gt;
&lt;h3 id=&quot;what-is-accessibility&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-accessibility&quot; aria-label=&quot;what is accessibility permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is accessibility?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Accessibility&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Accessibility&lt;/a&gt; refers to the design of products, devices, services, or environments for people who experience disabilities. Usability affects from the blind and color blind to the deaf and seizure prone. People in developing countries use the internet but may not necessarily know English. A site with poor usability makes it challenging for the elderly and those with motor skills disabilities to use.&lt;/p&gt;
&lt;figure alt=&quot;Blind students enjoying computer games at Techshare India 2012&quot;&gt;
  &lt;img src=&quot;/img/2016-05-19-accessibility-why-it-matters_students.jpg&quot;&gt;
&lt;/figure&gt;
([Image][3]:  Blind students enjoying computer games at Techshare India 2012)
&lt;p&gt;Federal websites must adhere to Section &lt;a href=&quot;http://www.section508.gov/content/learn/laws-and-policies&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;508&lt;/a&gt; which is a law that states Government sites must be accessible for people with disabilities. Some sites follow the &lt;a href=&quot;www.ada.gov&quot;&gt;ADA&lt;/a&gt; (Americans with Disabilities Act) guidelines loosely but the majority of websites could make a concerted effort to improve.&lt;/p&gt;
&lt;h4 id=&quot;the-dialogue-is-just-not-there&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-dialogue-is-just-not-there&quot; aria-label=&quot;the dialogue is just not there permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The dialogue is just not there.&lt;/h4&gt;
&lt;p&gt;And it&apos;s unfortunate. You&apos;d think that with the current tech boom more developers and startups would pay attention to accessibility. The fact of the matter is, unless you have a disability or are directly affected by a family member with one, chances are you&apos;ve never given it much thought. Even I didn&apos;t learn about web accessibility while I was studying web development.&lt;/p&gt;
&lt;figure alt=&quot;Google Trends graph of web accessibility and guidelines over time, captured May 16, 2012&quot;&gt;
  &lt;img src=&quot;/img/2016-05-19-accessibility-why-it-matters_accessibility-chart.png&quot;&gt;
&lt;/figure&gt;
([Image][6]: Google Trends graph of web accessibility and guidelines over time, captured May 16, 2016)
&lt;p&gt;Despite the lack of awareness, this leaves room for opportunity. Accessibility applications can be expensive and have a steep learning curve. There is an untapped market with both native and web accessibility applications that have capacity for great improvement.  The value you contribute through innovation and open source software is limitless.&lt;/p&gt;
&lt;h3 id=&quot;why-does-making-my-site-accessible-matter&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-does-making-my-site-accessible-matter&quot; aria-label=&quot;why does making my site accessible matter permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why does making my site accessible matter?&lt;/h3&gt;
&lt;p&gt;The UN Convention on the Rights of Persons with Disabilities recognizes access to information and communications technologies, including the Web, as a &lt;strong&gt;basic &lt;a href=&quot;http://www.un.org/disabilities/convention/conventionfull.shtml&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;human right&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The internet has become more than humanity&apos;s encyclopedia. Cultural and social behaviors bubble out of the world wide web and become elements of today&apos;s society. The internet provides a medium for people with disabilities to interact. Everyone benefits when we &lt;em&gt;support social inclusion for all.&lt;/em&gt; Tech is integrated in our culture and everyday life. Let’s try an experiment. For the next 30 seconds, navigate any webpage you want (this article can wait), and try navigating without a mouse. Hit tab and enter. See what it’s like to click links, fill in a form, whatever you like. Or better yet, if you have 3 or 4 minutes, turn on &lt;a href=&quot;http://webaim.org/articles/voiceover/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;VoiceOver&lt;/a&gt;, and navigate with just the audio. Use a screen reader with voice recognition if you&apos;re feeling lucky.&lt;/p&gt;
&lt;p&gt;By just taking those few seconds or couple of minutes, you can empathize with an entire world of users whose experience on the web is completely different from our own. And in the end, isn’t creating great experiences what software development is all about? This insight not only makes you a better developer but paves the way for building better UX. Beautifully designed sites avoid unnecessary noise and are navigable. Elegant applications incorporate architecture that flows and actions that are clear. Together we can make web accessible by default, the &lt;em&gt;standard&lt;/em&gt;.&lt;/p&gt;
&lt;h4 id=&quot;alright-how-do-i-start-making-my-site-accessible&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#alright-how-do-i-start-making-my-site-accessible&quot; aria-label=&quot;alright how do i start making my site accessible permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Alright, how do I start making my site accessible?&lt;/h4&gt;
&lt;p&gt;It&apos;s easier if you start putting thought into the site structure and picking colors from day one. Consider the flow of the site, would you be able to navigate through it if you were drunk? Test your colors with a contrast checker and start adding links to skip repetitive content. Imagine a screen reader describing the Facebook navigation every time you load the page. After the fifth time, you&apos;d know the messages icon goes right after the friend requests.&lt;/p&gt;
&lt;p&gt;Make sure you’re being semantic with your HTML tags. Use an actual &lt;code class=&quot;language-text&quot;&gt;&amp;lt;button&gt;&lt;/code&gt; element and divert from doing this:
&lt;code class=&quot;language-text&quot;&gt;&amp;lt;div class=&quot;button&quot; {{action&quot;showModal&quot;}}&gt;Open Modal&amp;lt;/div&gt;&lt;/code&gt;
If you are in the practice of using &lt;code class=&quot;language-text&quot;&gt;&amp;lt;div&gt;&lt;/code&gt; be cautious because the DOM doesn&apos;t recognize hierarchy. Divs and &lt;code class=&quot;language-text&quot;&gt;&amp;lt;span&gt;&lt;/code&gt; should be used for styling, else a screen reader won&apos;t recognize a header and won&apos;t read it. If you &lt;strong&gt;must&lt;/strong&gt; use a div as a button, please us the &lt;code class=&quot;language-text&quot;&gt;role&lt;/code&gt; attribute. This is a last resort.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/UNDERSTANDING-WCAG20/intro.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;WCAG&lt;/a&gt; 2.0 principle: Perceivable, Operable, Understandable or Robust&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Never use a timeout because the user won&apos;t be able to get to the content in time and it turns into a videogame that you must master to get to the next page. Make use of checkboxes or radio buttons. Add labels for your forms and tables. An added benefit from making your site accessible is that it overlaps with other best practices such as mobile web design, search engine optimization (SEO), and usability.&lt;/p&gt;
&lt;h4 id=&quot;here-are-couple-tools-you-can-start-playing-with&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#here-are-couple-tools-you-can-start-playing-with&quot; aria-label=&quot;here are couple tools you can start playing with permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Here are couple tools you can start playing with:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/axe/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;aXe&lt;/a&gt; is chrome extension that provides quick accessibility testing.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://achecker.ca/checker/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;AChecker&lt;/a&gt; is available if you&apos;re not a fan of chrome extensions. &lt;em&gt;&lt;em&gt;Note: If you have a single page app it won&apos;t work.&lt;/em&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.contrastchecker.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ContrastChecker&lt;/a&gt;- does just that.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://wave.webaim.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;WAVE&lt;/a&gt; (Web Accessibility Evaluation Tool) also offers a Chrome &lt;a href=&quot;http://wave.webaim.org/extension/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;extension&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/paypal/AATT&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;AATT&lt;/a&gt;, Automated Accessibility Testing Tool helps you integrate accessibility testing into your existing automation test suite.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&apos;re seeking a wiki style run through of best practices, I highly recommend &lt;a href=&quot;https://www.w3.org/WAI/gettingstarted/Overview.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;W3C&lt;/a&gt; (Web Accessibility Initiative), they have compiled strategies, guidelines, and resources on accessibility. Stanford University has generated &lt;a href=&quot;https://soap.stanford.edu/tips-and-tools/tips&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SOAP&lt;/a&gt; (Stanford Online Accessibility Program) to provide resources for designers, developers and content creators. Hopefully these resources will make it easier to transition to building sites that are sophisticated, accessibility friendly and most importantly inclusive.&lt;/p&gt;
&lt;h6 id=&quot;you-tha-real-mvp&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#you-tha-real-mvp&quot; aria-label=&quot;you tha real mvp permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;You tha real MVP&lt;/h6&gt;
&lt;p&gt;I&apos;d like to thank Robert DeLuca for taking the time from his schedule to allow me to interview him on accessibility. Rob is a Frontend developer and a contributor to &lt;a href=&quot;https://www.npmjs.com/package/ember-a11y&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ember-a11y&lt;/a&gt;, an open source initiative to create Ember addons that help make accessibility default.
He&apos;s also created awesome applications like &lt;a href=&quot;https://github.com/Robdel12/DropKick&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;DropKick&lt;/a&gt;, a plugin for creating beautiful, accessible, and painless custom dropdowns. You can find him on the Twitterverse &lt;a href=&quot;https://twitter.com/robdel12&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;(@robdel12)&lt;/a&gt; or talk accessibility on the Ember Slack (@robdel12).&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I’m Stephanie Riera &lt;a href=&quot;https://twitter.com/stefriera&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;(@stefriera)&lt;/a&gt;, and I build web applications for a living at The Frontside. If you enjoyed this, I&apos;d love to hear from you! Shoot me a line at stephanie@frontside(dot)io.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/7d251d688aa74bcfc79714a1b55df7d5/bd22c/2016-05-19-accessibility-why-it-matters_gaad.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Global Accessibility Awareness Day]]></title><link>https://frontside.com/blog/2016-05-17-global-accessibility-awareness-day/</link><guid isPermaLink="false">https://frontside.com/blog/2016-05-17-global-accessibility-awareness-day/</guid><category><![CDATA[accessibility]]></category><category><![CDATA[ember.js]]></category><category><![CDATA[community]]></category><dc:creator><![CDATA[Robert DeLuca]]></dc:creator><pubDate>Tue, 17 May 2016 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Thursday May 19th marks the fifth
&lt;a href=&quot;http://www.globalaccessibilityawarenessday.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Global Accessibility Awareness Day&lt;/a&gt;. The
goal for Global Accessibility Awareness Day (or GAAD for short) is to
get people who work in technology to start talking, thinking, or
learning about accessibility.&lt;/p&gt;
&lt;p&gt;If you&apos;re not familiar, accessibility is about building solutions for
those who have disabilities. For the web, it means considering those
who are deaf, blind, colorblind, or have motor skill disabilities in
your design and development.&lt;/p&gt;
&lt;p&gt;A group of people that deeply care about accessibility and
Ember.js have banded together. That group is called
&lt;a href=&quot;https://github.com/ember-a11y&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ember-a11y&lt;/a&gt;. Our goal is to make ember
accessible by default as much as we can, and the first step in that
direction is our
&lt;a href=&quot;https://github.com/ember-a11y/ember-a11y&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ember-a11y&lt;/a&gt; addon that
fills the gaps of the Ember router. Before this addon, those who rely
on screen readers would never know the page updated when switching
routes. &lt;a href=&quot;https://www.youtube.com/watch?v=1BGmTj4j3ms&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Here is a quick video demonstrating this.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That&apos;s only the start of what we want to accomplish as a
team. We&apos;re putting together a website that isolates and compiles some
of the top ember addons on &lt;a href=&quot;http://ember-observer.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Ember Observer&lt;/a&gt;
so you or assistive technology providers can test them. You can
&lt;a href=&quot;https://ember-a11y.github.io/a11y-demo-app/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;find the website here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For GAAD 2016 we would love your help adding as many of the
&lt;a href=&quot;https://emberobserver.com/categories/components&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;top component addons from ember observer&lt;/a&gt;
as possible. To stop work duplication,
&lt;a href=&quot;https://github.com/ember-a11y/a11y-demo-app/issues/new&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;add an issue&lt;/a&gt;
&lt;strong&gt;BEFORE&lt;/strong&gt; you start implementing the addon. That way, if someone else has
already started work on the addon you wanted to implement, you would know.&lt;/p&gt;
&lt;p&gt;If that doesn&apos;t strike your fancy and would like to contribute to
addons,
&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1q4DkaNwH8mh7xZJa1TmrHNcFuFuWdQ80iG88c7N4QII/edit#gid=0&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;check out this spreadsheet.&lt;/a&gt;
Here we&apos;ve started a list of addons that need accessiblity work. The
list can range anything from adding a &lt;code class=&quot;language-text&quot;&gt;role&lt;/code&gt; attribute to a
div acting as a button, to pushing accessibility through for the
wildly popular date picker component, Pikaday. To start working on
something from the spreadsheet, place your name in the &quot;assignee&quot;
column and highlight the row according to the legend at the bottom of
the document. You can also add things to the spreadsheet you find from
testing other addons!&lt;/p&gt;
&lt;p&gt;You could also catch this Google IO event about Accessibility titled
&lt;a href=&quot;https://events.google.com/io2016/schedule?sid=38631cfd-0bef-e511-a517-00155d5066d7#day2/38631cfd-0bef-e511-aI517-00155d5066d7&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&quot;Accessibility is My Favorite Part of the Platform&quot;.&lt;/a&gt;
It is a great talk that we can learn a lot from.&lt;/p&gt;
&lt;p&gt;If none of that looks interesting to you, at the very least spend 10-15
mins with a screen reader on any of your favorite sites. Try closing
your eyes or dimming the screen and navigating only using the screen
reader. This will help you understand how anyone who relies on a
screen reader uses a website. &lt;strong&gt;This might be one of the most valuable
things you do on GAAD.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;re an OS X user,
&lt;a href=&quot;http://webaim.org/articles/voiceover/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;WebAIM has a excellent tutorial on how to use VoiceOver&lt;/a&gt;. Use
CMD + F5 to toggle VoiceOver on or off. You can also toggle VoiceOver
on your iPhone if ask Siri to turn it on or off.&lt;/p&gt;
&lt;p&gt;If you&apos;re on Windows, you can use
&lt;a href=&quot;http://www.freedomscientific.com/downloads/jaws&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;JAWS on a free trial&lt;/a&gt;
or &lt;a href=&quot;http://www.nvaccess.org/download/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;NVDA&lt;/a&gt; which is free. JAWS is
the most popular screen reader
currently. &lt;a href=&quot;http://webaim.org/articles/jaws/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;WebAIM also has a great JAWS tutorial&lt;/a&gt;
and &lt;a href=&quot;http://webaim.org/articles/nvda/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;NVDA tutorial.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For me, this Global Accessibility Awareness Day will be sponsored by
The Frontside. I&apos;m going to try to give back to the community as much
as possible. My day is going to be split into 3 parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Push accessibility through &lt;a href=&quot;https://github.com/dbushell/Pikaday/pull/458&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;for Pikaday&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pairing hours [1-3pm]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rwjblue/ember-template-lint/issues/41&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Add template linting for common accessibility mistakes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I would like to pair with as many people as possible in 3 hours. Each
pairing session will be 25 minutes long and we can work on anything
accessibility-related you would like. This could be dropping the
ember-a11y addon into one of your apps, solving an issue from the
spreadsheet, or using a screen reader on websites. Sound interesting?
&lt;a href=&quot;http://pair.ember-a11y.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Sign up here!&lt;/a&gt; We&apos;re going to be using Screenhero or Skype for
screen sharing.&lt;/p&gt;
&lt;p&gt;I&apos;ll be around all day to help. Feel free to reach out on twitter
(&lt;a href=&quot;http://twitter.com/robdel12&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@robdel12&lt;/a&gt;) or on Slack (robdel12)! For Slack you
can snag me in the &lt;a href=&quot;https://web-a11y.herokuapp.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;web-a11y Slack&lt;/a&gt;
or the
&lt;a href=&quot;https://ember-community-slackin.herokuapp.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Ember community slack&lt;/a&gt;. What
are you waiting for? Let&apos;s get out there and make the web a little more
accessible! :)&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/25ff2318f7bfff9ff4a21fa6ab0afa99/de2bf/2016-05-17-global-accessibility-awareness-day-gaad.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[So You Just Finished a Bootcamp, Now What?]]></title><link>https://frontside.com/blog/2016-05-17-so-you-just-finished-a-bootcamp-now-what/</link><guid isPermaLink="false">https://frontside.com/blog/2016-05-17-so-you-just-finished-a-bootcamp-now-what/</guid><category><![CDATA[code]]></category><category><![CDATA[bootcamp]]></category><category><![CDATA[frontside]]></category><category><![CDATA[job]]></category><category><![CDATA[hiring]]></category><category><![CDATA[interview]]></category><category><![CDATA[oss]]></category><category><![CDATA[community]]></category><dc:creator><![CDATA[Stephanie Riera]]></dc:creator><pubDate>Tue, 17 May 2016 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You took the plunge and here you are, a newly minted code bootcamper. You&apos;ve endured the brain inundation of information and the inherent stress of not knowing what you&apos;re doing.
Congratulations, you&apos;re here now and you&apos;re still asking yourself, &quot;What do I do next?&quot;, I have no idea what I&apos;m doing. You&apos;re here though, thanks Google.&lt;/p&gt;
&lt;figure alt=&quot;I have no clue what I&apos;m doing dog on computer&quot;&gt;
  &lt;img src=&quot;/img/2016-05-17-so-you-just-finished-a-bootcamp-now-what_codedog.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;As a developer, our job 90% of the time is to figure things out and create solutions using the resources we have available. You are a developer, you are just unemployed and finding a job is kind of the same process. It boils down to utilizing the available resources and creating your own solutions.&lt;/p&gt;
&lt;p&gt;I&apos;ve been in your shoes. I quit my secure job in a laboratory and decided to switch from Molecular Biology to Programming. I heard about bootcamps on NPR and felt like it was the best option given my student loan debt wasn&apos;t going to pay for my next degree. Drinking magma from the center of the Earth sounded better than another 4 years in college for a CS degree.&lt;/p&gt;
&lt;p&gt;After finishing the bootcamp I wasn&apos;t sure where to go next. Most of the developer positions in my city had been occupied by the previous bootcamp cohorts and finding a job was proving to be more difficult than originally advertised. I have compiled all the lessons I&apos;ve learned along the way and hope it helps you on your journey.&lt;/p&gt;
&lt;h2 id=&quot;expectations-vs-reality&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#expectations-vs-reality&quot; aria-label=&quot;expectations vs reality permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Expectations vs Reality&lt;/h2&gt;
&lt;h5 id=&quot;bootcampers-expectation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bootcampers-expectation&quot; aria-label=&quot;bootcampers expectation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bootcampers&apos; expectation:&lt;/h5&gt;
&lt;p&gt;You graduated and by the end of the week you&apos;ll have your dream job in the bag. Better yet, your bootcamp will magically find the job for you. &lt;em&gt;Cue turntable stopping abruptly&lt;/em&gt;.
Some bootcamps may guarantee &lt;em&gt;job placement&lt;/em&gt; but that doesn&apos;t translate to working in a desireable company or project. Alternatively, other bootcamps will refund you some portion of what you paid if you don&apos;t get a job after a period of time.&lt;/p&gt;
&lt;p&gt;Technically, you are not guaranteed a job nor are you entitled to one. Some bootcamps help with the employment process by relaying available positions but you risk starting your career somewhere you shouldn&apos;t start at. You may very well find yourself unemployed 5 months after having graduated. I&apos;ll discuss this further in the next section.&lt;/p&gt;
&lt;h5 id=&quot;bootcampers-reality&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bootcampers-reality&quot; aria-label=&quot;bootcampers reality permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bootcampers&apos; reality:&lt;/h5&gt;
&lt;p&gt;Finding a job is akin to speed dating- it takes effort. You put on your best outfit and go to the interview with the hope of impressing them while getting to feel them out. Don&apos;t forget, they&apos;re doing the same thing too. The relationship should always be mutually beneficial.&lt;/p&gt;
&lt;p&gt;Every job will have have its own set responsibilities, company size, and culture. Before you start applying, sit down and think of what your ideal first job would look like. Do they participate in code reviews? Will they ask you to learn .NET and evolve into a customer support guru? Are they a TDD (Test Driven Development) shop or do they ship code lightening fast? Do you prefer working for a giant company or a startup?&lt;/p&gt;
&lt;p&gt;What is important to you? Not sure yet? That&apos;s fine too because even if you land a not so great job, it&apos;s experience nonetheless and you&apos;ll discover what you like or don&apos;t like. It may take kissing a couple frogs.&lt;/p&gt;
&lt;h5 id=&quot;employers-reality&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#employers-reality&quot; aria-label=&quot;employers reality permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Employer&apos;s reality:&lt;/h5&gt;
&lt;p&gt;Not everyone is a fan of bootcamp grads. Every bootcamp is different in how they present the curriculum and the scope varies greatly. You are not vetted and you lack the industry experience. Not all bootcamp graduates are good programmers and not all bootcamps prepare their students to be hireable. Combine those two and you have companies that have been burned from hiring bootcamp grads. If they consider hiring you then know that they are taking a risk on you. You are an investment and you are promising a return.&lt;/p&gt;
&lt;p&gt;Some companies say they ain&apos;t got time for that and prefer hiring a mid or senior developer. Others offer internships or contract-to-hire gigs as a form of test trial before actually committing which can be advantageous for both parties. Then there are progressive companies that understand the value of building a diverse team of all backgrounds and levels of experience. These companies have mentorship and personal growth entwined in their company culture and they take it to heart despite the challenges.&lt;/p&gt;
&lt;h2 id=&quot;unemployment-may-happen-and-yes-it-sucks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#unemployment-may-happen-and-yes-it-sucks&quot; aria-label=&quot;unemployment may happen and yes it sucks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Unemployment may happen, and yes it sucks.&lt;/h2&gt;
&lt;p&gt;If this happens, just power through. Even if money gets tight and you need a temporary job to pay the bills, remind yourself why this is temporary. Use your lunch breaks to catch up on podcasts or that JS book. Make sure any kind of free time is sacred and reserved to either studying or sleep.&lt;/p&gt;
&lt;p&gt;If you have the luxury of staying at home for a couple months while you find a job, don&apos;t waste it. Seeing your reflection on the black screen between Netflix episodes sitting on the couch covered in cheeto crumbs at 2 pm is no bueno.&lt;/p&gt;
&lt;p&gt;To avoid this, keep yourself accountable and productive by building your own &apos;work&apos; schedule.
This is what mine looked like until I was busy working 3 different side gigs:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;	- Wake up between 8:30 - 9 am
	- Exercise
	- Breakfast &amp;amp; shower
	- Finding jobs, applying, &amp;amp; phone interviews
	- Lunch
		- Optional: Go for a walk or switch activities as a mental break
	- Work on projects, portfolio, OSS
	- Dinner
	- Go to meetups or keep coding if there are no meetups that evening
	- 10:30 pm bedtime (avoid 3 am interweb voids)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;whatever-you-do-dont-stop-working&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whatever-you-do-dont-stop-working&quot; aria-label=&quot;whatever you do dont stop working permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Whatever you do, don&apos;t stop working&lt;/h3&gt;
&lt;h5 id=&quot;cast-a-wide-net&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cast-a-wide-net&quot; aria-label=&quot;cast a wide net permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cast a wide net&lt;/h5&gt;
&lt;p&gt;There&apos;s more than just searching on &lt;a href=&quot;https://indeed.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Indeed&lt;/a&gt;. Freelancing builds your portfolio, you can find small projects on &lt;a href=&quot;https://upwork.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Upwork&lt;/a&gt;, &lt;a href=&quot;https://fiverr.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Fiverr&lt;/a&gt;, and &lt;a href=&quot;https://craigslist.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Craigslist&lt;/a&gt;. Leverage your connections and let them know you&apos;re in the market, they might know someone. Recruiters are a great asset because you don&apos;t need to pay for their services, they get a cut from the Company that hires you. If you do this, make sure you are specific on what you&apos;re searching for. Give the recruiter your website or &lt;a href=&quot;https://github.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GitHub&lt;/a&gt; profile so that they can get to know you. Do some research on nearby shops and check out their careers page, not all of them post on job sites. Don&apos;t forget to check the city government jobs and language specific job boards.&lt;/p&gt;
&lt;h5 id=&quot;nail-your-interview&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#nail-your-interview&quot; aria-label=&quot;nail your interview permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Nail your interview&lt;/h5&gt;
&lt;p&gt;Do your research on the company interviewing you, it shows you&apos;re interested in their product, values, and history. Get the basic interview questions down, practice makes perfect. I went to interviews for jobs I knew I&apos;d turn down if I received an offer because I knew it was good practice.&lt;/p&gt;
&lt;p&gt;Now for the sound of death: pair programming interview. This can be nerve wracking especially for a junior developer yet it can be a blessing in disguise. How? Well, this gives your prospective employer a litmus test of where you are as a developer. You can avoid unrealistic expectations and it&apos;s okay to admit when you don&apos;t understand a concept. Remember, &lt;em&gt;your attitude under stressful situations&lt;/em&gt; says more than the code you&apos;re writing.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Last note, if you&apos;re a bootcamp grad, you probably became an expert in another industry. Don&apos;t neglect the fact that you had the courage to change career paths and the grit to learn a completely new discipline. You may not have all the experience right now but you have tenacity and other qualities that are equally valuable to an employer. &lt;strong&gt;You bring an unique experience and contribution to the table.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h5 id=&quot;oss&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#oss&quot; aria-label=&quot;oss permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;OSS&lt;/h5&gt;
&lt;p&gt;Open Source Software is valuable for everyone. When software is reviewed by hundreds of developers, it&apos;s hard for bugs to go unnoticed and the quality of the code is better than that of a 8 person dev team. Companies are jumping onboard the OSS train and nonprofits can use all the help they can get. As a developer you benefit from seeing how others create solutions and it&apos;s nice to contribute to a greater something. You can find the trending OSS projects on GitHub &lt;a href=&quot;https://github.com/trending&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt; and start pushing code.&lt;/p&gt;
&lt;h2 id=&quot;have-an-online-presence&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#have-an-online-presence&quot; aria-label=&quot;have an online presence permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Have an online presence&lt;/h2&gt;
&lt;p&gt;People are going to be doing their homework and looking you up. Let&apos;s face it, you&apos;re working in the tech world now, you should probably step your game up. Please do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use one (professional) email address for consistency.&lt;/li&gt;
&lt;li&gt;Invest in a good headshot &amp;#x26; use it across all your social media accounts. A white or brick background, good lighting and iPhone can do the trick.&lt;/li&gt;
&lt;li&gt;Tidy up your resume and tailor it to the job you&apos;re applying for. Save yourself the trouble and have multiple resumes. (Ex- Retail resume, Developer resume, Marketing resume, etc)&lt;/li&gt;
&lt;li&gt;Don&apos;t skip the cover letter. This is your opportunity to show off your writing skills and explain why you&apos;re a great hire they can&apos;t pass up. It also sets you apart from those candidates that aren&apos;t writing them.&lt;/li&gt;
&lt;li&gt;You should have a &lt;a href=&quot;https://linkedin.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;LinkedIn&lt;/a&gt; and it should not be empty. Later it will come in handy to stay connected with the professionals you meet and you can search for jobs here too.&lt;/li&gt;
&lt;li&gt;Push all your projects to GitHub.&lt;/li&gt;
&lt;li&gt;Don&apos;t be lazy, write those ReadMe&apos;s. Without proper documentation, a user won&apos;t know how to use your app and has no where to go find answers. If you leave developers with just a directory structure, it&apos;s not only useless but a fool proof way of having them leave your repo.&lt;/li&gt;
&lt;li&gt;Have your own domain where you link to your resume, GitHub, LinkedIn and other mediums like Twitter. This is a great place to exhibit your skills when asked about your experience.&lt;/li&gt;
&lt;li&gt;Clean up your online profiles. Google yourself, remove embarrassing tweets and delete those questionable Myspace photos.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;be-active-in-the-community&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#be-active-in-the-community&quot; aria-label=&quot;be active in the community permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Be active in the community&lt;/h2&gt;
&lt;p&gt;Getting stuck in code at home is horrifying because it takes hours to get unstuck. Being around other developers can make a huge difference. Check &lt;a href=&quot;https://meetup.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Meetup.com&lt;/a&gt; for tech groups in your city and don&apos;t be shy. Meetups offer a safe environment to learn new topics through their lightning talks, the ability to present your projects, receive constructive feedback, and lose the speaking jitters. Meetups organize fun hackathons and it&apos;s a great place to get your networking on. Let me tell you when it comes to jobs, it&apos;s all about &lt;em&gt;who you know&lt;/em&gt;.&lt;/p&gt;
&lt;figure alt=&quot;Photo by Kara Gomez of San Antonio Geekdom&quot;&gt;
&lt;img src=&quot;/img/2016-05-17-so-you-just-finished-a-bootcamp-now-what_geekdom.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Finding a coworking space in your area is paramount. You&apos;ll be informed of what is going on in your city&apos;s tech ecosystem, meet ambitious people, and even find out about positions with the local startups. Everyone here is busy hustling and simply being in that environment is better than trying to work from home or the loud Starbucks. These people like to work hard and play hard. The opportunity of making amazing friends along the way is real. Surround yourself with people that inspire you.&lt;/p&gt;
&lt;p&gt;Never leave your home without your business cards and a positive attitude. If you don&apos;t have any, you can order some on &lt;a href=&quot;https://vistaprint.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Vistaprint&lt;/a&gt; or &lt;a href=&quot;https:/moo.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Moo&lt;/a&gt;. Your card should include your contact information, the title of the job you desire (ie- Backend Developer), and your GitHub account. Design your card to be an extension of yourself, people will remember you. There should be no room for missed connections, always do your due diligence and follow up with an email. A friendly smile can go a long way. Be the person that introduces themselves or starts a conversation with the person sitting by themselves.&lt;/p&gt;
&lt;h3 id=&quot;give-first&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#give-first&quot; aria-label=&quot;give first permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Give first&lt;/h3&gt;
&lt;p&gt;Something I learned while working for Techstars was the value of giving first without the expectation of gaining anything in return. I can&apos;t stress how important and rewarding this is. You can be of service to others in a variety of ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Share advice in the form of tweets, a blog or a podcast. Sit down with someone who is interested in programming but is unsure. Sharing your experience even if you&apos;re not where you want to be yet can actually be inspiring to others.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Show what you learned at a meetup or at a brownbag lunch. Some schools host hackathons for children or have chapters of &lt;a href=&quot;https://girlswhocode.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Girls Who Code&lt;/a&gt; and they&apos;re always in need of helping hands. You don&apos;t need to be a seasoned developer to explain how the DOM works or how CSS can add style to a page. When you support your local YMCA or code group for veterans, you are spreading knowledge while solidifying these concepts. &lt;em&gt;The one who does the talking, does the learning.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Can&apos;t find any interesting meetups nearby? Create your own! I won&apos;t lie, it will take some planning and preparation on your end during the beginning but after that it gets easier especially after other organizers join. My bestfriend and I organized the first RailsGirls (a Ruby on Rails introductory hackathon for women of all ages) in San Antonio. We had a successful 30+ attendee turnout and I coached my own group without knowing a line of Ruby or the Rails framework.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Join a non-profit organization like &lt;a href=&quot;https://codeforamerica.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Code for America&lt;/a&gt; where you can tackle civic problems for the greater good. You can always be of assistance remotely.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Offer your time free of charge. When you help out the local girls soccer team by designing their logo, you are freeing their budget to allocate funds elsewhere. You&apos;ve become a contributing member of the community and when someone asks if anyone knows of a good designer, you have people that will vouch for you organically. Your name comes up everytime someone compliments their jersey.&lt;/p&gt;
&lt;figure alt=&quot;Photo by Kara Gomez of Rails Girls 2016 San Antonio&quot;&gt;
&lt;img src=&quot;/img/2016-05-17-so-you-just-finished-a-bootcamp-now-what_railsgirlsSA.jpg&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;Organic leads aside, let me tell you the most satisfying part. &lt;em&gt;Knowing you&apos;ve made a difference in someone&apos;s life.&lt;/em&gt; After the &lt;a href=&quot;https://railsgirls.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Rails Girls&lt;/a&gt; event, an older woman came and grabbed my hands to thank me for organizing the event. She said she never would&apos;ve imagined that she&apos;d be able to create an application from scratch. The majority of women who attended had never touched a line of code previously but left exhilarated and ready to continue learning because they knew it was achievable. I strongly recommend combining your passion with helping others because it&apos;s more fulfilling than you&apos;d think.&lt;/p&gt;
&lt;h2 id=&quot;be-kind-be-patient&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#be-kind-be-patient&quot; aria-label=&quot;be kind be patient permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Be kind, be patient&lt;/h2&gt;
&lt;p&gt;This journey can be a long one with unexpected twists and bumps on the road. I&apos;ve given you all the pointers on how to hustle hard but I must also touch on personal wellbeing. I&apos;ve asked you to be kind and of service to others but that should also include yourself. You might have moments of self doubt, frustration, anxiety, and I need you to know, I had those moments. If you know within yourself that this is what you want but you don&apos;t have the answers to everything else, that&apos;s okay. These difficult moments taught me how to &lt;em&gt;be comfortable with being uncomfortable.&lt;/em&gt; These moments shape you. Have patience and trust in your struggle- even if those around you don&apos;t.&lt;/p&gt;
&lt;p&gt;Circumvent outside noise. If you feel like your fire is being distinguished, listen to inspirational podcasts, read and watch autobiographies that amaze you. If you&apos;re feeling exhausted, listen to your body. Get a massage to relieve some tension. Go for a walk, watch a movie or go to bed early. Feed your body, mind, and soul. This trek is challenging but if you apply yourself, you&apos;d be surprised at the things you can accomplish in a year. If there is a will, there is a way.&lt;/p&gt;
&lt;p&gt;I’m Stephanie Riera (&lt;a href=&quot;https://twitter.com/stefriera&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@stefriera&lt;/a&gt; on twitter), and I build web applications for a living at &lt;a href=&quot;https://frontside.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Frontside&lt;/a&gt;. If you enjoyed this, I’d love to hear from you.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/be310e2bfa13f018d9cba265a515d120/4fe8c/2016-05-17-so-you-just-finished-a-bootcamp-now-what_techstars.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[The Insider Track]]></title><description><![CDATA[A guide to using kindness to elevate your conference experience.]]></description><link>https://frontside.com/blog/2016-03-18-the-insider-track/</link><guid isPermaLink="false">https://frontside.com/blog/2016-03-18-the-insider-track/</guid><category><![CDATA[conferences]]></category><category><![CDATA[community]]></category><dc:creator><![CDATA[Lydia Guarino]]></dc:creator><pubDate>Fri, 18 Mar 2016 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A guide to using kindness to elevate your conference experience.&lt;/p&gt;
&lt;p&gt;Get your sticker collections, backup batteries and ironic nerd mashup
t-shirts ready, because it&apos;s tech conference season!&lt;/p&gt;
&lt;p&gt;We&apos;re gearing up for one of our &lt;a href=&quot;http://emberconf.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;favorite conferences&lt;/a&gt; of the year, and
we&apos;ve been spending a lot of time discussing what it means to have an
amazing conference experience. We&apos;re incredibly stoked to see
our favorite thought leaders, community gurus and internet celebs BLOW
OUR MINDS with the new hotness and poignant epiphanies, but to
properly set expectations, &lt;em&gt;that&lt;/em&gt; is not what this article is about.&lt;/p&gt;
&lt;p&gt;If you&apos;ve got your ticket secured, you or your company
has invested in the opportunity to
create shared experiences with strangers from all over the world who
happen to be passionate about the same things you are. You&apos;ve pressed
pause on your life and traveled far from home to connect, grow and
recharge your techie batteries. You are here to be inspired to
innovate and to uncover new &lt;a href=&quot;http://www.inc.com/janine-popick/4-reasons-your-employees-should-attend-conferences.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;opportunities&lt;/a&gt; for yourself or for your company.&lt;/p&gt;
&lt;p&gt;Conferences are about &lt;a href=&quot;https://www.youtube.com/watch?v=xsG0gDkvDPw&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;community&lt;/a&gt; and community is all about
&lt;a href=&quot;http://oss-watch.ac.uk/resources/toptipscommunities&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;participation&lt;/a&gt;. If you are attending a conference strictly for the
speaker line up, you will likely have a better experience streaming
the conference from home. You&apos;ll definitely get a better seat. But, if you
want to fly home feeling like you just had the best three days of your
life, after a whirlwind of fascinating interactions with people you
once called strangers and now call friends, you have the conference
spirit and it&apos;s time to &lt;em&gt;supercharge&lt;/em&gt; your experience.&lt;/p&gt;
&lt;h2 id=&quot;lets-back-up-a-bit&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#lets-back-up-a-bit&quot; aria-label=&quot;lets back up a bit permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Let&apos;s back up a bit.&lt;/h2&gt;
&lt;p&gt;In a past life, before my development career, I was a sales rep for a
large tech company. Once or twice a year, the company&apos;s 700 or so
sales and vendor reps from all over the country would converge on
Austin for a three day Carnaval of hyper-charged networking events
that included extravagant parties, loud showboating at awards shows,
loads of vendor swag, and &lt;em&gt;lots and lots&lt;/em&gt; of people who lived life at
a completely different pace than I did.&lt;/p&gt;
&lt;p&gt;I spent a good amount of time at these events hiding in the restroom,
recharging my introvert batteries so that I could put my extrovert
mask back on. I&apos;d then wade back into the crowd with a crazed smile painted
on my face, feeling both overstimulated and exhausted at the same
time. Sometimes I just stayed in my hotel room instead of going
to the evening events.&lt;/p&gt;
&lt;p&gt;It was only after several of these conferences that I finally figured
out where my limits were, what my goals for the conference were, and
how I could be empowered to avoid the things that exhausted me, so I could
focus on the parts that were incredibly fun, inspiring and
rewarding. I learned that I needed to be much more intentional with my
time and energy.&lt;/p&gt;
&lt;h2 id=&quot;participation-over-observation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#participation-over-observation&quot; aria-label=&quot;participation over observation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Participation Over Observation&lt;/h2&gt;
&lt;p&gt;What worked for me was the decision to be a participant, not just an
observer. When I was intentional about participating, I felt in
control and was able to keep my energy up and my interactions
positive. Each positive interaction fed into the next, inoculating me
against the occasional not so awesome interaction. I left those events
feeling like I was on top of the world. I learned there was a formula
I could follow to dramatically enhance my experience and improve the
opportunities I came away with after the conference.&lt;/p&gt;
&lt;p&gt;I&apos;ve followed this formula at tech meet-ups and conferences for
the past three years. It&apos;s required very little tweaking. What
was once a survival mechanism for me and has now evolved into an
empowerment tool I use to forge strong connections with people who
might be my next client, hire or boss. It&apos;s required very little
tweaking because it&apos;s based on something pretty constant -- sales. And
sales is based on humans.&lt;/p&gt;
&lt;h2 id=&quot;you-are-a-sales-rep&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#you-are-a-sales-rep&quot; aria-label=&quot;you are a sales rep permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;You &lt;em&gt;are&lt;/em&gt; a sales rep.&lt;/h2&gt;
&lt;p&gt;Face it, when you attend a conference, you are selling. This truth is
scary for a lot of people in our industry. Sales sounds
like something reserved for the
pathologically extroverted among us. Luckily, it&apos;s a myth that you
have to be incredibly outgoing to be a successful salesperson. It may
help you get started, but it is not how you close a deal. You can&apos;t
get someone to buy something by &lt;em&gt;tricking them&lt;/em&gt; or by intimidating
them into cracking open a checkbook. You&apos;ve probably hung up on that
sales person. They probably get hung up on a lot. And that&apos;s because
sales is an exercise in &lt;a href=&quot;http://www.salestrainingadvice.com/2005/11/the-art-of-asking-good-questions-by-tim-hagen.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;investigation&lt;/a&gt;. It&apos;s the art of uncovering the
intersection between someone else&apos;s needs and something you can
offer. If you&apos;ve ever had the opportunity to watch a skilled
salesperson work their magic, you may have discovered that they do
significantly less talking than you might expect. Most of their words
are likely leaving their mouth in the form of questions.&lt;/p&gt;
&lt;p&gt;While you may not be pushing products at a conference, you &lt;em&gt;are&lt;/em&gt;
peddling memorable experiences and positive impressions. Impressions
that may lead to your next hire, your next client, or your next job
opportunity. You&apos;re selling the idea that you are someone others would
like to work with. You&apos;re selling the idea that you would be great to
sit next to all day and someone who would be fun to collaborate with.&lt;/p&gt;
&lt;p&gt;If this is not your first conference rodeo, you probably remember
&lt;em&gt;that guy&lt;/em&gt; that seemed like he knew and was adored by &lt;em&gt;everyone&lt;/em&gt; at
the conference. He was invited to do &lt;em&gt;everything&lt;/em&gt; and was &lt;em&gt;everywhere&lt;/em&gt;
you went. While it may be true that this person naturally has some
genetic defect that makes them fearless or has been sprinkled with
some kind of unicorn magic, it is far more likely that they have just
figured out the formula. It&apos;s a formula that will likely keep them
gainfully employed for the rest of their working life, regardless of
their objective level of technical skill, and it&apos;s surprisingly
straightforward.&lt;/p&gt;
&lt;h2 id=&quot;focus-your-energy-on-making-someone-elses-day-better-do-that-with-every-person-you-meet&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#focus-your-energy-on-making-someone-elses-day-better-do-that-with-every-person-you-meet&quot; aria-label=&quot;focus your energy on making someone elses day better do that with every person you meet permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Focus your energy on making someone else&apos;s day better. Do that with every* person you meet.&lt;/h2&gt;
&lt;p&gt;This sounds fluffy, and it is. I&apos;ve distilled it down into a mantra
that I can repeat to myself when I walk into a big room filled with
strangers. It&apos;s just a rephrasing of exactly what sales is:
&lt;em&gt;Uncover what someone else needs and figure out what you have to
meet that need&lt;/em&gt;. The implementation of this mantra is what I
call &lt;em&gt;The Formula&lt;/em&gt;. Sometimes I use all of these tools and sometimes I
just choose pieces for a specific setting. It took me a while to
work up to using the entire list. I recommend trying out
one or two that feel most comfortable at first and see how your
experience changes. Then, try a few more.&lt;/p&gt;
&lt;h2 id=&quot;the-formula&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-formula&quot; aria-label=&quot;the formula permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Formula&lt;/h2&gt;
&lt;h3 id=&quot;part-1---setting-the-stage&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#part-1---setting-the-stage&quot; aria-label=&quot;part 1   setting the stage permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Part 1 - Setting the Stage&lt;/h3&gt;
&lt;h4 id=&quot;1-wave-hello&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-wave-hello&quot; aria-label=&quot;1 wave hello permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. Wave hello.&lt;/h4&gt;
&lt;p&gt;The conference you are attending almost certainly has some &lt;a href=&quot;http://www.inc.com/eric-v-holtzclaw/five-ways-to-use-social-media-at-conferences.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;social
media channels&lt;/a&gt; associated with it. A couple days before a conference,
start to make your presence known on social media by sending a message
about how excited you are to be going to the conference. Thank the
organizers or share helpful tips for getting to the venue or finding
parking. Share a good place to eat that you discovered. Mention people
you are excited to meet up with. Establish yourself as a friendly and
welcoming person and people will be significantly more likely to reach
out to you or be brave enough to walk up to you. Something that often
gets overlooked is that your social media picture should be an
&lt;em&gt;actual&lt;/em&gt; recent picture of yourself. It&apos;s
how people find you in person or friend you after a positive
interaction.&lt;/p&gt;
&lt;h4 id=&quot;2-make-an-itinerary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-make-an-itinerary&quot; aria-label=&quot;2 make an itinerary permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. Make an itinerary.&lt;/h4&gt;
&lt;p&gt;Come up with a list of things you want to do or see while you&apos;re at
the conference. Pick out the talks you want to be sure to see, and
pick some times to break off into the &quot;Hallway Track.&quot; Some of the
best interactions you can have at a conference take place in the
quieter lulls when most people are watching talks. The Hallway Track
offers a smaller pool of people to converse with. Find several
restaurants, bars, after hours events, and recreation spots you&apos;d like
to visit. When people are huddled together after talks trying to
decide on a place to go, offer an assertive choice. You&apos;ll get to do
what you wanted to do, and people will appreciate that they didn&apos;t
have to play the &quot;I don&apos;t know, what do you want to do&quot; game. It also
gives you an easy way to invite the people you&apos;ve had good
interactions with to share specialized experiences with you.&lt;/p&gt;
&lt;h4 id=&quot;3-wear-a-costume&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-wear-a-costume&quot; aria-label=&quot;3 wear a costume permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. Wear a costume.&lt;/h4&gt;
&lt;p&gt;This is an old sales trick. &lt;em&gt;The Formula&lt;/em&gt; is about pushing past your
comfort zone. Being outside your comfort zone can be incredibly
exhausting. It&apos;s actually incredibly difficult for most humans not to
dwell on what people think of you. You are intentionally putting
yourself in a vulnerable position. I&apos;ve had a lot of success with
&lt;a href=&quot;http://www.harpersbazaar.com/culture/features/a10441/why-i-wear-the-same-thing-to-work-everday/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;costumes&lt;/a&gt;. This doesn&apos;t mean you should parade about in a feather boa
or a mask. It just has to be something that lets you be a little bit
of someone else while you&apos;re trying to overcome being more of
yourself. Sometimes, this is just a different hairstyle for me, or a new
pair of shoes, or wearing something that reminds me of someone I
love. It helps me get into my extrovert character, when my comfort
zone would be to quietly sit in the back row.&lt;/p&gt;
&lt;h3 id=&quot;part-2---finding-positive-interactions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#part-2---finding-positive-interactions&quot; aria-label=&quot;part 2   finding positive interactions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Part 2 - Finding Positive Interactions&lt;/h3&gt;
&lt;h4 id=&quot;1-ask-dont-tell&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-ask-dont-tell&quot; aria-label=&quot;1 ask dont tell permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. Ask, don&apos;t tell.&lt;/h4&gt;
&lt;p&gt;Small talk is the single hardest and most exhausting part of meeting
new people. The trick to making it through this uncomfortable part of
an interaction is to power through it with questions. Remind yourself
that your goal is to figure out who this person is, what their goals
are and what stands between them and achieving those goals. Your goal
is &lt;em&gt;not&lt;/em&gt; to impress them. You actually have very little control over
that part. What you &lt;em&gt;do&lt;/em&gt; have control over is your level of engagement
with this new person. People are interested in people who are
interested in them. People like people who like them. Asking someone
about what&apos;s important to them is the best and fastest way to have a
positive interaction. In a good interaction, that person will
reciprocate and ask you about what&apos;s important to you.&lt;/p&gt;
&lt;p&gt;Not everyone is going to be open to interacting with you, and that is
totally okay. Your goal is to give them the opportunity to engage with
you. If they don&apos;t reciprocate or you don&apos;t feel like it is going to
be a positive interaction, it is perfectly okay to move on to speaking
with someone else. Try not to take it personally. It&apos;s pretty
difficult to tease out why someone might not want to talk to you. The
best part about conferences is that there are a whole lot of
people. The next person you speak to is probably going to be open to a
conversation.&lt;/p&gt;
&lt;h4 id=&quot;2-be-the-includer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-be-the-includer&quot; aria-label=&quot;2 be the includer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. Be the includer.&lt;/h4&gt;
&lt;p&gt;This is my favorite tool. It&apos;s easier for some than others, and that&apos;s
okay. Give it a try and see how it goes. If you&apos;ve been in a
particular industry for a while, it can be very tempting to spend most
of your time at a conference with people you already know. You should
definitely spend some time hanging out with the people you know and
like, but you should also be actively figuring out how to connect
those people with others you know -- or better yet, with nice people
you just met. Sit down at a table with people you don&apos;t know. Invite
someone that is sitting alone to sit with you. Invite people to go do
something fun via social media. The more people you connect, the more
those people will connect you with others. The best part is that if
those people were nice, it’s likely that the people they introduce you
to will &lt;em&gt;also&lt;/em&gt; be nice.&lt;/p&gt;
&lt;p&gt;Satistically, any time you are at an event with a lot of people,
some minor subset of those people are not nice people. If someone
engages you and you do not feel safe or they make you feel inferior
or ashamed, quickly break that engagement and find someone else to
talk to. If you see someone else having a bad interaction, &lt;a href=&quot;http://www.ashedryden.com/blog/increasing-diversity-at-your-conference&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;offer
them a safe escape&lt;/a&gt; and invite them to join you.&lt;/p&gt;
&lt;h4 id=&quot;3-play-the-yes-game&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-play-the-yes-game&quot; aria-label=&quot;3 play the yes game permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. Play the yes game.&lt;/h4&gt;
&lt;p&gt;You&apos;ve just a couple of days to soak up as many opportunities and
experiences as possible. If you&apos;re lucky enough to be offered an
invitation and you don&apos;t have an incredibly compelling reason to turn
it down (unmovable conflict, you feel unsafe or you do not trust the
person inviting you), &lt;a href=&quot;http://www.huffingtonpost.com/panache-desai/the-power-of-one-magnific_b_6802330.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;say yes&lt;/a&gt;. It helps to think of this as a game. It
will encourage you to try something you might otherwise bow out
of. I&apos;m a little scared of hack sessions. I play the yes game and I
make myself go at conferences. It has always ended up being super
fun. Bring a buddy if you are feeling timid! It&apos;s a perfect
opportunity to be an includer. These invitations are almost always
where the greatest opportunities are hiding.&lt;/p&gt;
&lt;h3 id=&quot;part-3---reinforcing-positive-interactions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#part-3---reinforcing-positive-interactions&quot; aria-label=&quot;part 3   reinforcing positive interactions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Part 3 - Reinforcing Positive Interactions&lt;/h3&gt;
&lt;h4 id=&quot;1-reward-bravery&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-reward-bravery&quot; aria-label=&quot;1 reward bravery permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. Reward bravery.&lt;/h4&gt;
&lt;p&gt;Remind yourself that everyone you meet at a conference is being
brave. If someone is brave enough to come talk to you, engage them! If
you are lucky enough to get to talk to one of the speakers or
organizers, thank them for the time and effort they poured into
sharing something they care about with you. Publicly praising the
brave people you&apos;ve talked to on social media is a great way to
reinforce the confidence needed to take risks and be brave.&lt;/p&gt;
&lt;h4 id=&quot;2-follow-up&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-follow-up&quot; aria-label=&quot;2 follow up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. Follow up.&lt;/h4&gt;
&lt;p&gt;Conferences are a whirlwind tour. Everyone you meet has met hundreds
of people in a matter of days. If you uncovered an opportunity, don&apos;t
wait to follow up. Before you go to sleep each night, queue up emails
or social media touches to follow up with the people you met. Say
thank you to the people that helped make your experience great. If
someone offered you advice or encouraged you to try something new,
reach back out to them to let them know you followed their advice and
what the outcome was.&lt;/p&gt;
&lt;h2 id=&quot;community-is-about-participation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#community-is-about-participation&quot; aria-label=&quot;community is about participation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Community is about participation.&lt;/h2&gt;
&lt;p&gt;Conferences are about community, and community is all about
participation. Participation happens on a spectrum. If you are attending your
first conference or you&apos;re just working up to making the jump from
spectator to participant, assess your limits. Don&apos;t go gangbusters on
your first try. Pick a few strategies that sound like they might be in
your wheelhouse and make that your first step. If those work well for
you, try something you&apos;re a little more uncomfortable with. If all you
can manage is to be kind to the people that talk to you, you&apos;ve done
your part to help build a positive community. If you can help one or
two or twenty people have a wonderful conference experience, you&apos;ll
walk away with some fantastic new contacts, some inspiring new ideas,
enhanced confidence and perhaps a solid professional opportunity or
two.&lt;/p&gt;
&lt;p&gt;I’m Lydia Guarino (&lt;a href=&quot;https://twitter.com/lydiaguarino&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@lydiaguarino&lt;/a&gt; on twitter), and I build UI for a living at &lt;a href=&quot;https://frontside.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Frontside&lt;/a&gt;. If you enjoyed this, I’d love to hear from you.&lt;/p&gt;
&lt;p&gt;If you have a project you&apos;d like to work with us on,
&lt;a href=&quot;mailto:cowboyd@frontside.com&quot;&gt;get in touch&lt;/a&gt;. We&apos;re currently taking on
new projects.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/5f23532e40c757511f7fcae6eed49d5a/8a162/2016-03-18-the-insider-track_fridayhugsquare.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Functional Templating in Ember]]></title><description><![CDATA[See how easy it is to build a fully formed image upload widget complete with preview and progress bars when you apply functional programming techniques to your handlebars templates]]></description><link>https://frontside.com/blog/2016-01-22-functional-templating-in-ember/</link><guid isPermaLink="false">https://frontside.com/blog/2016-01-22-functional-templating-in-ember/</guid><category><![CDATA[ember]]></category><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Fri, 22 Jan 2016 12:00:00 GMT</pubDate><content:encoded>&lt;!-- &lt;% content_for :head do  %&gt;
  &lt;%= ember_stylesheet_link_tags &quot;2016-01-22-functional-templating-in-ember&quot; %&gt;
&lt;% end %&gt;
&lt;% content_for :foot do  %&gt;
  &lt;%= ember_javascript_tags &quot;2016-01-22-functional-templating-in-ember&quot; %&gt;
&lt;% end %&gt; --&gt;
&lt;blockquote&gt;
&lt;p&gt;TL;DR --  Avoid using &quot;magically bound&quot; internal component properties in your templates at all costs. Instead be explicit about only passing values around through actions and block params. This will engender a new level of breeziness to your UI.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Implementing a file upload in your web application is just the worst, am I right?&lt;/p&gt;
&lt;p&gt;I mean, once you get your server set up, it’s on to choosing which
off-the-shelf JavaScript Hairball ™ widget you’re going to use to
actually walk the user through the upload process. And no matter which
one you choose it never seems to fit quite right over the long-term
does it? Let’s forget for a moment that they usually come with their
own markup and style which is either difficult or impossible to
replace with your own. As irritating as that is though, it’s something
that we can perhaps live with, or at least wrestle into a submission
hold. But where one-size-fits-all solutions really start to fall down
is when you want to customize the actual file upload workflow. And
even the simplest file upload workflows are involved aren’t they?&lt;/p&gt;
&lt;p&gt;There’s not just the transfer of the bytes. First, there is the file selection process. If the file is an image, at the very least, you may want to show users a preview of that image. In some cases, you want to initiate the file upload immediately and without further action on the part of the user, but then again in others, you may need to stop and perform some intermediate work such as image resizing and cropping, and only then begin the transfer of the file to the server. If you’re uploading other MIME types like spreadsheets, there might be other intermediate preview-modify-and-confirm workflows altogether.&lt;/p&gt;
&lt;p&gt;And so if you’re like me up until about a year ago, your experience with it was a constant and simmering frustration of whacking the square peg of an upload widget into the round hole of your application’s unique workflow, and caulking around the inevitable gouges and gaps with healthy dollops of JavaScript. In a word: Exhausting. Exhausting to stand up in the first place, and exhausting to maintain over the long haul.&lt;/p&gt;
&lt;p&gt;So what would you say if I told you that with Ember components that are available on NPM right now you could build your own image upload widget, complete with preview and progress bars using nothing but about fifteen lines of Handlebars? Furthermore, what if I told you that you had complete freedom to use whatever markup and styling you saw fit, and beyond that, you could do it without a single line of JavaScript?&lt;/p&gt;
&lt;p&gt;With the technique I’m going to outline, you’ll see that these are not outlandish claims, but rather the happy, daily reality of working with what I like to call &lt;em&gt;functional templating&lt;/em&gt;. What makes a template functional? It&apos;s simple really. All it means is that the only way a name becomes bound to a value is via function application. That is to say, as a block parameter, or via a &lt;code class=&quot;language-text&quot;&gt;mut&lt;/code&gt; action.&lt;/p&gt;
&lt;p&gt;A key construct underlying functional templating is the component that has little or no visual presence in terms of markup, but whose sole purpose is to manage a single piece of state and present it to a template.&lt;/p&gt;
&lt;p&gt;I&apos;m going to be using three functional components today to build our file uploader, the first of which is the &lt;em&gt;file chooser&lt;/em&gt;. The file chooser is a component whose sole responsibility is to capture a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/FileList&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;FileList&lt;/a&gt; object and present it to the templating context. What happens to the files is not the concern of the file chooser however. That can be left up to other components later on down the road.&lt;/p&gt;
&lt;p&gt;Let&apos;s see it in action! Click the &quot;choose files&quot; button below to select any number of files and have their metadata displayed in the area below the button.&lt;/p&gt;
&lt;div data-component=&quot;demo-pane&quot; data-attrs=&apos;{&quot;name&quot;: &quot;file-chooser-only&quot;, &quot;title&quot;: &quot;Selecting Files&quot;}&apos;&gt;&lt;/div&gt;
&lt;p&gt;In this example, the &lt;code class=&quot;language-text&quot;&gt;x-file-input&lt;/code&gt;&apos;s action emits a &lt;code class=&quot;language-text&quot;&gt;FileList&lt;/code&gt; object every time that the user selects a group of files. By binding &lt;code class=&quot;language-text&quot;&gt;(action (mut files))&lt;/code&gt; to that action, we can inject that &lt;code class=&quot;language-text&quot;&gt;FileList&lt;/code&gt; into the handlebars scope, so that now it&apos;s available as a templating variable just the same as any other. Once it&apos;s in scope, the &lt;code class=&quot;language-text&quot;&gt;{{each}}&lt;/code&gt; iterates over the files and lists its metadata.&lt;/p&gt;
&lt;p&gt;Notice how the &lt;code class=&quot;language-text&quot;&gt;x-file-input&lt;/code&gt; component in our chooser places very little restriction on the markup that activates the dialog. In this case we chose a button, but we could have made it a link, or a label, or picture of a cat.&lt;/p&gt;
&lt;style type=&quot;text/css&quot;&gt;

 .demo-pane {
   margin-bottom: 2em;
 }

 figure {
   display: inline-block;
   margin-bottom: 1em;
 }

 figure img {
   border: 1px solid #ddd;
   border-radius: 3px;
   background-color: rgb(248,248,248);
   padding: 15px;
   margin: 0 !important;
   border: 1px solid rgb(249,249,249);
   box-shadow: #ccc 1px 1px 10px;
 }
 figcaption {
   padding: 10px 10px 10px 0;
   font-size: 90%;
   font-style: italic;
   border-bottom-left-radius: 2px;
   border-bottom-right-radius: 2px;
 }
&lt;/style&gt;
&lt;figure alt=&quot;picture of data flow from file input to template scope&quot;&gt;
  &lt;img style=&quot;background-color: rgb(248,248,248); padding 15px; border 1px solid #ddd;&quot; src=&quot;/img/2016-01-22-functional-templating-in-ember_file-chooser-only.svg&quot;&gt;
  &lt;figcaption&gt;Fig 1: Data flows from file input into template scope&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Selecting the files and viewing all the metadata about them is great, but in our case, where we&apos;re headed is a full featured file upload complete with preview. In order to get there, we&apos;ll use two more functional components.&lt;/p&gt;
&lt;h3 id=&quot;preview-all-the-images&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#preview-all-the-images&quot; aria-label=&quot;preview all the images permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Preview All the Images&lt;/h3&gt;
&lt;p&gt;In order to preview our image, we&apos;ll need to display it in the browser. Luckily, the &lt;a href=&quot;https://w3c.github.io/FileAPI/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;File API&lt;/a&gt; provides a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;createObjectURL&lt;/a&gt; method to help you do just that. Call it with a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Blob&lt;/a&gt; object, and it hands you back a url that you can use for links, images, or any other place a url might be prone to go. When you&apos;re done with it, you call &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;revokeObjectURL&lt;/a&gt; so that the browser knows it doesn&apos;t need to hang onto that Blob anymore.&lt;/p&gt;
&lt;p&gt;And in order to present this url to our templating context? Yep, you guessed it. We&apos;ll use a functional component. We&apos;ve written an &lt;code class=&quot;language-text&quot;&gt;object-url&lt;/code&gt; component which is responsible for managing an object url. It creates the url out of its &lt;code class=&quot;language-text&quot;&gt;blob&lt;/code&gt; attribute, and then revokes that url when either it receives a new &lt;code class=&quot;language-text&quot;&gt;blob&lt;/code&gt; attribute, or the component itself passes out of scope. Let&apos;s see it in action.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: In this example, the file input has been restricted to only image mime types by setting the &lt;code class=&quot;language-text&quot;&gt;accept&lt;/code&gt; attribute.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div data-component=&quot;demo-pane&quot; data-attrs=&apos;{&quot;name&quot;: &quot;choose-files-with-preview&quot;, &quot;title&quot;: &quot;Choose Images With Preview&quot;}&apos;&gt;&lt;/div&gt;
&lt;p&gt;All we do is allow the &lt;code class=&quot;language-text&quot;&gt;file&lt;/code&gt; attribute to flow right into the &lt;code class=&quot;language-text&quot;&gt;object-url&lt;/code&gt; component which yields the url we need into the template to make the image preview.&lt;/p&gt;
&lt;p&gt;Again, &lt;code class=&quot;language-text&quot;&gt;object-url&lt;/code&gt; has no markup of its own. Instead, its only job is to yield the model that makes the file preview markup possible. In this case, we bind the &lt;code class=&quot;language-text&quot;&gt;url&lt;/code&gt; value yielded by the &lt;code class=&quot;language-text&quot;&gt;x-object-url&lt;/code&gt; to the &lt;code class=&quot;language-text&quot;&gt;background-image&lt;/code&gt; property of a div and we&apos;re done.&lt;/p&gt;
&lt;figure alt=&quot;file value is converted into a url&quot;&gt;
  &lt;img src=&quot;/img/2016-01-22-functional-templating-in-ember_choose-files-with-preview.svg&quot;&gt;
  &lt;figcaption&gt;Fig 2: object-url :: Blob -&amp;gt; String&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Finally, we arrive at our destination: the actual upload. To do this, we use a functional component that executes a real life &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;XMLHttpRequest&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;This might seem totally nuts at first, but mostly because we’ve been trained over the years to think that a custom ajax request has  always got to feel “heavy”. It turns out though that your plain vanilla, garden variety XHR is actually a well defined state machine, and as such, it maps pretty neatly onto a functional component.&lt;/p&gt;
&lt;p&gt;We&apos;ll just let the file object flow into an &lt;code class=&quot;language-text&quot;&gt;x-xml-http-request&lt;/code&gt; component just like it did the &lt;code class=&quot;language-text&quot;&gt;x-object-url&lt;/code&gt;&lt;/p&gt;
&lt;figure alt=&quot;file object flows into x-xml-http-request&quot;&gt;
  &lt;img src=&quot;/img/2016-01-22-functional-templating-in-ember_full-demo.svg&quot;&gt;
  &lt;figcaption&gt;Fig 3: x-xml-http-request :: File -&amp;gt; XHR &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Again, the &lt;code class=&quot;language-text&quot;&gt;x-xml-http-request&lt;/code&gt; has absolutely no markup. Its only job is to continually yield a value into the template that represents the most up-to-date status of the request as it runs. Because of this, we can use it to very quickly model a progress bar! The only thing we need to do is leverage the &lt;code class=&quot;language-text&quot;&gt;xhr.upload.percentage&lt;/code&gt; property within the colorstops of a &lt;code class=&quot;language-text&quot;&gt;linear-gradient&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Heads Up!&lt;/em&gt; The following demo will actually upload images to &lt;a href=&quot;http://posttestserver.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;posttestserver.com&lt;/a&gt; which is a &lt;em&gt;real&lt;/em&gt; server on the &lt;em&gt;real&lt;/em&gt; internet.  Even though it’s  just a bit bucket that periodically wipes all of its contents, you should still &lt;em&gt;never&lt;/em&gt; upload anything sensitive to it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div data-component=&quot;demo-pane&quot; data-attrs=&apos;{&quot;name&quot;: &quot;full-demo&quot;, &quot;title&quot;: &quot;Image Upload With Preview&quot;}&apos;&gt;&lt;/div&gt;
&lt;p&gt;And there you have it. A fairly decent file upload widget in about 15 lines of handlebars. It&apos;s worth noting though, that if you don&apos;t like the way I&apos;ve done it here, you have a free hand to change the markup and workflow to suit your liking since the components I used don&apos;t prescribe any of it.&lt;/p&gt;
&lt;h3 id=&quot;dropping-the-f-bomb&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#dropping-the-f-bomb&quot; aria-label=&quot;dropping the f bomb permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Dropping the F-Bomb&lt;/h3&gt;
&lt;p&gt;These demos were nearly trivial to put together because of the composability afforded by shifting to a more functional style. Values never just magically appear from some unknown location that could be inside your controller or your component. Instead, as in a functional language, variable names like &lt;code class=&quot;language-text&quot;&gt;xhr&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;url&lt;/code&gt; are only ever introduced as the formal parameters of a function. Because each component only interacts with its environment via its inputs and its outputs, it means that they can freely click together output-to-input; in as many ways as you can think of.&lt;/p&gt;
&lt;p&gt;The first time this technique really came together for me it felt impossibly light-weight. It felt like I must be missing something. Could it really be that easy to upload a file? Could I really style it any way that I wanted? Did I really have control over every aspect of the entire workflow from start to finish? And could I really do all of that while providing little or no custom JavaScript? The answer to all those questions turned out to be yes, and the resulting feeling was spectacular.&lt;/p&gt;
&lt;hr/&gt;
&lt;p&gt;I’m Charles Lowell (&lt;a href=&quot;https://twitter.com/cowboyd&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@cowboyd&lt;/a&gt; on twitter), and I build UI for a living at &lt;a href=&quot;https://frontside.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Frontside&lt;/a&gt;. If you enjoyed this, I’d love to hear from you.&lt;/p&gt;
&lt;p&gt;Also, If you&apos;d like to work with our team doing stuff like this, then please &lt;a href=&quot;mailto:cowboyd@frontside.com&quot;&gt;get in touch&lt;/a&gt;. We&apos;re hiring.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/dd57d22b676f75ef5a4e78895f742818/fad57/2016-01-22-functional-templating-in-ember_lisp-all.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[X-Select Status Update]]></title><link>https://frontside.com/blog/2015-08-14-x-select-status-update/</link><guid isPermaLink="false">https://frontside.com/blog/2015-08-14-x-select-status-update/</guid><category><![CDATA[oss]]></category><category><![CDATA[ember]]></category><category><![CDATA[ember-addon]]></category><category><![CDATA[x-select]]></category><dc:creator><![CDATA[Robert DeLuca]]></dc:creator><pubDate>Fri, 14 Aug 2015 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At The Frontside, we love open source, and maintaining OSS projects is a high priority.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;emberx-select&lt;/code&gt; has grown in popularity. &lt;a href=&quot;http://emberjs.com/deprecations/v1.x/#toc_ember-select&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Even the ember deprecation guide recommends it&lt;/a&gt;. We are aiming to keep this component up to date with the latest versions of Ember.&lt;/p&gt;
&lt;p&gt;Before Glimmer (1.13) compatibility, we are making a release for Ember 1.12 or below.&lt;/p&gt;
&lt;h2 id=&quot;whats-new-in-113&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-new-in-113&quot; aria-label=&quot;whats new in 113 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What&apos;s new in 1.1.3?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Title attr bound to an option or select. &lt;a href=&quot;https://github.com/thefrontside/emberx-select/pull/32&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;PR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Add optionValuePath &lt;a href=&quot;https://github.com/thefrontside/emberx-select/pull/31&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;PR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fixed blockless form &lt;a href=&quot;https://github.com/thefrontside/emberx-select/commit/46c7acca9f7bd3a67b08f1fc1f6174759d47f465&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;PR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Default tabindex to 0 to make it tabable. &lt;a href=&quot;https://github.com/thefrontside/emberx-select/pull/37&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;PR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Introduce &lt;code class=&quot;language-text&quot;&gt;registerSelectHelper&lt;/code&gt; &lt;a href=&quot;https://github.com/thefrontside/emberx-select/pull/14&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;PR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Improve test helper &lt;a href=&quot;https://github.com/thefrontside/emberx-select/pull/27&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;PR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Improved testing coverage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See the &lt;a href=&quot;https://github.com/thefrontside/emberx-select/compare/v1.1.2...v1.1.3&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;diff here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thank you to everyone that has helped by submitting issues and pull requests! 1.1.3 will be the last version released that&apos;s compatible with Ember 1.12 or below.&lt;/p&gt;
&lt;h2 id=&quot;whats-new-in-20&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-new-in-20&quot; aria-label=&quot;whats new in 20 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What&apos;s new in 2.0?&lt;/h2&gt;
&lt;p&gt;In x-select 2.0 we dropped support for the blockless form. While it is useful for transitioning
from &lt;code class=&quot;language-text&quot;&gt;Ember.select&lt;/code&gt;, we strongly prefer to standardize writing &lt;code class=&quot;language-text&quot;&gt;selects&lt;/code&gt; in Ember as in HTML.
We no longer bundle x-select with the blockless form. To continue using blockless x-select, &lt;a href=&quot;https://github.com/thefrontside/emberx-select-blockless&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;use this addon&lt;/a&gt; it from x-select.&lt;/p&gt;
&lt;p&gt;x-select 2.0 arrays are now immutable. Every user selection creates a new state of the selected content.
Previously, multi-selects required updating content as a user interacts with the select component. This was unstable especially with async ember data relationships.&lt;/p&gt;
&lt;p&gt;Expect Glimmer/Ember 2.0 compatability in x-select 2.0 thanks to &lt;a href=&quot;https://github.com/thefrontside/emberx-select/pull/33&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;this PR&lt;/a&gt;
from James Rosen!&lt;/p&gt;
&lt;h3 id=&quot;known-glimmer-issue-with-x-select&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#known-glimmer-issue-with-x-select&quot; aria-label=&quot;known glimmer issue with x select permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Known Glimmer issue with x-select&lt;/h3&gt;
&lt;p&gt;To use x-select with Glimmer (Ember 1.13.x) requires 1.13.4+. Anything below
1.13.4 will throw&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Error: Assertion Failed: x-option component declared without enclosing x-select&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;because non-dirty component child views are not getting the correct parentView. You can see the related
ticket &lt;a href=&quot;https://github.com/emberjs/ember.js/pull/11651&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We also applied a &lt;a href=&quot;https://github.com/thefrontside/emberx-select/commit/843f76d6a033f587f9b5edb5fb0758c05e5629c3&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;small hack to work around&lt;/a&gt;
form attribute bindings which are broken in Ember 1.12-1.13.2 and fixed in Ember 1.13.3.
Ember data bindings are lost, so the parent form should not change. If data bindings are still necessary, call &lt;code class=&quot;language-text&quot;&gt;rerender()&lt;/code&gt; on the component after the data change.&lt;/p&gt;
&lt;p&gt;Once again, thanks to all the contributors that helped make the &lt;code class=&quot;language-text&quot;&gt;x-select&lt;/code&gt; component better for everyone!&lt;/p&gt;
&lt;h3 id=&quot;using-x-select-blockless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#using-x-select-blockless&quot; aria-label=&quot;using x select blockless permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using x-select-blockless&lt;/h3&gt;
&lt;p&gt;To use &lt;code class=&quot;language-text&quot;&gt;x-select-blockless&lt;/code&gt; you&apos;ll need to install both &lt;code class=&quot;language-text&quot;&gt;x-select-blockless&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;x-select&lt;/code&gt; ember addons. This is because
&lt;a href=&quot;https://github.com/thefrontside/emberx-select-blockless/blob/master/package.json#L42&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;we rely on&lt;/a&gt; x-select.&lt;/p&gt;
&lt;h3 id=&quot;compatibility-table&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#compatibility-table&quot; aria-label=&quot;compatibility table permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Compatibility Table&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;x-select&lt;/th&gt;
&lt;th&gt;Ember&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;v1.1.4 and before&lt;/td&gt;
&lt;td&gt;1.12 or lower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v2.x.x and after&lt;/td&gt;
&lt;td&gt;1.13.4 or higher&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</content:encoded></item><item><title><![CDATA[Programming in the Wild West]]></title><link>https://frontside.com/blog/2014-05-16-programming-in-the-wild-west/</link><guid isPermaLink="false">https://frontside.com/blog/2014-05-16-programming-in-the-wild-west/</guid><category><![CDATA[community]]></category><category><![CDATA[javascript]]></category><category><![CDATA[tdd]]></category><dc:creator><![CDATA[Brandon Hays]]></dc:creator><pubDate>Fri, 16 May 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Much like revisiting a neighborhood from my youth, when I reflect on my scant few years in software I&apos;m astonished at how much has changed.&lt;/p&gt;
&lt;p&gt;This might have also struck you at some point. Perhaps you were even a pioneer in your community&apos;s wild west days, huddling in log cabins of your own construction, only to look around now and see yoga studios and gourmet cupcake shops.&lt;/p&gt;
&lt;p&gt;The pattern of how and why this happens is actually related to the way the &quot;red-green-refactor&quot; loop in test-first development helps match our work to our brains. But more importantly, it&apos;s reflective of how we can adapt and help our communities as they mature.&lt;/p&gt;
&lt;h3 id=&quot;first-a-journey-into-the-human-brain&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#first-a-journey-into-the-human-brain&quot; aria-label=&quot;first a journey into the human brain permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;First, a journey into the human brain&lt;/h3&gt;
&lt;p&gt;Studies are revealing that during complex tasks, each of us switches between &lt;strong&gt;&quot;open mode&quot;&lt;/strong&gt;, primarily associated with free-form experimentation, and &lt;strong&gt;&quot;closed mode&quot;&lt;/strong&gt;, associated with focused execution.&lt;/p&gt;
&lt;p&gt;Sarah Mei spoke about this last year at LoneStarRuby, and compared the TDD cycle to moving between these modes. &lt;em&gt;(Starting at 12:20)&lt;/em&gt;&lt;/p&gt;
&lt;iframe width=&quot;640&quot; height=&quot;390&quot; src=&quot;//www.youtube.com/embed/P4RA7NYyG24&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;The general idea is that at different times, &lt;strong&gt;people are better at thinking about the big picture, or zooming in on the details, but not both simultaneously.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This sounds like a simple concept, even obvious, but we ignore it so much that when we actually put the idea into practice, it can be life-altering.&lt;/p&gt;
&lt;h3 id=&quot;test-first-and-open--closed-modes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#test-first-and-open--closed-modes&quot; aria-label=&quot;test first and open  closed modes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Test-first and open &amp;#x26; closed modes&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/experiment-1.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;The TDD cycle&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;First, I should clarify that this is representative of how I&apos;ve learned to define and practice test-first development, and others may have different definitions or methods.&lt;/p&gt;
&lt;p&gt;For me, this pattern has helped me leverage the strengths of open/closed modes in my brain, because &lt;strong&gt;it compartmentalizes times for experimentation and then execution.&lt;/strong&gt; Much of my own &quot;open mode&quot; experimentation happens via a practice that I don&apos;t often hear discussed in TDD circles: spiking code.&lt;/p&gt;
&lt;p&gt;The &quot;spike&quot; is where you throw away best practices, testing, and most forms of discipline in favor of discovery. You get out the machete and hack a meandering path from Point A to Point B.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spiking is the act of figuring out what question you need to be asking.&lt;/strong&gt; The &quot;red&quot; step is asking the question, then the rest of the TDD process is about answering it. To me, the spiking phase is an essential part of the &quot;open mode&quot; quest to ask the right questions.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The only rule of the spike is that it must be thrown away.&lt;/em&gt; You now know where Point B is, and the second trip through using discipline and techniques like TDD will reveal a much straighter path.&lt;/p&gt;
&lt;p&gt;But it&apos;s an extremely bitter pill: &lt;strong&gt;throwing away functioning code is one of the most ego-shattering, counterintuitive things I do as a developer.&lt;/strong&gt; However, I&apos;ve learned it&apos;s typically faster to subjugate my ego and just delete the code.&lt;/p&gt;
&lt;p&gt;The spike clears the &quot;fog of war&quot;, shedding light on real-life obstacles in my initial design. Their concrete result is a set of high-level integration tests, from which I can drive out a new implementation in a more direct, point-A-to-point-B way, without having to machete-hack through the jungle.&lt;/p&gt;
&lt;h3 id=&quot;how-this-relates-to-software-communities&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-this-relates-to-software-communities&quot; aria-label=&quot;how this relates to software communities permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How this relates to software communities&lt;/h3&gt;
&lt;p&gt;Software communities, unsurprisingly, behave much like the humans who comprise them.&lt;/p&gt;
&lt;p&gt;Yehuda Katz gave a landmark talk at RailsConf, inspiring this post in the first place. He talks about when it&apos;s time to move from &lt;em&gt;experimentation&lt;/em&gt; mode to &lt;em&gt;shared solutions&lt;/em&gt; mode in your community. &lt;em&gt;(Starting at 13:25)&lt;/em&gt;&lt;/p&gt;
&lt;iframe width=&quot;640&quot; height=&quot;390&quot; src=&quot;//www.youtube.com/embed/9naDS3r4MbY&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;The talk covers several topics, but the main point to me was that software communities have trouble toggling between experimentation (&quot;open&quot;) mode and shared solutions (&quot;closed&quot;) mode.&lt;/p&gt;
&lt;p&gt;To me, this looks a lot like the test-first cycle above:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/experiment-2.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;The community cycle&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Early in a community&apos;s maturity, it may be time for a bazaar of different solutions&lt;/strong&gt; while everyone is simply learning the right questions to ask. What does an authentication solution look like? What about persistence? Security? Code sharing? Scalability? Deployment?&lt;/p&gt;
&lt;p&gt;Once a community settles on those few key questions and sees some possible solutions to each, the time comes to get behind existing solutions and improve them. Often, these early projects aren&apos;t extremely pleasant to use or well-factored, but can serve to clear that &quot;fog of war&quot; inherent to a new domain. But once the fog is cleared, one or two solutions to a given problem usually gain traction within a community.&lt;/p&gt;
&lt;h3 id=&quot;worse-is-better&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#worse-is-better&quot; aria-label=&quot;worse is better permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&quot;Worse is Better&quot;&lt;/h3&gt;
&lt;p&gt;When it feels like a community is rallying around a shared set of abstractions, it may be time to delclare it a platform and move from experimentation mode to reaching an agreement. Examples of this in the past include the merging of rival Ruby frameworks Merb and Rails, or the Promises/A+ spec in JavaScript.&lt;/p&gt;
&lt;p&gt;In order for this to work, people in a community must be willing to put their energy and focus behind a set of solutions that they don&apos;t see as ideal. Maybe they even think they suck. Yehuda used the phrase &lt;a href=&quot;http://www.jwz.org/doc/worse-is-better.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&quot;worse is better&quot;&lt;/a&gt; to describe this. The concept is generally that &lt;strong&gt;after the time of experimentation, a community is better served by embracing a comparatively crummy solution and improving it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There&apos;s friction when this change starts happening. Some people feel left behind by the community they helped build. Others see the flaws in existing solutions and want to take their best shot at it, though the time for experimentation has passed. Many may feel that no shared solution could possibly approximate their unique needs.&lt;/p&gt;
&lt;p&gt;The good news is that after agreeing on a solution, even if it&apos;s a sub-optimal, you can improve the new shared solution, and without much fanfare, there&apos;s a new platform for everyone to build upon.&lt;/p&gt;
&lt;h3 id=&quot;platforms-and-scaffolding&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#platforms-and-scaffolding&quot; aria-label=&quot;platforms and scaffolding permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Platforms and scaffolding&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/experiment-3.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Platforms and scaffolding&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Each new layer adds a level of abstraction, so &lt;strong&gt;you need to have confidence in the layers beneath you.&lt;/strong&gt; In software projects, this confidence comes from good tests. In communities, the confidence tends to come from seeing a project in broad use.&lt;/p&gt;
&lt;p&gt;We don&apos;t spend a ton of time wondering if UNIX is going to crumble beneath us when we&apos;re building web applications on top of it, or that the V8 engine in Chrome is just going to stop evaluating JavaScript.&lt;/p&gt;
&lt;p&gt;At some point, we declare these to be stable platforms and simply build on top of them without constantly running down to the basement to make sure the furnace didn&apos;t explode.&lt;/p&gt;
&lt;h3 id=&quot;programming-in-the-wild-west&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#programming-in-the-wild-west&quot; aria-label=&quot;programming in the wild west permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Programming in the Wild West&lt;/h3&gt;
&lt;p&gt;When I was first learning to program, I was taught a term for people who refuse to leave the &quot;spike&quot; phase of programming. They&apos;re called &quot;cowboy coders&quot;, often disparagingly. Many of my favorite programmers work in this style, so I use the term hoping it implies no judgment on my part.&lt;/p&gt;
&lt;p&gt;Communities have an equivalent type, the &quot;pioneer&quot; who prefers to live in the experimentation phase. Pioneers would rather invent a persistence library or templating engine than spend their day building apps in an existing framework.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When you are in the Wild West, you are, by nature of your presence, a unique and special snowflake.&lt;/strong&gt; You&apos;re the pioneer. You could be the first doctor, the first newspaper editor, or the first blacksmith. All the problems you encounter are by definition novel, and you must survive by your own ingenuity.&lt;/p&gt;
&lt;p&gt;Pioneers have much to offer in the &quot;wild west&quot; phase of a developer community. There are few tools, no consensus, and little infrastructure, so there&apos;s ample opportunity to contribute in a significant way.&lt;/p&gt;
&lt;p&gt;The Rust community seems like a good example of a current-day wild west, leaving many questions yet to be asked, much less answered.&lt;/p&gt;
&lt;h3 id=&quot;the-taming-of-the-west&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-taming-of-the-west&quot; aria-label=&quot;the taming of the west permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The taming of the West&lt;/h3&gt;
&lt;p&gt;But after a while, the gold rush has passed, and people have set up Costcos and Pilates studios. The experimentation phase is over, and people have decided on a platform.&lt;/p&gt;
&lt;p&gt;Programmers using Rails might remember this starting around Rails 3.0. After that, the big questions were answered, and a few solutions emerged that have evolved into what are essentially just &lt;a href=&quot;http://words.steveklabnik.com/rails-has-two-default-stacks&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;two technology stacks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The problem occurs when remaining pioneers still want to build a hospital, but there are now plenty of decent hospitals. The community has matured to where offering a lot of alternative solutions start doing more harm than good, creating confusion and decision fatigue.&lt;/p&gt;
&lt;p&gt;How do you know a community is reaching the end of the experimentation phase?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You see articles saying &quot;please no more {{x technology}} testing libraries/package managers/persistence frameworks&quot;&lt;/li&gt;
&lt;li&gt;Consultants specializing in {{x technology}} proliferate&lt;/li&gt;
&lt;li&gt;Both traditional and hacker schools start teaching {{x technology}}&lt;/li&gt;
&lt;li&gt;You see job postings at Fortune 500 companies for {{x technology}}&lt;/li&gt;
&lt;li&gt;{{x technology}} is on the cover of magazines targeted at CEO types&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-bitter-pill&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-bitter-pill&quot; aria-label=&quot;the bitter pill permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The bitter pill&lt;/h3&gt;
&lt;p&gt;Remember the bitter pill in TDD, throwing away the spike to embrace discipline and move into closed mode?&lt;/p&gt;
&lt;p&gt;As a software community&apos;s experimentation phase wraps up and moves into shared solutions, developers have a bitter, ego-shattering pill to swallow, as well. &lt;strong&gt;It&apos;s the admission that you are not a special snowflake.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you want to continue working in the community you helped grow, you suddenly have to contend with the fact that many other people moved in and share your same set of problems. It can be brutal to face the idea that a community stands to get greater benefit if you now pour your efforts into shared solutions than into a bespoke, one-of-a-kind tool.&lt;/p&gt;
&lt;h3 id=&quot;go-west&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#go-west&quot; aria-label=&quot;go west permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Go West!&lt;/h3&gt;
&lt;p&gt;Some people have an insatiable desire to pioneer. They are never satisfied with the state of things and want to see the best solution prevail. As they see fences erected and freeways built, they can feel frustrated, as if their freedom is being taken away.&lt;/p&gt;
&lt;p&gt;A Rails developer may be tempted to create a better persistence framework, but the community has largely agreed on ActiveRecord and is actively working to make it better.&lt;/p&gt;
&lt;p&gt;So what&apos;s a pioneering spirit to do? That&apos;s the tough part. You can pioneer in ever-smaller niches within your community, swallow the bitter pill of not being a unique snowflake and work on the &quot;worse&quot; solutions, or head west in search of a less mature community in need of doctors and blacksmiths.&lt;/p&gt;
&lt;p&gt;You may even find it rewarding to play around with all three options. And the best part is, &lt;strong&gt;there is an infinite frontier for programmers.&lt;/strong&gt; You can always go west, there is always something new to explore if your desire is to chase the sunset into the unknown.&lt;/p&gt;
&lt;h3 id=&quot;understanding-openclosed-modes-is-good-for-your-software&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#understanding-openclosed-modes-is-good-for-your-software&quot; aria-label=&quot;understanding openclosed modes is good for your software permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Understanding open/closed modes is good for your software&lt;/h3&gt;
&lt;p&gt;I am insatiably curious as to why things work, and I&apos;m so glad that Sarah touched on exactly &lt;em&gt;why&lt;/em&gt; TDD works in her talk.&lt;/p&gt;
&lt;p&gt;I started as a &quot;cowboy coder&quot; and resisted testing for a long time, particularly TDD. It feels restrictive to have to compartmentalize. I already know how to make something work. But it doesn&apos;t take me much time to realize how expensive it is to try and do both modes at once, the complexity catches up with me, and I end up wishing I could throw the code in the garbage instead of maintain it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In TDD, you&apos;re dividing the incredibly complex task of writing software along the brain&apos;s natural modes.&lt;/strong&gt; In a designated period of &quot;open mode&quot; thinking, you start to ask the right questions, giving you a concrete result: failing test cases.&lt;/p&gt;
&lt;p&gt;You then have a natural break into closed-mode, solution-oriented work, and back again. You let the tests act as a sort of bookmark for your thinking as you toggle between modes, keeping you in context and making you more productive.&lt;/p&gt;
&lt;p&gt;Let&apos;s look again at the circular diagrams above. From that perspective, they look positively Sisyphean and don&apos;t tell the whole story. In reality, they are the means by which these towering platforms are built, but you have to view the circle from a third dimension to see it:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/experiment-4.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;The TDD cycle, from the side&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;With good tests, every trip around the loop provides more capabilities on top of a trustworthy codebase. You can keep building without fear of your codebase collapsing under the weight of its own complexity.&lt;/p&gt;
&lt;h3 id=&quot;understanding-openclosed-modes-is-good-for-communities&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#understanding-openclosed-modes-is-good-for-communities&quot; aria-label=&quot;understanding openclosed modes is good for communities permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Understanding open/closed modes is good for communities&lt;/h3&gt;
&lt;p&gt;In Yehuda&apos;s talk, he plays a couple of videos of Steve Jobs talking about using frameworks to provide a solid platform, so you can build your 5 stories starting on the 25th floor, rather than the 5th floor.&lt;/p&gt;
&lt;p&gt;In open source software communities, we can&apos;t simply buy into these platforms, we have to agree on them. This happens in the same open/closed cycle: we discover questions by experimenting in open mode, then diving into the closed-mode work of converging on a solution and improving it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The benefit is an exponential gain in productivity because we aren&apos;t exhausting ourselves&lt;/strong&gt; by keeping 25 floors of scaffolding from collapsing, and instead focusing only on the few flights that comprise our software&apos;s unique needs.&lt;/p&gt;
&lt;p&gt;At each turn of the loop, a community is establishing a platform for the next go-round. Open source has done a phenomenal job of this over the last 30 years, and the cumulative effect is simply staggering.&lt;/p&gt;
&lt;h3 id=&quot;the-pain-of-moving-into-closed-mode&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-pain-of-moving-into-closed-mode&quot; aria-label=&quot;the pain of moving into closed mode permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The pain of moving into &quot;closed mode&quot;&lt;/h3&gt;
&lt;p&gt;When Yehuda outlined the difficulty in moving from &quot;experimentation&quot; mode to &quot;shared solution&quot; mode, I felt as if a gong went off in my head, and I suddenly understood much of the friction in the maturing JavaScript community.&lt;/p&gt;
&lt;p&gt;I&apos;d contend that we&apos;re reaching the end of the JavaScript community&apos;s experimentation phase, particularly as it pertains to building client-side applications. We&apos;re starting to see people setting up Pilates studios and Costcos. It&apos;s entirely possible we&apos;ll be talking about ES6 as a watershed moment, the way Rails developers sometimes do about the shift to Rails 3.&lt;/p&gt;
&lt;p&gt;This can be rough on the pioneers who got us here. It can also feel constrictive to those who want to build a better version of an existing solution. It&apos;s not easy for me, either. I want great tools, not mediocre ones. But if we want the benefits of building on top of platforms instead of our own rickety scaffolding, &lt;strong&gt;our responsibility is to embrace imperfect solutions as they get traction, and then improve them.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&apos;m glad to have the opportunity to participate in the JavaScript community as it starts to converge on &quot;platform-level&quot; solutions. If we&apos;ll work together and embrace that we&apos;re not &quot;unique and special snowflakes&quot;, we can focus on the few floors that actually make our software unique and valuable to other people, so the next generation of developers can start building on the 1000th floor.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/2a1a0a3c66cbac1302754ed793ab03db/473cd/2014-05-16-programming-in-the-wild-west-1.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Ember and the future of the web]]></title><link>https://frontside.com/blog/2014-02-24-ember-and-the-future-of-the-web/</link><guid isPermaLink="false">https://frontside.com/blog/2014-02-24-ember-and-the-future-of-the-web/</guid><category><![CDATA[ember]]></category><category><![CDATA[platforms]]></category><category><![CDATA[prognostication]]></category><dc:creator><![CDATA[Brandon Hays]]></dc:creator><pubDate>Mon, 24 Feb 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you know me, you know it&apos;s easy to get me talking about &lt;a href=&quot;http://emberjs.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Ember.js&lt;/a&gt;. A year ago, I was deeply skeptical of developing client-side applications. Now, after spending a year shipping production applications in Ember, I believe that client-side apps represent the same generational leap that database-backed apps with Rails offered circa 2006.&lt;/p&gt;
&lt;p&gt;Despite the title of this article, I can&apos;t actually predict the future, but I can bet on it. And Charles and I are betting The Frontside&apos;s future on the fact that Ember provides a foundation for creating amazing, next-generation user experiences for the web.&lt;/p&gt;
&lt;h2 id=&quot;what-server-side-mvc-does-well-and-doesnt&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-server-side-mvc-does-well-and-doesnt&quot; aria-label=&quot;what server side mvc does well and doesnt permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What server-side MVC does well (and doesn&apos;t)&lt;/h2&gt;
&lt;p&gt;Server-side MVC frameworks rely on the classic Apple philosophy of optimizing for the 80% use case. These frameworks excel at taking a database, exposing CRUD (Create, Read, Update, Destroy) actions via HTTP, and building form-based UIs to work with these records. CRUD-oriented frameworks make it easy to build applications like blogs and contact management software.&lt;/p&gt;
&lt;p&gt;What server-side MVC frameworks are not particularly well-suited to are user-driven, stateful UIs like you&apos;d see in desktop apps like Word, Excel, or iTunes.&lt;/p&gt;
&lt;p&gt;Rails, as a mature framework, has evolved a set of standard solutions to these types of problems. Generally, they involve minimizing the amount of JavaScript needed and placing as much of the burden on the server as possible.&lt;/p&gt;
&lt;h2 id=&quot;server-side-workarounds&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#server-side-workarounds&quot; aria-label=&quot;server side workarounds permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Server-side workarounds&lt;/h2&gt;
&lt;p&gt;I&apos;ve built these many times &quot;the Rails way&quot;, and I can viscerally feel myself cross the boundaries of the things Rails does well. I might start by creating a template called &lt;code class=&quot;language-text&quot;&gt;create.js.erb&lt;/code&gt; to be triggered from &lt;code class=&quot;language-text&quot;&gt;new.html.erb&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;#tag_form&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&amp;lt;%=j render(&quot;form&quot;) %&gt;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;#tags&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&amp;lt;%=j render(@el.all_tags) %&gt;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;initSelect2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#tags&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But what&apos;s actually happening here is not simple (and has &lt;a href=&quot;http://homakov.blogspot.com/2013/05/do-not-use-rjs-like-techniques.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;security implications&lt;/a&gt; that bear keeping in mind):&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://homakov.blogspot.com/2013/05/do-not-use-rjs-like-techniques.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;img src=&quot;/img/rjs-flow.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;
&lt;em&gt;(Credit: &lt;a href=&quot;http://homakov.blogspot.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Egor Homakov&apos;s blog&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And that&apos;s a greatly simplified example. The fact is that if you&apos;re building stateful client-side interactions, you&apos;re already managing a lot of JavaScript, but your code is probably scattered across jQuery plugins, server-side rendered JavaScript, and custom JS in your assets.&lt;/p&gt;
&lt;p&gt;These patterns quickly become difficult to maintain, and the pain encourages developers to steer clear of complex interactions and focus on the Rails happy path.&lt;/p&gt;
&lt;p&gt;And this isn&apos;t necessarily a bad thing. We love Rails for making those tradeoffs on our behalf, so we can focus on the 80% case.&lt;/p&gt;
&lt;p&gt;But I have two cautions about this kind of pragmatism:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Trying to stretch the 80% solution into the other 20% almost always results in pain.&lt;/li&gt;
&lt;li&gt;Keep your eye on the 20%, because it may just be the next 80% use case.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;two-cases-for-using-ember&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#two-cases-for-using-ember&quot; aria-label=&quot;two cases for using ember permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Two cases for using Ember&lt;/h2&gt;
&lt;p&gt;Ember, to me, indicates a seismic shift in the way web applications are created. And not because Ember itself is so great (although I do like it a lot).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rather, it&apos;s that Ember makes it &lt;em&gt;fun&lt;/em&gt; to splash around in the other 20% and build next-generation applications.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&apos;ll make two cases for Ember and then explain how I see it as a representation of the web of the future.&lt;/p&gt;
&lt;h3 id=&quot;case-1-mvcmvc-is-a-feature-not-a-bug&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#case-1-mvcmvc-is-a-feature-not-a-bug&quot; aria-label=&quot;case 1 mvcmvc is a feature not a bug permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Case 1: MVC/MVC is a feature, not a bug&lt;/h3&gt;
&lt;p&gt;I&apos;m a classic pragmatist. I like to learn things with an eye toward solving problems. So the concept of an MVC framework on top of an MVC framework struck me as odious. But since then, I&apos;ve come to see it as incredibly freeing.&lt;/p&gt;
&lt;p&gt;I never realized how much of my thinking was shaped by the limitations of the tools I used until exploring something with a totally different set of capabilities and constraints.&lt;/p&gt;
&lt;p&gt;Let&apos;s look at the original Rails app, Basecamp:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/basecamp-marked-up.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Basecamp&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Yes, the screenshot is outdated. This is not meant as a knock against Basecamp, which has been since rewritten, but rather an example of how most of us write our Rails apps. &lt;strong&gt;Server-side MVC frameworks lay a yellow brick road right to that interface.&lt;/strong&gt; It&apos;s certainly representative of the majority of &lt;em&gt;my&lt;/em&gt; vanilla Rails applications.&lt;/p&gt;
&lt;p&gt;A few months ago, we started using the chat service Slack. I feel comfortable saying that it is a good example of web applications in 2014: it is so deeply interactive and so native-feeling that it nearly made me choke on my Cheerios.&lt;/p&gt;
&lt;p&gt;See if you can spot a direct mapping to database rows in Slack:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;figure&quot;&gt;&lt;img src=&quot;/img/slack-marked-up.png&quot;&gt;&lt;figcaption class=&quot;figure-caption&quot;&gt;Slack&lt;/figcaption&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;I sure couldn&apos;t pin it down. In fact, after downloading the standalone Slack app for OS X, I was sure that it was a native app until I right-clicked and saw &quot;inspect element&quot; in the menu. It&apos;s not an Ember app, but I can easily see how it would be done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Client-side applications basically require you to saw your applications in half.&lt;/strong&gt; Handle your persistence layer however you want, just expose APIs to create, update, fetch, or delete records (a task to which Rails is particularly well-suited).&lt;/p&gt;
&lt;p&gt;The other half of your application is now 100% tailored to the user interface you want to build. You find yourself using the language and workflow of your users, rather than wiggling around within the constraints of your database tables and columns.&lt;/p&gt;
&lt;p&gt;All of this is wonderful, but represents any client-side MVC, rather than being unique to Ember.&lt;/p&gt;
&lt;h3 id=&quot;case-2-you-need-models-you-just-might-not-know-it-yet&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#case-2-you-need-models-you-just-might-not-know-it-yet&quot; aria-label=&quot;case 2 you need models you just might not know it yet permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Case 2: You Need Models, You Just Might Not Know it Yet&lt;/h3&gt;
&lt;p&gt;Ember has a lot of strong suits, but one of the strongest is its rock-solid model layer. There aren&apos;t many hard UI problems that can&apos;t be made much simpler by using models to back your interactions.&lt;/p&gt;
&lt;p&gt;Back to my personal journey: After a while, I abandoned RJS and started using plain JavaScript and jQuery to manage complex interactions.&lt;/p&gt;
&lt;p&gt;My new AJAX-y workflow went like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Let the server render stuff to the page&lt;/li&gt;
&lt;li&gt;Set up a controller to handle AJAX requests from the UI&lt;/li&gt;
&lt;li&gt;Manipulate the DOM using a jQuery plugin&lt;/li&gt;
&lt;li&gt;Traverse the DOM again to see what changed&lt;/li&gt;
&lt;li&gt;Serialize changes from the DOM and send via AJAX&lt;/li&gt;
&lt;li&gt;The server returns an HTML string that is stuffed back into the DOM&lt;/li&gt;
&lt;li&gt;Repeat steps 3-6&lt;/li&gt;
&lt;li&gt;Spend days troubleshooting inconsistent UI results&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&apos;ll spare you the gory details, but I&apos;ve written a ton of code that looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ZOMG remember to clean up row position or everything breaks&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;renumberRows&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#sortable .content_item:visible&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.row_num&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not only is this style not simple, it&apos;s quite difficult to test. My application is flying blind on steps 3-5, which, as it turns out, is the absolute core of the user experience.&lt;/p&gt;
&lt;p&gt;With Ember, these DOM manipulations are &lt;em&gt;side effects&lt;/em&gt; of working with models. A user doesn&apos;t know it, but they&apos;re pushing actual data around, toggling boolean attributes, and moving full-blown objects between lists.&lt;/p&gt;
&lt;p&gt;Here&apos;s an Ember computed property to illustrate:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Model, you worry about position and I&apos;ll go get a soda&lt;/span&gt;
&lt;span class=&quot;token function-variable function&quot;&gt;sortedRows&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;rows&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sortBy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;position&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;rows&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I can&apos;t show actual comparison code to the &lt;code class=&quot;language-text&quot;&gt;renumberRows()&lt;/code&gt; function because in Ember, &lt;em&gt;there is none&lt;/em&gt;. Any changes rendered on the screen are the automatic result of changes to model data. With Ember&apos;s router, even your URL is rooted in this model data.&lt;/p&gt;
&lt;p&gt;Think about that for a second. Imagine never writing another line of jQuery code that second-guesses or cleans up inconsistencies from your DOM.&lt;/p&gt;
&lt;p&gt;Ember&apos;s object model, its system of observers and computed properties, and the way these are bound to the DOM are second to none. Its model layer isn&apos;t bolted on or mixed in, it&apos;s the foundation of the framework itself, and is absolutely rock solid.&lt;/p&gt;
&lt;h2 id=&quot;looking-out-for-the-next-80&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#looking-out-for-the-next-80&quot; aria-label=&quot;looking out for the next 80 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Looking out for the next 80%&lt;/h2&gt;
&lt;p&gt;The book &lt;a href=&quot;http://www.amazon.com/Innovators-Dilemma-Technologies-Management-Innovation-ebook/dp/B00E257S86/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Innovator&apos;s Dilemma&lt;/a&gt; is a fantastic read, and, I believe, applicable to the state of MVC frameworks.&lt;/p&gt;
&lt;p&gt;The same pragmatism that allows us to get things done can actually become toxic after a significant degree of success. Almost by default, people tend to try and extract the maximum value out of existing solutions. They don&apos;t notice as the ground shifts beneath them, and are often surprised to find that their old, reliable solution has been disrupted.&lt;/p&gt;
&lt;p&gt;By nearly all accounts, when Rails entered the scene it acted as this disruptive force. As anyone trying to bring Rails to work projects before 2010 will tell you, it was a tough sell, often being shouted down for not being &quot;enterprise grade&quot;.&lt;/p&gt;
&lt;p&gt;To me, the most powerful feature of Rails was that it took things that were excruciatingly painful to build and made them &lt;em&gt;fun&lt;/em&gt;. It took user interactions that were previously reserved for large teams of experienced developers and put that power in the hands of small, nimble teams and newer developers.&lt;/p&gt;
&lt;p&gt;Ten years after its inception, Rails now represents the 80% use case for web applications, with the 20% use case invovling highly interactive, app-like experiences.&lt;/p&gt;
&lt;h2 id=&quot;the-new-table-stakes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-new-table-stakes&quot; aria-label=&quot;the new table stakes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The new table stakes&lt;/h2&gt;
&lt;p&gt;A decade ago, my water delivery company could get away with a static site with their phone number on it if you wanted to sign up or schedule a delivery.&lt;/p&gt;
&lt;p&gt;Now, I&apos;d take my business elsewhere if I couldn&apos;t manage my delivery schedule online. The stakes simply went up. My expectations as a user went up.&lt;/p&gt;
&lt;p&gt;I&apos;ll contend that we&apos;re on the cusp of a new &quot;80% expectation&quot;: the majority of people using our software on the web are now becoming accustomed to richer, more app-like experiences. The stakes are being raised.&lt;/p&gt;
&lt;h2 id=&quot;embers-bet-on-the-future&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#embers-bet-on-the-future&quot; aria-label=&quot;embers bet on the future permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ember&apos;s bet on the future&lt;/h2&gt;
&lt;p&gt;Many of the benefits above are just about making it easier to do &lt;em&gt;the same things&lt;/em&gt; we did before. But that&apos;s not Ember&apos;s bet. Ember&apos;s gamble is that when armed with this set of tools, you&apos;ll attempt increasingly ambitious projects.&lt;/p&gt;
&lt;h4 id=&quot;browser-as-an-app-platform&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#browser-as-an-app-platform&quot; aria-label=&quot;browser as an app platform permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Browser as an App Platform&lt;/h4&gt;
&lt;p&gt;I can&apos;t speak for the team that created Ember, but I can say from my vantage point that it looks like Ember is betting that the browser will act as an application runtime, not unlike the platforms for iOS or Android, and that the web is becoming the world&apos;s largest and most open app marketplace.&lt;/p&gt;
&lt;h4 id=&quot;interchangeable-reusable-components&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#interchangeable-reusable-components&quot; aria-label=&quot;interchangeable reusable components permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Interchangeable, Reusable Components&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;http://css-tricks.com/modular-future-web-components/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Web Components&lt;/a&gt; are an important upcoming change to the way web developers work, and Ember&apos;s take on them is impressive. When you start using Ember Components, it feels like the jQuery UI of the future: You get reusable drop-in functionality that&apos;s totally customizable, and backed by Ember&apos;s model system.&lt;/p&gt;
&lt;p&gt;Ember Components are worth the price of admission alone, and we do drop them in as standalone pieces of interactivity into some of our server-side apps when it isn&apos;t feasible to create a full Ember application.&lt;/p&gt;
&lt;h2 id=&quot;ember-in-the-real-world&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ember-in-the-real-world&quot; aria-label=&quot;ember in the real world permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ember in the real world&lt;/h2&gt;
&lt;p&gt;Its rather audacious goals are why Ember is improving so quickly, and the things people are building with it are sometimes mind-boggling.&lt;/p&gt;
&lt;p&gt;Here are just a few of the cool things I&apos;ve seen come out of the Ember community lately:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://nbcnews.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;NBC News&lt;/a&gt;: NBC&apos;s new interface is more interactive exhibit than static news website&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://huboard.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Huboard&lt;/a&gt;: A lovely kanban board built on top of GitHub issues&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://discourse.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Discourse&lt;/a&gt;: No less audacious a goal than to replace every PHP forum on the internet&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://emberbeats.gavinjoyce.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Ember Beats&lt;/a&gt;: Super fun drum machine webapp&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://bustle.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Bustle&lt;/a&gt;: A women-focused news and opinion site&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vine.co/feed&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Vine&lt;/a&gt;: Twitter&apos;s 6-second video site&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The limitations of the Web have historically been in its underlying technologies, but with advances like HTML5, CSS3, and tools like Ember, our biggest limitation on the web is quickly becoming our own imaginations.&lt;/p&gt;
&lt;h2 id=&quot;challenges&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#challenges&quot; aria-label=&quot;challenges permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Challenges&lt;/h2&gt;
&lt;h4 id=&quot;challenge-1-the-learning-curve&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#challenge-1-the-learning-curve&quot; aria-label=&quot;challenge 1 the learning curve permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Challenge 1: The learning curve&lt;/h4&gt;
&lt;p&gt;Learning Ember was a challenge for me. I started pretty early and the framework was famous at the time for frequent, major API changes and sparse documentation.&lt;/p&gt;
&lt;p&gt;Those have both largely been addressed with &lt;a href=&quot;http://emberjs.com/guides/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;great documentation&lt;/a&gt; and things like &lt;a href=&quot;https://www.codeschool.com/courses/warming-up-with-emberjs&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Code School&lt;/a&gt;, and I see newcomers picking things up about 5 times faster than I did. (Here&apos;s hoping that speaks more about the state of Ember than it does my learning abilities.)&lt;/p&gt;
&lt;p&gt;That said, it is a big library and can still feel still quite challenging to learn, and may actually be &lt;em&gt;more&lt;/em&gt; difficult for programmers who are skilled at server-side MVC and must &quot;un-learn&quot; the way their framework handled working with the front end.&lt;/p&gt;
&lt;p&gt;But once you grasp a few core concepts, you&apos;ll start to &quot;get&quot; Ember, and we&apos;ll outline those in another post.&lt;/p&gt;
&lt;h4 id=&quot;challenge-2-js-solution-fragmentation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#challenge-2-js-solution-fragmentation&quot; aria-label=&quot;challenge 2 js solution fragmentation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Challenge 2: JS solution fragmentation&lt;/h4&gt;
&lt;p&gt;Tools for languages like Ruby are now mature, stable platforms, while JavaScript, by comparison, can feel like the wild west.&lt;/p&gt;
&lt;p&gt;If you want RSpec as your test framework in Rails, it&apos;s generally one or two lines of code to make the change. Choosing and setting up your test setup in JavaScript is still confusing and often fraught with issues.&lt;/p&gt;
&lt;p&gt;The good news is that people are working to solve this problem as well. Ember App Kit is one of the most ambitious projects I&apos;ve seen in this space. It&apos;s young but it seems to aim to make choosing and setting up all the ancillary stuff as simple as it is in server-side frameworks like Rails.&lt;/p&gt;
&lt;h2 id=&quot;so-why-ember-specifically&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#so-why-ember-specifically&quot; aria-label=&quot;so why ember specifically permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So why Ember, specifically?&lt;/h2&gt;
&lt;p&gt;Ember, like any tool or framework, doesn&apos;t offer the perfect solution to every problem. But recently, whenever I&apos;ve built an application without it, I&apos;ve wished I had it to manage the complexity that lurks behind nearly every front-end feature request.&lt;/p&gt;
&lt;p&gt;Between Ember&apos;s bulletproof object model and thoroughly-thought-out routing system, stuff that would have looked like a sheer cliff face before now looks like a playground to me.&lt;/p&gt;
&lt;p&gt;It&apos;s the epitome of a disruptive technology: Ember allows me to do things that I wouldn&apos;t have even thought to attempt before, because the degree of difficulty was so high my brain just closed the door on the option. (Paul Graham calls this &lt;a href=&quot;http://paulgraham.com/schlep.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;schlep blindness&lt;/a&gt;.) It begs to be given a harder class of user experience problem, which is fun, rewarding, and in line with our purpose at The Frontside to push UX on the web forward.&lt;/p&gt;
&lt;p&gt;Lastly, I tend to vote with community. I think Ruby and Rails has emerged as one of the best communities in any category, not just programming, and I feel similarly about the fast-growing, yet tight-knit Ember.js community.&lt;/p&gt;
&lt;h2 id=&quot;what-if-im-wrong&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-if-im-wrong&quot; aria-label=&quot;what if im wrong permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What if I&apos;m wrong?&lt;/h2&gt;
&lt;p&gt;What if my crystal ball is broken, and users stay content with web applications as they are?&lt;/p&gt;
&lt;p&gt;I can&apos;t deny that I really do believe we&apos;re looking at the future of web applications, but none of this future-talk matters too much. The simple point is this: &lt;strong&gt;Ember makes it fun to build things that are awesome.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And if you&apos;re going to do something, why not do something awesome?&lt;/p&gt;
&lt;p&gt;Ember may not be for every problem or every developer, but if you&apos;ll give it a shot on your next project with high front-end ambitions, I promise you&apos;ll start feeling less intimidated and more like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/challenge-accepted-l.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/093c02b0965808d22529433b21647b22/18bcc/2014-02-24-ember-and-the-future-of-the-web-peabody.jpg" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Ember on Rails: #REALTALK]]></title><link>https://frontside.com/blog/2013-09-21-ember-on-rails-realtalk/</link><guid isPermaLink="false">https://frontside.com/blog/2013-09-21-ember-on-rails-realtalk/</guid><category><![CDATA[talks]]></category><category><![CDATA[videos]]></category><category><![CDATA[ember]]></category><category><![CDATA[rails]]></category><dc:creator><![CDATA[Brandon Hays]]></dc:creator><pubDate>Sat, 21 Sep 2013 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you work in Rails and have ever wondered about Ember.js, you should know that Ember and Rails go together like Nutella and pretzels. (Which is to say, quite well indeed.)&lt;/p&gt;
&lt;p&gt;Get an inside look of the experience of going from having never tried Ember to shipping a production application in it. What makes Ember a good match for certain types of applications?&lt;/p&gt;
&lt;p&gt;This talk is intended to help relative newcomers jump in and start seeing the kind of crazy-ambitious applications you can build when you&apos;ve got Ember.js in your toolset.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/PdqbG71Dr84&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;strong&gt;Note: The audio is rough, but gets a little better as the talk progresses. Sorry about that.&lt;/strong&gt;&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/672b21ba3beb811b5a880aed771bbe3c/2a4de/2013-09-21-ember-on-rails-realtalk-2.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[The Ruby Racer Rides Again]]></title><link>https://frontside.com/blog/2012-12-04-therubyracer-rides-again/</link><guid isPermaLink="false">https://frontside.com/blog/2012-12-04-therubyracer-rides-again/</guid><category><![CDATA[javascript]]></category><category><![CDATA[ruby]]></category><category><![CDATA[therubyracer]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Tue, 04 Dec 2012 12:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;it-began-during-railsconf&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#it-began-during-railsconf&quot; aria-label=&quot;it began during railsconf permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;It began during RailsConf.&lt;/h2&gt;
&lt;p&gt;My fingers were itching to code, so between sessions I started
tinkering with some of the more fanciful enhancements to
&lt;a href=&quot;https://github.com/cowboyd/therubyracer&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Ruby Racer&lt;/a&gt; I&apos;d been contemplating as well as wrestling with
a number of long-standing bugs. But what started out as a small
refactoring slowly but relentlessly gained momentum until things
were completely out of control.&lt;/p&gt;
&lt;p&gt;By all accounts my hands were steady and the work proceeded in an
orderly fashion. Instead, it was &lt;em&gt;I&lt;/em&gt; who was out of control.
Personally and psychologically I was helpless to stop myself as line
after line, class after class unravelled before me --each one more
rapidly than before. Soon a critical mass was achieved and boom!
Nuclear. A from-scratch rewrite was underway.&lt;/p&gt;
&lt;p&gt;Yes it was a rewrite, but by the time I was aware of it, I was too
deeply invested to turn back.&lt;/p&gt;
&lt;p&gt;It&apos;s a tichy thing, is a rewrite. Instead of the careful, iterative
approach that serves as law in our profession, you drop everything
and sprint towards the cliff in the hope that you can lunge across the chasm in
in one leap. Once you&apos;re in the air there&apos;s no going back, and the
possibility is as thrilling as it is real that, like Icarus, you&apos;ll
hurtle into the abyss... another unsung casualty of hubris.&lt;/p&gt;
&lt;p&gt;The prize of course is a better library that is more stable, has more
features and is easier to build and install, so if a rewrite it had to be,
I did the only thing I could do yield myself to it utterly.&lt;/p&gt;
&lt;p&gt;I&apos;m happy to say that it&apos;s mostly there there and that, despite some outstanding
flaws, I&apos;ll be releasing the next version shortly. But more on that later.
First, what&apos;s new?&lt;/p&gt;
&lt;h2 id=&quot;stability&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#stability&quot; aria-label=&quot;stability permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Stability&lt;/h2&gt;
&lt;p&gt;For certain applications therubyracer has been plagued by crashes and memory
leaks that have limited its usefulness to a much smaller domain than
necessary: specifically, low-traffic applications that only instantiate a
single JavaScript context. These problems stemmed from within the library but
also from within Ruby itself.&lt;/p&gt;
&lt;p&gt;The Ruby Racer relies heavily on weak references in order to maintain
referential integrity between Ruby object and the JavaScript objects they
represent (and vice-versa). Sadly, the &lt;a href=&quot;http://bugs.ruby-lang.org/issues/show/4168&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;WeakRef implementation on 1.9 is
completely broken&lt;/a&gt;. This is unfortunate because functioning weak
references are sometimes a necessary component for building correct
programs on platforms with garbage collection. Luckily &lt;a href=&quot;https://github.com/bdurand/ref&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;there are
workarounds&lt;/a&gt; which have been deployed while we wait for 2.0.&lt;/p&gt;
&lt;p&gt;But that&apos;s not the whole story. It would be a shameful misrepresentatio
to lay the bulk of the blame on Ruby&apos;s door. Distributed garbage collection
is hard, and The Ruby Racer engaged in all manners of evil hackery and dark
GC foo in order to prevent cycles of garbage from spanning the Ruby and
JavaScript VMs. Sadly, this did not work in the general case, and furthermore,
was not portable to other Ruby implementations (or even Ruby versions).&lt;/p&gt;
&lt;p&gt;I&apos;ve come to realize that to solve these memory problems in the general case
would require each host Ruby platform, as well as V8, to expose a uniform
interface to its garbage collector so that The Ruby Racer can traverse its
object graph in order to detect cycles of garbage. In other words &quot;not
bloody likely.&quot;&lt;/p&gt;
&lt;p&gt;As a fallback, I&apos;ve decided to throw up my hands and eschew GC histrionics in
favor of more sane memory management in the C extension combined with an explicit
teardown mechanism for cases where cycles of garbage do occur. e.g.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;context = V8::Context.new
context[&apos;cycle&apos;] = context #oh no, a vicious cycle!

context.dispose() # Gordion knot is cleaved, sir!&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In exchange, we get a kinder, gentler racer that works on MRI as well as
Rubinius, and which you&apos;ll be able to rely on in your production processes.&lt;/p&gt;
&lt;h2 id=&quot;resource-constraints&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#resource-constraints&quot; aria-label=&quot;resource constraints permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Resource Constraints&lt;/h2&gt;
&lt;p&gt;Speaking of production, the upcoming release contains a much more
comprehensive coverage of underlying V8 functionality than every before.&lt;/p&gt;
&lt;p&gt;Among other things, you can query the V8 vm for heap usage by young generation,
old generation as well as absolute heap size including executable memory. Not
only that, but you can also place hard caps on each of these numbers. That way
you can contain memory usage and keep your processes under control; even in a
resource constrained environment like Heroku.&lt;/p&gt;
&lt;h2 id=&quot;a-hopefully-kinder-build&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-hopefully-kinder-build&quot; aria-label=&quot;a hopefully kinder build permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A (hopefully) kinder build&lt;/h2&gt;
&lt;p&gt;One of the sorest pain-points with The Ruby Racer was the way it built. Prior to
0.11, it had a hard dependency on the &lt;a href=&quot;http://bugs.ruby-lang.org/issues/show/4168&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;libv8 rubygem&lt;/a&gt; in order to provide the
actual V8 library. In retrospect, this was a bad idea.&lt;/p&gt;
&lt;p&gt;If you were unable to build the v8 contained in the libv8 gem, then
you were completely hosed. You could not use therubyracer at all. Or, if you
wanted to use a custom v8 patched for security or with tweaked startup data,
then you were out of luck. Finally, it raised an unnecessary barrier
to distributing therubyracer as a binary gem (which I would like to do more of).
If you have a binary version, then why do you need to have libv8 at all?&lt;/p&gt;
&lt;p&gt;For these reasons, the dependency on libv8 has been converted to a soft one. If
a compatible version is detected in your rubygems, then it will compile and link
against it. However, if for whatever reason, you do &lt;em&gt;not&lt;/em&gt; want to use the libv8
gem to build, then that is now your prerogative. The Ruby Racer will search
your system for v8 just like any other library.&lt;/p&gt;
&lt;p&gt;The only difference is that if you want to use the libv8 gem, then you will have
to explicitly require a compatible version in your Gemfile.&lt;/p&gt;
&lt;h2 id=&quot;more-bugs-but-not-on-rubinius&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#more-bugs-but-not-on-rubinius&quot; aria-label=&quot;more bugs but not on rubinius permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More bugs, but not on Rubinius&lt;/h2&gt;
&lt;p&gt;There are still some outstanding issues on MRI that emerge under a heavy stress of
rapid object allocation and deallocation. As far as I can tell they are related to
to the weakref implementation, wherein MRI gets confused and starts handing back
references to completely unrelated objects. I say &quot;as far as I can tell&quot; because the
subtleties involved lie beyond the frontier of my understanding of MRI internals.
Given my current workload, it is unlikely I will have time to make the necessary
investment in understanding required to completely quash these problems.&lt;/p&gt;
&lt;p&gt;Despite this, I&apos;m releasing the new version anyhow in order to support Rubinius more
fully and because I think that even on MRI it will solve more problems than it introduces.&lt;/p&gt;
&lt;p&gt;For starters, 0.11 is very stable on Rubinius and that platform is long overdue
for a version of therubyracer that doesn&apos;t suck. The Rubinius core team, and &lt;a href=&quot;https://twitter.com/dbussink&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@dbussink&lt;/a&gt;
in particular, have been very patient and helpful in helping me resolve all the lingering
crashes both big and small... even going to the trouble of adding checks and diagnostics
to the garbage collector just for my sake. They were even willing and often able to
diagnose problems I was having on MRI in order to make the library for everybody.
If anything, I feel that they deserve a functioning JavaScript environment and it wouldn&apos;t
be fair for me to withhold it from them.&lt;/p&gt;
&lt;p&gt;On the MRI front, I still think that closing some of the loopholes in the memory management,
the enhanced extensibility, and better build make it worth releasing anyway. I&apos;ve been
recommending people to upgrade to the beta for almost 3 months and it is almost always the
right decision. Given that I have neither the time nor the inclination to support what I now
consider to be the legacy release, I think it&apos;s high time to either shit or get off the
proverbial pot.&lt;/p&gt;
&lt;p&gt;If you, or anybody you know has a deep knowledge of MRI internals and would be willing to help
me address these issues as well as others that may arise, I would love to work with you to
knock &apos;em down.&lt;/p&gt;
&lt;p&gt;So this is why I&apos;m releasing version 0.11.0 of The Ruby Racer today. Of course, I may
come to quickly regret it, but that&apos;s what &lt;code class=&quot;language-text&quot;&gt;gem yank&lt;/code&gt; is for right?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Implementing a Jenkins Extension Point with the Native Java API inside a Ruby Plugin]]></title><link>https://frontside.com/blog/2012-01-16-implementing-a-jenkins-extension-point-with-native-api-in-ruby/</link><guid isPermaLink="false">https://frontside.com/blog/2012-01-16-implementing-a-jenkins-extension-point-with-native-api-in-ruby/</guid><category><![CDATA[jenkins]]></category><category><![CDATA[ruby]]></category><category><![CDATA[java]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 16 Jan 2012 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;In which I elaborate why the idomatic Ruby API is sometimes not enough,
and describe a method to harness the full power of the underlying
Jenkins API while still happily coding your extension in Ruby&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;the-ruby-api&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-ruby-api&quot; aria-label=&quot;the ruby api permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Ruby API&lt;/h2&gt;
&lt;p&gt;One of the primary goals of the &lt;a href=&quot;http://blog.thefrontside.net/2011/05/12/what-it-take-to-bring-ruby-to-jenkins&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;effort to bring Ruby to Jenkins&lt;/a&gt;
is to enable developers to extend Jenkins in a way that looks and
feels like a normal Ruby environment. This means using rake, bundler
ERB, and plain old Ruby objects to roll your plugin.&lt;/p&gt;
&lt;p&gt;For example, the &lt;a href=&quot;https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/tasks/BuildStep.java&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;native BuildStep&lt;/a&gt; class is made available through
the &lt;a href=&quot;https://github.com/jenkinsci/jenkins-plugin-runtime.rb/blob/master/lib/jenkins/tasks/build_step.rb&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Ruby BuildStep&lt;/a&gt;. They are similar to be sure, but the Ruby
object is much less complicated, and actually bears no relation to its
Java equivalent inside the Java hiearchy of inheritance.&lt;/p&gt;
&lt;p&gt;Exposing this simplicity is a worthy goal, but to do so requires
careful consideration of each Jenkins Java API and how to provide its
functionality in the Ruby way --no mean feat given the breadth of the
Jenkins.&lt;/p&gt;
&lt;p&gt;Sadly, it means that these Ruby-friendly APIs must necessarily lag
behind their Java counterparts.&lt;/p&gt;
&lt;p&gt;This can be a serious source of frustration for those looking to
dive into Jenkins Ruby development right now. Initial excitement is
quickly dulled when you find out that the extension point that you
wanted to implement is unavailable from Ruby land. You might get
discouraged and feel like you might as well be coding your plugin
with Java.&lt;/p&gt;
&lt;p&gt;Well don&apos;t lose heart! I&apos;d like to share with you a super easy way to
write your extension points in Ruby even when there isn&apos;t a friendly
wrapper. We&apos;ll actually implement a very handy extension point called
&lt;code class=&quot;language-text&quot;&gt;RunListener&lt;/code&gt; within a Ruby plugin even though it is not part of the
official Ruby API. We&apos;ll do it by scripting the Java class directly
with JRuby&apos;s Java integration feature, and then register it directly
with the plugin runtime.&lt;/p&gt;
&lt;h2 id=&quot;the-extension-point&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-extension-point&quot; aria-label=&quot;the extension point permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Extension Point&lt;/h2&gt;
&lt;p&gt;We&apos;ll be working with the Jenkins &lt;a href=&quot;https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/model/listeners/RunListener.java&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;RunListener&lt;/a&gt; interface. This is
a wonderful extension point that allows you to receive callbacks
at each point during the actual running of a build. There&apos;s currently
no nice ruby API for it, but we won&apos;t let that stop us.&lt;/p&gt;
&lt;p&gt;First, let&apos;s create a new plugin called &lt;em&gt;my-listener&lt;/em&gt;. We&apos;ll do this
with the &lt;code class=&quot;language-text&quot;&gt;jpi new&lt;/code&gt; command.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;legolas:Jenkins cowboyd$ jpi new my-listener
    create  my-listener/Gemfile
    create  my-listener/my-listener.pluginspec&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Fun fact: &apos;jpi&apos; is an acronym for (J)enkins (P)lug-(I)n. You can
install the tool with rubygems: &lt;code class=&quot;language-text&quot;&gt;gem install jpi&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Next, we&apos;ll cd into our new plugin and create our listener class
inside the models/ directory. Jenkins will automatically evaluate
everything in this directory on plugin initialization.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;legolas:Jenkins cowboyd$ cd my-listener/
legolas:my-listener cowboyd$ mkdir models
legolas:my-listener cowboyd$ touch models/my_listener.rb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our ultimate goal here is to implement a &lt;code class=&quot;language-text&quot;&gt;RunListener&lt;/code&gt;, so let&apos;s
go ahead and start our class definition inside that file.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;class MyListener &amp;lt; Java.hudson.model.listeners.RunListener
  def initialize()
    super(Java.hudson.model.Run.java_class)
  end
end&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There&apos;s a couple key takeaways here. First, notice that we use
JRuby integration to extend the class
&lt;code class=&quot;language-text&quot;&gt;hudson.model.listeners.RunListener&lt;/code&gt; directly. Second, and this is
a gotcha anytime you extend a Java class: you &lt;em&gt;must&lt;/em&gt; invoke one of
the Java super constructors if it does not have a default
constructor. I can&apos;t tell you how many times I&apos;ve been bitten by this.&lt;/p&gt;
&lt;p&gt;In our case, the &lt;code class=&quot;language-text&quot;&gt;RunListener&lt;/code&gt; class filters which jobs
it will provide callbacks for by class. By providing a more specific
class to the constructor, you limit the scope of jobs you&apos;ll receive
to subclasses of that class. For our purposes, we cast a pretty wide
net by selecting all builds via the &lt;code class=&quot;language-text&quot;&gt;AbstractBuild&lt;/code&gt; Java class.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pro Tip: when you&apos;re implementing a native Java API, it really
helps to have the javadoc open in one window so that you
can view the documentation and crib from the source&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now that we&apos;ve got our class defined, let&apos;s implement some methods!
We&apos;ll add callbacks for when a build is started and when it&apos;s
completed.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;class MyListener &amp;lt; Java.hudson.model.listeners.RunListener
  def initialize()
    super(Java.hudson.model.AbstractBuild.java_class)
  end
  def onStarted(run, listener)
    listener.getLogger().println(&quot;onStarted(#{run})&quot;)
  end
  def onCompleted(run, listener)
    listener.getLogger().println(&quot;onCompleted(#{run})&quot;)
  end
end
Jenkins.plugin.register_extension MyListener.new&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And finally, on the last line, we actually inform Jenkins about the
existence of our new Listener with the call to
&lt;code class=&quot;language-text&quot;&gt;Jenkins.plugin.register_extension&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And that&apos;s about it. We can start up our test server with our &lt;code class=&quot;language-text&quot;&gt;jpi&lt;/code&gt;
tool to see our listener in action.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;legolas:my-listener cowboyd$ jpi server
Listening for transport dt_socket at address: 8000
Running from: /Users/cowboyd/.rvm/gems/jruby-1.6.5/gems/jenkins-war-1.446/lib/jenkins/jenkins.war
...
Jan 16, 2012 12:46:15 AM ruby.RubyRuntimePlugin start
INFO: Injecting JRuby into XStream
Loading /Users/cowboyd/Projects/Jenkins/my-listener/models/my_listener.rb
INFO: Prepared all plugins
...
INFO: Jenkins is fully up and running&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To view the output, create a freestyle build called HelloWorld that
doesn&apos;t have any build steps at all, build it and view the console
output. You should see something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Started by user anonymous
onStarted(#&amp;lt;Java::HudsonModel::FreeStyleBuild:0x2870068a&gt;)
onCompleted(#&amp;lt;Java::HudsonModel::FreeStyleBuild:0x2870068a&gt;)
Finished: SUCCESS&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-sweet-reality&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-sweet-reality&quot; aria-label=&quot;the sweet reality permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Sweet Reality&lt;/h2&gt;
&lt;p&gt;Even though we were dealing more directly with Java, we were
still able to use all of the simplicity that comes with developing
plugins in Ruby. Furthermore, even though our extension point was just
scripted Java, it doesn&apos;t mean that inside its methods it can&apos;t call
as much pure Ruby code as its heart desires.&lt;/p&gt;
&lt;p&gt;I hope that if you&apos;re considering writing your next (or your first!)
Jenkins plugin in Ruby, you&apos;ll feel confident that you can always
fall back to the native APIs at any point.&lt;/p&gt;</content:encoded><media:content url="https://frontside.com/static/bf4163a654c532fd8669027037560ed5/2a4de/2012-01-16-implementing-a-jenkins-extension-point-with-native-api-in-ruby-1.png" type="image/png" medium="image" duration="30"/></item><item><title><![CDATA[Ruby for Jenkins Goes Pre-Alpha]]></title><link>https://frontside.com/blog/2011-09-13-ruby-for-jenkins-goes-pre-alpha/</link><guid isPermaLink="false">https://frontside.com/blog/2011-09-13-ruby-for-jenkins-goes-pre-alpha/</guid><category><![CDATA[java]]></category><category><![CDATA[ruby]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Tue, 13 Sep 2011 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;To quote Dave Bowman, &quot;something wonderful happened&quot; last week during the weekly &lt;a href=&quot;http://wiki.jenkins-ci.org/display/JENKINS/Jenkins+plugin+development+in+Ruby&quot; title=&quot;Jenkins Ruby Hacking&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Jenkins-Ruby hack session&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We were able to boot a &lt;a href=&quot;https://github.com/cowboyd/jenkins-prototype-ruby-plugin&quot; title=&quot;Prototype Ruby Plugin&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;plugin written in pure Ruby&lt;/a&gt; into a Jenkins server just by executing a single command from the command line (rake server). Furthermore, this command did not involve a compilation step, and the plugin that it booted did not bare a trace of evidence that it was to be loaded into a server written in Java.&lt;/p&gt;
&lt;p&gt;That&apos;s right. Using nothing but good &apos;ol Bundler and Rake, we hoisted a pure Ruby plugin into the Jenkins runtime.
And I can tell you that after hacking on this for almost a year: it felt... so.... good.... man.&lt;/p&gt;
&lt;p&gt;It&apos;s not time to declare victory yet, but at least the first two of &lt;a href=&quot;/2011/05/12/what-it-take-to-bring-ruby-to-jenkins&quot; title=&quot;What it takes to bring Ruby to Jenkins&quot;&gt;our major goals&lt;/a&gt; have been realized, and that is definitely a cause to celebrate.&lt;/p&gt;
&lt;p&gt;Practically, this means that rubyists can check out the source and get hacking without needing any knowledge of
Java or any Java toolchain. That&apos;s why I think it&apos;s safe to officially declare the project to be in
a &lt;em&gt;&lt;strong&gt;pre-alpha&lt;/strong&gt;&lt;/em&gt; state.&lt;/p&gt;
&lt;p&gt;It isn&apos;t yet for the faint of heart, and you&apos;re sure to find many things confusing and
difficult. But at least those who know only Ruby can contribute bug reports, identify pain points, and contribute
to the creative process.&lt;/p&gt;
&lt;p&gt;It&apos;s 8:20am, but it still feels like Miller time.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Ruby Racer isn't threadsafe... yet.]]></title><link>https://frontside.com/blog/2011-06-13-therubyracer-isnt-threadsafe-yet/</link><guid isPermaLink="false">https://frontside.com/blog/2011-06-13-therubyracer-isnt-threadsafe-yet/</guid><category><![CDATA[javascript]]></category><category><![CDATA[ruby]]></category><category><![CDATA[therubyracer]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 13 Jun 2011 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strike&gt;In which I explain problems unique to running The Ruby Racer in a multithreaded environment,
which users are affected by these problems, and what is to be done for them.&lt;/strike&gt;&lt;/p&gt;
&lt;p&gt;UPDATE: This issue has been resolved with &lt;a href=&quot;http://rubygems.org/gems/therubyracer/versions/0.9.1&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;version 0.9.1&lt;/a&gt;.
You should be able to stop reading here, update your Gemfile, and have a great day. That said, please don&apos;t
let me discourage you from continuing down the page. It&apos;s riveting.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There have been a number of crashes reported in &lt;a href=&quot;https://github.com/cowboyd/therubyracer/issues/79&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;several&lt;/a&gt; &lt;a href=&quot;https://github.com/rails/rails/issues/1667&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;different&lt;/a&gt; &lt;a href=&quot;http://redmine.ruby-lang.org/issues/4821&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;places&lt;/a&gt; for which &lt;a href=&quot;http://github.com/cowboyd/therubyracer&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Ruby Racer&lt;/a&gt; is the culprit. For the most part, these are people running an Rails 3.1 application in a multithreaded webserver such as WEBrick, but as we&apos;ll see, it could be anybody that is using The Ruby Racer in a mulithreaded environment. In order to speak to these and future issues
in one place, as well as prevent the spread of any misinformation or impressions, I wanted to very quickly explain what exactly is causing these crashes, who is affected by them and where, and finally how we&apos;re going to make them go away.&lt;/p&gt;
&lt;h2 id=&quot;background&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#background&quot; aria-label=&quot;background permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Background&lt;/h2&gt;
&lt;p&gt;When an instance of V8 starts running, it associates all of its global state with the currently running native OS thread. By global state, I mean things like heap storage, stacks, callbacks... everything that it needs to make JavaScript happen. Every time you &lt;code class=&quot;language-text&quot;&gt;eval()&lt;/code&gt; a script or you allocate an object with &lt;code class=&quot;language-text&quot;&gt;new&lt;/code&gt;, it retrieves that state from the executing thread to perform that operation.&lt;/p&gt;
&lt;p&gt;In a single threaded application, that&apos;s the end of the story. This is because every V8 operation happens from the same thread as the rest of your code, so the V8 state is always right there ready at all times. If you&apos;re running your app in a rack server like Passenger or Unicorn that uses a multi-process model to achieve concurrency, you&apos;ll never see this crash because you don&apos;t use threads. Also, if you&apos;re running on MRI 1.8.7 which uses green threads, you will also not be affected. While you may have more than one Ruby thread in your application, you still only have one &lt;em&gt;native&lt;/em&gt; OS thread which is what V8 will use.&lt;/p&gt;
&lt;p&gt;The problem comes in when you are using Ruby 1.9 in a multi-threaded environment and you access V8 from more than one thread. This is because 1.9 uses native OS threads under the covers for its own threading API. When The Ruby Racer starts up V8, it uses whatever thread happens to be running as the home for its runtime data. Then, when you try and do some JavaScript operation from another thread, V8 can&apos;t find its state, freaks out and crashes your entire process.&lt;/p&gt;
&lt;p&gt;Luckily, V8 does give us some help here. It provides a &lt;a href=&quot;http://bespin.cz/~ondras/html/classv8_1_1Unlocker.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;locker API&lt;/a&gt; as a way to deal with threading issues. It acts as both mutex on a V8 instance while at the same time providing a facility to access it from different threads.
We can wrap calls that touch V8 with a &lt;code class=&quot;language-text&quot;&gt;Locker&lt;/code&gt; in order to prevent these crashes. e.g.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;V8::C::Locker() do
  #... code that calls V8
end&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That sounds simple enough: just never access V8 without a lock and you&apos;re good. In fact, &lt;a href=&quot;https://github.com/sstephenson/execjs/blob/b67a563ab4c6e26dc468e948d523456d531463f9/lib/execjs/ruby_racer_runtime.rb#L70-86&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ExecJS does this&lt;/a&gt; whenever it invokes its therubyracer runtime, and it works... almost.&lt;/p&gt;
&lt;h2 id=&quot;i-would-have-gotten-away-with-it-too-if-it-hadnt-been-for-you-pesky-gcs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#i-would-have-gotten-away-with-it-too-if-it-hadnt-been-for-you-pesky-gcs&quot; aria-label=&quot;i would have gotten away with it too if it hadnt been for you pesky gcs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;I would have gotten away with it too if it hadn&apos;t been for you pesky GCs&lt;/h2&gt;
&lt;p&gt;If ExecJS locks V8, then why am I still crashing, and at seemingly random intervals?&lt;/p&gt;
&lt;p&gt;The problem comes when we need to run garbage collection. The awesome thing about The Ruby Racer is that it
lets you hold on to V8 objects from Ruby. It does this by using a proxy --a ruby object that implements all its behavior by delegating to an underlying JavaScript object. As long as Ruby holds a reference to that proxy, the proxy will in turn hold a reference to its underlying V8 object. However, when Ruby no longer holds a reference to the proxy and the proxy is garbage collected, we need to tell V8 that we aren&apos;t holding a reference to the underlying object anymore. And, as you may have guessed, in order to remove references to V8 objects, you need to hold what? Yep, the V8 lock. To operate properly, GC also needs to lock V8. Sadly, it does not, which explains why crashes continue to happen at random places.&lt;/p&gt;
&lt;p&gt;You might be asking yourself, &quot;why not just lock V8 in your GC routines and have done with it?&quot; The answer
is that it would be a terribly dangerous and irresponsible thing to do.&lt;/p&gt;
&lt;p&gt;Suppose that thread &lt;code class=&quot;language-text&quot;&gt;A&lt;/code&gt; has V8 locked and is doing some fancy JavaScript stuff. At some point, we do a context switch over to thread &lt;code class=&quot;language-text&quot;&gt;B&lt;/code&gt; which is not doing anything even remotely JavaScriptful like loading ActiveRecords from the database or something. Thread &lt;code class=&quot;language-text&quot;&gt;B&lt;/code&gt; is chugging threw lots of memory, and all of a sudden triggers GC. There are some V8 objects that need cleanup due to our JavaScript activities over in thread &lt;code class=&quot;language-text&quot;&gt;A&lt;/code&gt;, so it tries to lock V8, but uh-oh, thread &lt;code class=&quot;language-text&quot;&gt;A&lt;/code&gt; already holds the V8 lock, so GC may have to wait forever until it becomes available. Deadlock!&lt;/p&gt;
&lt;p&gt;The answer is that instead of immediately releasing v8 objects inside the GC thread, we need to equeue them somewhere where they can be released. This probably means starting a thread per V8 instance to consume this reference queue and release them in the context of a V8 lock that isn&apos;t contending for any other resources.
While the answer is not trivial, I don&apos;t expect it to be that complex.&lt;/p&gt;
&lt;h2 id=&quot;what-to-do-what-to-do&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-to-do-what-to-do&quot; aria-label=&quot;what to do what to do permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What to do? What to do?&lt;/h2&gt;
&lt;p&gt;In the mean time, there is a &lt;a href=&quot;https://gist.github.com/1011718&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;workaround&lt;/a&gt; for locking V8 with each request, which will ensure that GC running in that request will have already acquired the V8 lock. Bear in mind that this is not a silver bullet, and you still could encounter crashes and deadlocks, but they should be very few and far between. If, as is the case with most people, you are just using a multithreaded server in your development environment but deploy to multi-process model, then this should be sufficient. If on the other hand you run multi-threaded in production, then you should definitely &lt;em&gt;not&lt;/em&gt; be locking V8 in your middleware since this will effectively synchronize every request. Not a good idea.&lt;/p&gt;
&lt;p&gt;No matter which category you fall into, I expect that we&apos;ll have a beta fix by the end of this week, and if all goes well, a patch release after another. This may seem like a long time for such a small thing as coordinating locking with GC, but my experience tells me that threading is not a thing best done by humans, and so there will
inevitable stumbles and cursing.&lt;/p&gt;
&lt;p&gt;Also, I&apos;m keen to make sure that any solution is both invisible to you the developer, as well as compatible with other Ruby versions and implementations. This deserves some thought.&lt;/p&gt;
&lt;h2 id=&quot;what-youre-still-here&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-youre-still-here&quot; aria-label=&quot;what youre still here permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What? you&apos;re still here?&lt;/h2&gt;
&lt;p&gt;Alright, time to stop talking and get started with the repairs. I just wanted to take a moment to let you know what the problem was, why it was happening, how&apos;re you&apos;re affected, what you can do now, and when you can expect a more permanent fix.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What it takes to bring Ruby to Jenkins]]></title><link>https://frontside.com/blog/2011-05-12-what-it-take-to-bring-ruby-to-jenkins/</link><guid isPermaLink="false">https://frontside.com/blog/2011-05-12-what-it-take-to-bring-ruby-to-jenkins/</guid><category><![CDATA[java]]></category><category><![CDATA[ruby]]></category><category><![CDATA[jenkins]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Thu, 12 May 2011 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&quot;Jenkins Ruby Plugins&quot; are at an important, yet fragile stage of their life. Over the past several months, we have made
tremendous progress towards making extending Jenkins with nothing but Ruby a blissful reality. However, at this moment,
they exist only as a collection of hacks, or, to frame it more kindly, &quot;proofs of concept&quot; all buried quite deeply in a
&lt;a href=&quot;http://github.com/cowboyd/fog.hpi&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;terribly named repo on github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To name a few of them, we are now able to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;automatically discover Ruby plugins and register them&lt;/li&gt;
&lt;li&gt;work with Jenkins internals like BuildWrapper, RootActions, etc.. via a native Ruby-like API&lt;/li&gt;
&lt;li&gt;persist mixed hierarchies of Java and Ruby objects transparently as Jenkins configuration&lt;/li&gt;
&lt;li&gt;use ERB to template views, while still having access to the standard UI helpers&lt;/li&gt;
&lt;li&gt;extend the Jenkins REST API from Ruby&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is by no means an exhaustive list, but I want to stress just how far we&apos;ve come before I talk about where it is that
we need to go.&lt;/p&gt;
&lt;p&gt;While the work done so far represents some phenomenal accomplishments, in the end, they are only technical accomplishments which do not together create a coherent developer experience. So now, for this endeavor to succeed, we must focus our attention on making that &lt;em&gt;entire experience&lt;/em&gt;, from project start to release after release, as frictionless as possible.&lt;/p&gt;
&lt;p&gt;To that end, I propose the following high level goal for the Jenkins Ruby Plugins project:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To provide the facility to create, develop and release extensions for Jenkins with nothing but knowledge of the language, tools and best practices of the Ruby community.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is, I think, the most important ideal to aspire to when claiming to provide a Ruby development experience. Unless it feels like the real McCoy, then you aren&apos;t really developing Ruby at all, you&apos;re just scripting Java with JRuby. You won&apos;t fool anybody, and there will be far less enthusiasm and adoption.&lt;/p&gt;
&lt;p&gt;That said, several things follow logically from this thesis, the first of which is:&lt;/p&gt;
&lt;h3 id=&quot;absolutely-positively-no-maven&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#absolutely-positively-no-maven&quot; aria-label=&quot;absolutely positively no maven permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Absolutely, Positively, No Maven!&lt;/h3&gt;
&lt;p&gt;This is not an ideological stance on the value of Maven as a &lt;strike&gt;wretched pile of toad sick&lt;/strike&gt; software development tool. Rather, it is an explicit acknowledgement that it is not a Ruby tool, it doesn&apos;t fit with the community&apos;s style, and if you&apos;re using it
you might not be doing Java, but you &lt;em&gt;certainly&lt;/em&gt; aren&apos;t doing Ruby. Instead, we should turn to the Ruby tools that
occupy this same space: Rake for scripting the build, and Bundler for dependency management.&lt;/p&gt;
&lt;h3 id=&quot;ruby-like-project-structure&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ruby-like-project-structure&quot; aria-label=&quot;ruby like project structure permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ruby-Like Project Structure&lt;/h3&gt;
&lt;p&gt;If we aren&apos;t going to use Maven, then why should we be constrained by the project directory structure that it imposes. &lt;code class=&quot;language-text&quot;&gt;src/main/resources/what?&lt;/code&gt; Nope. Just one glance at Jenkins Ruby Plugin&apos;s layout in an editor or file system browser
should put a Rubyist&apos;s mind right at ease. You see that? There&apos;s your &lt;code class=&quot;language-text&quot;&gt;Gemfile&lt;/code&gt; just
where you left him. And oh, your pals &lt;code class=&quot;language-text&quot;&gt;lib/&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;spec/&lt;/code&gt; are there too. Let&apos;s get right to work!&lt;/p&gt;
&lt;h3 id=&quot;managing-the-project-life-cycle&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#managing-the-project-life-cycle&quot; aria-label=&quot;managing the project life cycle permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Managing The Project Life-Cycle&lt;/h3&gt;
&lt;p&gt;From inception to release, you should be able to manage all aspects of your Jenkins plugin with Ruby. There must be single
commands (or rake tasks) to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;conjure a new plugin into existence&lt;/li&gt;
&lt;li&gt;generate model/view boilerplate&lt;/li&gt;
&lt;li&gt;run a server with the plugin loaded&lt;/li&gt;
&lt;li&gt;package, push, tag and release a plugin to update-center&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;testing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#testing&quot; aria-label=&quot;testing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Testing&lt;/h3&gt;
&lt;p&gt;The importance of testing in the Ruby community cannot be overstated. The Ruby Tools need to provide a clear path to
testing the plugin at both the unit and functional levels.&lt;/p&gt;
&lt;h3 id=&quot;documentation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#documentation&quot; aria-label=&quot;documentation permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Documentation&lt;/h3&gt;
&lt;p&gt;The &quot;Ruby-like&quot; API that plugin development provides is similar, but not equivalent to its native Java equivalent.
It is critical that this API be well documented, so that developers can understand it, and do not find themselves constantly
referring to the JavaDoc, which they may very well not understand (it being Java), and might be misleading given the natural
asymmetries of the two APIs.&lt;/p&gt;
&lt;h2 id=&quot;heed-the-call&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#heed-the-call&quot; aria-label=&quot;heed the call permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heed the Call!&lt;/h2&gt;
&lt;p&gt;There are plenty of people who would love to see this project get done, but don&apos;t know where to start. I know this because I was one of them. The upshot is that now, as I&apos;ve just described, there is plenty of work to be done that doesn&apos;t require any knowledge of Java and very little knowledge of Jenkins internals. That means that &lt;em&gt;you&lt;/em&gt; can contribute in a meaningful way!&lt;/p&gt;
&lt;p&gt;Next week, I&apos;ll be publishing some specifications in the form of Cucumber scenarios for some of the features up above that we can discuss and then hopefully start implementing.&lt;/p&gt;
&lt;p&gt;But the most important thing that you can do is to join in on the conversation!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;irc://freenode.net/jenkins&quot;&gt;irc&lt;/a&gt;, and &lt;a href=&quot;http://groups.google.com/group/jenkinsrb&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;email&lt;/a&gt; are just a few of the ways to reach out!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Update. I have posted the first scenario: &lt;a href=&quot;https://github.com/cowboyd/jenkins.rb/blob/ruby-plugin-development/features/plugins/create-new-plugin.feature&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;creating a plugin&lt;/a&gt;.
The first bounty is officially posted.&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[Wrapping each Hudson distribution in its own RubyGem]]></title><link>https://frontside.com/blog/2011-01-06-wrapping-each-hudson-distribution-in-its-own-rubygem/</link><guid isPermaLink="false">https://frontside.com/blog/2011-01-06-wrapping-each-hudson-distribution-in-its-own-rubygem/</guid><category><![CDATA[ruby]]></category><category><![CDATA[hudson]]></category><category><![CDATA[java]]></category><category><![CDATA[jenkins]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Thu, 06 Jan 2011 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update&lt;/strong&gt;&lt;/em&gt;: As of version &lt;code class=&quot;language-text&quot;&gt;1.396&lt;/code&gt;, this is applicable to the &lt;a href=&quot;http://jenkins-ci.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Jenkins&lt;/a&gt; project.
&lt;code class=&quot;language-text&quot;&gt;1.395&lt;/code&gt; will be the last version of the hudson-war gem&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As you may or may not know, we here at The FrontSide have been working since
late last year to create a proper ruby environment for extending hudson. This
is no mean feat because it implies not only the ability to use nothing but ruby
&lt;em&gt;code&lt;/em&gt; to implement hudson plugins, but just as importantly, the ability to use
nothing but ruby &lt;em&gt;tools&lt;/em&gt; to develop them. That means no javac, no
&lt;a href=&quot;http://en.wikipedia.org/wiki/Jar_file&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;jar files&lt;/a&gt;, no &lt;a href=&quot;http://en.wikipedia.org/wiki/WAR_%28Sun_file_format%29&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;war files&lt;/a&gt;, and for the love of all that is holy: &lt;a href=&quot;http://kent.spillner.org/blog/work/2009/11/14/java-build-tools.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;absolutely,
positively, no maven&lt;/a&gt;. In short, the only folks you&apos;ll need to know to get in
the door with Hudson are your pals Ruby, Rake and Bundler.&lt;/p&gt;
&lt;p&gt;Of course, all those jars and wars and perhaps some class generation will be
there behind the scenes. After all, we&apos;ll still need to compile java stubs that
depend on core Hudson classes. We&apos;ll still need to package your plugin along
with its ruby code and dependencies in a jar file, and we&apos;ll still need to take
care of all the blah, blah, MANIFEST, blah, META-INF, WEB-INF, blah, blah, blah...&lt;/p&gt;
&lt;h2 id=&quot;the-war&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-war&quot; aria-label=&quot;the war permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The War&lt;/h2&gt;
&lt;p&gt;If we&apos;re going to do the compilation against Hudson core from within ruby and
Rake instead of maven, then we&apos;re going to need a reliable way to get at the
core hudson classes so that we can use them in our compilation classpath. Not
only that, but as part of the development process, you&apos;re going to want to test
your plugins against a fully functioning hudson server. Luckily, both of these
are contained in the full hudson distribution that you download as a single
war file. Wouldn&apos;t it be nice if you had a simple way to get at a specific
version of one of those wars and then get at all those java goodies contained
therein?&lt;/p&gt;
&lt;h2 id=&quot;the-gem&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-gem&quot; aria-label=&quot;the gem permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Gem&lt;/h2&gt;
&lt;p&gt;To my thinking, this sounds like a job for: RubyGems! That&apos;s why we&apos;re introducing
the new &lt;a href=&quot;https://rubygems.org/gems/hudson-war&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;hudson-war&lt;/a&gt; gem, which does nothing except wrap a single hudson
distribution so that it can be managed coherently just like any other ruby
component. Want the latest warfile?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;gem install hudson-war&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or perhaps you need hudson 1.386? That&apos;s fine, hudson-war versions are the same
as the hudson distributions they wrap.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;gem install hudson-war --version 1.386&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It&apos;s not just a war file either. In keeping with the best traditions of OOP
data comes bundled with behavior. The gem comes with a ruby API and a CLI baked
in to help us do all the nifty things we might want to do with a war file.
For starters, you might want to know where it is.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;legolas:~ cowboyd$ hudson.war location
/Users/cowboyd/.rvm/gems/ruby-1.8.7-p174/gems/hudson-war-1.386/lib/hudson/hudson.war&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you want to unpack it to a particular location then&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;legolas:~ cowboyd$ hudson.war unpack tmp
jar xvf /Users/cowboyd/.rvm/gems/ruby-1.8.7-p174/gems/hudson-war-1.386/lib/hudson/hudson.war -C tmp/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can run a test server with it&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;legolas:~ cowboyd$ hudson.war server --daemon
Forking into background to run as a daemon.
Use --logfile to redirect output to a file
legolas:~ cowboyd$ hudson.war server --kill&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Beyond the basics, let&apos;s say you want to do something interesting like compile
some java code against the hudson core. You&apos;re gonna need a classpath, and you
can get it with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;legolas:~ cowboyd$ hudson.war classpath
/Users/cowboyd/.hudson/wars/1.386/WEB-INF/lib/hudson-core-1.386.jar&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can even compile java code with it directly. Here we compile a trivial
class that has a dependency on hudson.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;legolas:~ cowboyd$ cat &gt; ImportsHudson.java
import hudson.model.Hudson;
public class ImportsHudson {
  public static void main(String args[]) {
    System.out.printf(&quot;The Hudson Model object&apos;s class is %s\n&quot;, Hudson.class.getName());
  }
}
legolas:~ cowboyd$ hudson.war javac ImportsHudson.java
legolas:~ cowboyd$ java -cp .:`hudson.war classpath` ImportsHudson
The Hudson Model object&apos;s class is hudson.model.Hudson&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It&apos;s like RVM for hudson. Wrangling java has never been so fun!&lt;/p&gt;
&lt;h2 id=&quot;the-war-gemmer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-war-gemmer&quot; aria-label=&quot;the war gemmer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The War Gemmer&lt;/h2&gt;
&lt;p&gt;Befitting a continuous integration project, the Hudson team releases a new
version at least every two weeks, and sometimes even sooner. It can be a bitch
to keep up with, so I&apos;ve set up a
&lt;a href=&quot;http://github.com/cowboyd/hudson-wargemmer&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;wargemmer hudson&lt;/a&gt; task to
periodically poll the update center to see if there is a new release. If there
is, it&apos;ll gem it right up and push it to rubygems. No fuss no muss.&lt;/p&gt;
&lt;p&gt;Let the war begin!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[We must come together to honor the command line]]></title><link>https://frontside.com/blog/2010-11-14-we-must-come-together-to-honor-the-command-line/</link><guid isPermaLink="false">https://frontside.com/blog/2010-11-14-we-must-come-together-to-honor-the-command-line/</guid><category><![CDATA[ruby]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Sun, 14 Nov 2010 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I reap no joy from writing command line interfaces in Ruby, and about 5 minutes before leaving RubyConf this year I realized that I am not alone.&lt;/p&gt;
&lt;p&gt;It&apos;s not angst I feel so much as a general &lt;em&gt;&quot;meh&quot;&lt;/em&gt;: There&apos;s a fairly decent out-of-the-box way to do it in &lt;code class=&quot;language-text&quot;&gt;OptionParser&lt;/code&gt;, but the minute you want to introduce commands is when the muddling begins. Sure you can see
your way through it, but it&apos;s never robust and you always get smacked in the ass by the edge cases that
inevitably come along.&lt;/p&gt;
&lt;h2 id=&quot;it-aint-for-lack-of-trying&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#it-aint-for-lack-of-trying&quot; aria-label=&quot;it aint for lack of trying permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;It ain&apos;t for lack of trying&lt;/h2&gt;
&lt;p&gt;My own abortive attempts not withstanding, I&apos;ve tried in the last year at least 3 different libraries for parsing CLI options in my applications and gems. These are
&lt;a href=&quot;http://github.com/davetron5000&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;gli&lt;/a&gt;, &lt;a href=&quot;http://github.com/wycats/thor&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;thor&lt;/a&gt; and &lt;a href=&quot;http://github.com/joshbuddy/optitron&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;optitron&lt;/a&gt;. I have known and loved each of these libraries in its own way, but ultimately all of them left me feeling unsatisfied. I won&apos;t go into my specific dissatisfactions with each here, but suffice it to say that my malaise was shared. The general consensus of the
cohort at the bar was that despite the recent innovations and improvements in the space, we&apos;d really have just been better off with
&quot;&lt;code class=&quot;language-text&quot;&gt;OptionParser&lt;/code&gt; plus commands.&quot;&lt;/p&gt;
&lt;h2 id=&quot;but-we-should-do-better&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#but-we-should-do-better&quot; aria-label=&quot;but we should do better permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But we should do better&lt;/h2&gt;
&lt;p&gt;Better off for sure, but is that still what we want: to just get by?&lt;/p&gt;
&lt;p&gt;No. we need a way to write command lines that feels like judo: deploying minimal force to effortlessly sling mountains of code.&lt;/p&gt;
&lt;p&gt;I say we can have our cake and eat it too. I say our command lines can be easy. I say our command lines can be sexy. I say our command lines can be so awesome that they crap rainbows and have herds of unicorns come thundering out of their asses.&lt;/p&gt;
&lt;p&gt;That&apos;s why I&apos;m starting the &lt;a href=&quot;http://github.com/cowboyd/optimal&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;optimal&lt;/a&gt; project. It may lead to nothing. It might even lead eventually to some code... that&apos;s not the point right now though. The point is to reach out to everyone who feels strongly about this and ask them to contribute ideas and requirements in order to build a consensus on the next generation of CLI builder that everybody can be proud of.&lt;/p&gt;
&lt;p&gt;It certainly will not happen overnight, but for the betterment of all, it&apos;s high time to find the true successor to OptionParser: the one the community sees eventually integrated into the standard library.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Accessing Javascript Objects from Ruby]]></title><link>https://frontside.com/blog/2010-10-25-accessing-javascript-objects-from-ruby/</link><guid isPermaLink="false">https://frontside.com/blog/2010-10-25-accessing-javascript-objects-from-ruby/</guid><category><![CDATA[javascript]]></category><category><![CDATA[ruby]]></category><category><![CDATA[therubyracer]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 25 Oct 2010 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Awhile back, I wrote a post on how to &lt;a href=&quot;/2010/06/30/accessing-ruby-objects-from-V8/&quot;&gt;access Ruby objects from inside your JavaScript enviroment&lt;/a&gt; when using &lt;a href=&quot;http://github.com/cowboyd/therubyracer&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Ruby Racer&lt;/a&gt;. It showed just some of the many ways that you can access Ruby state and call Ruby code from within JavaScript. However, the story doesn&apos;t end there. The Ruby Racer is, after all, a two way bridge, and I thought it would be useful to document some of the ways in which you can access your JavaScript environment from within Ruby.&lt;/p&gt;
&lt;p&gt;Let&apos;s start with the &lt;code class=&quot;language-text&quot;&gt;Context#eval&lt;/code&gt; method, which is used to execute JavaScript code from Ruby. Its the most intuitive way,
and what gets used most often for examples.&lt;/p&gt;
&lt;p&gt;Given a string, it compiles it as JavaScript source and then executes it inside the context. Nothing
crazy there:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;V8::Context.new do |cxt|
  cxt.eval(&apos;1 + 1&apos;) #=&gt; 2
  cxt.eval(&apos;foo = {bar: &quot;bar&quot;, baz: &quot;baz&quot;}&apos;)
  cxt.eval(&apos;foo.bar&apos;) #=&gt; &quot;bar&quot;
  cxt.eval(&apos;foo.baz&apos;) #=&gt; &quot;baz&quot;
  cxt.eval(&apos;new Object()&apos;) #=&gt; [object Object]
end&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Among other things, the context captures what functions and objects are defined in the global scope
whenever anything gets &lt;code class=&quot;language-text&quot;&gt;eval()&lt;/code&gt;&apos;d. So, for example, the &lt;code class=&quot;language-text&quot;&gt;Object&lt;/code&gt; constructor used in the last line is stored
in the context.&lt;/p&gt;
&lt;p&gt;As a tool for embedding however, &lt;code class=&quot;language-text&quot;&gt;eval()&lt;/code&gt; is the most blunt and (often) inefficient method available.
For this reason &lt;a href=&quot;http://github.com/cowboyd/therubyracer&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Ruby Racer&lt;/a&gt;, sports an extensive Ruby API for
interacting with JavaScript objects which includes accessing properties, calling functions and methods, as well
as creating new instances. In fact, I rarely use &lt;code class=&quot;language-text&quot;&gt;eval()&lt;/code&gt; &lt;em&gt;at all&lt;/em&gt; to manipulate a JavaScript context
except for loading source files into the interpreter.&lt;/p&gt;
&lt;p&gt;The Ruby API consists of &lt;code class=&quot;language-text&quot;&gt;V8::Object&lt;/code&gt; and all of its subclasses:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;V8::Context.new do |cxt|
  cxt.eval(&apos;new Object()&apos;).class #=&gt; V8::Object
  cxt.eval(&apos;(function() {})&apos;).class #=&gt; V8::Function
  cxt.eval(&apos;new Array()).class #=&gt; V8::Array
end&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;objects&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#objects&quot; aria-label=&quot;objects permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Objects&lt;/h2&gt;
&lt;p&gt;The most fundamental operations in dealing with JavaScript objects are the getting and setting of values.
Coincidentally, this is also a fundamental concept in Ruby, so it comes as no great surprise that we can re-use
those constructs in Ruby that deal with property access to mirror those same operations on their JavaScript
counterparts: the &lt;code class=&quot;language-text&quot;&gt;[]()&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;[]=()&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;foo()&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;foo=()&lt;/code&gt; methods:&lt;/p&gt;
&lt;p&gt;given the following context:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cxt = V8::Context.new
order = cxt.eval(&apos;order = {eggs: &quot;over-easy&quot;}&apos;)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;we can read the &lt;code class=&quot;language-text&quot;&gt;eggs&lt;/code&gt; property of our order in several differnt ways.
Via hash access (note that both string and symbol are acceptable as key values):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;order[&apos;eggs&apos;] #=&gt; &quot;over-easy&quot;
order[:eggs] #=&gt; &quot;over-easy&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Values can be set with the hash-style access as well, and changes made from Ruby
will be reflected accordingly on the JavaScript side&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;order[&apos;eggs&apos;] = &quot;sunny side up&quot;
cxt.eval(&apos;order.eggs&apos;) #=&gt; &quot;sunny side up&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For property names that are also valid Ruby method names, you can access them just
like you would with Ruby properties declared with &lt;code class=&quot;language-text&quot;&gt;attr_reader&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;attr_accessor&lt;/code&gt;. Again,
changes made to the object in this way will be reflected in JavaScript:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;  order.eggs #=&gt; &quot;sunny side up&quot;
  order.eggs = &quot;scrambled&quot;
  cxt.eval(&apos;order.eggs&apos;) #=&gt; &quot;scrambled&quot;
end&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the cases where the property name is not a valid Ruby method name, hash-style access is mandatory:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;order[&apos;Extra $%#@! Mayonaise!&apos;] = true&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;V8::Object&lt;/code&gt; also includes &lt;code class=&quot;language-text&quot;&gt;Enumerable&lt;/code&gt; and allows you to access all properties of a given object.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;order.each do |key, value|
  puts &quot;#{key} -&gt; #{value}&quot;
end

#outputs:
eggs -&gt; scrambled
Extra $%#@! Mayonaise! -&gt; true&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As a convenience, &lt;code class=&quot;language-text&quot;&gt;V8::Context&lt;/code&gt; delegates the hash access functions to the JavaScript object which serves
as its global scope.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;order == cxt[&apos;order&apos;] #=&gt; true
order == cxt.scope[&apos;order&apos;] #=&gt; true&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;arrays&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#arrays&quot; aria-label=&quot;arrays permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Arrays&lt;/h2&gt;
&lt;p&gt;Not much to see here, but before you move along: A &lt;code class=&quot;language-text&quot;&gt;V8::Array&lt;/code&gt; is like every other &lt;code class=&quot;language-text&quot;&gt;V8::Object&lt;/code&gt; except it has a &lt;code class=&quot;language-text&quot;&gt;length&lt;/code&gt; property, and
it enumerates over the items stored at indices instead of the key, value pairs of its properties.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;array = cxt.eval(&apos;[&quot;green&quot;, &quot;red&quot;, &quot;golden&quot;]&apos;)
array.length #=&gt; 3
array.map {|color| &quot;#{color} slumbers&quot;} #=&gt; [&apos;green slumbers&apos;, &apos;red slumbers&apos;, &apos;golden slumbers&apos;]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;a name=&quot;functions&quot;&gt;
&lt;/a&gt;
&lt;h2 id=&quot;functions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#functions&quot; aria-label=&quot;functions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Functions&lt;/h2&gt;
&lt;p&gt;Consider the classic &quot;Circle&quot; example from every object oriented playbook you&apos;ll ever read. In JavaScript,
the way to implement the circle &quot;class&quot; is with a constructor function.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;circle = cxt.eval&amp;lt;&amp;lt;-JS
  function Circle(radius) {
    this.radius = radius
    this.area = function() {
      return this.radius * this.radius * Math.PI
    }
    this.circumference = function() {
      return 2 * Math.PI * this.radius
    }
  }
  new Circle(5)
JS&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we have the &lt;code class=&quot;language-text&quot;&gt;Circle&lt;/code&gt; constructor defined, and we have a reference to an instance of it in Ruby,
we can call its methods just as though it were a normal Ruby object. Of course, only we know
that under the covers the implementation is actually in JavaScript:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;circle.class            #=&gt; V8::Object
circle.radius           #=&gt; 5
circle.area()           #=&gt; 25Π
circle.circumference()  #=&gt; 10Π&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In JavaScript, methods are just object properties that happen to be functions. Therefore, you can get
a reference to the actual function value just as you could from JavaScript simply by accessing the property
by name. The resulting value is an instance of &lt;code class=&quot;language-text&quot;&gt;V8::Function&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;area =                circle[&apos;area&apos;]
circumference =       circle[&apos;circumference&apos;]
area.class            #=&gt; V8::Function
circumference.class   #=&gt; V8::Function&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once you have a reference to a &lt;code class=&quot;language-text&quot;&gt;V8::Function&lt;/code&gt;, there are two ways to call the underlying JavaScript code
(Actually there are three, but the third will be covered in the next section). These are the &lt;code class=&quot;language-text&quot;&gt;call()&lt;/code&gt; and
&lt;code class=&quot;language-text&quot;&gt;methodcall()&lt;/code&gt; methods. To understand the difference between these two methods, it helps to understand how
JavaScript functions themselves are invoked. In the event, there is the option to pass an object
which will serve as the implicit invocant or &lt;code class=&quot;language-text&quot;&gt;this&lt;/code&gt; value. If no &lt;code class=&quot;language-text&quot;&gt;this&lt;/code&gt; is provided, the function will
use the global scope in its place. Take for example the following JavaScript&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;var circle = new Circle(5)
var area = circle.area  //=&gt; [object Function]
//no invocant, corresponds to ruby call()
area()  //=&gt; NaN, there is no global &apos;radius&apos;.
//call with invocant, corresponds ruby methodcall()
area.apply(circle)  //=&gt; 25Π&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The same code in Ruby:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;area = circle[&apos;area&apos;]
area.class              #=&gt; V8::Function
area.call()             #=&gt; NaN
area.methodcall(circle) #=&gt; 25Π&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because of this mechanism, JavaScript method invocation is much more flexible than Ruby in the sense that
virtually &lt;em&gt;any&lt;/em&gt; object can be used as the invocant of &lt;em&gt;any&lt;/em&gt; function provided it has the requisite properties
to satisfy the function&apos;s requirements:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;area.methodcall(:radius =&gt; 5) #=&gt; 25Π
other_circle = OpenStruct.new
other_circle.radius = 10
area.methodcall(other_circle) #=&gt; 100Π&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A very powerful construct indeed.&lt;/p&gt;
&lt;h2 id=&quot;constructors&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#constructors&quot; aria-label=&quot;constructors permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Constructors&lt;/h2&gt;
&lt;p&gt;But wait, there&apos;s more! Any JavaScript function can be either invoked normally, or, combined with the &lt;code class=&quot;language-text&quot;&gt;new&lt;/code&gt; keyword,
as a &lt;em&gt;constructor&lt;/em&gt;. It&apos;s what we used in the original eval() block to create the instance of &lt;code class=&quot;language-text&quot;&gt;Circle&lt;/code&gt; whose methods we were messing
about with.&lt;/p&gt;
&lt;p&gt;That was not quite necessary since we can invoke functions as constructors from Ruby too. This is done with the &lt;code class=&quot;language-text&quot;&gt;new&lt;/code&gt;
method of &lt;code class=&quot;language-text&quot;&gt;V8::Function&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Circle = cxt[&apos;Circle&apos;]
circle2 = Circle.new(3)
circle2.radius        #=&gt; 3
circle2.area          #=&gt; 9Π
circle2.circumference #=&gt; 6Π&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Interestingly, when used as a constructor, a JavaScript function is almost completely indistinguishable from a Ruby class.
This apparent duality between classes and functions is behind the decision to &lt;a href=&quot;/2010/06/30/accessing-ruby-objects-from-V8#classes&quot;&gt;represent Ruby classes reflected into JavaScript as functions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The driving goal in all of these cases is the ability to author intuitive, tightly bound JavaScript, which necessarily doesn&apos;t
involve evaluating strings to get what you want done. In closing, if there is something missing from this API you think would
be useful, I would love to &lt;a href=&quot;http://github.com/cowboyd/therubyracer/issues&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;hear about it&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[RYE: Repeat Yourself Enough]]></title><link>https://frontside.com/blog/2009-06-29-rye-repeat-yourself-enough/</link><guid isPermaLink="false">https://frontside.com/blog/2009-06-29-rye-repeat-yourself-enough/</guid><category><![CDATA[proskillz]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 29 Jun 2009 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Lately, I&apos;ve been practicing the exact opposite of the DRY principle. Yup, you read that right:  I repeat myself constantly, and in as many different contexts... including code, database schemas, test-plans and even documentation. The reason: So I won&apos;t have to repeat myself. It&apos;s not that I don&apos;t buy into the DRY principle, or that I&apos;m somehow skeptical about the value its proper application yields. I just find it difficult to achieve in practice.&lt;/p&gt;
&lt;p&gt;According to the &lt;a href=&quot;pragmaticprogrammer.com&quot;&gt;Pragmatic Programmers&lt;/a&gt; who coined the term:&lt;/p&gt;
&lt;p&gt;DRY says that every piece of system knowledge should have one authoritative, unambiguous representation. Every piece of knowledge in the development of something should have a single representation. A system&apos;s knowledge is far broader than just its code. It refers to database schemas, test plans, the build system, even documentation.&lt;/p&gt;
&lt;p&gt;Essentially it is an empirical measure against which to gauge the proper level of abstraction in your system. If you have not made the right abstractions, then you will be found to be repeating yourself, whereas if you &lt;em&gt;have&lt;/em&gt; made the right abstractions, then you won&apos;t. This is because abstractions &lt;em&gt;directly encode&lt;/em&gt; the system  knowledge that DRY talks about no less than 3 times in its definition.&lt;/p&gt;
&lt;p&gt;The benefits of good abstractions are many and well known, and I&apos;m not going to go into them here (there&apos;s always the internet for that), but what I&apos;ve taken particular heed of lately is that abstraction is a double-edged sword that should not be wielded lightly. Get it right, and the previously intractable dissolves to simplicity in an instant... but get it wrong, and a snarl of complexity gridlocks your code base just as fast.&lt;/p&gt;
&lt;p&gt;You see, I wasn&apos;t telling the whole truth when I said before that abstractions directly encode system knowledge. It would be more correct to say: &lt;em&gt;Good&lt;/em&gt; abstractions directly encode system knowledge. &lt;em&gt;Bad&lt;/em&gt; abstractions directly encode &lt;em&gt;system ignorance.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The problem is that the DRY principle, while still very valid and useful, doesn&apos;t help us here because  it assumes system knowledge as its input. But really valuable system knowledge isn&apos;t just lying around, it must be carefully constructed with significant amounts of research and analysis. That is to say, it must be learned. And what better way is there to learn something than by doing it over and over again until you know it inside and out? What better way is there than trial and error to really &lt;em&gt;get at the physics&lt;/em&gt; of a phenomenon until you can use it to easily analyze it in all its forms? The fact is, you&apos;ve got to repeat yourself over and over enough times until you can say with confidence: &lt;em&gt;This I know to be true.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can think of it like doing your math homework, or being like Daniel-San: waxing Mr Miyagi&apos;s car again and again until you know karate by instinct. In fact, I&apos;m convinced that there&apos;s no other way to generate &lt;em&gt;real&lt;/em&gt; knowledge.&lt;/p&gt;
&lt;p&gt;Ironically, I repeat myself a lot these days because I hate repeating myself. I loathe it with an almost pathological passion, and sometimes (more often then I&apos;d like to admit) it plays to my disadvantage. In my obsessive/compulsive rush to not repeat myself I&apos;ll introduce a bad abstraction based on flawed or incomplete system knowledge, and worse still, I won&apos;t know that I took the wrong fork in the road until it&apos;s way late in the game and it&apos;s hard to find the way back home.&lt;/p&gt;
&lt;p&gt;That&apos;s why I&apos;m playing it cool lately and making sure that I repeat myself enough to &lt;em&gt;perfect&lt;/em&gt; the system knowledge required to keep myself DRY.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[In Search of a Better Autogrowing Textfield]]></title><link>https://frontside.com/blog/2008-12-16-in-search-of-a-better-autogrowing-textfield/</link><guid isPermaLink="false">https://frontside.com/blog/2008-12-16-in-search-of-a-better-autogrowing-textfield/</guid><category><![CDATA[dhtml]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Tue, 16 Dec 2008 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Autogrowing textfields are a nice piece of flash for any web application. They conserve precious screen real-estate, but grow to a height just big enough to accomodate the text the user actually typed without resorting to unsightly things scrollbars.&lt;/p&gt;
&lt;p&gt;There are a number of solutions out there, but since I&apos;m using &lt;a target=&quot;_blank&quot; href=&quot;http://jquery.com&quot;&gt;jQuery&lt;/a&gt; on my current project, the two that I evaluated were &lt;a href=&quot;http://plugins.jquery.com/project/Growfield&quot; target=&quot;_blank&quot;&gt;Growfield&lt;/a&gt; and &lt;a target=&quot;_blank&quot; href=&quot;http://plugins.jquery.com/project/Autogrow&quot;&gt;Autogrow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While those two plugins often did what they were supposed to do, they also had tons of quirks and edge cases that prompted me give it a go myself. Specifically, I found that depending on the browser and operating system I would encounter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;eye-jarring jitter wherein the textfield would expand and contract my 1 or 2 pixels with every keystroke&lt;/li&gt;&lt;/li&gt;
&lt;li&gt;resizing of the textfield to 0 pixels, when there was no text in the box&lt;/li&gt;
&lt;li&gt;intermittent loss of focus on some browsers&lt;/li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But most importantly, it seemed that more often than not, the text did not actually grow correctly in any of the real-world environments that I tried in my production application.&lt;/p&gt;
&lt;p&gt;As I discovered, the main reason for this was that the technique used was to fill a hidden DIV element with the text from the textfield, and then use the height of that DIV to determine how tall the textfield should be. That works great except for one nasty detail: most browsers use native widgets for text inputs, and those native widgets have their own word-wrap and layout code, so even things like font, line-height and letter spacing being equal, you can still get different word-wrap behavior from OS to OS.&lt;/p&gt;
&lt;p&gt;In an attempt to side-step all of these issues, I thought &quot;what if instead of using a DIV element to calculate the height, I could use a native textfield?&quot; After all, if native textfields use a different word-wrap and layout algorithms, can&apos;t I just try and harness those algorithms, whatever they might be? At first this seems perfectly circular i.e.: I don&apos;t know what the ideal height of a textarea should be, so I&apos;ll use the height of a texarea to find out. Of course there&apos;s a twist, and the wonderful little property that makes it all possible is the &lt;a target=&quot;_blank&quot; href=&quot;https://developer.mozilla.org/en/DOM/element.scrollHeight&quot;&gt;scrollHeight&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;lines, not heights.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Please Stop Using Global Variables in Ruby]]></title><link>https://frontside.com/blog/2008-06-25-please-stop-using-global-variables-in-ruby/</link><guid isPermaLink="false">https://frontside.com/blog/2008-06-25-please-stop-using-global-variables-in-ruby/</guid><category><![CDATA[ruby]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Wed, 25 Jun 2008 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I couldn&apos;t sleep this morning. I woke up around 4:30 AM thinking about how code is organized in ruby. I&apos;m sure I will look back on my life with disbelief and a touch of shame at such behavior, but that is (hopefully) decades away.&lt;/p&gt;
&lt;p&gt;The problem turning around in my head which eventually caused me to wake was my own inability to come to terms with a prevalent pattern in the ruby community: the global variable. Swirling in my semi-conscious mind was a motley mixture of bewilderment, self-doubt, scorn and a touch of righteous indignation.&lt;/p&gt;
&lt;p&gt;On the one hand, there must be something I&apos;m missing. One of the reasons I love ruby-space is that it tends to be filled with talented programmers who work the language to produce code that is powerful while at the same time being easy to understand and use. Surely, their collective conscious is a better guide than my own experience and intuition. I worry that is primarily my own fuddy-duddity that prevents me from accepting global variables as good practice.&lt;/p&gt;
&lt;p&gt;To clarify, when I speak about global variables, I&apos;m talking primarily about using global class objects as the repositories for methods and state. There are plenty examples out there of this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;# active record
Post.find(:all)

# amazon s3
S3Object.store(&apos;me.jpg&apos;, open(&apos;headshot.jpg&apos;), &apos;photos&apos;)

# paypal-business gem
Paypal.capture(params)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In each of the preceding examples, there is implicit state stored on the class object. In active record, the database connection information, in S3Object, the AWS access key id and secret key, and finally, in Paypal, the paypal server url and business account name. Because the class object is global, the state on it is effectively global. And &lt;em&gt;that&lt;/em&gt; is what sets my spidey sense to tingling.&lt;/p&gt;
&lt;p&gt;Not only is this style subject to the all the arguments for why &lt;a href=&quot;http://c2.com/cgi/wiki?GlobalVariablesAreBad&quot;&gt;global variables are bad&lt;/a&gt;, but it just flat-out makes the API&apos;s themselves less useful. Here&apos;s an example from an actual project.&lt;/p&gt;
&lt;p&gt;I had a system which needed to talk to two different SQS queues which were contained in two separate amazon web services accounts. Unfortunately, the standard SQS api uses class variables to store configuration information, and then a set of class methods to access the queue services, so I was forced to overwrite the global configuration parameters every time I wanted to access the queue. Luckily, the application was not multi threaded, or I would have been stuck rolling my own.&lt;/p&gt;
&lt;p&gt;I don&apos;t see why:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;SQS.access_key_id = &apos;ACCESS_ID&apos;
SQS.secret_access_key = &apos;SECRET&apos;
q = SQS.get_queue &apos;MyQueue&apos;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;is any better than:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@sqs = SQS.new :access_key_id =&gt; &apos;ACCESS_ID&apos;, :secret_access_key =&gt; &apos;SECRET&apos;
q = @sqs.get_queue &apos;MyQueue&apos;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(IMHO it&apos;s uglier) and in the second, hypothetical API, you can painlessly, and in a thread-safe manner talk to multiple queues on multiple accounts.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@one = SQS.new :access_key_id =&gt; &apos;AccountOne&apos;, :secret_access_key =&gt; &quot;AccountOneSecret&quot;
@two = SQS.new :access_key_id =&gt; &apos;AccountTwo&apos;, :secret_access_key =&gt; &quot;AccountTwoSecret&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But there&apos;s a deeper principle at stake here than allowing multiple instances. It&apos;s about giving &lt;em&gt;power to the programmer&lt;/em&gt;, and letting them control the API, and not the other way around.&lt;/p&gt;
&lt;p&gt;It seems to me that when you&apos;re designing an API, you want the programmer(to the greatest extent possible) be able to create their own little world over which they have complete control. The should be able to spin up as many instances of your code and use it in ways that perhaps you hadn&apos;t thought of without them having to worry that one world will interfere with another world they&apos;ve created.&lt;/p&gt;
&lt;p&gt;If you&apos;ve absolutely got to go global, it&apos;s very little effort to wrap a static/global interface around a single default instance, but not the other way around. Given the similarity in effort, it seems like embedability is the way to go.&lt;/p&gt;
&lt;p&gt;Global variables surely have their place in some applications, and I&apos;m not opposed to them on purely ideological grounds, but ruby already has a construct for global variables... it&apos;s called the &apos;$&apos; sigil.&lt;/p&gt;
&lt;p&gt;In your environment.rb, or wherever you can just put:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;#environment.rb
$sqs = SQS.new :access_key_id =&gt; &apos;AccountOne&apos;, :secret_access_key =&gt; &quot;AccountOneSecret&quot;

#somewhere else
q = $sqs.get_queue &quot;MyQueue&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;My suspicion is that Ruby on Rails shares a large portion of the blame for the evolution of this style what with &lt;code&gt;ActiveRecord.establish_connection()&lt;/code&gt; and friends. As the highest profile ruby project it&apos;s only natural that people will copy its conventions --for better or for worse. Still, I wish people in the future would break from this particular precedent and if they go global, to do it properly. Give the poor class objects a break!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Patiently waiting for JavaFX]]></title><link>https://frontside.com/blog/2008-06-05-patiently-waiting-for-javafx-script/</link><guid isPermaLink="false">https://frontside.com/blog/2008-06-05-patiently-waiting-for-javafx-script/</guid><category><![CDATA[java]]></category><category><![CDATA[jafafx]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Thu, 05 Jun 2008 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;About a year ago, SUN announced a &quot;new&quot; platform for developing embeddable applications on the web, and they called this platform JavaFX. In reality, this new platform seems to me less of an innovation and more of a rehabilitation of the applet infrastructure which they allowed to languish over the last decade.&lt;/p&gt;
&lt;p&gt;That&apos;s not a criticism, it&apos;s a compliment. I&apos;m happy that they&apos;re going to give applets another go. Heck, I&apos;m even glad they&apos;re calling it JavaFX too. &quot;Applet&quot; always sounded too effete anyway. In any case I&apos;ve always like the applet model, and wished it were a more viable option for web development. Given the success of Flex, which also uses the applet model, other people must feel this way too.&lt;/p&gt;
&lt;p&gt;But I digress.&lt;/p&gt;
&lt;p&gt;As far as I can tell (I&apos;ve only been able to get my hands on some demos and a little open source compiler) JavaFX involves upgrading some of the more boorish aspects of the  java browser plugin. To name a few: faster download and initialization of application and JRE code, tighter integration and communication with the rest of the DOM, modern video and audio codecs.... All those are necessary upgrades to ensure the viability of the platform, but they can hardly be called innovative&lt;/p&gt;
&lt;p&gt;That said, one new and curious aspect of JavaFX is that it will (for the most part) &lt;em&gt;not&lt;/em&gt; be written in Java. Instead, SUN is promoting a completely new and aptly named scripting language: JavaFX script.&lt;/p&gt;
&lt;p&gt;Of all the new features it was the specification of this language that impressed me most. I&apos;m not sure how this little gem of a language managed to come out of SUN, but it&apos;s absolutely loaded with modern language features to make programming in it clear and concise.&lt;/p&gt;
&lt;p&gt;I&apos;m talking about&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;closures&lt;/li&gt;
&lt;li&gt;pure functions&lt;/li&gt;
&lt;li&gt;lazy evaluation&lt;/li&gt;
&lt;li&gt;list comprehensions (that put ruby&apos;s to shame)&lt;/li&gt;
&lt;li&gt;optional declarative syntax&lt;/li&gt;
&lt;li&gt;rolled in query language for searching and modifying data structures&lt;/li&gt;
&lt;li&gt;data binding supported at the language level&lt;/li&gt;
&lt;li&gt;tons of stuff I&apos;m sure I don&apos;t even know about....&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall it seems like JavaFX script is like 4 separate languages existing in harmony in one neat package, and as I read more and more about it, I kept thinking to myself &quot;This is not just some standard UI scripting language with a little sugar and a few extra hooks for writing GUIs. This is positively &lt;em&gt;avante-garde&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I like the idea that SUN can challenge their developers to think in new ways, but I can also imagine a backlash, or more mildly put, an general aversion in the developer community, since this is not any old language research project, but the centerpiece in SUN&apos;s product in the battle over the browser VM.&lt;/p&gt;
&lt;p&gt;So where did this decision come from to go with such a departure from the norm when it came to defining JavaFX script? I like it alot, but I worry that SUN is going to chicken out, and go with something a little less sexy but a little more digestible (at least in the short term) to its current developers as well as the developers of competing platforms like Adobe Flex or Microsoft Silverlight.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[mod_rewrite: Remeber that the version counts]]></title><link>https://frontside.com/blog/2007-06-11-when-using-mod-rewrite-remember-that-the-version-counts/</link><guid isPermaLink="false">https://frontside.com/blog/2007-06-11-when-using-mod-rewrite-remember-that-the-version-counts/</guid><category><![CDATA[tips]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Mon, 11 Jun 2007 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Pro Tip: Which regular expressions work depends on the version of Apache/mod_rewrite that you&apos;re using. I recently tested the following rewrite rule on Apache2&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;RewriteRule ^archives/(\d+).html http://www.thefrontside.net/map2new.php?$1 [R]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I wanted to match files like archives/000532.html.&lt;/p&gt;
&lt;p&gt;But when it came time to deploy, it didn&apos;t work. Turns out the environment I was deploying to was using a different version of Apache. That&apos;s bad practice of course, but aside from that, the little gotcha was that the regular expression interpreter was different in different versions of Apache, and in this case, its behavior differed not only from the newer version but also from the behavior of most regexp engine&apos;s out there. Specifically, the &quot;digit&quot; literal &lt;code class=&quot;language-text&quot;&gt;\d&lt;/code&gt; is not understood by older versions (which interpret it as a literal &quot;d&quot;).&lt;/p&gt;
&lt;p&gt;Instead I had to use [0-9]&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;RewriteRule ^archives/([0-9]+).html http://www.thefrontside.net/map2new.php?$1 [R]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a very specific nugget, but hopefully it will save someone a headache down the road. Just remember, if your mod_rewrite regexp isn&apos;t working, &lt;em&gt;check the specific version of the engine&lt;/em&gt;, and make sure your regexp is one that it will understand.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Trans-Global Pair Programming]]></title><link>https://frontside.com/blog/2007-06-09-the-chicken-and-the-vine-trans-global-pair-programming/</link><guid isPermaLink="false">https://frontside.com/blog/2007-06-09-the-chicken-and-the-vine-trans-global-pair-programming/</guid><category><![CDATA[proskillz]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Sat, 09 Jun 2007 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The Frontside Software is a three person company with &quot;offices&quot; in Michigan, Finland, Massachusetts, and New Jersey. We&apos;re don&apos;t see each other every day, and we&apos;re rarely in the same room, but we still do a significant portion of our development work in pairs. Despite many other competing setups, we still do this with the not-so-new, not-so-exciting, yet extremely flexible and reliable &lt;a href=&quot;http://www.realvnc.com/what.html&quot; title=&quot;Real VNC&quot;&gt;VNC&lt;/a&gt; combined with a voip product like &lt;a href=&quot;http://skype.com&quot; title=&quot;Skype VOIP&quot;&gt;skype&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;How it works&lt;/h3&gt;
&lt;p&gt;One of us (the driver) runs a vnc server which transmits everything that is rendered on his display to one or more vnc clients (passengers) being run by the other half of the pair. That way, the client can see everything that goes on while the driver is coding, including  his code editor, his web browser, his terminal windows, etc... Meanwhile, you&apos;ve got real-time audio so that you can talk about the work you&apos;re doing as you&apos;re doing it.&lt;/p&gt;
&lt;h3&gt;Is there something better?&lt;/h3&gt;
&lt;p&gt;Not yet. We&apos;ve seen some new collaborative coding tools like &lt;a href=
&quot;http://www.codingmonkeys.de/subethaedit/&quot; title=&quot;SubEthaEdit Site&quot;&gt;SubEthaEdit&lt;/a&gt; and &lt;a href=&quot;http://gobby.0x539.de/trac/&quot; title=&quot;Gobby Trac Site&quot;&gt;Gobby&lt;/a&gt; come down with some very slick features. Specifically, the updating and syncing of editor state between the two machines is very fast, and effectively coordinates multiple people editing the same document, with as few clashes as possible. The way in which they do this is impressive, but after having given it several abortive attempts as a real solution for remote pair programming, we went back to good old VNC. Here&apos;s why:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Lack of editing features:&lt;/strong&gt; The collaborative editors of today are good at one thing: editing text collaboratively. The problem is that when you&apos;re pair-programming, you&apos;re not editing text, you&apos;re editing code, and code is only a simple sequence of text to a computer. There are lots of editors these days that leverage the semantically rich structure of the documents on which they operate like TextMate, Emacs, Eclipse.... everybody has a favorite, and because your collaborative editor is not your favorite, that means it sucks ;-)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lack of environment:&lt;/strong&gt; Of course, there are a scant few collaborative editing plug-ins for existing IDEs which would seem to address this problem, but adding on another layer, development is about more than just coding. It&apos;s about browsing documentation, running servers, invoking build scripts from the command line, and about a million other tiny tasks. In effect, your &lt;em&gt;actual&lt;/em&gt; IDE is not just one application, it&apos;s your whole computer, and if the only thing being shared is a single app, then it cuts your pair out of a lot of important context. With VNC, everybody sees what&apos;s going on all the time. They can see not only the code, but also the running program.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Editing the same document at the same time isn&apos;t really helpful anyway&lt;/strong&gt;: If you&apos;ve done much pair-programming, then you realize that the real value doesn&apos;t come from having two sets of fingers on the keyboard at the same time. In fact quite the opposite: Both participants are following the thread of development, but one of them is freed entirely from the act of coding so that they can think about high-level architectural issues, or lookup api docs, or google for resources --all in parallel. Having both people pounding on the keyboard actually hinders this dynamic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VNC is cross platform&lt;/strong&gt;: This is a biggie. There are vnc clients and servers for Windows, OSX, and Linux (we code on all three), and they all interoperate with each other. That&apos;s a pretty hard feature to top, especially for single-platform apps like SubEthaEdit and Gobby which run on OSX and Linux respectively.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;About the only drawback to pair programming with VNC is that there can be some fairly significant lag (between 1-4 seconds) depending on network load on either end, but even so, when it comes to &lt;em&gt;actually&lt;/em&gt; developing collaboratively, VNC and Skype are our daily tools of choice.&lt;/p&gt;
&lt;h3&gt;VNC Clients/servers&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OSX client&lt;/strong&gt;: &lt;a href=&quot;http://sourceforge.net/projects/cotvnc/&quot; title=&quot;Chicken of the VNC&quot;&gt;Chicken of the VNC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OSX server&lt;/strong&gt;: &lt;a href=&quot;http://www.redstonesoftware.com/products/vine/server/vineosx/&quot; title=&quot;Vine Server&quot;&gt;Vine Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows/Linux client/server&lt;/strong&gt;: &lt;a href=&quot;http://www.tightvnc.com/download.html&quot; title=&quot;Tight VNC&quot;&gt;http://www.tightvnc.com/download.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Taming the Rhino]]></title><link>https://frontside.com/blog/2006-08-04-taming-the-rhino-making-mozillas-javascript-command-line-a-little-less-brutish/</link><guid isPermaLink="false">https://frontside.com/blog/2006-08-04-taming-the-rhino-making-mozillas-javascript-command-line-a-little-less-brutish/</guid><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Fri, 04 Aug 2006 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently &lt;a href=&quot;learning-javascript-from-the-command-line&quot;&gt;described&lt;/a&gt; how to use the one of the &lt;a href=&quot;http://www.mozilla.org/js/&quot;&gt;freely available shells&lt;/a&gt; as a great way to explore your javascript runtime. There are two implementations of the javascript interpreter sponsored by the Mozilla project, &lt;a href=&quot;http://www.mozilla.org/js/spidermonkey&quot;&gt;Spider Monkey&lt;/a&gt; an interpreter implemented in C, and &lt;a href=&quot;http://www.mozilla.org/rhino/&quot;&gt;Rhino&lt;/a&gt;, an interpreter implemented in Java. With respect to the javascript runtime itself, these two implementations are almost identical, and so what works in one, will generally work in the other. They diverge, however, when it comes to embedding objects and functions that are implemented in a language other than javascript. Naturally, Spidermonkey is better suited for embedding objects implemented in C, while Rhino excels at embedding objects implemented in Java.&lt;/p&gt;
&lt;p&gt;What exactly is &quot;embedding&quot; an object implemented in Java? If you don&apos;t know what this means already, I could try to describe it to you, but why not show it live and in the flesh with the Rhino command line? That&apos;s the exploratory technique that I find so valuable.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cowboyd@subzero:~$ java -classpath js.jar org.mozilla.javascript.tools.shell.Main
Rhino 1.5 release 5 2004 03 25
js&gt; var javaString = new java.lang.String(&quot;Hello World&quot;)
js&gt; javaString.hashCode()
-862545276
js&gt; javaString.startsWith(&quot;Hello&quot;)
true
js&gt; javaString.startsWith(&quot;World&quot;)
false
js&gt; var jsString = new String(&quot;Hello World&quot;)
js&gt; jsString.startsWith(&quot;Hello&quot;)
js: &quot;&amp;lt;stdin&gt;&quot;, line 5: uncaught JavaScript exception: TypeError: startsWith is not a function. (&amp;lt;stdin&gt;; line 5)
js&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, javaString is a reference to an actual &lt;code class=&quot;language-text&quot;&gt;java.lang.String&lt;/code&gt; object, and has access to all the methods of that class, many of which are not contained in the native javascript &lt;code class=&quot;language-text&quot;&gt;String&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Embedding goes two ways. Not only can you instantiate and use java objects from javascript, but you can also pass in javascript objects as parameters to java methods. You can even extend objects and implement interfaces in javascript! Once again, the command line shows this in action. In this example, we&apos;ll implement the &lt;code class=&quot;language-text&quot;&gt;java.lang.Runnable&lt;/code&gt; interface in javascript&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cowboyd@subzero:~$ java -classpath js.jar org.mozilla.javascript.tools.shell.Main
Rhino 1.5 release 5 2004 03 25
js&gt; var impl = new Object()
js&gt; impl.run = function() {print(&quot;Yeah that&apos;s right, you better run!&quot;)}

function () {
    print(&quot;Yeah that&apos;s right, you better run!&quot;);
}

js&gt; var runnable = new java.lang.Runnable(impl)
js&gt; var thread = new java.lang.Thread(runnable)
js&gt; thread.run()
Yeah that&apos;s right, you better run!
js&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is all well and good, but that&apos;s quite a bit of code to get right the first time! Chances are, if you&apos;re just starting out with the Rhino command line, you&apos;re not going to have as much luck, especially if you&apos;re using it as a tool to learn javascript in the first place, and unfortunately, this is where Rhino comes up &lt;em&gt;way&lt;/em&gt; short. Rather than have a forgiving &lt;a href=&quot;http://en.wikipedia.org/wiki/Command_line_interface&quot;&gt;CLI&lt;/a&gt;, Rhino punishes you for every syntactic and semantic error that you make by not collecting command history. Even worse, hitting the up and down arrows result in bizarre character literals output directly to the prompt. You can&apos;t even correct a mistake that you&apos;ve made in the current line you&apos;re typing without backspacing all the way to the error, and then re-typing from that point on.&lt;/p&gt;
&lt;p&gt;In this example, I&apos;d like to arrow-left so that I can correct my misspelling of &quot;java.lang&quot;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cowboyd@subzero:~$ java -classpath js.jar org.mozilla.javascript.tools.shell.Main
Rhino 1.5 release 5 2004 03 25
js&gt; var r = new java.lng.Runnable(^[[D^[[D^[[D^[[D&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Ugh!&lt;/strong&gt; Or what happens if the shell didn&apos;t take my last command because it was slightly bogus? I&apos;d like to retrieve the command with the up-arrow, edit it a little bit in-place and then try again because after all, it was only &lt;em&gt;slightly&lt;/em&gt; bogus. Watch me try and recover from this minor syntax error...&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cowboyd@subzero:~$ java -classpath /usr/share/java/js.jar org.mozilla.javascript.tools.shell.Main
Rhino 1.5 release 5 2004 03 25
js&gt; var f = function() {print(&quot;oops I forgot to close these parens&quot;}
js: &quot;&amp;lt;stdin&gt;&quot;, line 29: missing ) after argument list
js: var f = function() {print(&quot;oops I forgot to close these parens&quot;}
js: ...............................................................^
js: &quot;&amp;lt;stdin&gt;&quot;, line 29: missing } after function body
js: var f = function() {print(&quot;oops I forgot to close these parens&quot;}
js: ...............................................................^
js: &quot;&amp;lt;stdin&gt;&quot;, line 29: Compilation produced 2 syntax errors.
js&gt;
js&gt; //I know. Up-arrow to the rescue!
js&gt; ^[[A^[[A^[[A^[[A^[[A^[[A //drat, foiled again!&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These problems are in particularly nasty contraposition to the technique of exploration via the shell which I advocate because the the cost for failure is so expensive. Indeed, what is so wonderful about most modern shells is that the cost for a syntax error is so small. For some reason, the implementors of the Rhino CLI decided to implement their shell with the typical functionality circa 1962.&lt;/p&gt;
&lt;p&gt;It&apos;s not a problem for me though, thanks to one of my favorite unsung java libraries, &lt;a href=&quot;http://jline.sourceforge.net/&quot;&gt;JLine&lt;/a&gt;. JLine hits a super sweet spot in that it takes somewhere around 0 effort to add loads of standard functionality to your command line interfaces. It seems that no one in the java world bothers with a decent CLI; tragic in my opinion, but probably because it&apos;s considered well-understood, non-trivial and therefore tedious. With JLine, building that CLI comes at around 0 cost. What&apos;s really cool about JLine is that a program doesn&apos;t even need to be written with it. It can transparently intercept the console input for &lt;em&gt;any&lt;/em&gt; java program and seamlessly splice on any and all functionality you&apos;d expect from a hot shell: in-place editing, command history, you name it. In a word: &lt;em&gt;perfect&lt;/em&gt; for a beast like Rhino.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cowboyd@subzero:~$ java -classpath js.jar:jline.jar  jline.ConsoleRunner org.mozilla.javascript.tools.shell.Main
Rhino 1.5 release 5 2004 03 25
js&gt; prnt(&quot;oops let me try that again&quot;)
js: &quot;&amp;lt;stdin&gt;&quot;, line 1: uncaught JavaScript exception: ReferenceError: &quot;prnt&quot; is not defined. (&amp;lt;stdin&gt;; line 1)
js&gt; print(&quot;oops let me try that again&quot;)
oops let me try that again
js&gt; //trust me, that was easy. Just like it should have been in the first place.
js&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;JLine truly is a healing salve for your chafing CLI woes. Did I mention that it&apos;s cross-platform?&lt;/p&gt;
&lt;p&gt;While the barrier to entry is extremely low, the path to upgrade is but a mild upward slope. If you do end up wanting nice extras such as TAB-completion or custom key bindings, it has a simple configuration mechanism, and &lt;a href=&quot;http://jline.sourceforge.net/apidocs/index.html&quot;&gt;Java API&lt;/a&gt; to make the pain of writing custom code as minimal as possible. But that&apos;s another bedtime story altogether.&lt;/p&gt;
&lt;p&gt;I hope you enjoy JLine with Rhino, or with any other impolite java command lines you may use!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Live Stylesheets]]></title><link>https://frontside.com/blog/2006-07-15-live-stylesheets/</link><guid isPermaLink="false">https://frontside.com/blog/2006-07-15-live-stylesheets/</guid><category><![CDATA[dhtml]]></category><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Sat, 15 Jul 2006 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Even after working with DTML for over a year, I&apos;m still constantly astounded by how &lt;em&gt;dynamic it actually is&lt;/em&gt;. The most important thing to keep in the back of your head as a DHTML programmer is that the same mechanisms used by the browser to build an HTML document at load time are available to your in-page scripts. So, really, the static loading of your pages when you access a url is just the HTML parser invoking the same methods on the same objects that are available to your javascript code.&lt;/p&gt;
&lt;!--break--&gt;
&lt;p&gt;Take this static HTML code:&lt;/p&gt;
&lt;code type=&quot;html&quot;&gt;
&lt;html&gt;
&lt;body&gt;&lt;div id=&quot;foo&quot;&gt;This is my div&lt;/div&gt;&lt;/body&gt;
&lt;/html&gt;
&lt;/code&gt;
&lt;p&gt;The same result can be achieved dynamically:&lt;/p&gt;
&lt;code type=&quot;html&quot;&gt;
&lt;html&gt;
&lt;body onload=&quot;addFoo()&quot;&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
function addFoo() {
   var foo = document.createElement(&apos;div&apos;)
   foo.id = &quot;foo&quot;
   var fooContent = document.createTextNode(&quot;This is my div&quot;)
   foo.appendChild(fooContent)
   document.body.appendChild(foo)
}
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
&lt;/code&gt;
&lt;p&gt;Nothing mind-blowing there; indeed, this technique is the cornerstone of DHTML. But it takes awhile to let it sink in to the point where using it is one of your first strategies to solving a problem. Specifically, you can use it not only to dynamically change layout-related HTML elements (span, div, ul, table, et al...), but also to create/modify &lt;em&gt;behavioral elements&lt;/em&gt;(link, script, meta, etc...)&lt;/p&gt;
&lt;p&gt;That said, I was recently trying to create a CSS stylesheet at runtime, and enable it so that its rules would be active in the page. At first, I was trying to use the &lt;a href=&quot;http://www.w3.org/TR/DOM-Level-2-Style/ecma-script-binding.html&quot;&gt;W3C DOM CSS interface&lt;/a&gt;, the idea being to  create a stylesheet object, add a bunch of rules to it corresponding to the rules that I wanted, and then put it into the stylesheets array. Unfortunately, doing this in a cross-platform way is &lt;a href=&quot;http://www.quirksmode.org/dom/w3c_css.html&quot;&gt;borderline impossible&lt;/a&gt;. After pounding my head against that for awhile and getting nowhere,  I figured, &quot;why not just create the whole thing as a top-level html element, and let the browser just take it away from there?&quot; The basic strategy is this: create a &lt;code&gt;style&lt;/code&gt; DOM Element dynamically, add text content to it representing the actual stylesheet, and then pop it into the HTML DOM. With a few caveats, it works like a charm. The browser parses the text as CSS, and links in into the live cascade.&lt;/p&gt;
&lt;p&gt;I mentioned caveats.. well, of course there are the obligatory cross-browser compatibility issues to be aware of:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;In Internet Explorer, you can&apos;t just append a Text Node to a Style element, you have to use some trickery to get it to work.&lt;/li&gt;
  &lt;li&gt;KHTML &amp;amp; Safari do not honor &lt;code&gt;style&lt;/code&gt; elements that are not contained in the HEAD element of the document.&lt;/li&gt;
  &lt;li&gt;While IE and Mozilla always create a HEAD element for you if one doesn&apos;t exist, Opera and KHTML do not.&lt;/li&gt;
  &lt;li&gt;While Opera will honor a dynamically created HEAD element, KHTML will not. (That&apos;s a bug in KHTML as far as I&apos;m concerned as it violates the DHTML principle that I&apos;ve been talking about.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All in all, they&apos;re nothing to worry about and do not stand in the way of the fundamental technique. I&apos;ve created a &lt;a href=&quot;/bitbucket/live-stylesheet.html&quot;&gt;demo page&lt;/a&gt; showing this code in action. As a nice side effect, it works as quick way of playing around with CSS properties and how they effect the styling of elements.&lt;/p&gt;
&lt;p&gt;Here is the source snippet implementing the technique I&apos;ve described here:&lt;/p&gt;
&lt;code type=&quot;javascript&quot;&gt;
   var style = document.createElement(&apos;style&apos;)
   style.setAttribute(&apos;type&apos;, &apos;text/css&apos;)
&lt;p&gt;var cssText = $(&apos;cssText&apos;).value
if (style.styleSheet) { //IE only
style.styleSheet.cssText = cssText
} else {
//for some reason this fails in IE.
var text = document.createTextNode(cssText)
style.appendChild(text)
}
&lt;/code&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Learning Javascript from the Command Line]]></title><link>https://frontside.com/blog/2006-07-08-learning-javascript-from-the-command-line/</link><guid isPermaLink="false">https://frontside.com/blog/2006-07-08-learning-javascript-from-the-command-line/</guid><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Charles Lowell]]></dc:creator><pubDate>Sat, 08 Jul 2006 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In the &lt;a href=&quot;http://www.drunkandretired/podcast&quot;&gt;Drunk and Retired Podcast&lt;/a&gt;, &lt;a href=&quot;http://www.drunkandretired.com/2006/07/08/drunkandretiredcom-podcast-episode-59-lightside-v-darkside-plus-learning-javascript-the-language-not-the-javascript-the-browser-scriptus/#comments&quot;&gt;episode  59&lt;/a&gt; I spoke about learning your way around javascript the language independently from the browser, and how you can use the command line tools that come with the various javascript engines to interactively explore the javascript runtime.&lt;/p&gt;
&lt;p&gt;When most folks think about javascript, they think about scripts that they embed into their web pages, but the truth is that it is a general-purpose programming language &lt;em&gt;that has absolutely nothing to do with HTML&lt;/em&gt;. In fact, the javascript runtime is so orthogonal to other web browser functionality, that mozilla offers the javascript interpreter that it uses in Firefox and friends as a &lt;a href=&quot;http://www.mozilla.org/js/spidermonkey&quot;&gt;completely separate download&lt;/a&gt;. It&apos;s available as both .deb or .rpm package, and just to show it: Here&apos;s the wonderful hello world program, as entered into the shell.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cowboyd@subzero:~$ js
js&gt; alert(&apos;hello world&apos;)
1: ReferenceError: alert is not defined
js&gt;    &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;OK, so I boobie-trapped that example in an attempt to beat the point I&apos;ve been making to death. It&apos;s an error because `alert()` isn&apos;t actually part of javascript. In the context with which we&apos;re familiar(DHTML), it&apos;s a function that&apos;s &lt;em&gt;defined by the browser&lt;/em&gt;. Of course, it just so happens that every browser implements `alert()` to behave in almost exactly the same way, but the function itself has nothing to do with the javascript core. Implementing our own version of alert is simple enough though.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;js&gt; var alert = function(message) { print(message)}
js&gt; alert(&apos;hello world&apos;)
hello world
js&gt;            &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Personally, I love the command line because it let&apos;s you dig your fingers deep into the computer&apos;s brain and, by pushing its buttons directly, see what&apos;s going to work and what isn&apos;t. Every time I have a question about how the javascript interpreter is going to behave, I don&apos;t look up the spec, or write something into my programs that I&apos;m not sure how it will work. Instead, I fire up my trusty interpreter to discover &lt;em&gt;empirically&lt;/em&gt; how the system works. Need to know if a RegExp is going to match? Don&apos;t guess. Ask the interpreter.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;js&gt; &quot;foo&quot;.match(/bar/)
null
js&gt; &quot;foo&quot;.match(/oo/)
oo
js&gt; &quot;foo&quot;.match(/oo$/)
oo
js&gt;             &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Wonder what the built-in &quot;constructor&quot; property of an object is? The runtime can tell you. It&apos;s his business after all.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;js&gt; function A() {}
js&gt; var a = new A()
js&gt; var o = new Object()
js&gt; a.constructor

function A() {
}

js&gt; o.constructor

function Object() {
    [native code]
}

js&gt; o.constructor == Object
true
js&gt; a.constructor == A
true
js&gt;                            &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Sure, you could write an in-browser script to do all this and throw output at yourself in the form of alerts, but the beauty of the javascript command line is that you can collapse the whole edit-save-reload-alert scripting cycle into a single step; type in the next line and see what happens. It&apos;s that super-tight feedback which let&apos;s you learn that much faster.&lt;/p&gt;</content:encoded></item></channel></rss>