<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Travis Fischer</title>
    <description>The latest articles on Forem by Travis Fischer (@transitivebullshit).</description>
    <link>https://forem.com/transitivebullshit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F267369%2F681505de-4258-4bb9-bec0-e2f5ecc5e39b.jpg</url>
      <title>Forem: Travis Fischer</title>
      <link>https://forem.com/transitivebullshit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/transitivebullshit"/>
    <language>en</language>
    <item>
      <title>The Absolute Best JS Dev Tools in 2022</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Mon, 11 Apr 2022 19:09:14 +0000</pubDate>
      <link>https://forem.com/transitivebullshit/the-absolute-best-js-dev-tools-in-2022-33ij</link>
      <guid>https://forem.com/transitivebullshit/the-absolute-best-js-dev-tools-in-2022-33ij</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A breakdown of the most important JS dev tools in 2022, including their most relevant tradeoffs, and some opinionated advice sprinkled on top.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the world of software engineering, it’s important to have a firm understanding of the tools at your disposal.&lt;/p&gt;

&lt;p&gt;But the landscape of JS tooling is always changing at such a rapid pace.&lt;/p&gt;

&lt;p&gt;And 2022 is no different.&lt;/p&gt;

&lt;p&gt;So I decided to break down the most important dev tools that you should be aware of in 2022.&lt;/p&gt;

&lt;p&gt;We’ll start with the lowest-level tools and work our way up to higher-level tools from there. Let’s get started 💪&lt;/p&gt;




&lt;h2&gt;
  
  
  Compilers
&lt;/h2&gt;

&lt;p&gt;Compilers are responsible for transforming your input code into some target output format. For our purposes, we’re focusing on compilers which support transpiling modern JavaScript and TypeScript into specific versions of ECMAscript that are compatible with browsers and recent versions of Node.js.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9qR94CFb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hxh8kpwbrvd8ksv9u3lp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9qR94CFb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hxh8kpwbrvd8ksv9u3lp.jpg" alt="Compilers" width="880" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most important thing to understand about this space is that it’s in the middle of undergoing a massive shift from compilers like &lt;a href="https://www.typescriptlang.org/docs/handbook/compiler-options.html"&gt;tsc&lt;/a&gt; and &lt;a href="https://babeljs.io/"&gt;babel&lt;/a&gt;, which are written in higher-level interpreted languages, to compilers like &lt;a href="https://swc.rs/"&gt;swc&lt;/a&gt; and &lt;a href="https://esbuild.github.io/"&gt;esbuild&lt;/a&gt;, which are written in much faster, compiled languages.&lt;/p&gt;

&lt;p&gt;This shift results in &lt;strong&gt;10-100x faster compilation times&lt;/strong&gt; as shown in this esbuild demo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1oQtXIc5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uq7sevdtveo5orkw9i7j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1oQtXIc5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uq7sevdtveo5orkw9i7j.png" alt="esbuild" width="880" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re updating your devtools stack or starting a new project in 2022, then you’ll want to consider using one of these next-gen compilers under the hood. They may not be as mature as the official typescript compiler or babel, but the benefits of having 100x faster builds cannot be understated.&lt;/p&gt;

&lt;p&gt;Note that neither swc nor esbuild perform type checking. They simply transpile code into the desired output format as quickly and efficiently as possible. For the time being, if you’re working with TypeScript, you’ll almost always need to have the official TypeScript compiler as part of your toolchain to guarantee that you’re getting the most out of TypeScript’s static type checking. It’s also worth mentioning that the author of swc, &lt;a href="https://twitter.com/kdy1dev"&gt;kdy1dev&lt;/a&gt; is working on &lt;a href="https://kdy1.dev/posts/2022/1/tsc-go"&gt;porting tsc to Go&lt;/a&gt; in order to remove the need for tsc in many cases, as it tends to be the bottleneck in most toolchains.&lt;/p&gt;

&lt;h3&gt;
  
  
  SWC vs esbuild
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;swc&lt;/code&gt; and &lt;code&gt;esbuild&lt;/code&gt; are both excellent, blazing fast, open source JS / TS compilers. They have &lt;a href="https://datastation.multiprocess.io/blog/2021-11-13-benchmarking-esbuild-swc-typescript-babel.html"&gt;comparable performance&lt;/a&gt; and are both used regularly in production by some of the world’s largest companies.&lt;/p&gt;

&lt;p&gt;It’s likely that your choice between the two will be dictated more by the higher-level tools built on top of these compilers as opposed to choosing between them directly.&lt;/p&gt;

&lt;p&gt;Notable projects using &lt;code&gt;swc&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/advanced-features/compiler"&gt;Vercel and Next.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/devongovett/status/1369033422002389000"&gt;Deno’s linter, formatter, and docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://parceljs.org"&gt;Parcel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nrwl/nx"&gt;nx&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notable projects using &lt;code&gt;esbuild&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vitejs.dev"&gt;Vite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nuxtjs.org"&gt;Nuxt.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/remix-run/remix"&gt;Remix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kit.svelte.dev/"&gt;SvelteKit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tsup.egoist.sh"&gt;tsup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 In software engineering, convenient statements such as “technology A is better than technology B” rarely hold much value. Rather, you should try to always keep context in mind. In this case, there are many scenarios where you’d be better off using tsc or babel.&lt;/p&gt;

&lt;p&gt;Becoming a better software engineer often boils down to thoroughly understanding the tradeoffs involved with these types of decisions, and balancing those tradeoffs against the particular constraints of your project, team, and business’ needs.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Bundlers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--osFVPp1H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0i2ibms7uttftb8j31s3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--osFVPp1H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0i2ibms7uttftb8j31s3.png" alt="Webpack" width="880" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bundlers are responsible for taking all of your input source files and bundling them together into an easy-to-consume output format. The two most common use cases for bundlers are bundling libraries and bundling resources for web applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gqFcSBJj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sojvz023lfh9izvjahjv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gqFcSBJj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sojvz023lfh9izvjahjv.jpg" alt="Bundlers" width="880" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bundlers like &lt;code&gt;webpack&lt;/code&gt; and &lt;code&gt;rollup&lt;/code&gt; are the swiss-army knives of modern JS toolchains. They are both extremely extensible, with well-maintained plugins covering major use cases. It’s relatively straightforward, for example, to use any of the popular compilers listed above to transpile TS code with either webpack or rollup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://parceljs.org"&gt;Parcel&lt;/a&gt;, on the other hand, provides a mostly zero-config approach to bundling. It focuses on simplicity as opposed to extensibility and uses &lt;code&gt;swc&lt;/code&gt; as a compiler under the hood.&lt;/p&gt;

&lt;p&gt;Note that &lt;code&gt;swc&lt;/code&gt; and &lt;code&gt;esbuild&lt;/code&gt; both provide basic bundling capabilities as well, though compared with these alternatives, they’re not full-featured enough to be included on this list.&lt;/p&gt;

&lt;p&gt;For a much more detailed comparison of these bundlers, check out &lt;a href="https://bundlers.tooling.report/"&gt;tooling.report&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Package Managers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Package_management"&gt;Package managers&lt;/a&gt; are responsible for managing dependencies in the form of &lt;a href="https://npmjs.com"&gt;NPM&lt;/a&gt; packages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6NeXKhaM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/woljrw524yqqxox34vh6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6NeXKhaM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/woljrw524yqqxox34vh6.jpg" alt="Package managers" width="880" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s a &lt;a href="https://blog.logrocket.com/javascript-package-managers-compared/"&gt;lot of history&lt;/a&gt; here, but the TL;DR is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All of these package managers have similar features and perf nowadays, so don’t be too worried about which one you’re using.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pnpm.io/"&gt;pnpm&lt;/a&gt; seems to be gaining a lot of traction very quickly. 💪&lt;/li&gt;
&lt;li&gt;The way yarn berry was rolled out and the subsequent deprecation of yarn v1 turned a lot of people off from using yarn, though yarn berry has come a long way in the past few years.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://yarnpkg.com/features/pnp"&gt;yarn plug’n’play&lt;/a&gt; is an interesting approach, but in practice, it has only seen adoption in cases with very large monorepos.

&lt;ul&gt;
&lt;li&gt;I can’t tell you the number of times I’ve wanted to inspect or add console.log statements to my &lt;code&gt;node_modules&lt;/code&gt;, and not being able to do so is a real disadvantage.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Adoption by popular projects
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RXR_mwAl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2pyo8ma1yc3uymwl53zu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RXR_mwAl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2pyo8ma1yc3uymwl53zu.png" alt="Package manager adoption" width="880" height="501"&gt;&lt;/a&gt;&lt;br&gt;
^ A breakdown of the package managers chosen by popular projects. This image is from &lt;a href="https://twitter.com/doppelmutzi"&gt;Sebastian Weber&lt;/a&gt;’s excellent &lt;a href="https://blog.logrocket.com/javascript-package-managers-compared/"&gt;package manager deep dive&lt;/a&gt;. Note that at the time of this writing, none of these projects are using Yarn PnP.&lt;/p&gt;




&lt;h2&gt;
  
  
  Library Development
&lt;/h2&gt;

&lt;p&gt;These tools are meant to help library authors bundle and publish modern NPM packages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ccg71_rH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rc8kuumw8p7zm6emr21w.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ccg71_rH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rc8kuumw8p7zm6emr21w.jpg" alt="Library development tools" width="880" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re developing a new library in 2022, you’ll likely want to use one of these higher-level tools to simplify your workflow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you have a TS package and want to take advantage of extremely fast build times courtesy of &lt;a href="https://esbuild.github.io/"&gt;esbuild&lt;/a&gt;, then &lt;a href="https://tsup.egoist.sh"&gt;tsup&lt;/a&gt; is a great option.&lt;/li&gt;
&lt;li&gt;If you have a TS package and need some additional features, then &lt;a href="https://tsdx.io"&gt;tsdx&lt;/a&gt; is a great option.&lt;/li&gt;
&lt;li&gt;If you have a TS or JS package, then &lt;a href="https://github.com/developit/microbundle"&gt;microbundle&lt;/a&gt; is also a great option.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vitejs.dev/"&gt;Vite&lt;/a&gt; is mainly a tool for building frontend web apps, but it also includes support for &lt;a href="https://vitejs.dev/guide/build.html#library-mode"&gt;outputting libraries&lt;/a&gt; and is a very solid all-around option.&lt;/li&gt;
&lt;li&gt;For monorepos, &lt;a href="https://github.com/nrwl/nx"&gt;nx&lt;/a&gt; looks really promising.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My personal preference will be to use &lt;a href="https://tsup.egoist.sh/"&gt;tsup&lt;/a&gt; for TS packages, mainly because once you’ve experienced 100x faster builds, it’s really difficult to consider switching back to anything else.&lt;/p&gt;

&lt;h3&gt;
  
  
  More Info
&lt;/h3&gt;

&lt;p&gt;Most of these tools don’t currently provide great support for TS monorepos which take advantage of &lt;a href="https://www.typescriptlang.org/docs/handbook/project-references.html"&gt;composite project references&lt;/a&gt;. For the time being, my recommendation for this case is to use &lt;code&gt;tsc&lt;/code&gt; for type checking and generating &lt;code&gt;.d.ts&lt;/code&gt; typings (with &lt;code&gt;emitDeclarationOnly: true&lt;/code&gt;) and &lt;code&gt;tsup&lt;/code&gt; for compiling code in each of the sub-packages. For an example of this approach, check out the &lt;a href="https://github.com/NotionX/react-notion-x"&gt;react-notion-x&lt;/a&gt; monorepo (one of my OSS projects).&lt;/p&gt;

&lt;p&gt;Publishing modern NPM packages is a nuanced topic that goes well beyond the scope of this article. For more info on ESM, commonjs, dual-package publishing, exports, and more see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.the-guild.dev/blog/support-nodejs-esm"&gt;What does it take to support Node.js ESM?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sindresorhus’ notes on &lt;a href="https://github.com/sindresorhus/meta/discussions/15"&gt;publishing&lt;/a&gt; and &lt;a href="https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c"&gt;consuming&lt;/a&gt; ESM packages&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Web App Development
&lt;/h2&gt;

&lt;p&gt;These higher-level tools and frameworks are intended to help developers build modern web applications without worrying about all the details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1Zjm8WsK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ie4g9qpckxdwnlvrpu59.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1Zjm8WsK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ie4g9qpckxdwnlvrpu59.jpg" alt="Web app development tools and frameworks" width="880" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re developing a new web app in 2022 using &lt;a href="https://reactjs.org"&gt;React&lt;/a&gt;, then I would highly recommend using &lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt;. It has the best support, the most active community, and close integration with &lt;a href="https://vercel.com/"&gt;Vercel&lt;/a&gt;, the world’s leading deployment platform for modern web apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://remix.run/blog/remix-vs-next"&gt;Remix&lt;/a&gt; provides a really compelling alternative to Next.js. It’s from the makers of &lt;a href="https://github.com/remix-run/react-router"&gt;react-router&lt;/a&gt;, and though it’s relatively new, they’re definitely a framework to keep an eye on.&lt;/p&gt;

&lt;p&gt;If you’re developing a new web app using &lt;a href="https://vuejs.org"&gt;Vue&lt;/a&gt;, then &lt;a href="https://nuxtjs.org/"&gt;Nuxt.js&lt;/a&gt; and &lt;a href="https://vitejs.dev"&gt;Vite&lt;/a&gt; are both great options.&lt;/p&gt;

&lt;p&gt;And last, but certainly not least, if you want something more light-weight, then give &lt;a href="https://parceljs.org"&gt;Parcel&lt;/a&gt; a try. 🤗&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 There seems to be a roughly equal number of projects building on top of &lt;code&gt;swc&lt;/code&gt; and &lt;code&gt;esbuild&lt;/code&gt;. The same observation goes for &lt;code&gt;webpack&lt;/code&gt; and &lt;code&gt;rollup&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;Modern web development has evolved significantly over the past 10 years. Developers today are lucky to have such a wide range of amazing, well-maintained tools to choose from.&lt;/p&gt;

&lt;p&gt;This is, however, by no means a comprehensive list of dev tools. If there’s something missing that you’d like to see added, let me know on &lt;a href="https://twitter.com/transitive_bs"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hopefully this breakdown has helped you parse the most important aspects of the current JS / TS dev tools landscape, and hopefully it’ll help you to make more informed decisions going forwards.&lt;/p&gt;




&lt;p&gt;If you found this article helpful, then consider following me on twitter for more &lt;a href="https://twitter.com/transitive_bs"&gt;@transitive_bs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>typescript</category>
      <category>node</category>
    </item>
    <item>
      <title>Saasify's Approach to OSS</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Thu, 26 Mar 2020 22:43:04 +0000</pubDate>
      <link>https://forem.com/transitivebullshit/saasify-s-approach-to-oss-off</link>
      <guid>https://forem.com/transitivebullshit/saasify-s-approach-to-oss-off</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I'm very proud to announce that Saasify's open source &lt;a href="https://github.com/saasify-sh/saasify"&gt;&lt;strong&gt;GitHub repo&lt;/strong&gt;&lt;/a&gt; has just hit 600 stars. ⭐&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a small but important milestone for us that has taken over a year of consistent, daily work including contributions across over a dozen related projects in the more general JS and TS communities.&lt;/p&gt;

&lt;p&gt;I'm a big believer in the power of open source and can say from experience that a lot of people underestimate the second &amp;amp; third-order effects of building a strong open source community.&lt;/p&gt;

&lt;p&gt;With all this in mind, I thought this would be the perfect time to share some general thoughts on our approach to open source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Saasify's Open Core
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QuCEmUXQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.saasify.sh/content/images/2020/03/open-core.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QuCEmUXQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.saasify.sh/content/images/2020/03/open-core.jpg" alt="" width="634" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Saasify is what's known as an &lt;a href="https://coss.media/open-core-definition-examples-tradeoffs/"&gt;open core&lt;/a&gt; company. This just means that some of our code is open source, and some of it is closed source.&lt;/p&gt;

&lt;p&gt;Our platform's codebase is split into two monorepos, one for our &lt;a href="https://github.com/saasify-sh/saasify"&gt;publicly-facing&lt;/a&gt;, MIT-licensed open source work, and one that's private, for proprietary closed source work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Saasify Open Source&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User-facing parts of the platform (e.g., our &lt;a href="https://github.com/saasify-sh/saasify/tree/master/packages/saasify-cli"&gt;Node.js CLI&lt;/a&gt;, &lt;a href="https://github.com/saasify-sh/saasify/tree/master/packages/react-saasify"&gt;React component library&lt;/a&gt;, &lt;a href="https://github.com/saasify-sh/saasify/tree/master/website"&gt;marketing website / admin webapp&lt;/a&gt;, &lt;a href="https://github.com/saasify-sh/saasify/tree/master/packages/saasify-client"&gt;JS client API&lt;/a&gt;, etc)&lt;/li&gt;
&lt;li&gt;All platform documentation (&lt;a href="https://github.com/saasify-sh/saasify/tree/master/docs"&gt;source&lt;/a&gt; and &lt;a href="https://docs.saasify.sh/"&gt;generated docs&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Lots of generally useful functionality that other open source projects and companies may benefit from (&lt;a href="https://github.com/saasify-sh/saasify/tree/master/packages/saasify-openapi-utils"&gt;OpenAPI utilities&lt;/a&gt;, &lt;a href="https://github.com/saasify-sh/saasify/tree/master/packages/saasify-faas-utils"&gt;FaaS utilities&lt;/a&gt;, &lt;a href="https://github.com/saasify-sh/saasify/tree/master/packages/saasify-badges"&gt;badge generator&lt;/a&gt; powered by headless Chrome, etc)&lt;/li&gt;
&lt;li&gt;20 or so example projects showcasing different use cases for Saasify&lt;/li&gt;
&lt;li&gt;A standalone project for &lt;a href="https://github.com/transitive-bullshit/functional-typescript"&gt;Functional TypeScript&lt;/a&gt; which transforms normal TS functions (and jsdoc-annotated JS functions) into JSON Schemas and OpenAPI specs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Saasify Closed Source&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our platform's main backend API&lt;/li&gt;
&lt;li&gt;Our API gateway for proxying FaaS requests&lt;/li&gt;
&lt;li&gt;Various serverless functions whose business logic is built on top of OSS packages from Saasify's public repo&lt;/li&gt;
&lt;li&gt;The template-based SaaS web client (most of the React components that comprise this webapp are from our open source &lt;a href="https://github.com/saasify-sh/saasify/tree/master/packages/react-saasify"&gt;react-saasify&lt;/a&gt; package)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choosing what to open source versus what to keep proprietary with the ultimate goal of building a sustainable business is a difficult balancing act, and there's no one right way to go about it. We're sharing Saasify's approach so far in the spirit of transparency and in the hope that it will help other founders make similar decisions in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Open Source Advantage
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C5djj61x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.saasify.sh/content/images/2020/03/b_upscaled_image_x4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C5djj61x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.saasify.sh/content/images/2020/03/b_upscaled_image_x4.jpg" alt="" width="880" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Working out in the open has some important, fundamental advantages over more traditional proprietary approaches.&lt;/p&gt;

&lt;p&gt;For starters, it's one thing to &lt;em&gt;claim&lt;/em&gt; that your company's transparent, has a solid platform that customers can rely on, and that customers can trust you, but it's really a different thing entirely to &lt;em&gt;show&lt;/em&gt; all of these things by putting your code where your mouth is and open sourcing much of your core platform. Having a reputable presence in the open source community is increasingly becoming a major advantage for aspiring indie hackers.&lt;/p&gt;

&lt;p&gt;Another advantage of investing time in open source is that &lt;strong&gt;it will eventually attract other talented developers&lt;/strong&gt; who want to have an understanding of what things look like under the hood before considering whether or not they'd want to work with you. If you can show publicly that your platform is reasonably clean and follows modern best practices, you'll be able to have conversations with many top developers who would otherwise not give your company a second glance.&lt;/p&gt;

&lt;p&gt;Aside from the very rare occasional viral HN post or influencer plug, &lt;strong&gt;successful open source projects tend to follow a very similar lifecycle as bootstrapped businesses&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;They both generally take a &lt;strong&gt;slow, methodical approach&lt;/strong&gt; to gaining traction and eventual success or failure can't be pinpointed to any one particular feature, strategy, or decision. It's a combination of consistent grinding, iterating based on user feedback, and ultimately persistence that separates both successful open source projects and indie products from unsuccessful ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Onwards &amp;amp; Upwards
&lt;/h3&gt;

&lt;p&gt;If there's one thing that I'd love for other startup founders and indie hackers to take from our experience so far, it's an appreciation for &lt;strong&gt;how powerful open source can be as a natural content marketing and business development strategy&lt;/strong&gt; especially for early adopters who tend to be more technically savvy.&lt;/p&gt;

&lt;p&gt;As we continue our journey towards becoming the Shopify for SaaS, we're actively looking for other developers, designers, marketers, and like-minded business people to help us reach our goals. If this type of thing gets you excited, please &lt;a href="https://docs.saasify.sh/#/support"&gt;reach out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On a related note, &lt;a href="https://coss.media/"&gt;COSS.media&lt;/a&gt; is one of my favorite resources discussing the tradeoffs and advantages of mixing open source with commercial business. If this stuff interests you, definitely check out their blog.&lt;/p&gt;

&lt;p&gt;And finally, check out our &lt;a href="https://github.com/saasify-sh/saasify"&gt;&lt;strong&gt;open source repo&lt;/strong&gt;&lt;/a&gt; for inspiration and let us know what you think. 🙏&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>startup</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Making Your Code Beautiful</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Sun, 16 Feb 2020 08:44:00 +0000</pubDate>
      <link>https://forem.com/transitivebullshit/making-your-code-beautiful-1nc3</link>
      <guid>https://forem.com/transitivebullshit/making-your-code-beautiful-1nc3</guid>
      <description>&lt;p&gt;&lt;em&gt;The best techniques for sharing code snippets and screencasts that will help propel your open source projects to success.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Creating your own open source projects can be extremely rewarding, but it can be hard to break through the noise and get other developers to trust and use your software. You can gain a lot of ground by following &lt;a href="https://opensource.guide/" rel="noopener noreferrer"&gt;common best practices&lt;/a&gt; like including solid documentation, adding unit tests, integrating with a CI/CD oriented towards open-source projects (like &lt;a href="https://travis-ci.org/" rel="noopener noreferrer"&gt;travis-ci&lt;/a&gt; or &lt;a href="https://circleci.com/" rel="noopener noreferrer"&gt;circle-ci&lt;/a&gt;), and enforcing consistent style conventions.&lt;/p&gt;

&lt;p&gt;One of the most effective and easiest ways I’ve found to make open source projects really stand out from the crowd is &lt;strong&gt;adding quality screenshots or animated demos&lt;/strong&gt;. Whenever I see this attention to detail, not only does it prove to me that the author cares about the project, but it’s the absolute fastest way to convey what the project actually does.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AKbC-gUATfgCAHLos0n-Bqg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AKbC-gUATfgCAHLos0n-Bqg.gif" alt="Making Your Code Beautiful"&gt;&lt;/a&gt;&lt;/p&gt;
Animation Credit: &lt;a href="http://chrisdermody.com/css-only-coding-animation/" rel="noopener noreferrer"&gt;CSS-only coding animation&lt;/a&gt; by &lt;a href="http://chrisdermody.com/" rel="noopener noreferrer"&gt;Chris Dermody&lt;/a&gt;



&lt;p&gt;Including quality screenshots and demos is becoming an increasingly important part of what I’d call &lt;strong&gt;Developer UX&lt;/strong&gt; , that is the flow a prospective developer takes from considering adding your project as a dependency all the way through successful integration and future maintenance.&lt;/p&gt;

&lt;p&gt;Towards that end, we’ll be looking at three common use cases for improving the developer UX of your open source projects with media:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static code snippets (images)&lt;/li&gt;
&lt;li&gt;Animated code demos (GIFs or animated SVGs)&lt;/li&gt;
&lt;li&gt;Project screencasts (videos)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Static Code Snippets
&lt;/h3&gt;

&lt;p&gt;Sharing small bits of static code is definitely the most common and important use case on this list. Every open source project’s readme should include some easily parseable &lt;em&gt;example usage&lt;/em&gt; snippet, so let’s start there.&lt;/p&gt;

&lt;h4&gt;
  
  
  GitHub-Flavored Markdown Snippets
&lt;/h4&gt;

&lt;p&gt;At the easiest end of the spectrum, GitHub allows &lt;a href="https://guides.github.com/features/mastering-markdown/" rel="noopener noreferrer"&gt;syntax highlighting&lt;/a&gt; in markdown code snippets. Hopefully, this style of embedding is familiar to you, and if not, I would definitely recommend starting here.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
Javascript snippet embedded in markdown from one of my favorite npm modules, &lt;a href="https://github.com/sindresorhus/p-map" rel="noopener noreferrer"&gt;p-map&lt;/a&gt; by &lt;a href="https://sindresorhus.com/" rel="noopener noreferrer"&gt;sindresorhus&lt;/a&gt;.




&lt;h4&gt;
  
  
  GitHub Gists
&lt;/h4&gt;

&lt;p&gt;The code snippet above also provides an example of an extremely popular way of sharing static code snippets via &lt;a href="https://help.github.com/articles/about-gists/" rel="noopener noreferrer"&gt;GitHub Gists&lt;/a&gt;, which have the following advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linkable&lt;/li&gt;
&lt;li&gt;Support versioning&lt;/li&gt;
&lt;li&gt;Support discussion via comments&lt;/li&gt;
&lt;li&gt;Syntax highlighting&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Carbon
&lt;/h4&gt;

&lt;p&gt;Markdown snippets and GitHub gists are both useful, but if you really want to make your code pop, then look no further than &lt;a href="https://github.com/dawnlabs/carbon" rel="noopener noreferrer"&gt;Carbon&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AVNf1MPtmigHEoO1yo-bvuQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AVNf1MPtmigHEoO1yo-bvuQ.png" alt="Making Your Code Beautiful"&gt;&lt;/a&gt;&lt;/p&gt;
Image Credit: &lt;a href="https://github.com/dawnlabs/carbon" rel="noopener noreferrer"&gt;Carbon&lt;/a&gt;



&lt;p&gt;Carbon is a very popular open source project that allows you to easily create aesthetically pleasing code screenshots, along with a plethora of customization options and community plugins. It’s a great choice for making a hero image stand out in your readme, increasing engagement on social media, or for writing engineering-related blog posts like this one 😛.&lt;/p&gt;

&lt;h3&gt;
  
  
  Animated Code Demos
&lt;/h3&gt;

&lt;p&gt;Including a high quality, inline demo that quickly demonstrates your project’s core use case is the single most important suggestion I have to give.&lt;/p&gt;

&lt;p&gt;There are a ton of different ways to go about creating these types of demos, however, so I’d like to discuss what I’ve found to be the best approach here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://asciinema.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Asciinema&lt;/strong&gt;&lt;/a&gt; is a free tool that lets you record and share your terminal sessions, the right way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://asciinema.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Asciinema&lt;/strong&gt;&lt;/a&gt; provides a lightweight, purely text-based approach to terminal recording, which allows you to make lossless recordings that can then be shared directly or rendered to animated SVG, animated GIF, or video. It surprised me just how many popular open source projects on GitHub make use of Asciinema — I would highly recommend checking it out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A6XX4DHE0HSHrGjiLFxmigQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A6XX4DHE0HSHrGjiLFxmigQ.gif" alt="Making Your Code Beautiful"&gt;&lt;/a&gt;&lt;/p&gt;
Example Asciinema screencast converted to a GIF (credit: &lt;a href="https://github.com/transitive-bullshit/create-react-library" rel="noopener noreferrer"&gt;create-react-library&lt;/a&gt;) Note that the quality of this embedded GIF is much lower than the animated SVG in the linked &lt;a href="https://github.com/transitive-bullshit/create-react-library" rel="noopener noreferrer"&gt;readme&lt;/a&gt; as discussed below.



&lt;h4&gt;
  
  
  Animated SVG or GIFs?
&lt;/h4&gt;

&lt;p&gt;We all know GIFs are a horribly inefficient, lossy format, but let’s dig a little deeper into this particular use case.&lt;/p&gt;

&lt;p&gt;Compare the above embedded screencast gif to the animated SVG of the same screencast from the &lt;a href="https://github.com/transitive-bullshit/create-react-library" rel="noopener noreferrer"&gt;readme&lt;/a&gt;. It’s difficult to embed an inline comparison side-by-side, but the animated SVG is &lt;strong&gt;significantly sharper and smaller&lt;/strong&gt; , coming in at 73kb vs 4.4MB for the lower quality GIF.&lt;/p&gt;

&lt;p&gt;Why is this even a discussion then? Well, you can’t exactly include custom HTML everywhere on the web, now can you? Unfortunately for the foreseeable future, GIFs will live on as a necessary evil for these use cases. But open source authors, please consider using animated SVG versus GIFs for your GitHub projects!&lt;/p&gt;

&lt;p&gt;There are some very popular open source projects on GitHub that have started using more efficient animated SVGs for their demos, such as &lt;a href="https://github.com/facebook/create-react-app" rel="noopener noreferrer"&gt;create-react-app&lt;/a&gt;, but in general, you’ll find GIFs to be much more common.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
Examples of using the excellent &lt;a href="https://github.com/marionebl/svg-term-cli" rel="noopener noreferrer"&gt;svg-term-cli&lt;/a&gt; to generate our lossless animated SVG.




&lt;p&gt;It’s important to note that when discussing animated SVGs, we’re really talking about embedding an HTML snippet into GitHub-flavored markdown that links to an SVG file encoded with each frame as an SVG group and the animation defined via CSS keyframes (example SVG &lt;a href="https://raw.githubusercontent.com/transitive-bullshit/create-react-library/master/media/demo.svg" rel="noopener noreferrer"&gt;source&lt;/a&gt;).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
Insert this HTML snippet into any GitHub-flavored markdown file to embed the linked animated SVG with optimal sharpness and low size overhead compared with a comparable GIF.




&lt;p&gt;For reference, here is the screencast from &lt;a href="https://github.com/transitive-bullshit/create-react-library" rel="noopener noreferrer"&gt;create-react-library&lt;/a&gt; we’ve been using as an example in several different formats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Original &lt;a href="https://asciinema.org/a/167645" rel="noopener noreferrer"&gt;asciicast&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;High quality &lt;a href="https://camo.githubusercontent.com/3f38f2bacbc1a6b49a5172232e8a4ccb9f10173f/68747470733a2f2f63646e2e7261776769742e636f6d2f7472616e7369746976652d62756c6c736869742f6372656174652d72656163742d6c6962726172792f6d61737465722f6d656469612f64656d6f2e737667" rel="noopener noreferrer"&gt;animated SVG&lt;/a&gt; created with &lt;a href="https://github.com/marionebl/svg-term-cli" rel="noopener noreferrer"&gt;svg-term-cli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Low quality &lt;a href="https://cdn-images-1.medium.com/max/1600/1*6XX4DHE0HSHrGjiLFxmigQ.gif" rel="noopener noreferrer"&gt;GIF&lt;/a&gt; created with &lt;a href="https://github.com/asciinema/asciicast2gif" rel="noopener noreferrer"&gt;asciicast2gif&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Capturing and Optimizing GIFs
&lt;/h4&gt;

&lt;p&gt;Asciinema is great for terminal-based recording, but what if you want to record a UI component or website? Well, my first and foremost answer here is to always include a usable demo if possible alongside your project, especially if it’s a frontend web project. It’s really easy to get started with GitHub &lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;Page’s&lt;/a&gt; free hosting!&lt;/p&gt;

&lt;p&gt;If you do want to include a GIF, I’d recommend using either &lt;a href="https://giphy.com/apps/giphycapture" rel="noopener noreferrer"&gt;GIPHY Capture&lt;/a&gt; or &lt;a href="https://getkap.co/" rel="noopener noreferrer"&gt;Kap&lt;/a&gt; to record your screen and output a GIF. Alternatively, if you have a video recorded from another source, I’d recommend using &lt;a href="https://github.com/sindresorhus/gifski-app" rel="noopener noreferrer"&gt;Gifski&lt;/a&gt; to convert the video to an as-optimized-as-possible GIF for ease of embedding.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
Example of embedding a GIF into GitHub-flavored markdown files. (see the resulting gif below)




&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2Ack6cRbbe3uaelEG2JPsIMw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2Ack6cRbbe3uaelEG2JPsIMw.gif" alt="Making Your Code Beautiful"&gt;&lt;/a&gt;&lt;/p&gt;
Quality demo GIF embedded in readme using the snippet above. (image credit: &lt;a href="https://github.com/terkelg/prompts" rel="noopener noreferrer"&gt;prompts&lt;/a&gt; by &lt;a href="https://github.com/terkelg" rel="noopener noreferrer"&gt;terkelg&lt;/a&gt;)



&lt;h3&gt;
  
  
  Project Screencasts
&lt;/h3&gt;

&lt;p&gt;If your project is becoming more involved or you’re launching your project to a wider audience, including walkthrough video(s) can really help with user onboarding and support.&lt;/p&gt;

&lt;h4&gt;
  
  
  Screenflow
&lt;/h4&gt;

&lt;p&gt;My go-to screen recording software is &lt;a href="https://www.telestream.net/screenflow/overview.htm" rel="noopener noreferrer"&gt;ScreenFlow&lt;/a&gt;, which is not cheap at $129, but gives you a lot of powerful, quality tools for the price, including precise rectangular screen recording, video and audio track mixing, audio voiceovers, transition effects, and more. This type of screencast is quite a bit more complicated than the screenshots and terminal session recordings we were looking at earlier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Developer UX is important for promoting and marketing your work, which can in turn lead to very real consequences, as getting noticed for your open source contributions is definitely one of the best ways to gain notoriety and land big job opportunities as a software engineer.&lt;/p&gt;

&lt;p&gt;I hope some of the techniques I’ve covered help you to promote your open source projects. If you’ve found this article useful and end up creating a snazzy screenshot or animated demo, add a comment linking to your project and let me know!&lt;/p&gt;

&lt;p&gt;And as always, don’t forget to spread the ❤️… in the form of beautiful coding demos, of course!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>npm</category>
    </item>
    <item>
      <title>Gaming CS Interviews</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Tue, 04 Feb 2020 01:18:00 +0000</pubDate>
      <link>https://forem.com/transitivebullshit/gaming-cs-interviews-c37</link>
      <guid>https://forem.com/transitivebullshit/gaming-cs-interviews-c37</guid>
      <description>&lt;p&gt;&lt;em&gt;Tips for Kicking Ass at Whiteboard Interviews for Non-CS Peeps.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let me start by saying that &lt;a href="https://github.com/poteto/hiring-without-whiteboards" rel="noopener noreferrer"&gt;many companies in the tech industry&lt;/a&gt; have started &lt;a href="https://techcrunch.com/2013/06/22/the-technical-interview-is-dead/" rel="noopener noreferrer"&gt;moving away from&lt;/a&gt; traditional, technical whiteboard interviews, myself included, because they tend to bare little relevance to an employee’s day-to-day development work. Most companies are better off focusing on testing &lt;a href="https://hired.com/blog/employers/whiteboard-interview-alternatives/" rel="noopener noreferrer"&gt;practical skills and the ability to deliver&lt;/a&gt; as opposed to algorithmic, computer science questions, and that’s coming from someone who genuinely loves those types of questions. There are exceptions to this, of course, but I believe most engineering jobs today fall into this category.&lt;/p&gt;

&lt;p&gt;With that being said, the largest and most esteemed tech companies such as &lt;strong&gt;Google, Facebook, Amazon, Microsoft&lt;/strong&gt; , etc. all still employ very similar technical interview loops that &lt;em&gt;tend to greatly favor candidates with standard computer science backgrounds over candidates who are either self-taught&lt;/em&gt; or who prefer to focus on software engineering over the “science” aspect of computer science.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.&lt;/p&gt;

&lt;p&gt;— Max Howell (&lt;a class="mentioned-user" href="https://dev.to/mxcl"&gt;@mxcl&lt;/a&gt;) &lt;a href="https://twitter.com/mxcl/status/608682016205344768?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;June 10, 2015&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Regardless of your views on whether or not this process is fair or optimal, I have a lot of friends who fall into this latter category of being self-taught or software-engineering heavy and scoff at the thought of interviewing with one of these bigger players, even though I know from experience that they would fit in just fine once they made it past the interviews. Given that these are also some of the better, more passionate devs I’ve had the pleasure of working with, I wanted to share some no-bullshit advice I’ve accumulated over the years in the hopes of encouraging other engineers out there to consider advancing their careers by spending time at one or more of the bigger tech companies.&lt;/p&gt;

&lt;p&gt;I sincerely believe that most developers who are proficient at developing code in their language of choice are capable of passing a Google-style interview loop by adopting the right mindset and studying a few key topics and question archetypes ahead of time.&lt;/p&gt;

&lt;p&gt;So, with that goal in mind, let’s dive into that whiteboard…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AZPn6I2GD84VDKdGXMmASSQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AZPn6I2GD84VDKdGXMmASSQ.jpeg" alt="Gaming CS Interviews"&gt;&lt;/a&gt;Here’s a picture of a generic whiteboard… because it’s on topic and not at all redundant…&lt;/p&gt;

&lt;h3&gt;
  
  
  General Tips
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;When given a programming problem, never start coding right away&lt;/strong&gt;. Always talk through the problem, by first verifying that your assumptions and thought processes are on the right track.&lt;/p&gt;

&lt;p&gt;I highly recommend trying to get comfortable verbalizing your thought process at all times but especially when you’re not sure how to proceed. Oftentimes, the interviewer cares more about your thought process than the solution and/or will give you guidance according to your thoughts. Guidance is expected; a great interview should be more of a conversation than a one-sided question and one-sided answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generally start out with the most naive, straight-forward approach to a problem&lt;/strong&gt; you can think of, even if you think it’s really inefficient. &lt;strong&gt;Verbalize your thought process in doing so&lt;/strong&gt;, and either the interviewer will say that's great and you can start coding, or you’ll get confirmation that they want to dig deeper into a more optimal solution which generally leads to a conversation about where the most inefficient part of the algorithm is (like the innermost loop) and how you could potentially mitigate its runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Always use the programming language you’re most comfortable with&lt;/strong&gt;; never use a “harder” language because you think it will make you look more legit.&lt;/p&gt;

&lt;p&gt;At the end of the interview, &lt;strong&gt;your assessment will be highly subjective, so keep that in mind and try to have some fun and cold read the interviewer to play off of his or her interests&lt;/strong&gt;. Almost always asking them early on about what they do at company X will help you understand the type of person they are and also helps to put them in a good mood because people love to talk about themselves. For instance, I recently interviewed with a developer who works on a compiler team at company X which adjusted the way I approached certain parts of the conversation to be more low-level and joke at one point about something all compiler peeps can relate to. If they like you as a person, they’ll be more lenient in their assessment whether they’re aware of it or not; that’s just human nature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2400%2F1%2AqgyBgEnzcEkjmuA4rm_ukA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2400%2F1%2AqgyBgEnzcEkjmuA4rm_ukA.png" alt="Gaming CS Interviews"&gt;&lt;/a&gt;Credit: &lt;a href="https://xkcd.com/1293/" rel="noopener noreferrer"&gt;xkcd&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Interview Topics
&lt;/h3&gt;

&lt;p&gt;There are some very common archetypes in algorithmic interviews that tend to account for the vast majority of questions you’ll encounter.&lt;/p&gt;

&lt;p&gt;If you understand these core question types and can solve some example problems from each of them, you’ll have a much better eye for solving similar problems during a real interview and subsequently solving real problems on the job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Algorithmic Complexity
&lt;/h3&gt;

&lt;p&gt;This topic boils down to understanding &lt;a href="http://bigocheatsheet.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;big-O notation&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;.&lt;/strong&gt; Even though there are other, more rare measures of complexity (like little-o, theta…) and topics like NP completeness, &lt;em&gt;I&lt;/em&gt; &lt;em&gt;would recommend skimming them&lt;/em&gt;, as they’re unlikely to appear in a typical technical interview.&lt;/p&gt;

&lt;p&gt;For almost every problem you’re asked to solve in an interview, you’ll either be asked explicitly about the big-O runtime of a proposed solution or be implicitly expected to bring it up during your discussion.&lt;/p&gt;

&lt;p&gt;This part can definitely be gamed somewhat by just practicing a bit on a representative set of problems ahead of time. You’ll both get the hang of it and also generally be able to fairly easily say that problem X looks like problem Y so they’re likely to have similar runtimes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/ofqccIX7HcjPG/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/ofqccIX7HcjPG/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;
I love how they portray algorithms in movies, don’t you? (Credit: &lt;a href="https://www.imdb.com/title/tt1843866/" rel="noopener noreferrer"&gt;The Winter Soldier&lt;/a&gt;, 2014)



&lt;p&gt;Note that with big-O complexity, it’s most common to think about the problem in terms of &lt;em&gt;runtime&lt;/em&gt;, but it can also come into play in terms of &lt;em&gt;space&lt;/em&gt; storage. For example, a sorting algorithm may take &lt;code&gt;O(n log(n))&lt;/code&gt; runtime which is pretty common but be able to operate on an array in-place, only requiring &lt;code&gt;O(n)&lt;/code&gt; storage. Sometimes this can be an important factor when considering between alternative approaches or an interviewer will add that you are memory-bound or something.&lt;/p&gt;

&lt;p&gt;I recommend reviewing and understanding the big-O runtime of the most common data structure operations, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add / remove / get / find from an &lt;strong&gt;array&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;add / remove / find from a &lt;strong&gt;linked list&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;add / remove / peek from a &lt;strong&gt;stack&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;add / remove / peek from a &lt;strong&gt;queue&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;add / remove / get from a &lt;strong&gt;hashmap&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;add / remove / get from a &lt;strong&gt;balanced binary tree&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;add / remove / get from a &lt;strong&gt;heap&lt;/strong&gt; (though heaps are less common…)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should be intimately familiar with the runtime of each of these operations, since many algorithms will use these as building blocks. It is extremely worth it to not only &lt;a href="http://bigocheatsheet.com/" rel="noopener noreferrer"&gt;memorize these runtimes&lt;/a&gt;, but to have a solid understanding of how they are derived.&lt;/p&gt;

&lt;p&gt;This topic can be difficult to grasp under different circumstances for even the most qualified candidates, so don’t worry if you’re able to come up with a solution but have trouble fleshing out its runtime. Also note that this is one of the easiest topics to “game” by practicing on examples ahead of time.&lt;/p&gt;

&lt;p&gt;Understanding Big-O complexity will affect your ability to answer interview questions on all of the following topics, which is why it is the single most important base topic to focus on before proceeding.&lt;/p&gt;

&lt;p&gt;One common subtopic I would recommend having a basic familiarity with is &lt;em&gt;amortized&lt;/em&gt; big-O, aka &lt;em&gt;expected&lt;/em&gt; big-O, whereby you use some neat probability theory to say that the &lt;em&gt;expected value&lt;/em&gt; of an operation is, for instance, &lt;code&gt;O(1)&lt;/code&gt; even though sometimes it may be &lt;code&gt;O(n)&lt;/code&gt; for individual calls. The most common examples of amortized / expected big-O in practice are hashmap lookups being amortized &lt;code&gt;O(1)&lt;/code&gt; and quicksort being amortized &lt;code&gt;O(n log(n))&lt;/code&gt;. In Javascript, for instance, all object lookups such as &lt;code&gt;myObject.foo&lt;/code&gt; or &lt;code&gt;window.document&lt;/code&gt; are amortized &lt;code&gt;O(1)&lt;/code&gt; hashmap lookups (aside from special cases where the compiler is able to optimize these operations under the hood).&lt;/p&gt;

&lt;h3&gt;
  
  
  Graphs and Trees
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AAWSQKpkJ2KJRba_069a8bw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AAWSQKpkJ2KJRba_069a8bw.png" alt="Gaming CS Interviews"&gt;&lt;/a&gt;Example graph composed of nodes and edges.&lt;/p&gt;

&lt;p&gt;Graphs are one area where there is a &lt;em&gt;lot&lt;/em&gt; of potential complexity and bullshit to wade through, but at the end of the day, almost all graph-related interview questions are really pretty simple once you understand the basics. &lt;em&gt;It can just be overwhelming sometimes when you’re not sure what “the basics” are&lt;/em&gt; and you’re trying to understand something like Dijkstra's algorithm which is definitely beyond the scope of what most interviews will delve into.&lt;/p&gt;

&lt;h4&gt;
  
  
  Terminology
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;A graph is a set of nodes and edges between some of those nodes. Nodes and edges often have payloads like a label or weight associated with them.&lt;/li&gt;
&lt;li&gt;The most common graph distinction is between undirected vs directed graphs. E.g., when you have an edge between two nodes, is it a directed, one-way street, or is an undirected, two-way street where you can go in both directions when going from node to node.&lt;/li&gt;
&lt;li&gt;A tree is a very common type of graph with some interesting constraints, so anything you learn about graphs in general also applies to trees like binary search trees and the DOM.&lt;/li&gt;
&lt;li&gt;Traversing a graph is the process of visiting nodes in a graph, usually starting from a root node and expanding out from there &lt;em&gt;recursively&lt;/em&gt; based on each node’s neighbors.&lt;/li&gt;
&lt;li&gt;The two main algorithms to understand w.r.t. graphs that &lt;strong&gt;95% of graph questions boil down to, are breadth-first-search (BFS), and depth-first-search (DFS)&lt;/strong&gt;, visualized briefly below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A8RXunYj5Wqw74yTUK237NQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A8RXunYj5Wqw74yTUK237NQ.gif" alt="Gaming CS Interviews"&gt;&lt;/a&gt;BFS vs DFS visualization (credit: &lt;a href="https://github.com/kdn251/interviews" rel="nofollow noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://github.com/kdn251/interviews" rel="noopener noreferrer"&gt;https://github.com/kdn251/interviews&lt;/a&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  Advice
&lt;/h4&gt;

&lt;p&gt;When working with graphs, it can be especially useful to visualize them by drawing examples on a whiteboard, which is one of the only good uses I can think of for a whiteboard during a generic technical interview...&lt;/p&gt;

&lt;p&gt;There are lots of different types of graphs and specializations that you may come across during studying, but their distinctions are rarely important for interviews.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AFbQdXuD2apR-AsZD1PVsfw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AFbQdXuD2apR-AsZD1PVsfw.jpeg" alt="Gaming CS Interviews"&gt;&lt;/a&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction" rel="noopener noreferrer"&gt;Document Object Model&lt;/a&gt; (DOM) is an important example of a common graph used by many frontend developers.&lt;/p&gt;

&lt;p&gt;You should be very comfortable coding BFS and DFS from scratch. Even if the question isn’t directly “code BFS”, lots of questions will indirectly involve you traversing a graph starting from a given node of interest and making sure you’re not visiting nodes multiple times which is exactly what BFS/DFS excel at.&lt;/p&gt;

&lt;p&gt;Notice how interchangeably I use BFS/DFS; they are very slight variations on each other and most of the time it doesn’t matter if you use BFS or DFS, but you should still understand the difference between the two and be able to draw example traversals on a whiteboard.&lt;/p&gt;

&lt;p&gt;BFS and DFS can both be implemented iteratively or recursively (any so-called “tail-recursive” function can be rewritten iteratively). The recursive mindset is much more powerful so I’d focus your efforts there first.&lt;/p&gt;

&lt;p&gt;Most of the time, it’s totally up to you in terms of how you define the graph you’ll be working with. For example, here is a very succinct way of representing a graph by defining a single &lt;code&gt;Node&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;Node-centric example graph representation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A common distinction with graphs is whether the data structure you use is “node-centric” or “graph-centric”. The previous &lt;code&gt;Node&lt;/code&gt; definition is node-centric because each node is smart and encapsulates information about its adjacent edges. Here’s an alternative graph-centric example, where we also use integers to represent nodes:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
Graph-centric example graph representation.




&lt;p&gt;Example question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Given a graph where nodes represent major US cities and edges represent flights between those cities, write a function that takes in two cities and returns a valid flight path between those two cities or null if no such flight path exists.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;The most direct solution to this problem uses DFS.&lt;/li&gt;
&lt;li&gt;A harder variant of this type of question would be to find the &lt;em&gt;shortest&lt;/em&gt; path if each edge (flight) had a number associated with it that represented distance, which is where Djikstra’s algorithm would come into play.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2Aq5J9uG5jEGCI3po2Vx-eew.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2Aq5J9uG5jEGCI3po2Vx-eew.gif" alt="Gaming CS Interviews"&gt;&lt;/a&gt;&lt;/p&gt;
Graph visualization of flights between major US cities (credit: &lt;a href="https://databricks.com/blog/2016/03/16/on-time-flight-performance-with-graphframes-for-apache-spark.html" rel="noopener noreferrer"&gt;databricks&lt;/a&gt;).



&lt;h3&gt;
  
  
  Sorting
&lt;/h3&gt;

&lt;p&gt;Sorting numbers, strings, etc. is a very common sub-problem in solving many interview questions. It won’t be common for an interviewer to ask you to write mergesort or quicksort or any other type of sort, but it will be quite common to either have to sort some part of your input as a piece of the puzzle or have the solution very closely resemble a widely-known sorting algorithm. For this reason, it’s useful to &lt;a href="https://www.toptal.com/developers/sorting-algorithms" rel="noopener noreferrer"&gt;review&lt;/a&gt; and be able to code the most common ones.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
Note: please don’t take this algorithm seriously. (Credit: &lt;a href="https://www.reddit.com/r/ProgrammerHumor/comments/5w9pnz/new_ultra_fast_sorting_algorithm/" rel="noopener noreferrer"&gt;Reddit&lt;/a&gt;)



&lt;h4&gt;
  
  
  Common Sorting Algorithms
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mergesort&lt;/strong&gt; ; in particular, its recursive “divide &amp;amp; conquer” approach comes up often. &lt;code&gt;O(n log(n))&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quicksort&lt;/strong&gt; ; generally considered the most robust, general-purpose sorting algorithm. generally amortized &lt;code&gt;O(n log(n))&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Radixsort&lt;/strong&gt; ; only works on numbers using bit hacks but is significantly more efficient. &lt;code&gt;O(n)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Radix sort is too advanced to implement in any interview that’s not from Hell, so don’t worry about its internals, but it can come in handy knowing that it exists and being able to make use of it.&lt;/p&gt;

&lt;p&gt;Example question:&lt;/p&gt;

&lt;p&gt;&amp;gt; &lt;em&gt;Given an array of integers, write a function that will remove all duplicates. Be sure to add the obligatory followup, what is its runtime?&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The “aha” moment here comes if you realize that by sorting the input, you can just walk along the array with all duplicates being next to each other, resulting in an efficient solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Strings
&lt;/h3&gt;

&lt;p&gt;Review string primitive operations in your preferred language. Eg., for javascript, &lt;code&gt;slice&lt;/code&gt;, &lt;code&gt;substr&lt;/code&gt;, &lt;code&gt;substring&lt;/code&gt;, &lt;code&gt;toLowerCase&lt;/code&gt;, &lt;code&gt;toUpperCase&lt;/code&gt;, &lt;code&gt;charAt&lt;/code&gt;, and very basic regex stuff using &lt;code&gt;match&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AFYDEnkzmY_z8bhyBaepn_w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AFYDEnkzmY_z8bhyBaepn_w.jpeg" alt="Gaming CS Interviews"&gt;&lt;/a&gt;&lt;/p&gt;
Luckily, most interview questions focus on ascii.



&lt;h4&gt;
  
  
  Notes
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Strings are just arrays of characters, so any algorithms you learn for arrays also applies to strings.&lt;/li&gt;
&lt;li&gt;A very common type of string problem involves finding all possible substrings of a given input string.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Given a password string of length n as input and a mapping from all 26 lowercase characters to possible alternates (like “e” maps to [“e”, “E”, “3”]), implement a function that returns all possible password combinations you could generate of length n.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;For example, “haxor” could be “Haxor”, “hax0r”, “HAX0r”, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Recursion
&lt;/h3&gt;

&lt;p&gt;Writing recursive functions should flow like bread &amp;amp; butter and has a lot of overlap with all the other topics listed here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A88wP0oLqg-FMO3uwRihQOA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A88wP0oLqg-FMO3uwRihQOA.jpeg" alt="Gaming CS Interviews"&gt;&lt;/a&gt;Credit: The Internets&lt;/p&gt;

&lt;p&gt;Example question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Implement a function that will return the nth number in the fibonacci sequence (1, 1, 2, 3, 5, 8, 13, …).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;A common follow-up is that the straight-forward solution is typically pretty inefficient, so how could you optimize the recursion?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Given a binary tree, implement a “visitor” pattern function that takes in a node and visits all children. Implement prefix, infix, and postfix traversals.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;The difference in the traversal order is just moving the order you visit the “current” node around, either before the children, after the left child, or after the right child.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Given a simplified DOM node defined as:&lt;/em&gt; &lt;code&gt;class Node { string className; Array&amp;lt;Node&amp;gt; children; }&lt;/code&gt;&lt;em&gt;, write a function that takes in a&lt;/em&gt; &lt;code&gt;Node&lt;/code&gt; &lt;em&gt;along with a target css class and returns a list of all subnodes which match that CSS class.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Aside from the traversal, which you’ll likely do recursively, the logic to visit each node needs to take into account the fact that DOM nodes can have multiple classnames, so it’s not enough just to do a direct comparison between the target CSS class and a Node’s &lt;code&gt;className&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This is exactly what the built-in function &lt;code&gt;getElementsByClassName&lt;/code&gt; does.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Brainteasers (Abstract Shit)
&lt;/h3&gt;

&lt;p&gt;Brainteasers aren’t as common as they used to be, and these types of questions are more common for PMs (project / program managers), but they still come up occasionally in developer interviews as well.&lt;/p&gt;

&lt;p&gt;They typically involve asking you to solve some impossible or outlandishly difficult problem, epitomizing the mantra that your thought process is more important than the solution you come up with.&lt;/p&gt;

&lt;p&gt;One of the most famous examples comes from Google back in the day asking candidates “How would you move Mt. Fuji?”&lt;/p&gt;

&lt;h4&gt;
  
  
  Advice
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Realize that the goal isn’t to come up with the best possible solution, but rather a reasonable, viable solution that is backed by reasoning.&lt;/li&gt;
&lt;li&gt;Ask clarifying questions; “Where are we moving Mt. Fuji to?”, “What resources do we have to accomplish the task?”, etc.&lt;/li&gt;
&lt;li&gt;One common subset of brainteasers is to ask “How many X exist?” such as “How many gas stations are there in the US?”&lt;/li&gt;
&lt;li&gt;The goal here is to be able to guesstimate some numbers that give an idea of the order of magnitude of the response, so if we estimate that there are 10 gas stations per town and 2000 towns per state and 50 states, … which should be more than enough to get the ball rolling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Less Common Topics
&lt;/h3&gt;

&lt;p&gt;These topics aren’t as common as the core algorithm and data structure topics above, but depending on the position you’re applying for, it’s still a good idea to understand the high-level categories and be able to recognize a certain type of question when you encounter it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Concurrency&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;More generic data structures&lt;/li&gt;
&lt;li&gt;Dynamic programming&lt;/li&gt;
&lt;li&gt;Architecture&lt;/li&gt;
&lt;li&gt;And sooooo many more…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A6rnI9P6h2P863Fqemky7Fw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A6rnI9P6h2P863Fqemky7Fw.jpeg" alt="Gaming CS Interviews"&gt;&lt;/a&gt;&lt;/p&gt;
Image Credit: &lt;a href="https://github.com/jwasham/coding-interview-university" rel="noopener noreferrer"&gt;Coding Interview University&lt;/a&gt; and &lt;a href="http://www.hbo.com/silicon-valley" rel="noopener noreferrer"&gt;Silicon Valley&lt;/a&gt;



&lt;h3&gt;
  
  
  Where To Go From Here?
&lt;/h3&gt;

&lt;p&gt;The purpose of this post is to serve as a jumping off point to focus your interview prep on a few, core topics. Once you’re ready to dive into more detail, here are some great resources that’ll help you flesh out a better understanding of these core concepts with a focus on practical interview training.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jwasham/coding-interview-university#graphs" rel="noopener noreferrer"&gt;Coding Interview University&lt;/a&gt; is one of the most starred repos on Github and for good reason. It aggregates articles, classes, videos, and other learning resources across a large number of topics relevant to CS interviews. My only word of warning is that it is pretty overwhelming and covers a lot more areas than are really necessary for standard technical interviews. Nonetheless, this is the first place I would recommend going to learn or review any of the topics I’ve outlined in this post.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.hiredintech.com/" rel="noopener noreferrer"&gt;Hired in Tech&lt;/a&gt; is an amazing, well-organized resource which covers a lot of useful high-level techniques as well as specific examples. I would thoroughly recommend checking it out.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/yangshun/tech-interview-handbook" rel="noopener noreferrer"&gt;Tech Interview Handbook&lt;/a&gt; is a great resource that, in addition to covering a lot of CS material itself, also gives more practical tips for what to expect and how to approach technical interview loops.&lt;/p&gt;

&lt;p&gt;Once you’re comfortable with the core CS concepts I’ve outlined here, I’d recommend spending most of your prep time practicing online coding problems. Just remember while practicing to consider how you’d verbalize your thought process in a real interview setting and remember to consider things like big-O in addition to solving the problems themselves. Here are some of my favorite resources for finding quality practice interview questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/donnemartin/interactive-coding-challenges" rel="noopener noreferrer"&gt;Interactive Coding Challenges&lt;/a&gt; — Lists a large number of interactive practice questions, many of which come with solutions and explanations.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.interviewcake.com/google-interview-questions" rel="noopener noreferrer"&gt;Google Interview Questions&lt;/a&gt; — Great list of interview questions previously used by Google provided by Interview Cake.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/jwasham/coding-interview-university#coding-exerciseschallenges" rel="noopener noreferrer"&gt;Coding Interview University&lt;/a&gt; — Their section on coding exercises / challenges is a great meta-list of additional resources to find practice questions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, the best way to get more comfortable with interviewing is by actually interviewing. I know this sounds obvious, but one concrete piece of advice I can give is to apply anywhere and everywhere, even to companies you wouldn’t necessarily consider working for, with the tacit goal of gaining valuable experience in real-world interviews and the added benefit of possibly finding opportunities you didn’t know existed beforehand.&lt;/p&gt;

&lt;p&gt;For example, if you’re interested in working for Google / Facebook / Twitter / etc, but you wouldn’t be too keen on working for Oracle &amp;amp; IBM (strictly for example purposes…), I’d encourage you to still apply to them in order to gain practical experience and get more comfortable with interviewing. This is the absolute best way I know of to hone your skills in real-world settings that are going to be fairly comparable to interview loops at the more prestigious tech companies.&lt;/p&gt;

&lt;p&gt;❤️ Travis&lt;/p&gt;

&lt;p&gt;Before you go, if you found this article useful, I'd love it if you checked out my latest &lt;a href="https://github.com/saasify-sh/saasify" rel="noopener noreferrer"&gt;project on GitHub&lt;/a&gt;. Thanks!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>javascript</category>
      <category>interview</category>
      <category>career</category>
    </item>
    <item>
      <title>JavaScript Modules Worth Using 🔥</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Sun, 02 Feb 2020 18:25:00 +0000</pubDate>
      <link>https://forem.com/transitivebullshit/javascript-modules-worth-using-4267</link>
      <guid>https://forem.com/transitivebullshit/javascript-modules-worth-using-4267</guid>
      <description>&lt;p&gt;&lt;em&gt;A quick breakdown of the most useful JavaScript modules that I find myself using over and over again.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is an opinionated article that focuses on general-purpose modules and utilities that I’ve found invaluable to Node.js and frontend JavaScript development. It won’t be exhaustive or include any special-purpose modules, as those types of &lt;a href="https://awesomelists.top/" rel="noopener noreferrer"&gt;awesome lists&lt;/a&gt; are indeed awesome but tend to be a bit overwhelming.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AEd4yEvBF4DmMJ1Es1p_hXw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AEd4yEvBF4DmMJ1Es1p_hXw.jpeg" alt="JavaScript Modules Worth Using 🔥"&gt;&lt;/a&gt;&lt;/p&gt;
Yeahhh we all love npmmmmm huzzahhhhhh!!! (Image Credit: &lt;a href="http://blog.npmjs.org/post/161081169345/v500" rel="noopener noreferrer"&gt;npm&lt;/a&gt;)



&lt;h3&gt;
  
  
  Command Line Tools
&lt;/h3&gt;

&lt;p&gt;Let’s get started with some extremely useful command line tools.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/sindresorhus/np" rel="noopener noreferrer"&gt;&lt;strong&gt;np&lt;/strong&gt;&lt;/a&gt; - A better &lt;code&gt;npm publish&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you’re an npm author, I’d highly recommend checking out &lt;a href="https://github.com/sindresorhus/np" rel="noopener noreferrer"&gt;np&lt;/a&gt;, as it makes the process of bumping versions, adding git release tags, and publishing to npm a breeze, especially once you start having more than a couple of modules to maintain. It’s also worth noting &lt;a href="https://github.com/zeit/release" rel="noopener noreferrer"&gt;release&lt;/a&gt; by &lt;a href="https://zeit.co/" rel="noopener noreferrer"&gt;Zeit&lt;/a&gt; as a solid alternative.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A64gMHXogmFze4Y1_RuESnw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A64gMHXogmFze4Y1_RuESnw.gif" alt="🔥 JavaScript Modules Worth Using 🔥"&gt;&lt;/a&gt;Image Credit: &lt;a href="https://github.com/sindresorhus/np" rel="noopener noreferrer"&gt;np&lt;/a&gt; by &lt;a href="https://sindresorhus.com/" rel="noopener noreferrer"&gt;Sindre Sorhus&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://yarnpkg.com" rel="noopener noreferrer"&gt;&lt;strong&gt;yarn&lt;/strong&gt;&lt;/a&gt; - An alternative package manager to &lt;code&gt;npm&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There’s no clear winner between &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt;. The recent drama over &lt;code&gt;yarn&lt;/code&gt; v2 is probably enough to push many &lt;code&gt;yarn&lt;/code&gt; devs back to using &lt;code&gt;npm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As a JS developer in 2020 just make sure that you’re at least familiar with both &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt; and be comfortable switching off between them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://prettier.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;prettier&lt;/strong&gt;&lt;/a&gt; - An opinionated code formatter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Prettier enforces a consistent style by parsing your code and re-printing it with its own rules that take the maximum line length into account, wrapping code when necessary.&lt;/p&gt;

&lt;p&gt;I love &lt;a href="https://eslint.org/" rel="noopener noreferrer"&gt;eslint&lt;/a&gt; and have been a long-time user of JavaScript &lt;a href="https://standardjs.com/" rel="noopener noreferrer"&gt;Standard Style&lt;/a&gt; in particular, but the idea behind automatic code formatters like &lt;a href="https://prettier.io/" rel="noopener noreferrer"&gt;prettier&lt;/a&gt; and &lt;a href="https://golang.org/cmd/gofmt/" rel="noopener noreferrer"&gt;gofmt&lt;/a&gt; is undeniably attractive.&lt;/p&gt;

&lt;p&gt;As developers, we spend way too much time and mental energy worrying about code presentation and styling, whereas &lt;a href="https://prettier.io/" rel="noopener noreferrer"&gt;prettier&lt;/a&gt; alleviates the need for those thought processes and allows you to focus on what you’re writing instead of how you’re writing it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A5MvKCbHX2-GM4ERUd1UljA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A5MvKCbHX2-GM4ERUd1UljA.png" alt="🔥 JavaScript Modules Worth Using 🔥"&gt;&lt;/a&gt;Image Credit: &lt;a href="https://github.com/prettier/prettier" rel="noopener noreferrer"&gt;prettier&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://zeit.co/now" rel="noopener noreferrer"&gt;&lt;strong&gt;now&lt;/strong&gt;&lt;/a&gt; - Extremely simple deployments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now is absolutely the best free deployment system that exists today in terms of simplicity, reliability, and feature set. It‘s great for testing static and dynamic deployments and scales up nicely if and when you require more servers. Aaaaaaaaaand did I mention that it’s &lt;strong&gt;free&lt;/strong&gt; until you want to scale up?!&lt;/p&gt;

&lt;p&gt;It plays extremely well with Node.js and JS-powered webapps. I’d also highly recommend checking out the rest of &lt;a href="https://zeit.co/" rel="noopener noreferrer"&gt;Zeit’s&lt;/a&gt; offerings as well, as their team is comprised by some of the best JS devs the community has to offer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AOuTnNz8z_4pDz2YG0eqUAA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AOuTnNz8z_4pDz2YG0eqUAA.png" alt="🔥 JavaScript Modules Worth Using 🔥"&gt;&lt;/a&gt;Image Credit: &lt;a href="https://zeit.co" rel="noopener noreferrer"&gt;Zeit&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://asciinema.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;asciinema&lt;/strong&gt;&lt;/a&gt; - Free tool for recording high quality terminal sessions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;See my previous blog post “&lt;a href="https://hackernoon.com/presenting-your-code-beautifully-fdbab9e6fb68" rel="noopener noreferrer"&gt;Making your Code Beautiful&lt;/a&gt;” for a breakdown of how you can take advantage of &lt;a href="https://asciinema.org/" rel="noopener noreferrer"&gt;asciinema&lt;/a&gt; to produce quality code demos &amp;amp; screencasts like the pros.&lt;/p&gt;




&lt;h3&gt;
  
  
  Promises
&lt;/h3&gt;

&lt;p&gt;This section really deserves an entire article unto itself, especially now that &lt;a href="https://zeit.co/blog/async-and-await" rel="noopener noreferrer"&gt;async &amp;amp; await&lt;/a&gt; have started becoming the de facto standard paradigm for concurrent programming in JavaScript. With that being said, I’d highly recommend checking out &lt;a href="https://sindresorhus.com/" rel="noopener noreferrer"&gt;Sindre Sorhus&lt;/a&gt;’ excellent &lt;a href="https://github.com/sindresorhus/promise-fun" rel="noopener noreferrer"&gt;promise-fun&lt;/a&gt; module collection if you haven’t already. My only gripe with these modules is that they likely won’t work out-of-the-box with most frontend toolchains like &lt;a href="https://github.com/facebook/create-react-app" rel="noopener noreferrer"&gt;create-react-app&lt;/a&gt; or &lt;a href="https://rollupjs.org" rel="noopener noreferrer"&gt;rollup&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here are a few of the most useful gems which stick out for working with promises and async-style code in Node:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/sindresorhus/pify" rel="noopener noreferrer"&gt;&lt;strong&gt;pify&lt;/strong&gt;&lt;/a&gt; - Promisify a callback-style function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are a lot of ways to convert functions from old-school callback-style to Promise-style, but I’ve found &lt;a href="https://github.com/sindresorhus/pify" rel="noopener noreferrer"&gt;pify&lt;/a&gt; to be the best. It’s tiny and has some niceties like automatic method binding that the built-in &lt;a href="https://nodejs.org/api/util.html#util_util_promisify_original" rel="noopener noreferrer"&gt;util.promisify&lt;/a&gt; is lacking.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/sindresorhus/p-map" rel="noopener noreferrer"&gt;&lt;strong&gt;p-map&lt;/strong&gt;&lt;/a&gt; - Map over promises concurrently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Concurrency is great, but most of the time you want to set a practical limit on parallelism whether it be throttling network bandwidth or compute resources. This is where &lt;a href="https://github.com/sindresorhus/p-map" rel="noopener noreferrer"&gt;p-map&lt;/a&gt; really shines. I use it 99% of the time as a drop-in replacement for &lt;code&gt;Promise.all(…)&lt;/code&gt;, which doesn’t support limiting parallelism.&lt;/p&gt;

&lt;p&gt;Before I was aware of &lt;a href="https://github.com/sindresorhus/p-map" rel="noopener noreferrer"&gt;p-map&lt;/a&gt;, I created my own version &lt;a href="https://github.com/transitive-bullshit/async-await-parallel" rel="noopener noreferrer"&gt;async-await-parallel&lt;/a&gt;, but you should use &lt;a href="https://github.com/sindresorhus/p-map" rel="noopener noreferrer"&gt;p-map&lt;/a&gt; as it’s better. 😛&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/sindresorhus/p-retry" rel="noopener noreferrer"&gt;&lt;strong&gt;p-retry&lt;/strong&gt;&lt;/a&gt; - Retry a promise-returning or async function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I generally wrap any HTTP requests and external service calls with &lt;a href="https://github.com/sindresorhus/p-retry" rel="noopener noreferrer"&gt;p-retry&lt;/a&gt; to add a basic level of robustness to them. Combined with &lt;a href="https://github.com/sindresorhus/p-map" rel="noopener noreferrer"&gt;p-map&lt;/a&gt;, you can process large batches of external requests with controlled parallelism without having to worry too much about an occasional transport error, socket hang-up, or server timeout.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/sindresorhus/p-timeout" rel="noopener noreferrer"&gt;&lt;strong&gt;p-timeout&lt;/strong&gt;&lt;/a&gt; - Timeout a promise after a specified amount of time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Alongside &lt;a href="https://github.com/sindresorhus/p-retry" rel="noopener noreferrer"&gt;p-retry&lt;/a&gt;, &lt;a href="https://github.com/sindresorhus/p-timeout" rel="noopener noreferrer"&gt;p-timeout&lt;/a&gt; is a must for robustly working with third-party APIs and services. You can also specify an optional fallback, as oftentimes returning &lt;em&gt;something&lt;/em&gt; is better than hanging indefinitely or returning after an inordinate amount of time.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/transitive-bullshit/p-cache" rel="noopener noreferrer"&gt;&lt;strong&gt;p-cache&lt;/strong&gt;&lt;/a&gt; or &lt;a href="https://github.com/sindresorhus/p-memoize" rel="noopener noreferrer"&gt;&lt;strong&gt;p-memoize&lt;/strong&gt;&lt;/a&gt; - Memoize the results of an async function via an &lt;a href="https://github.com/isaacs/node-lru-cache" rel="noopener noreferrer"&gt;LRU cache&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The aim of many of these Promise utilities reminds me a lot of architecting robust &lt;a href="https://blog.risingstack.com/designing-microservices-architecture-for-failure/" rel="noopener noreferrer"&gt;microservices&lt;/a&gt;, where every external dependency can be treated with a common interface supporting retrys, timeouts, caching, circuit breakers, fallbacks, etc.&lt;/p&gt;

&lt;p&gt;Graceful degradation of functionality is generally preferable to overwhelming the system or not responding at all, so if you’re not too familiar with microservices, check them out and see if their design decisions can help improve your Promise handling abilities as well.&lt;/p&gt;




&lt;h3&gt;
  
  
  Scraping
&lt;/h3&gt;

&lt;p&gt;There are a lot of great scraping utilities out there, some of which operate on raw HTML like &lt;a href="https://github.com/cheeriojs/cheerio" rel="noopener noreferrer"&gt;cheerio&lt;/a&gt;, and some of which simulate a full browser environment like &lt;a href="https://github.com/GoogleChrome/puppeteer" rel="noopener noreferrer"&gt;puppeteer&lt;/a&gt;. What you decide to use really depends on your use case, as working with raw HTML is a lot quicker and more lightweight, whereas automating a headless browser is more robust at the cost of being heavier to get started.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/cheeriojs/cheerio" rel="noopener noreferrer"&gt;&lt;strong&gt;cheerio&lt;/strong&gt;&lt;/a&gt; - Fast, flexible, and lean implementation of core &lt;code&gt;jQuery&lt;/code&gt; designed specifically for the server.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cheerio is really great for quick &amp;amp; dirty web scraping where you just want to operate against raw HTML. It provides a robust jQuery-like syntax for traversing &amp;amp; manipulating HTML documents. Cheerio pairs particularly well with &lt;a href="https://github.com/request/request-promise-native" rel="noopener noreferrer"&gt;request-promise-native&lt;/a&gt; below for fetching remote HTML documents.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/GoogleChrome/puppeteer" rel="noopener noreferrer"&gt;&lt;strong&gt;puppeteer&lt;/strong&gt;&lt;/a&gt; - Headless Chrome Node API&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unlike cheerio, puppeteer is a wrapper for automating headless chrome instances, which is really useful for working with modern JS-powered SPAs. Since you’re working with Chrome itself, it also has best-in-class support for parsing / rendering / scripting conformance. Headless Chrome is still relatively new, but it will likely phase out older approaches such as &lt;a href="http://phantomjs.org/" rel="noopener noreferrer"&gt;PhantomJS&lt;/a&gt; in the years to come.&lt;/p&gt;

&lt;p&gt;If you need to faithfully scrape websites, automate web-based workflows, or capture screenshots, &lt;a href="https://github.com/GoogleChrome/puppeteer" rel="noopener noreferrer"&gt;puppeteer&lt;/a&gt; is a clear winner that will only become more popular with time.&lt;/p&gt;




&lt;h3&gt;
  
  
  Node.js
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/rolodato/dotenv-safe" rel="noopener noreferrer"&gt;&lt;strong&gt;dotenv-safe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;-&lt;/strong&gt; Load environment variables from &lt;code&gt;.env&lt;/code&gt; and ensure they’re all present.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This module extends the hugely popular &lt;a href="https://github.com/motdotla/dotenv" rel="noopener noreferrer"&gt;dotenv&lt;/a&gt; module to enforce the existence of expected environment variables via a &lt;code&gt;.env.example&lt;/code&gt; file. Like the original, it provides fast, secure, and robust environment variable support for Node.&lt;/p&gt;

&lt;p&gt;It also plays well with Zeit’s &lt;a href="https://zeit.co/now" rel="noopener noreferrer"&gt;now.sh&lt;/a&gt; deployments with the &lt;code&gt;”dotenv”: true&lt;/code&gt; option set in &lt;a href="https://zeit.co/blog/now-json" rel="noopener noreferrer"&gt;now.json&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/request/request" rel="noopener noreferrer"&gt;&lt;strong&gt;request&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://github.com/request/request-promise-native" rel="noopener noreferrer"&gt;&lt;strong&gt;request-promise-native&lt;/strong&gt;&lt;/a&gt; - Simplified HTTP request client.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Making HTTP requests is an extremely common operation, and my goto module here is &lt;a href="https://github.com/request/request-promise-native" rel="noopener noreferrer"&gt;request-promise-native&lt;/a&gt; which wraps the original &lt;a href="https://github.com/request/request" rel="noopener noreferrer"&gt;request&lt;/a&gt; module with native ES6 promise support. 95% of the time I want to await the result of a promisified HTTP request. The other 5% of the time I want to work with the response stream directly, in which case I use the underlying &lt;a href="https://github.com/request/request" rel="noopener noreferrer"&gt;request&lt;/a&gt; module, foregoing Promise support.&lt;/p&gt;

&lt;p&gt;For robustness, I will oftentimes wrap &lt;a href="https://github.com/request/request-promise-native" rel="noopener noreferrer"&gt;request-promise-native&lt;/a&gt; calls in some combination of &lt;a href="https://github.com/sindresorhus/p-retry" rel="noopener noreferrer"&gt;p-retry&lt;/a&gt;, &lt;a href="https://github.com/sindresorhus/p-timeout" rel="noopener noreferrer"&gt;p-timeout&lt;/a&gt;, and &lt;a href="https://github.com/transitive-bullshit/p-cache" rel="noopener noreferrer"&gt;p-cache&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It’s also worth mentioning &lt;a href="https://github.com/sindresorhus/got" rel="noopener noreferrer"&gt;got&lt;/a&gt; as a newer alternative to &lt;a href="https://github.com/request/request" rel="noopener noreferrer"&gt;request&lt;/a&gt; with promise support baked in, although I haven’t used it much personally.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;Example of downloading an HTML document with &lt;a href="https://github.com/request/request-promise-native" rel="noopener noreferrer"&gt;request-promise-native&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/tj/consolidate.js" rel="noopener noreferrer"&gt;&lt;strong&gt;consolidate&lt;/strong&gt;&lt;/a&gt; - Template engine consolidation library for Node.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Consolidate is great for handling any type of backend templating (emails, tweets, raw html, etc.). I generally use &lt;a href="http://handlebarsjs.com/" rel="noopener noreferrer"&gt;handlebars&lt;/a&gt; as my templating engine of choice, but no matter what, I always wrap my template usage in &lt;a href="https://github.com/tj/consolidate.js" rel="noopener noreferrer"&gt;consolidate&lt;/a&gt;, because it provides a simple &amp;amp; consistent interface to templating regardless of the template engine you decide to use under the hood.&lt;/p&gt;

&lt;p&gt;For example, I used consolidate in &lt;a href="https://github.com/transitive-bullshit/create-react-library" rel="noopener noreferrer"&gt;create-react-library&lt;/a&gt; to render the boilerplate’s templates with library-specific variables.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/sindresorhus/execa" rel="noopener noreferrer"&gt;&lt;strong&gt;execa&lt;/strong&gt;&lt;/a&gt; - A better &lt;code&gt;child_process&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Extremely useful if you need to run a shell command or spawn a child process in general.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/jprichardson/node-fs-extra" rel="noopener noreferrer"&gt;&lt;strong&gt;fs-extra&lt;/strong&gt;&lt;/a&gt; - A better &lt;code&gt;fs&lt;/code&gt; with additional methods and Promise support.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s rare that I find myself using &lt;code&gt;fs&lt;/code&gt; directly anymore. Try &lt;code&gt;fs-extra&lt;/code&gt; and you won’t look back.&lt;/p&gt;




&lt;h3&gt;
  
  
  Math
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://d3js.org/" rel="noopener noreferrer"&gt;D3&lt;/a&gt; (Data-Driven Documents) is a popular frontend library for data visualization and animation. It also contains some of the best &lt;em&gt;standalone packages&lt;/em&gt; for common math operations that I find myself consistently choosing over alternative modules.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/d3/d3-random" rel="noopener noreferrer"&gt;&lt;strong&gt;d3-random&lt;/strong&gt;&lt;/a&gt; — Generate random numbers from various distributions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When &lt;code&gt;Math.random&lt;/code&gt; doesn’t cut it, give &lt;a href="https://github.com/d3/d3-random" rel="noopener noreferrer"&gt;d3-random&lt;/a&gt; a try. It supports sampling from different common distributions, including uniform, normal, and exponential.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/d3/d3-ease" rel="noopener noreferrer"&gt;&lt;strong&gt;d3-ease&lt;/strong&gt;&lt;/a&gt; - Easing functions for smooth animations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2Auham3g52-ohGs0d8OZ42xQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2Auham3g52-ohGs0d8OZ42xQ.png" alt="🔥 JavaScript Modules Worth Using 🔥"&gt;&lt;/a&gt;Image Credit: &lt;a href="https://github.com/d3/d3-ease" rel="noopener noreferrer"&gt;d3-ease&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/d3/d3-interpolate" rel="noopener noreferrer"&gt;&lt;strong&gt;d3-interpolate&lt;/strong&gt;&lt;/a&gt; - Interpolate numbers, colors, strings, arrays, objects, whatever!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This module provides a variety of interpolation methods for blending between two arbitrary values. Values may be numbers, colors, strings, arrays, or even deeply-nested objects.&lt;/p&gt;




&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/avajs/ava" rel="noopener noreferrer"&gt;&lt;strong&gt;ava&lt;/strong&gt;&lt;/a&gt; - Awesome JS test runner.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s not surprising that my go-to for unit test runner for Node.js is yet another tool created by Sindre Sorhus. Ava is a newer unit test runner that takes a lot of what was good about &lt;a href="https://mochajs.org/" rel="noopener noreferrer"&gt;mocha&lt;/a&gt;, &lt;a href="https://github.com/substack/tape" rel="noopener noreferrer"&gt;tape&lt;/a&gt;, &lt;a href="http://chaijs.com/" rel="noopener noreferrer"&gt;chai&lt;/a&gt; and other JS test runners, and bundles it all together into a quality project with sensible defaults that “just works”.&lt;/p&gt;

&lt;p&gt;It’s worth noting that Ava’s tests are run in parallel by default, which you can disable at the file-level for use cases like database testing where the order your unit tests run may be important.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AC5QnzBhjtNaffYeda9RMFA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AC5QnzBhjtNaffYeda9RMFA.gif" alt="🔥 JavaScript Modules Worth Using 🔥"&gt;&lt;/a&gt;Image Credit: &lt;a href="https://github.com/avajs/ava" rel="noopener noreferrer"&gt;ava&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/node-nock/nock" rel="noopener noreferrer"&gt;&lt;strong&gt;nock&lt;/strong&gt;&lt;/a&gt; - HTTP mocking and expectations library.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nock is great for testing modules that perform HTTP requests in isolation. If your Node module makes HTTP requests and you want to provide proper unit testing, then &lt;a href="https://github.com/node-nock/nock" rel="noopener noreferrer"&gt;nock&lt;/a&gt; is the way to go.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://sinonjs.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;sinon&lt;/strong&gt;&lt;/a&gt; - Function spies, stubs and mocks for JS testing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sinon is a very useful utility library for writing isolated tests by taking advantage of dependency injection. It should be a part of every Node developer’s tool belt.&lt;/p&gt;




&lt;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;I hope you’ve found this breakdown helpful, even if it’s just learning about one quality module that you weren’t aware of before. I know a lot of aspiring and seasoned developers alike who end up rolling their own solutions to common problems, which can be a useful practice in &amp;amp; of itself, but it’s also good to know when there are quality, existing solutions you should be using instead of constantly reinventing the wheel.&lt;/p&gt;

&lt;p&gt;The size &amp;amp; scope of NPM’s module library is unprecedented, and imho it’s one of JavaScript’s biggest advantages compared with other programming languages. The better you become at taking advantage of npm modules, the faster and more productive you’ll be as a developer. Higher-order “soft” skills like this are one of the hallmarks of becoming a &lt;a href="http://antirez.com/news/112" rel="noopener noreferrer"&gt;mythical 10x programmer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have any favorite npm modules I left out? Let me know by sharing your favorite modules in the comments! ❤️&lt;/p&gt;




&lt;h4&gt;
  
  
  Before you go…
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;If you liked this article, please leave leave a ❤&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>npm</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Scraping the web with Node.js</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Wed, 29 Jan 2020 09:49:00 +0000</pubDate>
      <link>https://forem.com/transitivebullshit/scraping-the-web-with-node-js-43og</link>
      <guid>https://forem.com/transitivebullshit/scraping-the-web-with-node-js-43og</guid>
      <description>&lt;p&gt;&lt;em&gt;An in-depth guide to building a minimal, robust web scraper for extracting structured data on the internets.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Node.js provides a perfect, dynamic environment to quickly experiment and work with data from the web.&lt;/p&gt;

&lt;p&gt;While there are more and more visual scraping products these days (&lt;a href="https://www.import.io/"&gt;import.io&lt;/a&gt;, &lt;a href="https://tryspider.com"&gt;Spider&lt;/a&gt;, &lt;a href="https://scrapinghub.com/"&gt;Scrapinghub&lt;/a&gt;, &lt;a href="https://apify.com/"&gt;Apify&lt;/a&gt;, &lt;a href="http://crawly.diffbot.com"&gt;Crawly&lt;/a&gt;, ……), there will always be a need for the simplicity and flexibility of writing one-off scrapers manually.&lt;/p&gt;

&lt;p&gt;This post is intended as a tutorial for writing these types of data extraction scripts in Node.js, including some subtle best practices that I’ve learned from writing dozens of these types of crawlers over the years.&lt;/p&gt;

&lt;p&gt;In particular, we’ll be walking through how to create a scraper for GitHub’s &lt;a href="https://github.com/trending"&gt;list&lt;/a&gt; of trending repositories. If you want to follow along with the code, &lt;strong&gt;check out the repo&lt;/strong&gt; &lt;a href="https://github.com/transitive-bullshit/scrape-github-trending"&gt;&lt;strong&gt;scrape-github-trending&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building Blocks
&lt;/h3&gt;

&lt;p&gt;One of the best features of Node.js is the extremely comprehensive community of open source modules it has to offer. For this type of task, we’ll be leaning heavily on two modules, &lt;a href="https://github.com/sindresorhus/got"&gt;&lt;strong&gt;got&lt;/strong&gt;&lt;/a&gt; to robustly download raw HTML, and &lt;a href="https://github.com/cheeriojs/cheerio"&gt;&lt;strong&gt;cheerio&lt;/strong&gt;&lt;/a&gt; which provides a jQuery-inspired API for parsing and traversing those pages.&lt;/p&gt;

&lt;p&gt;Cheerio is really great for quick &amp;amp; dirty web scraping where you just want to operate against raw HTML. If you’re dealing with more advanced scenarios where you want your crawler to mimic a real user as close as possible or navigate client-side scripting, you’ll likely want to use &lt;a href="https://github.com/GoogleChrome/puppeteer"&gt;&lt;strong&gt;Puppeteer&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Unlike cheerio, puppeteer is a wrapper for automating headless chrome instances, which is really useful for working with modern JS-powered SPAs. Since you’re working with Chrome itself, it also has best-in-class support for parsing / rendering / scripting conformance. Headless Chrome is still relatively new, but it will likely phase out older approaches such as &lt;a href="http://phantomjs.org/"&gt;PhantomJS&lt;/a&gt; in the years to come.&lt;/p&gt;

&lt;p&gt;As far as &lt;a href="https://github.com/sindresorhus/got"&gt;&lt;strong&gt;got&lt;/strong&gt;&lt;/a&gt; goes, there are dozens of HTTP fetching libraries available on NPM, with some of the more popular alternatives being &lt;a href="https://github.com/visionmedia/superagent"&gt;superagent&lt;/a&gt;, &lt;a href="https://github.com/axios/axios"&gt;axios&lt;/a&gt;, &lt;a href="https://github.com/developit/unfetch"&gt;unfetch&lt;/a&gt; (isomorphic === usable from Node.js or browser), and finally &lt;a href="https://yarnpkg.com/en/package/request"&gt;request&lt;/a&gt; / &lt;a href="https://github.com/request/request-promise-native"&gt;request-promise-native&lt;/a&gt; (most popular library by far though the maintainers have officially deprecated any future development).&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;Alright, for this tutorial we’ll be writing a scraper for GitHub’s list of &lt;a href="https://github.com/trending"&gt;trending repositories&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first thing I do when writing a scraper is to open the target page in Chrome and take a look at the how the desired data is structured in dev tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wSyFnnwF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2AIpxFkpKHX7j69pyPVVwanw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wSyFnnwF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2AIpxFkpKHX7j69pyPVVwanw.png" alt="Scraping the web with Node.js"&gt;&lt;/a&gt;Chrome Devtools is very handy for scraping 💯Also, I know I know I need to charge my laptop…. 😂&lt;/p&gt;

&lt;p&gt;Switching back and forth between the &lt;code&gt;Console&lt;/code&gt; and &lt;code&gt;Elements&lt;/code&gt; tabs, you can use the &lt;code&gt;$$(‘.repo-list li’)&lt;/code&gt; selector in the console to select all of the trending repos.&lt;/p&gt;

&lt;p&gt;What you’re looking for in creating these &lt;a href="https://adam-marsden.co.uk/css-cheat-sheet"&gt;CSS selectors&lt;/a&gt; is to keep them as simple as possible while also making them as focused as possible. By looking through the &lt;code&gt;Elements&lt;/code&gt; tab and selecting the elements you’re interested in, you’ll usually come up with some potential selectors that may work. The next step is to try them out in the &lt;code&gt;Console&lt;/code&gt; tab using the &lt;code&gt;$$()&lt;/code&gt; syntax to make sure you’re only selecting the elements you intended to select. One rule of thumb here is to try and avoid using aspects of the HTML’s structure or classes that may change more often in refactors or code rewrites.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s write a scraper!
&lt;/h3&gt;

&lt;p&gt;Now that we have a good idea of some CSS selectors that will target our desired data, let’s convert them to a Node.js script:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Note that we’re using &lt;a href="https://zeit.co/blog/async-and-await"&gt;async / await syntax&lt;/a&gt; here to handle downloading the external web page asynchronously in a way that looks synchronous.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Line 12: we download the remote page and extract it’s text &lt;code&gt;body&lt;/code&gt; (HTML).&lt;/li&gt;
&lt;li&gt;Line 14: we load that HTML into cheerio so that it’s easy to traverse and manipulate.&lt;/li&gt;
&lt;li&gt;Line 15: we select all the repository &lt;code&gt;li&lt;/code&gt; elements using our previous CSS selector and map over them.&lt;/li&gt;
&lt;li&gt;Lines 16–32: we extract the relevant portions of each trending repo into a plain JSON object.&lt;/li&gt;
&lt;li&gt;Line 33: here we’re filtering out any repos that failed to parse correctly or threw an error. These will be &lt;code&gt;undefined&lt;/code&gt; in the array and &lt;code&gt;[].filter(Boolean)&lt;/code&gt; is a shorthand syntax for filtering any non-truthy values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, we’ve succeeded in scraping a single web page and extracting some relevant data. Here’s some example JSON output at this point:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Crawling Deeper
&lt;/h3&gt;

&lt;p&gt;Now that we’ve explored how to scrape a single page, the next logical step is to branch out and crawl multiple pages. You could even get fancy and crawl links recursively from this point on, but for now we’ll just focus on crawling one level down in this data, that is the repository URLs themselves.&lt;/p&gt;

&lt;p&gt;We’ll follow a very similar approach to how we scraped the original trending list. First, load up an example GitHub repository in Chrome and look through some of the most useful metadata that GitHub exposes and how you might target those elements via CSS selectors.&lt;/p&gt;

&lt;p&gt;Once you have a good handle on what data you want to extract and have some working selectors in the &lt;code&gt;Console&lt;/code&gt;, it’s time to write a Node.js function to download and parse a single GitHub repository.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The only real difference here from our first scraping example is that we’re using some different &lt;code&gt;cheerio&lt;/code&gt; utility methods like &lt;a href="https://github.com/cheeriojs/cheerio#findselector"&gt;$.find()&lt;/a&gt; and also doing some additional string parsing to coerce the data to our needs.&lt;/p&gt;

&lt;p&gt;At this point, we’re able to extract a lot of the most useful metadata about each repo individually, but we need a way of robustly mapping over all the repos we want to process. For this, we’re going to use the excellent &lt;a href="https://github.com/sindresorhus/p-map"&gt;&lt;strong&gt;p-map&lt;/strong&gt;&lt;/a&gt; module. Most of the time you want to set a practical limit on parallelism whether it be throttling network bandwidth or compute resources. This is where &lt;a href="https://github.com/sindresorhus/p-map"&gt;p-map&lt;/a&gt; really shines. I use it 99% of the time as a drop-in replacement for &lt;code&gt;Promise.all(…)&lt;/code&gt;, which doesn’t support limiting parallelism.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here, we’re mapping over each repository with a maximum concurrency of 3 requests at a time. This helps significantly in making your crawler more robust against random network and server issues.&lt;/p&gt;

&lt;p&gt;If you want to add one more level of robustness here, I would recommend wrapping your sub-scraping async functions in &lt;a href="https://github.com/sindresorhus/p-retry"&gt;p-retry&lt;/a&gt; and &lt;a href="https://github.com/sindresorhus/p-timeout"&gt;p-timeout&lt;/a&gt;. This is what &lt;a href="https://nicedoc.io/sindresorhus/got"&gt;got&lt;/a&gt; is actually doing under the hood to ensure more robust HTTP requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  All together now
&lt;/h3&gt;

&lt;p&gt;Here is the full executable Node.js code. You can also find the full reproducible project at &lt;a href="https://github.com/transitive-bullshit/scrape-github-trending"&gt;scrape-github-trending&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And an example of the corresponding JSON output:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I have used this exact pattern dozens of times for one-off scraping tasks in Node.js. It’s simple, robust, and really easy to customize to practically any targeted crawling / scraping scenarios.&lt;/p&gt;

&lt;p&gt;It’s worth mentioning that &lt;a href="https://github.com/IonicaBizau/scrape-it"&gt;scrape-it&lt;/a&gt; also looks like a very well engineered library that is essentially doing everything under the hood in this article.&lt;/p&gt;

&lt;p&gt;If your crawling use case requires a more distributed workflow or more complicated client-side parsing, I would highly recommend checking out &lt;a href="https://github.com/GoogleChrome/puppeteer"&gt;Puppeteer&lt;/a&gt;, which is a game changing library from Google for automating headless Chrome. You may also want to check out the related crawling resources listed in &lt;a href="https://github.com/transitive-bullshit/awesome-puppeteer"&gt;awesome-puppeteer&lt;/a&gt; such as &lt;a href="https://github.com/yujiosaka/headless-chrome-crawler"&gt;headless-chrome-crawler&lt;/a&gt; which provides a distributed crawling solution built on top of Puppeteer.&lt;/p&gt;

&lt;p&gt;In my experience, however, 95% of the time a simple one-file script like the one in this article tends to do the job just fine. And imho, &lt;a href="https://en.wikipedia.org/wiki/KISS_principle"&gt;KISS&lt;/a&gt; is the single most important rule in software engineering.&lt;/p&gt;

&lt;p&gt;Thanks for your time &amp;amp;&amp;amp; I wish you luck on your future scraping adventures!&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>opensource</category>
      <category>scraping</category>
    </item>
    <item>
      <title>Data Fingerprinting in JavaScript</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Sun, 26 Jan 2020 23:35:20 +0000</pubDate>
      <link>https://forem.com/transitivebullshit/data-fingerprinting-in-javascript-ojm</link>
      <guid>https://forem.com/transitivebullshit/data-fingerprinting-in-javascript-ojm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I want to talk a little about how you can use &lt;strong&gt;content-based addressing&lt;/strong&gt; (aka data fingerprinting) as a general approach to make your applications faster and more secure with some practical JavaScript examples.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First off, I find the concept of content-based addressing dope af. 👀&lt;/p&gt;

&lt;p&gt;It's an extremely powerful tool for building services that are fundamentally more performant, scalable and secure. 💪&lt;/p&gt;

&lt;p&gt;It's related to immutability, decentralization, data integrity, and more buzzwords...&lt;/p&gt;

&lt;p&gt;But it's also so useful and under-appreciated in general that I wanted to write a practical intro to show how it works alongside some real-world JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the hell are you talking about?
&lt;/h2&gt;

&lt;p&gt;You can think of content-based addressing as &lt;strong&gt;fingerprinting for data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Just like how fingerprints allow you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify a person based on their fingerprint&lt;/li&gt;
&lt;li&gt;Refer to a fingerprint as a unique ID for the person&lt;/li&gt;
&lt;li&gt;Tell if two people are the same person based on their fingerprints&lt;/li&gt;
&lt;li&gt;Quickly test to see if a person is in a database using just their fingerprint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just replace "person" with "data" in the above descriptions and you have a rough overview of what content-based addressing enables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jnSdF_kY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.transitivebullsh.it/content/images/2020/01/b_upscaled_image_x2-optim.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jnSdF_kY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.transitivebullsh.it/content/images/2020/01/b_upscaled_image_x2-optim.jpg" alt="" width="880" height="584"&gt;&lt;/a&gt;&lt;/p&gt;
Do you know where your data's been? 👀



&lt;p&gt;Put another way, content-based addressing allows you to uniquely and efficiently reference data based on it's actual content as opposed to something external like an ID or a URL.&lt;/p&gt;

&lt;p&gt;Database-generated IDs, random GUIDs, and URLs are all useful in their own right, but they're not quite as powerful as data fingerprinting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shut up and show me some code
&lt;/h2&gt;

&lt;p&gt;Let's see how this looks with some real-world code that I've used for reals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash.pick&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stableStringify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fast-json-stable-stringify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keyFoo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keyBar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fingerprint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stableStringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This snippet leaves out the &lt;code&gt;hash&lt;/code&gt; function (more on that below), but it does represent the core algorithm pretty clearly.&lt;/p&gt;

&lt;p&gt;It creates a content-based hash &lt;code&gt;fingerprint&lt;/code&gt; of any JavaScript object &lt;code&gt;myData&lt;/code&gt; that is a unique representation of that object based on the keys we care about &lt;code&gt;[ 'keyFoo', 'keyBar' ]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In short, this fingerprint offers you a very efficient way of telling when two JavaScript objects are the same.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If two content-based IDs are the same, the data in those objects is the same.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No need for a deep comparison. No need for Redux. Just pure immutable goodness.&lt;/p&gt;

&lt;h2&gt;
  
  
  So how does this actually work?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bSMemorO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.transitivebullsh.it/content/images/2020/01/f_upscaled_image_x2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bSMemorO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.transitivebullsh.it/content/images/2020/01/f_upscaled_image_x2.jpg" alt="" width="880" height="392"&gt;&lt;/a&gt;&lt;/p&gt;
We'll break this process into three distinct steps: 1) Input data 2) data cleaning 3) simplification.



&lt;p&gt;Let's take another look at our JavaScript code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash.pick&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stableStringify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fast-json-stable-stringify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keyFoo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keyBar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fingerprint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stableStringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;First&lt;/strong&gt;, we take as &lt;strong&gt;input&lt;/strong&gt; any JavaScript object &lt;code&gt;myData&lt;/code&gt;. This could be a model from your database or some object containing Redux-like app state, for instance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second&lt;/strong&gt;, we &lt;strong&gt;clean&lt;/strong&gt; our data to ensure that we're only considering parts of the data we actually care about via &lt;code&gt;lodash.pick&lt;/code&gt;. This step is optional but usually you'll want to clean your data like this before proceeding. I've found in practice that most of the time there will be parts of your data that aren't actually representative of the uniqueness of your model (we'll refer to this extra stuff as metadata 😉).&lt;/p&gt;

&lt;p&gt;As an example, let's say I want to create unique IDs for all of the rows in a SQL table. Most SQL implementations will add metadata to your table like the date an entry was created or modified, and it's unlikely we'd want this metadata to affect our notion of uniqueness. In other words, if two rows were inserted into the table at different times but have the exact same values according to our application's business logic, then we want to treat them as having the same fingerprint so we filter out this extra metadata.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third&lt;/strong&gt;, we &lt;strong&gt;simplify&lt;/strong&gt; our cleaned data into a stable, efficient representation that we can store and use for quick comparisons. Most of the time this step involves some sort of &lt;a href="https://simple.wikipedia.org/wiki/Cryptographic_hash_function"&gt;cryptographic hash&lt;/a&gt; to normalize the way we refer to our content in a unique, concise manner.&lt;/p&gt;

&lt;p&gt;In the code above, we want to make sure that our hashing is &lt;a href="https://stackoverflow.com/questions/1517793/what-is-stability-in-sorting-algorithms-and-why-is-it-important"&gt;&lt;strong&gt;stable&lt;/strong&gt;&lt;/a&gt;, which is made easy for us by the &lt;a href="https://github.com/epoberezkin/fast-json-stable-stringify"&gt;fast-json-stable-stringify&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;This awesome package recursively makes sure that no matter how our JavaScript object was constructed or what order its keys may be in, it will always output the same string representation for any two objects that have deep equality.&lt;/p&gt;

&lt;p&gt;There are some details this explanation is glossing over, but that's the beauty of the &lt;a href="https://www.npmjs.com/"&gt;NPM ecosystem&lt;/a&gt; – we don't have to understand all the bits &amp;amp; pieces to take advantage of their abstractions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's hash this thing out
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gta5ERnH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.transitivebullsh.it/content/images/2020/01/hashing_upscaled_image_x2-optim.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gta5ERnH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.transitivebullsh.it/content/images/2020/01/hashing_upscaled_image_x2-optim.jpg" alt="" width="880" height="544"&gt;&lt;/a&gt;&lt;/p&gt;
Whatsha up to?



&lt;p&gt;Up until now, we've glossed over the hashing aspect of things, so let's see what this looks like in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hasha&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;hasha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that there are lots of different ways you could define your &lt;code&gt;hash&lt;/code&gt; function. This example uses a very common &lt;a href="https://en.wikipedia.org/wiki/SHA-2"&gt;SHA256&lt;/a&gt; hash function and outputs a 64-character hex encoding of the results.&lt;/p&gt;

&lt;p&gt;Here is an example output fingerprint: &lt;code&gt;2d3ea73f0faacebbb4a437ff758c84c8ef7fd6cce45c07bee1ff59deae3f67f5&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here is an alternative hash implementation that uses the Node.js crypto package directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both of these hash implementations are equivalent for our purposes.&lt;/p&gt;

&lt;p&gt;The most important thing to keep in mind here is that we want to use a cryptographic hash function to output a compact, unique fingerprint that changes if our input data changes and remains the same if our input data remains the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  So where should I go from here?
&lt;/h2&gt;

&lt;p&gt;Once you start thinking about how data can be uniquely defined by its content, the applications are really endless.&lt;/p&gt;

&lt;p&gt;Here are a few use cases where I've personally found this approach useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generating unique identifiers for immutable deployments of serverless functions at &lt;a href="https://saasify.sh/"&gt;Saasify&lt;/a&gt;. I know &lt;a href="https://zeit.co/"&gt;ZEIT&lt;/a&gt; uses a very similar approach to optimize their lambda deployments and package dependencies.&lt;/li&gt;
&lt;li&gt;Generating unique identifiers for videos based on the database schema we used to generate them at &lt;a href="https://blog.transitivebullsh.it/automagical-architecture/"&gt;Automagical&lt;/a&gt;. If two videos have the same fingerprint, they should have the same content. One note here is that it's often useful to add a version number to your data before hashing since changes in our video renderer resulted in changes to the output videos.&lt;/li&gt;
&lt;li&gt;Caching Stripe plans and coupons that have the same parameters across different projects and accounts.&lt;/li&gt;
&lt;li&gt;Caching client-side models and HTTP metadata in a React webapp.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We've really only started to scratch the surface of what you can do with content-based addressing. Hopefully, I've shown how simple this mindset shift can be done in JavaScript and touched on a bit on the benefits this approach brings to the table.&lt;/p&gt;

&lt;p&gt;If you enjoy this stuff, I would recommend checking out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://flyingzumwalt.gitbooks.io/decentralized-web-primer/avenues-for-access/lessons/power-of-content-addressing.html"&gt;The power of content-based addressing&lt;/a&gt; - An awesome intro to the topic with a focus on content identifiers (CIDs) as they're used in &lt;a href="https://ipfs.io/"&gt;IPFS&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://multiformats.io/multihash/"&gt;Multihashes&lt;/a&gt; - Self-describing hashes. 💪&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Merkle_tree"&gt;Merkle trees&lt;/a&gt; - A recursive data structure built on top of content-based hashes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Rabin_fingerprint"&gt;Rabin fingerprinting&lt;/a&gt; - An efficient string searching algorithm that uses content-based hashing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ipfs.io/"&gt;IPFS&lt;/a&gt; - InterPlanetary File System.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://libp2p.io/"&gt;libp2p&lt;/a&gt; - Modular building blocks for decentralized applications.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/saasify-sh/saasify"&gt;Saasify&lt;/a&gt; - An easier way for devs to earn passive income... Oh wait, that's my company and it's not really related to content-based addressing but cut me some slack haha 😂&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks! 🙏&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>database</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>How interested are you in working remotely?</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Sun, 26 Jan 2020 04:44:07 +0000</pubDate>
      <link>https://forem.com/saasify/how-interested-are-you-in-working-remotely-35f9</link>
      <guid>https://forem.com/saasify/how-interested-are-you-in-working-remotely-35f9</guid>
      <description>&lt;p&gt;Lately, I've been having some fun pushing the limits of Typeform's free tier with the goal of doing some market research for &lt;a href="https://github.com/saasify-sh/saasify"&gt;Saasify&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since we're really all about helping developers launch their own remote passive income streams, I'd love it if some of you fine folks took a few minutes to help me with some &lt;a href="https://travisfischer.typeform.com/to/yOo9Wb"&gt;market research&lt;/a&gt;. (10 questions, ~2 minutes)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And because your time is valuable&lt;/strong&gt;, if you fill out the survey and respond to this thread pointing me to a project of yours, &lt;strong&gt;I will personally review your project / website / landing page / idea&lt;/strong&gt; and give you the best feedback I can offer. Maybe it'll be worthwhile, maybe it won't but I promise that I'll try to help you out with targeted feedback.&lt;/p&gt;

&lt;p&gt;Also, if any hackers out there have had success with their own forms of market research, I'd love to hear what's worked for you.&lt;/p&gt;

&lt;p&gt;Thanks! ❤&lt;/p&gt;

&lt;p&gt;&lt;a href="https://travisfischer.typeform.com/to/yOo9Wb"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---4tJrxvA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/lsqzn4m36hdqkp0qya44.png" alt="Survey preview" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>saas</category>
      <category>api</category>
      <category>serverless</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Modern web accessibility 💪</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Wed, 15 Jan 2020 00:16:51 +0000</pubDate>
      <link>https://forem.com/saasify/modern-web-accessibility-audits-4h5l</link>
      <guid>https://forem.com/saasify/modern-web-accessibility-audits-4h5l</guid>
      <description>&lt;p&gt;We're excited to help enable a more accessible &amp;amp; inclusive web via &lt;a href="https://github.com/saasify-sh/ta11y"&gt;Ta11y&lt;/a&gt;, an open source suite of modern web accessibility testing tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;We've tried to design Ta11y to be as simple to use as possible.&lt;/p&gt;

&lt;p&gt;The easiest way to get started is via the &lt;a href="https://github.com/saasify-sh/ta11y"&gt;CLI&lt;/a&gt;, but you can also use it programmatically from Node.js via &lt;a href="https://github.com/saasify-sh/ta11y/blob/master/packages/ta11y-core"&gt;@ta11y/core&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ta11y uses &lt;a href="https://pptr.dev/"&gt;Puppeteer&lt;/a&gt; to crawl and extract content from websites, so you can be sure you're testing any dynamic, JavaScript-powered content that your users will see.&lt;/p&gt;

&lt;p&gt;Ta11y supports a large number of output formats such as JSON, Excel, CSV, and HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility as a service&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Audit your websites with a range of test suites including WCAG 2.0/2.1 A, AA, AAA, Section 508, HTML validation, as well as our own best practices.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible and automated&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Run manual tests during development and then integrate into any CI pipeline. Supports generating reports in XLS, XLSX, CSV, JSON, HTML, and more.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runs in any environment&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Easy integration that supports localhost, firewalls, custom auth, as well as any public production environment.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern dynamic websites&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Ta11y treats all websites as dynamic with full JavaScript support, so you'll test pages as your users actually experience them.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free to try&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Simple to get started for free, then &lt;a href="https://dev.to/pricing"&gt;sign up&lt;/a&gt; once you're ready to remove rate limits. Have a non-profit use case? &lt;a href="//mailto:support@saasify.sh"&gt;Get in touch&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private &amp;amp; secure&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Ta11y is built using serverless functions and never stores any of your data or audit results.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;




&lt;p&gt;This example runs the wcag2a and wcag2aa audit test suites on the given URL and outputs the results to an Excel spreadsheet (supports any &lt;code&gt;xls&lt;/code&gt;, &lt;code&gt;xlsx&lt;/code&gt;, or &lt;code&gt;csv&lt;/code&gt; file).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ta11y https://example.com &lt;span class="nt"&gt;-o&lt;/span&gt; audit.xls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;This example runs the wcag2a and wcag2aa audit test suites on the given URL and outputs the results to a comma-separated-value file (&lt;code&gt;csv&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ta11y https://example.com &lt;span class="nt"&gt;--suites&lt;/span&gt; wcag2a,wcag2aa &lt;span class="nt"&gt;-o&lt;/span&gt; audit.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;This example will crawl all pages of a local site and then perform an audit of the results.&lt;/p&gt;

&lt;p&gt;Note that the local site does not have to be publicly accessible as content extraction happens locally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ta11y http://localhost:3000 &lt;span class="nt"&gt;--crawl&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; audit.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;Ta11y is a new open source project written in JavaScript and built on the shoulders of other OSS giants.&lt;/p&gt;

&lt;p&gt;We're looking for feedback and contributors, so please try it out and let us know if you have any thoughts. Thanks! 🙏&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://ta11y.saasify.sh" title="ta11y"&gt;
    &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3kHxQVip--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/saasify-sh/ta11y/master/media/logo.svg%3Fsanitize%3Dtrue" alt="ta11y Logo" width="82" height="72"&gt;
  &lt;/a&gt;
&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>opensource</category>
      <category>javascript</category>
    </item>
    <item>
      <title>A better way to fund OSS</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Mon, 02 Dec 2019 20:00:42 +0000</pubDate>
      <link>https://forem.com/transitivebullshit/a-better-way-to-fund-oss-43ee</link>
      <guid>https://forem.com/transitivebullshit/a-better-way-to-fund-oss-43ee</guid>
      <description>&lt;p&gt;Hi everyone! 😄&lt;/p&gt;

&lt;p&gt;For the past year, I've been trying to make it easier for OSS devs to earn sustainable funding.&lt;/p&gt;

&lt;p&gt;I'm very proud to be working on &lt;a href="https://github.com/saasify-sh/saasify"&gt;Saasify&lt;/a&gt;, a platform which enables devs to monetize open source projects via serverless APIs. 😍&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our mission at Saasify is to provide sustainable funding for open source.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GHrwcB5d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/03214uqdsqv00tfksen3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GHrwcB5d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/03214uqdsqv00tfksen3.png" alt="How Saasify Works"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you've ever struggled to make a living working on open source, I hear you.&lt;/p&gt;

&lt;p&gt;OSS can be extremely powerful and rewarding, but there is a huge problem that exists in the market between how valuable open source is to every business in existence versus how difficult it is for OSS developers to capture any of that value.&lt;/p&gt;

&lt;p&gt;Donation platforms like Patreon and GitHub Sponsors help with a very small percentage of this problem because the business model of voluntarily giving back to OSS is inherently weak.&lt;/p&gt;

&lt;p&gt;Contrast this with the standard SaaS API business model of paying based on usage that aligns much more naturally with how businesses actually pay for software critical to their core business needs.&lt;/p&gt;

&lt;p&gt;Saasify is aiming to bridge the gap between this disparity by reducing the barrier to entry for developers who are interested in earning passive income via SaaS.&lt;/p&gt;

&lt;p&gt;On a personal level, &lt;strong&gt;I care deeply about the problem of OSS sustainability&lt;/strong&gt; and am looking to connect with other devs who feel similarly. And while Saasify won't work for every project, it's my sincere hope that it will help other independent OSS developers like myself earn passive income.&lt;/p&gt;

&lt;p&gt;Looking forward to hearing your thoughts on Saasify &amp;amp;&amp;amp; thanks for reading!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>WordCloud</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Tue, 19 Nov 2019 09:02:34 +0000</pubDate>
      <link>https://forem.com/transitivebullshit/wordcloud-3hei</link>
      <guid>https://forem.com/transitivebullshit/wordcloud-3hei</guid>
      <description>&lt;p&gt;Very excited to be launching &lt;a href="https://www.producthunt.com/posts/wordcloud"&gt;WordCloud&lt;/a&gt; today on PH!&lt;/p&gt;

&lt;p&gt;It's a simple API to create attractive, unique preview images from any URL.&lt;/p&gt;

&lt;p&gt;This SaaS API wraps the open source &lt;a href="https://github.com/minimaxir/stylecloud"&gt;stylecloud&lt;/a&gt; and &lt;a href="https://github.com/amueller/word_cloud"&gt;wordcloud&lt;/a&gt; packages, with 80% of any revenue from the API being set aside for these OSS authors.&lt;/p&gt;

&lt;p&gt;Our core mission at Saasify is to provide sustainable funding for open source developers, and today marks a big step in that direction.&lt;/p&gt;

&lt;p&gt;I'm particularly excited as this is our first launch for an API written in Python, where we're relying heavily on &lt;a href="https://fastapi.tiangolo.com/"&gt;FastAPI&lt;/a&gt; to generate the OpenAPI schema that powers the API.&lt;/p&gt;

&lt;p&gt;It's also open source -- check out the relatively simple &lt;a href="https://github.com/saasify-sh/saasify/tree/master/examples/python/wordcloud"&gt;code&lt;/a&gt; we used to generate this webapp.&lt;/p&gt;

&lt;p&gt;If you have any questions or comments, please let me know -- thanks!&lt;/p&gt;

</description>
      <category>saas</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>One SaaS PH Launch a Week...</title>
      <dc:creator>Travis Fischer</dc:creator>
      <pubDate>Fri, 08 Nov 2019 01:14:55 +0000</pubDate>
      <link>https://forem.com/saasify/one-saas-ph-launch-a-week-19jm</link>
      <guid>https://forem.com/saasify/one-saas-ph-launch-a-week-19jm</guid>
      <description>&lt;p&gt;Our team at Saasify is busy preparing for our YC interview in a few weeks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In order to validate our product, our main objective right now is to launch one fully polished FaaS API every week for the next two months!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We recently had our first two PH launches for products built on top of Saasify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.producthunt.com/posts/puppet-master"&gt;Puppet Master&lt;/a&gt; - Headless chrome as a service.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.producthunt.com/posts/synopsis-2"&gt;Synopsis&lt;/a&gt; - Summarize any website or article automagically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These should give you a good idea for the types of SaaS API products we're targeting.&lt;/p&gt;

&lt;p&gt;One of the things that I'm most excited about is how &lt;strong&gt;Saasify enables us to launch many product experiments very quickly&lt;/strong&gt;. Too many founders put all their eggs into one basket and inevitably fail to find product / market fit, and with Saasify, we're hoping that each of these product launches will teach us about more about our market and what to focus on.&lt;/p&gt;

&lt;p&gt;Our thesis is that many of these individual FaaS products will fail to gain traction, but if each one has a certain probability of finding product / market fit, then N independent product launches improves our chances linearly by N, which imho is extremely powerful in the aggregate.&lt;/p&gt;

&lt;p&gt;Eventually, these products will all blend into a cohesive marketplace of standardized FaaS, but for now we're focusing on marketing them as standalone SaaS products to optimize messaging and inbound channels.&lt;/p&gt;

&lt;p&gt;We have a strong pipeline of projects and OSS authors we're working with to meet our aggressive launch schedule, but we need YOUR help!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you have a project you'd like to &lt;a href="https://saasify.sh/"&gt;saasify and start monetizing&lt;/a&gt;, we'd LOVE to hear from you!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Feel free to DM me on our &lt;a href="https://join.slack.com/t/saasify/shared_invite/enQtODAxODA5MzU0NjczLTczOGU3NzNkYTJlMWIwZDkyNjJkOTk3MGEwZThlOWQyNTQxODZjZTExNjAzODJlZDQ3MWM5NWQwMGRiMDcyZTY"&gt;open slack&lt;/a&gt; &amp;amp;&amp;amp; thanks for reading!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>saas</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
