From b34e858aa6e456b9ea843c50ed93f49ad2ec50f3 Mon Sep 17 00:00:00 2001
From: jbilling <jbilling@oreilly.com>
Date: Mon, 9 Oct 2017 13:08:28 -0700
Subject: [PATCH 01/71] Edited atlas.json with Atlas code editor

---
 atlas.json | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/atlas.json b/atlas.json
index e134be9..039f44d 100644
--- a/atlas.json
+++ b/atlas.json
@@ -8,6 +8,10 @@
   ],
   "files": [
     "sections/cover.html",
+    "cover.html",
+    "titlepage.html",
+    "copyright.html",
+    "toc.html",
     "chapters/ch01.asciidoc",
     "chapters/ch02.asciidoc",
     "chapters/ch03.asciidoc",

From 3b5da6c4678f0dff2a4553c3aba23d1767f57347 Mon Sep 17 00:00:00 2001
From: jbilling <jbilling@oreilly.com>
Date: Mon, 9 Oct 2017 13:10:17 -0700
Subject: [PATCH 02/71] Edited atlas.json with Atlas code editor

---
 atlas.json | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/atlas.json b/atlas.json
index 039f44d..3389f65 100644
--- a/atlas.json
+++ b/atlas.json
@@ -8,10 +8,10 @@
   ],
   "files": [
     "sections/cover.html",
-    "cover.html",
-    "titlepage.html",
-    "copyright.html",
-    "toc.html",
+    "sections/cover.html",
+    "sections/titlepage.html",
+    "sections/copyright.html",
+    "sections/toc.html",
     "chapters/ch01.asciidoc",
     "chapters/ch02.asciidoc",
     "chapters/ch03.asciidoc",

From a300f316ce379588d027d20042d6b92dad3a6bfb Mon Sep 17 00:00:00 2001
From: jbilling <jbilling@oreilly.com>
Date: Mon, 9 Oct 2017 13:19:58 -0700
Subject: [PATCH 03/71] Edited sections/copyright.html with Atlas code editor

---
 sections/copyright.html | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/sections/copyright.html b/sections/copyright.html
index 0dc9163..80d4693 100644
--- a/sections/copyright.html
+++ b/sections/copyright.html
@@ -1,11 +1,11 @@
 <section data-type="copyright-page"><!--TITLE-->
-<h1>Modular ES6</h1>
+<h1>Mastering Modular Javascript</h1>
 <!--AUTHOR-->
 
 <p class="author">by Nicolás Bevacqua</p>
 <!-- COPYRIGHT -->
 
-<p class="copyright">Copyright © 2016 ???. All rights reserved.</p>
+<p class="copyright">Copyright © 2017 Nicolás Bevacqua. All rights reserved.</p>
 
 <p class="printlocation">Printed in the United States of America.</p>
 <!--PUBLISHER-->
@@ -17,10 +17,7 @@ <h1>Modular ES6</h1>
 
 <ul class="stafflist">
 	<li><span class="staffrole">Editor: </span>Allyson MacDonald</li>
-	<li><span class="staffrole">Production Editor: </span>TO COME</li>
-	<li><span class="staffrole">Copyeditor: </span>TO COME</li>
-	<li><span class="staffrole">Proofreader: </span>TO COME</li>
-	<li><span class="staffrole">Indexer: </span>TO COME</li>
+	<li><span class="staffrole">Production Editor: </span>Justin Billing</li>
 	<li><span class="staffrole">Interior Designer: </span>David Futato</li>
 	<li><span class="staffrole">Cover Designer: </span>TO COME</li>
 	<li><span class="staffrole">Illustrator: </span>Rebecca Demarest</li>
@@ -28,15 +25,15 @@ <h1>Modular ES6</h1>
 <!-- PRINTINGS -->
 
 <ul class="printings">
-	<li><span class="printedition">Month Year:</span> First Edition</li>
+	<li><span class="printedition">October 2017:</span> First Edition</li>
 </ul>
 <!-- REVISIONS -->
 
 <div>
-<h1 class="revisions">Revision History for the First Edition</h1>
+<h1 class="revisions">Revision History for the Early Release</h1>
 
 <ul class="releases">
-	<li><span class="revdate">yyyy-mm-dd:</span> First Release</li>
+	<li><span class="revdate">2017-10-10:</span> First Early Release</li>
 </ul>
 </div>
 <!-- ERRATA -->
@@ -51,8 +48,7 @@ <h1 class="revisions">Revision History for the First Edition</h1>
 </div>
 
 <div class="copyright-bottom">
-<p class="isbn">xxx-x-xxx-xxxx-x</p>
+<p class="isbn">978-1-491-95561-1</p>
 
-<p class="printer">[???]</p>
 </div>
 </section>

From 899a2ac42c59e3f2b06003d638e52bb70b6189f7 Mon Sep 17 00:00:00 2001
From: jbilling <jbilling@oreilly.com>
Date: Mon, 9 Oct 2017 13:22:05 -0700
Subject: [PATCH 04/71] Edited sections/copyright.html with Atlas code editor

---
 sections/copyright.html | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sections/copyright.html b/sections/copyright.html
index 80d4693..5b3c941 100644
--- a/sections/copyright.html
+++ b/sections/copyright.html
@@ -5,7 +5,7 @@ <h1>Mastering Modular Javascript</h1>
 <p class="author">by Nicolás Bevacqua</p>
 <!-- COPYRIGHT -->
 
-<p class="copyright">Copyright © 2017 Nicolás Bevacqua. All rights reserved.</p>
+<p class="copyright">Copyright ©2017 Nicolás Bevacqua. All rights reserved.</p>
 
 <p class="printlocation">Printed in the United States of America.</p>
 <!--PUBLISHER-->
@@ -19,7 +19,7 @@ <h1>Mastering Modular Javascript</h1>
 	<li><span class="staffrole">Editor: </span>Allyson MacDonald</li>
 	<li><span class="staffrole">Production Editor: </span>Justin Billing</li>
 	<li><span class="staffrole">Interior Designer: </span>David Futato</li>
-	<li><span class="staffrole">Cover Designer: </span>TO COME</li>
+	<li><span class="staffrole">Cover Designer: </span>Karen Montgomery</li>
 	<li><span class="staffrole">Illustrator: </span>Rebecca Demarest</li>
 </ul>
 <!-- PRINTINGS -->
@@ -38,7 +38,7 @@ <h1 class="revisions">Revision History for the Early Release</h1>
 </div>
 <!-- ERRATA -->
 
-<p class="errata">See <a href="http://oreilly.com/catalog/errata.csp?isbn=9781449370787">http://oreilly.com/catalog/errata.csp?isbn=9781449370787</a> for release details.</p>
+<p class="errata">See <a href="http://oreilly.com/catalog/errata.csp?isbn=9781491955680">http://oreilly.com/catalog/errata.csp?isbn=9781491955680</a> for release details.</p>
 <!--LEGAL-->
 
 <div class="legal">

From 13c18aa1f8e160515f709bbf54cd82025106aa49 Mon Sep 17 00:00:00 2001
From: jbilling <jbilling@oreilly.com>
Date: Mon, 9 Oct 2017 13:23:00 -0700
Subject: [PATCH 05/71] Edited sections/copyright.html with Atlas code editor

---
 sections/copyright.html | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/sections/copyright.html b/sections/copyright.html
index 5b3c941..6d309de 100644
--- a/sections/copyright.html
+++ b/sections/copyright.html
@@ -42,13 +42,12 @@ <h1 class="revisions">Revision History for the Early Release</h1>
 <!--LEGAL-->
 
 <div class="legal">
-<p>The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. <em>book title</em>, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc.</p>
+<p>The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. <em>Mastering Modular Javascript</em>, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc.</p>
 
-<p>While the publisher and the authors have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the authors disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights. <!--PROD: Uncomment the following sentence if appropriate and add it to the above para:--><!--This book is not intended as [legal/medical/financial; use the appropriate reference] advice. Please consult a qualified professional if you require [legal/medical/financial] advice.--></p>
+<p>While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights. <!--PROD: Uncomment the following sentence if appropriate and add it to the above para:--><!--This book is not intended as [legal/medical/financial; use the appropriate reference] advice. Please consult a qualified professional if you require [legal/medical/financial] advice.--></p>
 </div>
 
 <div class="copyright-bottom">
 <p class="isbn">978-1-491-95561-1</p>
-
 </div>
 </section>

From 3a5f59205f9615b87d1e640e5430598032d37ca2 Mon Sep 17 00:00:00 2001
From: jbilling <jbilling@oreilly.com>
Date: Mon, 9 Oct 2017 13:24:58 -0700
Subject: [PATCH 06/71] Edited sections/copyright.html with Atlas code editor

---
 sections/copyright.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sections/copyright.html b/sections/copyright.html
index 6d309de..3629c37 100644
--- a/sections/copyright.html
+++ b/sections/copyright.html
@@ -12,7 +12,7 @@ <h1>Mastering Modular Javascript</h1>
 
 <p class="publisher">Published by <span class="publishername">O’Reilly Media, Inc.</span>, 1005 Gravenstein Highway North, Sebastopol, CA 95472.</p>
 
-<p>O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (<a href="http://safaribooksonline.com">http://safaribooksonline.com</a>). For more information, contact our corporate/institutional sales department: 800-998-9938 or <span data-type="email">corporate@oreilly.com</span>.</p>
+<p>O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (<a href="http://safaribooksonline.com">http://safaribooksonline.com</a>). For more information, contact our corporate/institutional sales department: 800-998-9938 or <a data-type="email" href="mailto:corporate@oreilly.com"><em class="hyperlink">corporate@oreilly.com</em></a></p>
 <!--STAFF LIST-->
 
 <ul class="stafflist">

From 3ae275736c0767af34e596dd7ba3411299b5795e Mon Sep 17 00:00:00 2001
From: jbilling <jbilling@oreilly.com>
Date: Mon, 9 Oct 2017 13:25:32 -0700
Subject: [PATCH 07/71] Edited sections/copyright.html with Atlas visual editor

---
 sections/copyright.html | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sections/copyright.html b/sections/copyright.html
index 3629c37..be66ab2 100644
--- a/sections/copyright.html
+++ b/sections/copyright.html
@@ -1,5 +1,5 @@
 <section data-type="copyright-page"><!--TITLE-->
-<h1>Mastering Modular Javascript</h1>
+<h1>Mastering Modular JavaScript</h1>
 <!--AUTHOR-->
 
 <p class="author">by Nicolás Bevacqua</p>
@@ -12,7 +12,7 @@ <h1>Mastering Modular Javascript</h1>
 
 <p class="publisher">Published by <span class="publishername">O’Reilly Media, Inc.</span>, 1005 Gravenstein Highway North, Sebastopol, CA 95472.</p>
 
-<p>O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (<a href="http://safaribooksonline.com">http://safaribooksonline.com</a>). For more information, contact our corporate/institutional sales department: 800-998-9938 or <a data-type="email" href="mailto:corporate@oreilly.com"><em class="hyperlink">corporate@oreilly.com</em></a></p>
+<p>O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (<a href="http://safaribooksonline.com">http://safaribooksonline.com</a>). For more information, contact our corporate/institutional sales department: 800-998-9938 or <a data-type="email" href="mailto:corporate@oreilly.com"><em class="hyperlink">corporate@oreilly.com</em></a>.</p>
 <!--STAFF LIST-->
 
 <ul class="stafflist">
@@ -42,7 +42,7 @@ <h1 class="revisions">Revision History for the Early Release</h1>
 <!--LEGAL-->
 
 <div class="legal">
-<p>The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. <em>Mastering Modular Javascript</em>, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc.</p>
+<p>The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. <em>Mastering Modular JavaScript</em>, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc.</p>
 
 <p>While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights. <!--PROD: Uncomment the following sentence if appropriate and add it to the above para:--><!--This book is not intended as [legal/medical/financial; use the appropriate reference] advice. Please consult a qualified professional if you require [legal/medical/financial] advice.--></p>
 </div>

From 4771f91f06fa6a795c1b3670c266f17de40faa64 Mon Sep 17 00:00:00 2001
From: jbilling <jbilling@oreilly.com>
Date: Mon, 9 Oct 2017 13:26:41 -0700
Subject: [PATCH 08/71] Edited sections/titlepage.html with Atlas code editor

---
 sections/titlepage.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sections/titlepage.html b/sections/titlepage.html
index e9e9e19..202560b 100644
--- a/sections/titlepage.html
+++ b/sections/titlepage.html
@@ -1,5 +1,5 @@
 <section data-type="titlepage">
-<h1>Modular ES6</h1>
+<h1>Mastering Modular JavaScript</h1>
 <!--(only include edition line if it's 2e or higher -->
 
 <p class="author">Nicolás Bevacqua</p>

From f582b7ac8b38f745ecd653ab9a343d52c895892a Mon Sep 17 00:00:00 2001
From: jbilling <jbilling@oreilly.com>
Date: Mon, 9 Oct 2017 13:33:01 -0700
Subject: [PATCH 09/71] Edited theme/epub/layout.html with Atlas code editor

---
 theme/epub/layout.html | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/theme/epub/layout.html b/theme/epub/layout.html
index 213896d..6eca804 100644
--- a/theme/epub/layout.html
+++ b/theme/epub/layout.html
@@ -1,15 +1,15 @@
 {{ doctype }}
 <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
-  <head>
-    <meta charset="utf-8" />
-    <meta name="publisher" content="O'Reilly Media, Inc."/>
-    <meta name="author" content="AUTHOR NAMES HERE"/>
-    <meta name="date" content="RETAIL AVAILABILITY DATE FROM PDB MANUFACTURING TAB HERE IN YYYY-MM-DD FORM (e.g., 2014-07-07)"/>
-    <meta name="description" content="BOOK MARKETING DESCRIPTION HERE. (This can be supplied by the author, but otherwise the Consumer Short Text from the Marketing tab in the PDB works here - just make sure not to paste curly quotes or em dashes! Replace with straight quotes and hyphens.)"/>
-    <meta name="identifier" content="TECH-BOOK-ISBN-13"/>
-    <title>{{ title }}</title>
-  </head>
-  <body data-type="book">
-    {{ content }}
-  </body>
+ <head>
+  <title>{{ title }}</title>
+  <meta charset="utf-8" />
+  <meta name="publisher" content="O'Reilly Media, Inc."/>
+  <meta name="author" content="Nicolás Bevacqua"/>
+  <meta name="date" content="2017-10-10"/>
+  <meta name="description" content="With this practical guide, frontend and backend Node.js developers alike will learn how to scale out JavaScript applications by breaking codebases into smaller modules. Author Nicolas Bevacqua covers features in ECMAScript 6 (ES6; the latest version of the specification that includes JavaScript) that support modularization. If you have a working knowledge of JavaScript, this book is for you."/>
+  <meta name="identifier" content="978-1-491-95568-0"/>
+ </head>
+ <body data-type="book">
+ {{ content }}
+ </body>
 </html>

From b5662d55ca48c10e9b0b59020b086e6f7675cadf Mon Sep 17 00:00:00 2001
From: jbilling <jbilling@oreilly.com>
Date: Mon, 9 Oct 2017 13:33:31 -0700
Subject: [PATCH 10/71] Edited theme/mobi/layout.html with Atlas code editor

---
 theme/mobi/layout.html | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/theme/mobi/layout.html b/theme/mobi/layout.html
index 213896d..6eca804 100644
--- a/theme/mobi/layout.html
+++ b/theme/mobi/layout.html
@@ -1,15 +1,15 @@
 {{ doctype }}
 <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
-  <head>
-    <meta charset="utf-8" />
-    <meta name="publisher" content="O'Reilly Media, Inc."/>
-    <meta name="author" content="AUTHOR NAMES HERE"/>
-    <meta name="date" content="RETAIL AVAILABILITY DATE FROM PDB MANUFACTURING TAB HERE IN YYYY-MM-DD FORM (e.g., 2014-07-07)"/>
-    <meta name="description" content="BOOK MARKETING DESCRIPTION HERE. (This can be supplied by the author, but otherwise the Consumer Short Text from the Marketing tab in the PDB works here - just make sure not to paste curly quotes or em dashes! Replace with straight quotes and hyphens.)"/>
-    <meta name="identifier" content="TECH-BOOK-ISBN-13"/>
-    <title>{{ title }}</title>
-  </head>
-  <body data-type="book">
-    {{ content }}
-  </body>
+ <head>
+  <title>{{ title }}</title>
+  <meta charset="utf-8" />
+  <meta name="publisher" content="O'Reilly Media, Inc."/>
+  <meta name="author" content="Nicolás Bevacqua"/>
+  <meta name="date" content="2017-10-10"/>
+  <meta name="description" content="With this practical guide, frontend and backend Node.js developers alike will learn how to scale out JavaScript applications by breaking codebases into smaller modules. Author Nicolas Bevacqua covers features in ECMAScript 6 (ES6; the latest version of the specification that includes JavaScript) that support modularization. If you have a working knowledge of JavaScript, this book is for you."/>
+  <meta name="identifier" content="978-1-491-95568-0"/>
+ </head>
+ <body data-type="book">
+ {{ content }}
+ </body>
 </html>

From 0ea2ea77061fdbcb76a5a976212affa4429597f6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Wed, 4 Oct 2017 20:11:02 -0300
Subject: [PATCH 11/71] start on ch05

---
 chapters/ch05.asciidoc | 55 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 49 insertions(+), 6 deletions(-)

diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index bd2914f..d0e957d 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -1,21 +1,64 @@
 [[modular-patterns-and-practices]]
 == Modular Patterns and Practices
 
-..
+In this chapter we'll take a look at some of the latest language features and how we can leverage those in our programs while reducing complexity in the process. We'll also analyze concrete coding patterns and conventions that can help us develop simple alternatives to otherwise complex problems.
 
 === 5.1 Leveraging Modern JavaScript
 
-# discuss role of latest language features, spread, how they can make code more maintainable, async/await, promises, etc
+When used conscientiously, the latest JavaScript features can be of great help in reducing the amount of code whose sole purpose is to work around language limitations, increasing signal -- the amount of valuable information that can be extracted from reading a piece of code -- while eliminating boilerplate and repetition.
+
+==== 5.1.1 Template Literals
+
+Before ES6, the JavaScript community came up with half a dozen ways of arriving at multi-line strings: from strings chained with `\` escape characters or `+` arithmetic operators, to using `Array#join`, or resorting to the string representation of comments in a function -- all merely for multi-line support.
+
+Further, inserting variables into a string isn't possible, but that's easily circumvented by concatenating them with one or more strings.
+
+[source,javascript]
+----
+'Hello ' + name + ', I\'m Nicolás!'
+----
+
+Template literals arrived in ES6 and resolve multi-line strings in a feature that was native to the language, without the need for any clever hacks in user-space.
+
+Unlike strings, with template literals we can interpolate expressions using a streamlined syntax. They involve less escaping, too, thanks to using backticks instead of single or double quotation marks, which appear more frequently in English text.
+
+[source,javascript]
+----
+`Hello ${ name }, I'm Nicolás!`
+----
+
+Besides these improvements, template literals also offer the possibility of tagged templates. You can prefix the template with a custom function that transforms the template's output use cases like input sanitization, formatting, or anything else.
+
+Whenever we need to compose a string using data, template literals are a terse alternative to string concatenation. When we want to avoid escaping single or double quotes, template literals can help. The same is true when we want to write multi-line strings.
+
+In every other case -- when there's no interpolation, escaping, or multi-line needs -- the choice comes down to a mere matter of style. In the last chapter of Practical Modern JavaScript, "Practical Considerations", I advocatedfootnoteref:[template-literals,You can read a blog post I wrote about why template literals are better than strings at: https://mjavascript.com/out/template-literals. Practical Modern JavaScript (O'Reilly, 2017) is the first book in the Modular JavaScript series. You're currently reading the second book of the same series.] in favor of using template literals in every case. This was for a few factors, but here's the two most important ones: because of convenience, so that you don't have to convert a string back and forth between single quoted string and template literals depending on its contents; and because of consistency, so that you don't have to stop and think about which kind of quotation mark -- single, double, or backtick -- to use each time. Template literals may take some time to get accustomed to: we've used single quoted strings for a long time, and template literals have only been around for a while. You or your team might prefer sticking with single quoted strings, and that's perfectly fine too.
+
+[NOTE]
+====
+When it comes to style choices, you'll rarely face problems if you let your team come to a consensus about the preferred style choice and later enforce that choice by way of a lint tool like ESLint. It's entirely valid ot stick with single quoted strings and only use template literals when deemed absolutely necessary, if that's what most of the team prefers.
+
+Using a tool like ESLint and a continuous integration job to enforce its rules means nobody has to perform the time consuming job of keeping everyone in line with the house style. When tooling enforces style choices, discussions about those choices won't crop up as often in discussion threads while contributors are collaborating on units of work.
+====
+
+It's important to differentiate between purely stylistic choices, which tend to devolve in contentious time-sinking discussions, and choices where there's more ground to be covered in the everlasting battle against complexity.
+
+==== 5.1.2 Destructuring, Rest, and Spread
+
+
 
-==== 5.1.1 Destructuring, Rest, Spread, and Template Literals
 
 .. how each of these features helps us keep code simpler, or how to simplify existing code using them.
 
-==== 5.1.2 Striving for simple `const` bindings
+
+
+
+
+
+==== 5.1.3 Striving for simple `const` bindings
 
 .. thinking about how `let` and `var` may mean we're doing complicated things, and how striving to avoid those bindings almost always leads to better/simpler code.
 
-==== 5.1.3 Asynchronous Functions and Promises
+==== 5.1.4 Asynchronous Functions and Promises
 
 .. why converting flows to promises may be a good way of simplifying it, on the basis that a lot of the language now is built around support for promises
 
@@ -35,7 +78,7 @@ how we can decorate components either via composition or decorators to add featu
 
 in real apps you'll seldom have to use inheritance except when connecting to specific frameworks you depend on, or for specific patterns, everywhere else probably use composition [ellaborate on that]
 
-==== 5.3 Code Patterns
+=== 5.3 Code Patterns
 
 ..
 

From 3bff8f1a0a10d00d49d4c9ffb29e790c253f0485 Mon Sep 17 00:00:00 2001
From: jbilling <jbilling@oreilly.com>
Date: Wed, 11 Oct 2017 08:54:05 -0700
Subject: [PATCH 12/71] Updated atlas.json

---
 atlas.json | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/atlas.json b/atlas.json
index 3389f65..aaed592 100644
--- a/atlas.json
+++ b/atlas.json
@@ -1,11 +1,5 @@
 {
   "branch": "master",
-  "name": "bevacqua/mastering-modular-javascript",
-  "title": "Mastering Modular JavaScript",
-  "export_formats": [
-    "html",
-    "pdf"
-  ],
   "files": [
     "sections/cover.html",
     "sections/cover.html",
@@ -25,7 +19,7 @@
       "syntaxhighlighting": true,
       "show_comments": false,
       "color_count": false,
-      "trim_size": "7inx9.1875in"
+      "trim_size": "6inx9in"
     },
     "epub": {
       "toc": true,
@@ -51,8 +45,14 @@
     }
   },
   "theme": "oreillymedia/animal_theme",
+  "title": "Mastering Modular JavaScript",
+  "name": "bevacqua/mastering-modular-javascript",
+  "export_formats": [
+    "html",
+    "pdf"
+  ],
   "templating": false,
   "print_isbn13": "",
   "lang": "en",
   "accent_color": "cmyk(100%, 3%, 50%, 0%)"
-}
+}
\ No newline at end of file

From 2a037bbd967006324bf4b9092faae9a93343ddb9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Thu, 11 Jan 2018 12:49:07 -0300
Subject: [PATCH 13/71] moving

---
 chapters/ch05.asciidoc | 99 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 96 insertions(+), 3 deletions(-)

diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index d0e957d..a9107f6 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -40,26 +40,119 @@ When it comes to style choices, you'll rarely face problems if you let your team
 Using a tool like ESLint and a continuous integration job to enforce its rules means nobody has to perform the time consuming job of keeping everyone in line with the house style. When tooling enforces style choices, discussions about those choices won't crop up as often in discussion threads while contributors are collaborating on units of work.
 ====
 
-It's important to differentiate between purely stylistic choices, which tend to devolve in contentious time-sinking discussions, and choices where there's more ground to be covered in the everlasting battle against complexity.
+It's important to differentiate between purely stylistic choices, which tend to devolve in contentious time-sinking discussions, and choices where there's more ground to be covered in the everlasting battle against complexity. While the former may make a codebase subjectively easier to read, or aesthetically pleasing, it is only through deliberate action that we'll keep complexity in check. Granted, a consistent style throughout a codebase can help contain complexity, but the exact style is unimportant as long as we enforce it consistently.
 
 ==== 5.1.2 Destructuring, Rest, and Spread
 
+The destructuring, rest and spread features came into effect in ES6. These features accomplish a number of different things, which we'll now discuss.
 
+Destructuring helps us indicate the fields of an object that we'll be using to compute the output of a function. In the following example, we destructure a few properties from a `ticker` variable, and then combine that with a `...details` rest pattern containing every property of `ticker` that we haven't explicitly named in our destructuring pattern.
 
+[source,javascript]
+----
+const { low, high, ask, ...details } = ticker
+----
 
-.. how each of these features helps us keep code simpler, or how to simplify existing code using them.
+When we use destructuring methodically and near the top of our functions, or -- even better -- in the parameter list, we are making it obvious what the exact contract of our function is in terms of inputs.
 
+Deep destructuring offers the ability to take this one step further, digging as deep as necessary into the structure of the object we're accessing. Consider the following example, where we destructure the JSON response body with details about an apartment. When we have a destructuring statement like this near the top of a function that's used to render a view, the aspects of the apartment listing are needed to render it become self-evident at a glance. In addition, we avoid repetition when accessing property chains like `response.contact.name` or `response.contact.phone`.
 
+[source,javascript]
+----
+const {
+  title,
+  description,
+  askingPrice,
+  features: {
+    area,
+    bathrooms,
+    bedrooms,
+    amenities
+  },
+  contact: {
+    name,
+    phone,
+    email
+  }
+} = response
+----
 
+One contention point might be that, at times, the deeply destructured property name doesn't make sense outside of its context. For instance, we've introduce `name` to our scope, but it's the name of the contact for the listing, not to be confused with the name of the listing itself. In these cases, the alternative may be to give `response.contact.name` an alias whereby we add the parent property as a prefix, so that we're left with `name: contactName`.
 
+Object spread helps us create a shallow copy of an object using a little native syntax. We can also combine object spread with our own properties, so that we create a copy that also overwrites the values in the original object we're spreading.
 
+[source,javascript]
+----
+const faxCopy = { ...fax }
+const newCopy = { ...fax, date: new Date() }
+----
+
+This allows us to create slightly modified shallow copies of other objects. When dealing with discrete state management, this means we don't need to resort to `Object.assign` method calls or utility libraries. While there's nothing inherently wrong with `Object.assign` calls, the object spread `...` abstraction is easier for us to internalize and mentally map its meaning back to `Object.assign` without us realizing it, and so the code becomes easier to read because we're dealing with less unabstracted knowledge.
 
 ==== 5.1.3 Striving for simple `const` bindings
 
-.. thinking about how `let` and `var` may mean we're doing complicated things, and how striving to avoid those bindings almost always leads to better/simpler code.
+If we use `const` by default, then the need to use `let` or `var` can be ascribed to code that's more complicated than it should be. Striving to avoid those kinds of bindings almost always leads to better and simpler code.
+
+In section 4.2.4 we've looked into the case where a `let` binding is assigned a default value, and have conditional statements immediately after, that might change the contents of the variable binding.
+
+[source,javascript]
+----
+// …
+let type = 'contributor'
+if (user.administrator) {
+  type = 'administrator'
+} else if (user.roles.includes('edit_articles')) {
+  type = 'editor'
+}
+// …
+----
+
+Most reasons why we may need to use `let` or `var` bindings are variants of the above and can be resolved by extracting the assignments into a function where the returned value is then assigned to a `const` binding. This moves the complexity out of the way, and eliminates the need for looking ahead to see if the binding is reassigned at some point in the code flow later on.
+
+[source,javascript]
+----
+// …
+const type = getUserType(user)
+// …
+
+function getUserType(user) {
+  if (user.administrator) {
+    return 'administrator'
+  }
+  if (user.roles.includes('edit_articles')) {
+    return 'editor'
+  }
+  return 'contributor'
+}
+----
+
+A variation of this problem is when we repeatedly assign the result of an operation to the same binding, in order to split it into several lines.
+
+[source,javascript]
+----
+let values = [1, 2, 3, 4, 5]
+values = values.map(value => value * 2)
+values = values.filter(value => value > 5)
+// <- [6, 8, 10]
+----
+
+A better approach would be to create new bindings every time, computing their values based on the previous binding, and picking up the benefits of using `const` in doing so -- where we can rest assured that the binding doesn't change later in the flow.
+
+[source,javascript]
+----
+const initialValues = [1, 2, 3, 4, 5]
+const doubledValues = initialValues.map(value => value * 2)
+const finalValues = doubledValues.filter(value => value > 5)
+// <- [6, 8, 10]
+----
+
+Let's move onto a more interesting topic: asynchronous code flows.
 
 ==== 5.1.4 Asynchronous Functions and Promises
 
+
+
+
 .. why converting flows to promises may be a good way of simplifying it, on the basis that a lot of the language now is built around support for promises
 
 === 5.2 Composition and Inheritance

From 2d01f3f8605b39e0de3033a71f72211d2ea530af Mon Sep 17 00:00:00 2001
From: Justin Lee <justinlee0022@gmail.com>
Date: Fri, 9 Feb 2018 10:34:07 -0800
Subject: [PATCH 14/71] Update ch01.asciidoc

Fixed typo, asynchrnous -> asynchronous
---
 chapters/ch01.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch01.asciidoc b/chapters/ch01.asciidoc
index 3d6a6f0..68b51c1 100644
--- a/chapters/ch01.asciidoc
+++ b/chapters/ch01.asciidoc
@@ -200,7 +200,7 @@ We can apply modular design concepts on every level of a given system. If a proj
 
 When we want to make an application more maintainable, we should consider creating explicitly defined layers of code, so that we can grow each layer horizontally while preventing the complexity of those additions from spreading to other, unrelated, layers. The same thought process can be applied to individual components, splitting them into two or more smaller components that are then tied together by yet another small component, which could act as a composition layer whose sole responsibility is knitting together several underlying components.
 
-At the module level, we should strive to keep functions simple and expressive, with descriptive names and not too many responsibilities. Maybe we'll have a function dedicated exclusively to broidering together a group of tasks under a particular asynchrnous flow, while having other functions for each task that we need to perform within that control flow. The topmost flow controlling function could be exposed as a public interface method for our module, but the only part of it that should be treated as public interface are the parameters that we receive as inputs for that function and the output produced by that same topmost function. Everything else becomes an implementation detail and is, as such, to be considered swappable.
+At the module level, we should strive to keep functions simple and expressive, with descriptive names and not too many responsibilities. Maybe we'll have a function dedicated exclusively to broidering together a group of tasks under a particular asynchronous flow, while having other functions for each task that we need to perform within that control flow. The topmost flow controlling function could be exposed as a public interface method for our module, but the only part of it that should be treated as public interface are the parameters that we receive as inputs for that function and the output produced by that same topmost function. Everything else becomes an implementation detail and is, as such, to be considered swappable.
 
 The internal functions of a module won't have as rigid of an interface either: as long as the public interface holds, we can change the implementation -- including the interfaces of functions that make up that implementation -- however we want. This is not to say, however, that we should treat those interfaces any less deliberately. The key to proper modular design is in having an utmost respect for all interfaces, and that includes the interfaces exposed by internal functions.
 

From feb354c1df331b38457c772f5c401ce8a0dac6a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Mon, 19 Mar 2018 02:59:23 -0300
Subject: [PATCH 15/71] getting back on track

---
 chapters/ch05.asciidoc | 98 +++++++++++++++++++++++++++++++++++++-----
 chapters/ch07.asciidoc | 16 -------
 2 files changed, 87 insertions(+), 27 deletions(-)
 delete mode 100644 chapters/ch07.asciidoc

diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index a9107f6..c2572d4 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -5,7 +5,7 @@ In this chapter we'll take a look at some of the latest language features and ho
 
 === 5.1 Leveraging Modern JavaScript
 
-When used conscientiously, the latest JavaScript features can be of great help in reducing the amount of code whose sole purpose is to work around language limitations, increasing signal -- the amount of valuable information that can be extracted from reading a piece of code -- while eliminating boilerplate and repetition.
+When used judiciously, the latest JavaScript features can be of great help in reducing the amount of code whose sole purpose is to work around language limitations. This increases signal -- the amount of valuable information that can be extracted from reading a piece of code -- while eliminating boilerplate and repetition.
 
 ==== 5.1.1 Template Literals
 
@@ -77,7 +77,7 @@ const {
 } = response
 ----
 
-One contention point might be that, at times, the deeply destructured property name doesn't make sense outside of its context. For instance, we've introduce `name` to our scope, but it's the name of the contact for the listing, not to be confused with the name of the listing itself. In these cases, the alternative may be to give `response.contact.name` an alias whereby we add the parent property as a prefix, so that we're left with `name: contactName`.
+One contention point might be that, at times, the deeply destructured property name doesn't make sense outside of its context. For instance, we've introduce `name` to our scope, but it's the name of the contact for the listing, not to be confused with the name of the listing itself. In these cases, the alternative may be to give `response.contact.name` an alias where we add the parent property name as a prefix, so that we're left with a binding named `contactName` or `responseContactName`.
 
 Object spread helps us create a shallow copy of an object using a little native syntax. We can also combine object spread with our own properties, so that we create a copy that also overwrites the values in the original object we're spreading.
 
@@ -93,7 +93,7 @@ This allows us to create slightly modified shallow copies of other objects. When
 
 If we use `const` by default, then the need to use `let` or `var` can be ascribed to code that's more complicated than it should be. Striving to avoid those kinds of bindings almost always leads to better and simpler code.
 
-In section 4.2.4 we've looked into the case where a `let` binding is assigned a default value, and have conditional statements immediately after, that might change the contents of the variable binding.
+In section 4.2.4 we looked into the case where a `let` binding is assigned a default value, and have conditional statements immediately after, that might change the contents of the variable binding.
 
 [source,javascript]
 ----
@@ -126,7 +126,7 @@ function getUserType(user) {
 }
 ----
 
-A variation of this problem is when we repeatedly assign the result of an operation to the same binding, in order to split it into several lines.
+A variant of this problem is when we repeatedly assign the result of an operation to the same binding, in order to split it into several lines.
 
 [source,javascript]
 ----
@@ -148,24 +148,100 @@ const finalValues = doubledValues.filter(value => value > 5)
 
 Let's move onto a more interesting topic: asynchronous code flows.
 
-==== 5.1.4 Asynchronous Functions and Promises
+==== 5.1.4 Navigating Callbacks, Promises, and Asynchronous Functions
 
+JavaScript now offers several options when it comes to describing asynchronous algorithms: the plain callback pattern, promises, async functions, async iterators, async generators, plus any patterns offered by libraries consumed in our applications. Each solution comes with their own set of strengths and weaknesses: callbacks are typically a solid choice, but we often need to get libraries involved when we want to execute our work concurrently; Promises might be hard to understand at first, but they offer a few utilities like `Promise#all` for concurrent work, yet they might be hard to debug under some circumstances; Async functions require a bit of understanding on top of being comfortable with promises, but they're easier to debug and often result in simpler code, plus they can be interspersed with synchronous functions rather easily as well; Iterators and generators are powerful tools, but there aren't many practical use cases for them, so we must consider whether we're using them because they fit our needs or just because we can.
 
+It could be argued that callbacks are the simplest mechanism, although a similar case could be made for promises now that so much of the language is built around them. In any case, consistency should remain as the primary driving force of how we decide which pattern to use. While it's okay to mix and match a few different patterns, most of the time we should be using the same patterns again and again, so that our team can develop a sense of familiarity with the codebase, instead of having to take a guess whenever encountering an unchartered portion of the application.
 
+Using promises and async functions inevitably involves casting callbacks into this pattern. In the following example we make up a `delay` function that returns promises which settle after a provided timeout.
 
-.. why converting flows to promises may be a good way of simplifying it, on the basis that a lot of the language now is built around support for promises
+[source,javascript]
+----
+function delay(timeout) {
+  const resolver = resolve => {
+    setTimeout(() => {
+      resolve()
+    }, timeout)
+  }
+  return new Promise(resolver))
+}
+delay(2000).then(…)
+----
+
+A similar pattern would have to be used to consume functions taking a last argument that's an error-first callback style function in Node.js. Starting with Node.js v8.0.0, however, there's a utility built-in that "promisifies" these callback-based functions so that they return promises.
+
+[source,javascript]
+----
+import { promisify } from 'util'
+import { readFile } from 'fs'
+const readFilePromise = promisify(readFile)
+
+readFilePromise('./data.json', 'utf8').then(data => {
+  console.log(`Data: ${ data }`)
+})
+----
+
+There are libraries that could do the same for the client-side, one such example being `bluebird`, or we can create our own `promisify`. In essence, `promisify` takes the function that we want to use in promise-based flows, and returns a different -- "promisified" -- function which returns a promise where we call the original function passing all the provided arguments plus our own callback, where we settle the promise after deciding whether it should be fulfilled or rejected.
+
+[source,javascript]
+----
+function promisify(fn) {
+  return (...rest) => {
+    return new Promise((resolve, reject) => {
+      fn(...rest, (err, result) => {
+        if (err) {
+          reject(err)
+          return
+        }
+        resolve(result)
+      })
+    })
+  }
+}
+----
+
+Casting promises back into a callback-based format is less involved because we can add reactions to handle both the fulfillment and rejection results, and call back `done` passing in the corresponding result where appropriate.
+
+[source,javascript]
+----
+function unpromisify(p, done) {
+  p.then(
+    data => done(null, data),
+    error => done(error)
+  )
+}
+unpromisify(delay(2000), err => {
+  // …
+})
+----
+
+Lastly, when it comes to converting promises to async functions, the language acts as a native compatibility layer, boxing every expression we `await` on into promises, so there's no need for any casting at the application level.
+
+We can apply our guidelines of what constitutes clear code to asynchronous code flows just as well, since there aren't fundamental differences at play in the way we write these functions. Our focus should be on how these flows are connected together, regardless of whether they're comprised of callbacks, promises, or something else. When plumbing tasks together, one of the main sources of complexity is nesting. When several tasks are nested in a tree-like shape, we might end up with code that's deeply nested. One of the best solutions to this readability problem is to break our flow into smaller trees, which would consequently be more shallow. We'll have to connect these trees together by adding a few extra function calls, but we'll have removed significant complexity when trying to understand the general flow of operations.
 
 === 5.2 Composition and Inheritance
 
-..
+Let's explore how we can improve our application designs beyond what JavaScript offers purely at the language level. In this section we'll discuss two different approaches to growing parts of a codebase: inheritance, where we scale vertically by stacking pieces of code on top of each other so that we can leverage existing features while customizing others and adding our own; and composition, where we scale our application horizontally by adding related or unrelated pieces of code at the same level of abstraction while keeping complexity to a minimum.
 
-==== 5.2.1 Aspects and Decorators
+==== 5.2.1 The Perks of Inheritance
 
-how we can decorate components either via composition or decorators to add features to them, and reuse that logic for other kinds of components..
+Up until ES6 introduced first-class syntax for prototypal inheritance to JavaScript, it wasn't a widely used feature in user-land. However, with the introduction of a `class` keyword, paired with the React framework hailing classes as the go-to way of declaring stateful components, classes have shed some light on a pattern that was previously unpopular (at least when it comes to JavaScript).
+
+Inheritance is useful when there's an abstract interface to implement and methods to override, particularly when the objects being represented can be mapped to the real world. In practical terms and in the case of JavaScript, inheritance works great when the prototype being extended offers a good description for the parent prototype: a `Car` is a `Vehicle`, but a car is not a `SteeringWheel`, the wheel is just one aspect of the car.
 
-==== 5.2.2 The Perks of Inheritance
+In the case of React, the `Component` class dictates the standard behavior and lifecycle of components, while leaving the rendering up to the inheriting class. When necessary, the consumer can also decide to implement methods such as `componentDidMount`, which allows for event binding after a component tree is mounted; `componentDidCatch`, which can be used to trap unhandled exceptions anywhere in the component lifecycle; among a variety of other virtual methods.
 
-.. how inheritance can be useful when there's an abstract interface to implement and methods to override, thinking of React's Component in terms of `render()` being an abstract method to be implemented and pretty much every other method being a virtual method [in C# terms], explains benefits of these kinds of contracts. maybe hint at 5.5.2 protocols
+
+
+
+
+
+
+
+==== 5.2.2 Composition: Aspects and Decorators
+
+how we can decorate components either via composition or decorators to add features to them, and reuse that logic for other kinds of components..
 
 ==== 5.2.3 Choosing between Composition and Inheritance
 
diff --git a/chapters/ch07.asciidoc b/chapters/ch07.asciidoc
deleted file mode 100644
index 49a9d7b..0000000
--- a/chapters/ch07.asciidoc
+++ /dev/null
@@ -1,16 +0,0 @@
-[[managing-complexity-across-modules]]
-== Managing Complexity Across Modules
-
-# chapter around ways of reducing complexity across whole module system
-
-# complexity of change across layers/time, drop mention of How Buildings Learn
-
-# managing local state (as an instance factory) vs globally (e.g mongoose.currentConnection)
-
-=== 7.1
-
-..
-
-==== 7.1.1
-
-..

From b88f211e870d9d9477a2324ebb8555992398ce84 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sun, 25 Mar 2018 17:38:14 -0300
Subject: [PATCH 16/71] Inheritance, functional composition, decorators.

---
 chapters/ch05.asciidoc | 109 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 102 insertions(+), 7 deletions(-)

diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index c2572d4..5ca6731 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -224,28 +224,123 @@ We can apply our guidelines of what constitutes clear code to asynchronous code
 
 Let's explore how we can improve our application designs beyond what JavaScript offers purely at the language level. In this section we'll discuss two different approaches to growing parts of a codebase: inheritance, where we scale vertically by stacking pieces of code on top of each other so that we can leverage existing features while customizing others and adding our own; and composition, where we scale our application horizontally by adding related or unrelated pieces of code at the same level of abstraction while keeping complexity to a minimum.
 
-==== 5.2.1 The Perks of Inheritance
+==== 5.2.1 Inheritance through Classes
 
-Up until ES6 introduced first-class syntax for prototypal inheritance to JavaScript, it wasn't a widely used feature in user-land. However, with the introduction of a `class` keyword, paired with the React framework hailing classes as the go-to way of declaring stateful components, classes have shed some light on a pattern that was previously unpopular (at least when it comes to JavaScript).
+Up until ES6 introduced first-class syntax for prototypal inheritance to JavaScript, prototypes weren't a widely used feature in user-land. Instead, libraries offered helper methods that made inheritance simpler, using prototypal inheritance under the hood, but hiding the implementation details from their consumers. Even though ES6 classes look a lot like classes in other languages, they're syntactic sugar using prototypes under the hood, making them compatible with older techniques and libraries.
 
-Inheritance is useful when there's an abstract interface to implement and methods to override, particularly when the objects being represented can be mapped to the real world. In practical terms and in the case of JavaScript, inheritance works great when the prototype being extended offers a good description for the parent prototype: a `Car` is a `Vehicle`, but a car is not a `SteeringWheel`, the wheel is just one aspect of the car.
+The introduction of a `class` keyword, paired with the React framework hailing classes as the go-to way of declaring stateful components, classes have helped spark some love for a pattern that was previously quite unpopular when it comes to JavaScript. In the case of React, the base `Component` class offers lightweight state management methods, while leaving the rendering and lifecycle up to the consumer classes extending `Component`. When necessary, the consumer can also decide to implement methods such as `componentDidMount`, which allows for event binding after a component tree is mounted; `componentDidCatch`, which can be used to trap unhandled exceptions that arise during the component lifecycle; among a variety of other soft interface methods. There's no mention of these optional lifecycle hooks anywhere in the base `Component` class, which are instead confined to the rendering mechanisms of React. In this sense, we note that the `Component` class stays focused on state management, while everything else is offered up by the consumer.
 
-In the case of React, the `Component` class dictates the standard behavior and lifecycle of components, while leaving the rendering up to the inheriting class. When necessary, the consumer can also decide to implement methods such as `componentDidMount`, which allows for event binding after a component tree is mounted; `componentDidCatch`, which can be used to trap unhandled exceptions anywhere in the component lifecycle; among a variety of other virtual methods.
+Inheritance is also useful when there's an abstract interface to implement and methods to override, particularly when the objects being represented can be mapped to the real world. In practical terms and in the case of JavaScript, inheritance works great when the prototype being extended offers a good description for the parent prototype: a `Car` is a `Vehicle` but a car is not a `SteeringWheel`: the wheel is just one aspect of the car.
 
+==== 5.2.2 The Perks of Composition: Aspects and Decorators
 
+With inheritance we can add layers of complexity to an object. These layers are meant to be ordered, we start with the least specific foundational bits of the object and build our way up to the most specific aspects of it. When we write code based on inheritance chains, complexity is spread across the different classes, but lies mostly at the foundational layers which offer a terse API while hiding this complexity away. Composition is an alternative to inheritance. Rather than building objects by vertically stacking functionality, composition relies on stringing together orthogonal aspects of functionality. In this sense, orthogonality means that the bits of functionality we compose together complements each other, but doesn't alter one another's behavior.
 
+One way to compose functionality is additive: we could write decorators, which augment existing objects with new functionality. In the following code snippet we have a `makeEmitter` function which adds flexible event handling functionality to any target object, providing them with an `.on` method, where we can add event listeners to the target object; and an `.emit` method, where the consumer can indicate a type of event and any number of parameters to be passed to event listeners.
 
+[source,javascript]
+----
+function makeEmitter(target) {
+  const listeners = []
+
+  target.on = (eventType, listener) => {
+    if (!(eventType in listeners)) {
+      listeners[eventType] = []
+    }
+
+    listeners[eventType].push(listener)
+  }
+
+  target.emit = (eventType, ...params) => {
+    if (!(eventType in listeners)) {
+      return
+    }
+
+    listeners[eventType].forEach(listener => {
+      listener(...params)
+    })
+  }
+
+  return target
+}
+
+const person = makeEmitter({
+  name: 'Artemisa',
+  age: 27
+})
+
+person.on('move', (x, y) => {
+  console.log(`${ person.name } moved to [${ x }, ${ y }].`)
+})
+
+person.emit('move', 23, 5)
+// <- 'Artemisa moved to [23, 5].'
+----
+
+This approach is versatile, helping us add event emission functionality to any object without the need for adding an `EventEmitter` class somewhere in the prototype chain of the object. This is useful in cases where you don't own the base class, when the targets aren't class-based, or when the functionality to be added isn't meant to be part of every instance of a class: there are persons who emit events and persons that are quiet and don't need this functionality.
+
+Another way of doing composition, that doesn't rely on decorators, is to rely on functional aspects instead, without mutating your target object. In the following snippet we do just that: we have an `emitters` map where we store target objects and map them to the event listeners they have, an `onEvent` function that associates event listeners to target objects, and an `emitEvent` function that fires all event listeners of a given type for a target object, passing the provided parameters. All of this is accomplished in such a way that there's no need to modify the `person` object in order to have event handling capabilities associated with the object.
+
+[source,javascript]
+----
+const emitters = new Map()
+
+function onEvent(target, eventType, listener) {
+  if (!emitters.has(target)) {
+    emitters.set(target, {})
+  }
 
+  const listeners = emitters.get(target)
 
+  if (!(eventType in listeners)) {
+    listeners[eventType] = []
+  }
 
+  listeners[eventType].push(listener)
+}
 
-==== 5.2.2 Composition: Aspects and Decorators
+function emitEvent(target, eventType, ...params) {
+  if (!emitters.has(target)) {
+    return
+  }
 
-how we can decorate components either via composition or decorators to add features to them, and reuse that logic for other kinds of components..
+  const listeners = emitters.get(target)
+
+  if (!(eventType in listeners)) {
+    return
+  }
+
+  listeners[eventType].forEach(listener => {
+    listener(...params)
+  })
+}
+
+const person = {
+  name: 'Artemisa',
+  age: 27
+}
+
+onEvent(person, 'move', (x, y) => {
+  console.log(`${ person.name } moved to [${ x }, ${ y }].`)
+})
+
+emitEvent(person, 'move', 23, 5)
+// <- 'Artemisa moved to [23, 5].'
+----
+
+Let's move onto deciding whether to use inheritance, decorators, or functional composition, where each pattern shines, and when to avoid them.
 
 ==== 5.2.3 Choosing between Composition and Inheritance
 
-in real apps you'll seldom have to use inheritance except when connecting to specific frameworks you depend on, or for specific patterns, everywhere else probably use composition [ellaborate on that]
+In the real world, you'll seldom have to use inheritance except when connecting to specific frameworks you depend on, to apply specific patterns such as extending native JavaScript arrays, or when performance is of the utmost necessity. When it comes to performance as a reason for using prototypes, we should highlight the need to test our assumptions and measure different approaches before jumping all in into a pattern that might not be ideal to work with, for the sake of a performance gain we might not observe.
+
+Decoration and functional composition are friendlier patterns because they aren't as restrictive. Once you inherit from something, you can't later choose to inherit from something else, unless you keep adding inheritance layers to your prototype chain. This becomes a problem when several classes inherit from a base class but they then need to branch out while still sharing different portions of functionality. In these cases and many others, using composition is going to let us pick and choose the functionality we need without sacrificing our flexibility.
+
+The functional approach is a bit more cumbersome to implement than simply mutating objects or adding base classes, but it offers the most flexibility. By avoiding changes to the underlying target, we keep objects easy to serialize into JSON, unencumbered by a growing collection of methods, and thus more readily compatible across our codebase.
+
+Furthermore, using base classes makes it a bit hard to reuse the logic at varying insertion points in our prototype chains. Using decorators, likewise, makes it challenging to add similar methods that support slightly different use cases. Using a functional approach leads to less coupling in this regard, but it could also complicate the underlying implementation of the makeup for objects, making it hard to decypher how their functionality ties in together, tainting our fundamental understanding of how code flows and making debugging sessions longer than need be.
+
+As with most things programming, your codebase will benefit from a semblance of consistency. Even if you use all three patterns, -- and others -- a codebase that uses half a dozen patterns in equal amounts will be harder to understand, work with, and build on, than an equivalnet codebase that instead uses one pattern for the vast majority of its code while using other patterns in smaller ways when warranted. Picking the right pattern for each situation and striving for consistency might seem at odds with each other, but this is again a balancing act. The trade-off is between consistency in the grand scale of our codebase versus simplicity in the local piece of code we're working on. The question to ask is then: are we obtaining enough of a simplicity gain that it warrants the sacrifice of some consistency?
 
 === 5.3 Code Patterns
 

From 2991a3292b646d9fa02b3796d04313ceeece1444 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sun, 25 Mar 2018 19:58:41 -0300
Subject: [PATCH 17/71] revealing pattern

---
 chapters/ch05.asciidoc | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index 5ca6731..39f5e00 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -344,16 +344,29 @@ As with most things programming, your codebase will benefit from a semblance of
 
 === 5.3 Code Patterns
 
-..
+Digging a bit deeper and into more specific elements of architecture design, in this section we'll explore a few of the most common patterns for creating boundaries from which complexity cannot escape, encapsulating functionality, and communicating across these boundaries or application layers.
 
 ==== 5.3.1 Revealing Module
 
-.. this one is sort-of obvious but explain how hiding most of a class in a function can help avoid unwarranted access
+The revealing module pattern has become a staple in the world of JavaScript. The premise is simple enough: expose precisely what consumers should be able to access, and avoid exposing anything else. The reasons for this are manifold. Preventing unwarranted access to implementation details reduces the likelihood of your module's interface being abused for unsupported use cases that might bring headaches to both the module implementer and the consumer alike.
+
+Explicitly avoid exposing methods meant to be private, such as a hypothetical `_calculatePriceHistory` method, which relies on the leading hyphen as a way of discouraging direct access and signaling that it should be regarded as private. Avoiding such methods prevents test code from accessing private methods directly, resulting in tests that make assertions solely regarding the interface and which can be later referenced as documentation on how to use the interface; prevents consumers from monkey-patching implementation details, leading to more transparent interfaces; and also often results in cleaner interfaces due to the fact that the interface is all there is, and there's no alternative ways of interacting with the module through direct use of its internals.
+
+JavaScript modules are of a revealing nature by default, making it easy for us to follow the revealing pattern of not giving away access to implementation details. Any function, object, class, or variable we declare is private unless we explicitly decide to `export` it from the module.
+
+When we expose only a thin interface, our implementation can change largely without having an impact on how consumers use the module, nor on the tests that cover the module. As a mental exercise, always be on the lookout for aspects of an interface that should be turned into implementation details and extricated from the interface itself.
 
 ==== 5.3.2 Object Factories
 
 .. and how they're great for keeping state contained to the instance
 
+
+
+
+
+
+
+
 ==== 5.3.3 Event Emission
 
 .. events for things that we want to have clearly-delineated side-effects.

From aef6c59c7f378d60373269cc505cce381d93fd9a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sun, 25 Mar 2018 20:00:41 -0300
Subject: [PATCH 18/71] tweak headlines

---
 chapters/ch05.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index 39f5e00..b063ac6 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -386,7 +386,7 @@ When should we `Array#reduce`?
 
 .. chat about filtering and mapping, how iterators can help create a pipeline, but how tools like `lodash` also do this when we use the wrapper style, and how this shouldn't be a topmost concern of ours
 
-==== 5.4.2 Reducing lists into as hash-maps
+==== 5.4.2 Reducing data unto accumulators and itself
 
 .. (and other use cases for reduce)
 

From 8fa7e99cff224987a7ca121e69dfbcb319b17662 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 30 Mar 2018 16:58:40 -0300
Subject: [PATCH 19/71] finish tweaking up chapter 5

---
 atlas.json             |  5 ++-
 chapters/ch05.asciidoc | 85 ++++++++++++++++++++++++++++--------------
 2 files changed, 60 insertions(+), 30 deletions(-)

diff --git a/atlas.json b/atlas.json
index 94b2c86..e8b61bd 100644
--- a/atlas.json
+++ b/atlas.json
@@ -8,7 +8,8 @@
     "chapters/ch01.asciidoc",
     "chapters/ch02.asciidoc",
     "chapters/ch03.asciidoc",
-    "chapters/ch04.asciidoc"
+    "chapters/ch04.asciidoc",
+    "chapters/ch05.asciidoc"
   ],
   "formats": {
     "pdf": {
@@ -54,4 +55,4 @@
   "print_isbn13": "",
   "lang": "en",
   "accent_color": "cmyk(100%, 3%, 50%, 0%)"
-}
\ No newline at end of file
+}
diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index b063ac6..2e102b8 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -358,56 +358,85 @@ When we expose only a thin interface, our implementation can change largely with
 
 ==== 5.3.2 Object Factories
 
-.. and how they're great for keeping state contained to the instance
-
-
-
+Even when using JavaScript modules and following the revealing pattern strictly, we might end up with unintentional sharing of state across our usage of a module. Incidental state might result in unexpected results from an interface: consumers don't have a complete picture because other consumers are contributing changes to this shared state as well, sometimes making it hard to figure out what exactly is going on in an application.
 
+If we were to move our functional event emitter code snippet, with `onEvent` and `emitEvent`, into a JavaScript module, we'd notice that the `emitters` map is now a local global for that module, meaning all of the module's scope has access to `emitters`. This is what we'd want, because that way we can register event listeners in `onEvent` and fire them off in `emitEvent`. In most other situations, however, sharing persistent state across public interface methods is a recipe for unexpected bugs.
 
+Suppose we have a `StringBuilder` module that can be used to join strings in a performant manner. Even if consumers were supposed to use it synchronously and flush state in one fell swoop, without giving way for a second consumer to taint the state and produce unexpected results, our module shouldn't rely on consumer behavior to provide consistent results. The following contrived implementation relies on local shared state, and would need consumers to use the module strictly as intended, making all calls to `append` and `stringify` in sequence.
 
+[source,javascript]
+----
+const buffer = []
 
+export function append(...text) {
+  buffer.push(...text)
+}
 
-==== 5.3.3 Event Emission
+export function stringify() {
+  return buffer.splice(0, buffer.length).join('')
+}
+----
 
-.. events for things that we want to have clearly-delineated side-effects.
+Here's an example of how consuming the previous module could work. As soon as we try to asynchronously append text to the buffer, things will start getting out of hand, with strings getting bits and pieces unrelated to what we expect.
 
-==== 5.3.4 Message Passing
+[source,javascript]
+----
+const name = 'Sophie'
+append('hello')
+append(name)
+append(', it is nice to meet you!')
+stringify() // <- 'Hello Sophie, it is nice to meet you!'
+----
 
-.. situations like SW, normal workers, extensions, frames.
+Blatantly, this contrived module is poorly designed, as its buffer should never be used to construct several unrelated strings. We should instead expose a factory function that returns an object from its own self-contained scope, where all relevant state is shut off from the outside world. The methods on this object are equivalent to the exported interface of a plain JavaScript module, but state mutations are contained to instances that consumers create.
 
-=== 5.4 Data manipulation use cases
+[source,javascript]
+----
+function getStringBuilder() {
+  const buffer = []
 
-.. tips and tricks to consider when working with data. not isolated methods but instead use cases.
-.. Mapping data
-Filtering through data
-When should we `Array#reduce`?
+  function append(...text) {
+    buffer.push(...text)
+  }
 
-==== 5.4.1 Filtering and mapping data
+  function stringify() {
+    return buffer.splice(0, buffer.length).join('')
+  }
 
-.. chat about filtering and mapping, how iterators can help create a pipeline, but how tools like `lodash` also do this when we use the wrapper style, and how this shouldn't be a topmost concern of ours
+  return { append, stringify }
+}
+----
 
-==== 5.4.2 Reducing data unto accumulators and itself
+Using the string builder like this is just as straightforward, except that now we can do things asynchronously and even if other consumers are also using string builders of their own, each user will have their own state, preventing corrupt data.
 
-.. (and other use cases for reduce)
+[source,javascript]
+----
+const { append, stringify } = getStringBuilder()
+const name = 'Sophie'
+append('hello')
+append(name)
+append(', it is nice to meet you!')
+stringify() // <- 'Hello Sophie, it is nice to meet you!'
+----
 
-==== 5.4.3 The caveats of `Array#reduce`
+As we just showed, even when using modern language constructs and JavaScript modules, it's not too hard to create complications through shared state. Thus, we should always strive to contain mutable state as close to its consumers as possible.
 
-.. it's not used often, but when it's used, it's quite often for the wrong reasons. explain why it can be very complex to understand if the use case isn't correct
+==== 5.3.3 Event Emission
 
-=== 5.5 Conventions and Protocols
+We've already explored at length the pattern of registering event listeners associated to arbitrary plain JavaScript objects and firing events of any kind, triggering those listeners. Event handling is most useful when we want to have clearly-delineated side-effects.
 
-..
+In the browser, for instance, we can bind a `click` event to an specific DOM element. When the `click` event is fired, we might issue an HTTP request, render a different page, start an animation, or play an audio file.
 
-==== 5.5.1 Enforcing User-Defined Contracts
+Events are a useful way of reporting progress whenever we're dealing with a queue. While processing a queue, we could fire a `progress` event whenever an item is processed, allowing the UI or any other consumer to render and update a progress indicator or apply a partial unit of work relying on the data processed by the queue.
 
-.. coming up with own conventions, what/why and how to enforce it. probably talk of Symbol
+Events also offer a mechanism to provide hooks into the lifecycle of an object, for example the Angular view rendering framework used event propagation to enable hierarchical communication across separate components. This allowed Angular codebases to keep components decoupled from one another while still being able to react to each other's state changes and interact.
 
-==== 5.5.2 JavaScript Protocols
+Having event listeners allowed a component to receive a message, perhaps process it by updating its display elements, and then maybe reply with an event of its own, allowing for rich interaction without necessarily having to introduce another module to act as an intermediary.
 
-[aka interface]
+==== 5.3.4 Message Passing and the Simplicity of JSON
 
-.. the proposal: https://github.com/michaelficarra/proposal-first-class-protocols
+When it comes to ServiceWorker, web workers, browser extensions, frames, API calls, or WebSocket integrations, we might run into issues if we don't plan for robust data serialization ahead of time. This is generally when using classes to represent data starts to breaks down, because we'd need a way to serialize instances into their raw data counterparts (typically JSON) before sending it over the wire, since the receiving end wouldn't know how to decode a JavaScript class instance, and there isn't a standardized way of encoding them either. At the same time, we'd need a way to deserialize this plain JSON data on the receiving end, creating another class instance making sure it has the correct state.
 
-==== 5.5.3 Conventions at a Large Scale
+JSON, a subset of the JavaScript grammar, was purpose-built for this use case, where we often have to serialize data, send it over the wire, and deserialize it on the other end. Plain JavaScript objects are a great way to store data in our applications, offer frictionless serialization out the box, and lead to cleaner data structures because we can keep logic decoupled from the data.
 
-.. talk about conventions such as MVC, React's view rendering mechanism, or other large-scale conventions we adopt and seldom think about etc
+When the language on both the sending and receiving ends is JavaScript, we can share a module with all the functionality that we need around the data structure. This way, we don't have to worry about serialization, since we're using plain JavaScript objects and can rely on JSON for the transport layer. We don't have to concern ourselves with sharing functionality either, because we can rely on the JavaScript module system for that part.

From ad85a59d743ba9d3fe499c72a736a3439a56f830 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sat, 31 Mar 2018 18:05:49 -0300
Subject: [PATCH 20/71] intro to last chapter

---
 chapters/ch06.asciidoc | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 9feafa5..f83ccad 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -1,7 +1,9 @@
-[[secure-isolated-and-scalable]]
-== Secure, Isolated, and Scalable
+[[development-methodology-and-philosophy]]
+== Development Methodology and Philosophy
 
-# chapter around basically 12factor but repurposed for modules
+Even though most of us work on projects where the source code is not publicly available, we can all benefit from following open-source best practices, many of which still apply in closed-source project development. Pretending all of our code is going to be open-source results in better configuration and secret management, better documentation, better interfaces, and more maintainable codebases overall.
+
+In this chapter we'll explore open-source principles and look at ways in which we can adapt a methodology and set of robustness principles known as "The Twelve-Factor App"footnote:[see-tfa,You can find the original 12 Factor App methodology and its documentation at: https://mjavascript.com/out/12factor.] -- generally devised for back-end development -- to modern JavaScript application development, front-end and back-end alike.
 
 === 6.1
 

From c7e7fc5e0b2bc8ce0c6b70fb5411810b35798aac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sat, 31 Mar 2018 21:10:09 -0300
Subject: [PATCH 21/71] configuration

---
 chapters/ch06.asciidoc | 33 ++++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index f83ccad..b546252 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -5,10 +5,37 @@ Even though most of us work on projects where the source code is not publicly av
 
 In this chapter we'll explore open-source principles and look at ways in which we can adapt a methodology and set of robustness principles known as "The Twelve-Factor App"footnote:[see-tfa,You can find the original 12 Factor App methodology and its documentation at: https://mjavascript.com/out/12factor.] -- generally devised for back-end development -- to modern JavaScript application development, front-end and back-end alike.
 
-=== 6.1
+=== 6.1 Secure Configuration Management
 
-..
+When it comes to configuration secrets in closed-source projects, like API keys or HTTP session decryption keys, it is not uncommon for them to be hardcoded in place. In open-source projects, instead, these are typically instead obtained through environment variables or encrypted configuration files that aren't committed to version control systems alongside our codebase.
+
+In the case of open-source projects, this allows the developer to share the vast majority of their application without compromising the security of their production systems. While this might not be an immediate concern in closed-source environments, we need to consider that once a secret is committed to version control, it's etched into our version history unless we force a rewrite of that history, scrubbing the secrets from existence. Even then, it cannot be guaranteed that a malicious actor has gained access to these secrets at some point before they were scrubbed from history, and thus a better solution to this problem is rotating the secrets that might be compromised, revoking access through the old secrets and starting to use new, uncompromised secrets.
+
+While effective, this approach can be time consuming when we have several secrets under our belt, and when our application is large enough, leaked secrets might pose significant risk even when exposed for a short period of time. As such, it's best to approach secrets with careful consideration by default, and avoid headaches later in the lifetime of a project.
+
+The absolute least we could be doing is giving every secret a unique name, and placing them in a JSON file. Any sensitive information or configurable values may qualify as a secret, and this might range from private signing keys used to sign certificates to port numbers or database connection strings.
+
+[source,javascript]
+----
+{
+  "PORT": 3000,
+  "MONGO_URI": "mongodb://localhost/mjavascript",
+  "SESSION_SECRET": "ditch-foot-husband-conqueror"
+}
+----
+
+Instead of hardcoding these variables wherever they're used, or even placing them in a constant at the beginning of the module, we centralize all sensitive information in a single file, that can then be excluded from version control. Besides helping us share the secrets across modules, making updates easier, this approach encourages us to isolate information that we previously wouldn't have considered sensitive, like the work factor used for salting passwords.
+
+Another benefit of going down this road is that, given we have all environment configuration in a central store, we can point our application to a different secret store depending on whether we're provisioning the application for production, staging, or one of the local development environments used by our developers.
 
-==== 6.1.1
+When it comes to sharing the secrets, given we're purposely excluding them from source version control, we can take many approaches, such as using environment variables, storing them in JSON files kept in an Amazon S3 bucket, or using an encrypted repository dedicated to our application secrets.
+
+==== 6.2
 
 ..
+
+
+
+
+
+

From 5c3ab9b1f0c56d870cdf4c5c04a02bd0ac5f666d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Tue, 3 Apr 2018 22:31:52 -0300
Subject: [PATCH 22/71] outline last chapter

---
 chapters/ch06.asciidoc | 33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index b546252..823da80 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -30,12 +30,41 @@ Another benefit of going down this road is that, given we have all environment c
 
 When it comes to sharing the secrets, given we're purposely excluding them from source version control, we can take many approaches, such as using environment variables, storing them in JSON files kept in an Amazon S3 bucket, or using an encrypted repository dedicated to our application secrets.
 
-==== 6.2
+==== 6.2 Dependency Containment
 
-..
+.. how to manage deps
 
 
 
+==== 6.3 First Party, Third Party, and Last Party
+
+.. treat everything as if were third party, apis and components alike
+
+
+
+==== 6.4 Build, Release, Run
+
+.. clearly defined build processes
+
+
+
+==== 6.5 Statelessness
+
+.. avoid keeping global state
+
+
+
+==== 6.6 Disposability
+
+.. gracefully blow up components
+
+
+
+==== 6.7 Parity in Development and Production
+
+.. keeping stuff like CSP on par makes for less brittle and unexpected things
+
+
 
 
 

From 074d1ab59f94b32d4ed2afe6f2c07a18c73ea2e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 6 Apr 2018 21:10:35 -0300
Subject: [PATCH 23/71] dependencies, interfaces

---
 chapters/ch06.asciidoc | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 823da80..24b7d68 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -30,17 +30,21 @@ Another benefit of going down this road is that, given we have all environment c
 
 When it comes to sharing the secrets, given we're purposely excluding them from source version control, we can take many approaches, such as using environment variables, storing them in JSON files kept in an Amazon S3 bucket, or using an encrypted repository dedicated to our application secrets.
 
-==== 6.2 Dependency Containment
+==== 6.2 Explicit Dependency Management
 
-.. how to manage deps
+It's not practical to include dependencies in our repositories, given these are often in the hundreds of megabytes and often include environment-dependant and operating system dependant files. During development, we want to make sure we get non-breaking upgrades to our dependencies, which can help us resolve bugs and tighten our grip around security vulnerabilities. For deployments, we want reproducible builds, where installing our dependencies yields the same results every time. The solution is often to include a dependency manifest, indicating what exact versions of the libraries in our dependency tree we want to be installing. This can be accomplished with npm (starting with version 5) and its `package-lock.json` manifest, as well as through the Yarn package manager and its `yarn.lock` manifest, both of which we should be publishing to our versioned repository.
 
+Every dependency in our application should be explicitly declared in our manifest, relying on globally installed packages or global variables as little as possible. Implicit dependencies involve additional steps across environments, where developers and deployment flows alike must take action to ensure these extra dependencies are installed, beyond what a simple `npm install` step could achieve.
 
+Always installing identical versions of our dependencies -- and identical versions of our dependencies' dependencies -- brings us one step closer to having development environments that closely mirror what we do in production. This increases the likelyhood we can swiftly reproduce bugs that occurred in production in our local environments, while decreasing the odds that something that worked during development fails in staging.
 
-==== 6.3 First Party, Third Party, and Last Party
+==== 6.3 Interfaces as Black Boxes
 
-.. treat everything as if were third party, apis and components alike
+On a similar note to that of the last section, we should treat our own components no differently than how we treat third party libraries and modules. Granted, we can make changes to our own code a lot more quickly than we can effect change in third party code -- if that's at all possible. However, when we treat all components and interfaces (including our own HTTP API) as if they were foreign to us, we can focus on consuming and testing against interfaces, while ignoring the underlying implementation.
 
+Avoiding distinctions helps us write unit tests where we mock dependencies that aren't under test, regardless of whether they were developed in-house or by a third party. When writing tests we always assume that third party modules are generally well-tested enough that it's not our responsibility to include them in our test cases. The same thinking should apply to first party modules that just happen to be dependencies of the module we're currently writing tests for.
 
+This same reasoning can be applied to security concerns such as input sanitization. Regardless of what kind of application we're developing, we can't trust user input unless it's sanitized. Malicious actors could be angling to take over our servers, our customers' data, or otherwise inject content onto our web pages. These users might be customers or even employees, so we shouldn't treat them differently depending on that, when it comes to input sanitization.
 
 ==== 6.4 Build, Release, Run
 

From 11fbc337886d437ddeae702dd82335fef40a785a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Wed, 11 Apr 2018 17:02:40 -0300
Subject: [PATCH 24/71] brr

---
 chapters/ch06.asciidoc | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 24b7d68..680ad4c 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -48,7 +48,17 @@ This same reasoning can be applied to security concerns such as input sanitizati
 
 ==== 6.4 Build, Release, Run
 
-.. clearly defined build processes
+Having clearly defined and delineated build processes is key when it comes to successfully managing an application across development, staging, and production environments.
+
+Build processes have a few different aspects to them. At the highest level, there's the shared logic where we install and compile our assets so that they can be consumed by our runtime application.
+
+For development, we focus on enhanced debugging facilities, using development versions of libraries, source maps, and verbose logging levels; custom ways of overriding behavior, so that we can easily mimic how the production environment would look like, and where possible we also throw in a real-time debugging server that takes care of restarting our application when code changes, applying CSS changes without refreshing the page, and so on.
+
+In staging, we want an environment that closely resembles production, so we'll avoid most debugging features, but we might still want source maps and verbose logging to be able to trace bugs with ease.
+
+Production focuses more heavily on minification, image optimization, and advanced techniques like route-based bundle splitting, where we only serve modules that are actually used by the pages visited by a user; tree shaking, where we statically analyze our module graph and remove functions that aren't being used; and security features, such as a hardened Content-Security-Policy policy that mitigates attack vectors like XSS or CSRF.
+
+Note how up until this point we haven't discussed environments. Building assets and deploying them is often tightly coupled, meaning it's often non-trivial to build an application for production but deploy it for local development to see whether it's working as expected.
 
 
 

From b46a4613e4900d0e10954904bfd379791d5dd19f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sat, 14 Apr 2018 00:02:26 -0300
Subject: [PATCH 25/71] notes on deployments/configuration

---
 chapters/ch06.asciidoc | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 680ad4c..74b74c4 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -58,12 +58,12 @@ In staging, we want an environment that closely resembles production, so we'll a
 
 Production focuses more heavily on minification, image optimization, and advanced techniques like route-based bundle splitting, where we only serve modules that are actually used by the pages visited by a user; tree shaking, where we statically analyze our module graph and remove functions that aren't being used; and security features, such as a hardened Content-Security-Policy policy that mitigates attack vectors like XSS or CSRF.
 
-Note how up until this point we haven't discussed environments. Building assets and deploying them is often tightly coupled, meaning it's often non-trivial to build an application for production but deploy it for local development to see whether it's working as expected.
-
-
+Note how up until this point we have focused on how we build our assets, but not how we deploy them. These two processes, build and deployment, are closely related but they shouldn't be intertwined. A clean build process where we end up with a packaged application we can easily deploy, and a deployment process that takes care of the specifics regardless of whether you're deploying to your own local environment, or to a hosted staging or production environment, means that for the most part we won't need to worry about environments during our build processes or at runtime.
 
 ==== 6.5 Statelessness
 
+We've already explored how state, if left unchecked, can lead us straight to the heat death of our applications.
+
 .. avoid keeping global state
 
 

From 6e03d9cedfb8d8e2a1cf27a09bc14a196c0ad8f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Tue, 24 Apr 2018 18:24:09 -0300
Subject: [PATCH 26/71] csp

---
 chapters/ch06.asciidoc | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 74b74c4..5833c05 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -56,29 +56,42 @@ For development, we focus on enhanced debugging facilities, using development ve
 
 In staging, we want an environment that closely resembles production, so we'll avoid most debugging features, but we might still want source maps and verbose logging to be able to trace bugs with ease.
 
-Production focuses more heavily on minification, image optimization, and advanced techniques like route-based bundle splitting, where we only serve modules that are actually used by the pages visited by a user; tree shaking, where we statically analyze our module graph and remove functions that aren't being used; and security features, such as a hardened Content-Security-Policy policy that mitigates attack vectors like XSS or CSRF.
+Production focuses more heavily on minification, image optimization, and advanced techniques like route-based bundle splitting, where we only serve modules that are actually used by the pages visited by a user; tree shaking, where we statically analyze our module graph and remove functions that aren't being used; and security features, such as a hardened `Content-Security-Policy` policy that mitigates attack vectors like XSS or CSRF.
 
 Note how up until this point we have focused on how we build our assets, but not how we deploy them. These two processes, build and deployment, are closely related but they shouldn't be intertwined. A clean build process where we end up with a packaged application we can easily deploy, and a deployment process that takes care of the specifics regardless of whether you're deploying to your own local environment, or to a hosted staging or production environment, means that for the most part we won't need to worry about environments during our build processes or at runtime.
 
 ==== 6.5 Statelessness
 
-We've already explored how state, if left unchecked, can lead us straight to the heat death of our applications.
-
-.. avoid keeping global state
+We've already explored how state, if left unchecked, can lead us straight to the heat death of our applications. Keeping state to a minimum translates directly into applications that are easier to debug. The least global state there is, the less unpredictable the current conditions of an application will be at any one point in time, and the least surprises we'll run into while debugging.
 
+One particularly insidious form of state is caching. A cache is a great way to increase performance in an application by avoiding expensive lookups most of the time. When state management tools are used as a caching mechanism, we might fall into a trap where different bits and pieces of derived application state were derived at different points in time, thus rendering different bits of the application using data computed at different points in time.
 
+Derived state should seldom be treated as state that's separate from the data it was derived from. When it's not, we might run into situations where the original data is updated, but the derived state is not, becoming stale and inaccurate. When, instead, we always compute derived state from the original data, we reduce the likelyhood that this derived state will become stale.
 
 ==== 6.6 Disposability
 
-.. gracefully blow up components
+Whenever we hook up an event listener, regardless of whether we're listening for DOM events or those from an event emitter, we should also strongly consider disposing of the listener when the concerned parties are no longer interested in the event being raised. For instance, if we have a React component that, upon mount, starts listening for `resize` events on the `window` object, we should also make sure we remove those event listeners upon the component being unmounted.
 
+This kind of dilligence ensures that we can set up and tear down bits of our application without leaving behind mounting piles of listeners that would result in memory leaks, which are hard to track down and pinpoint.
 
+The concept of disposability goes beyond just event handlers, though. Any sort of resource that we allocate and attach to an object, component, or service is created, should be released and cleaned up when that attachment ceases to exist. This way, we can confidently create and dispose of as many components as we want, without putting our application's performance at risk.
 
 ==== 6.7 Parity in Development and Production
 
-.. keeping stuff like CSP on par makes for less brittle and unexpected things
+We've established the importance of having clearly defined build and deployment processes. In a similar vein, we have the different application environments like development, production, staging, feature branches, SaaS vs. on-premise environments, and so on. Environments are divergent by definition, we are going to end up with different features in different environments, whether they are debugging facilities, product features, or performance optimizations.
+
+Whenever we incorporate environment-specific feature flags or logic, we need to pay attention to the discrepancies introduced by these changes. Could the environment-dependant logic be tightened so that the bare minimum divergence is introduced? Should we isolate the newly introduced logic fork into a single module that takes care of as many aspects of the divergence as possible? Could the flags that are enabled as we're developing features for an specific environment result in inadvertently introducing bugs into other environments where a different set of flags is enabled?
+
+Conversely, the opposite is true. Like with many things programming, creating these divergences is relatively easy, whereas deleting them might prove most challenging. This difficulty arises from the unknown situations we might not typically run into during development or unit testing, but which are still valid situations in our production environments.
+
+As an example, consider the following scenario. We have a production application using `Content-Security-Policy` rules to mitigate malicious attack vectors. For the development environment, we also add a few extra rules like `'unsafe-inline'` letting our developer tools manipulate the page so that code and style changes are reloaded without requiring a full page refresh, speeding up our precious development productivity and saving time. Our application already has a component that users can leverage to edit programming source code, but we now have a requirement to change that component.
 
+We swap the current component with the a new one from our company's own component framework, so we know it's battle-tested and works well in other production applications developed in house. We test things in our local development environment, and everything works as expected. Tests pass. Other developers review our code, test locally in their own environments as well, and find nothing wrong with it. We merge our code, and a couple weeks later deploy to production. Before long, we start getting support requests about the code editing feature being broken, and need to roll back the changeset which introduced the new code editor.
 
+What went wrong? We didn't notice the fact that the new component doesn't work unless `style-src: 'unsafe-inline'` is present. Given that we allow inline styles in development, catering to our convenient developer tools, this wasn't a problem during development or local testing performed by our team mates. However when we deploy to production, which follows a more strict set of CSP rules, the `'unsafe-inline` rule is not served, and the component breaks down.
 
+The problem here is that we had a divergence in parity which prevented us from identifying a limitation in the new component: it uses inline styles to position the text cursor. This is at odds with our strict CSP rules, but it can't be properly identified because our development environment is more lax about CSP than production is.
 
+As much as possible, we should strive to keep these kinds of divergences to a minimum, because if we don't, bugs might find their way to production, and a customer might end up reporting the bug to us. Merely being aware of discrepancies like this is not enough, because it's not practical nor effective to keep these logic gates in your head so that whenever you're implementing a change you mentally go through the motions of how the change would differ if your code was running in production instead.
 
+Proper integration testing might catch many of these kinds of mistakes, but that won't always be the case.

From 4f7f679bab437b6295415c5fe9324999f2e66541 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Tue, 24 Apr 2018 18:25:21 -0300
Subject: [PATCH 27/71] add chapter 6 to manifest

---
 atlas.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/atlas.json b/atlas.json
index e8b61bd..1990f22 100644
--- a/atlas.json
+++ b/atlas.json
@@ -9,7 +9,8 @@
     "chapters/ch02.asciidoc",
     "chapters/ch03.asciidoc",
     "chapters/ch04.asciidoc",
-    "chapters/ch05.asciidoc"
+    "chapters/ch05.asciidoc",
+    "chapters/ch06.asciidoc"
   ],
   "formats": {
     "pdf": {

From 7b0bb1a07a39d19fe48551f3bc01fbae7adb9212 Mon Sep 17 00:00:00 2001
From: Paul Binns <paul.binns@team.telstra.com>
Date: Sat, 28 Apr 2018 22:13:09 +1000
Subject: [PATCH 28/71] Ch01 fixes to grammer and spelling

Tweaks to wording
---
 chapters/ch01.asciidoc | 42 +++++++++++++++++++++---------------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/chapters/ch01.asciidoc b/chapters/ch01.asciidoc
index 68b51c1..4cf384f 100644
--- a/chapters/ch01.asciidoc
+++ b/chapters/ch01.asciidoc
@@ -1,13 +1,13 @@
 [[module-thinking]]
 == Module Thinking
 
-Even after the printing press was invented, publishing books remains a challenging endeavor. Yes, there's typically an author -- or authors -- who scribbled the content wherever and whenever they found time to do so. But there's also a content editor, tasked with helping the author transform their stream of conciousness into a relatable story that's not too dry to read, something to be especially careful about when it comes to technical or business books. We have the technical reviewers, watchful subject matter experts on the lookout for egregious mistakes in technical definitions or interpretations. And lastly, -- of course -- we have the content editor, the typo linters of prose and last bastion of proper grammar. Thus far, however, we've barely scratched the surface: everyone mentioned above is mostly interested in the contents of the book, but we don't do much else. There's also, as an example, the typesetters whose job is to ensure the book looks good when it goes to print -- bidding good riddance to orphans and widows, poorly-wrapped lines of code, and so much more. Someone has to design the cover, or to approve the table of contents for the first draft so that the author gets a contract. Several people oversee the process that culminates in the book going to press, -- usually referred to as production -- as well. Once copies are printed, they need to be distributed. Eventually, the book hits the shelves (physical or otherwise) and starts selling. Someone buys the book, and finally starts to read it. We could write entire books about the purchase transaction alone.
+Even after the printing press was invented, publishing books remains a challenging endeavor. Yes, there's typically an author -- or authors -- who scribbled the content wherever and whenever they found time to do so. But there's also a content editor, tasked with helping the author transform their stream of consciousness into a relatable story that's not too dry to read, something to be especially careful about when it comes to technical or business books. We have the technical reviewers, watchful subject matter experts on the lookout for egregious mistakes in technical definitions or interpretations. And lastly, -- of course -- we have the content editor, the typo linters of prose and last bastion of proper grammar. Thus far, however, we've barely scratched the surface: everyone mentioned above is mostly interested in the contents of the book, but we don't do much else. There's also, as an example, the typesetters whose job is to ensure the book looks good when it goes to print -- bidding good riddance to orphans and widows, poorly-wrapped lines of code, and so much more. Someone has to design the cover, or to approve the table of contents for the first draft so that the author gets a contract. Several people oversee the process that culminates in the book going to press, -- usually referred to as production -- as well. Once copies are printed, they need to be distributed. Eventually, the book hits the shelves (physical or otherwise) and starts selling. Someone buys the book, and finally starts to read it. We could write entire books about the purchase transaction alone.
 
-The complexity of the whole process is mind-boggling, and yet, to each individual, it's not that complicated. The author, for example, merely has to write a few hundred words every day. Where did all that complexity go? There's a reason the process is so compartimentalized. We're not that good at handling high-level complexity, and breaking it down into single responsibilities such as "write content", "improve how prose flows", "review technical concerns", "fix grammar mistakes", "typeset for production", or "handle purchases" is what makes the process simpler for individuals working on the mammoth project that is writing a book or just about any business enterprise.
+The complexity of the whole process is mind-boggling, and yet, to each individual, it's not that complicated. The author, for example, merely has to write a few hundred words every day. Where did all that complexity go? There's a reason the process is so compartmentalized. We're not that good at handling high-level complexity, and breaking it down into single responsibilities ( such as "write content", "improve how prose flows", "review technical concerns", "fix grammar mistakes", "typeset for production", or "handle purchases" ), is what makes the process simpler for individuals, working on the mammoth project that is writing a book or just about any business enterprise.
 
 Publishing is just an example, but we could do this exercise with just about anything. Pick an object on your desk, any object. Think how it got there. Now zoom out, think some more, how was it made? What is it made of? How many people were involved in manufacturing each piece, assembling it, perfecting it, and getting it to the store where it was bought? Is it a fruit? How many people were involved in planting it, fighting off pests, pruning plants, packaging the fruit, and getting it to the store where it was bought?
 
-Software is not all that different, except complexity is all around us. At the deepest zoom levels we find constraints defined by physical constants such as the speed of light, individual bits and hardware, interrupt calls, assembly language, and much more. Zooming out we find the megastructures of the technology sector, which handle everything from search queries to payment processing. Somewhere in the midst of all this complexity, there's us developers, and the projects bestowed upon us.
+Software is not all that different, except complexity is all around us. At the deepest zoom levels we find constraints defined by physical constants such as the speed of light, individual bits and hardware, interrupt calls, assembly language, and much more. Zooming out we find the mega-structures of the technology sector, which handle everything from search queries to payment processing. Somewhere in the midst of all this complexity, there's us developers, and the projects bestowed upon us.
 
 We hardly stop to think about the complexity underlying everyday objects and interactions, since doing so would be paralyzing. Instead, we abstract solutions behind interfaces, so much that they _become_ -- in our minds -- the interface. Some of these interfaces map well to the abstracted implementation, and they feel great. Others don't map all that well to the implementation, and we end up feeling confused and frustrated. Software is not at all different. We don't want to think about the system as a whole, and virtually everything we work with sits behind interfaces that are simpler to use and understand than their underlying implementations.
 
@@ -15,15 +15,15 @@ This already happens at the system level, and we hardly think about it. Let's di
 
 === 1.1 Introduction to Module Thinking
 
-Embracing module thinking is understanding that complexity is, ultimately, inescapable. At the same time, that complexity can be sweeped under an interface, hardly to ever be seen or thought of again. But, and here's one of the tricky parts, the interface needs to be well-designed so that its users don't become frustrated. That frustration could even lead us to peering under the hood and finding that the implementation is vastly more complex than the poor interface we're frustrated by, and maybe if the interface didn't exist in the first place, we'd be better off in terms of maintainability and readability.
+Embracing module thinking is understanding that complexity is, ultimately, inescapable. At the same time, that complexity can be swept under an interface, hardly to ever be seen or thought of again. But, and here's one of the tricky parts, the interface needs to be well-designed so that its users don't become frustrated. That frustration could even lead us to peering under the hood and finding that the implementation is vastly more complex than the poor interface we're frustrated by, and maybe if the interface didn't exist in the first place, we'd be better off in terms of maintainability and readability.
 
 Systems can be organized granularly: we can split them into projects, made of multiple applications, containing several application-level layers, where we can have hundreds of modules, made up of thousands of functions, and so on. A granular approach helps us write code that's easy to understand and maintain, by attaining a reasonable degree of modularity, while preserving our sanity. In section 1.4, we'll discuss how we can best leverage this granularity to create modular applications.
 
-Whenever we delineate a component, there's going to be a public interface other parts of the system can leverage to access our component. The interface -- or API -- will be comprised of the set of methods or attributes that our component exposes, these methods or attributes can also be referred to as touchpoints, that is, the aspects of the interface that can be publicly interacted with. The fewer touchpoints an interface has, the smaller its surface area is, and the simpler the interface becomes. An interface with a large surface area is highly flexible, but it might also be a lot harder to understand and use, given the high amount of functionality exposed by the interface.
+Whenever we delineate a component, there's going to be a public interface other parts of the system can leverage to access our component. The interface -- or API -- will be comprised of the set of methods or attributes that our component exposes. These methods or attributes, can also be referred to as touchpoints, that is, the aspects of the interface that can be publicly interacted with. The fewer touchpoints an interface has, the smaller its surface area is, and the simpler the interface becomes. An interface with a large surface area is highly flexible, but it might also be a lot harder to understand and use, given the high amount of functionality exposed by the interface.
 
-This interface serves a dual purpose. It allows us to develop new bits and pieces of the component, only exposing functionality that's ready for public consumption while keeping private everything that's not meant to be shared with other components. At the same time, it allows consumers -- that is, components or systems that are leveraging our interface -- to reap the benefits of the functionality we expose without concerning themselves with the details of how we implemented that functionality.
+This interface serves a dual purpose. It allows us to develop new bits and pieces of the component, only exposing functionality that's ready for public consumption while keeping private everything that's not meant to be shared with other components. At the same time, it allows consumers -- that is, components or systems that are leveraging our interface -- to reap the benefits of the functionality we expose, without concerning themselves with the details of how we implemented that functionality.
 
-Robust, documented interfaces are one of the best ways of isolating a complicated piece of code so that others can consume its functionality without knowing any implementation details. A systematic arrangement of robust interfaces can be accrued to form a layer, -- such as service or data layers in enterprise applications -- and in doing so we might be able to largely isolate and circumscribe logic to one of those layers, while keeping presentational concerns separate from strictly business or persistance related concerns. Such a forceful separation is effective because it keeps individual components tidy and layers uniform. Uniform layers, comprised of components similar in pattern or shape, offer a sense of familiarity that makes them more straightforward to consume on a sustained basis from the point of view of a single developer, who over time becomes ever more used to familiar API shapes.
+Robust, documented interfaces are one of the best ways of isolating a complicated piece of code so that others can consume its functionality without knowing any implementation details. A systematic arrangement of robust interfaces can be accrued to form a layer, -- such as service or data layers in enterprise applications -- and in doing so we might be able to largely isolate and circumscribe logic to one of those layers, while keeping presentational concerns separate from strictly business or persistence related concerns. Such a forceful separation is effective because it keeps individual components tidy and layers uniform. Uniform layers, comprised of components similar in pattern or shape, offer a sense of familiarity that makes them more straightforward to consume on a sustained basis from the point of view of a single developer, who over time becomes ever more used to familiar API shapes.
 
 Relying on consistent API shapes is a great way of increasing productivity, given the difficulty of coming up with adequate interface designs. When we consistently leverage similar API shapes, we don't have to come up with new designs every time, and consumers can rest assured that you haven't reinvented the wheel every time. We'll discuss API design at length over the coming chapters.
 
@@ -33,7 +33,7 @@ When it comes to JavaScript, modularity is a modern concept. In this section we'
 
 ==== 1.2.1 Script Tags and Closures
 
-In the early days, JavaScript was inlined in HTML `<script>` tags. At best, it was offloaded to dedicated script files, all of which shared a global scope.
+In the early days, JavaScript was in-lined in HTML `<script>` tags. At best, it was offloaded to dedicated script files, all of which shared a global scope.
 
 Any variables declared in one of these files or inline scripts would be imprinted on the global `window` object, creating leaks across entirely unrelated scripts that might've lead to conflicts or even broken experiences, where a variable in one script might inadvertently replace a global that another script was relying on.
 
@@ -75,7 +75,7 @@ mathlib.sum(1, 2, 3)
 
 This pattern was, coincidentally, an open invitation for JavaScript tooling to burgeon, allowing developers to -- for the first time -- safely concatenate every IIFE module into a single file, reducing the strain on the network.
 
-The problem in the IIFE approach was that there wasn't an explicit dependency tree. This means developers had to manufacture component file lists in a precise order, so that dependencies would load before any modules that dependend on them did -- recursively.
+The problem in the IIFE approach was that there wasn't an explicit dependency tree. This means developers had to manufacture component file lists in a precise order, so that dependencies would load before any modules that depended on them did -- recursively.
 
 ==== 1.2.2 RequireJS, AngularJS, and Dependency Injection
 
@@ -139,7 +139,7 @@ module.factory('calculator', ['mathlib', function(mathlib) {
 }])
 ----
 
-Needless to say, the delay in introducing this little-known build tool, combined with the over-engineered aspect of having an extra build step to unbreak something that shouldn't have been broken, discouraged the use of a pattern that carried such a negligible benefit anyway. Developers mostly chose to stick with the familiar RequireJS-like hardcoded dependency array format.
+Needless to say, the delay in introducing this little-known build tool, combined with the over-engineered aspect of having an extra build step to un-break something that shouldn't have been broken, discouraged the use of a pattern that carried such a negligible benefit anyway. Developers mostly chose to stick with the familiar RequireJS-like hard-coded dependency array format.
 
 ==== 1.2.3 Node.js and the Advent of CommonJS
 
@@ -154,7 +154,7 @@ Much like RequireJS and AngularJS, CommonJS dependencies are also referred to by
 
 Unlike RequireJS or AngularJS, CommonJS was rather strict. In RequireJS and AngularJS you could have many dynamically-defined modules per file, whereas CommonJS had a one-to-one mapping between files and modules. At the same time, RequireJS had several ways of declaring a module and AngularJS had several kinds of factories, services, providers and so on -- besides the fact that its dependency injection mechanism was tightly coupled to the AngularJS framework itself. CommonJS, in contrast, had a single way of declaring modules. Any JavaScript file was a module, calling `require` would load dependencies, and anything assigned to `module.exports` was its interface. This enabled better tooling and code introspection -- making it easier for tools to learn the hierarchy of a CommonJS component system.
 
-Eventually, Browserify was invented as way of bridging the gap between CommonJS modules for Node.js servers and the browser. Using the `browserify` command-line interface program and providing it with the path to an entry point module, one could combine an unthinkable amount of modules into a single browser-ready bundle. The killer feature of CommonJS, the npm package registry, was decisive in aiding its takeover of the module loading ecosystem.
+Eventually, Browserify was invented as a way of bridging the gap between CommonJS modules for Node.js servers and the browser. Using the `browserify` command-line interface program and providing it with the path to an entry point module, one could combine an unthinkable amount of modules into a single browser-ready bundle. The killer feature of CommonJS, the npm package registry, was decisive in aiding its takeover of the module loading ecosystem.
 
 Granted, npm wasn't limited to CommonJS modules or even JavaScript packages, but that was and still is by and large its primary use case. The prospect of having thousands of packages (now over half a million and steadily growing) available in your web application at the press of a few fingertips, combined with the ability to reuse large portions of a system on both the Node.js web server and each client's web browser, was too much of a competitive advantage for the other systems to keep up.
 
@@ -162,7 +162,7 @@ Granted, npm wasn't limited to CommonJS modules or even JavaScript packages, but
 
 As ES6 became standardized in June of 2015, and with Babel transpiling ES6 into ES5 long before then, a new revolution was quickly approaching. The ES6 specification included a module system native to JavaScript, often referred to as ECMAScript Modules (ESM).
 
-ESM is largely influenced by CJS and its predecessors, offering a static declarative API as well as a promise-based dynamic programmative API, as illustrated next.
+ESM is largely influenced by CJS and its predecessors, offering a static declarative API as well as a promise-based dynamic programmable API, as illustrated next.
 
 [source,javascript]
 ----
@@ -186,31 +186,31 @@ We've already addressed the fact that modularity, as opposed to a single shared
 
 Maintainability, or the ability to effect change in the codebase, also improves significantly because of this. When code is simple and modular, it's easier to build upon and extend. Maintainability is valuable regardless of team size: even in a team of one, if we leave a piece of code untouched for a few months and then come back to it, it might be hard to improve upon or even understand if we didn't consider writing maintainable code the first time around.
 
-Modular code is meant to be highly maintainable by default. By keeping pieces of code simple and following the Single Responsibility Priciple (SRP), whereby it only aims to fulfill one goal, and combining these simple pieces of code into more sophisticated components, we're able to compose our way to larger components, and eventually an entire application. When each piece of code in a program is modular, the codebase appears to be simple when we're looking at individual components, yet on the whole it is able to exhibit complex behaviors, just like the book publishing process we've discussed in the beginning of this chapter.
+Modular code is meant to be highly maintainable by default. By keeping pieces of code simple and following the Single Responsibility Principle (SRP), whereby it only aims to fulfill one goal, and combining these simple pieces of code into more sophisticated components, we're able to compose our way to larger components, and eventually an entire application. When each piece of code in a program is modular, the codebase appears to be simple when we're looking at individual components, yet on the whole it is able to exhibit complex behaviors, just like the book publishing process we've discussed in the beginning of this chapter.
 
-Components in modular applications are defined by their interfaces. The implementation of those components is not their essence, but their interfaces are. When interfaces are well-designed, they can be grown in non-breaking ways, augmenting the amount of use cases they can satisfy, without compromising existing usage. When we have a mindfully designed interface, the implementation behind that interface becomes easy to tweak or swap entirely. Strong interfaces are effective at hiding away weak implementations, that can be later refactored into more robust implementations provided the interface holds. Strong interfaces are also excellent for unit testing, because we won't have to worry about the implementation and we can test the interface, -- the inputs and outputs of a component or function -- if the interface is well-tested plus robust, we can surely consider its implementation in a secondary plane.
+Components in modular applications are defined by their interfaces. The implementation of those components is not their essence, but their interfaces are. When interfaces are well-designed, they can be grown in non-breaking ways, augmenting the amount of use cases they can satisfy, without compromising existing usage. When we have a mindfully designed interface, the implementation behind that interface becomes easy to tweak or swap entirely. Strong interfaces are effective at hiding away weak implementations, that can be later refactored into more robust implementations provided the interface holds. Strong interfaces are also excellent for unit testing, because we won't have to worry about the implementation and we can test the interface, -- the inputs and outputs of a component or function. If the interface is well-tested and robust, we can surely consider its implementation in a secondary plane.
 
-Given those implementations are secondary to the foremost requirement of having intuitive interfaces, that aren't coupled to their implementations, we can concern ourselves with the tradeoff between flexibility and simplicity. Flexibility inevitably comes at the cost of added complexity, which is a good reason not to offer flexible interfaces. At the same time, flexibility is often a necessity, and thus we need to strike the right balance by deciding how much rigidity we can get away with in our interfaces. This balance would mean an interface appeases its consumers thanks to its ease of use, but that it also enables advanced or more uncommon use cases when needed, without too much of a detrimental effect on the ease of use or at the cost of greatly enhanced implementation complexity.
+Given those implementations are secondary to the foremost requirement of having intuitive interfaces, that aren't coupled to their implementations, we can concern ourselves with the trade-off between flexibility and simplicity. Flexibility inevitably comes at the cost of added complexity, which is a good reason not to offer flexible interfaces. At the same time, flexibility is often a necessity, and thus we need to strike the right balance by deciding how much rigidity we can get away with in our interfaces. This balance would mean an interface appeases its consumers thanks to its ease of use, but that it also enables advanced or more uncommon use cases when needed, without too much of a detrimental effect on the ease of use or at the cost of greatly enhanced implementation complexity.
 
-We'll discuss the tradeoffs between flexibility, simplicity, composability, and the right amount of future-proofing in the following couple of chapters.
+We'll discuss the trade-offs between flexibility, simplicity, composability, and the right amount of future-proofing in the following couple of chapters.
 
 === 1.4 Modular Granularity
 
-We can apply modular design concepts on every level of a given system. If a project's demands outgrow its initial scope, maybe we should consider splitting that project into several, smaller projects with smaller teams that are more manageable. The same can be said of applications, when they become large or complex enough, we might want to split them into differentiated products.
+We can apply modular design concepts on every level of a given system. If a project's demands outgrow its initial scope, maybe we should consider splitting that project into several, smaller projects with smaller teams that are more manageable. The same can be said of applications: when they become large or complex enough, we might want to split them into differentiated products.
 
 When we want to make an application more maintainable, we should consider creating explicitly defined layers of code, so that we can grow each layer horizontally while preventing the complexity of those additions from spreading to other, unrelated, layers. The same thought process can be applied to individual components, splitting them into two or more smaller components that are then tied together by yet another small component, which could act as a composition layer whose sole responsibility is knitting together several underlying components.
 
-At the module level, we should strive to keep functions simple and expressive, with descriptive names and not too many responsibilities. Maybe we'll have a function dedicated exclusively to broidering together a group of tasks under a particular asynchronous flow, while having other functions for each task that we need to perform within that control flow. The topmost flow controlling function could be exposed as a public interface method for our module, but the only part of it that should be treated as public interface are the parameters that we receive as inputs for that function and the output produced by that same topmost function. Everything else becomes an implementation detail and is, as such, to be considered swappable.
+At the module level, we should strive to keep functions simple and expressive, with descriptive names and not too many responsibilities. Maybe we'll have a function dedicated exclusively to pulling together a group of tasks under a particular asynchronous flow, while having other functions for each task that we need to perform within that control flow. The topmost flow controlling function could be exposed as a public interface method for our module, but the only part of it that should be treated as public interface are the parameters that we receive as inputs for that function and the output produced by that same topmost function. Everything else becomes an implementation detail and is, as such, to be considered swappable.
 
 The internal functions of a module won't have as rigid of an interface either: as long as the public interface holds, we can change the implementation -- including the interfaces of functions that make up that implementation -- however we want. This is not to say, however, that we should treat those interfaces any less deliberately. The key to proper modular design is in having an utmost respect for all interfaces, and that includes the interfaces exposed by internal functions.
 
 Within functions, we'll also note a need to componentize aspects of the implementation, giving those aspects a name in the way of function calls, deferring complexity that doesn't need to be immediately dealt with in the main body of the function until later in the read-through of a given piece of code. We're writing programs that are meant to be readable and writable for other humans and even ourselves in the future. Virtually everyone who has done any amount of programming has experienced a feeling of frustration when glancing at a piece of code they themselves wrote a few months prior, only to later realize that, with a fresh pair of eyes the design they had then come up with wasn't as solid as they originally intended.
 
-Remember, computer program development is largely a human and collaborative endeavor. We're not optimizing for computers to run programs as fast as possible. If we were, we'd be writing binary or hardcoding logic into circuit boards. Instead, our focus is to empower an organization so that its developers can remain productive and able to quickly understand and even modify pieces of code they haven't ran across before. Working under the soft embrace of conventions and practices -- that place developers on an even keel -- closes that cycle by making sure future development is consistent with how the application has taken shape up until the present.
+Remember, computer program development is largely a human and collaborative endeavor. We're not optimizing for computers to run programs as fast as possible. If we were, we'd be writing binary or hard-coding logic into circuit boards. Instead, our focus is to empower an organization so that its developers can remain productive and able to quickly understand and even modify pieces of code they haven't ran across before. Working under the soft embrace of conventions and practices -- that place developers on an even keel -- closes that cycle by making sure future development is consistent with how the application has taken shape up until the present.
 
 Going back to performance, we should be treating it as a feature, where for the most part we don't place a higher premium on it than we would for other features. Unless performance needs to be a defining feature of our system for business reasons, we shouldn't worry about ensuring the system runs at top speed on all code paths. Doing so is bound to result in highly complex applications that are hard to maintain, debug, extend, and justify.
 
-We, as developers, often over-do architecture as well, and a lot of the reasoning about performance optimization applies here as well. Laying out an all-encompassing architecture that has the potential to save us trouble as we scale to billions of transactions per second might cost us considerable time spent upfront and possibly also lock us into a series of abstractions that will be hard to keep up with, for no foreseeable gains in the near term. It's a lot better when we focus on problems we're already running into, or might soon run into, instead of trying to plan for a hockey-stick growth of infrastructure and throughtput without any data to back up the hockey-stick growth we're anticipating.
+We, as developers, often over-do architecture as well, and a lot of the reasoning about performance optimization applies here as well. Laying out an all-encompassing architecture that has the potential to save us trouble as we scale to billions of transactions per second might cost us considerable time spent upfront and possibly also lock us into a series of abstractions that will be hard to keep up with, for no foreseeable gains in the near term. It's a lot better when we focus on problems we're already running into, or might soon run into, instead of trying to plan for a hockey-stick growth of infrastructure and throughput without any data to back up the hockey-stick growth we're anticipating.
 
 When we don't plan in such a long-term form, an interesting thing occurs, our systems will grow more naturally, adapting to the needs of the near-term, gradually progressing towards support for a larger application and larger set of requirements. When that progression is gradual, we'll notice a corrective behavior in how abstractions are picked up or discarded as we grow. If we settle on abstractions too early, and they end up being the wrong abstractions, we'll pay dearly for that mistake. Bad abstractions force us to bend entire applications to their will, and once we've realized that the abstraction is bad and ought to be removed, we might be so heavily invested in it that pulling out might be costly. This, paired with the sunk cost fallacy, whereby we're tempted to keep the abstraction just because we've spent a lot of time, sweat, and blood on it, can be very hazardous indeed.
 
@@ -228,6 +228,6 @@ Up until the launch of a Gmail beta client in April, 2004, which demonstrated th
 
 With the advent of frameworks like Backbone, Angular, Ember, and React, new techniques and breakthroughs also made an uptick on the web. Writing code under ES6 and beyond, but then transpiling parts of that code down to ES5 to attain broader browser support; shared rendering, using the same code on both server and client to render a page quickly on initial page load and continue to load pages quickly upon navigation; automated code bundling, packing the modules that comprise an application into a single bundle for optimized delivery; bundle-splitting along routes, so that there are several bundles outputted, each optimized for the initially visited route; CSS bundling at the JavaScript module level, so that CSS -- which doesn't feature a native module system -- can also be split across bundles; and a myriad ways of optimizing assets like images at compile time, improving productivity during development while keeping production deployments highly performant, are all part of the iterative nature of innovation in the web.
 
-This explosion of innovation doesn't stem from sheer creativity alone but also out of necessity: web applications are getting increasingly complex, as is their scope, purpose, and requirements. It follows logically, then, that the ecosystem around them would grow to accomodate those expanded requirements, in terms of better tooling, better libraries, better coding practices, architectures, standards, patterns, and more choice in general.
+This explosion of innovation doesn't stem from sheer creativity alone but also out of necessity: web applications are getting increasingly complex, as is their scope, purpose, and requirements. It follows logically, then, that the ecosystem around them would grow to accommodate those expanded requirements, in terms of better tooling, better libraries, better coding practices, architectures, standards, patterns, and more choice in general.
 
 While there are heaps of books on proper application design, there isn't a lot of material to be found on the topic of modular application design, let alone modular JavaScript application design -- hence this book. While the ample majority of the advice, musings, and teachings in this book aren't at all specific to JavaScript, the fresh focus on JavaScript means you'll be learning about how to write modular web applications while keeping in consideration the quirks that make the web such a unique platform, and JavaScript, special in many ways.

From 1c222a8b6949ebb105d780b68f64f8b7a99453fd Mon Sep 17 00:00:00 2001
From: Adam Rackis <adamrackis@hotmail.com>
Date: Sat, 28 Apr 2018 14:21:50 -0500
Subject: [PATCH 29/71] Chapter 5 tweaks

---
 chapters/ch05.asciidoc | 78 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 76 insertions(+), 2 deletions(-)

diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index da71842..86cebc5 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -77,7 +77,52 @@ const {
 } = response
 ----
 
-One contention point might be that, at times, the deeply destructured property name doesn't make sense outside of its context. For instance, we've introduce `name` to our scope, but it's the name of the contact for the listing, not to be confused with the name of the listing itself. In these cases, the alternative may be to give `response.contact.name` an alias where we add the parent property name as a prefix, so that we're left with a binding named `contactName` or `responseContactName`.
+At times, a deeply destructured property name may not make sense outside of its context. For instance, we introduce `name` to our scope, but it's the name of the contact for the listing, not to be confused with the name of the listing itself. We can clarify this by giving the contact's `name` an alias, like `contactName` or `responseContactName`.
+
+[source,javascript]
+----
+const {
+  title,
+  description,
+  askingPrice,
+  features: {
+    area,
+    bathrooms,
+    bedrooms,
+    amenities
+  },
+  contact: {
+    name: responseContactName,
+    phone,
+    email
+  }
+} = response
+----
+
+When using `:` to alias, it can be difficult at first to remember whether the original name, or the aliased name comes first. One helpful way to keep this straight is to mentally replace `:` with the word "as."  So `name: responseContactName` would read as "name as responseContactName." 
+
+We can even have the same property listed twice, if we wanted to destructure some of its contents, while also maintaining access to the object itself.  For example, if we wanted to destructure the `contact` object's contents, like we do above, but also take a reference to the whole `contact` object, we can do the following
+
+[source,javascript]
+----
+const {
+  title,
+  description,
+  askingPrice,
+  features: {
+    area,
+    bathrooms,
+    bedrooms,
+    amenities
+  },
+  contact: responseContact,
+  contact: {
+    name: responseContactName,
+    phone,
+    email
+  }
+} = response
+----
 
 Object spread helps us create a shallow copy of an object using a little native syntax. We can also combine object spread with our own properties, so that we create a copy that also overwrites the values in the original object we're spreading.
 
@@ -146,6 +191,16 @@ const finalValues = doubledValues.filter(value => value > 5)
 // <- [6, 8, 10]
 ----
 
+NOTE - this doesn't make sense.  The original example assigned to the SAME variable over and over again.  Wouldn't the simplified, equivalent code just chain the subsequent calls?
+
+[source,javascript]
+----
+let values = [1, 2, 3, 4, 5]
+  .map(value => value * 2)
+  .filter(value => value > 5)
+// <- [6, 8, 10]
+----
+
 Let's move onto a more interesting topic: asynchronous code flows.
 
 ==== 5.1.4 Navigating Callbacks, Promises, and Asynchronous Functions
@@ -435,7 +490,26 @@ Having event listeners allowed a component to receive a message, perhaps process
 
 ==== 5.3.4 Message Passing and the Simplicity of JSON
 
-When it comes to ServiceWorker, web workers, browser extensions, frames, API calls, or WebSocket integrations, we might run into issues if we don't plan for robust data serialization ahead of time. This is generally when using classes to represent data starts to breaks down, because we'd need a way to serialize instances into their raw data counterparts (typically JSON) before sending it over the wire, since the receiving end wouldn't know how to decode a JavaScript class instance, and there isn't a standardized way of encoding them either. At the same time, we'd need a way to deserialize this plain JSON data on the receiving end, creating another class instance making sure it has the correct state.
+When it comes to ServiceWorker, web workers, browser extensions, frames, API calls, or WebSocket integrations, we might run into issues if we don't plan for robust data serialization ahead of time. This is a place where using classes to represent data can break down, because we need a way to serialize class instances into raw data (typically JSON) before sending over the wire, and, crucially, the recipient needs to decode this JSON back into a class instance. It's the second part where classes start to fail, since there isn't a standardized way of reconstructing a class instance from JSON. For example
+
+[source,javascript]
+----
+class Person{
+  constructor(name, address){
+    this.name = name;
+    this.address = address;
+  }
+  speak(){
+    alert(`My name is ${this.name}`);
+  }
+}
+
+let nico = new Person("Nico", "123 Main St");
+----
+
+Although we can easily serialize our `nico` instance with `JSON.stringify(nico);`, and then send it over the wire, the code on the other end will have no standard way of turning this JSON back into an instance of our `Person` class.
+
+NOTE: then again, can you clarify why the receiving end would need to deserialize the data back into class instances, rather than just use raw object literals?  Assymetric representations of the same data is likely uglfy, and needlessly complex, and so possibly the only reason, and a good one, but it might be worth spelling out explicitly.
 
 JSON, a subset of the JavaScript grammar, was purpose-built for this use case, where we often have to serialize data, send it over the wire, and deserialize it on the other end. Plain JavaScript objects are a great way to store data in our applications, offer frictionless serialization out the box, and lead to cleaner data structures because we can keep logic decoupled from the data.
 

From 294ebce69b7c367bcf288a11345378bc0e6d89b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Tue, 29 May 2018 17:31:15 -0300
Subject: [PATCH 30/71] secret management

---
 chapters/ch06.asciidoc | 86 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 5833c05..71d62f3 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -30,6 +30,92 @@ Another benefit of going down this road is that, given we have all environment c
 
 When it comes to sharing the secrets, given we're purposely excluding them from source version control, we can take many approaches, such as using environment variables, storing them in JSON files kept in an Amazon S3 bucket, or using an encrypted repository dedicated to our application secrets.
 
+One concrete and effective way of accomplishing this in real-world environments is using several "dot env" files, each with a clearly defined purpose. In order of precedence:
+
+- `.env.defaults.json` can be used to define default values that aren't necessarily overwritten across environments, such as the application listening port, the `NODE_ENV` variable, and configurable options you don't want to hard-code into your application code. These default settings should be safe to check into source control
+- `.env.production.json`, `.env.staging.json`, and others can be used for environment-specific settings, such as the various production connection strings for databases, cookie encoding secrets, API keys, and so on
+- `.env.json` could be your local, machine-specific settings, useful for secrets or configuration changes that shouldn't be shared with other team members
+
+Furthermore, you could also accept simple modifications to environment settings through environment variables, such as when executing `PORT=3000 node app`, which is often convenient during development.
+
+There's an npm package called `nconf` which we can use to handle reading and merging all of these sources of application settings with ease.
+
+The following piece of code shows how you could configure `nconf` to do what we've just described.
+
+```
+// env
+import nconf from 'nconf'
+
+nconf.env()
+nconf.file('environment', `.env.${ nodeEnv() }.json`)
+nconf.file('machine', '.env.json')
+nconf.file('defaults', '.env.defaults.json')
+
+process.env.NODE_ENV = nodeEnv() // consistency
+
+function nodeEnv() {
+  return accessor('NODE_ENV')
+}
+
+function accessor(key) {
+  return nconf.get(key)
+}
+
+export default accessor
+```
+
+The module also exposes an interface through which we can consume these application settings by making a function call such as `env('PORT')`.
+
+Assuming we have an `.env.defaults.json` that looks like the following, we could pass in the `NODE_ENV` flag when starting our staging, test, or production application and get the proper environment settings back, helping us simplify the process of loading up an environment.
+
+```
+{
+  "NODE_ENV": "development"
+}
+```
+
+When it comes to the browser, we could use the exact same files and environment variables, but include a dedicated browser-specific object field, like so:
+
+```
+{
+  "NODE_ENV": "development",
+  "BROWSER_ENV": {
+    "MIXPANEL_API_KEY": "some-api-key",
+    "GOOGLE_MAPS_API_KEY": "another-api-key"
+  }
+}
+```
+
+Then, we could write a tiny script like the following to print all of those settings.
+
+```
+// print-browser-env
+import env from './lib/env'
+console.log(env('BROWSER_ENV'))
+```
+
+Naturally, we don't want to mix server-side settings with browser settings, because browser settings are usually accessible to anyone with a user agent, the ability to visit our website, and basic programming skills, meaning we would do well not to bundle highly sensitive secrets with our client-side applications. To resolve the issue, we can have a build step that prints the settings for the appropriate environment to an `.env.browser.json` file, and then only use that file on the client-side.
+
+```
+node print-browser-env
+```
+
+Furthermore, we should replicate the `env` file from the server-side in the client-side, so that application settings are consumed in much of the same way in both sides of the wire.
+
+```
+// client/env
+import env from './env.browser.json'
+
+export default function accessor(key) {
+  if (typeof key === 'string') {
+    return env[key]
+  }
+  return env
+}
+```
+
+There are many other ways of storing our application settings, each with their pros and cons. The approach we just discussed, though, is relatively easy to implement and solid enough to get started. As an upgrade, you might want to look into using AWS Secrets Manager. That way, you'd have a single secret to take care of in team members' environments, instead of every single secret. A secret service also takes care of encryption, secure storage, secret rotation (useful in the case of a data breach), among other advanced features.
+
 ==== 6.2 Explicit Dependency Management
 
 It's not practical to include dependencies in our repositories, given these are often in the hundreds of megabytes and often include environment-dependant and operating system dependant files. During development, we want to make sure we get non-breaking upgrades to our dependencies, which can help us resolve bugs and tighten our grip around security vulnerabilities. For deployments, we want reproducible builds, where installing our dependencies yields the same results every time. The solution is often to include a dependency manifest, indicating what exact versions of the libraries in our dependency tree we want to be installing. This can be accomplished with npm (starting with version 5) and its `package-lock.json` manifest, as well as through the Yarn package manager and its `yarn.lock` manifest, both of which we should be publishing to our versioned repository.

From 4bd09b191b8ba7ca74af04b4aa6044412094bf3d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Tue, 29 May 2018 17:31:31 -0300
Subject: [PATCH 31/71] lines

---
 chapters/ch06.asciidoc | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 71d62f3..ab1affb 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -114,7 +114,9 @@ export default function accessor(key) {
 }
 ```
 
-There are many other ways of storing our application settings, each with their pros and cons. The approach we just discussed, though, is relatively easy to implement and solid enough to get started. As an upgrade, you might want to look into using AWS Secrets Manager. That way, you'd have a single secret to take care of in team members' environments, instead of every single secret. A secret service also takes care of encryption, secure storage, secret rotation (useful in the case of a data breach), among other advanced features.
+There are many other ways of storing our application settings, each with their pros and cons. The approach we just discussed, though, is relatively easy to implement and solid enough to get started. As an upgrade, you might want to look into using AWS Secrets Manager. That way, you'd have a single secret to take care of in team members' environments, instead of every single secret.
+
+A secret service also takes care of encryption, secure storage, secret rotation (useful in the case of a data breach), among other advanced features.
 
 ==== 6.2 Explicit Dependency Management
 

From 1f2360b0a4d468089a96baa20fd673520bad3af8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sat, 2 Jun 2018 16:14:48 -0300
Subject: [PATCH 32/71] tweaks

---
 chapters/ch06.asciidoc | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index ab1affb..771c851 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -42,6 +42,8 @@ There's an npm package called `nconf` which we can use to handle reading and mer
 
 The following piece of code shows how you could configure `nconf` to do what we've just described.
 
+We import the `nconf` package, and declare configuration sources from highest priority to lowest priority, while `nconf` will do the merging (higher priority settings will always take precedence). We then set the actual `NODE_ENV` environment variable, because libraries often rely on this property to decide whether to instrument or optimize their output.
+
 ```
 // env
 import nconf from 'nconf'
@@ -90,8 +92,10 @@ Then, we could write a tiny script like the following to print all of those sett
 
 ```
 // print-browser-env
-import env from './lib/env'
-console.log(env('BROWSER_ENV'))
+import env from './env'
+const browserEnv = env('BROWSER_ENV')
+const prettyJson = JSON.stringify(browserEnv, null, 2)
+console.log(prettyJson)
 ```
 
 Naturally, we don't want to mix server-side settings with browser settings, because browser settings are usually accessible to anyone with a user agent, the ability to visit our website, and basic programming skills, meaning we would do well not to bundle highly sensitive secrets with our client-side applications. To resolve the issue, we can have a build step that prints the settings for the appropriate environment to an `.env.browser.json` file, and then only use that file on the client-side.
@@ -103,7 +107,7 @@ node print-browser-env
 Furthermore, we should replicate the `env` file from the server-side in the client-side, so that application settings are consumed in much of the same way in both sides of the wire.
 
 ```
-// client/env
+// browser/env
 import env from './env.browser.json'
 
 export default function accessor(key) {
@@ -114,7 +118,7 @@ export default function accessor(key) {
 }
 ```
 
-There are many other ways of storing our application settings, each with their pros and cons. The approach we just discussed, though, is relatively easy to implement and solid enough to get started. As an upgrade, you might want to look into using AWS Secrets Manager. That way, you'd have a single secret to take care of in team members' environments, instead of every single secret.
+There are many other ways of storing our application settings, each with their own associated pros and cons. The approach we just discussed, though, is relatively easy to implement and solid enough to get started. As an upgrade, you might want to look into using AWS Secrets Manager. That way, you'd have a single secret to take care of in team members' environments, instead of every single secret.
 
 A secret service also takes care of encryption, secure storage, secret rotation (useful in the case of a data breach), among other advanced features.
 

From 8157323f48008a97722a55c037f985519e5e0cba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sat, 2 Jun 2018 16:40:07 -0300
Subject: [PATCH 33/71] tweak words

---
 chapters/ch05.asciidoc | 32 ++++++++++----------------------
 1 file changed, 10 insertions(+), 22 deletions(-)

diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index 86cebc5..8532aa1 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -99,7 +99,7 @@ const {
 } = response
 ----
 
-When using `:` to alias, it can be difficult at first to remember whether the original name, or the aliased name comes first. One helpful way to keep this straight is to mentally replace `:` with the word "as."  So `name: responseContactName` would read as "name as responseContactName." 
+When using `:` to alias, it can be difficult at first to remember whether the original name or the aliased name comes first. One helpful way to keep it straight is to mentally replace `:` with the word "as".  That way, `name: responseContactName` would read as "name as responseContactName".
 
 We can even have the same property listed twice, if we wanted to destructure some of its contents, while also maintaining access to the object itself.  For example, if we wanted to destructure the `contact` object's contents, like we do above, but also take a reference to the whole `contact` object, we can do the following
 
@@ -191,16 +191,6 @@ const finalValues = doubledValues.filter(value => value > 5)
 // <- [6, 8, 10]
 ----
 
-NOTE - this doesn't make sense.  The original example assigned to the SAME variable over and over again.  Wouldn't the simplified, equivalent code just chain the subsequent calls?
-
-[source,javascript]
-----
-let values = [1, 2, 3, 4, 5]
-  .map(value => value * 2)
-  .filter(value => value > 5)
-// <- [6, 8, 10]
-----
-
 Let's move onto a more interesting topic: asynchronous code flows.
 
 ==== 5.1.4 Navigating Callbacks, Promises, and Asynchronous Functions
@@ -490,26 +480,24 @@ Having event listeners allowed a component to receive a message, perhaps process
 
 ==== 5.3.4 Message Passing and the Simplicity of JSON
 
-When it comes to ServiceWorker, web workers, browser extensions, frames, API calls, or WebSocket integrations, we might run into issues if we don't plan for robust data serialization ahead of time. This is a place where using classes to represent data can break down, because we need a way to serialize class instances into raw data (typically JSON) before sending over the wire, and, crucially, the recipient needs to decode this JSON back into a class instance. It's the second part where classes start to fail, since there isn't a standardized way of reconstructing a class instance from JSON. For example
+When it comes to ServiceWorker, web workers, browser extensions, frames, API calls, or WebSocket integrations, we might run into issues if we don't plan for robust data serialization ahead of time. This is a place where using classes to represent data can break down, because we need a way to serialize class instances into raw data (typically JSON) before sending it over the wire, and, crucially, the recipient needs to decode this JSON back into a class instance. It's the second part where classes start to fail, since there isn't a standardized way of reconstructing a class instance from JSON. For example:
 
 [source,javascript]
 ----
-class Person{
-  constructor(name, address){
-    this.name = name;
-    this.address = address;
+class Person {
+  constructor(name, address) {
+    this.name = name
+    this.address = address
   }
-  speak(){
-    alert(`My name is ${this.name}`);
+  greet() {
+    console.log(`Hi! My name is ${ this.name }.`)
   }
 }
 
-let nico = new Person("Nico", "123 Main St");
+const rwanda = new Person('Rwanda', '123 Main St')
 ----
 
-Although we can easily serialize our `nico` instance with `JSON.stringify(nico);`, and then send it over the wire, the code on the other end will have no standard way of turning this JSON back into an instance of our `Person` class.
-
-NOTE: then again, can you clarify why the receiving end would need to deserialize the data back into class instances, rather than just use raw object literals?  Assymetric representations of the same data is likely uglfy, and needlessly complex, and so possibly the only reason, and a good one, but it might be worth spelling out explicitly.
+Although we can easily serialize our `rwanda` instance with `JSON.stringify(rwanda)`, and then send it over the wire, the code on the other end will have no standard way of turning this JSON back into an instance of our `Person` class, which might have a lot more functionality than merely a `greet` function. The receiving end might have no business deserializing this data back into the class instance it originated from, but in some cases there's merit to having an exact replica object back on the other end. For example, to reduce friction when passing messages between a website and a web worker, both sides should be dealing in the same data structure. In such scenario, simple JavaScript objects are ideal.
 
 JSON, a subset of the JavaScript grammar, was purpose-built for this use case, where we often have to serialize data, send it over the wire, and deserialize it on the other end. Plain JavaScript objects are a great way to store data in our applications, offer frictionless serialization out the box, and lead to cleaner data structures because we can keep logic decoupled from the data.
 

From decfbd9451c3c0d1a21e04f8afe142261bea2db8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sat, 2 Jun 2018 16:44:27 -0300
Subject: [PATCH 34/71] merge

---
 chapters/ch06.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 771c851..b125599 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -7,7 +7,7 @@ In this chapter we'll explore open-source principles and look at ways in which w
 
 === 6.1 Secure Configuration Management
 
-When it comes to configuration secrets in closed-source projects, like API keys or HTTP session decryption keys, it is not uncommon for them to be hardcoded in place. In open-source projects, instead, these are typically instead obtained through environment variables or encrypted configuration files that aren't committed to version control systems alongside our codebase.
+When it comes to configuration secrets in closed-source projects, like API keys or HTTP session decryption keys, it is not uncommon for them to be hard-coded in place. In open-source projects, instead, these are typically instead obtained through environment variables or encrypted configuration files that aren't committed to version control systems alongside our codebase.
 
 In the case of open-source projects, this allows the developer to share the vast majority of their application without compromising the security of their production systems. While this might not be an immediate concern in closed-source environments, we need to consider that once a secret is committed to version control, it's etched into our version history unless we force a rewrite of that history, scrubbing the secrets from existence. Even then, it cannot be guaranteed that a malicious actor has gained access to these secrets at some point before they were scrubbed from history, and thus a better solution to this problem is rotating the secrets that might be compromised, revoking access through the old secrets and starting to use new, uncompromised secrets.
 

From 296ffb1cefe444be5b186416f932925d8d946aa7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sat, 2 Jun 2018 16:45:43 -0300
Subject: [PATCH 35/71] cleanup

---
 chapters/ch01.asciidoc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/chapters/ch01.asciidoc b/chapters/ch01.asciidoc
index 4cf384f..45cd2cd 100644
--- a/chapters/ch01.asciidoc
+++ b/chapters/ch01.asciidoc
@@ -33,7 +33,7 @@ When it comes to JavaScript, modularity is a modern concept. In this section we'
 
 ==== 1.2.1 Script Tags and Closures
 
-In the early days, JavaScript was in-lined in HTML `<script>` tags. At best, it was offloaded to dedicated script files, all of which shared a global scope.
+In the early days, JavaScript was inlined in HTML `<script>` tags. At best, it was offloaded to dedicated script files, all of which shared a global scope.
 
 Any variables declared in one of these files or inline scripts would be imprinted on the global `window` object, creating leaks across entirely unrelated scripts that might've lead to conflicts or even broken experiences, where a variable in one script might inadvertently replace a global that another script was relying on.
 
@@ -188,7 +188,7 @@ Maintainability, or the ability to effect change in the codebase, also improves
 
 Modular code is meant to be highly maintainable by default. By keeping pieces of code simple and following the Single Responsibility Principle (SRP), whereby it only aims to fulfill one goal, and combining these simple pieces of code into more sophisticated components, we're able to compose our way to larger components, and eventually an entire application. When each piece of code in a program is modular, the codebase appears to be simple when we're looking at individual components, yet on the whole it is able to exhibit complex behaviors, just like the book publishing process we've discussed in the beginning of this chapter.
 
-Components in modular applications are defined by their interfaces. The implementation of those components is not their essence, but their interfaces are. When interfaces are well-designed, they can be grown in non-breaking ways, augmenting the amount of use cases they can satisfy, without compromising existing usage. When we have a mindfully designed interface, the implementation behind that interface becomes easy to tweak or swap entirely. Strong interfaces are effective at hiding away weak implementations, that can be later refactored into more robust implementations provided the interface holds. Strong interfaces are also excellent for unit testing, because we won't have to worry about the implementation and we can test the interface, -- the inputs and outputs of a component or function. If the interface is well-tested and robust, we can surely consider its implementation in a secondary plane.
+Components in modular applications are defined by their interfaces. The implementation of those components is not their essence, but their interfaces are. When interfaces are well-designed, they can be grown in non-breaking ways, augmenting the amount of use cases they can satisfy, without compromising existing usage. When we have a mindfully designed interface, the implementation behind that interface becomes easy to tweak or swap entirely. Strong interfaces are effective at hiding away weak implementations, that can be later refactored into more robust implementations provided the interface holds. Strong interfaces are also excellent for unit testing, because we won't have to worry about the implementation and we can test the interface -- the inputs and outputs of a component or function. If the interface is well-tested and robust, we can surely consider its implementation in a secondary plane.
 
 Given those implementations are secondary to the foremost requirement of having intuitive interfaces, that aren't coupled to their implementations, we can concern ourselves with the trade-off between flexibility and simplicity. Flexibility inevitably comes at the cost of added complexity, which is a good reason not to offer flexible interfaces. At the same time, flexibility is often a necessity, and thus we need to strike the right balance by deciding how much rigidity we can get away with in our interfaces. This balance would mean an interface appeases its consumers thanks to its ease of use, but that it also enables advanced or more uncommon use cases when needed, without too much of a detrimental effect on the ease of use or at the cost of greatly enhanced implementation complexity.
 

From 489f3d8735d9545fa0781fd505723c0c0effea31 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sat, 2 Jun 2018 17:27:32 -0300
Subject: [PATCH 36/71] Address feedback from @mathias

---
 chapters/ch01.asciidoc | 14 ++++++------
 chapters/ch02.asciidoc | 51 +++++++++++++++++++++---------------------
 chapters/ch03.asciidoc |  2 +-
 chapters/ch04.asciidoc | 44 ++++++++++++++++++++++++++----------
 chapters/ch05.asciidoc | 32 +++++++++++++++++---------
 5 files changed, 88 insertions(+), 55 deletions(-)

diff --git a/chapters/ch01.asciidoc b/chapters/ch01.asciidoc
index 45cd2cd..ddd5d6e 100644
--- a/chapters/ch01.asciidoc
+++ b/chapters/ch01.asciidoc
@@ -19,7 +19,7 @@ Embracing module thinking is understanding that complexity is, ultimately, inesc
 
 Systems can be organized granularly: we can split them into projects, made of multiple applications, containing several application-level layers, where we can have hundreds of modules, made up of thousands of functions, and so on. A granular approach helps us write code that's easy to understand and maintain, by attaining a reasonable degree of modularity, while preserving our sanity. In section 1.4, we'll discuss how we can best leverage this granularity to create modular applications.
 
-Whenever we delineate a component, there's going to be a public interface other parts of the system can leverage to access our component. The interface -- or API -- will be comprised of the set of methods or attributes that our component exposes. These methods or attributes, can also be referred to as touchpoints, that is, the aspects of the interface that can be publicly interacted with. The fewer touchpoints an interface has, the smaller its surface area is, and the simpler the interface becomes. An interface with a large surface area is highly flexible, but it might also be a lot harder to understand and use, given the high amount of functionality exposed by the interface.
+Whenever we delineate a component, there's going to be a public interface which other parts of the system can leverage to access our component. The interface -- or API -- is comprised of the set of methods or attributes that our component exposes. These methods or attributes, can also be referred to as touchpoints, that is, the aspects of the interface that can be publicly interacted with. The fewer touchpoints an interface has, the smaller its surface area is, and the simpler the interface becomes. An interface with a large surface area is highly flexible, but it might also be a lot harder to understand and use, given the high amount of functionality exposed by the interface.
 
 This interface serves a dual purpose. It allows us to develop new bits and pieces of the component, only exposing functionality that's ready for public consumption while keeping private everything that's not meant to be shared with other components. At the same time, it allows consumers -- that is, components or systems that are leveraging our interface -- to reap the benefits of the functionality we expose, without concerning themselves with the details of how we implemented that functionality.
 
@@ -154,7 +154,7 @@ Much like RequireJS and AngularJS, CommonJS dependencies are also referred to by
 
 Unlike RequireJS or AngularJS, CommonJS was rather strict. In RequireJS and AngularJS you could have many dynamically-defined modules per file, whereas CommonJS had a one-to-one mapping between files and modules. At the same time, RequireJS had several ways of declaring a module and AngularJS had several kinds of factories, services, providers and so on -- besides the fact that its dependency injection mechanism was tightly coupled to the AngularJS framework itself. CommonJS, in contrast, had a single way of declaring modules. Any JavaScript file was a module, calling `require` would load dependencies, and anything assigned to `module.exports` was its interface. This enabled better tooling and code introspection -- making it easier for tools to learn the hierarchy of a CommonJS component system.
 
-Eventually, Browserify was invented as a way of bridging the gap between CommonJS modules for Node.js servers and the browser. Using the `browserify` command-line interface program and providing it with the path to an entry point module, one could combine an unthinkable amount of modules into a single browser-ready bundle. The killer feature of CommonJS, the npm package registry, was decisive in aiding its takeover of the module loading ecosystem.
+Eventually, Browserify was invented as a way of bridging the gap between CommonJS modules for Node.js servers and the browser. Using the `browserify` command-line interface program and providing it with the path to an entry-point module, one could combine an unthinkable amount of modules into a single browser-ready bundle. The killer feature of CommonJS, the npm package registry, was decisive in aiding its takeover of the module loading ecosystem.
 
 Granted, npm wasn't limited to CommonJS modules or even JavaScript packages, but that was and still is by and large its primary use case. The prospect of having thousands of packages (now over half a million and steadily growing) available in your web application at the press of a few fingertips, combined with the ability to reuse large portions of a system on both the Node.js web server and each client's web browser, was too much of a competitive advantage for the other systems to keep up.
 
@@ -174,15 +174,15 @@ import('./mathlib').then(mathlib => {
 
 In ESM, too, every file is a module with its own scope and context. One major advantage in ESM over CJS is how ESM has -- and encourages -- a way of statically importing dependencies. Static imports vastly improve the introspection capabilities of module systems, given they can be analyzed statically and lexically extracted from the abstract syntax tree (AST) of each module in the system. Static imports in ESM are constrained to the topmost level of a module, further simplifying parsing and introspection.
 
-In Node.js v8.5.0, ESM module support was introduced behind a flag. Most evergreen browsers also support ESM modules behind flags.
+In Node.js v8.5.0, ESM support was introduced behind an `--experimental-modules` flag -- provided that we use the `.mjs` file extension for our modules. Most evergreen browsers already support ESM without flags.
 
-Webpack is a successor to Browserify that largely took over in the role of universal module bundler thanks to a broader set of features. Just like in the case of Babel and ES6, Webpack has long supported ESM with both its `import` and `export` statements as well as the dynamic `import()` function. It has made a particularly fruitful adoption of ESM, in no little parts thanks to the introduction of a "code-splitting" mechanism whereby it's able to partition an application into different bundles to improve performance on first load experiences.
+Webpack is a successor to Browserify that largely took over in the role of universal module bundler thanks to a broader set of features. Just like in the case of Babel and ES6, Webpack has long supported ESM with both its static `import` and `export` statements as well as the dynamic `import()` function-like expression. It has made a particularly fruitful adoption of ESM, in no little parts thanks to the introduction of a "code-splitting" mechanism whereby it's able to partition an application into different bundles to improve performance on first load experiences.
 
 Given how ESM is native to the language, -- as opposed to CJS -- it can be expected to completely overtake the module ecosystem in a few years time.
 
 === 1.3 The Perks of Modular Design
 
-We've already addressed the fact that modularity, as opposed to a single shared global scope, helps avoid unexpected clashes in variable names thanks to the diversification of scoping across modules. Beyond a fix for clashes, modularity spread across files limits the amount of complexity we have to pay attention to when working on any one particular feature. In doing so, our team will be able to focus on the task at hand and be more productive as a result.
+We've already addressed the fact that modularity, as opposed to a single shared global scope, helps avoid unexpected clashes in variable names thanks to the diversification of scoping across modules. Beyond a fix for clashes, modularity spread across files limits the amount of complexity we have to pay attention to when working on any one particular feature. In doing so, our team is able to focus on the task at hand and be more productive as a result.
 
 Maintainability, or the ability to effect change in the codebase, also improves significantly because of this. When code is simple and modular, it's easier to build upon and extend. Maintainability is valuable regardless of team size: even in a team of one, if we leave a piece of code untouched for a few months and then come back to it, it might be hard to improve upon or even understand if we didn't consider writing maintainable code the first time around.
 
@@ -212,7 +212,7 @@ Going back to performance, we should be treating it as a feature, where for the
 
 We, as developers, often over-do architecture as well, and a lot of the reasoning about performance optimization applies here as well. Laying out an all-encompassing architecture that has the potential to save us trouble as we scale to billions of transactions per second might cost us considerable time spent upfront and possibly also lock us into a series of abstractions that will be hard to keep up with, for no foreseeable gains in the near term. It's a lot better when we focus on problems we're already running into, or might soon run into, instead of trying to plan for a hockey-stick growth of infrastructure and throughput without any data to back up the hockey-stick growth we're anticipating.
 
-When we don't plan in such a long-term form, an interesting thing occurs, our systems will grow more naturally, adapting to the needs of the near-term, gradually progressing towards support for a larger application and larger set of requirements. When that progression is gradual, we'll notice a corrective behavior in how abstractions are picked up or discarded as we grow. If we settle on abstractions too early, and they end up being the wrong abstractions, we'll pay dearly for that mistake. Bad abstractions force us to bend entire applications to their will, and once we've realized that the abstraction is bad and ought to be removed, we might be so heavily invested in it that pulling out might be costly. This, paired with the sunk cost fallacy, whereby we're tempted to keep the abstraction just because we've spent a lot of time, sweat, and blood on it, can be very hazardous indeed.
+When we don't plan in such a long-term form, an interesting thing occurs: our systems grow more naturally, adapting to the needs of the near-term, gradually progressing towards support for a larger application and larger set of requirements. When that progression is gradual, we notice a corrective behavior in how abstractions are picked up or discarded as we grow. If we settle on abstractions too early, and they end up being the wrong abstractions, we pay dearly for that mistake. Bad abstractions force us to bend entire applications to their will, and once we've realized that the abstraction is bad and ought to be removed, we might be so heavily invested in it that pulling out might be costly. This, paired with the sunk cost fallacy, whereby we're tempted to keep the abstraction just because we've spent a lot of time, sweat, and blood on it, can be very hazardous indeed.
 
 We'll devote an important part of this book to understanding how we can identify and leverage the right abstractions at the right time, so that the risk they incur is minimized.
 
@@ -222,7 +222,7 @@ Due to its history, JavaScript is particularly interesting when it comes to modu
 
 The lack of native modularity in the web -- due to the way a program is loaded in chunks using HTML `<script>` tags -- is in stark contrast with any other execution environments where programs can be made up of any number of files and modular architectures are natively supported by the language, its compiler, and its file system based environment. On the web, we're only now barely beginning to scratch the surface of native modules, something other programming environments have had since their inception. As we discussed in section 1.2, the lack of a native module loading mechanism, paired with the lack of native modules beyond just files that shared a global scope, forced the web community to get creative in its approach to modularity.
 
-The native JavaScript modules specification that eventually landed into the language was heavily influenced by this community-led effort. Even as of this writing we're still probably some 5 years away from being able to use the native module system effectively on the web. This shortcoming of the web is evidenced by how patterns that were adopted universally elsewhere, like layered or component-based architectures, weren't even contemplated on the web for most of its lifetime thus far.
+The native JavaScript modules specification that eventually landed into the language was heavily influenced by this community-led effort. Even as of this writing we're still probably some 2 or 3 years away from being able to use the native module system effectively on the web. This shortcoming of the web is evidenced by how patterns that were adopted universally elsewhere, like layered or component-based architectures, weren't even contemplated on the web for most of its lifetime thus far.
 
 Up until the launch of a Gmail beta client in April, 2004, which demonstrated the power of asynchronous JavaScript HTTP requests to provide a single-page application experience, and then the initial release of jQuery in 2006, which provided a hassle-free cross-browser web development experience, JavaScript was seldom regarded as a serious modern development platform.
 
diff --git a/chapters/ch02.asciidoc b/chapters/ch02.asciidoc
index c057d64..7a4f019 100644
--- a/chapters/ch02.asciidoc
+++ b/chapters/ch02.asciidoc
@@ -264,9 +264,9 @@ This is akin to how some libraries were written in the days before JavaScript ha
 })()
 ----
 
-When exposing touchpoints on an interface, it's important to gauge if consumers will need the touchpoint at all, how it helps them, and whether it could be made simpler. For instance, it might be the case that instead of exposing several different touchpoints the user can pick from, they'd be better off with a single touchpoint that leverages the appropriate code path based on provided inputs while, at the same time, the component would couple a smaller part of its implementation to its interface.
+When exposing touchpoints on an interface, it's important to gauge if consumers need the touchpoint at all, how it helps them, and whether it could be made simpler. For instance, it might be the case that instead of exposing several different touchpoints the user can pick from, they're be better off with a single touchpoint that leverages the appropriate code path based on provided inputs while, at the same time, the component would couple a smaller part of its implementation to its interface.
 
-Thinking in API-first terms can help, because then we'd have a decent idea of the kind of API surface we want, and armed with that we can decide how we want to allow consumers to interact with the component.
+Thinking in API-first terms can help, because then we have a decent idea of the kind of API surface we want, and armed with that we can decide how we want to allow consumers to interact with the component.
 
 As new use cases arise and our component system grows, we should stick to an API-first mindset and the revealing pattern, so that the component doesn't suddenly become more complex. Gradually introducing complexity can help us design the right interface for our component. One where we don't offer every solution imaginable, but also one where we elegantly solve the consumer's use cases, provided they fall within the responsibility of our component.
 
@@ -276,7 +276,7 @@ Open-source software components often get feature requests that are overly speci
 
 Granted, it's important for a component to satisfy the needs of most of its consumers, but this doesn't mean we should attempt to satisfy use cases one by one, or in isolation. Almost invariably, doing so results in duplicated logic, inconsistency at the API level, and several different ways of accomplishing the same goal, often with inconsistent observed results.
 
-When a commonality can be found, abstractions involve less friction and help avoid the inconsistencies named earlier. Consider for example the case of DOM event listeners, where we have an HTML attribute and matching JavaScript DOM element property for each event, such as `onclick`, `onchange`, `oninput`, and so on. Each of these properties can be assigned a `listener` function that handles the event. Then there's `EventTarget#addEventListener`, which has a signature like `addEventListener(type, listener, options)`​footnoteref:[addeventlistener-options,The `options` parameter is an optional configuration object -- that's relatively new to the Web API -- where we can set flags such as `capture`, which has the same behavior as passing a `useCapture` flag; `passive`, which suppresses calls to `event.preventDefault()` in the `listener`; and `once`, which indicates the event listener should be removed after being invoked for the first time.], centralizing all event handling logic in a single method that takes the `type` of event as a parameter. Naturally, this API is better for a number of reasons. First off, `EventTarget#addEventListener` is a method, making its behavior clearly defined. Meanwhile `on*` handlers are set through assignment, which isn't as clearly defined: when does the effect of assigning an event handler begin? how is the handler removed? are we limited to a single event handler or is there a way around it? are we going to get an error when we assign a non-function value as an event listener, will the raised event result in an error when trying to invoke the non-function? Furthermore, new event types can be added transparently to `addEventListener`, without having to change the API surface, whereas with the `on*` technique we would have to introduce yet another property.
+When a commonality can be found, abstractions involve less friction and help avoid the inconsistencies named earlier. Consider for example the case of DOM event listeners, where we have an HTML attribute and matching JavaScript DOM element property for each event handler, such as `onclick`, `onchange`, `oninput`, and so on. Each of these properties can be assigned a `listener` function that handles the event. Then there's `EventTarget#addEventListener`, which has a signature like `addEventListener(type, listener, options)`​footnoteref:[addeventlistener-options,The `options` parameter is an optional configuration object -- that's relatively new to the Web API -- where we can set flags such as `capture`, which has the same behavior as passing a `useCapture` flag; `passive`, which suppresses calls to `event.preventDefault()` in the `listener`; and `once`, which indicates the event listener should be removed after being invoked for the first time.], centralizing all event handling logic in a single method that takes the `type` of event as a parameter. Naturally, this API is better for a number of reasons. First off, `EventTarget#addEventListener` is a method, making its behavior clearly defined. Meanwhile `on*` handlers are set through assignment, which isn't as clearly defined: when does the effect of assigning an event handler begin? how is the handler removed? are we limited to a single event handler or is there a way around it? are we going to get an error when we assign a non-function value as an event listener, will the raised event result in an error when trying to invoke the non-function? Furthermore, new event types can be added transparently to `addEventListener`, without having to change the API surface, whereas with the `on*` technique we would have to introduce yet another property.
 
 Another case where abstractions come in handy might be whenever we are dealing with quirks in cross-browser DOM manipulation. Having a function like `on(element, eventType, eventListener)` would be superior than testing whether `addEventListener` is supported and deciding which of the various event listening options is optimal for each case, every time, as it drastically reduces code duplication while also handling every case consistently, limiting complexity.
 
@@ -296,7 +296,7 @@ Besides state for an individual user and application-wide state, there's also th
 
 We shall think of state as our program's internal entropy. When state reigns, entropy reigns, and the application becomes unbearably hard to debug. One of the goals in modular design is to keep state to the minimum possible. As an application grows larger so does its state and the possible state permutations grow with it. Modularity takes aim at this issue by chopping a state tree into manageable bits and pieces, where each branch of the tree deals with a particular subset of the state. This approach enables us to contain the growing application state as our codebase grows in size.
 
-A function is deemed pure when it's output depends solely on its input. Pure functions do not produce any side effects other than the output that's returned. In the following example, the `sum` function receives a list of `numbers` and returns the sum of adding all of them together. It is a pure function because it doesn't take into account any external state, and it doesn't emit any side effects.
+A function is deemed pure when its output depends solely on its input. Pure functions do not produce any side effects other than the output that's returned. In the following example, the `sum` function receives a list of `numbers` and returns the sum of adding all of them together. It is a pure function because it doesn't take into account any external state, and it doesn't emit any side effects.
 
 [source,javascript]
 ----
@@ -305,7 +305,7 @@ function sum(numbers) {
 }
 ----
 
-Sometimes we'll have a requirement to keep state across function calls. For instance, a simple incremental counter might lead to us to implement a module such as the following. The `increment` function isn't pure, given that `count` is external state.
+Sometimes we have a requirement to keep state across function calls. For instance, a simple incremental counter might lead to us to implement a module such as the following. The `increment` function isn't pure, given that `count` is external state.
 
 [source,javascript]
 ----
@@ -328,7 +328,7 @@ const factory = () => {
 export default factory
 ----
 
-As long as we limit the usage of each counter spewed by the `factory` to a given portion of the application which knows about each other usage, the state becomes more manageable, as we end up with less moving parts involved. When we eliminate impurity in public interfaces, we're effectively circumscribing entropy to the calling code. The consumer receives a brand new counter every time, and it's entirely responsible for managing its state. It can still pass the `counter` down to its dependents, but it's in control of how dependents get to manipulate that state, if at all.
+As long as we limit the usage of each counter spewed by the `factory` to a given portion of the application which knows about each other usage, the state becomes more manageable, as we end up with fewer moving parts involved. When we eliminate impurity in public interfaces, we're effectively circumscribing entropy to the calling code. The consumer receives a brand new counter every time, and it's entirely responsible for managing its state. It can still pass the `counter` down to its dependents, but it's in control of how dependents get to manipulate that state, if at all.
 
 This is something we observe in the wild, with popular libraries such as the `request` packagefootnote:[You can find `request` here: https://mjavascript.com/out/request.] in Node.js, which can be used to make HTTP requests. The `request` function relies largely on sensible defaults for the `options` you can pass to it. Sometimes, we want to make requests using a different set of defaults.
 
@@ -374,17 +374,17 @@ One prominent example of flexible inputs can be found in the jQuery library. Wit
 - `$(html, attributes)`
 - `$(callback)`
 
-Though it's not uncommon for JavaScript libraries to offer a getter and a setter as overloads of the same method, API methods should generally have a single, well defined responsibility. Most of the time, this translates into clean-cut API design. In the case of the dollar function, we have three different use cases.
+Though it's not uncommon for JavaScript libraries to offer a getter and a setter as overloads of the same method, API methods should generally have a single, well-defined responsibility. Most of the time, this translates into clean-cut API design. In the case of the dollar function, we have three different use cases.
 
 - `$(callback)` binds a function to be executed when the DOM has finished loading
 - `$(html)` overloads create elements out of the provided `html`
 - Every other overload matches elements in the DOM against the provided input
 
-While we might consider selectors and element creation to play the role of getters and setters, the `$(callback)` overload feels out of place. We need to take a step back and realize that jQuery is a decade old library which revolutionized front-end development due -- in no small part -- to its ease of use. Back in the day, the requirement to wait for DOM ready was in heavy demand and so it made sense to promote it to the dollar function. Needless to say, jQuery is quite a unique case, but it's nevertheless an excellent example of how providing multiple overloads can result in a dead simple interface, even when there's more overloads than the user can keep in the back of their heads. Most methods in jQuery offer several ways for consumers to present inputs without altering the responsibilities of those methods.
+While we might consider selectors and element creation to play the role of getters and setters, the `$(callback)` overload feels out of place. We need to take a step back and realize that jQuery is a decade-old library which revolutionized front-end development due -- in no small part -- to its ease of use. Back in the day, the requirement to wait for DOM ready was in heavy demand and so it made sense to promote it to the dollar function. Needless to say, jQuery is quite a unique case, but it's nevertheless an excellent example of how providing multiple overloads can result in a dead simple interface, even when there's more overloads than the user can keep in the back of their heads. Most methods in jQuery offer several ways for consumers to present inputs without altering the responsibilities of those methods.
 
 A new library with a shape similar to jQuery would be a rare find. Modern JavaScript libraries and applications favor a more modular approach, and so the DOM ready callback would be its own function, and probably its own package. There's still insight to be had by analyzing jQuery, though. This library had great user experience due to its consistency. One of the choices in jQuery was not to throw errors, which were reserved for bugs, user errors in our own code, or invalid selectors, in order to avoid frustrated users. Whenever jQuery finds an inappropriate input parameter, it prefers to return an empty list of matches instead. Silent failures can however be tricky: they might leave the consumer without any cues as to what the problem is, wondering whether it's an issue in their code, a bug in the library they're using, or something else.
 
-Even when a library is as flexible as jQuery is, it's important to identify invalid input early. As an example, the next snippet shows how jQuery will throw an error on selectors it can't parse.
+Even when a library is as flexible as jQuery is, it's important to identify invalid input early. As an example, the next snippet shows how jQuery throws an error on selectors it can't parse.
 
 [source,javascript]
 ----
@@ -398,8 +398,10 @@ A good example of optional parameters is the native DOM `fetch` API. In the next
 
 [source,javascript]
 ----
-fetch('/api/users')
-fetch('/api/users/rob', { method: 'DELETE' })
+await fetch('/api/users')
+await fetch('/api/users/rob', {
+  method: 'DELETE'
+})
 ----
 
 Supposing that -- if we were the API designers for `fetch` -- we originally devised `fetch` as just a way of doing `GET ${ resource }`. When we got a requirement for a way of choosing the HTTP method, we could've avoided the options object and reached directly for a `fetch(resource, method)` overload. While this would've served our particular requirement, it would've been short-sighted. As soon as we got a requirement to configure something else, we'd be left with the need of supporting both `fetch(resource, method)` and `fetch(resource, options)` overloads, so that we avoid breaking backward compatibility. Worse still, we might be tempted to introduce a third parameter that configures our next requirement. Soon, we'd end up with an API such as the infamous `KeyboardEvent#initKeyEvent` methodfootnote:[See the MDN documentation at https://mjavascript.com/out/initkeyevent.], whose signature is outlined below.
@@ -427,15 +429,15 @@ A key aspect of API design is readability. How far can users get without having
 - The consumer doesn't need to concern herself with options they don't need
 - Developers reading pieces of code which consume the API can immediately understand what parameters are being used, since they're explicitly named in the options object
 
-As we make progress, we'll keep naturally coming back to the `options` object in API design.
+As we make progress, we keep naturally coming back to the `options` object in API design.
 
 ==== 2.2.3 Unambiguity
 
 The output shape for a function shouldn't depend on how it received its input or the result that was produced. This rule is almost universally agreed upon: you should aim to surprise consumers of your API as little as possible. There are a couple of cases where we may slip up and end up with an ambiguous API. For the same kind of result, we should return the same kind of output.
 
-For instance, `Array#find` always returns `undefined` when it doesn't find any items that match the provided predicate function. If it instead returned `null` when the array is empty, for example, that'd be inconsistent and wrong. We'd be making the consumer unsure about whether they should test for `undefined` or `null`, and they might end up being tempted to use loose equality comparison because of that uncertainty.
+For instance, `Array#find` always returns `undefined` when it doesn't find any items that match the provided predicate function. If it instead returned `null` when the array is empty, for example, that'd be inconsistent with other use cases, and thus wrong. We'd be making the consumer unsure about whether they should test for `undefined` or `null`, and they might end up being tempted to use loose equality comparison because of that uncertainty, given `== null` matches both `null` and `undefined`.
 
-On the same vein, we should avoid optional input parameters which transform the result into a different data type. Favor composability -- or a new method -- instead, where possible. An option which decides whether a raw object such as a `Date` or a DOM element should be  wrapped in an instance of jQuery or similar libraries such as `moment` before returning the result, or a `json` option which causes the result to be a JSON string when `true` and an object otherwise is ill-advised, unless there are technical reasons why we must do so.
+On the same vein, we should avoid optional input parameters which transform the result into a different data type. Favor composability -- or a new method -- instead, where possible. An option which decides whether a raw object such as a `Date` or a DOM element should be  wrapped in an instance of jQuery or similar libraries such as `moment` before returning the result, or a `json` option which causes the result to be a JSON-formatted string when `true` and an object otherwise is ill-advised, unless there are technical reasons why we must do so.
 
 It isn't necessary to treat failure and success with the same response shape, meaning that failure results can always be `null` or `undefined`, while success results might be an array list. However, consistency should be required across all failure cases and across all sucess cases, respectively.
 
@@ -447,9 +449,8 @@ Note how simple it is to use `fetch` in the simplest case: it receives the resou
 
 [source,javascript]
 ----
-fetch('/api/users/john').then(res => {
-  console.log(res.statusCode)
-})
+const res = await fetch('/api/users/john')
+console.log(res.statusCode)
 // <- 200
 ----
 
@@ -457,11 +458,9 @@ If we want to take things a bit further, we can chain onto the response object t
 
 [source,javascript]
 ----
-fetch('/api/users/john')
-  .then(res => res.json())
-  .then(data => {
-    console.log(data.name)
-  })
+const res = await fetch('/api/users/john')
+const data = res.json()
+console.log(data.name)
 // <- 'John Doe'
 ----
 
@@ -469,10 +468,12 @@ If we instead wanted to remove the user, we need to provide the `method` option.
 
 [source,javascript]
 ----
-fetch('/api/users/john', { method: `DELETE` })
+await fetch('/api/users/john', {
+  method: `DELETE`
+})
 ----
 
-The `fetch` function can't do much without a specified resource, which is why this parameter is required and not part of an options object. Having sensible defaults for every other parameter is a key component of keeping the `fetch` interface simple. The `method` defaults to `GET`, which is the most common HTTP verb and thus the one we're most likely to use. Good defaults are conservative, and good options are additive. The `fetch` function doesn't transmit any cookies by default -- a conservative default -- but a `credentials` option set to `include` will make cookies work -- an additive option.
+The `fetch` function can't do much without a specified resource, which is why this parameter is required and not part of an options object. Having sensible defaults for every other parameter is a key component of keeping the `fetch` interface simple. The `method` defaults to `GET`, which is the most common HTTP verb and thus the one we're most likely to use. Good defaults are conservative, and good options are additive. The `fetch` function doesn't transmit any cookies by default -- a conservative default -- but a `credentials` option set to `include` makes cookies work -- an additive option.
 
 In another example, we could implement a Markdown compiler function with a default option that supports autolinking resource locators, which can be disabled by the consumer with an `autolinking: false` option. In this case, the implicit default would be `autolinking: true`. Negated option names such as `avoidAutolinking` are sometimes justified because they make it so that the default value is `false`, which on the surface sounds correct for options that aren't user-provided. Negated options however tend to confuse users who are confronted with the double negative in `avoidAutolinking: false`. It's best to use additive or positive options, preventing the double negative: `autolinking: true`.
 
@@ -484,7 +485,7 @@ Any interface benefits from being its smallest possible self. A small surface ar
 
 The malleability of an interface depends on the way it is consumed. Functions and variables that are private to a module are only depended upon by other parts of that module, and are thus highly malleable. The bits that make up the public API of a module are not as malleable, since we might need to change the way each dependant uses our module. If those bits make up the public API of the package, then we're looking at bumping our library's version so that we can safely break its public API without major and unexpected repercussions.
 
-Not all changes are breaking changes, however. We might learn from an interface like the one in `fetch`, for example, which remains highly malleable even in the face of change. Even though the interface is tiny for it's simplest use case, -- `GET /resource` -- the `options` parameter can grow by leaps and bounds without causing trouble for consumers, while extending the capabilities of `fetch`.
+Not all changes are breaking changes, however. We might learn from an interface like the one in `fetch`, for example, which remains highly malleable even in the face of change. Even though the interface is tiny for its simplest use case, -- `GET /resource` -- the `options` parameter can grow by leaps and bounds without causing trouble for consumers, while extending the capabilities of `fetch`.
 
 We can avoid creating interfaces that contain several slightly different solutions for similar problems by holistically designing the interface to solve the underlying common denominator, maximizing the reusability of a component's internals in the process.
 
diff --git a/chapters/ch03.asciidoc b/chapters/ch03.asciidoc
index 9ad2520..e948f39 100644
--- a/chapters/ch03.asciidoc
+++ b/chapters/ch03.asciidoc
@@ -109,7 +109,7 @@ We've discussed interface design at great length, but we haven't touched on deci
 
 Even when the smaller component isn't being reused anywhere else, and perhaps not even tested on its own, it's still worth moving it to a different file. Why? Because we're removing the complexity that makes up the child component from its parent virtually for free. We're only paying a cheap indirection cost, where the child component is now referenced as a dependency of its parent instead of being inlined. When we split up the internals of a large component into several children, we're chopping up its internal complexity and ending up with several simple components. The complexity didn't dissipate, it's subtly hidden away in the interrelationships between these child components and their parent, but that's now the biggest concern in the parent module, whereas each of the smaller modules doesn't need to know much about these relationships.
 
-Chopping up internals doesn't merely only work for view components and their children. That said, view components pose a great example that might help us visualize how complexity can remain flat across a component system, regardless of how deep we go, instead of being contained in a large component with little structure and a high level of complexity or coupling. This is akin to looking at the universe on a macroscopic level and then taking a closer look, until we get to the atomic level, and then beyond. Each layer has its own complexities and intricacies waiting to be discovered, but the complexity is spread across the layers rather than clustered on any one particular layer. The spread reduces the amount of complexity we have to observe and deal with on any given layer.
+Chopping up internals doesn't merely only work for view components and their children. That said, view components pose a great example that might help us visualize how complexity can remain flat across a component system, regardless of how deep we go, instead of being contained in a large component with little structure and a high-level of complexity or coupling. This is akin to looking at the universe on a macroscopic level and then taking a closer look, until we get to the atomic level, and then beyond. Each layer has its own complexities and intricacies waiting to be discovered, but the complexity is spread across the layers rather than clustered on any one particular layer. The spread reduces the amount of complexity we have to observe and deal with on any given layer.
 
 Speaking of layers, it is at this stage of the design process that you might want to consider defining different layers for your application. You might be used to having models, views, and controllers in MVC applications, or maybe you're accustomed to actions, reducers, and selectors in Redux applications. Maybe you should think of implemeting a service layer where all the business logic occurs, or perhaps a persistance layer where all the caching and persistent storage takes place.
 
diff --git a/chapters/ch04.asciidoc b/chapters/ch04.asciidoc
index 215d0f7..83c0963 100644
--- a/chapters/ch04.asciidoc
+++ b/chapters/ch04.asciidoc
@@ -1,7 +1,7 @@
 [[shaping-internals]]
 == Shaping Internals
 
-Thus far we've addressed modular design and API design concerns from a high level perspective, but avoided plunging into the deep end of implementation details. In contrast, this chapter is devoted to advice and concrete actions we can take to improve the quality of our component implementations. We'll discuss complexity, ways to remediate it, the perils of state, and how to better leverage data structures.
+Thus far we've addressed modular design and API design concerns from a high-level perspective, but avoided plunging into the deep end of implementation details. In contrast, this chapter is devoted to advice and concrete actions we can take to improve the quality of our component implementations. We'll discuss complexity, ways to remediate it, the perils of state, and how to better leverage data structures.
 
 === 4.1 Internal Complexity
 
@@ -109,12 +109,13 @@ We could've used more variables without creating a function, inlining the comput
 [source,javascript]
 ----
 const hasToken = auth === undefined || auth.token === undefined
-const hasValidToken = hasToken ? auth.expires > Date.now() : false
+const hasValidToken = hasToken && auth.expires > Date.now()
 if (hasValidToken) {
   return
 }
 ----
 
+
 Both of these options have their downsides. If we couple the return statements with the parent function, we'll need to be careful if we want to replicate the logic elsewhere, as the return statements and possibly their logic will have to adapt as well. If we decide to use ternary operators as a way of short-circuiting, we'll end up with logic that might be as complex as what we originally had in the `if` statement.
 
 Using a function not only avoids these two problems thanks to the ability to `return` intermediate results, but also defers reasoning about its contents until we actually need to understand how tokens are checked for validity.
@@ -177,7 +178,7 @@ var double = function(x) {
 }
 ----
 
-Furthermore, if we're dealing with a `let` or `const` binding, then TDZ semantics will produce an error if we reference the binding at all before the variable declaration statement is reached.
+Furthermore, if we're dealing with a `let` or `const` binding, then TDZ semantics produce an error if we reference the binding at all before the variable declaration statement is reached.
 
 [source,javascript]
 ----
@@ -197,21 +198,21 @@ function double(x) {
 }
 ----
 
-Now, we mentioned texts are written sequentially, and how the writers avoids surprises by presenting concepts before discussing them. Establishing a context in a program is a different endeavor, however. If we have a module that has the goal of rendering a chart with user engagement statistics, the top of the function should address things the reader already knows, namely the high level flow for what the rendering function is meant to do: analyze the data, construct some data views and model that data into something we can feed into a visualization library that then renders the desired chart.
+Now, we mentioned texts are written sequentially, and how the writers avoids surprises by presenting concepts before discussing them. Establishing a context in a program is a different endeavor, however. If we have a module that has the goal of rendering a chart with user engagement statistics, the top of the function should address things the reader already knows, namely the high-level flow for what the rendering function is meant to do: analyze the data, construct some data views and model that data into something we can feed into a visualization library that then renders the desired chart.
 
-What we have to avoid is jumping directly into unimportant functions such as a data point label formatter, or the specifics of the data modelling. By keeping only the high level flow near the top, and the specifics towards the end, complex functionality can be designed in such a way that the reader experiences a zoomed out overview of the functionality at first, and as they read the code they uncover the details of how this chart was implemented.
+What we have to avoid is jumping directly into unimportant functions such as a data point label formatter, or the specifics of the data modelling. By keeping only the high-level flow near the top, and the specifics towards the end, complex functionality can be designed in such a way that the reader experiences a zoomed out overview of the functionality at first, and as they read the code they uncover the details of how this chart was implemented.
 
 In a concrete sense, this means we should present functions in a codebase in the order that they'll be read by the consumer (a first-in first-out queue), and not in the execution order (a last-in first-out stack). While computers do as they're told and dig ever deeper into the flow, executing the most deeply nested routines before jumping out of a series of subroutines and executing the next line, this is an unfruitful way for humans to read a codebase, given we're ill-suited to keeping all that state in our heads.
 
-Perhaps a more specific analogy for this kind of spiraling approach can be found in newspaper articles, where the author typically offers a title that describes an event at the highest possible level, and then follows up with a lead paragraph that summarizes what happened, again at a high level. The body of the article starts also at a high level, carefully avoiding to spook the reader with too many details. It is only midway through the article that we'll start finding details about the event which, aided by the context set forth in the beginning of the article, can give us a complete picture of what transpired.
+Perhaps a more specific analogy for this kind of spiraling approach can be found in newspaper articles, where the author typically offers a title that describes an event at the highest possible level, and then follows up with a lead paragraph that summarizes what happened, again at a high-level. The body of the article starts also at a high-level, carefully avoiding to spook the reader with too many details. It is only midway through the article that we'll start finding details about the event which, aided by the context set forth in the beginning of the article, can give us a complete picture of what transpired.
 
-Given the stack-based nature of programming, it's not that easy to naturally approach programs as if they were newspaper articles. We can, however, defer execution of implementation details to other functions or subroutines, and thanks to hoisting, we can place those subroutines after their higher level counterparts. In doing so, we're organizing our programs in a way that invites readers in, shows them a few high level hints, and then gradually unveils the spooky details of how a feature is implemented.
+Given the stack-based nature of programming, it's not that easy to naturally approach programs as if they were newspaper articles. We can, however, defer execution of implementation details to other functions or subroutines, and thanks to hoisting, we can place those subroutines after their higher level counterparts. In doing so, we're organizing our programs in a way that invites readers in, shows them a few high-level hints, and then gradually unveils the spooky details of how a feature is implemented.
 
 ==== 4.2.4 Extracting Functions
 
 Deliberate, pyramidal structures where we deal with higher level concerns near the top and switch to more specific problems as we go deeper into the inner workings of a system works wonders in keeping complexity on a tight leash. Such structures are particularly powerful because they break up complex items into their own individual units near the flat bottom of the system, avoiding a complicated interweaving of concerns that are fuzzied together, becoming undistinguishable from one another over time.
 
-Pushing anything that gets in the way of the current flow to the bottom of a function is an effective way of streamlining readability. As an example, consider the case where we have a non-trivial mapper inline in the heart of a function. In the following code snippet we're mapping the users into user models, as we often need to do when we prepare JSON responses for API calls.
+Pushing anything that gets in the way of the current flow to the bottom of a function is an effective way of streamlining readability. As an example, consider the case where we have a non-trivial mapper inline in the heart of a function. In the following code snippet we're mapping the users into user models, as we often need to do when preparing JSON responses for API calls.
 
 [source,javascript]
 ----
@@ -298,7 +299,7 @@ function getUserWebsite(user) {
 }
 ----
 
-When we want to name an aspect of a routine without adding a comment, we could create a function to host that functionality. Doing so doesn't just give a name to what the algorithm is doing, but it also allows us to push that code out of the way, leaving behind only the high level description of what's going to happen.
+When we want to name an aspect of a routine without adding a comment, we could create a function to host that functionality. Doing so doesn't just give a name to what the algorithm is doing, but it also allows us to push that code out of the way, leaving behind only the high-level description of what's going to happen.
 
 ==== 4.2.5 Flattening Nested Callbacks
 
@@ -417,7 +418,7 @@ We've already discussed at length why creating abstractions isn't always the bes
 
 When we do avoid creating abstractions prematurely, we'll start noticing functions that have an uncanny resemblance to the shape of similar functions: maybe the flow is identical, maybe the output is similar, or maybe all that really changes is we're accessing an attribute named `href` in one case and an attribute named `src` in another case.
 
-Consider the case of an HTML crawler which needs to pull out snippets of an HTML page and reuse them later in a different context. Among other things, this crawler will need to take relative resource locators like `/weekly` and resolve them to absolute endpoints like `https://ponyfoo.com/weekly`, depending on the origin where the resource was crawled from. This way, the HTML snippets can then be repurposed on other mediums such as on a different origin or a PDF file, without breaking the end-user experience.
+Consider the case of an HTML crawler which needs to pull out snippets of an HTML page and reuse them later in a different context. Among other things, this crawler needs to take relative resource locators like `/weekly` and resolve them to absolute endpoints like `https://ponyfoo.com/weekly`, depending on the origin where the resource was crawled from. This way, the HTML snippets can then be repurposed on other mediums such as on a different origin or a PDF file, without breaking the end-user experience.
 
 The following piece of code takes a piece of HTML and transforms `a[href]` and `img[src]` into absolute endpoints using the `$` jQuery-like DOM utility library.
 
@@ -590,7 +591,7 @@ const successfulMovies = movieModels.filter(
 )
 ----
 
-Thanks to us making fresh copies of the objects we're working with, we've preserved the `movies` collection intact. If we now assume that `movies` was an input to our function, we could say that modifying any movie in that collection would've made our function impure, since it'd have the side-effect of unexpectedly altering the input.
+Thanks to us making fresh copies of the objects we're working with, we've preserved the `movies` collection. If we now assume that `movies` was an input to our function, we could say that modifying any movie in that collection would've made our function impure, since it'd have the side-effect of unexpectedly altering the input.
 
 By introducing immutability, we've kept the function pure. That means that its output only depends on its inputs, and that we don't create any side-effects such as changing the inputs themselves. This in turn guarantees that the function is idempotent, where calling a function repeatedly with the same input always produces the same result, given the output depends solely on the inputs and there are no side-effects. In contrast, the idempotence property would've been brought into question if we had tainted the input by adding a `profit` field to every movie.
 
@@ -632,7 +633,26 @@ An array-based list is great whenever we need to sort the list or map its object
 }
 ----
 
-The data structure we pick will constrain and determine the shape our API can take. Complex programs are often, in no small part, the end result of combining poor data structures with new or unforeseen requirements that don't exactly fit in well with those structures. It's usually well worth it to transform data into something that's amenable to the task at hand, so that the algorithm is simplified by making the data easier to consume.
+Using `Map` we could create a similar structure and benefit from the native `Map` API as well.
+
+[source,javascript]
+----
+new Map([
+  ['understanding-javascript-async-await', {
+    slug: 'understanding-javascript-async-await',
+    title: 'Understanding JavaScript’s async await',
+    contents: '…'
+  }],
+  ['pattern-matching-in-ecmascript', {
+    slug: 'pattern-matching-in-ecmascript',
+    title: 'Pattern Matching in ECMAScript',
+    contents: '…'
+  }],
+  …
+])
+----
+
+The data structure we pick constrains and determines the shape our API can take. Complex programs are often, in no small part, the end result of combining poor data structures with new or unforeseen requirements that don't exactly fit in well with those structures. It's usually well worth it to transform data into something that's amenable to the task at hand, so that the algorithm is simplified by making the data easier to consume.
 
 Now, we can't possibly foresee all scenarios when coming up with the data structure we'll use at first, but what we can do is create intermediate representations of the same underlying data using new structures that do fit the new requirements. We can then leverage these structures, which were optimized for the new requirements, when writing code to fulfill those requirements. The alternative, resorting to the original data structure when writing new code that doesn't quite fit with it, will invariably result in logic that has to work around the limitations of the existing data structure, and as a result we'll end up with less than ideal code, that might take some effort understanding and updating.
 
diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index 8532aa1..6375c36 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -31,16 +31,16 @@ Besides these improvements, template literals also offer the possibility of tagg
 
 Whenever we need to compose a string using data, template literals are a terse alternative to string concatenation. When we want to avoid escaping single or double quotes, template literals can help. The same is true when we want to write multi-line strings.
 
-In every other case -- when there's no interpolation, escaping, or multi-line needs -- the choice comes down to a mere matter of style. In the last chapter of Practical Modern JavaScript, "Practical Considerations", I advocatedfootnoteref:[template-literals,You can read a blog post I wrote about why template literals are better than strings at: https://mjavascript.com/out/template-literals. Practical Modern JavaScript (O'Reilly, 2017) is the first book in the Modular JavaScript series. You're currently reading the second book of the same series.] in favor of using template literals in every case. This was for a few factors, but here's the two most important ones: because of convenience, so that you don't have to convert a string back and forth between single quoted string and template literals depending on its contents; and because of consistency, so that you don't have to stop and think about which kind of quotation mark -- single, double, or backtick -- to use each time. Template literals may take some time to get accustomed to: we've used single quoted strings for a long time, and template literals have only been around for a while. You or your team might prefer sticking with single quoted strings, and that's perfectly fine too.
+In every other case -- when there's no interpolation, escaping, or multi-line needs -- the choice comes down to a mere matter of style. In the last chapter of Practical Modern JavaScript, "Practical Considerations", I advocatedfootnoteref:[template-literals,You can read a blog post I wrote about why template literals are better than strings at: https://mjavascript.com/out/template-literals. Practical Modern JavaScript (O'Reilly, 2017) is the first book in the Modular JavaScript series. You're currently reading the second book of the same series.] in favor of using template literals in every case. This was for a few factors, but here's the two most important ones: because of convenience, so that you don't have to convert a string back and forth between single-quoted string and template literals depending on its contents; and because of consistency, so that you don't have to stop and think about which kind of quotation mark -- single, double, or backtick -- to use each time. Template literals may take some time to get accustomed to: we've used single-quoted strings for a long time, and template literals have only been around for a while. You or your team might prefer sticking with single-quoted strings, and that's perfectly fine too.
 
 [NOTE]
 ====
-When it comes to style choices, you'll rarely face problems if you let your team come to a consensus about the preferred style choice and later enforce that choice by way of a lint tool like ESLint. It's entirely valid ot stick with single quoted strings and only use template literals when deemed absolutely necessary, if that's what most of the team prefers.
+When it comes to style choices, you'll rarely face problems if you let your team come to a consensus about the preferred style choice and later enforce that choice by way of a lint tool like ESLint. It's entirely valid ot stick with single-quoted strings and only use template literals when deemed absolutely necessary, if that's what most of the team prefers.
 
 Using a tool like ESLint and a continuous integration job to enforce its rules means nobody has to perform the time consuming job of keeping everyone in line with the house style. When tooling enforces style choices, discussions about those choices won't crop up as often in discussion threads while contributors are collaborating on units of work.
 ====
 
-It's important to differentiate between purely stylistic choices, which tend to devolve in contentious time-sinking discussions, and choices where there's more ground to be covered in the everlasting battle against complexity. While the former may make a codebase subjectively easier to read, or aesthetically pleasing, it is only through deliberate action that we'll keep complexity in check. Granted, a consistent style throughout a codebase can help contain complexity, but the exact style is unimportant as long as we enforce it consistently.
+It's important to differentiate between purely stylistic choices, which tend to devolve in contentious time-sinking discussions, and choices where there's more ground to be covered in the everlasting battle against complexity. While the former may make a codebase subjectively easier to read, or aesthetically pleasing, it is only through deliberate action that we keep complexity in check. Granted, a consistent style throughout a codebase can help contain complexity, but the exact style is unimportant as long as we enforce it consistently.
 
 ==== 5.1.2 Destructuring, Rest, and Spread
 
@@ -134,6 +134,8 @@ const newCopy = { ...fax, date: new Date() }
 
 This allows us to create slightly modified shallow copies of other objects. When dealing with discrete state management, this means we don't need to resort to `Object.assign` method calls or utility libraries. While there's nothing inherently wrong with `Object.assign` calls, the object spread `...` abstraction is easier for us to internalize and mentally map its meaning back to `Object.assign` without us realizing it, and so the code becomes easier to read because we're dealing with less unabstracted knowledge.
 
+Another benefit worth pointing out is that `Object.assign()` can cause accidents: if we forget to pass an empty object literal as the first argument for this use case, we end up mutating the object. With object spread, there is no way to accidentally mutate anything, since the pattern always acts as if an empty object was passed to `Object.assign` in the first position.
+
 ==== 5.1.3 Striving for simple `const` bindings
 
 If we use `const` by default, then the need to use `let` or `var` can be ascribed to code that's more complicated than it should be. Striving to avoid those kinds of bindings almost always leads to better and simpler code.
@@ -181,6 +183,16 @@ values = values.filter(value => value > 5)
 // <- [6, 8, 10]
 ----
 
+An alternative would be to avoid reassignment, and instead use chaining, as shown next.
+
+[source,javascript]
+----
+const finalValues = [1, 2, 3, 4, 5]
+  .map(value => value * 2)
+  .filter(value => value > 5)
+// <- [6, 8, 10]
+----
+
 A better approach would be to create new bindings every time, computing their values based on the previous binding, and picking up the benefits of using `const` in doing so -- where we can rest assured that the binding doesn't change later in the flow.
 
 [source,javascript]
@@ -214,7 +226,7 @@ function delay(timeout) {
 delay(2000).then(…)
 ----
 
-A similar pattern would have to be used to consume functions taking a last argument that's an error-first callback style function in Node.js. Starting with Node.js v8.0.0, however, there's a utility built-in that "promisifies" these callback-based functions so that they return promises.
+A similar pattern would have to be used to consume functions taking a last argument that's an error-first callback style function in Node.js. Starting with Node.js v8.0.0, however, there's a utility built-in that "promisifies" these callback-based functions so that they return promises.footnote:[Note also that, starting in Node.js v10.0.0, the native `fs.promises` interface can be used to access promise-based versions of the `fs` module's methods.]
 
 [source,javascript]
 ----
@@ -332,16 +344,16 @@ const emitters = new Map()
 
 function onEvent(target, eventType, listener) {
   if (!emitters.has(target)) {
-    emitters.set(target, {})
+    emitters.set(target, new Map())
   }
 
   const listeners = emitters.get(target)
 
   if (!(eventType in listeners)) {
-    listeners[eventType] = []
+    listeners.set(eventType, [])
   }
 
-  listeners[eventType].push(listener)
+  listeners.get(eventType).push(listener)
 }
 
 function emitEvent(target, eventType, ...params) {
@@ -351,11 +363,11 @@ function emitEvent(target, eventType, ...params) {
 
   const listeners = emitters.get(target)
 
-  if (!(eventType in listeners)) {
+  if (!listeners.has(eventType)) {
     return
   }
 
-  listeners[eventType].forEach(listener => {
+  listeners.get(eventType).forEach(listener => {
     listener(...params)
   })
 }
@@ -422,7 +434,7 @@ export function stringify() {
 }
 ----
 
-Here's an example of how consuming the previous module could work. As soon as we try to asynchronously append text to the buffer, things will start getting out of hand, with strings getting bits and pieces unrelated to what we expect.
+Here's an example of how consuming the previous module could work. As soon as we try to asynchronously append text to the buffer, things start getting out of hand, with strings getting bits and pieces unrelated to what we expect.
 
 [source,javascript]
 ----

From da9daa16736478411d6fe9cf0e0ea70864cb6dbb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sun, 3 Jun 2018 10:14:07 -0300
Subject: [PATCH 37/71] address feedback from @rreverser

---
 chapters/ch05.asciidoc | 97 +++++++++++++++++++++++++++++-------------
 chapters/ch06.asciidoc | 28 +++++++++++-
 2 files changed, 94 insertions(+), 31 deletions(-)

diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index 6375c36..5e9693d 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -340,7 +340,7 @@ Another way of doing composition, that doesn't rely on decorators, is to rely on
 
 [source,javascript]
 ----
-const emitters = new Map()
+const emitters = new WeakMap()
 
 function onEvent(target, eventType, listener) {
   if (!emitters.has(target)) {
@@ -385,6 +385,8 @@ emitEvent(person, 'move', 23, 5)
 // <- 'Artemisa moved to [23, 5].'
 ----
 
+Note how we're using both `WeakMap` and `Map` here. Using a plain `Map` would prevent garbage collection from cleaning things up when `target` is only being referenced by `Map` entries, whereas `WeakMap` would allow garbage collection to take place. Given we usually want to attach events to objects, we can use `WeakMap` as a way to avoid creating strong references that might end up leading to memory leaks. On the other hand, it's okay to use a regular `Map` for the event listeners, given those are associated to an event type string.
+
 Let's move onto deciding whether to use inheritance, decorators, or functional composition, where each pattern shines, and when to avoid them.
 
 ==== 5.2.3 Choosing between Composition and Inheritance
@@ -409,7 +411,7 @@ The revealing module pattern has become a staple in the world of JavaScript. The
 
 Explicitly avoid exposing methods meant to be private, such as a hypothetical +_calculatePriceHistory+ method, which relies on the leading hyphen as a way of discouraging direct access and signaling that it should be regarded as private. Avoiding such methods prevents test code from accessing private methods directly, resulting in tests that make assertions solely regarding the interface and which can be later referenced as documentation on how to use the interface; prevents consumers from monkey-patching implementation details, leading to more transparent interfaces; and also often results in cleaner interfaces due to the fact that the interface is all there is, and there's no alternative ways of interacting with the module through direct use of its internals.
 
-JavaScript modules are of a revealing nature by default, making it easy for us to follow the revealing pattern of not giving away access to implementation details. Any function, object, class, or variable we declare is private unless we explicitly decide to `export` it from the module.
+JavaScript modules are of a revealing nature by default, making it easy for us to follow the revealing pattern of not giving away access to implementation details. Functions, objects, classes, and any other bindings we declare are private unless we explicitly decide to `export` them from the module.
 
 When we expose only a thin interface, our implementation can change largely without having an impact on how consumers use the module, nor on the tests that cover the module. As a mental exercise, always be on the lookout for aspects of an interface that should be turned into implementation details and extricated from the interface itself.
 
@@ -419,61 +421,98 @@ Even when using JavaScript modules and following the revealing pattern strictly,
 
 If we were to move our functional event emitter code snippet, with `onEvent` and `emitEvent`, into a JavaScript module, we'd notice that the `emitters` map is now a local global for that module, meaning all of the module's scope has access to `emitters`. This is what we'd want, because that way we can register event listeners in `onEvent` and fire them off in `emitEvent`. In most other situations, however, sharing persistent state across public interface methods is a recipe for unexpected bugs.
 
-Suppose we have a `StringBuilder` module that can be used to join strings in a performant manner. Even if consumers were supposed to use it synchronously and flush state in one fell swoop, without giving way for a second consumer to taint the state and produce unexpected results, our module shouldn't rely on consumer behavior to provide consistent results. The following contrived implementation relies on local shared state, and would need consumers to use the module strictly as intended, making all calls to `append` and `stringify` in sequence.
+Suppose we have a `calculator` module that can be used to make basic calculations through a stream of operations. Even if consumers were supposed to use it synchronously and flush state in one fell swoop, without giving way for a second consumer to taint the state and produce unexpected results, our module shouldn't rely on consumer behavior to provide consistent results. The following contrived implementation relies on local shared state, and would need consumers to use the module strictly as intended, making all calls to `add`, `multiply`, and `calculate` in sequence.
 
 [source,javascript]
 ----
-const buffer = []
+const operations = []
+let state = 0
 
-export function append(...text) {
-  buffer.push(...text)
+export function add(value) {
+  operations.push(() => {
+    state += value
+  })
+}
+
+export function multiply(value) {
+  operations.push(() => {
+    state *= value
+  })
 }
 
-export function stringify() {
-  return buffer.splice(0, buffer.length).join('')
+export function calculate() {
+  operations.forEach(op => op())
+  return state
 }
 ----
 
-Here's an example of how consuming the previous module could work. As soon as we try to asynchronously append text to the buffer, things start getting out of hand, with strings getting bits and pieces unrelated to what we expect.
+Here's an example of how consuming the previous module could work. As soon as we tried to asynchronously append text to the buffer, things would start getting out of hand, with the operations array getting bits and pieces of unrelated calculations, tainting our calculations.
 
 [source,javascript]
 ----
-const name = 'Sophie'
-append('hello')
-append(name)
-append(', it is nice to meet you!')
-stringify() // <- 'Hello Sophie, it is nice to meet you!'
+add(3)
+add(4)
+multiply(-2)
+calculate() // <- -14
 ----
 
-Blatantly, this contrived module is poorly designed, as its buffer should never be used to construct several unrelated strings. We should instead expose a factory function that returns an object from its own self-contained scope, where all relevant state is shut off from the outside world. The methods on this object are equivalent to the exported interface of a plain JavaScript module, but state mutations are contained to instances that consumers create.
+A slightly better approach would get rid of the `state` variable, and instead pass the state around operation handlers, so that each operation knows the current state, and applies any necessary changes to it. The `calculate` step would create a new initial state each time, and go from there.
 
 [source,javascript]
 ----
-function getStringBuilder() {
-  const buffer = []
+const operations = []
+
+export function add(value) {
+  operations.push(state => state + value)
+}
+
+export function multiply(value) {
+  operations.push(state => state * value)
+}
+
+export function calculate() {
+  return operations.reduce((result, op) =>
+    op(result)
+  , 0)
+}
+----
+
+This approach presents problems too, however. Even though the `state` will always be reset to `0`, we're treating unrelated operations as if they were all part of a whole, which is still wrong.
+
+Blatantly, this contrived module is poorly designed, as its operations buffer should never be used to drive several unrelated calculations. We should instead expose a factory function that returns an object from its own self-contained scope, where all relevant state is shut off from the outside world. The methods on this object are equivalent to the exported interface of a plain JavaScript module, but state mutations are contained to instances that consumers create.
+
+[source,javascript]
+----
+export function getCalculator() {
+  const operations = []
+
+  function add(value) {
+    operations.push(state => state + value)
+  }
 
-  function append(...text) {
-    buffer.push(...text)
+  function multiply(value) {
+    operations.push(state => state * value)
   }
 
-  function stringify() {
-    return buffer.splice(0, buffer.length).join('')
+  function calculate() {
+    return operations.reduce((result, op) =>
+      op(result)
+    , 0)
   }
 
-  return { append, stringify }
+  return { add, multiply, calculate }
 }
 ----
 
-Using the string builder like this is just as straightforward, except that now we can do things asynchronously and even if other consumers are also using string builders of their own, each user will have their own state, preventing corrupt data.
+Using the calculator like this is just as straightforward, except that now we can do things asynchronously and even if other consumers are also using string builders of their own, each user will have their own state, preventing data corruption.
 
 [source,javascript]
 ----
-const { append, stringify } = getStringBuilder()
-const name = 'Sophie'
-append('hello')
-append(name)
-append(', it is nice to meet you!')
-stringify() // <- 'Hello Sophie, it is nice to meet you!'
+const { append, stringify } = getCalculator()
+add(3)
+add(4)
+multiply(-2)
+calculate() // <- -14
 ----
 
 As we just showed, even when using modern language constructs and JavaScript modules, it's not too hard to create complications through shared state. Thus, we should always strive to contain mutable state as close to its consumers as possible.
diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index b125599..a78b5fd 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -124,9 +124,33 @@ A secret service also takes care of encryption, secure storage, secret rotation
 
 ==== 6.2 Explicit Dependency Management
 
-It's not practical to include dependencies in our repositories, given these are often in the hundreds of megabytes and often include environment-dependant and operating system dependant files. During development, we want to make sure we get non-breaking upgrades to our dependencies, which can help us resolve bugs and tighten our grip around security vulnerabilities. For deployments, we want reproducible builds, where installing our dependencies yields the same results every time. The solution is often to include a dependency manifest, indicating what exact versions of the libraries in our dependency tree we want to be installing. This can be accomplished with npm (starting with version 5) and its `package-lock.json` manifest, as well as through the Yarn package manager and its `yarn.lock` manifest, both of which we should be publishing to our versioned repository.
+It's not practical to include dependencies in our repositories, given these are often in the hundreds of megabytes and often include environment-dependant and operating system dependant files. During development, we want to make sure we get non-breaking upgrades to our dependencies, which can help us resolve bugs and tighten our grip around security vulnerabilities. For deployments, we want reproducible builds, where installing our dependencies yields the same results every time.
 
-Every dependency in our application should be explicitly declared in our manifest, relying on globally installed packages or global variables as little as possible. Implicit dependencies involve additional steps across environments, where developers and deployment flows alike must take action to ensure these extra dependencies are installed, beyond what a simple `npm install` step could achieve.
+The solution is often to include a dependency manifest, indicating what exact versions of the libraries in our dependency tree we want to be installing. This can be accomplished with npm (starting with version 5) and its `package-lock.json` manifest, as well as through Facebook's Yarn package manager and its `yarn.lock` manifest, both of which we should be publishing to our versioned repository.
+
+Using these manifests across environments ensures we get reproducible installs of our dependencies, meaning everyone working with the codebase -- as well as hosted environments -- deals with the same package versions, both at the top level (direct dependencies) and regardless the nesting depth (dependencies of dependencies -- of dependencies).
+
+Every dependency in our application should be explicitly declared in our manifest, relying on globally installed packages or global variables as little as possible. Implicit dependencies involve additional steps across environments, where developers and deployment flows alike must take action to ensure these extra dependencies are installed, beyond what a simple `npm install` step could achieve. Here's an example of how a `package-lock.json` file might look:
+
+```
+{
+  "name": "A",
+  "version": "0.1.0",
+  // metadata…
+  "dependencies": {
+    "B": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/B/-/B-0.0.1.tgz",
+      "integrity": "sha512-DeAdb33F+"
+      "dependencies": {
+        "C": {
+          "version": "git://github.com/org/C.git#5c380ae319fc4efe9e7f2d9c78b0faa588fd99b4"
+        }
+      }
+    }
+  }
+}
+```
 
 Always installing identical versions of our dependencies -- and identical versions of our dependencies' dependencies -- brings us one step closer to having development environments that closely mirror what we do in production. This increases the likelyhood we can swiftly reproduce bugs that occurred in production in our local environments, while decreasing the odds that something that worked during development fails in staging.
 

From b7aaf620e2ab83cdde379a22f962e7b0d32d8840 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sun, 3 Jun 2018 10:20:18 -0300
Subject: [PATCH 38/71] bits

---
 chapters/ch06.asciidoc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index a78b5fd..1e57c77 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -152,6 +152,8 @@ Every dependency in our application should be explicitly declared in our manifes
 }
 ```
 
+Using the information in a package lock file, package managers can take steps to install the same bits every time, preserving our ability to quickly iterate and install package updates, while keeping our code safe.
+
 Always installing identical versions of our dependencies -- and identical versions of our dependencies' dependencies -- brings us one step closer to having development environments that closely mirror what we do in production. This increases the likelyhood we can swiftly reproduce bugs that occurred in production in our local environments, while decreasing the odds that something that worked during development fails in staging.
 
 ==== 6.3 Interfaces as Black Boxes

From 724096ac87960470e56cd5aa20510afbd1bff40d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Wed, 13 Jun 2018 12:33:02 -0300
Subject: [PATCH 39/71] resurrect stuff from missing laptop

---
 chapters/ch06.asciidoc | 49 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 43 insertions(+), 6 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 1e57c77..656d9c3 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -30,6 +30,8 @@ Another benefit of going down this road is that, given we have all environment c
 
 When it comes to sharing the secrets, given we're purposely excluding them from source version control, we can take many approaches, such as using environment variables, storing them in JSON files kept in an Amazon S3 bucket, or using an encrypted repository dedicated to our application secrets.
 
+Using what's commonly referred to as "dot env" files is an effective way of securely managing secrets in Node.js applications, and there's a module called `nconf` that can aid us in setting these up. These files typically contain two types of data: secrets that mustn't be shared outside of execution environments, and configuration values that should be editable and which we don't want to hardcode.
+
 One concrete and effective way of accomplishing this in real-world environments is using several "dot env" files, each with a clearly defined purpose. In order of precedence:
 
 - `.env.defaults.json` can be used to define default values that aren't necessarily overwritten across environments, such as the application listening port, the `NODE_ENV` variable, and configurable options you don't want to hard-code into your application code. These default settings should be safe to check into source control
@@ -66,7 +68,14 @@ function accessor(key) {
 export default accessor
 ```
 
-The module also exposes an interface through which we can consume these application settings by making a function call such as `env('PORT')`.
+The module also exposes an interface through which we can consume these application settings by making a function call such as `env('PORT')`. Whenever we need to access one of the configuration settings, we can import `env.js` and ask for the computed value of the relevant setting, and `nconf` takes care of the bulk of figuring out which settings take precedence over what, and what the value should be for the current environment.
+
+[source,javascript]
+----
+import env from './env'
+
+const port = env('PORT')
+----
 
 Assuming we have an `.env.defaults.json` that looks like the following, we could pass in the `NODE_ENV` flag when starting our staging, test, or production application and get the proper environment settings back, helping us simplify the process of loading up an environment.
 
@@ -76,6 +85,8 @@ Assuming we have an `.env.defaults.json` that looks like the following, we could
 }
 ```
 
+Often, we find ourselves in need to replicate this sort of logic in the client-side. Naturally, we can't share server-side secrets in the client-side, as that'd leak our secrets to anyone snooping through our JavaScript files in the browser. Still, we might want to be able to access a few environment settings such as the `NODE_ENV`, our application's domain or port, Google Analytics tracking ID, and similarly safe-to-advertise configuration details.
+
 When it comes to the browser, we could use the exact same files and environment variables, but include a dedicated browser-specific object field, like so:
 
 ```
@@ -100,10 +111,16 @@ console.log(prettyJson)
 
 Naturally, we don't want to mix server-side settings with browser settings, because browser settings are usually accessible to anyone with a user agent, the ability to visit our website, and basic programming skills, meaning we would do well not to bundle highly sensitive secrets with our client-side applications. To resolve the issue, we can have a build step that prints the settings for the appropriate environment to an `.env.browser.json` file, and then only use that file on the client-side.
 
+We could incorporate this encapsulation into our build process, adding the following command-line call.
+
 ```
-node print-browser-env
+node print-browser-env > browser/.env.browser.json
 ```
 
+Note that in order for this pattern to work properly, we'll need to know the environment we're building for at the time when we compile the browser dot env file, as passing in a different `NODE_ENV` environment variable would produce different results depending on our target environment.
+
+By compiling client-side configuration settings in this way, we avoid leaking server-side configuration secrets onto the client-side.
+
 Furthermore, we should replicate the `env` file from the server-side in the client-side, so that application settings are consumed in much of the same way in both sides of the wire.
 
 ```
@@ -111,10 +128,10 @@ Furthermore, we should replicate the `env` file from the server-side in the clie
 import env from './env.browser.json'
 
 export default function accessor(key) {
-  if (typeof key === 'string') {
-    return env[key]
+  if (typeof key !== 'string') {
+    return env
   }
-  return env
+  return key in env ? env[key] : null
 }
 ```
 
@@ -152,7 +169,7 @@ Every dependency in our application should be explicitly declared in our manifes
 }
 ```
 
-Using the information in a package lock file, package managers can take steps to install the same bits every time, preserving our ability to quickly iterate and install package updates, while keeping our code safe.
+Using the information in a package lock file, which contains details about every package we depend upon and all of their dependencies as well, package managers can take steps to install the same bits every time, preserving our ability to quickly iterate and install package updates, while keeping our code safe.
 
 Always installing identical versions of our dependencies -- and identical versions of our dependencies' dependencies -- brings us one step closer to having development environments that closely mirror what we do in production. This increases the likelyhood we can swiftly reproduce bugs that occurred in production in our local environments, while decreasing the odds that something that worked during development fails in staging.
 
@@ -160,6 +177,8 @@ Always installing identical versions of our dependencies -- and identical versio
 
 On a similar note to that of the last section, we should treat our own components no differently than how we treat third party libraries and modules. Granted, we can make changes to our own code a lot more quickly than we can effect change in third party code -- if that's at all possible. However, when we treat all components and interfaces (including our own HTTP API) as if they were foreign to us, we can focus on consuming and testing against interfaces, while ignoring the underlying implementation.
 
+One way to improve our interfaces is to write detailed documentation about the input an interface touchpoint expects, and how it affects the output it provides in each case. The process of writing documentation often leads us to uncover limitations in how the interface is designed, and we might decide to change it as a result. Consumers love good documentation because it means less fumbling about with the implementation (or often, implementors), to understand how the interface is meant to be consumed, and whether it can accomplish what they need.
+
 Avoiding distinctions helps us write unit tests where we mock dependencies that aren't under test, regardless of whether they were developed in-house or by a third party. When writing tests we always assume that third party modules are generally well-tested enough that it's not our responsibility to include them in our test cases. The same thinking should apply to first party modules that just happen to be dependencies of the module we're currently writing tests for.
 
 This same reasoning can be applied to security concerns such as input sanitization. Regardless of what kind of application we're developing, we can't trust user input unless it's sanitized. Malicious actors could be angling to take over our servers, our customers' data, or otherwise inject content onto our web pages. These users might be customers or even employees, so we shouldn't treat them differently depending on that, when it comes to input sanitization.
@@ -213,3 +232,21 @@ The problem here is that we had a divergence in parity which prevented us from i
 As much as possible, we should strive to keep these kinds of divergences to a minimum, because if we don't, bugs might find their way to production, and a customer might end up reporting the bug to us. Merely being aware of discrepancies like this is not enough, because it's not practical nor effective to keep these logic gates in your head so that whenever you're implementing a change you mentally go through the motions of how the change would differ if your code was running in production instead.
 
 Proper integration testing might catch many of these kinds of mistakes, but that won't always be the case.
+
+==== 6.8 Abstraction Matters
+
+Eager abstraction can result in catastrophe. Conversely, failure to identify and abstract away sources of major complexity can be incredibly costly as well. When we consume complex interfaces directly, but don't necessarily take advantage of all the advanced configuration options that interface has to offer, we are missing out on a powerful abstraction we could be using. The alternative would be to create a middle layer in front of the complex interface, and have consumers go through that layer instead.
+
+This intermediate layer would be in charge of calling the complex abstraction itself, but offers a simpler interface with less configuration options and improved ease of use for the use cases that matter to us. Often, complicated or legacy interfaces demand that we offer up data that could be derived from other parameters being passed into the function call. For example, we might be asked how many adults, how many children, and how many people in total are looking to make a flight booking, even though the latter can be derived from the former. Other examples include expecting fields to be in a particular string format (such as a date string that could be derived from a native JavaScript date instead), using nomenclature that's relevant to the implmentation but not so much to the consumer, or a lack of sensible defaults (required fields which are rarely changed into anything other than a recommended value that isn't set by default).
+
+When we're building out a web application which consumes a highly parametized API in order to search for the cheapest hassle-free flights -- to give an example -- and we anticipate consuming this API in a few different ways, it would cost us dearly not to abstract away most of the parameters demanded by the API which do not fit our use case. This middle layer can take care of establishing sensible default values and of converting reasonable data structures such as native JavaScript dates or case insensitive airport codes into the formats demanded by the API we're using.
+
+In addition, our abstraction could also take care of any follow up API calls that need to be made in order to hydrate data. For example, a flight search API might return an airline code for each different flight, such as AA for American Airlines, but a UI consumer would also necessitate to hydrate AA into a display name for the airline, accompanied by a logo to embed on the user interface, and perhaps even a quick link to their check-in page.
+
+When we call into the backing API every time, with the full query, appeasing its quirks and shortcomings instead of taking the abstracted approach, it will not only be difficult to maintain an application that consumes those endpoints in more than one place, but it will also become a challenge down the road, when we want to include results from a different provider, which of course would have their own set of quirks and shortcomings. At this point we would have two separate sets of API calls, one for each provider, and each massaging the data to accomodate provider-specific quirks in a module which shouldn't be concerned with such matters, but only the results themselves.
+
+A middle layer could leverage a normalized query from the consumer, such as the one where we took a native date and then format it when calling the flight search API, and then adapt that query into either of the backing services that actually produce flight search results. This way, the consumer only has to deal with a single, simplified interface, while having the ability to seamlessly interact with two similar backing services that offer different interfaces.
+
+The same case could, and should, be made for the data structures returned from either of these backing services. By normalizing the data into a structure that only contains information that's relevant to our consumers, and augmenting it with the derived information they need (such as the airline name and details as explained earlier), the consumer can focus on their own concerns while leveraging a data structure that's close to their needs. At the same time, this normalization empowers our abstraction to merge results from both backing services and treat them as if they came from a single source: the abstraction itself, leaving the backing services as mere implementation details.
+
+When we rely directly on the original responses, we may find ourselves writing view components that are more verbose than they need be, containing logic to pull together the different bits of metadata needed to render our views, mapping data from the API representation into what we actually want to display, and then mapping user input back into what the API expects. With a layer in between, we can keep this mapping logic contained in a single place, and leave the rest of our application unencumbered by it.

From fcd3fea0c234c38eb56f832fa0a34794bb39ec0e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Wed, 13 Jun 2018 19:39:15 -0300
Subject: [PATCH 40/71] expanding on things

---
 chapters/ch06.asciidoc | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 656d9c3..5b67335 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -141,13 +141,17 @@ A secret service also takes care of encryption, secure storage, secret rotation
 
 ==== 6.2 Explicit Dependency Management
 
-It's not practical to include dependencies in our repositories, given these are often in the hundreds of megabytes and often include environment-dependant and operating system dependant files. During development, we want to make sure we get non-breaking upgrades to our dependencies, which can help us resolve bugs and tighten our grip around security vulnerabilities. For deployments, we want reproducible builds, where installing our dependencies yields the same results every time.
+The reason why we often feel tempted to check our dependencies into source control is so that we get the exact same versions across the dependency tree, every time, in every environment.
 
-The solution is often to include a dependency manifest, indicating what exact versions of the libraries in our dependency tree we want to be installing. This can be accomplished with npm (starting with version 5) and its `package-lock.json` manifest, as well as through Facebook's Yarn package manager and its `yarn.lock` manifest, both of which we should be publishing to our versioned repository.
+Including dependency trees in our repositories is not practical, however, given these are often in the hundreds of megabytes and frequently include compiled assets that are built based on the target environment and operating system, meaning that the build process itself -- the act `npm` executing a `rebuild` step after `npm install` ends -- is environment dependant, and thus not suitable for a presumably platform-agnostic code repository.
+
+During development, we want to make sure we get non-breaking upgrades to our dependencies, which can help us resolve upstream bugs, tighten our grip around security vulnerabilities, and leverage new features or improvements. For deployments however, we want reproducible builds, where installing our dependencies yields the same results every time.
+
+The solution is to include a dependency manifest, indicating what exact versions of the libraries in our dependency tree we want to be installing. This can be accomplished with npm (starting with version 5) and its `package-lock.json` manifest, as well as through Facebook's Yarn package manager and its `yarn.lock` manifest, either of which we should be publishing to our versioned repository.
 
 Using these manifests across environments ensures we get reproducible installs of our dependencies, meaning everyone working with the codebase -- as well as hosted environments -- deals with the same package versions, both at the top level (direct dependencies) and regardless the nesting depth (dependencies of dependencies -- of dependencies).
 
-Every dependency in our application should be explicitly declared in our manifest, relying on globally installed packages or global variables as little as possible. Implicit dependencies involve additional steps across environments, where developers and deployment flows alike must take action to ensure these extra dependencies are installed, beyond what a simple `npm install` step could achieve. Here's an example of how a `package-lock.json` file might look:
+Every dependency in our application should be explicitly declared in our manifest, relying on globally installed packages or global variables as little as possible -- and ideally not at all. Implicit dependencies involve additional steps across environments, where developers and deployment flows alike must take action to ensure these extra dependencies are installed, beyond what a simple `npm install` step could achieve. Here's an example of how a `package-lock.json` file might look:
 
 ```
 {
@@ -175,7 +179,7 @@ Always installing identical versions of our dependencies -- and identical versio
 
 ==== 6.3 Interfaces as Black Boxes
 
-On a similar note to that of the last section, we should treat our own components no differently than how we treat third party libraries and modules. Granted, we can make changes to our own code a lot more quickly than we can effect change in third party code -- if that's at all possible. However, when we treat all components and interfaces (including our own HTTP API) as if they were foreign to us, we can focus on consuming and testing against interfaces, while ignoring the underlying implementation.
+On a similar note to that of the last section, we should treat our own components no differently than how we treat third party libraries and modules. Granted, we can make changes to our own code a lot more quickly than we can effect change in third party code -- if that's at all possible, in some cases. However, when we treat all components and interfaces (including our own HTTP API) as if they were foreign to us, we can focus on consuming and testing against interfaces, while ignoring the underlying implementation.
 
 One way to improve our interfaces is to write detailed documentation about the input an interface touchpoint expects, and how it affects the output it provides in each case. The process of writing documentation often leads us to uncover limitations in how the interface is designed, and we might decide to change it as a result. Consumers love good documentation because it means less fumbling about with the implementation (or often, implementors), to understand how the interface is meant to be consumed, and whether it can accomplish what they need.
 
@@ -183,6 +187,8 @@ Avoiding distinctions helps us write unit tests where we mock dependencies that
 
 This same reasoning can be applied to security concerns such as input sanitization. Regardless of what kind of application we're developing, we can't trust user input unless it's sanitized. Malicious actors could be angling to take over our servers, our customers' data, or otherwise inject content onto our web pages. These users might be customers or even employees, so we shouldn't treat them differently depending on that, when it comes to input sanitization.
 
+Putting ourselves in the shoes of the consumer is often the best tool to guard us against half-baked interfaces. When -- as a thought exercise -- you stop and think about how you'd want to consume an interface, and the different ways in which you might need to consume it, you often end up with a much better interface as a result. This is not to say we want to enable consumers to be able to do just about everything, but we want to make affordances where consuming an interface becomes as straightforward as possible and doesn't feel like a chore. If consumers are all but required to include long blocks of business logic right after they consume an interface, we need to stop ourselves and ask: would that business logic belong behind the interface rather than at its doorstep?
+
 ==== 6.4 Build, Release, Run
 
 Having clearly defined and delineated build processes is key when it comes to successfully managing an application across development, staging, and production environments.

From 326e475abc2f37fd45b5a8d83a69947afc8266f6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Thu, 14 Jun 2018 18:47:41 -0300
Subject: [PATCH 41/71] more words

---
 chapters/ch06.asciidoc | 34 +++++++++++++++++++++-------------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 5b67335..51827b9 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -38,13 +38,13 @@ One concrete and effective way of accomplishing this in real-world environments
 - `.env.production.json`, `.env.staging.json`, and others can be used for environment-specific settings, such as the various production connection strings for databases, cookie encoding secrets, API keys, and so on
 - `.env.json` could be your local, machine-specific settings, useful for secrets or configuration changes that shouldn't be shared with other team members
 
-Furthermore, you could also accept simple modifications to environment settings through environment variables, such as when executing `PORT=3000 node app`, which is often convenient during development.
+Furthermore, you could also accept simple modifications to environment settings through environment variables, such as when executing `PORT=3000 node app`, which is convenient during development.
 
 There's an npm package called `nconf` which we can use to handle reading and merging all of these sources of application settings with ease.
 
 The following piece of code shows how you could configure `nconf` to do what we've just described.
 
-We import the `nconf` package, and declare configuration sources from highest priority to lowest priority, while `nconf` will do the merging (higher priority settings will always take precedence). We then set the actual `NODE_ENV` environment variable, because libraries often rely on this property to decide whether to instrument or optimize their output.
+We import the `nconf` package, and declare configuration sources from highest priority to lowest priority, while `nconf` will do the merging (higher priority settings will always take precedence). We then set the actual `NODE_ENV` environment variable, because libraries rely on this property to decide whether to instrument or optimize their output.
 
 ```
 // env
@@ -85,7 +85,7 @@ Assuming we have an `.env.defaults.json` that looks like the following, we could
 }
 ```
 
-Often, we find ourselves in need to replicate this sort of logic in the client-side. Naturally, we can't share server-side secrets in the client-side, as that'd leak our secrets to anyone snooping through our JavaScript files in the browser. Still, we might want to be able to access a few environment settings such as the `NODE_ENV`, our application's domain or port, Google Analytics tracking ID, and similarly safe-to-advertise configuration details.
+We usually find ourselves in need to replicate this sort of logic in the client-side. Naturally, we can't share server-side secrets in the client-side, as that'd leak our secrets to anyone snooping through our JavaScript files in the browser. Still, we might want to be able to access a few environment settings such as the `NODE_ENV`, our application's domain or port, Google Analytics tracking ID, and similarly safe-to-advertise configuration details.
 
 When it comes to the browser, we could use the exact same files and environment variables, but include a dedicated browser-specific object field, like so:
 
@@ -141,9 +141,9 @@ A secret service also takes care of encryption, secure storage, secret rotation
 
 ==== 6.2 Explicit Dependency Management
 
-The reason why we often feel tempted to check our dependencies into source control is so that we get the exact same versions across the dependency tree, every time, in every environment.
+The reason why we sometimes feel tempted to check our dependencies into source control is so that we get the exact same versions across the dependency tree, every time, in every environment.
 
-Including dependency trees in our repositories is not practical, however, given these are often in the hundreds of megabytes and frequently include compiled assets that are built based on the target environment and operating system, meaning that the build process itself -- the act `npm` executing a `rebuild` step after `npm install` ends -- is environment dependant, and thus not suitable for a presumably platform-agnostic code repository.
+Including dependency trees in our repositories is not practical, however, given these are typically in the hundreds of megabytes and frequently include compiled assets that are built based on the target environment and operating system, meaning that the build process itself -- the act `npm` executing a `rebuild` step after `npm install` ends -- is environment dependant, and thus not suitable for a presumably platform-agnostic code repository.
 
 During development, we want to make sure we get non-breaking upgrades to our dependencies, which can help us resolve upstream bugs, tighten our grip around security vulnerabilities, and leverage new features or improvements. For deployments however, we want reproducible builds, where installing our dependencies yields the same results every time.
 
@@ -181,36 +181,44 @@ Always installing identical versions of our dependencies -- and identical versio
 
 On a similar note to that of the last section, we should treat our own components no differently than how we treat third party libraries and modules. Granted, we can make changes to our own code a lot more quickly than we can effect change in third party code -- if that's at all possible, in some cases. However, when we treat all components and interfaces (including our own HTTP API) as if they were foreign to us, we can focus on consuming and testing against interfaces, while ignoring the underlying implementation.
 
-One way to improve our interfaces is to write detailed documentation about the input an interface touchpoint expects, and how it affects the output it provides in each case. The process of writing documentation often leads us to uncover limitations in how the interface is designed, and we might decide to change it as a result. Consumers love good documentation because it means less fumbling about with the implementation (or often, implementors), to understand how the interface is meant to be consumed, and whether it can accomplish what they need.
+One way to improve our interfaces is to write detailed documentation about the input an interface touchpoint expects, and how it affects the output it provides in each case. The process of writing documentation leads to uncovering limitations in how the interface is designed, and we might decide to change it as a result. Consumers love good documentation because it means less fumbling about with the implementation (or its implementors), to understand how the interface is meant to be consumed, and whether it can accomplish what they need.
 
 Avoiding distinctions helps us write unit tests where we mock dependencies that aren't under test, regardless of whether they were developed in-house or by a third party. When writing tests we always assume that third party modules are generally well-tested enough that it's not our responsibility to include them in our test cases. The same thinking should apply to first party modules that just happen to be dependencies of the module we're currently writing tests for.
 
 This same reasoning can be applied to security concerns such as input sanitization. Regardless of what kind of application we're developing, we can't trust user input unless it's sanitized. Malicious actors could be angling to take over our servers, our customers' data, or otherwise inject content onto our web pages. These users might be customers or even employees, so we shouldn't treat them differently depending on that, when it comes to input sanitization.
 
-Putting ourselves in the shoes of the consumer is often the best tool to guard us against half-baked interfaces. When -- as a thought exercise -- you stop and think about how you'd want to consume an interface, and the different ways in which you might need to consume it, you often end up with a much better interface as a result. This is not to say we want to enable consumers to be able to do just about everything, but we want to make affordances where consuming an interface becomes as straightforward as possible and doesn't feel like a chore. If consumers are all but required to include long blocks of business logic right after they consume an interface, we need to stop ourselves and ask: would that business logic belong behind the interface rather than at its doorstep?
+Putting ourselves in the shoes of the consumer is the best tool to guard us against half-baked interfaces. When -- as a thought exercise -- you stop and think about how you'd want to consume an interface, and the different ways in which you might need to consume it, you end up with a much better interface as a result. This is not to say we want to enable consumers to be able to do just about everything, but we want to make affordances where consuming an interface becomes as straightforward as possible and doesn't feel like a chore. If consumers are all but required to include long blocks of business logic right after they consume an interface, we need to stop ourselves and ask: would that business logic belong behind the interface rather than at its doorstep?
 
 ==== 6.4 Build, Release, Run
 
-Having clearly defined and delineated build processes is key when it comes to successfully managing an application across development, staging, and production environments.
+Build processes have a few different aspects to them. At the highest level, there's the shared logic where we install and compile our assets so that they can be consumed by our runtime application. This can mean anything like installing system or application dependencies, copying files over to a different directory, compiling files into a different language or bundling them together, among a multitude of other requirements your application might have.
 
-Build processes have a few different aspects to them. At the highest level, there's the shared logic where we install and compile our assets so that they can be consumed by our runtime application.
+Having clearly defined and delineated build processes is key when it comes to successfully managing an application across development, staging, and production environments. Each of these commonplace environments, and other environments you might encounter, is used for a specific purpose and benefits from being geared towards that purpose.
 
 For development, we focus on enhanced debugging facilities, using development versions of libraries, source maps, and verbose logging levels; custom ways of overriding behavior, so that we can easily mimic how the production environment would look like, and where possible we also throw in a real-time debugging server that takes care of restarting our application when code changes, applying CSS changes without refreshing the page, and so on.
 
-In staging, we want an environment that closely resembles production, so we'll avoid most debugging features, but we might still want source maps and verbose logging to be able to trace bugs with ease.
+In staging, we want an environment that closely resembles production, so we'll avoid most debugging features, but we might still want source maps and verbose logging to be able to trace bugs with ease. Our primary goal with staging environments generally is to weed out as many bugs as possible before the production push, and thus it is vital that these environments are this middle ground between debugging affordance and production resemblance.
 
-Production focuses more heavily on minification, image optimization, and advanced techniques like route-based bundle splitting, where we only serve modules that are actually used by the pages visited by a user; tree shaking, where we statically analyze our module graph and remove functions that aren't being used; and security features, such as a hardened `Content-Security-Policy` policy that mitigates attack vectors like XSS or CSRF.
+Production focuses more heavily on minification, optimizing images statically to reduce their byte size, and advanced techniques like route-based bundle splitting, where we only serve modules that are actually used by the pages visited by a user; tree shaking, where we statically analyze our module graph and remove functions that aren't being used; critical CSS inlining, where we precompute the most frequently used CSS styles so that we can inline them in the page and defer the rest of the styles to an asynchronous model that has a quicker time to interactive; and security features, such as a hardened `Content-Security-Policy` policy that mitigates attack vectors like XSS or CSRF.
 
-Note how up until this point we have focused on how we build our assets, but not how we deploy them. These two processes, build and deployment, are closely related but they shouldn't be intertwined. A clean build process where we end up with a packaged application we can easily deploy, and a deployment process that takes care of the specifics regardless of whether you're deploying to your own local environment, or to a hosted staging or production environment, means that for the most part we won't need to worry about environments during our build processes or at runtime.
+Testing also plays a significant role when it comes to processes around an application. Testing is typically done in two different stages. Locally, developers test before a build, making sure linters don't produce any errors or that tests aren't failing. Then, before merging code into the mainline repository, we often run tests in a continuous integration (CI) environment to ensure we don't merge broken code into our application. When it comes to CI, we start off by building our application, and then test against that, making sure the compiled application is in order.
+
+For these processes to be effective, they must be consistent. Intermittent test failures feel worse than not having tests for the particular part of our application we're having trouble testing, because these failures affect every single test job. When tests fail in this way, we can no longer feel confident that a passing build means everything is in order, and this translates directly into decreased morale and increased frustration across the team as well. When an intermittent test failure is identified, the best course of action is to eliminate the intermittence as soon as possible, either by fixing the source of the intermittence, or by removing the test entirely. If the test is removed, make sure to file a ticket so that a well-functioning test is added later on. Intermittence in test failures can be a symptom of bad design, and in our quest to fix these failures we might resolve architecture issues along the way.
+
+Note how up until this point we have focused on how we build and test our assets, but not how we deploy them. These two processes, build and deployment, are closely related but they shouldn't be intertwined. A clearly isolated build process where we end up with a packaged application we can easily deploy, and a deployment process that takes care of the specifics regardless of whether you're deploying to your own local environment, or to a hosted staging or production environment, means that for the most part we won't need to worry about environments during our build processes nor at runtime.
 
 ==== 6.5 Statelessness
 
-We've already explored how state, if left unchecked, can lead us straight to the heat death of our applications. Keeping state to a minimum translates directly into applications that are easier to debug. The least global state there is, the less unpredictable the current conditions of an application will be at any one point in time, and the least surprises we'll run into while debugging.
+We've already explored how state, if left unchecked, can lead us straight to the heat death of our applications. Keeping state to a minimum translates directly into applications that are easier to debug. The less global state there is, the less unpredictable the current conditions of an application will be at any one point in time, and the least surprises we'll run into while debugging.
 
 One particularly insidious form of state is caching. A cache is a great way to increase performance in an application by avoiding expensive lookups most of the time. When state management tools are used as a caching mechanism, we might fall into a trap where different bits and pieces of derived application state were derived at different points in time, thus rendering different bits of the application using data computed at different points in time.
 
 Derived state should seldom be treated as state that's separate from the data it was derived from. When it's not, we might run into situations where the original data is updated, but the derived state is not, becoming stale and inaccurate. When, instead, we always compute derived state from the original data, we reduce the likelyhood that this derived state will become stale.
 
+State is almost ubiquitous, and practically a synonym with application. Applications without state aren't particularly useful, but how can we better manage state? If we look at applications such as your typical web server, their main job is to receive requests, process them, and send a response. Consequently, web servers associate state to each request, keeping it close to the request handlers, the most relevant party. There should be as little global state as possible when it comes to web servers, with the vast majority of state contained in each request/response cycle instead. In this way, we save ourselves from a world of trouble when setting up horizontal scaling with multiple server nodes that don't need to communicate with each other in order to maintain consistency across web server nodes, leaving that job to the data persistance layer instead, which is ultimately responsible for the state as its source of truth.
+
+When a request results in a long running job (such as sending out an email campaign, modifying records in a persistant database, etc), it's best to hand that off into a separate service that -- again -- mostly keeps state regarding said job. Separating services into specific needs means we can keep web servers lean, stateless, and improve our flows by adding more servers, persistent queues (so that we don't drop jobs), and so on. When every task is tethered together through tight coupling and state, it becomes challenging to maintain, upgrade, and scale a service over time.
+
 ==== 6.6 Disposability
 
 Whenever we hook up an event listener, regardless of whether we're listening for DOM events or those from an event emitter, we should also strongly consider disposing of the listener when the concerned parties are no longer interested in the event being raised. For instance, if we have a React component that, upon mount, starts listening for `resize` events on the `window` object, we should also make sure we remove those event listeners upon the component being unmounted.

From 5a53a86683c7dd9e53f9e4bcfe2a9072007e5b5a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sat, 16 Jun 2018 01:28:35 -0300
Subject: [PATCH 42/71] caching example

---
 chapters/ch06.asciidoc | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 51827b9..5c02f10 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -215,9 +215,13 @@ One particularly insidious form of state is caching. A cache is a great way to i
 
 Derived state should seldom be treated as state that's separate from the data it was derived from. When it's not, we might run into situations where the original data is updated, but the derived state is not, becoming stale and inaccurate. When, instead, we always compute derived state from the original data, we reduce the likelyhood that this derived state will become stale.
 
-State is almost ubiquitous, and practically a synonym with application. Applications without state aren't particularly useful, but how can we better manage state? If we look at applications such as your typical web server, their main job is to receive requests, process them, and send a response. Consequently, web servers associate state to each request, keeping it close to the request handlers, the most relevant party. There should be as little global state as possible when it comes to web servers, with the vast majority of state contained in each request/response cycle instead. In this way, we save ourselves from a world of trouble when setting up horizontal scaling with multiple server nodes that don't need to communicate with each other in order to maintain consistency across web server nodes, leaving that job to the data persistance layer instead, which is ultimately responsible for the state as its source of truth.
+State is almost ubiquitous, and practically a synonym of applications, because applications without state aren't particularly useful. The question then arises: how can we better manage state? If we look at applications such as your typical web server, their main job is to receive requests, process them, and send back the appropriate responses. Consequently, web servers associate state to each request, keeping it near request handlers, the most relevant consumer of request state. There is as little global state as possible when it comes to web servers, with the vast majority of state contained in each request/response cycle instead. In this way, web servers save themselves from a world of trouble when setting up horizontal scaling with multiple server nodes that don't need to communicate with each other in order to maintain consistency across web server nodes, leaving that job to a data persistance layer, which is ultimately responsible for the state as its source of truth.
 
-When a request results in a long running job (such as sending out an email campaign, modifying records in a persistant database, etc), it's best to hand that off into a separate service that -- again -- mostly keeps state regarding said job. Separating services into specific needs means we can keep web servers lean, stateless, and improve our flows by adding more servers, persistent queues (so that we don't drop jobs), and so on. When every task is tethered together through tight coupling and state, it becomes challenging to maintain, upgrade, and scale a service over time.
+When a request results in a long running job (such as sending out an email campaign, modifying records in a persistant database, etc), it's best to hand that off into a separate service that -- again -- mostly keeps state regarding said job. Separating services into specific needs means we can keep web servers lean, stateless, and improve our flows by adding more servers, persistent queues (so that we don't drop jobs), and so on. When every task is tethered together through tight coupling and state, it could become challenging to maintain, upgrade, and scale a service over time.
+
+Derived state in the form of caches is not uncmoon in the world of web servers. In the case of a personal website with some books available for download, for instance, we might be tempted to store the PDF representation of each book in a file, so that we don't have to recompile the PDF whenever the corresponding `/book` route is visited. When the book is updated, we'd recompute the PDF file and flush it to disk again, so that this derived state remains fresh. When our web server ceases to be single node and we start using a cluster of several nodes, however, it might not be so trivial to broadcast the news about books being updated across nodes, and thus it'd be best to leave derived state to the persistance layer. Otherwise, a web server node might receive the request to update a book, perform the update and recompute the PDF file on that node, but we'd be inadvertently invalidating the PDF files being served by other nodes, which would have stale copies of the PDF representation.
+
+A better alternative in such a case would be to store derived state in a data store like Redis or Amazon S3, either of which we could update from any web server, and then serving precomputed results from Redis directly. In this way we'd still be able to access the latency benefits of using precomputed derived state, but at the same time we'd stay resilient when these requests or updates can happen on multiple web server nodes.
 
 ==== 6.6 Disposability
 

From 0524355855f8d5cda5a7556e47696385aa4335ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Mon, 18 Jun 2018 14:33:57 -0300
Subject: [PATCH 43/71] discuss centralizing code by function

---
 chapters/ch06.asciidoc | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 5c02f10..bc46dd2 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -223,15 +223,26 @@ Derived state in the form of caches is not uncmoon in the world of web servers.
 
 A better alternative in such a case would be to store derived state in a data store like Redis or Amazon S3, either of which we could update from any web server, and then serving precomputed results from Redis directly. In this way we'd still be able to access the latency benefits of using precomputed derived state, but at the same time we'd stay resilient when these requests or updates can happen on multiple web server nodes.
 
-==== 6.6 Disposability
+[NOTE]
+====
+On Disposability
 
 Whenever we hook up an event listener, regardless of whether we're listening for DOM events or those from an event emitter, we should also strongly consider disposing of the listener when the concerned parties are no longer interested in the event being raised. For instance, if we have a React component that, upon mount, starts listening for `resize` events on the `window` object, we should also make sure we remove those event listeners upon the component being unmounted.
 
 This kind of dilligence ensures that we can set up and tear down bits of our application without leaving behind mounting piles of listeners that would result in memory leaks, which are hard to track down and pinpoint.
 
 The concept of disposability goes beyond just event handlers, though. Any sort of resource that we allocate and attach to an object, component, or service is created, should be released and cleaned up when that attachment ceases to exist. This way, we can confidently create and dispose of as many components as we want, without putting our application's performance at risk.
+====
 
-==== 6.7 Parity in Development and Production
+Another improvement which could aid in complexity management is to structure applications so that all business logic is contained in a single directory structure (e.g `lib/` or `services/`) acting as a physical layer where we keep all the logic together. In doing so, we'll open ourselves up for more opportunities to reuse logic, because team members will know to go looking here before reimplementing slightly different functions that perform more or less similar computations for derived state.
+
+Colocation of view components with its immediate counterparts is appealing, -- that is, keeping each view's main component, child components, controllers, and logic in the same structure -- however, doing so in a way that tightly couples business logic to specific components can be detrimental to having a clear understanding of how an application works as a whole.
+
+Large client-side applications often suffer from not having a single place where logic should be deposited, and as a result the logic is instead spread amongst components, view controllers, and the API, instead of being mostly handled in the server-side, and then in a single physical location in the client-side code structure. This centralization can be key for newcomers to the team seeking to better understand how the application flows, because otherwise they'd have to go fishing around our view components and controllers in order to ascertain what's going on. A dauting proposition when first dipping our toes in the uncharted shores of a new codebase.
+
+The same case could be made about any other function of our code, as having clearly defined layers in an application can make it straightforward to understand how an algorithm flows from layer to layer, but we'll find the biggest rewards to reap when it comes to isolating business logic from the rest of the application code.
+
+==== 6.6 Parity in Development and Production
 
 We've established the importance of having clearly defined build and deployment processes. In a similar vein, we have the different application environments like development, production, staging, feature branches, SaaS vs. on-premise environments, and so on. Environments are divergent by definition, we are going to end up with different features in different environments, whether they are debugging facilities, product features, or performance optimizations.
 
@@ -251,7 +262,7 @@ As much as possible, we should strive to keep these kinds of divergences to a mi
 
 Proper integration testing might catch many of these kinds of mistakes, but that won't always be the case.
 
-==== 6.8 Abstraction Matters
+==== 6.7 Abstraction Matters
 
 Eager abstraction can result in catastrophe. Conversely, failure to identify and abstract away sources of major complexity can be incredibly costly as well. When we consume complex interfaces directly, but don't necessarily take advantage of all the advanced configuration options that interface has to offer, we are missing out on a powerful abstraction we could be using. The alternative would be to create a middle layer in front of the complex interface, and have consumers go through that layer instead.
 

From 08f6f292f47440a7d3d442e6c6f86439e20b860c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 22 Jun 2018 10:46:51 -0300
Subject: [PATCH 44/71] review feedback closes #8

---
 chapters/ch05.asciidoc | 150 ++++++++++++++++++++++++++++++++++-------
 chapters/ch06.asciidoc |  20 +++---
 2 files changed, 135 insertions(+), 35 deletions(-)

diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index 5e9693d..826e59b 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -27,7 +27,30 @@ Unlike strings, with template literals we can interpolate expressions using a st
 `Hello ${ name }, I'm Nicolás!`
 ----
 
-Besides these improvements, template literals also offer the possibility of tagged templates. You can prefix the template with a custom function that transforms the template's output use cases like input sanitization, formatting, or anything else.
+Besides these improvements, template literals also offer the possibility of tagged templates. You can prefix the template with a custom function that transforms the template's output, enabling use cases like input sanitization, formatting, or anything else.
+
+As an illustrative example, the following function could be used for the sanitization use case mentioned above. Any expressions interpolated into a template go through the `insane` function from a library by the same name, which strips out unsafe bits of HTML -- tags, attributes, or whole trees -- to keep user-provided strings honest.
+
+[source,javascript]
+----
+import insane from 'insane'
+
+function sanitize(template, ...expressions) {
+  return template.reduce((accumulator, part, i) => {
+    return accumulator + insane(expressions[i - 1]) + part
+  })
+}
+----
+
+In the following example we embed a user-provided `comment` as an interpolated expression in a template literal, and the `sanitize` tag takes care of the rest.
+
+[source,javascript]
+----
+const comment = 'exploit time! <iframe src="http://evil.corp"></iframe>'
+const html = sanitize`<div>${ comment }</div>`
+console.log(html)
+// <- '<div>exploit time! </div>'
+----
 
 Whenever we need to compose a string using data, template literals are a terse alternative to string concatenation. When we want to avoid escaping single or double quotes, template literals can help. The same is true when we want to write multi-line strings.
 
@@ -35,16 +58,16 @@ In every other case -- when there's no interpolation, escaping, or multi-line ne
 
 [NOTE]
 ====
-When it comes to style choices, you'll rarely face problems if you let your team come to a consensus about the preferred style choice and later enforce that choice by way of a lint tool like ESLint. It's entirely valid ot stick with single-quoted strings and only use template literals when deemed absolutely necessary, if that's what most of the team prefers.
+When it comes to style choices, you'll rarely face problems if you let your team come to a consensus about the preferred style choice and later enforce that choice by way of a lint tool like ESLint. It's entirely valid to stick with single-quoted strings and only use template literals when deemed absolutely necessary, if that's what most of the team prefers.
 
-Using a tool like ESLint and a continuous integration job to enforce its rules means nobody has to perform the time consuming job of keeping everyone in line with the house style. When tooling enforces style choices, discussions about those choices won't crop up as often in discussion threads while contributors are collaborating on units of work.
+Using a tool like ESLint and a continuous integration job to enforce its rules means nobody has to perform the time-consuming job of keeping everyone in line with the house style. When tooling enforces style choices, discussions about those choices won't crop up as often in discussion threads while contributors are collaborating on units of work.
 ====
 
-It's important to differentiate between purely stylistic choices, which tend to devolve in contentious time-sinking discussions, and choices where there's more ground to be covered in the everlasting battle against complexity. While the former may make a codebase subjectively easier to read, or aesthetically pleasing, it is only through deliberate action that we keep complexity in check. Granted, a consistent style throughout a codebase can help contain complexity, but the exact style is unimportant as long as we enforce it consistently.
+It's important to differentiate between purely stylistic choices, which tend to devolve in contentious time-sinking discussions, and choices where there's more ground to be covered in the everlasting battle against complexity. While the former may make a codebase subjectively easier to read, or more aesthetically pleasing, it is only through deliberate action that we keep complexity in check. Granted, a consistent style throughout a codebase can help contain complexity, but the exact style is unimportant as long as we enforce it consistently.
 
 ==== 5.1.2 Destructuring, Rest, and Spread
 
-The destructuring, rest and spread features came into effect in ES6. These features accomplish a number of different things, which we'll now discuss.
+The destructuring, rest, and spread features came into effect in ES6. These features accomplish a number of different things, which we'll now discuss.
 
 Destructuring helps us indicate the fields of an object that we'll be using to compute the output of a function. In the following example, we destructure a few properties from a `ticker` variable, and then combine that with a `...details` rest pattern containing every property of `ticker` that we haven't explicitly named in our destructuring pattern.
 
@@ -101,7 +124,7 @@ const {
 
 When using `:` to alias, it can be difficult at first to remember whether the original name or the aliased name comes first. One helpful way to keep it straight is to mentally replace `:` with the word "as".  That way, `name: responseContactName` would read as "name as responseContactName".
 
-We can even have the same property listed twice, if we wanted to destructure some of its contents, while also maintaining access to the object itself.  For example, if we wanted to destructure the `contact` object's contents, like we do above, but also take a reference to the whole `contact` object, we can do the following
+We can even have the same property listed twice, if we wanted to destructure some of its contents, while also maintaining access to the object itself. For example, if we wanted to destructure the `contact` object's contents, like we do above, but also take a reference to the whole `contact` object, we can do the following:
 
 [source,javascript]
 ----
@@ -207,7 +230,14 @@ Let's move onto a more interesting topic: asynchronous code flows.
 
 ==== 5.1.4 Navigating Callbacks, Promises, and Asynchronous Functions
 
-JavaScript now offers several options when it comes to describing asynchronous algorithms: the plain callback pattern, promises, async functions, async iterators, async generators, plus any patterns offered by libraries consumed in our applications. Each solution comes with their own set of strengths and weaknesses: callbacks are typically a solid choice, but we often need to get libraries involved when we want to execute our work concurrently; Promises might be hard to understand at first, but they offer a few utilities like `Promise#all` for concurrent work, yet they might be hard to debug under some circumstances; Async functions require a bit of understanding on top of being comfortable with promises, but they're easier to debug and often result in simpler code, plus they can be interspersed with synchronous functions rather easily as well; Iterators and generators are powerful tools, but there aren't many practical use cases for them, so we must consider whether we're using them because they fit our needs or just because we can.
+JavaScript now offers several options when it comes to describing asynchronous algorithms: the plain callback pattern, promises, async functions, async iterators, async generators, plus any patterns offered by libraries consumed in our applications.
+
+Each solution comes with its own set of strengths and weaknesses:
+
+1. Callbacks are typically a solid choice, but we often need to get libraries involved when we want to execute our work concurrently
+2. Promises might be hard to understand at first, but they offer a few utilities like `Promise#all` for concurrent work, yet they might be hard to debug under some circumstances
+3. Async functions require a bit of understanding on top of being comfortable with promises, but they're easier to debug and often result in simpler code, plus they can be interspersed with synchronous functions rather easily as well
+4. Iterators and generators are powerful tools, but there aren't all that many practical use cases for them, so we must consider whether we're using them because they fit our needs or just because we can.
 
 It could be argued that callbacks are the simplest mechanism, although a similar case could be made for promises now that so much of the language is built around them. In any case, consistency should remain as the primary driving force of how we decide which pattern to use. While it's okay to mix and match a few different patterns, most of the time we should be using the same patterns again and again, so that our team can develop a sense of familiarity with the codebase, instead of having to take a guess whenever encountering an unchartered portion of the application.
 
@@ -221,12 +251,12 @@ function delay(timeout) {
       resolve()
     }, timeout)
   }
-  return new Promise(resolver))
+  return new Promise(resolver)
 }
 delay(2000).then(…)
 ----
 
-A similar pattern would have to be used to consume functions taking a last argument that's an error-first callback style function in Node.js. Starting with Node.js v8.0.0, however, there's a utility built-in that "promisifies" these callback-based functions so that they return promises.footnote:[Note also that, starting in Node.js v10.0.0, the native `fs.promises` interface can be used to access promise-based versions of the `fs` module's methods.]
+A similar pattern would have to be used to consume functions taking a last argument that's an error-first callback-style function in Node.js. Starting with Node.js v8.0.0, however, there's a utility built-in that "promisifies" these callback-based functions so that they return promises.footnote:[Note also that, starting in Node.js v10.0.0, the native `fs.promises` interface can be used to access promise-based versions of the `fs` module's methods.]
 
 [source,javascript]
 ----
@@ -243,7 +273,8 @@ There are libraries that could do the same for the client-side, one such example
 
 [source,javascript]
 ----
-function promisify(fn) {
+// promisify.js
+export default function promisify(fn) {
   return (...rest) => {
     return new Promise((resolve, reject) => {
       fn(...rest, (err, result) => {
@@ -258,6 +289,19 @@ function promisify(fn) {
 }
 ----
 
+Using a `promisify` function, then, would be no different than the earlier example with `readFile`, except we'd be providing our own `promisify` implementation.
+
+[source,javascript]
+----
+import promisify from './promisify'
+import { readFile } from 'fs'
+const readFilePromise = promisify(readFile)
+
+readFilePromise('./data.json', 'utf8').then(data => {
+  console.log(`Data: ${ data }`)
+})
+----
+
 Casting promises back into a callback-based format is less involved because we can add reactions to handle both the fulfillment and rejection results, and call back `done` passing in the corresponding result where appropriate.
 
 [source,javascript]
@@ -285,13 +329,13 @@ Let's explore how we can improve our application designs beyond what JavaScript
 
 Up until ES6 introduced first-class syntax for prototypal inheritance to JavaScript, prototypes weren't a widely used feature in user-land. Instead, libraries offered helper methods that made inheritance simpler, using prototypal inheritance under the hood, but hiding the implementation details from their consumers. Even though ES6 classes look a lot like classes in other languages, they're syntactic sugar using prototypes under the hood, making them compatible with older techniques and libraries.
 
-The introduction of a `class` keyword, paired with the React framework hailing classes as the go-to way of declaring stateful components, classes have helped spark some love for a pattern that was previously quite unpopular when it comes to JavaScript. In the case of React, the base `Component` class offers lightweight state management methods, while leaving the rendering and lifecycle up to the consumer classes extending `Component`. When necessary, the consumer can also decide to implement methods such as `componentDidMount`, which allows for event binding after a component tree is mounted; `componentDidCatch`, which can be used to trap unhandled exceptions that arise during the component lifecycle; among a variety of other soft interface methods. There's no mention of these optional lifecycle hooks anywhere in the base `Component` class, which are instead confined to the rendering mechanisms of React. In this sense, we note that the `Component` class stays focused on state management, while everything else is offered up by the consumer.
+The introduction of a `class` keyword, paired with the React framework originally hailing classes as the go-to way of declaring stateful components, classes have helped spark some love for a pattern that was previously quite unpopular when it comes to JavaScript. In the case of React, the base `Component` class offers lightweight state management methods, while leaving the rendering and lifecycle up to the consumer classes extending `Component`. When necessary, the consumer can also decide to implement methods such as `componentDidMount`, which allows for event binding after a component tree is mounted; `componentDidCatch`, which can be used to trap unhandled exceptions that arise during the component lifecycle; among a variety of other soft interface methods. There's no mention of these optional lifecycle hooks anywhere in the base `Component` class, which are instead confined to the rendering mechanisms of React. In this sense, we note that the `Component` class stays focused on state management, while everything else is offered up by the consumer.
 
 Inheritance is also useful when there's an abstract interface to implement and methods to override, particularly when the objects being represented can be mapped to the real world. In practical terms and in the case of JavaScript, inheritance works great when the prototype being extended offers a good description for the parent prototype: a `Car` is a `Vehicle` but a car is not a `SteeringWheel`: the wheel is just one aspect of the car.
 
 ==== 5.2.2 The Perks of Composition: Aspects and Decorators
 
-With inheritance we can add layers of complexity to an object. These layers are meant to be ordered, we start with the least specific foundational bits of the object and build our way up to the most specific aspects of it. When we write code based on inheritance chains, complexity is spread across the different classes, but lies mostly at the foundational layers which offer a terse API while hiding this complexity away. Composition is an alternative to inheritance. Rather than building objects by vertically stacking functionality, composition relies on stringing together orthogonal aspects of functionality. In this sense, orthogonality means that the bits of functionality we compose together complements each other, but doesn't alter one another's behavior.
+With inheritance we can add layers of complexity to an object. These layers are meant to be ordered: we start with the least specific foundational bits of the object and build our way up to the most specific aspects of it. When we write code based on inheritance chains, complexity is spread across the different classes, but lies mostly at the foundational layers which offer a terse API while hiding this complexity away. Composition is an alternative to inheritance. Rather than building objects by vertically stacking functionality, composition relies on stringing together orthogonal aspects of functionality. In this sense, orthogonality means that the bits of functionality we compose together complements each other, but doesn't alter one another's behavior.
 
 One way to compose functionality is additive: we could write decorators, which augment existing objects with new functionality. In the following code snippet we have a `makeEmitter` function which adds flexible event handling functionality to any target object, providing them with an `.on` method, where we can add event listeners to the target object; and an `.emit` method, where the consumer can indicate a type of event and any number of parameters to be passed to event listeners.
 
@@ -385,7 +429,7 @@ emitEvent(person, 'move', 23, 5)
 // <- 'Artemisa moved to [23, 5].'
 ----
 
-Note how we're using both `WeakMap` and `Map` here. Using a plain `Map` would prevent garbage collection from cleaning things up when `target` is only being referenced by `Map` entries, whereas `WeakMap` would allow garbage collection to take place. Given we usually want to attach events to objects, we can use `WeakMap` as a way to avoid creating strong references that might end up leading to memory leaks. On the other hand, it's okay to use a regular `Map` for the event listeners, given those are associated to an event type string.
+Note how we're using both `WeakMap` and `Map` here. Using a plain `Map` would prevent garbage collection from cleaning things up when `target` is only being referenced by `Map` entries, whereas `WeakMap` allows garbage collection to take place on the objects that make up its keys. Given we usually want to attach events to objects, we can use `WeakMap` as a way to avoid creating strong references that might end up causing memory leaks. On the other hand, it's okay to use a regular `Map` for the event listeners, given those are associated to an event type string.
 
 Let's move onto deciding whether to use inheritance, decorators, or functional composition, where each pattern shines, and when to avoid them.
 
@@ -399,7 +443,7 @@ The functional approach is a bit more cumbersome to implement than simply mutati
 
 Furthermore, using base classes makes it a bit hard to reuse the logic at varying insertion points in our prototype chains. Using decorators, likewise, makes it challenging to add similar methods that support slightly different use cases. Using a functional approach leads to less coupling in this regard, but it could also complicate the underlying implementation of the makeup for objects, making it hard to decypher how their functionality ties in together, tainting our fundamental understanding of how code flows and making debugging sessions longer than need be.
 
-As with most things programming, your codebase will benefit from a semblance of consistency. Even if you use all three patterns, -- and others -- a codebase that uses half a dozen patterns in equal amounts will be harder to understand, work with, and build on, than an equivalnet codebase that instead uses one pattern for the vast majority of its code while using other patterns in smaller ways when warranted. Picking the right pattern for each situation and striving for consistency might seem at odds with each other, but this is again a balancing act. The trade-off is between consistency in the grand scale of our codebase versus simplicity in the local piece of code we're working on. The question to ask is then: are we obtaining enough of a simplicity gain that it warrants the sacrifice of some consistency?
+As with most things programming, your codebase benefits from a semblance of consistency. Even if you use all three patterns, -- and others -- a codebase that uses half a dozen patterns in equal amounts is harder to understand, work with, and build on, than an equivalent codebase that instead uses one pattern for the vast majority of its code while using other patterns in smaller ways when warranted. Picking the right pattern for each situation and striving for consistency might seem at odds with each other, but this is again a balancing act. The trade-off is between consistency in the grand scale of our codebase versus simplicity in the local piece of code we're working on. The question to ask is then: are we obtaining enough of a simplicity gain that it warrants the sacrifice of some consistency?
 
 === 5.3 Code Patterns
 
@@ -409,7 +453,7 @@ Digging a bit deeper and into more specific elements of architecture design, in
 
 The revealing module pattern has become a staple in the world of JavaScript. The premise is simple enough: expose precisely what consumers should be able to access, and avoid exposing anything else. The reasons for this are manifold. Preventing unwarranted access to implementation details reduces the likelihood of your module's interface being abused for unsupported use cases that might bring headaches to both the module implementer and the consumer alike.
 
-Explicitly avoid exposing methods meant to be private, such as a hypothetical +_calculatePriceHistory+ method, which relies on the leading hyphen as a way of discouraging direct access and signaling that it should be regarded as private. Avoiding such methods prevents test code from accessing private methods directly, resulting in tests that make assertions solely regarding the interface and which can be later referenced as documentation on how to use the interface; prevents consumers from monkey-patching implementation details, leading to more transparent interfaces; and also often results in cleaner interfaces due to the fact that the interface is all there is, and there's no alternative ways of interacting with the module through direct use of its internals.
+Explicitly avoid exposing methods that are meant to be private, such as a hypothetical +_calculatePriceHistory+ method, which relies on the leading underscore as a way of discouraging direct access and signaling that it should be regarded as private. Avoiding such methods prevents test code from accessing private methods directly, resulting in tests that make assertions solely regarding the interface and which can be later referenced as documentation on how to use the interface; prevents consumers from monkey-patching implementation details, leading to more transparent interfaces; and also often results in cleaner interfaces due to the fact that the interface is all there is, and there's no alternative ways of interacting with the module through direct use of its internals.
 
 JavaScript modules are of a revealing nature by default, making it easy for us to follow the revealing pattern of not giving away access to implementation details. Functions, objects, classes, and any other bindings we declare are private unless we explicitly decide to `export` them from the module.
 
@@ -419,9 +463,9 @@ When we expose only a thin interface, our implementation can change largely with
 
 Even when using JavaScript modules and following the revealing pattern strictly, we might end up with unintentional sharing of state across our usage of a module. Incidental state might result in unexpected results from an interface: consumers don't have a complete picture because other consumers are contributing changes to this shared state as well, sometimes making it hard to figure out what exactly is going on in an application.
 
-If we were to move our functional event emitter code snippet, with `onEvent` and `emitEvent`, into a JavaScript module, we'd notice that the `emitters` map is now a local global for that module, meaning all of the module's scope has access to `emitters`. This is what we'd want, because that way we can register event listeners in `onEvent` and fire them off in `emitEvent`. In most other situations, however, sharing persistent state across public interface methods is a recipe for unexpected bugs.
+If we were to move our functional event emitter code snippet, with `onEvent` and `emitEvent`, into a JavaScript module, we'd notice that the `emitters` map is now a lexical top-level binding for that module, meaning all of the module's scope has access to `emitters`. This is what we'd want, because that way we can register event listeners in `onEvent` and fire them off in `emitEvent`. In most other situations, however, sharing persistent state across public interface methods is a recipe for unexpected bugs.
 
-Suppose we have a `calculator` module that can be used to make basic calculations through a stream of operations. Even if consumers were supposed to use it synchronously and flush state in one fell swoop, without giving way for a second consumer to taint the state and produce unexpected results, our module shouldn't rely on consumer behavior to provide consistent results. The following contrived implementation relies on local shared state, and would need consumers to use the module strictly as intended, making all calls to `add`, `multiply`, and `calculate` in sequence.
+Suppose we have a `calculator` module that can be used to make basic calculations through a stream of operations. Even if consumers were supposed to use it synchronously and flush state in one fell swoop, without giving way for a second consumer to taint the state and produce unexpected results, our module shouldn't rely on consumer behavior to provide consistent results. The following contrived implementation relies on local shared state, and would need consumers to use the module strictly as intended, making any calls to `add` and `multiply`, leaving `calculate` as the last method that's meant to be called only once.
 
 [source,javascript]
 ----
@@ -446,16 +490,35 @@ export function calculate() {
 }
 ----
 
-Here's an example of how consuming the previous module could work. As soon as we tried to asynchronously append text to the buffer, things would start getting out of hand, with the operations array getting bits and pieces of unrelated calculations, tainting our calculations.
+Here's an example of how consuming the previous module could work.
 
 [source,javascript]
 ----
+import { add, multiply, calculate } from './calculator'
 add(3)
 add(4)
 multiply(-2)
 calculate() // <- -14
 ----
 
+As soon as we tried to append operations in two places, things would start getting out of hand, with the operations array getting bits and pieces of unrelated computations, tainting our calculations.
+
+[source,javascript]
+----
+// a.js
+import { add, calculate } from './calculator'
+add(3)
+setTimeout(() => {
+  add(4)
+  calculate() // <- 14, an extra 7 because of b.js
+}, 100)
+
+// b.js
+import { add, calculate } from './calculator'
+add(2)
+calculate() // <- 5, an extra 3 from a.js
+----
+
 A slightly better approach would get rid of the `state` variable, and instead pass the state around operation handlers, so that each operation knows the current state, and applies any necessary changes to it. The `calculate` step would create a new initial state each time, and go from there.
 
 [source,javascript]
@@ -477,9 +540,25 @@ export function calculate() {
 }
 ----
 
-This approach presents problems too, however. Even though the `state` will always be reset to `0`, we're treating unrelated operations as if they were all part of a whole, which is still wrong.
+This approach presents problems too, however. Even though the `state` is always reset to `0`, we're treating unrelated operations as if they were all part of a whole, which is still wrong.
 
-Blatantly, this contrived module is poorly designed, as its operations buffer should never be used to drive several unrelated calculations. We should instead expose a factory function that returns an object from its own self-contained scope, where all relevant state is shut off from the outside world. The methods on this object are equivalent to the exported interface of a plain JavaScript module, but state mutations are contained to instances that consumers create.
+[source,javascript]
+----
+// a.js
+import { add, calculate } from './calculator'
+add(3)
+setTimeout(() => {
+  add(4)
+  calculate() // <- 9, an extra 2 from b.js
+}, 100)
+
+// b.js
+import { add, calculate } from './calculator'
+add(2)
+calculate() // <- 5, an extra 3 from a.js
+----
+
+Blatantly, our contrived module is poorly designed, as its operations buffer should never be used to drive several unrelated calculations. We should instead expose a factory function that returns an object from its own self-contained scope, where all relevant state is shut off from the outside world. The methods on this object are equivalent to the exported interface of a plain JavaScript module, but state mutations are contained to instances that consumers create.
 
 [source,javascript]
 ----
@@ -504,24 +583,45 @@ export function getCalculator() {
 }
 ----
 
-Using the calculator like this is just as straightforward, except that now we can do things asynchronously and even if other consumers are also using string builders of their own, each user will have their own state, preventing data corruption.
+Using the calculator like this is just as straightforward, except that now we can do things asynchronously and even if other consumers are also making computations of their own, each user will have their own state, preventing data corruption.
 
 [source,javascript]
 ----
-const { append, stringify } = getCalculator()
+import { getCalculator } from './calculator'
+const { add, multiply, calculate } = getCalculator()
 add(3)
 add(4)
 multiply(-2)
 calculate() // <- -14
 ----
 
+Even with our two-file example, we wouldn't have any problems anymore, since each file would have its own atomic calculator.
+
+[source,javascript]
+----
+// a.js
+import { getCalculator } from './calculator'
+const { add, calculate } = getCalculator()
+add(3)
+setTimeout(() => {
+  add(4)
+  calculate() // <- 7
+}, 100)
+
+// b.js
+import { getCalculator } from './calculator'
+const { add, calculate } = getCalculator()
+add(2)
+calculate() // <- 2
+----
+
 As we just showed, even when using modern language constructs and JavaScript modules, it's not too hard to create complications through shared state. Thus, we should always strive to contain mutable state as close to its consumers as possible.
 
 ==== 5.3.3 Event Emission
 
 We've already explored at length the pattern of registering event listeners associated to arbitrary plain JavaScript objects and firing events of any kind, triggering those listeners. Event handling is most useful when we want to have clearly-delineated side-effects.
 
-In the browser, for instance, we can bind a `click` event to an specific DOM element. When the `click` event is fired, we might issue an HTTP request, render a different page, start an animation, or play an audio file.
+In the browser, for instance, we can bind a `click` event to an specific DOM element. When the `click` event fires, we might issue an HTTP request, render a different page, start an animation, or play an audio file.
 
 Events are a useful way of reporting progress whenever we're dealing with a queue. While processing a queue, we could fire a `progress` event whenever an item is processed, allowing the UI or any other consumer to render and update a progress indicator or apply a partial unit of work relying on the data processed by the queue.
 
@@ -548,8 +648,8 @@ class Person {
 const rwanda = new Person('Rwanda', '123 Main St')
 ----
 
-Although we can easily serialize our `rwanda` instance with `JSON.stringify(rwanda)`, and then send it over the wire, the code on the other end will have no standard way of turning this JSON back into an instance of our `Person` class, which might have a lot more functionality than merely a `greet` function. The receiving end might have no business deserializing this data back into the class instance it originated from, but in some cases there's merit to having an exact replica object back on the other end. For example, to reduce friction when passing messages between a website and a web worker, both sides should be dealing in the same data structure. In such scenario, simple JavaScript objects are ideal.
+Although we can easily serialize our `rwanda` instance with `JSON.stringify(rwanda)`, and then send it over the wire, the code on the other end has no standard way of turning this JSON back into an instance of our `Person` class, which might have a lot more functionality than merely a `greet` function. The receiving end might have no business deserializing this data back into the class instance it originated from, but in some cases there's merit to having an exact replica object back on the other end. For example, to reduce friction when passing messages between a website and a web worker, both sides should be dealing in the same data structure. In such scenarios, simple JavaScript objects are ideal.
 
-JSON, a subset of the JavaScript grammar, was purpose-built for this use case, where we often have to serialize data, send it over the wire, and deserialize it on the other end. Plain JavaScript objects are a great way to store data in our applications, offer frictionless serialization out the box, and lead to cleaner data structures because we can keep logic decoupled from the data.
+JSON -- nowfootnote:[json-grammar,Up until recently, JSON wasn't -- strictly speaking -- a proper subset of ECMA-262. A recent proposal has amended the ECMAScript specification to consider bits of JSON that were previously invalid JavaScript to be valid JavaScript. Learn more at: https://mjavascript.com/out/json-subset.] a subset of the JavaScript grammar -- was purpose-built for this use case, where we often have to serialize data, send it over the wire, and deserialize it on the other end. Plain JavaScript objects are a great way to store data in our applications, offer frictionless serialization out the box, and lead to cleaner data structures because we can keep logic decoupled from the data.
 
 When the language on both the sending and receiving ends is JavaScript, we can share a module with all the functionality that we need around the data structure. This way, we don't have to worry about serialization, since we're using plain JavaScript objects and can rely on JSON for the transport layer. We don't have to concern ourselves with sharing functionality either, because we can rely on the JavaScript module system for that part.
diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index bc46dd2..3b6197f 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -7,11 +7,11 @@ In this chapter we'll explore open-source principles and look at ways in which w
 
 === 6.1 Secure Configuration Management
 
-When it comes to configuration secrets in closed-source projects, like API keys or HTTP session decryption keys, it is not uncommon for them to be hard-coded in place. In open-source projects, instead, these are typically instead obtained through environment variables or encrypted configuration files that aren't committed to version control systems alongside our codebase.
+When it comes to configuration secrets in closed-source projects, like API keys or HTTPS session decryption keys, it is not uncommon for them to be hard-coded in place. In open-source projects, instead, these are typically instead obtained through environment variables or encrypted configuration files that aren't committed to version control systems alongside our codebase.
 
 In the case of open-source projects, this allows the developer to share the vast majority of their application without compromising the security of their production systems. While this might not be an immediate concern in closed-source environments, we need to consider that once a secret is committed to version control, it's etched into our version history unless we force a rewrite of that history, scrubbing the secrets from existence. Even then, it cannot be guaranteed that a malicious actor has gained access to these secrets at some point before they were scrubbed from history, and thus a better solution to this problem is rotating the secrets that might be compromised, revoking access through the old secrets and starting to use new, uncompromised secrets.
 
-While effective, this approach can be time consuming when we have several secrets under our belt, and when our application is large enough, leaked secrets might pose significant risk even when exposed for a short period of time. As such, it's best to approach secrets with careful consideration by default, and avoid headaches later in the lifetime of a project.
+While effective, this approach can be time-consuming when we have several secrets under our belt, and when our application is large enough, leaked secrets pose significant risk even when exposed for a short period of time. As such, it's best to approach secrets with careful consideration by default, and avoid headaches later in the lifetime of a project.
 
 The absolute least we could be doing is giving every secret a unique name, and placing them in a JSON file. Any sensitive information or configurable values may qualify as a secret, and this might range from private signing keys used to sign certificates to port numbers or database connection strings.
 
@@ -24,7 +24,7 @@ The absolute least we could be doing is giving every secret a unique name, and p
 }
 ----
 
-Instead of hardcoding these variables wherever they're used, or even placing them in a constant at the beginning of the module, we centralize all sensitive information in a single file, that can then be excluded from version control. Besides helping us share the secrets across modules, making updates easier, this approach encourages us to isolate information that we previously wouldn't have considered sensitive, like the work factor used for salting passwords.
+Instead of hardcoding these variables wherever they're used, or even placing them in a constant at the beginning of the module, we centralize all sensitive information in a single file that can then be excluded from version control. Besides helping us share the secrets across modules, making updates easier, this approach encourages us to isolate information that we previously wouldn't have considered sensitive, like the work factor used for salting passwords.
 
 Another benefit of going down this road is that, given we have all environment configuration in a central store, we can point our application to a different secret store depending on whether we're provisioning the application for production, staging, or one of the local development environments used by our developers.
 
@@ -143,7 +143,7 @@ A secret service also takes care of encryption, secure storage, secret rotation
 
 The reason why we sometimes feel tempted to check our dependencies into source control is so that we get the exact same versions across the dependency tree, every time, in every environment.
 
-Including dependency trees in our repositories is not practical, however, given these are typically in the hundreds of megabytes and frequently include compiled assets that are built based on the target environment and operating system, meaning that the build process itself -- the act `npm` executing a `rebuild` step after `npm install` ends -- is environment dependant, and thus not suitable for a presumably platform-agnostic code repository.
+Including dependency trees in our repositories is not practical, however, given these are typically in the hundreds of megabytes and frequently include compiled assets that are built based on the target environment and operating system, meaning that the build process itself -- the act of `npm` executing a `rebuild` step after `npm install` ends -- is environment-dependant, and thus not suitable for a presumably platform-agnostic code repository.
 
 During development, we want to make sure we get non-breaking upgrades to our dependencies, which can help us resolve upstream bugs, tighten our grip around security vulnerabilities, and leverage new features or improvements. For deployments however, we want reproducible builds, where installing our dependencies yields the same results every time.
 
@@ -179,11 +179,11 @@ Always installing identical versions of our dependencies -- and identical versio
 
 ==== 6.3 Interfaces as Black Boxes
 
-On a similar note to that of the last section, we should treat our own components no differently than how we treat third party libraries and modules. Granted, we can make changes to our own code a lot more quickly than we can effect change in third party code -- if that's at all possible, in some cases. However, when we treat all components and interfaces (including our own HTTP API) as if they were foreign to us, we can focus on consuming and testing against interfaces, while ignoring the underlying implementation.
+On a similar note to that of the last section, we should treat our own components no differently than how we treat third-party libraries and modules. Granted, we can make changes to our own code a lot more quickly than we can effect change in third-party code -- if that's at all possible, in some cases. However, when we treat all components and interfaces (including our own HTTP API) as if they were foreign to us, we can focus on consuming and testing against interfaces, while ignoring the underlying implementation.
 
 One way to improve our interfaces is to write detailed documentation about the input an interface touchpoint expects, and how it affects the output it provides in each case. The process of writing documentation leads to uncovering limitations in how the interface is designed, and we might decide to change it as a result. Consumers love good documentation because it means less fumbling about with the implementation (or its implementors), to understand how the interface is meant to be consumed, and whether it can accomplish what they need.
 
-Avoiding distinctions helps us write unit tests where we mock dependencies that aren't under test, regardless of whether they were developed in-house or by a third party. When writing tests we always assume that third party modules are generally well-tested enough that it's not our responsibility to include them in our test cases. The same thinking should apply to first party modules that just happen to be dependencies of the module we're currently writing tests for.
+Avoiding distinctions helps us write unit tests where we mock dependencies that aren't under test, regardless of whether they were developed in-house or by a third-party. When writing tests we always assume that third-party modules are generally well-tested enough that it's not our responsibility to include them in our test cases. The same thinking should apply to first party modules that just happen to be dependencies of the module we're currently writing tests for.
 
 This same reasoning can be applied to security concerns such as input sanitization. Regardless of what kind of application we're developing, we can't trust user input unless it's sanitized. Malicious actors could be angling to take over our servers, our customers' data, or otherwise inject content onto our web pages. These users might be customers or even employees, so we shouldn't treat them differently depending on that, when it comes to input sanitization.
 
@@ -209,17 +209,17 @@ Note how up until this point we have focused on how we build and test our assets
 
 ==== 6.5 Statelessness
 
-We've already explored how state, if left unchecked, can lead us straight to the heat death of our applications. Keeping state to a minimum translates directly into applications that are easier to debug. The less global state there is, the less unpredictable the current conditions of an application will be at any one point in time, and the least surprises we'll run into while debugging.
+We've already explored how state, if left unchecked, can lead us straight to the heat death of our applications. Keeping state to a minimum translates directly into applications that are easier to debug. The less global state there is, the less unpredictable the current conditions of an application are at any one point in time, and the fewer surprises we'll run into while debugging.
 
 One particularly insidious form of state is caching. A cache is a great way to increase performance in an application by avoiding expensive lookups most of the time. When state management tools are used as a caching mechanism, we might fall into a trap where different bits and pieces of derived application state were derived at different points in time, thus rendering different bits of the application using data computed at different points in time.
 
-Derived state should seldom be treated as state that's separate from the data it was derived from. When it's not, we might run into situations where the original data is updated, but the derived state is not, becoming stale and inaccurate. When, instead, we always compute derived state from the original data, we reduce the likelyhood that this derived state will become stale.
+Derived state should seldom be treated as state that's separate from the data it was derived from. When it's not, we might run into situations where the original data is updated, but the derived state is not, becoming stale and inaccurate. When, instead, we always compute derived state from the original data, we reduce the likelihood that this derived state will become stale.
 
 State is almost ubiquitous, and practically a synonym of applications, because applications without state aren't particularly useful. The question then arises: how can we better manage state? If we look at applications such as your typical web server, their main job is to receive requests, process them, and send back the appropriate responses. Consequently, web servers associate state to each request, keeping it near request handlers, the most relevant consumer of request state. There is as little global state as possible when it comes to web servers, with the vast majority of state contained in each request/response cycle instead. In this way, web servers save themselves from a world of trouble when setting up horizontal scaling with multiple server nodes that don't need to communicate with each other in order to maintain consistency across web server nodes, leaving that job to a data persistance layer, which is ultimately responsible for the state as its source of truth.
 
 When a request results in a long running job (such as sending out an email campaign, modifying records in a persistant database, etc), it's best to hand that off into a separate service that -- again -- mostly keeps state regarding said job. Separating services into specific needs means we can keep web servers lean, stateless, and improve our flows by adding more servers, persistent queues (so that we don't drop jobs), and so on. When every task is tethered together through tight coupling and state, it could become challenging to maintain, upgrade, and scale a service over time.
 
-Derived state in the form of caches is not uncmoon in the world of web servers. In the case of a personal website with some books available for download, for instance, we might be tempted to store the PDF representation of each book in a file, so that we don't have to recompile the PDF whenever the corresponding `/book` route is visited. When the book is updated, we'd recompute the PDF file and flush it to disk again, so that this derived state remains fresh. When our web server ceases to be single node and we start using a cluster of several nodes, however, it might not be so trivial to broadcast the news about books being updated across nodes, and thus it'd be best to leave derived state to the persistance layer. Otherwise, a web server node might receive the request to update a book, perform the update and recompute the PDF file on that node, but we'd be inadvertently invalidating the PDF files being served by other nodes, which would have stale copies of the PDF representation.
+Derived state in the form of caches is not uncmoon in the world of web servers. In the case of a personal website with some books available for download, for instance, we might be tempted to store the PDF representation of each book in a file, so that we don't have to recompile the PDF whenever the corresponding `/book` route is visited. When the book is updated, we'd recompute the PDF file and flush it to disk again, so that this derived state remains fresh. When our web server ceases to be single-node and we start using a cluster of several nodes, however, it might not be so trivial to broadcast the news about books being updated across nodes, and thus it'd be best to leave derived state to the persistance layer. Otherwise, a web server node might receive the request to update a book, perform the update and recompute the PDF file on that node, but we'd be inadvertently invalidating the PDF files being served by other nodes, which would have stale copies of the PDF representation.
 
 A better alternative in such a case would be to store derived state in a data store like Redis or Amazon S3, either of which we could update from any web server, and then serving precomputed results from Redis directly. In this way we'd still be able to access the latency benefits of using precomputed derived state, but at the same time we'd stay resilient when these requests or updates can happen on multiple web server nodes.
 
@@ -229,7 +229,7 @@ On Disposability
 
 Whenever we hook up an event listener, regardless of whether we're listening for DOM events or those from an event emitter, we should also strongly consider disposing of the listener when the concerned parties are no longer interested in the event being raised. For instance, if we have a React component that, upon mount, starts listening for `resize` events on the `window` object, we should also make sure we remove those event listeners upon the component being unmounted.
 
-This kind of dilligence ensures that we can set up and tear down bits of our application without leaving behind mounting piles of listeners that would result in memory leaks, which are hard to track down and pinpoint.
+This kind of diligence ensures that we can set up and tear down bits of our application without leaving behind mounting piles of listeners that would result in memory leaks, which are hard to track down and pinpoint.
 
 The concept of disposability goes beyond just event handlers, though. Any sort of resource that we allocate and attach to an object, component, or service is created, should be released and cleaned up when that attachment ceases to exist. This way, we can confidently create and dispose of as many components as we want, without putting our application's performance at risk.
 ====

From c8f1b1e97592c8064e51c9e0c0bd42718769c050 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 22 Jun 2018 11:17:18 -0300
Subject: [PATCH 45/71] fix headings

---
 chapters/ch06.asciidoc | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 3b6197f..1e14df4 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -139,7 +139,7 @@ There are many other ways of storing our application settings, each with their o
 
 A secret service also takes care of encryption, secure storage, secret rotation (useful in the case of a data breach), among other advanced features.
 
-==== 6.2 Explicit Dependency Management
+=== 6.2 Explicit Dependency Management
 
 The reason why we sometimes feel tempted to check our dependencies into source control is so that we get the exact same versions across the dependency tree, every time, in every environment.
 
@@ -177,7 +177,7 @@ Using the information in a package lock file, which contains details about every
 
 Always installing identical versions of our dependencies -- and identical versions of our dependencies' dependencies -- brings us one step closer to having development environments that closely mirror what we do in production. This increases the likelyhood we can swiftly reproduce bugs that occurred in production in our local environments, while decreasing the odds that something that worked during development fails in staging.
 
-==== 6.3 Interfaces as Black Boxes
+=== 6.3 Interfaces as Black Boxes
 
 On a similar note to that of the last section, we should treat our own components no differently than how we treat third-party libraries and modules. Granted, we can make changes to our own code a lot more quickly than we can effect change in third-party code -- if that's at all possible, in some cases. However, when we treat all components and interfaces (including our own HTTP API) as if they were foreign to us, we can focus on consuming and testing against interfaces, while ignoring the underlying implementation.
 
@@ -189,7 +189,7 @@ This same reasoning can be applied to security concerns such as input sanitizati
 
 Putting ourselves in the shoes of the consumer is the best tool to guard us against half-baked interfaces. When -- as a thought exercise -- you stop and think about how you'd want to consume an interface, and the different ways in which you might need to consume it, you end up with a much better interface as a result. This is not to say we want to enable consumers to be able to do just about everything, but we want to make affordances where consuming an interface becomes as straightforward as possible and doesn't feel like a chore. If consumers are all but required to include long blocks of business logic right after they consume an interface, we need to stop ourselves and ask: would that business logic belong behind the interface rather than at its doorstep?
 
-==== 6.4 Build, Release, Run
+=== 6.4 Build, Release, Run
 
 Build processes have a few different aspects to them. At the highest level, there's the shared logic where we install and compile our assets so that they can be consumed by our runtime application. This can mean anything like installing system or application dependencies, copying files over to a different directory, compiling files into a different language or bundling them together, among a multitude of other requirements your application might have.
 
@@ -207,7 +207,7 @@ For these processes to be effective, they must be consistent. Intermittent test
 
 Note how up until this point we have focused on how we build and test our assets, but not how we deploy them. These two processes, build and deployment, are closely related but they shouldn't be intertwined. A clearly isolated build process where we end up with a packaged application we can easily deploy, and a deployment process that takes care of the specifics regardless of whether you're deploying to your own local environment, or to a hosted staging or production environment, means that for the most part we won't need to worry about environments during our build processes nor at runtime.
 
-==== 6.5 Statelessness
+=== 6.5 Statelessness
 
 We've already explored how state, if left unchecked, can lead us straight to the heat death of our applications. Keeping state to a minimum translates directly into applications that are easier to debug. The less global state there is, the less unpredictable the current conditions of an application are at any one point in time, and the fewer surprises we'll run into while debugging.
 
@@ -242,7 +242,7 @@ Large client-side applications often suffer from not having a single place where
 
 The same case could be made about any other function of our code, as having clearly defined layers in an application can make it straightforward to understand how an algorithm flows from layer to layer, but we'll find the biggest rewards to reap when it comes to isolating business logic from the rest of the application code.
 
-==== 6.6 Parity in Development and Production
+=== 6.6 Parity in Development and Production
 
 We've established the importance of having clearly defined build and deployment processes. In a similar vein, we have the different application environments like development, production, staging, feature branches, SaaS vs. on-premise environments, and so on. Environments are divergent by definition, we are going to end up with different features in different environments, whether they are debugging facilities, product features, or performance optimizations.
 
@@ -262,7 +262,7 @@ As much as possible, we should strive to keep these kinds of divergences to a mi
 
 Proper integration testing might catch many of these kinds of mistakes, but that won't always be the case.
 
-==== 6.7 Abstraction Matters
+=== 6.7 Abstraction Matters
 
 Eager abstraction can result in catastrophe. Conversely, failure to identify and abstract away sources of major complexity can be incredibly costly as well. When we consume complex interfaces directly, but don't necessarily take advantage of all the advanced configuration options that interface has to offer, we are missing out on a powerful abstraction we could be using. The alternative would be to create a middle layer in front of the complex interface, and have consumers go through that layer instead.
 

From f876a9e13771778e07ef10796aa8983b836243bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 22 Jun 2018 11:44:07 -0300
Subject: [PATCH 46/71] footnoteref:

---
 chapters/ch02.asciidoc | 8 ++++----
 chapters/ch03.asciidoc | 4 ++--
 chapters/ch04.asciidoc | 2 +-
 chapters/ch05.asciidoc | 4 ++--
 chapters/ch06.asciidoc | 2 +-
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/chapters/ch02.asciidoc b/chapters/ch02.asciidoc
index 7a4f019..1469dd1 100644
--- a/chapters/ch02.asciidoc
+++ b/chapters/ch02.asciidoc
@@ -330,7 +330,7 @@ export default factory
 
 As long as we limit the usage of each counter spewed by the `factory` to a given portion of the application which knows about each other usage, the state becomes more manageable, as we end up with fewer moving parts involved. When we eliminate impurity in public interfaces, we're effectively circumscribing entropy to the calling code. The consumer receives a brand new counter every time, and it's entirely responsible for managing its state. It can still pass the `counter` down to its dependents, but it's in control of how dependents get to manipulate that state, if at all.
 
-This is something we observe in the wild, with popular libraries such as the `request` packagefootnote:[You can find `request` here: https://mjavascript.com/out/request.] in Node.js, which can be used to make HTTP requests. The `request` function relies largely on sensible defaults for the `options` you can pass to it. Sometimes, we want to make requests using a different set of defaults.
+This is something we observe in the wild, with popular libraries such as the `request` packagefootnoteref:[request-pkg,You can find `request` here: https://mjavascript.com/out/request.] in Node.js, which can be used to make HTTP requests. The `request` function relies largely on sensible defaults for the `options` you can pass to it. Sometimes, we want to make requests using a different set of defaults.
 
 The library might've offered a solution where we could change the default values for every call to `request`. This would've been poor design, as it'd make their handling of `options` more unstable, where we'd have to take into account every corner of our codebase before we could be confident about the `options` we'd ultimately end up with when calling `request`.
 
@@ -338,7 +338,7 @@ Request chose a solution where it has a `request.defaults(options)` method which
 
 === 2.2 CRUST: Consistent, Resilient, Unambiguous, Simple and Tiny
 
-A well-regarded API typically packs several of the following traits. It is consistent, meaning it is idempotentfootnote:[For a given set of inputs, an idempotent function always produces the same output.] and has a similar signature shape as that of related functions. It is resilient, meaning its interface is flexible and accepts input expressed in a few different ways, including optional parameters and overloading. Yet, it is unambiguous, there aren't multiple interpretations of how the API should be used, what it does, how to provide inputs or how to understand the output. Through all of this, it manages to stay simple: it's straightforward to use and it handles common use cases with little to no configuration, while allowing customization for advanced use cases. Lastly, a CRUST interface is also tiny: it meets its goals but it isn't overdesigned, it's comprised by the smallest possible surface area while allowing for future non-breaking extensibility. CRUST mostly regards the outer layer of a system (be it a package, a file, or a function), but its principles will seep into the innards of its components and result in simpler code overall.
+A well-regarded API typically packs several of the following traits. It is consistent, meaning it is idempotentfootnoteref:[idempotence-def,For a given set of inputs, an idempotent function always produces the same output.] and has a similar signature shape as that of related functions. It is resilient, meaning its interface is flexible and accepts input expressed in a few different ways, including optional parameters and overloading. Yet, it is unambiguous, there aren't multiple interpretations of how the API should be used, what it does, how to provide inputs or how to understand the output. Through all of this, it manages to stay simple: it's straightforward to use and it handles common use cases with little to no configuration, while allowing customization for advanced use cases. Lastly, a CRUST interface is also tiny: it meets its goals but it isn't overdesigned, it's comprised by the smallest possible surface area while allowing for future non-breaking extensibility. CRUST mostly regards the outer layer of a system (be it a package, a file, or a function), but its principles will seep into the innards of its components and result in simpler code overall.
 
 That's a lot to take in. Let's try and break down the CRUST principle. In this section we explore each trait, detailing what they mean and why it's important that our interfaces follow each of them.
 
@@ -404,7 +404,7 @@ await fetch('/api/users/rob', {
 })
 ----
 
-Supposing that -- if we were the API designers for `fetch` -- we originally devised `fetch` as just a way of doing `GET ${ resource }`. When we got a requirement for a way of choosing the HTTP method, we could've avoided the options object and reached directly for a `fetch(resource, method)` overload. While this would've served our particular requirement, it would've been short-sighted. As soon as we got a requirement to configure something else, we'd be left with the need of supporting both `fetch(resource, method)` and `fetch(resource, options)` overloads, so that we avoid breaking backward compatibility. Worse still, we might be tempted to introduce a third parameter that configures our next requirement. Soon, we'd end up with an API such as the infamous `KeyboardEvent#initKeyEvent` methodfootnote:[See the MDN documentation at https://mjavascript.com/out/initkeyevent.], whose signature is outlined below.
+Supposing that -- if we were the API designers for `fetch` -- we originally devised `fetch` as just a way of doing `GET ${ resource }`. When we got a requirement for a way of choosing the HTTP method, we could've avoided the options object and reached directly for a `fetch(resource, method)` overload. While this would've served our particular requirement, it would've been short-sighted. As soon as we got a requirement to configure something else, we'd be left with the need of supporting both `fetch(resource, method)` and `fetch(resource, options)` overloads, so that we avoid breaking backward compatibility. Worse still, we might be tempted to introduce a third parameter that configures our next requirement. Soon, we'd end up with an API such as the infamous `KeyboardEvent#initKeyEvent` methodfootnoteref:[mdn-initkeyevent,See the MDN documentation at https://mjavascript.com/out/initkeyevent.], whose signature is outlined below.
 
 [source,javascript]
 ----
@@ -425,7 +425,7 @@ event.initKeyEvent(type, { bubbles, cancelable, viewArg,
 A key aspect of API design is readability. How far can users get without having to reach for the documentation? In the case of `initKeyEvent`, not very, unless they memorize the position of each of 10 parameters, and their default values, chances are they're going to reach for the documentation every time. When designing an interface that might otherwise end up with four or more parameters, an `options` object carries a multitude of benefits:
 
 - The consumer can declare options in any order, as the arguments are no longer positional inside the `options` object
-- The API can offer default values for each option. This helps the consumer avoid specifying defaults just so that they can change another positional parameterfootnote:[Assuming we have a `createButton(size = 'normal', type = 'primary', color = 'red')` method and we want to change its color, we'd have to do `createButton('normal', 'primary', 'blue')` to accomplish that, only because the API didn't have an `options` object. If the API ever changes its defaults, we'd have to change any function calls accordingly as well.]
+- The API can offer default values for each option. This helps the consumer avoid specifying defaults just so that they can change another positional parameterfootnoteref:[api-readability,Assuming we have a `createButton(size = 'normal', type = 'primary', color = 'red')` method and we want to change its color, we'd have to do `createButton('normal', 'primary', 'blue')` to accomplish that, only because the API didn't have an `options` object. If the API ever changes its defaults, we'd have to change any function calls accordingly as well.]
 - The consumer doesn't need to concern herself with options they don't need
 - Developers reading pieces of code which consume the API can immediately understand what parameters are being used, since they're explicitly named in the options object
 
diff --git a/chapters/ch03.asciidoc b/chapters/ch03.asciidoc
index e948f39..9dc6d83 100644
--- a/chapters/ch03.asciidoc
+++ b/chapters/ch03.asciidoc
@@ -81,7 +81,7 @@ Taken literally, moving fast and breaking things is a dreadful way to go about s
 
 The code that makes up a product should be covered by tests, minimizing the risk of bugs making their way to production. When we take "Move Fast and Break Things" literally, we are tempted to think testing is optional, since it slows us down and we need to move fast. A product that's not test covered will be, ironically, unable to move fast when bugs inevitable arise and wind down engineering speed.
 
-A better mantra might be one that can be taken literally, such as "Move Deliberately and Experiment". This mantra carries the same sentiment as the Facebook mantra of "Move Fast and Break Things", but its true meaning isn't meant to be decoded or interpreted. Experimentation is a key aspect of software design and development. We should constantly try out and validate new ideas, verifying whether they pose better solutions than the status quo. We could interpret "Move Fast and Break Things" as "A/B testfootnote:[A/B testing is a form of user testing where we take a small portion of users and present them with a different experience than what we present to the general userbase. We then track engagement among the two groups, and if the engagement is higher for the users with the new experience, then we might go ahead and present that to our entire userbase. It is an effective way of reducing risk when we want to modify our user experience, by testing our assumptions in small experiments before we introduce changes to the majority of our users.] early and A/B test often", and "Move Deliberately and Experiment" can convey this meaning as well.
+A better mantra might be one that can be taken literally, such as "Move Deliberately and Experiment". This mantra carries the same sentiment as the Facebook mantra of "Move Fast and Break Things", but its true meaning isn't meant to be decoded or interpreted. Experimentation is a key aspect of software design and development. We should constantly try out and validate new ideas, verifying whether they pose better solutions than the status quo. We could interpret "Move Fast and Break Things" as "A/B testfootnoteref:[ab-testing,A/B testing is a form of user testing where we take a small portion of users and present them with a different experience than what we present to the general userbase. We then track engagement among the two groups, and if the engagement is higher for the users with the new experience, then we might go ahead and present that to our entire userbase. It is an effective way of reducing risk when we want to modify our user experience, by testing our assumptions in small experiments before we introduce changes to the majority of our users.] early and A/B test often", and "Move Deliberately and Experiment" can convey this meaning as well.
 
 To move deliberately is to move with cause. Engineering tempo will rarely be guided by the development team's desire to move faster, but is most often instead bound by release cycles and the complexity in requirements needed to meet those releases. Of course, everyone wants engineering to move fast where possible, but interface design shouldn't be hurried, regardless of whether the interface we're dealing with is an architecture, a layer, a component, or a function. Internals aren't as crucial to get right, for as long as the interface holds, the internals can be later improved for performance or readability gains. This is not to advocate sloppily developed internals, but rather to encourage respectfully and deliberately thought out interface design.
 
@@ -187,7 +187,7 @@ Tom Preston-Werner wrote about the notion of README-driven development as a way
 
 There's a popular phrase in the world of CSS about how it's an "append-only language" implicating that once a piece of CSS code has been added it can't be removed any longer, because doing so could inadvertently break our designs, due to the way the cascade works. JavaScript doesn't make it quite that hard to remove code, but it's indeed a highly dynamic language, and removing code with the certainty that nothing will break remains a bit of a challenge as well.
 
-Naturally, it's easier to modify a module's internal implementation than to change its public API, as the effects of doing so would be limited to the module's internals. Internal changes that don't affect the API are typically not observable from the outside. The exception to that rule would be when consumers monkey-patchfootnote:[Monkey-patching is when we intentionally modify the public interface of a component from the outside in order to add, remove, or modify its functionality. Monkey-patching can be helpful when we want to change the behavior of a component we don't control, such as a library or dependency. Patching is error-prone because we might be affecting other consumers of this API, who are unaware of our patches. The API itself or its internals may also change, breaking the assumptions made about them in our patch. While it's generally best avoided, sometimes it's the only choice at hand.] our interface, sometimes becoming able to observe some of our internals. In this case, however, the consumer should be aware of how brittle monkey-patching a module they do not control is, and they did so assuming the risk of breakage.
+Naturally, it's easier to modify a module's internal implementation than to change its public API, as the effects of doing so would be limited to the module's internals. Internal changes that don't affect the API are typically not observable from the outside. The exception to that rule would be when consumers monkey-patchfootnoteref:[monkey-patching,Monkey-patching is when we intentionally modify the public interface of a component from the outside in order to add, remove, or modify its functionality. Monkey-patching can be helpful when we want to change the behavior of a component we don't control, such as a library or dependency. Patching is error-prone because we might be affecting other consumers of this API, who are unaware of our patches. The API itself or its internals may also change, breaking the assumptions made about them in our patch. While it's generally best avoided, sometimes it's the only choice at hand.] our interface, sometimes becoming able to observe some of our internals. In this case, however, the consumer should be aware of how brittle monkey-patching a module they do not control is, and they did so assuming the risk of breakage.
 
 In section 3.1.2 we observed that the best code is no code at all, and this has implications when it comes to removing code as well. Code we never write is code we don't need to worry about deleting. The less code there is, the less code we need to maintain, the less potential bugs we are yet to uncover, and the less code we need to read, test, and deliver over mobile networks to speed-hungry humans.
 
diff --git a/chapters/ch04.asciidoc b/chapters/ch04.asciidoc
index 83c0963..39f7ce2 100644
--- a/chapters/ch04.asciidoc
+++ b/chapters/ch04.asciidoc
@@ -104,7 +104,7 @@ if (hasValidToken(auth)) {
 }
 ----
 
-We could've used more variables without creating a function, inlining the computation of `hasValidToken` right before the `if` check. A crucial difference between the function-based refactor and the inlining solution is that we used a short-circuiting `return` statement to preemptively bail when we already knew the token was invalidfootnote:[In the example, we immediately return `false` when the token isn't present.], however we can't use `return` statements to bail from the snippet of code that computes `hasValidToken` in the following piece of code without coupling its computation to knowledge about what the routine should return for failure cases. As a result, our only options are tightly coupling the inline subroutine to its containing function, or using a logical or ternary operator in the intermediate steps of the inlined computation.
+We could've used more variables without creating a function, inlining the computation of `hasValidToken` right before the `if` check. A crucial difference between the function-based refactor and the inlining solution is that we used a short-circuiting `return` statement to preemptively bail when we already knew the token was invalidfootnoteref:[return-early,In the example, we immediately return `false` when the token isn't present.], however we can't use `return` statements to bail from the snippet of code that computes `hasValidToken` in the following piece of code without coupling its computation to knowledge about what the routine should return for failure cases. As a result, our only options are tightly coupling the inline subroutine to its containing function, or using a logical or ternary operator in the intermediate steps of the inlined computation.
 
 [source,javascript]
 ----
diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index 826e59b..89a54ec 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -256,7 +256,7 @@ function delay(timeout) {
 delay(2000).then(…)
 ----
 
-A similar pattern would have to be used to consume functions taking a last argument that's an error-first callback-style function in Node.js. Starting with Node.js v8.0.0, however, there's a utility built-in that "promisifies" these callback-based functions so that they return promises.footnote:[Note also that, starting in Node.js v10.0.0, the native `fs.promises` interface can be used to access promise-based versions of the `fs` module's methods.]
+A similar pattern would have to be used to consume functions taking a last argument that's an error-first callback-style function in Node.js. Starting with Node.js v8.0.0, however, there's a utility built-in that "promisifies" these callback-based functions so that they return promises.footnoteref:[native-promises,Note also that, starting in Node.js v10.0.0, the native `fs.promises` interface can be used to access promise-based versions of the `fs` module's methods.]
 
 [source,javascript]
 ----
@@ -650,6 +650,6 @@ const rwanda = new Person('Rwanda', '123 Main St')
 
 Although we can easily serialize our `rwanda` instance with `JSON.stringify(rwanda)`, and then send it over the wire, the code on the other end has no standard way of turning this JSON back into an instance of our `Person` class, which might have a lot more functionality than merely a `greet` function. The receiving end might have no business deserializing this data back into the class instance it originated from, but in some cases there's merit to having an exact replica object back on the other end. For example, to reduce friction when passing messages between a website and a web worker, both sides should be dealing in the same data structure. In such scenarios, simple JavaScript objects are ideal.
 
-JSON -- nowfootnote:[json-grammar,Up until recently, JSON wasn't -- strictly speaking -- a proper subset of ECMA-262. A recent proposal has amended the ECMAScript specification to consider bits of JSON that were previously invalid JavaScript to be valid JavaScript. Learn more at: https://mjavascript.com/out/json-subset.] a subset of the JavaScript grammar -- was purpose-built for this use case, where we often have to serialize data, send it over the wire, and deserialize it on the other end. Plain JavaScript objects are a great way to store data in our applications, offer frictionless serialization out the box, and lead to cleaner data structures because we can keep logic decoupled from the data.
+JSON -- nowfootnoteref:[json-grammar,Up until recently, JSON wasn't -- strictly speaking -- a proper subset of ECMA-262. A recent proposal has amended the ECMAScript specification to consider bits of JSON that were previously invalid JavaScript to be valid JavaScript. Learn more at: https://mjavascript.com/out/json-subset.] a subset of the JavaScript grammar -- was purpose-built for this use case, where we often have to serialize data, send it over the wire, and deserialize it on the other end. Plain JavaScript objects are a great way to store data in our applications, offer frictionless serialization out the box, and lead to cleaner data structures because we can keep logic decoupled from the data.
 
 When the language on both the sending and receiving ends is JavaScript, we can share a module with all the functionality that we need around the data structure. This way, we don't have to worry about serialization, since we're using plain JavaScript objects and can rely on JSON for the transport layer. We don't have to concern ourselves with sharing functionality either, because we can rely on the JavaScript module system for that part.
diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 1e14df4..1bcc1b2 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -3,7 +3,7 @@
 
 Even though most of us work on projects where the source code is not publicly available, we can all benefit from following open-source best practices, many of which still apply in closed-source project development. Pretending all of our code is going to be open-source results in better configuration and secret management, better documentation, better interfaces, and more maintainable codebases overall.
 
-In this chapter we'll explore open-source principles and look at ways in which we can adapt a methodology and set of robustness principles known as "The Twelve-Factor App"footnote:[see-tfa,You can find the original 12 Factor App methodology and its documentation at: https://mjavascript.com/out/12factor.] -- generally devised for back-end development -- to modern JavaScript application development, front-end and back-end alike.
+In this chapter we'll explore open-source principles and look at ways in which we can adapt a methodology and set of robustness principles known as "The Twelve-Factor App"footnoteref:[see-tfa,You can find the original 12 Factor App methodology and its documentation at: https://mjavascript.com/out/12factor.] -- generally devised for back-end development -- to modern JavaScript application development, front-end and back-end alike.
 
 === 6.1 Secure Configuration Management
 

From 7195c84703ff862c3936716ab3f4e3342d01eabb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 22 Jun 2018 12:13:45 -0300
Subject: [PATCH 47/71] mention async loading closes #7

---
 chapters/ch01.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch01.asciidoc b/chapters/ch01.asciidoc
index ddd5d6e..c31338f 100644
--- a/chapters/ch01.asciidoc
+++ b/chapters/ch01.asciidoc
@@ -172,7 +172,7 @@ import('./mathlib').then(mathlib => {
 })
 ----
 
-In ESM, too, every file is a module with its own scope and context. One major advantage in ESM over CJS is how ESM has -- and encourages -- a way of statically importing dependencies. Static imports vastly improve the introspection capabilities of module systems, given they can be analyzed statically and lexically extracted from the abstract syntax tree (AST) of each module in the system. Static imports in ESM are constrained to the topmost level of a module, further simplifying parsing and introspection.
+In ESM, too, every file is a module with its own scope and context. One major advantage in ESM over CJS is how ESM has -- and encourages -- a way of statically importing dependencies. Static imports vastly improve the introspection capabilities of module systems, given they can be analyzed statically and lexically extracted from the abstract syntax tree (AST) of each module in the system. Static imports in ESM are constrained to the topmost level of a module, further simplifying parsing and introspection. Another advantage of ESM over CommonJS `require()` is that ESM specifies a way of doing asynchronous module loading, which implies that parts of an application's dependency graph could be loaded in response to specific events, concurrently, or lazily as needed. Although this feature is not yet implemented in most environments at the time of this writing, there is strong indicationfootnoteref:[esm-node,You can dive into the specifics through this article from a member of the Node.js team, Myles Borins: https://mjavascript.com/out/esm-node.] that Node.js would incorporate it in the future.
 
 In Node.js v8.5.0, ESM support was introduced behind an `--experimental-modules` flag -- provided that we use the `.mjs` file extension for our modules. Most evergreen browsers already support ESM without flags.
 

From c08ca46c1429d80834257ec9ea0f924699730701 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 22 Jun 2018 14:34:26 -0300
Subject: [PATCH 48/71] fix typo

---
 readme.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/readme.md b/readme.md
index db505f7..1f93376 100644
--- a/readme.md
+++ b/readme.md
@@ -6,7 +6,7 @@
 
 [<img align='right' src='http://i.imgur.com/2QRmp82.png' />][toc]
 
-Modular JavaScript is a book series with the mission of improving our collective understanding of writing robust, well-tested, modular JavaScript code. Mastering Modular JavaScript is the second book in the series, and it discusses modular JavaScript application deveolpment. Mastering Modular JavaScript includes hundreds of real-world patterns and practices, as well as detailed explanations of what works and what hasn’t when it comes to leveraging ES6 in the wild.
+Modular JavaScript is a book series with the mission of improving our collective understanding of writing robust, well-tested, modular JavaScript code. Mastering Modular JavaScript is the second book in the series, and it discusses modular JavaScript application development. Mastering Modular JavaScript includes hundreds of real-world patterns and practices, as well as detailed explanations of what works and what hasn’t when it comes to leveraging ES6 in the wild.
 
 🗞 **Start** with the [book series launch announcement][announcement] on *Pony Foo*  
 🐤 **Share** a [message on *Twitter*][tweet] or within your social circles  

From 4eac14407c6b50046771f1c00ce495fac4402003 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 22 Jun 2018 14:50:12 -0300
Subject: [PATCH 49/71] typo

---
 contributing.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/contributing.md b/contributing.md
index 8876461..678a7a4 100644
--- a/contributing.md
+++ b/contributing.md
@@ -1,6 +1,6 @@
 # Interested in Contributing?
 
-Good stuff! Your contributions to Practical ES6 and the Modular JavaScript campaign efforts will be greatly appreciated! 👏
+Good stuff! Your contributions to Mastering Modular JavaScript and the Modular JavaScript campaign efforts will be greatly appreciated! 👏
 
 You can help raise the quality bar for my books by helping me fix bugs in code, grammar, or explanations. Feel free to report an issue and let me know! This way, we can minimize the amount of errata we'll have to publish later on and improve the overall quality of the book series.
 

From 104260109f239197a4ea82bb645a6789651c46bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 22 Jun 2018 17:48:54 -0300
Subject: [PATCH 50/71] fixes

---
 chapters/ch02.asciidoc | 15 ++++++++++-----
 chapters/ch05.asciidoc | 10 +++++-----
 chapters/ch06.asciidoc | 14 +++++++-------
 3 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/chapters/ch02.asciidoc b/chapters/ch02.asciidoc
index 1469dd1..5caaf4a 100644
--- a/chapters/ch02.asciidoc
+++ b/chapters/ch02.asciidoc
@@ -87,7 +87,8 @@ The following example shows an email component that's only concerned with config
 ----
 import mailApi from 'mail-api'
 import { mailApiSecret } from './secrets'
-export default function send (options, done) {
+
+export default function send(options, done) {
   const { to, subject, html } = options
   const client = mailApi({ mailApiSecret })
   client.send({
@@ -103,7 +104,7 @@ It wouldn't be hard to create a drop-in replacement by developing a module which
 
 [source,javascript]
 ----
-export default function send (options, done) {
+export default function send(options, done) {
   const { to, subject, html } = options
   console.log(`
     Sending email.
@@ -120,12 +121,14 @@ By the same token, a templating component could be developed orthogonally, with
 [source,javascript]
 ----
 import insane from 'insane'
-function sanitize (template, ...expressions) {
+
+function sanitize(template, ...expressions) {
   return template.reduce((result, part, i) =>
     result + insane(expressions[i - 1]) + part
   )
 }
-export default function compile (model) {
+
+export default function compile(model) {
   const { title, body, tags } = model
   const html = sanitize`
     <h1>${ title }</h1>
@@ -142,7 +145,9 @@ export default function compile (model) {
 }
 ----
 
-Changing the API slightly shouldn't be an issue, as long as the API remains consistent across the components we want to make interchangeable. A different implementation could take a template identifier, in addition to the +model+ object, so that the template itself is also decoupled from the +compile+ function.
+Slightly modifying the API shouldn't be an issue, as long as it remains consistent across the components we want to make interchangeable. For instance, a different implementation could take a template identifier, in addition to the +model+ object, so that the template itself is also decoupled from the +compile+ function.
+
+When we keep the API consistent across implementationsfootnoteref:[impl-examples, For example, one implementation might merely compile an HTML email using inline templates, another might use HTML template files, another could rely on a third party service, and yet another could compile emails as plain-text instead.], using the same signature across every module, it's easy to swap out implementations depending on context such as the execution environment (development vs. staging vs. production) or any other dynamic context that we need to rely upon.
 
 As we mentioned earlier, a third module could plumb together different components which handle separate concerns, such as templating and email sending. The following example leverages the logging email provider and the static templating function to join both concerns together. Interestingly, this module doesn't break SRP either, as its only concern is to plumb other modules together.
 
diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index 89a54ec..62b11f4 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -333,11 +333,11 @@ The introduction of a `class` keyword, paired with the React framework originall
 
 Inheritance is also useful when there's an abstract interface to implement and methods to override, particularly when the objects being represented can be mapped to the real world. In practical terms and in the case of JavaScript, inheritance works great when the prototype being extended offers a good description for the parent prototype: a `Car` is a `Vehicle` but a car is not a `SteeringWheel`: the wheel is just one aspect of the car.
 
-==== 5.2.2 The Perks of Composition: Aspects and Decorators
+==== 5.2.2 The Perks of Composition: Aspects and Extensions
 
 With inheritance we can add layers of complexity to an object. These layers are meant to be ordered: we start with the least specific foundational bits of the object and build our way up to the most specific aspects of it. When we write code based on inheritance chains, complexity is spread across the different classes, but lies mostly at the foundational layers which offer a terse API while hiding this complexity away. Composition is an alternative to inheritance. Rather than building objects by vertically stacking functionality, composition relies on stringing together orthogonal aspects of functionality. In this sense, orthogonality means that the bits of functionality we compose together complements each other, but doesn't alter one another's behavior.
 
-One way to compose functionality is additive: we could write decorators, which augment existing objects with new functionality. In the following code snippet we have a `makeEmitter` function which adds flexible event handling functionality to any target object, providing them with an `.on` method, where we can add event listeners to the target object; and an `.emit` method, where the consumer can indicate a type of event and any number of parameters to be passed to event listeners.
+One way to compose functionality is additive: we could write extension functions, which augment existing objects with new functionality. In the following code snippet we have a `makeEmitter` function which adds flexible event handling functionality to any target object, providing them with an `.on` method, where we can add event listeners to the target object; and an `.emit` method, where the consumer can indicate a type of event and any number of parameters to be passed to event listeners.
 
 [source,javascript]
 ----
@@ -380,7 +380,7 @@ person.emit('move', 23, 5)
 
 This approach is versatile, helping us add event emission functionality to any object without the need for adding an `EventEmitter` class somewhere in the prototype chain of the object. This is useful in cases where you don't own the base class, when the targets aren't class-based, or when the functionality to be added isn't meant to be part of every instance of a class: there are persons who emit events and persons that are quiet and don't need this functionality.
 
-Another way of doing composition, that doesn't rely on decorators, is to rely on functional aspects instead, without mutating your target object. In the following snippet we do just that: we have an `emitters` map where we store target objects and map them to the event listeners they have, an `onEvent` function that associates event listeners to target objects, and an `emitEvent` function that fires all event listeners of a given type for a target object, passing the provided parameters. All of this is accomplished in such a way that there's no need to modify the `person` object in order to have event handling capabilities associated with the object.
+Another way of doing composition, that doesn't rely on extension functions, is to rely on functional aspects instead, without mutating your target object. In the following snippet we do just that: we have an `emitters` map where we store target objects and map them to the event listeners they have, an `onEvent` function that associates event listeners to target objects, and an `emitEvent` function that fires all event listeners of a given type for a target object, passing the provided parameters. All of this is accomplished in such a way that there's no need to modify the `person` object in order to have event handling capabilities associated with the object.
 
 [source,javascript]
 ----
@@ -431,7 +431,7 @@ emitEvent(person, 'move', 23, 5)
 
 Note how we're using both `WeakMap` and `Map` here. Using a plain `Map` would prevent garbage collection from cleaning things up when `target` is only being referenced by `Map` entries, whereas `WeakMap` allows garbage collection to take place on the objects that make up its keys. Given we usually want to attach events to objects, we can use `WeakMap` as a way to avoid creating strong references that might end up causing memory leaks. On the other hand, it's okay to use a regular `Map` for the event listeners, given those are associated to an event type string.
 
-Let's move onto deciding whether to use inheritance, decorators, or functional composition, where each pattern shines, and when to avoid them.
+Let's move onto deciding whether to use inheritance, extension functions, or functional composition, where each pattern shines, and when to avoid them.
 
 ==== 5.2.3 Choosing between Composition and Inheritance
 
@@ -441,7 +441,7 @@ Decoration and functional composition are friendlier patterns because they aren'
 
 The functional approach is a bit more cumbersome to implement than simply mutating objects or adding base classes, but it offers the most flexibility. By avoiding changes to the underlying target, we keep objects easy to serialize into JSON, unencumbered by a growing collection of methods, and thus more readily compatible across our codebase.
 
-Furthermore, using base classes makes it a bit hard to reuse the logic at varying insertion points in our prototype chains. Using decorators, likewise, makes it challenging to add similar methods that support slightly different use cases. Using a functional approach leads to less coupling in this regard, but it could also complicate the underlying implementation of the makeup for objects, making it hard to decypher how their functionality ties in together, tainting our fundamental understanding of how code flows and making debugging sessions longer than need be.
+Furthermore, using base classes makes it a bit hard to reuse the logic at varying insertion points in our prototype chains. Using extension functions, likewise, makes it challenging to add similar methods that support slightly different use cases. Using a functional approach leads to less coupling in this regard, but it could also complicate the underlying implementation of the makeup for objects, making it hard to decypher how their functionality ties in together, tainting our fundamental understanding of how code flows and making debugging sessions longer than need be.
 
 As with most things programming, your codebase benefits from a semblance of consistency. Even if you use all three patterns, -- and others -- a codebase that uses half a dozen patterns in equal amounts is harder to understand, work with, and build on, than an equivalent codebase that instead uses one pattern for the vast majority of its code while using other patterns in smaller ways when warranted. Picking the right pattern for each situation and striving for consistency might seem at odds with each other, but this is again a balancing act. The trade-off is between consistency in the grand scale of our codebase versus simplicity in the local piece of code we're working on. The question to ask is then: are we obtaining enough of a simplicity gain that it warrants the sacrifice of some consistency?
 
diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 1bcc1b2..a0324fa 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -40,11 +40,9 @@ One concrete and effective way of accomplishing this in real-world environments
 
 Furthermore, you could also accept simple modifications to environment settings through environment variables, such as when executing `PORT=3000 node app`, which is convenient during development.
 
-There's an npm package called `nconf` which we can use to handle reading and merging all of these sources of application settings with ease.
+We can use the `nconf` npm package to handle reading and merging all of these sources of application settings with ease.
 
-The following piece of code shows how you could configure `nconf` to do what we've just described.
-
-We import the `nconf` package, and declare configuration sources from highest priority to lowest priority, while `nconf` will do the merging (higher priority settings will always take precedence). We then set the actual `NODE_ENV` environment variable, because libraries rely on this property to decide whether to instrument or optimize their output.
+The following piece of code shows how you could configure `nconf` to do what we've just described: we import the `nconf` package, and declare configuration sources from highest priority to lowest priority, while `nconf` will do the merging (higher priority settings will always take precedence). We then set the actual `NODE_ENV` environment variable, because libraries rely on this property to decide whether to instrument or optimize their output.
 
 ```
 // env
@@ -143,7 +141,7 @@ A secret service also takes care of encryption, secure storage, secret rotation
 
 The reason why we sometimes feel tempted to check our dependencies into source control is so that we get the exact same versions across the dependency tree, every time, in every environment.
 
-Including dependency trees in our repositories is not practical, however, given these are typically in the hundreds of megabytes and frequently include compiled assets that are built based on the target environment and operating system, meaning that the build process itself -- the act of `npm` executing a `rebuild` step after `npm install` ends -- is environment-dependant, and thus not suitable for a presumably platform-agnostic code repository.
+Including dependency trees in our repositories is not practical, however, given these are typically in the hundreds of megabytes and frequently include compiled assets that are built based on the target environment and operating systemfootnoteref:[npm-rebuild,When we run `npm install`, npm also executes a `rebuild` step after `npm install` ends. The rebuild step recompiles native binaries, building different assets depending on the execution environment and the local machine's operating system.], meaning that the build process itself is environment-dependant, and thus not suitable for a presumably platform-agnostic code repository.
 
 During development, we want to make sure we get non-breaking upgrades to our dependencies, which can help us resolve upstream bugs, tighten our grip around security vulnerabilities, and leverage new features or improvements. For deployments however, we want reproducible builds, where installing our dependencies yields the same results every time.
 
@@ -205,6 +203,8 @@ Testing also plays a significant role when it comes to processes around an appli
 
 For these processes to be effective, they must be consistent. Intermittent test failures feel worse than not having tests for the particular part of our application we're having trouble testing, because these failures affect every single test job. When tests fail in this way, we can no longer feel confident that a passing build means everything is in order, and this translates directly into decreased morale and increased frustration across the team as well. When an intermittent test failure is identified, the best course of action is to eliminate the intermittence as soon as possible, either by fixing the source of the intermittence, or by removing the test entirely. If the test is removed, make sure to file a ticket so that a well-functioning test is added later on. Intermittence in test failures can be a symptom of bad design, and in our quest to fix these failures we might resolve architecture issues along the way.
 
+As we'll extensively discuss in the fourth book in the Modular JavaScript series, there are numerous services that can aid with the CI process. Travisfootnoteref:[travis,Check out their website at: https://mjavascript.com/out/travis.] offers a quick way to get started integration testing your applications by connecting to your project's `git` repository and running a command of your choosing, where an exit code of `0` means the CI job passes and a different exit code will mean the CI job failed. Codecovfootnoteref:[codecov,Check out their website at: https://mjavascript.com/out/codecov.] can help out on the code coverage side, ensuring most code paths in our application logic are covered by test cases. Solutions like WebPageTestfootnoteref:[wpt,Check out their website at: https://mjavascript.com/out/wpt.], PageSpeedfootnoteref:[pagespeed,Check out their website at: https://mjavascript.com/out/pagespeed.], and Lighthousefootnoteref:[lighthouse,Check out their website at: https://mjavascript.com/out/lighthouse.] can be integrated into the CI process we run on a platform like Travis to ensure that changes to our web applications don't have a negative impact on performance. Running these hooks on every commit and even in Pull Request branches can help keep bugs and regressions out of the mainline of your applications, and thus out of staging and production environments.
+
 Note how up until this point we have focused on how we build and test our assets, but not how we deploy them. These two processes, build and deployment, are closely related but they shouldn't be intertwined. A clearly isolated build process where we end up with a packaged application we can easily deploy, and a deployment process that takes care of the specifics regardless of whether you're deploying to your own local environment, or to a hosted staging or production environment, means that for the most part we won't need to worry about environments during our build processes nor at runtime.
 
 === 6.5 Statelessness
@@ -219,7 +219,7 @@ State is almost ubiquitous, and practically a synonym of applications, because a
 
 When a request results in a long running job (such as sending out an email campaign, modifying records in a persistant database, etc), it's best to hand that off into a separate service that -- again -- mostly keeps state regarding said job. Separating services into specific needs means we can keep web servers lean, stateless, and improve our flows by adding more servers, persistent queues (so that we don't drop jobs), and so on. When every task is tethered together through tight coupling and state, it could become challenging to maintain, upgrade, and scale a service over time.
 
-Derived state in the form of caches is not uncmoon in the world of web servers. In the case of a personal website with some books available for download, for instance, we might be tempted to store the PDF representation of each book in a file, so that we don't have to recompile the PDF whenever the corresponding `/book` route is visited. When the book is updated, we'd recompute the PDF file and flush it to disk again, so that this derived state remains fresh. When our web server ceases to be single-node and we start using a cluster of several nodes, however, it might not be so trivial to broadcast the news about books being updated across nodes, and thus it'd be best to leave derived state to the persistance layer. Otherwise, a web server node might receive the request to update a book, perform the update and recompute the PDF file on that node, but we'd be inadvertently invalidating the PDF files being served by other nodes, which would have stale copies of the PDF representation.
+Derived state in the form of caches is not uncmoon in the world of web servers. In the case of a personal website with some books available for download, for instance, we might be tempted to store the PDF representation of each book in a file, so that we don't have to recompile the PDF whenever the corresponding `/book` route is visited. When the book is updated, we'd recompute the PDF file and flush it to disk again, so that this derived state remains fresh. When our web server ceases to be single-node and we start using a cluster of several nodes, however, it might not be so trivial to broadcast the news about books being updated across nodes, and thus it'd be best to leave derived state to the persistance layer. Otherwise, a web server node might receive the request to update a book, perform the update and recompute the PDF file on that node, but we’d be failing to invalidate the PDF files being served by other nodes, which would have, and continue to serve stale copies of the PDF representation.
 
 A better alternative in such a case would be to store derived state in a data store like Redis or Amazon S3, either of which we could update from any web server, and then serving precomputed results from Redis directly. In this way we'd still be able to access the latency benefits of using precomputed derived state, but at the same time we'd stay resilient when these requests or updates can happen on multiple web server nodes.
 
@@ -238,7 +238,7 @@ Another improvement which could aid in complexity management is to structure app
 
 Colocation of view components with its immediate counterparts is appealing, -- that is, keeping each view's main component, child components, controllers, and logic in the same structure -- however, doing so in a way that tightly couples business logic to specific components can be detrimental to having a clear understanding of how an application works as a whole.
 
-Large client-side applications often suffer from not having a single place where logic should be deposited, and as a result the logic is instead spread amongst components, view controllers, and the API, instead of being mostly handled in the server-side, and then in a single physical location in the client-side code structure. This centralization can be key for newcomers to the team seeking to better understand how the application flows, because otherwise they'd have to go fishing around our view components and controllers in order to ascertain what's going on. A dauting proposition when first dipping our toes in the uncharted shores of a new codebase.
+Large client-side applications often suffer from not having a single place where logic should be deposited, and as a result the logic is instead spread amongst components, view controllers, and the API, instead of being mostly handled in the server-side, and then in a single physical location in the client-side code structure. This centralization can be key for newcomers to the team seeking to better understand how the application flows, because otherwise they'd have to go fishing around our view components and controllers in order to ascertain what's going on. A daunting proposition when first dipping our toes in the uncharted shores of a new codebase.
 
 The same case could be made about any other function of our code, as having clearly defined layers in an application can make it straightforward to understand how an algorithm flows from layer to layer, but we'll find the biggest rewards to reap when it comes to isolating business logic from the rest of the application code.
 

From 3621532d342c39a41fe906f8a0ffc6903a05ccb0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 22 Jun 2018 17:56:10 -0300
Subject: [PATCH 51/71] comment on redux

---
 chapters/ch06.asciidoc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index a0324fa..53dd10d 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -242,6 +242,8 @@ Large client-side applications often suffer from not having a single place where
 
 The same case could be made about any other function of our code, as having clearly defined layers in an application can make it straightforward to understand how an algorithm flows from layer to layer, but we'll find the biggest rewards to reap when it comes to isolating business logic from the rest of the application code.
 
+Using a state management solution like Redux or MobX, where we isolate all state from the rest of the application, would be another option. Regardless of our approach, the most important aspect remains that we stick to clearly isolating the view rendering aspects in our applications from its business logic aspects, as much as possible.
+
 === 6.6 Parity in Development and Production
 
 We've established the importance of having clearly defined build and deployment processes. In a similar vein, we have the different application environments like development, production, staging, feature branches, SaaS vs. on-premise environments, and so on. Environments are divergent by definition, we are going to end up with different features in different environments, whether they are debugging facilities, product features, or performance optimizations.

From 227ee951011c79bfc6c4e9b4a482440763ecfba1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 22 Jun 2018 18:10:13 -0300
Subject: [PATCH 52/71] follow old review

---
 chapters/ch02.asciidoc | 10 +++++-----
 chapters/ch03.asciidoc |  4 ++--
 chapters/ch04.asciidoc | 11 ++++++-----
 3 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/chapters/ch02.asciidoc b/chapters/ch02.asciidoc
index 5caaf4a..2afea77 100644
--- a/chapters/ch02.asciidoc
+++ b/chapters/ch02.asciidoc
@@ -173,7 +173,7 @@ A flawed API is a lot harder to repair. There may be several implementations whi
 
 Having a mindful design focus on public interfaces is paramount to developing maintainable component systems. Well designed interfaces can stand the test of time by introducing new implementations that conform to that same interface. A properly designed interface should make it simple to access the most basic or common use cases for the component, while being flexible enough to support other use cases as they arise.
 
-Often, an interface doesn't have the necesity of offering multiple implementations. We must think in terms of the component's API first, regardless. Abstracting the implementation is only a small part of the puzzle. The answer to API design lies in figuring out which properties and methods consumers will need, while keeping the interface as small as possible.
+An interface often doesn't have the necessity of supporting multiple implementations, but we must nonetheless think in terms of the public API first. Abstracting the implementation is only a small part of the puzzle. The answer to API design lies in figuring out which properties and methods consumers will need, while keeping the interface as small as possible.
 
 When we need to implement a new component, a good rule of thumb is drawing up the API calls we'd need to make against that new component. For instance, we might want a component to interact with the Elasticsearch REST API. Elasticsearch is a database engine with advanced search and analytics capabilities, where documents are stored in indices and arranged by type.
 
@@ -387,7 +387,7 @@ Though it's not uncommon for JavaScript libraries to offer a getter and a setter
 
 While we might consider selectors and element creation to play the role of getters and setters, the `$(callback)` overload feels out of place. We need to take a step back and realize that jQuery is a decade-old library which revolutionized front-end development due -- in no small part -- to its ease of use. Back in the day, the requirement to wait for DOM ready was in heavy demand and so it made sense to promote it to the dollar function. Needless to say, jQuery is quite a unique case, but it's nevertheless an excellent example of how providing multiple overloads can result in a dead simple interface, even when there's more overloads than the user can keep in the back of their heads. Most methods in jQuery offer several ways for consumers to present inputs without altering the responsibilities of those methods.
 
-A new library with a shape similar to jQuery would be a rare find. Modern JavaScript libraries and applications favor a more modular approach, and so the DOM ready callback would be its own function, and probably its own package. There's still insight to be had by analyzing jQuery, though. This library had great user experience due to its consistency. One of the choices in jQuery was not to throw errors, which were reserved for bugs, user errors in our own code, or invalid selectors, in order to avoid frustrated users. Whenever jQuery finds an inappropriate input parameter, it prefers to return an empty list of matches instead. Silent failures can however be tricky: they might leave the consumer without any cues as to what the problem is, wondering whether it's an issue in their code, a bug in the library they're using, or something else.
+A new library with a shape similar to jQuery would be a rare find. Modern JavaScript libraries and applications favor a more modular approach, and so the DOM ready callback would be its own function, and probably its own package. There's still insight to be had by analyzing jQuery, though. This library had great user experience due to its consistency. One of the choices in jQuery was not to throw errors which resulted from bugs, user errors in our own code, or invalid selectors, in order to avoid frustrated users. Whenever jQuery finds an inappropriate input parameter, it prefers to return an empty list of matches instead. Silent failures can however be tricky: they might leave the consumer without any cues as to what the problem is, wondering whether it's an issue in their code, a bug in the library they're using, or something else.
 
 Even when a library is as flexible as jQuery is, it's important to identify invalid input early. As an example, the next snippet shows how jQuery throws an error on selectors it can't parse.
 
@@ -399,7 +399,7 @@ $('{div}')
 
 Besides overloading, jQuery also comes with a wealth of optional parameters. While overloads are meant as different ways of accepting one particular input, optional parameters serve a different purpose, one of augmenting a function to support more use cases.
 
-A good example of optional parameters is the native DOM `fetch` API. In the next snippet we have two `fetch` calls. The first one only receives a string for the HTTP resource we want to fetch, and a `GET` method is assumed. In the second example we've specified the second parameter, and indicated that we want to use the `DELETE` HTTP method.
+A good example of optional parameters is the native DOM `fetch` API. In the next snippet we have two `fetch` calls. The first one only receives a string for the HTTP resource we want to fetch, and a `GET` method is assumed. In the second example we've specified the second parameter, and indicated that we want to use the `DELETE` HTTP verb.
 
 [source,javascript]
 ----
@@ -409,7 +409,7 @@ await fetch('/api/users/rob', {
 })
 ----
 
-Supposing that -- if we were the API designers for `fetch` -- we originally devised `fetch` as just a way of doing `GET ${ resource }`. When we got a requirement for a way of choosing the HTTP method, we could've avoided the options object and reached directly for a `fetch(resource, method)` overload. While this would've served our particular requirement, it would've been short-sighted. As soon as we got a requirement to configure something else, we'd be left with the need of supporting both `fetch(resource, method)` and `fetch(resource, options)` overloads, so that we avoid breaking backward compatibility. Worse still, we might be tempted to introduce a third parameter that configures our next requirement. Soon, we'd end up with an API such as the infamous `KeyboardEvent#initKeyEvent` methodfootnoteref:[mdn-initkeyevent,See the MDN documentation at https://mjavascript.com/out/initkeyevent.], whose signature is outlined below.
+Supposing that -- if we were the API designers for `fetch` -- we originally devised `fetch` as just a way of doing `GET ${ resource }`. When we got a requirement for a way of choosing the HTTP verb, we could've avoided the options object and reached directly for a `fetch(resource, verb)` overload. While this would've served our particular requirement, it would've been short-sighted. As soon as we got a requirement to configure something else, we'd be left with the need of supporting both `fetch(resource, verb)` and `fetch(resource, options)` overloads, so that we avoid breaking backward compatibility. Worse still, we might be tempted to introduce a third parameter that configures our next requirement. Soon, we'd end up with an API such as the infamous `KeyboardEvent#initKeyEvent` methodfootnoteref:[mdn-initkeyevent,See the MDN documentation at https://mjavascript.com/out/initkeyevent.], whose signature is outlined below.
 
 [source,javascript]
 ----
@@ -482,7 +482,7 @@ The `fetch` function can't do much without a specified resource, which is why th
 
 In another example, we could implement a Markdown compiler function with a default option that supports autolinking resource locators, which can be disabled by the consumer with an `autolinking: false` option. In this case, the implicit default would be `autolinking: true`. Negated option names such as `avoidAutolinking` are sometimes justified because they make it so that the default value is `false`, which on the surface sounds correct for options that aren't user-provided. Negated options however tend to confuse users who are confronted with the double negative in `avoidAutolinking: false`. It's best to use additive or positive options, preventing the double negative: `autolinking: true`.
 
-Going back to `fetch`, note how little configuration or implementation-specific knowledge we need for the simplest case. This hardly changes when we need to choose the HTTP method, since we just need to add an option. Well designed interfaces have a habit of making it appear effortless for consumers to use the API for its simplest use case, and have them spend a little more effort for slightly more complicated use cases. As the use case becomes more complicated, so does the way in which the interface needs to be bent. This is because we're taking the interface to the limit, but it goes to show how much work can be put into keeping an interface simple by optimizing for common use cases.
+Going back to `fetch`, note how little configuration or implementation-specific knowledge we need for the simplest case. This hardly changes when we need to choose the HTTP verb, since we just need to add an option. Well designed interfaces have a habit of making it appear effortless for consumers to use the API for its simplest use case, and have them spend a little more effort for slightly more complicated use cases. As the use case becomes more complicated, so does the way in which the interface needs to be bent. This is because we're taking the interface to the limit, but it goes to show how much work can be put into keeping an interface simple by optimizing for common use cases.
 
 ==== 2.2.5 Tiny surface areas
 
diff --git a/chapters/ch03.asciidoc b/chapters/ch03.asciidoc
index 9dc6d83..c7fde21 100644
--- a/chapters/ch03.asciidoc
+++ b/chapters/ch03.asciidoc
@@ -1,7 +1,7 @@
 [[module-design]]
 == Module Design
 
-Thinking in terms of API-driven and documentation-driven design will yield more usable modules than not doing so. You might argue that internals are not that important: "as long as the interface holds, we can put anything we want in the mix!". A usable interface is only one side of the equation, but it will do little to keep the maintainability of your applications in check. Properly designed module internals help keep our code readable and its intent clear. In this chapter we'll debate what it takes to write modules with scalability in mind, but without getting too far ahead of our current requirements. We'll discuss the CRUST constraints in some more depth, and finally ellaborate on how to prune modules as they become larger and more complex over time.
+Thinking in terms of API-driven and documentation-driven design will yield more usable modules than not doing so. You might argue that internals are not that important: "as long as the interface holds, we can put anything we want in the mix!". A usable interface is only one side of the equation; it will do little to keep the maintainability of your applications in check. Properly designed module internals help keep our code readable and its intent clear. In this chapter we'll debate what it takes to write modules with scalability in mind, but without getting too far ahead of our current requirements. We'll discuss the CRUST constraints in some more depth, and finally ellaborate on how to prune modules as they become larger and more complex over time.
 
 === 3.1 Growing a Module
 
@@ -41,7 +41,7 @@ Abstractions aren't free, but they can shield portions of code from complexity.
 
 When we're weighing whether to offer an interface like CSS selectors or callbacks, we're deciding how much we want to abstract, and how much we want to leave up to the consumer. When we choose to let the user provide CSS selectors, we keep the interface short, but the use cases will be limited as well. Consumers won't be able, for example, to decide dynamically whether the element is draggable or not beyond what a CSS selector can offer. When we choose to let the user provide callbacks, we make it harder for them to use our interface, since they now have to provide bits and pieces of the implementation themselves, but that expense buys them great flexibility in how to decide what is draggable and what is not.
 
-As most things in program design, API design is a constant tradeoff between simplicity and flexibility. For each particular case, it is our responsibility to decide how flexible we want the interface to be, but at the expense of simplicity. We can also decide how simple we want an interface to be, but at the expense of simplicity. Going back to jQuery, it's interesting to note how they always favor simplicity, by allowing you to provide as little information as needed for most of their API methods. Meanwhile, they avoid sacrificing flexibility by offering countless overloads for each of their API methods. The complexity lies in their implementation, balancing arguments by figuring out whether they're a `NodeList`, a DOM element, an array, a function, a selector, or something else, -- not to mention optional parameters -- before even starting to fulfill the consumer's goal when making an API call. Consumers observe some of the complexity at the seams, when sifting through documentation and finding out about all the different ways of accomplishing the same goals. And yet, despite all of jQuery's internal complexity, code which consumes the jQuery API manages to stay ravashingly simple.
+As most things in program design, API design is a constant tradeoff between simplicity and flexibility. For each particular case, it is our responsibility to decide how flexible we want the interface to be, but at the expense of simplicity. We can also decide how simple we want an interface to be, but at the expense of flexibility. Going back to jQuery, it's interesting to note how they always favor simplicity, by allowing you to provide as little information as needed for most of their API methods. Meanwhile, they avoid sacrificing flexibility by offering countless overloads for each of their API methods. The complexity lies in their implementation, balancing arguments by figuring out whether they're a `NodeList`, a DOM element, an array, a function, a selector, or something else, -- not to mention optional parameters -- before even starting to fulfill the consumer's goal when making an API call. Consumers observe some of the complexity at the seams, when sifting through documentation and finding out about all the different ways of accomplishing the same goals. And yet, despite all of jQuery's internal complexity, code which consumes the jQuery API manages to stay ravashingly simple.
 
 ==== 3.1.2 Design for Today
 
diff --git a/chapters/ch04.asciidoc b/chapters/ch04.asciidoc
index 39f7ce2..f503a33 100644
--- a/chapters/ch04.asciidoc
+++ b/chapters/ch04.asciidoc
@@ -369,7 +369,7 @@ async.series([
 ], err => console.log(err ? 'failed!' : 'done!'))
 ----
 
-Libraries like `async` come with several ways of mixing and matching asynchronous code flows, be them in series of concurrent, allowing us to pass variables between callbacks without having to nest together entire asynchronous flows.
+Libraries like `async` come with several ways of mixing and matching asynchronous code flows, in series or concurrent, allowing us to pass variables between callbacks without having to nest together entire asynchronous flows.
 
 Naturally, callbacks aren't the only asynchronous flow pattern that might end up in hell. Promises can end up in this state just as easily, as shown in the next contrived snippet.
 
@@ -490,7 +490,7 @@ Once we know the inputs are well-formed, data processing can begin. We'll transf
 
 Each aspect of a transformation operation can be analyzed and moved into its own function. The smaller function may take a few of the inputs in the larger function, or perhaps some of the intermediate values that were produced in the larger function. It can then conduct its own input sanitization, and be broken apart even further. The process of identifying aspects of an operation that can be recursively compartimentalized and moved into their own functions is highly effective because it allows for dauntingly large functions to be broken into simpler pieces that aren't as daunting to refactor.
 
-At first, we can identify the largest aspects of a function, which might be 3 or 4, and break those apart. The first part might involve filtering out the parts of the input we're not interested in, the second might involve mapping that into something else, and the third part might involve merging all of the data together. Once we've identified each aspect of the function we might break those into their own functions, with their own inputs and output. Subsequently, we can do this for each of those smaller functions.
+At first, we can identify the 3 or 4 largest aspects of a function, and break those apart. The first part might involve filtering out the parts of the input we're not interested in, the second might involve mapping that into something else, and the third part might involve merging all of the data together. Once we've identified each aspect of the function we might break those into their own functions, with their own inputs and output. Subsequently, we can do this for each of those smaller functions.
 
 We can keep doing this for as long as there's opportunity for the functions to be simplified. As discussed in the previous section, it's valuable to take a step back after each of these refactors, and evaluate whether the end result is indeed simpler and easier to work with than what we had before it was refactored.
 
@@ -512,8 +512,9 @@ In the world of web development, a human decides to open a new tab in their favo
 
 Naturally, Google receives this request at one of the front-end edges of its public network, in charge of balancing the load and routing requests to healthy back-end services. The query goes through a variety of analyzers that attempt to break it down to its semantic roots, stripping the query down to its essential keywords in an attempt to better match relevant results.
 
-The search engine figures out the 10 most relevant results for “cat pickle gif” out of billions of pages in its index – which was of course primed by a different system that’s also part of the whole – and at the same time, Google pulls down a highly targeted piece of relevant advertisement about cat gifs that matches what they believe is the demographic the human making the query belongs to, thanks to a sophisticated ad network, figures out whether the user is authenticated with Google through an HTTP header session cookie and the search results page starts being constructed and streamed to the human, who now appears impatient and fidgety.
-As the first few bits of HTML being streaming down the wire, the search engine produces its results and hands them back to the front-end servers, which includes it in the HTML stream that’s sent back to the human. The web browser has been working hard at this too, parsing the incomplete pieces of HTML that have been streaming down the wire as best it could, even daring to launch other admirably and equally-mind-boggling requests for HTTP resources presumed to be JavaScript, CSS, font, and image files as the HTML continues to stream down the wire. The first few chunks of HTML are converted into a DOM tree, and the browser would finally be able to begin rendering bits and pieces of the page on the screen, if it weren’t because it’s still waiting on those equally-mind-boggling CSS and font requests.
+The search engine figures out the 10 most relevant results for “cat pickle gif” out of billions of pages in its index – which was of course primed by a different system that’s also part of the whole – and at the same time, Google pulls down a highly targeted piece of relevant advertisement about cat gifs that matches what they believe is the demographic the human making the query belongs to, thanks to a sophisticated ad network that figures out whether the user is authenticated with Google through an HTTP header session cookie and the search results page starts being constructed and streamed to the human, who now appears impatient and fidgety.
+
+As the first few bits of HTML being streaming down the wire, the search engine produces its results and hands them back to the front-end servers, which includes it in the HTML stream that’s sent back to the human. The web browser has been working hard at this too, parsing the incomplete pieces of HTML that have been streaming down the wire as best it could, even daring to launch other admirably and equally-mind-boggling requests for HTTP resources presumed to be JavaScript, CSS, font, and image files as the HTML continues to stream down the wire. The first few chunks of HTML are converted into a DOM tree, and the browser would finally be able to begin rendering bits and pieces of the page on the screen, weren't it for the pending, equally-mind-boggling CSS and font requests.
 
 As the CSS stylesheets and fonts are transmitted, the browser begins modeling the CSSOM and getting a more complete picture of how to turn the HTML and CSS plain text chunks provided by Google servers into a graphical representation that the human finds pleasant. Browser extensions get a chance to meddle with the content, removing the highly targeted piece of relevant advertisement about cat gifs before I even realize Google hoped I wouldn’t block ads this time around.
 
@@ -527,7 +528,7 @@ We've established that the overall state of a system has little to do with our a
 
 Whenever there's persistance involved, there's going to be a discrepancy between ephemeral state and realized state. In the case of a web application, we could define ephemeral state as any user input that hasn't resulted in state being persisted yet, as might be the case of an unsaved user preference that might be lost unless persisted. We can say realized state is the state that has been persisted, and that different programs might have different strategies on how to convert ephemeral state into realized state. A web application might adopt an Offline-First pattern where ephemeral state is automatically synchronized to an IndexedDB database in the browser, and eventually realized by updating the state persisted on a back-end system. When the Offline-First page is reloaded, unrealized state may be pushed to the back-end or discarded.
 
-Incidental state can occur when we have a piece of data that's used in several parts of an application, and which is derived from other pieces of data. When the original piece of data is updated, it wouldn't be hard to inadvertently leave the derived pieces of data in their current state, making them stale in comparison with the updated original pieces of data. As an example, consider a piece of user input in Markdown and the HTML representation derived from that piece of Markdown. If the piece of Markdown is updated but the previously compiled pieces of HTML are not, then different parts of the system might display different bits of HTML out of what was apparently the same single Markdown source.
+Incidental state can occur when we have a piece of data that's used in several parts of an application, and which is derived from other pieces of data. When the original piece of data is updated, it wouldn't be hard to inadvertently leave the derived pieces of data in their current state, making them stale when compared to the updated original pieces of data. As an example, consider a piece of user input in Markdown and the HTML representation derived from that piece of Markdown. If the piece of Markdown is updated but the previously compiled pieces of HTML are not, then different parts of the system might display different bits of HTML out of what was apparently the same single Markdown source.
 
 When we persist derived state, we're putting the original and the derived data at risk of falling out of sync. This isn't the case just when dealing with persistance layers, but can also occur in a few other scenarios as well. When dealing with caching layers, their content may become stale because the underlying original piece of content is updated but we forget to invalidate pieces of content derived from the updated data. Database denormalization is another common occurrence of this problem, whereby creating derived state can result in synchronization problems and stale byproducts of the original data.
 

From 9053a7f9476a5b408d170fe2bae210ce9b2202c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Wed, 27 Jun 2018 17:53:49 -0300
Subject: [PATCH 53/71] Follow @rreverser's year-old review

---
 chapters/ch01.asciidoc | 37 +++++++++++++++++++++++++++++++------
 chapters/ch03.asciidoc |  4 ++--
 chapters/ch04.asciidoc |  2 ++
 3 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/chapters/ch01.asciidoc b/chapters/ch01.asciidoc
index c31338f..cd5f067 100644
--- a/chapters/ch01.asciidoc
+++ b/chapters/ch01.asciidoc
@@ -35,7 +35,32 @@ When it comes to JavaScript, modularity is a modern concept. In this section we'
 
 In the early days, JavaScript was inlined in HTML `<script>` tags. At best, it was offloaded to dedicated script files, all of which shared a global scope.
 
-Any variables declared in one of these files or inline scripts would be imprinted on the global `window` object, creating leaks across entirely unrelated scripts that might've lead to conflicts or even broken experiences, where a variable in one script might inadvertently replace a global that another script was relying on.
+Any variables or bindings declared in one of these files or inline scripts would be imprinted on the global `window` object, creating leaks across entirely unrelated scripts that might've lead to conflicts or even broken experiences, where a variable in one script might inadvertently replace a global that another script was relying on.
+
+[source,html]
+----
+<script>
+  var initialized = false
+
+  if (!initialized) {
+    init()
+  }
+
+  function init() {
+    initialized = true
+    console.log('init')
+  }
+</script>
+
+<script>
+  if (initialized) {
+    console.log('was initialized!')
+  }
+
+  // even `init` has been implicitly made a global variable
+  console.log('init' in window)
+</script>
+----
 
 Eventually, as web applications started growing in size and complexity, the concept of scoping and the dangers of a global scope became evident and more well-known. Immediately-invoking function expressions (IIFE) were invented and became an instant mainstay. An IIFE worked by wrapping an entire file or portions of a file in a function that executed immediately after evaluation. Each function in JavaScript creates a new level of scoping, meaning `var` variable bindings would be contained by the IIFE. Even though variable declarations are hoisted to the top of their containing scope, they'd never become implicit globals, thanks to the IIFE wrapper, thus suppressing the brittleness of implicit JavaScript globals.
 
@@ -56,7 +81,7 @@ void function() {
 }()
 ----
 
-Using the IIFE pattern, libraries would typically create modules by exposing and then reusing a single binding on the `window` object, thus avoiding global namespace pollution. The next snippet shows how we might create a `mathlib` component with a `sum` method in one of these IIFE-based libraries. If we wanted to add more modules to `mathlib`, we could place each of them in a separate IIFE which adds its own methods to the `mathlib` public interface, while anything else could stay private to the component that defined the new portion of functionality.
+Using the IIFE pattern, libraries would typically create modules by exposing and then reusing a single binding on the `window` object, thus minimizing global namespace pollution. The next snippet shows how we might create a `mathlib` component with a `sum` method in one of these IIFE-based libraries. If we wanted to add more modules to `mathlib`, we could place each of them in a separate IIFE which adds its own methods to the `mathlib` public interface, while anything else could stay private to the component that defined the new portion of functionality.
 
 [source,javascript]
 ----
@@ -73,7 +98,7 @@ mathlib.sum(1, 2, 3)
 // <- 6
 ----
 
-This pattern was, coincidentally, an open invitation for JavaScript tooling to burgeon, allowing developers to -- for the first time -- safely concatenate every IIFE module into a single file, reducing the strain on the network.
+This pattern was, coincidentally, an open invitation for JavaScript tooling to burgeon, allowing developers to -- for the first time -- concatenate every IIFE module into a single file, reducing the strain on the network. Provided the primitive bundling solutions that existed at the time were able to figure out their way around automatic semicolon insertion and minified content without breaking your application logic.
 
 The problem in the IIFE approach was that there wasn't an explicit dependency tree. This means developers had to manufacture component file lists in a precise order, so that dependencies would load before any modules that depended on them did -- recursively.
 
@@ -160,7 +185,7 @@ Granted, npm wasn't limited to CommonJS modules or even JavaScript packages, but
 
 ==== 1.2.4 ES6, `import`, Babel, and Webpack
 
-As ES6 became standardized in June of 2015, and with Babel transpiling ES6 into ES5 long before then, a new revolution was quickly approaching. The ES6 specification included a module system native to JavaScript, often referred to as ECMAScript Modules (ESM).
+As ES6 became standardized in June of 2015, and with Babel transpiling ES6 into ES5 long before then, a new revolution was quickly approaching. The ES6 specification included a module syntax native to JavaScript, often referred to as ECMAScript Modules (ESM).
 
 ESM is largely influenced by CJS and its predecessors, offering a static declarative API as well as a promise-based dynamic programmable API, as illustrated next.
 
@@ -176,7 +201,7 @@ In ESM, too, every file is a module with its own scope and context. One major ad
 
 In Node.js v8.5.0, ESM support was introduced behind an `--experimental-modules` flag -- provided that we use the `.mjs` file extension for our modules. Most evergreen browsers already support ESM without flags.
 
-Webpack is a successor to Browserify that largely took over in the role of universal module bundler thanks to a broader set of features. Just like in the case of Babel and ES6, Webpack has long supported ESM with both its static `import` and `export` statements as well as the dynamic `import()` function-like expression. It has made a particularly fruitful adoption of ESM, in no little parts thanks to the introduction of a "code-splitting" mechanism whereby it's able to partition an application into different bundles to improve performance on first load experiences.
+Webpack is a successor to Browserify that largely took over in the role of universal module bundler thanks to a broader set of features. Just like in the case of Babel and ES6, Webpack has long supported ESM with both its static `import` and `export` statements as well as the dynamic `import()` function-like expression. It has made a particularly fruitful adoption of ESM, in no little part thanks to the introduction of a "code-splitting" mechanismfootnote:[Code-splitting lets you to split your application into several bundles based on different entry points, and also lets you extract dependencies shared across bundles into a single reusable bundle. Learn more at: https://mjavascript.com/out/code-splitting.] whereby it's able to partition an application into different bundles to improve performance on first load experiences.
 
 Given how ESM is native to the language, -- as opposed to CJS -- it can be expected to completely overtake the module ecosystem in a few years time.
 
@@ -226,7 +251,7 @@ The native JavaScript modules specification that eventually landed into the lang
 
 Up until the launch of a Gmail beta client in April, 2004, which demonstrated the power of asynchronous JavaScript HTTP requests to provide a single-page application experience, and then the initial release of jQuery in 2006, which provided a hassle-free cross-browser web development experience, JavaScript was seldom regarded as a serious modern development platform.
 
-With the advent of frameworks like Backbone, Angular, Ember, and React, new techniques and breakthroughs also made an uptick on the web. Writing code under ES6 and beyond, but then transpiling parts of that code down to ES5 to attain broader browser support; shared rendering, using the same code on both server and client to render a page quickly on initial page load and continue to load pages quickly upon navigation; automated code bundling, packing the modules that comprise an application into a single bundle for optimized delivery; bundle-splitting along routes, so that there are several bundles outputted, each optimized for the initially visited route; CSS bundling at the JavaScript module level, so that CSS -- which doesn't feature a native module system -- can also be split across bundles; and a myriad ways of optimizing assets like images at compile time, improving productivity during development while keeping production deployments highly performant, are all part of the iterative nature of innovation in the web.
+With the advent of frameworks like Backbone, Angular, Ember, and React, new techniques and breakthroughs also made an uptick on the web. Writing code under ES6 and beyond, but then transpiling parts of that code down to ES5 to attain broader browser support; shared rendering, using the same code on both server and client to render a page quickly on initial page load and continue to load pages quickly upon navigation; automated code bundling, packing the modules that comprise an application into a single bundle for optimized delivery; bundle-splitting along routes, so that there are several bundles outputted, each optimized for the initially visited route; CSS bundling at the JavaScript module level, so that CSS -- which doesn't feature a native module syntax -- can also be split across bundles; and a myriad ways of optimizing assets like images at compile time, improving productivity during development while keeping production deployments highly performant, are all part of the iterative nature of innovation in the web.
 
 This explosion of innovation doesn't stem from sheer creativity alone but also out of necessity: web applications are getting increasingly complex, as is their scope, purpose, and requirements. It follows logically, then, that the ecosystem around them would grow to accommodate those expanded requirements, in terms of better tooling, better libraries, better coding practices, architectures, standards, patterns, and more choice in general.
 
diff --git a/chapters/ch03.asciidoc b/chapters/ch03.asciidoc
index c7fde21..961169d 100644
--- a/chapters/ch03.asciidoc
+++ b/chapters/ch03.asciidoc
@@ -65,7 +65,7 @@ It's important to note that abstractions should evolve naturally, rather than ha
 
 In a similar fashion to that of the last section, we should first wait until use cases emerge and then reconsider an abstraction when its benefits become clear. While developing unneeded functionality is little more than a waste of time, leveraging the wrong abstractions will kill or, at best, cripple our component's interface. While good abstractions are a powerful tool that can reduce the complexity and volume of code we write, subjecting consumers to inappropriate abstractions might increase the amount of code they need to write and will forcibly increase complexity by having users bend to the will of the abstraction, causing frustration and eventual abandonment of the poorly abstracted component.
 
-HTTP libraries are a great example of how the right abstraction for an interface depends entirely on the use cases its consumer has in mind. Plain `GET` calls can be serviced with callbacks or promises, but streaming requires an event-driven interface which allows the consumer to act as soon as the stream has portions of data ready for consumption. A typical `GET` request could be serviced by an event-driven interface as well, allowing the implementer to abstract every use case under an event-driven model. To the consumer, this model would feel a bit convoluted for the simplest case, however. Even when we've grouped every use case under a convenient abstraction, the consumer shouldn't have to settle for `get('/cats').on('data', gotCats)` when they could be using a simpler `get('/cats', gotCats)` interface instead, which wouldn't need to handle error events separately, either, instead relying on the Node.js convention where the first argument passed to callbacks is an error or `null` when everything goes smoothly.
+HTTP libraries are a great example of how the right abstraction for an interface depends entirely on the use cases its consumer has in mind. Plain `GET` calls can be serviced with callbacks or promises, but streaming requires an event-driven interface which allows the consumer to act as soon as the stream has portions of data ready for consumption. A typical `GET` request could be serviced by an event-driven interface as well, allowing the implementer to abstract every use case under an event-driven model. To the consumer, this model would feel a bit convoluted for the simplest case, however. Even when we've grouped every use case under a convenient abstraction, the consumer shouldn't have to settle for `get('/cats').on('data', gotCats)` when their use case doesn't involve streaming and they could be using a simpler `get('/cats', gotCats)` interface instead, which wouldn't need to handle error events separately, either, instead relying on the Node.js convention where the first argument passed to callbacks is an error or `null` when everything goes smoothly.
 
 An HTTP library that's primarily focused on streaming might go for the event-driven model in all cases, arguing that convenience methods such as a callback-based interface could be implemented on top of their primitive interface. This is acceptable, we're focusing on the use case at hand and keeping our API surface as small as possible, while still allowing our library to be wrapped for higher-level consumption. If our library was primarily focused on the experience of leveraging its interface, we might go for the callback or promise based approach. When that library then has to support streaming, it might incorporate an event-driven interface. At this point we'd have to decide whether we'll expose that kind of interface solely for streaming purposes, or if it'll be available for commonplace scenarios as well. On the one hand, exposing it solely for the streaming use case keeps the API surface small. On the other, exposing it for every use case results in a more flexible and consistent API, which might be what consumers expect.
 
@@ -155,7 +155,7 @@ We can't prevent this from happening over and over -- not entirely. Unexpected b
 
 What we can do is mitigate the risk of bugs by writing more predictable code or improving test coverage. We can also become more proficient at debugging.
 
-On the predictable code arena, we must be sure to handle every expected error. When it comes to error handling we typically will bubble the error up the stack and handle it at the top, by logging it to an analytics tracker, to standard output, or to a database. When using a function call we know might throw, like `JSON.parse` on user input, we should wrap it with `try`/`catch` and handle the error. If we're dealing with conventional callbacks that have an error argument, let's handle the error in a guard clause. Whenever we have a promise chain, make sure to add a `.catch` reaction to the end of the chain that handles any errors ocurring in the chain. In the case of `async` functions, we could use `try`/`catch` or, alternatively, we can also add a `.catch` reaction to the result of invoking the async function. While leveraging streams or other conventional event-based interfaces, make sure to bind an `error` event handler. Proper error handling should all but eliminate the chance of expected errors crippling our software. Simple code is predictable. Thus, following the suggestions in chapter 4 will aid us in reducing the odds of encountering unexpected errors as well.
+On the predictable code arena, we must be sure to handle every expected error. When it comes to error handling we typically will bubble the error up the stack and handle it at the top, by logging it to an analytics tracker, to standard output, or to a database. When using a function call we know might throw, like `JSON.parse` on user input, we should wrap it with `try`/`catch` and handle the error, again bubbling it up to the consumer if our inability to proceed with the function logic is final. If we're dealing with conventional callbacks that have an error argument, let's handle the error in a guard clause. Whenever we have a promise chain, make sure to add a `.catch` reaction to the end of the chain that handles any errors ocurring in the chain. In the case of `async` functions, we could use `try`/`catch` or, alternatively, we can also add a `.catch` reaction to the result of invoking the async function. While leveraging streams or other conventional event-based interfaces, make sure to bind an `error` event handler. Proper error handling should all but eliminate the chance of expected errors crippling our software. Simple code is predictable. Thus, following the suggestions in chapter 4 will aid us in reducing the odds of encountering unexpected errors as well.
 
 Test coverage can help detect unexpected errors. If we have simple and predictable code, it's harder for unexpected errors to seep through the seams. Tests can further abridge the gap by enlarging the corpus of expected errors. When we add tests, preventable errors are codified by test cases and fixtures. When tests are comprehensive enough, we might run into unexpected errors in testing and fix them. Since we've already codified them in a test case, these errors can't happen again (a test regression) without our test suite failing.
 
diff --git a/chapters/ch04.asciidoc b/chapters/ch04.asciidoc
index f503a33..5c439b9 100644
--- a/chapters/ch04.asciidoc
+++ b/chapters/ch04.asciidoc
@@ -299,6 +299,8 @@ function getUserWebsite(user) {
 }
 ----
 
+Regardless of your flavor of choice when it comes to variable binding, bits of code that select some slice of application state are best shoved away from the relevant logic that will use this selected state to perform some action. This way, we're not distracted with concerns about how state is selected, instead of being focused on the action that our application logic is trying to carry out.
+
 When we want to name an aspect of a routine without adding a comment, we could create a function to host that functionality. Doing so doesn't just give a name to what the algorithm is doing, but it also allows us to push that code out of the way, leaving behind only the high-level description of what's going to happen.
 
 ==== 4.2.5 Flattening Nested Callbacks

From 3ddae75a6e9443f02ff74eee8c51ee94de41f644 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 29 Jun 2018 17:39:49 -0300
Subject: [PATCH 54/71] round off preface

---
 atlas.json                |   1 +
 chapters/ch01.asciidoc    |   2 +-
 sections/preface.asciidoc | 198 ++++++++++++++++++++------------------
 3 files changed, 104 insertions(+), 97 deletions(-)

diff --git a/atlas.json b/atlas.json
index 1990f22..da203fd 100644
--- a/atlas.json
+++ b/atlas.json
@@ -5,6 +5,7 @@
     "sections/titlepage.html",
     "sections/copyright.html",
     "sections/toc.html",
+    "sections/preface.asciidoc",
     "chapters/ch01.asciidoc",
     "chapters/ch02.asciidoc",
     "chapters/ch03.asciidoc",
diff --git a/chapters/ch01.asciidoc b/chapters/ch01.asciidoc
index cd5f067..3408031 100644
--- a/chapters/ch01.asciidoc
+++ b/chapters/ch01.asciidoc
@@ -1,7 +1,7 @@
 [[module-thinking]]
 == Module Thinking
 
-Even after the printing press was invented, publishing books remains a challenging endeavor. Yes, there's typically an author -- or authors -- who scribbled the content wherever and whenever they found time to do so. But there's also a content editor, tasked with helping the author transform their stream of consciousness into a relatable story that's not too dry to read, something to be especially careful about when it comes to technical or business books. We have the technical reviewers, watchful subject matter experts on the lookout for egregious mistakes in technical definitions or interpretations. And lastly, -- of course -- we have the content editor, the typo linters of prose and last bastion of proper grammar. Thus far, however, we've barely scratched the surface: everyone mentioned above is mostly interested in the contents of the book, but we don't do much else. There's also, as an example, the typesetters whose job is to ensure the book looks good when it goes to print -- bidding good riddance to orphans and widows, poorly-wrapped lines of code, and so much more. Someone has to design the cover, or to approve the table of contents for the first draft so that the author gets a contract. Several people oversee the process that culminates in the book going to press, -- usually referred to as production -- as well. Once copies are printed, they need to be distributed. Eventually, the book hits the shelves (physical or otherwise) and starts selling. Someone buys the book, and finally starts to read it. We could write entire books about the purchase transaction alone.
+Even after the printing press was invented, publishing books remains a challenging endeavor. Yes, there's typically an author -- or authors -- who scribbled the content wherever and whenever they found time to do so. But there's also a content editor, tasked with helping the author transform their stream of consciousness into a relatable story that's not too dry to read, something to be especially careful about when it comes to technical or business books. We have the technical reviewers, watchful subject matter experts on the lookout for egregious mistakes in technical definitions or interpretations. And lastly, -- of course -- we have the copy editor, the typo linters of prose and last bastion of proper grammar. Thus far, however, we've barely scratched the surface: everyone mentioned above is mostly interested in the contents of the book, but we don't do much else. There's also, as an example, the typesetters whose job is to ensure the book looks good when it goes to print -- bidding good riddance to orphans and widows, poorly-wrapped lines of code, and so much more. Someone has to design the cover, or to approve the table of contents for the first draft so that the author gets a contract. Several people oversee the process that culminates in the book going to press, -- usually referred to as production -- as well. Once copies are printed, they need to be distributed. Eventually, the book hits the shelves (physical or otherwise) and starts selling. Someone buys the book, and finally starts to read it. We could write entire books about the purchase transaction alone.
 
 The complexity of the whole process is mind-boggling, and yet, to each individual, it's not that complicated. The author, for example, merely has to write a few hundred words every day. Where did all that complexity go? There's a reason the process is so compartmentalized. We're not that good at handling high-level complexity, and breaking it down into single responsibilities ( such as "write content", "improve how prose flows", "review technical concerns", "fix grammar mistakes", "typeset for production", or "handle purchases" ), is what makes the process simpler for individuals, working on the mammoth project that is writing a book or just about any business enterprise.
 
diff --git a/sections/preface.asciidoc b/sections/preface.asciidoc
index 4fda2e2..1459dba 100644
--- a/sections/preface.asciidoc
+++ b/sections/preface.asciidoc
@@ -1,96 +1,102 @@
-[preface]
-== Preface
-
-=== Conventions Used in This Book
-
-The following typographical conventions are used in this book:
-
-_Italic_:: Indicates new terms, URLs, email addresses, filenames, and file extensions.
-
-+Constant width+:: Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords.
-
-**`Constant width bold`**:: Shows commands or other text that should be typed literally by the user.
-
-_++Constant width italic++_:: Shows text that should be replaced with user-supplied values or by values determined by context.
-
-
-[TIP]
-====
-This element signifies a tip or suggestion.
-====
-
-[NOTE]
-====
-This element signifies a general note.
-====
-
-[WARNING]
-====
-This element indicates a warning or caution.
-====
-
-=== Using Code Examples
-++++
-<!--PROD: Please reach out to author to find out if they will be uploading code examples to oreilly.com or their own site (e.g., GitHub). If there is no code download, delete this whole section. If there is, when you email digidist with the link, let them know what you filled in for title_title (should be as close to book title as possible, i.e., learning_python_2e). This info will determine where digidist loads the files.-->
-++++
-
-Supplemental material (code examples, exercises, etc.) is available for download at link:$$https://github.com/oreillymedia/title_title$$[].
-
-This book is here to help you get your job done. In general, if example code is offered with this book, you may use it in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing a CD-ROM of examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission.
-
-We appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “_Book Title_ by Some Author (O’Reilly). Copyright 2012 Some Copyright Holder, 978-0-596-xxxx-x.”
-
-If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at pass:[<a class="email" href="mailto:permissions@oreilly.com"><em>permissions@oreilly.com</em></a>].
-
-=== Safari® Books Online
-
-[role = "safarienabled"]
-[NOTE]
-====
-pass:[<a href="http://safaribooksonline.com" class="orm:hideurl:ital"><em class="hyperlink">Safari Books Online</em></a>] is an on-demand digital library that delivers expert pass:[<a href="https://www.safaribooksonline.com/explore/" class="orm:hideurl">content</a>] in both book and video form from the world&#8217;s leading authors in technology and business.
-====
-
-Technology professionals, software developers, web designers, and business and creative professionals use Safari Books Online as their primary resource for research, problem solving, learning, and certification training.
-
-++++
-<p>Safari Books Online offers a range of <a href="https://www.safaribooksonline.com/pricing/" class="orm:hideurl">plans and pricing</a> for <a href="https://www.safaribooksonline.com/enterprise/" class="orm:hideurl">enterprise</a>, <a href="https://www.safaribooksonline.com/government/" class="orm:hideurl">government</a>, <a href="https://www.safaribooksonline.com/academic-public-library/" class="orm:hideurl">education</a>, and individuals.</p>
-
-<p>Members have access to thousands of books, training videos, and prepublication manuscripts in one fully searchable database from publishers like O&#8217;Reilly Media, Prentice Hall Professional, Addison-Wesley Professional, Microsoft Press, Sams, Que, Peachpit Press, Focal Press, Cisco Press, John Wiley &amp; Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FT Press, Apress, Manning, New Riders, McGraw-Hill, Jones &amp; Bartlett, Course Technology, and hundreds <a href="https://www.safaribooksonline.com/our-library/" class="orm:hideurl">more</a>. For more information about Safari Books Online, please visit us <a class="orm:hideurl">online</a>.</p>
-++++
-
-=== How to Contact Us
-
-Please address comments and questions concerning this book to the publisher:
-
-++++
-<ul class="simplelist">
-  <li>O’Reilly Media, Inc.</li>
-  <li>1005 Gravenstein Highway North</li>
-  <li>Sebastopol, CA 95472</li>
-  <li>800-998-9938 (in the United States or Canada)</li>
-  <li>707-829-0515 (international or local)</li>
-  <li>707-829-0104 (fax)</li>
-</ul>
-++++
-
-We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at link:$$http://www.oreilly.com/catalog/<catalog page>$$[].
-
-++++
-<!--Don't forget to update the link above.-->
-++++
-
-To comment or ask technical questions about this book, send email to pass:[<a class="email" href="mailto:bookquestions@oreilly.com"><em>bookquestions@oreilly.com</em></a>].
-
-For more information about our books, courses, conferences, and news, see our website at link:$$http://www.oreilly.com$$[].
-
-Find us on Facebook: link:$$http://facebook.com/oreilly$$[]
-
-Follow us on Twitter: link:$$http://twitter.com/oreillymedia$$[]
-
-Watch us on YouTube: link:$$http://www.youtube.com/oreillymedia$$[]
-
-=== Acknowledgments
-
-++++
-<!--Fill in...-->
-++++
+[preface]
+== Preface
+
+I started toying with Node.js -- and, unbeknownst to me, getting into a serious relationship with JavaScript -- at about the same time as I discovered open-source and fell in love with its practices. Coming from the closed-source landscape in C#, the open-source ecosystem around Node.js gave me a new perspective and joy in figuring out how to write robust code that others find pleasant enough to consume. It's with this background that I find myself always pondering about how an interface should be defined, who would be consuming it, and how they'd like to spend their time doing something else than figuring out what we originally intended them to do.
+
+=== Who Should Read This Book
+
+This book is meant for developers, enthusiasts, and professionals with a working knowledge of JavaScript and ES6footnote:[ES6 effected a profound change in the JavaScript language, introducing multiple syntax improvements, a few handfuls of new methods. This book assumes familiarity with JavaScript after ES6. You can learn more about ES6 syntax by visiting the following link for a crash course: https://mjavascript.com/out/es6.]. These developers, and anyone interested in learning more about writing modular code that's readable, maintainable, and scalable, even beyond the JavaScript language, shall benefit from reading _Mastering Modular JavaScript_.
+
+=== Why Modular JavaScript?
+
+The goal of this book is to offer an affable way of becoming a successful module author. It's not that writing JavaScript modules is particularly hard, but following sound design practices to ensure we deliver the right amounts of simplicity and flexibility so that consumers can rely on modules to be simple most of the time, but flexible when it matters, -- while keeping internal complexity in check -- is hardly a trivial task. I wrote bits and pieces about proper application design in JavaScript Application Designfootnote:[JavaScript Application Design is a book I published through Manning in 2015. It revolves around build processes, but also features chapters on managing complexity, on sensible asynchronous flow control code, on REST API design, and on JavaScript testing concerns. Learn more at: https://mjavascript.com/out/jad.] and for the Pony Foo blog, but I've been yearning to publish something more comprehensive that was exclusively dedicated to reasoning about, designing, and writing modular code.
+
+Though, I couldn't find any books that addressed the subject from a JavaScript point of view, you can easily find other books that touch on the subject of modular code, such as Code Complete or Clean Code, and leverage their teachings in your JavaScript development efforts. Mastering Modular JavaScript is an attempt to draw attention from what you should be doing, and instead focus on you coming to your own conclusions about what you should be doing and why -- without imposing axiomatic rules that only contribute to what artificially self-proclaims and positions itself as "clean code".
+
+This book tries to explain how you could be writing modular code without being overt. Instead, we'll try to shed light into the fundamentals behind modular architecture, and it's history when it comes to JavaScript, so that you earn a better understanding of what it means to write modular applications, and what's to be gained from doing so.
+
+Rather than rely on long-winded, pages-long, thoroughly analyzed, concrete examples, the book hopes to challenge you to apply its passages to the problems that you're trying to address in your own programs, and coming to your own realizations by weighing the benefits and drawbacks of taking one of a few possible approaches. In software, there is no such thing as one-size-fits-all, and you're often going to leverage your own best judgement to decide how to write it. All software adapts to the context that surrounds it, and if you've done any work at all involving software deployments or releases, then you surely are intimate with exactly how hard it is to cram the same piece of software into different execution environments.
+
+Just like with Practical Modern JavaScript, -- the first in the Modular JavaScript series -- this book has the goal of establishing a baseline we can take for granted in the rest of the Modular JavaScript series. After having learned all about the latest language features in Practical Modern JavaScript, and all about modular design thinking in this book, we'll be all set to discuss solution-specific concerns in Universal JavaScript and then testing and deployment in subsequent books, without necessarily delving too deeply into concepts taught in previous books. This incremental and modular approach is meant to be pervasive across the series, each book, each chapter, and each section.
+
+=== How Is This Book Organized?
+
+<<module-thinking>> discusses the evolution of modularity in the context of JavaScript. From the early days of embedding JavaScript in `onclick` attributes, to CommonJS and finally native ECMAScript modules. It then looks at the benefits of writing self-contained code, and of doing so at every level of a system: services, applications, components, modules, functions, blocks, and so on.
+
+<<modularity-principles>> covers the essentials of modular design, giving you a foundation from which you can write modules that are conscientious of their API surface, how it's --in all likelihood-- going to be consumed, where the responsibilities lie, and what belongs on the interface.
+
+A good portion of <<module-design>> is devoted to understanding what kind of problems you should be solving, and how to do it while keeping an eye on how the module and its interface may evolve, being shy about abstractions while waiting for clear patterns to emerge. <<module-design>> prods beneath the surface and gets you thinking of best practices around documentation, error handling, and following your own reasoning by applying your own context to the problem that is being resolved.
+
+In <<shaping-internals>>, we get comfortable talking about internal complexity, tight coupling, and weighing the merits of frameworks and conventions. The bulk of <<shaping-internals>> is spent discussing some of the many ways in which we can reduce complexity by refactoring our code. We then discuss the role of state in relation to complexity, and how it can be mitigated. Data structures play a role as well, as picking the right ones is both challenging and immensely rewarding when it comes to keeping complexity in check.
+
+<<modular-patterns-and-practices>> is specifically about JavaScript, detailing how we can leverage modern language constructs to write clear programs. This chapter also examines patterns such as inheritance and composition, leading into a discussion about which option is better depending on your use case. <<modular-patterns-and-practices>> is rounded out by tackling classic patterns like revealing modules, object factories, event emitters, and JSON message passing.
+
+<<development-methodology-and-philosophy>> describes the mindset of a battle-hardened module developer, addressing security concerns and dependency management, build and integration processes, interfaces and abstractions, and generally a potpourri of module design advice and best practices.
+
+Those of you who are already familiar with the history of modularity when it comes to JavaScript would do well to -- at the very least -- skim through the history lessons in the first chapter. If you're more of the type that's comfortable jumping around the pages in a book, I would still recommend reading through every chapter, given this relatively short book is more of a story to be told about well-reasoned programs than it is a compendium of recipes.
+
+=== Conventions Used in This Book
+
+The following typographical conventions are used in this book:
+
+_Italic_:: Indicates new terms, URLs, email addresses, filenames, and file extensions.
+
++Constant width+:: Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords.
+
+[TIP]
+====
+This icon signifies a tip, suggestion, or general note.
+====
+
+[WARNING]
+====
+This icon indicates a warning or caution.
+====
+
+=== O'Reilly Safari
+
+[role = "safarienabled"]
+[NOTE]
+====
+pass:[<a href="http://oreilly.com/safari" class="orm:hideurl"><em class="hyperlink">Safari</em></a>] (formerly Safari Books Online) is a membership-based training and reference platform for enterprise, government, educators, and individuals.
+====
+
+Members have access to thousands of books, training videos, Learning Paths, interactive tutorials, and curated playlists from over 250 publishers, including O’Reilly Media, Harvard Business Review, Prentice Hall Professional, Addison-Wesley Professional, Microsoft Press, Sams, Que, Peachpit Press, Adobe, Focal Press, Cisco Press, John Wiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FT Press, Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett, and Course Technology, among others.
+
+For more information, please visit pass:[<a href="http://oreilly.com/safari" class="orm:hideurl"><em>http://oreilly.com/safari</em></a>].
+
+[role="pagebreak-before"]
+=== How to Contact Us
+
+Please address comments and questions concerning this book to the publisher:
+
+++++
+<ul class="simplelist">
+  <li>O’Reilly Media, Inc.</li>
+  <li>1005 Gravenstein Highway North</li>
+  <li>Sebastopol, CA 95472</li>
+  <li>800-998-9938 (in the United States or Canada)</li>
+  <li>707-829-0515 (international or local)</li>
+  <li>707-829-0104 (fax)</li>
+</ul>
+++++
+
+We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at link:$$http://www.oreilly.com/catalog/0636920047124$$[].
+
+To comment or ask technical questions about this book, send email to pass:[<a class="email" href="mailto:bookquestions@oreilly.com"><em>bookquestions@oreilly.com</em></a>].
+
+For more information about our books, courses, conferences, and news, see our website at link:$$http://www.oreilly.com$$[].
+
+Find us on Facebook: link:$$http://facebook.com/oreilly$$[]
+
+Follow us on Twitter: link:$$http://twitter.com/oreillymedia$$[]
+
+Watch us on YouTube: link:$$http://www.youtube.com/oreillymedia$$[]
+
+=== Acknowledgments
+
+There are a lot of people to thank for _Mastering Modular JavaScript_ coming to fruition. First and foremost we have Virginia Wilson, the main content editor in charge of this book and the Modular JavaScript series at O'Reilly. She offered insight where it counted, was very understanding when my schedule tightened and the writing slowed down to a trickle, and always kept an extremely positive attitude about things!
+
+The technical reviewers were also out of this world. Mathias Bynens focused on making sure my comments around the ECMAScript specification were up to par, as usual. Ingvar Stepanyan always seems ready to jump at the chance of helping out with technical reviews for my books, and he's always offering unique points of views which result in more clear descriptions and more thorough examples, I'm incredibly grateful for his work. Adam Rackis has also been super helpful during technical review for the series, always providing solid commentary about bits that needed to be corrected, better fleshed out, or prose that might not have been all that clear.
+
+As usual, I'd also like to thank my wife, Marianela, for always standing right beside me through the emotional rollercoaster that is writing these books.

From 8eb382a8c3f675485f0c226a19c3e36f4383c905 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 29 Jun 2018 17:48:04 -0300
Subject: [PATCH 55/71] tweak preface because move bulk of ch01 intro into it

---
 chapters/ch01.asciidoc    | 12 ++----------
 sections/preface.asciidoc | 12 +++++++++++-
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/chapters/ch01.asciidoc b/chapters/ch01.asciidoc
index 3408031..1162552 100644
--- a/chapters/ch01.asciidoc
+++ b/chapters/ch01.asciidoc
@@ -1,17 +1,9 @@
 [[module-thinking]]
 == Module Thinking
 
-Even after the printing press was invented, publishing books remains a challenging endeavor. Yes, there's typically an author -- or authors -- who scribbled the content wherever and whenever they found time to do so. But there's also a content editor, tasked with helping the author transform their stream of consciousness into a relatable story that's not too dry to read, something to be especially careful about when it comes to technical or business books. We have the technical reviewers, watchful subject matter experts on the lookout for egregious mistakes in technical definitions or interpretations. And lastly, -- of course -- we have the copy editor, the typo linters of prose and last bastion of proper grammar. Thus far, however, we've barely scratched the surface: everyone mentioned above is mostly interested in the contents of the book, but we don't do much else. There's also, as an example, the typesetters whose job is to ensure the book looks good when it goes to print -- bidding good riddance to orphans and widows, poorly-wrapped lines of code, and so much more. Someone has to design the cover, or to approve the table of contents for the first draft so that the author gets a contract. Several people oversee the process that culminates in the book going to press, -- usually referred to as production -- as well. Once copies are printed, they need to be distributed. Eventually, the book hits the shelves (physical or otherwise) and starts selling. Someone buys the book, and finally starts to read it. We could write entire books about the purchase transaction alone.
+As discussed in the preface, complexity seems to be all around us while we're working on software projects. So are abstractions, that keep complexity hidden away from us under rocks we don't dare touching. These rocks are our interfaces to the rest of the world, so that we can get away with hardly thinking about it. JavaScript is no exception here -- on the contrary: as powerful as dynamic languages are, it is also that much easier, and even tempting, to write complex programs when we're using them.
 
-The complexity of the whole process is mind-boggling, and yet, to each individual, it's not that complicated. The author, for example, merely has to write a few hundred words every day. Where did all that complexity go? There's a reason the process is so compartmentalized. We're not that good at handling high-level complexity, and breaking it down into single responsibilities ( such as "write content", "improve how prose flows", "review technical concerns", "fix grammar mistakes", "typeset for production", or "handle purchases" ), is what makes the process simpler for individuals, working on the mammoth project that is writing a book or just about any business enterprise.
-
-Publishing is just an example, but we could do this exercise with just about anything. Pick an object on your desk, any object. Think how it got there. Now zoom out, think some more, how was it made? What is it made of? How many people were involved in manufacturing each piece, assembling it, perfecting it, and getting it to the store where it was bought? Is it a fruit? How many people were involved in planting it, fighting off pests, pruning plants, packaging the fruit, and getting it to the store where it was bought?
-
-Software is not all that different, except complexity is all around us. At the deepest zoom levels we find constraints defined by physical constants such as the speed of light, individual bits and hardware, interrupt calls, assembly language, and much more. Zooming out we find the mega-structures of the technology sector, which handle everything from search queries to payment processing. Somewhere in the midst of all this complexity, there's us developers, and the projects bestowed upon us.
-
-We hardly stop to think about the complexity underlying everyday objects and interactions, since doing so would be paralyzing. Instead, we abstract solutions behind interfaces, so much that they _become_ -- in our minds -- the interface. Some of these interfaces map well to the abstracted implementation, and they feel great. Others don't map all that well to the implementation, and we end up feeling confused and frustrated. Software is not at all different. We don't want to think about the system as a whole, and virtually everything we work with sits behind interfaces that are simpler to use and understand than their underlying implementations.
-
-This already happens at the system level, and we hardly think about it. Let's discuss how we can apply the same concepts to the work we do, so that we can minimize the amount of complexity we need to stare at when working on a project, a feature, a piece of functionality, down to the branches of a single function.
+To get started, let's discuss how we can better apply abstractions, interfaces, and their underlying concepts to the work we do, so that we can minimize the amount of complexity we need to stare at when working on a project, a feature, a piece of functionality, down to the branches of a single function.
 
 === 1.1 Introduction to Module Thinking
 
diff --git a/sections/preface.asciidoc b/sections/preface.asciidoc
index 1459dba..ac51523 100644
--- a/sections/preface.asciidoc
+++ b/sections/preface.asciidoc
@@ -1,7 +1,15 @@
 [preface]
 == Preface
 
-I started toying with Node.js -- and, unbeknownst to me, getting into a serious relationship with JavaScript -- at about the same time as I discovered open-source and fell in love with its practices. Coming from the closed-source landscape in C#, the open-source ecosystem around Node.js gave me a new perspective and joy in figuring out how to write robust code that others find pleasant enough to consume. It's with this background that I find myself always pondering about how an interface should be defined, who would be consuming it, and how they'd like to spend their time doing something else than figuring out what we originally intended them to do.
+Even after the printing press was invented, publishing books remains a challenging endeavor. Yes, there's typically an author -- or authors -- who scribbled the content wherever and whenever they found time to do so. But there's also a content editor, tasked with helping the author transform their stream of consciousness into a relatable story that's not too dry to read, something to be especially careful about when it comes to technical or business books. We have the technical reviewers, watchful subject matter experts on the lookout for egregious mistakes in technical definitions or interpretations. And lastly, -- of course -- we have the copy editor, the typo linters of prose and last bastion of proper grammar. Thus far, however, we've barely scratched the surface: everyone mentioned above is mostly interested in the contents of the book, but we don't do much else. There's also, as an example, the typesetters whose job is to ensure the book looks good when it goes to print -- bidding good riddance to orphans and widows, poorly-wrapped lines of code, and so much more. Someone has to design the cover, or to approve the table of contents for the first draft so that the author gets a contract. Several people oversee the process that culminates in the book going to press, -- usually referred to as production -- as well. Once copies are printed, they need to be distributed. Eventually, the book hits the shelves (physical or otherwise) and starts selling. Someone buys the book, and finally starts to read it. We could write entire books about the purchase transaction alone.
+
+The complexity of the whole process is mind-boggling, and yet, to each individual, it's not that complicated. The author, for example, merely has to write a few hundred words every day. Where did all that complexity go? There's a reason the process is so compartmentalized. We're not that good at handling high-level complexity, and breaking it down into single responsibilities ( such as "write content", "improve how prose flows", "review technical concerns", "fix grammar mistakes", "typeset for production", or "handle purchases" ), is what makes the process simpler for individuals, working on the mammoth project that is writing a book or just about any business enterprise.
+
+Publishing is just an example, but we could do this exercise with just about anything. Pick an object on your desk, any object. Think how it got there. Now zoom out, think some more, how was it made? What is it made of? How many people were involved in manufacturing each piece, assembling it, perfecting it, and getting it to the store where it was bought? Is it a fruit? How many people were involved in planting it, fighting off pests, pruning plants, packaging the fruit, and getting it to the store where it was bought?
+
+Software is not all that different, except complexity is all around us. At the deepest zoom levels we find constraints defined by physical constants such as the speed of light, individual bits and hardware, interrupt calls, assembly language, and much more. Zooming out we find the mega-structures of the technology sector, which handle everything from search queries to payment processing. Somewhere in the midst of all this complexity, there's us developers, and the projects bestowed upon us.
+
+We hardly stop to think about the complexity underlying everyday objects and interactions, since doing so would be paralyzing. Instead, we abstract solutions behind interfaces, so much that they _become_ -- in our minds -- the interface. Some of these interfaces map well to the abstracted implementation, and they feel great. Others don't map all that well to the implementation, and we end up feeling confused and frustrated. Software is not at all different. We don't want to think about the system as a whole, and virtually everything we work with sits behind interfaces that are simpler to use and understand than their underlying implementations.
 
 === Who Should Read This Book
 
@@ -9,6 +17,8 @@ This book is meant for developers, enthusiasts, and professionals with a working
 
 === Why Modular JavaScript?
 
+I started toying with Node.js -- and, unbeknownst to me, getting into a serious relationship with JavaScript -- at about the same time as I discovered open-source and fell in love with its practices. Coming from the closed-source landscape in C#, the open-source ecosystem around Node.js gave me a new perspective and joy in figuring out how to write robust code that others find pleasant enough to consume. It's with this background that I find myself always pondering about how an interface should be defined, who would be consuming it, and how they'd like to spend their time doing something else than figuring out what we originally intended them to do.
+
 The goal of this book is to offer an affable way of becoming a successful module author. It's not that writing JavaScript modules is particularly hard, but following sound design practices to ensure we deliver the right amounts of simplicity and flexibility so that consumers can rely on modules to be simple most of the time, but flexible when it matters, -- while keeping internal complexity in check -- is hardly a trivial task. I wrote bits and pieces about proper application design in JavaScript Application Designfootnote:[JavaScript Application Design is a book I published through Manning in 2015. It revolves around build processes, but also features chapters on managing complexity, on sensible asynchronous flow control code, on REST API design, and on JavaScript testing concerns. Learn more at: https://mjavascript.com/out/jad.] and for the Pony Foo blog, but I've been yearning to publish something more comprehensive that was exclusively dedicated to reasoning about, designing, and writing modular code.
 
 Though, I couldn't find any books that addressed the subject from a JavaScript point of view, you can easily find other books that touch on the subject of modular code, such as Code Complete or Clean Code, and leverage their teachings in your JavaScript development efforts. Mastering Modular JavaScript is an attempt to draw attention from what you should be doing, and instead focus on you coming to your own conclusions about what you should be doing and why -- without imposing axiomatic rules that only contribute to what artificially self-proclaims and positions itself as "clean code".

From fb60434cf59f2392f37c1855e03e83a5a23708b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 29 Jun 2018 18:08:10 -0300
Subject: [PATCH 56/71] conclusions

---
 chapters/ch01.asciidoc    | 2 +-
 chapters/ch04.asciidoc    | 2 ++
 chapters/ch05.asciidoc    | 2 ++
 chapters/ch06.asciidoc    | 2 ++
 sections/preface.asciidoc | 2 ++
 5 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/chapters/ch01.asciidoc b/chapters/ch01.asciidoc
index 1162552..08b63b4 100644
--- a/chapters/ch01.asciidoc
+++ b/chapters/ch01.asciidoc
@@ -247,4 +247,4 @@ With the advent of frameworks like Backbone, Angular, Ember, and React, new tech
 
 This explosion of innovation doesn't stem from sheer creativity alone but also out of necessity: web applications are getting increasingly complex, as is their scope, purpose, and requirements. It follows logically, then, that the ecosystem around them would grow to accommodate those expanded requirements, in terms of better tooling, better libraries, better coding practices, architectures, standards, patterns, and more choice in general.
 
-While there are heaps of books on proper application design, there isn't a lot of material to be found on the topic of modular application design, let alone modular JavaScript application design -- hence this book. While the ample majority of the advice, musings, and teachings in this book aren't at all specific to JavaScript, the fresh focus on JavaScript means you'll be learning about how to write modular web applications while keeping in consideration the quirks that make the web such a unique platform, and JavaScript, special in many ways.
+In the next chapter we'll break down the meaning of complexity, and start building fortifications against complexity in the programs we write. By following a few rules around how we encapsulate logic across layers upon layers of components, we'll commence our journey to simpler program design.
diff --git a/chapters/ch04.asciidoc b/chapters/ch04.asciidoc
index 5c439b9..5f46bcf 100644
--- a/chapters/ch04.asciidoc
+++ b/chapters/ch04.asciidoc
@@ -720,3 +720,5 @@ Splitting logic into a few files under the same directory helps us prevent an ex
 The alternative, placing logic related to a particular aspect of our application such as blog posts directly in the components where it's needed, will cause trouble if left unchecked. Doing so might be beneficial in terms of short-term productivity, but longer-term we need to worry about coupling logic, strictly related to blog posts in this case, together with entirely different concerns. At the same time, if we sprinkle a bulk of the logic across several unrelated components, we become at risk of missing critical aspects of functionality when making large-scale updates to the codebase, and because of this we might end up making the wrong assumptions, or mistakes that only become evident much further down the line.
 
 It's acceptable to start out placing logic directly where it's needed at first, when it's unclear whether the functionality will grow or how much. Once this initial exploratory period ellapses, and it becomes clear the functionality is here to stay and more might be to come, it's advisable that we isolate the functionality for the reasons stated above. Later, as the functionality grows in size and in concerns that need to be addressed, we can componentize each aspect into different modules that are still grouped together logically in the file system, making it easy to take all of interrelated concerns into account when need be.
+
+Now that we have broken down the essentials of module design and how to delineate interfaces, as well as how to lockdown, isolate, and drive down complexity in our internal implementations, we're ready to start discussing JavaScript-specific language features and an assortment of patterns that we can benefit from.
diff --git a/chapters/ch05.asciidoc b/chapters/ch05.asciidoc
index 62b11f4..7b03b64 100644
--- a/chapters/ch05.asciidoc
+++ b/chapters/ch05.asciidoc
@@ -653,3 +653,5 @@ Although we can easily serialize our `rwanda` instance with `JSON.stringify(rwan
 JSON -- nowfootnoteref:[json-grammar,Up until recently, JSON wasn't -- strictly speaking -- a proper subset of ECMA-262. A recent proposal has amended the ECMAScript specification to consider bits of JSON that were previously invalid JavaScript to be valid JavaScript. Learn more at: https://mjavascript.com/out/json-subset.] a subset of the JavaScript grammar -- was purpose-built for this use case, where we often have to serialize data, send it over the wire, and deserialize it on the other end. Plain JavaScript objects are a great way to store data in our applications, offer frictionless serialization out the box, and lead to cleaner data structures because we can keep logic decoupled from the data.
 
 When the language on both the sending and receiving ends is JavaScript, we can share a module with all the functionality that we need around the data structure. This way, we don't have to worry about serialization, since we're using plain JavaScript objects and can rely on JSON for the transport layer. We don't have to concern ourselves with sharing functionality either, because we can rely on the JavaScript module system for that part.
+
+Armed with a foundation for writing solid modules based on your own reasoning, we now turn the page to operational concerns such as handling application secrets responsibly, making sure our dependencies don't fail us, taking care of how we orchestrate build processes and continuous integration, and dealing with nuance in state management and the high-stakes decision-making around producing the right abstractions.
diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 53dd10d..99ea19a 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -281,3 +281,5 @@ A middle layer could leverage a normalized query from the consumer, such as the
 The same case could, and should, be made for the data structures returned from either of these backing services. By normalizing the data into a structure that only contains information that's relevant to our consumers, and augmenting it with the derived information they need (such as the airline name and details as explained earlier), the consumer can focus on their own concerns while leveraging a data structure that's close to their needs. At the same time, this normalization empowers our abstraction to merge results from both backing services and treat them as if they came from a single source: the abstraction itself, leaving the backing services as mere implementation details.
 
 When we rely directly on the original responses, we may find ourselves writing view components that are more verbose than they need be, containing logic to pull together the different bits of metadata needed to render our views, mapping data from the API representation into what we actually want to display, and then mapping user input back into what the API expects. With a layer in between, we can keep this mapping logic contained in a single place, and leave the rest of our application unencumbered by it.
+
+Mastering modular JavaScript isn't strictly about following a well-defined set of rules, but rather about being able to put yourself on the shoes of your consumers, foreplanning for feature development that may be coming down the pipe, -- but not too extensively -- and treating documentation with the same respect and care that you should be putting into interface design. The internals, as the implementation details that they are, can always be improved later. Of course, we'll want to patch or at least abstract away those sources of complexity, but it is in their shell that beautiful modules truly shine.
diff --git a/sections/preface.asciidoc b/sections/preface.asciidoc
index ac51523..5521872 100644
--- a/sections/preface.asciidoc
+++ b/sections/preface.asciidoc
@@ -25,6 +25,8 @@ Though, I couldn't find any books that addressed the subject from a JavaScript p
 
 This book tries to explain how you could be writing modular code without being overt. Instead, we'll try to shed light into the fundamentals behind modular architecture, and it's history when it comes to JavaScript, so that you earn a better understanding of what it means to write modular applications, and what's to be gained from doing so.
 
+While there are heaps of books on proper application design, there isn't a lot of material to be found on the topic of modular application design, let alone modular JavaScript application design -- hence this book. While the ample majority of the advice, musings, and teachings in this book aren't at all specific to JavaScript, the fresh focus on JavaScript means you'll be learning about how to write modular web applications while keeping in consideration the quirks that make the web such a unique platform, and JavaScript, special in many ways.
+
 Rather than rely on long-winded, pages-long, thoroughly analyzed, concrete examples, the book hopes to challenge you to apply its passages to the problems that you're trying to address in your own programs, and coming to your own realizations by weighing the benefits and drawbacks of taking one of a few possible approaches. In software, there is no such thing as one-size-fits-all, and you're often going to leverage your own best judgement to decide how to write it. All software adapts to the context that surrounds it, and if you've done any work at all involving software deployments or releases, then you surely are intimate with exactly how hard it is to cram the same piece of software into different execution environments.
 
 Just like with Practical Modern JavaScript, -- the first in the Modular JavaScript series -- this book has the goal of establishing a baseline we can take for granted in the rest of the Modular JavaScript series. After having learned all about the latest language features in Practical Modern JavaScript, and all about modular design thinking in this book, we'll be all set to discuss solution-specific concerns in Universal JavaScript and then testing and deployment in subsequent books, without necessarily delving too deeply into concepts taught in previous books. This incremental and modular approach is meant to be pervasive across the series, each book, each chapter, and each section.

From 997ef8d740f1553dff8cf56c0ab01c6b653f6486 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 29 Jun 2018 18:12:22 -0300
Subject: [PATCH 57/71] flesh out book conclusion

---
 chapters/ch06.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index 99ea19a..c15cf42 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -282,4 +282,4 @@ The same case could, and should, be made for the data structures returned from e
 
 When we rely directly on the original responses, we may find ourselves writing view components that are more verbose than they need be, containing logic to pull together the different bits of metadata needed to render our views, mapping data from the API representation into what we actually want to display, and then mapping user input back into what the API expects. With a layer in between, we can keep this mapping logic contained in a single place, and leave the rest of our application unencumbered by it.
 
-Mastering modular JavaScript isn't strictly about following a well-defined set of rules, but rather about being able to put yourself on the shoes of your consumers, foreplanning for feature development that may be coming down the pipe, -- but not too extensively -- and treating documentation with the same respect and care that you should be putting into interface design. The internals, as the implementation details that they are, can always be improved later. Of course, we'll want to patch or at least abstract away those sources of complexity, but it is in their shell that beautiful modules truly shine.
+Mastering modular JavaScript isn't strictly about following a well-defined set of rules, but rather about being able to put yourself on the shoes of your consumers, foreplanning for feature development that may be coming down the pipe, -- but not too extensively -- and treating documentation with the same respect and care that you should be putting into interface design. The internals, as the implementation details that they are, can always be improved later. Of course, we'll want to patch -- or, at least, abstract away -- those sources of complexity, but it is in their shell that beautiful modules truly shine. Above all, trust your own judgement and don't let the latest development fads clog your decision-making!

From baabb2c939d675bc2c916c1cebeae52870957561 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 29 Jun 2018 18:43:20 -0300
Subject: [PATCH 58/71] include campaign backer list

---
 sections/preface.asciidoc | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/sections/preface.asciidoc b/sections/preface.asciidoc
index 5521872..16cd864 100644
--- a/sections/preface.asciidoc
+++ b/sections/preface.asciidoc
@@ -111,4 +111,8 @@ There are a lot of people to thank for _Mastering Modular JavaScript_ coming to
 
 The technical reviewers were also out of this world. Mathias Bynens focused on making sure my comments around the ECMAScript specification were up to par, as usual. Ingvar Stepanyan always seems ready to jump at the chance of helping out with technical reviews for my books, and he's always offering unique points of views which result in more clear descriptions and more thorough examples, I'm incredibly grateful for his work. Adam Rackis has also been super helpful during technical review for the series, always providing solid commentary about bits that needed to be corrected, better fleshed out, or prose that might not have been all that clear.
 
-As usual, I'd also like to thank my wife, Marianela, for always standing right beside me through the emotional rollercoaster that is writing these books.
+I would be remiss if I didn't call out everyone who backed the Indiegogo campaign for the Modular JavaScript book series back in 2016. Thank you for placing your trust in me when these books were merely an idea, injecting me with a large dose of enthusiasm early on. If we ever run into each other, the beers are on me! In no particular order:
+
+Aaron Endsley, Aaron Hans, Aaron Olson, Aaron Wells, Adam Rackis, Adi Purnama Mutiara, Adrian Li, Adrian Rand, Agustin Nicolas Polo, Alan Chandler, Alasdair Shepherd, Alejandro Nanez O, Alexis Mills, Allen Dean, Anastasios Alexiou, Andrea Giammarchi, Andres Mijares, Andrew Broman, Andrew Kenward, Andrew Shell, Andrew Van Slaars, Andrey Golovin, Angel Ramirez Morel, Anna Vu, Anselm Hannemann, Anthony Casson, Arnau Pujol, Arnis Lupiks, Artur Jonczyk", Aziz Khoury, Barney Scott, Beau Cronin, Ben Lagoutte, Ben Mann, Benjamin Bank, benjamintpoon, Benny Neugebauer, Bishal Pantha, Bran Sorem, Brent Huffman, Bruce Hyatt, Burton Podczerwinski, Béla Varga, Ca-Phun Ung, Cameron Stark, Carlos López, Casper de Rooij, Chad Thoreson, Charles Herman, Charles Rector, Charlie Hill, Chase Hagwood, Chris Fothergill, chris weber, Christopher Dresel, Christopher Gonzales, Christopher Hamilton, Christopher Scott, Cindy Juarez, Claudia Hernández, Constantin Chirila, Cris Ryan Tan, Dallen Richard Loder, Dan Hayden, Dan M., Dan Perrera, Dan Rocha, Daniel Cloud, Daniel Egger, Daniel Sleeth, David Ershag, David G. Chaves, David González Polán, David Hobbs, David Lemarier, Dayan Barros, Dejan Cencelj, Denise Darmawi, Derick Rodriguez, Derik Badman, Dick Grayson, Dmitry Goryunov, Don Hamilton III, Donald Gary, Doug Chase, Dumitru Florin Gabriel, Eder Sánchez, Edgar Barrantes, Edouard Baudry, Eduardo Rabelo, Eric Lezotte, Ersan Temizyurek, Ezequiel Cabrera, Fabian Marz, Fabio Vedovelli, Fabrice Le Coz, Federico Foresti, Fer To, Fernando Ripoll Lafuente, Flavio Spaini, Fran Nunez, Francesco Strappini, Francisco Cerdas, Fredrik Forsmo, Fredrik Lexberg, Gabor Dolla, Gabriel Chertok, Gabriel García Seco, Gergo Szonyi, Giovanni Londero, glennjonesnet, Gorshunov Vladimir, Guy Tepper, Hamish Macpherson, Hanslutter Fomben, Henk Jan van Wijk, Hernan Chiosso, Horváth László Gábor, Hugo Lopes, Ian B. De La Cruz, Ian Doyle, Ian McCausland, Ignacio Anaya, Istvan Szmozsanszky, Ivan Saveliev, Ivan Tanev, J. Singh, jack pallot, Jack W McNicol, Jaime García, Jake Smith, Janderson Martins, Jani Kraner, Jared Moran, Jason Broyles, Jason Finch, Jean Osorio, Jeffrey Borisch, Jelena Jovanovic, Jennifer Dixon, Jeremy Tymes, Jeremy Wilken, Jia Fei Fei, Jiaxing Wang, Joachim Kliemann, Joan Maria Talarn, Johannes Weiser, John Engstrom, john fogarty, John Johnson, Jon Saw, Jonathan Boiser, Joostc Schermers, Josh Adam, Josh Magness, José Esparza, jsnisenson, Juan Lopez, Junrou Nishida, Jörn Flath, Karthikeya Pammi, Kevin Gimbel, Kevin Rambaud, Kevin Scheffelmeier, Kevin Youkhana, kgarbaya, konker, Kostas Galanos, Kris Bulman, Kyle Simpson, Lalit Agrawala, Lea P., Leonardo Di Lella, Lidor Lapid, mailtorenil, Marc Grabanski, Marco Martins, marco.scarpa, Marcus Bransbury, Mariano Campo, Mark Kramer, Martijn Rouwendal, Martin Ansty, Martin Gonzalez, Martin Luna, Massimiliano Filacchioni, Mathias Bynens, Matt Riley, Matt Webb, Matteo Hertel, Matthew Bagwell, Mauro Gestoso, Max Felgenhauer, Maxwell Chiareli, Michael Chan, Michael Erdey, Michael Klose, Michael Kühnel, Michael Spreu, Michael Vezzani, Mike Kidder, Mike Parsons, Mitchell Gates, Nathan Heskew, Nathan Schlehlein, Nick Dunn, Nick Klunder, Nicolás Isnardi, Norbert Sienkiewicz, Oliver Wehn, Olivier Camon, Olivier Van hamme, Owen Densmore, P. Ghinde, Patrick Nouvion, Patrick Thompson, Paul Aeria, Paul Albertson, Paul Cooper, Paul Grock, Paul Kalupnieks, Paul Kamma, Paul Vernon, Paula Penedo Barbosa, Paulo Elias, Per Fröjd, Peter deHaan, Peter Holzer, Peter Piekarczyk, peterdoane, Phan An, Piotr Seefeld, Pranava S Balugari, Rahul Ravikumar, Randy Ferrer, Renato Alonso, Rey Bango, Reynaldo Tortoledo, Ric Johnson, Ricardo Pereira, Richard Davey, Richard Hoffmann, Richard Weltman, Riyadh Al Nur, Robert Buchholz, Ron Male, Ryan Castner, Ryan Ewing, Rylan Cottrell, Salvatore Torcivia, Sean Esteva, Sebastian Brieschenk, Sergey Efremov, Sergey Melnikov, Shane Eckel, Shaunak Kashyap, Shawn Searcy, Simeon Vincent, simonkeary, Stefan Boehm, Steve Mahony, Steven Kingston, Stoyan Delev, Stuart Robson, Sumit Sarkar, Swizec Teller, Szabolcs Legradi, Tanner Donovan, Ted Young, Thee Sritabtim, Thomas Noe, Thomas Schwarz, Tim Goshinski, Tim Osborn, Tim Pietrusky, Tony Brown, Tudosa Razvan, Ture Gjørup, Umar Farooq Khawaja, Uri Chandler, Victor Rosell, Vinay Puppal, Vladimir Bruno, Vladimir Simonov, Vladimir Zeifman, Wayne Callender, Wayne Patterson, Wee Keat Liew, Wes Bos, Wonmin Jeon, Yann LE CORRE, Yevgen Safronov, Yonatan Mevorach, youbiteme, Zach Gottlieb, Zachary Hawkins, Zane Thomas, 坤福 曾, @agolveo, @amstarri, @bondydaa, @cbergenhem, @cde008, @changke, @dhtrinh02, @dlteron.green, @eduplessis, @eonilsson, @fogarty.tj, @fortune, @gm.schlereth, @illusionmh, @jcnoble2, and @michael!
+
+As usual, I'd also like to thank my wife, Marianela, for always standing right beside me through the emotional rollercoaster that is writing these books. I don't know how she does it.

From 778709c8579be7a2cafe271ee4c18e9998606556 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Fri, 29 Jun 2018 18:44:37 -0300
Subject: [PATCH 59/71] spacing

---
 sections/preface.asciidoc | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sections/preface.asciidoc b/sections/preface.asciidoc
index 16cd864..7bb0cee 100644
--- a/sections/preface.asciidoc
+++ b/sections/preface.asciidoc
@@ -111,7 +111,9 @@ There are a lot of people to thank for _Mastering Modular JavaScript_ coming to
 
 The technical reviewers were also out of this world. Mathias Bynens focused on making sure my comments around the ECMAScript specification were up to par, as usual. Ingvar Stepanyan always seems ready to jump at the chance of helping out with technical reviews for my books, and he's always offering unique points of views which result in more clear descriptions and more thorough examples, I'm incredibly grateful for his work. Adam Rackis has also been super helpful during technical review for the series, always providing solid commentary about bits that needed to be corrected, better fleshed out, or prose that might not have been all that clear.
 
-I would be remiss if I didn't call out everyone who backed the Indiegogo campaign for the Modular JavaScript book series back in 2016. Thank you for placing your trust in me when these books were merely an idea, injecting me with a large dose of enthusiasm early on. If we ever run into each other, the beers are on me! In no particular order:
+I would be remiss if I didn't call out everyone who backed the Indiegogo campaign for the Modular JavaScript book series back in 2016. Thank you for placing your trust in me when these books were merely an idea, injecting me with a large dose of enthusiasm early on. If we ever run into each other, the beers are on me!
+
+In no particular order:
 
 Aaron Endsley, Aaron Hans, Aaron Olson, Aaron Wells, Adam Rackis, Adi Purnama Mutiara, Adrian Li, Adrian Rand, Agustin Nicolas Polo, Alan Chandler, Alasdair Shepherd, Alejandro Nanez O, Alexis Mills, Allen Dean, Anastasios Alexiou, Andrea Giammarchi, Andres Mijares, Andrew Broman, Andrew Kenward, Andrew Shell, Andrew Van Slaars, Andrey Golovin, Angel Ramirez Morel, Anna Vu, Anselm Hannemann, Anthony Casson, Arnau Pujol, Arnis Lupiks, Artur Jonczyk", Aziz Khoury, Barney Scott, Beau Cronin, Ben Lagoutte, Ben Mann, Benjamin Bank, benjamintpoon, Benny Neugebauer, Bishal Pantha, Bran Sorem, Brent Huffman, Bruce Hyatt, Burton Podczerwinski, Béla Varga, Ca-Phun Ung, Cameron Stark, Carlos López, Casper de Rooij, Chad Thoreson, Charles Herman, Charles Rector, Charlie Hill, Chase Hagwood, Chris Fothergill, chris weber, Christopher Dresel, Christopher Gonzales, Christopher Hamilton, Christopher Scott, Cindy Juarez, Claudia Hernández, Constantin Chirila, Cris Ryan Tan, Dallen Richard Loder, Dan Hayden, Dan M., Dan Perrera, Dan Rocha, Daniel Cloud, Daniel Egger, Daniel Sleeth, David Ershag, David G. Chaves, David González Polán, David Hobbs, David Lemarier, Dayan Barros, Dejan Cencelj, Denise Darmawi, Derick Rodriguez, Derik Badman, Dick Grayson, Dmitry Goryunov, Don Hamilton III, Donald Gary, Doug Chase, Dumitru Florin Gabriel, Eder Sánchez, Edgar Barrantes, Edouard Baudry, Eduardo Rabelo, Eric Lezotte, Ersan Temizyurek, Ezequiel Cabrera, Fabian Marz, Fabio Vedovelli, Fabrice Le Coz, Federico Foresti, Fer To, Fernando Ripoll Lafuente, Flavio Spaini, Fran Nunez, Francesco Strappini, Francisco Cerdas, Fredrik Forsmo, Fredrik Lexberg, Gabor Dolla, Gabriel Chertok, Gabriel García Seco, Gergo Szonyi, Giovanni Londero, glennjonesnet, Gorshunov Vladimir, Guy Tepper, Hamish Macpherson, Hanslutter Fomben, Henk Jan van Wijk, Hernan Chiosso, Horváth László Gábor, Hugo Lopes, Ian B. De La Cruz, Ian Doyle, Ian McCausland, Ignacio Anaya, Istvan Szmozsanszky, Ivan Saveliev, Ivan Tanev, J. Singh, jack pallot, Jack W McNicol, Jaime García, Jake Smith, Janderson Martins, Jani Kraner, Jared Moran, Jason Broyles, Jason Finch, Jean Osorio, Jeffrey Borisch, Jelena Jovanovic, Jennifer Dixon, Jeremy Tymes, Jeremy Wilken, Jia Fei Fei, Jiaxing Wang, Joachim Kliemann, Joan Maria Talarn, Johannes Weiser, John Engstrom, john fogarty, John Johnson, Jon Saw, Jonathan Boiser, Joostc Schermers, Josh Adam, Josh Magness, José Esparza, jsnisenson, Juan Lopez, Junrou Nishida, Jörn Flath, Karthikeya Pammi, Kevin Gimbel, Kevin Rambaud, Kevin Scheffelmeier, Kevin Youkhana, kgarbaya, konker, Kostas Galanos, Kris Bulman, Kyle Simpson, Lalit Agrawala, Lea P., Leonardo Di Lella, Lidor Lapid, mailtorenil, Marc Grabanski, Marco Martins, marco.scarpa, Marcus Bransbury, Mariano Campo, Mark Kramer, Martijn Rouwendal, Martin Ansty, Martin Gonzalez, Martin Luna, Massimiliano Filacchioni, Mathias Bynens, Matt Riley, Matt Webb, Matteo Hertel, Matthew Bagwell, Mauro Gestoso, Max Felgenhauer, Maxwell Chiareli, Michael Chan, Michael Erdey, Michael Klose, Michael Kühnel, Michael Spreu, Michael Vezzani, Mike Kidder, Mike Parsons, Mitchell Gates, Nathan Heskew, Nathan Schlehlein, Nick Dunn, Nick Klunder, Nicolás Isnardi, Norbert Sienkiewicz, Oliver Wehn, Olivier Camon, Olivier Van hamme, Owen Densmore, P. Ghinde, Patrick Nouvion, Patrick Thompson, Paul Aeria, Paul Albertson, Paul Cooper, Paul Grock, Paul Kalupnieks, Paul Kamma, Paul Vernon, Paula Penedo Barbosa, Paulo Elias, Per Fröjd, Peter deHaan, Peter Holzer, Peter Piekarczyk, peterdoane, Phan An, Piotr Seefeld, Pranava S Balugari, Rahul Ravikumar, Randy Ferrer, Renato Alonso, Rey Bango, Reynaldo Tortoledo, Ric Johnson, Ricardo Pereira, Richard Davey, Richard Hoffmann, Richard Weltman, Riyadh Al Nur, Robert Buchholz, Ron Male, Ryan Castner, Ryan Ewing, Rylan Cottrell, Salvatore Torcivia, Sean Esteva, Sebastian Brieschenk, Sergey Efremov, Sergey Melnikov, Shane Eckel, Shaunak Kashyap, Shawn Searcy, Simeon Vincent, simonkeary, Stefan Boehm, Steve Mahony, Steven Kingston, Stoyan Delev, Stuart Robson, Sumit Sarkar, Swizec Teller, Szabolcs Legradi, Tanner Donovan, Ted Young, Thee Sritabtim, Thomas Noe, Thomas Schwarz, Tim Goshinski, Tim Osborn, Tim Pietrusky, Tony Brown, Tudosa Razvan, Ture Gjørup, Umar Farooq Khawaja, Uri Chandler, Victor Rosell, Vinay Puppal, Vladimir Bruno, Vladimir Simonov, Vladimir Zeifman, Wayne Callender, Wayne Patterson, Wee Keat Liew, Wes Bos, Wonmin Jeon, Yann LE CORRE, Yevgen Safronov, Yonatan Mevorach, youbiteme, Zach Gottlieb, Zachary Hawkins, Zane Thomas, 坤福 曾, @agolveo, @amstarri, @bondydaa, @cbergenhem, @cde008, @changke, @dhtrinh02, @dlteron.green, @eduplessis, @eonilsson, @fogarty.tj, @fortune, @gm.schlereth, @illusionmh, @jcnoble2, and @michael!
 

From 54541e86e6b233cdad20adfc53506dace91f3abd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Mon, 2 Jul 2018 16:45:35 -0300
Subject: [PATCH 60/71] update heading

---
 chapters/ch01.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch01.asciidoc b/chapters/ch01.asciidoc
index 08b63b4..11968cd 100644
--- a/chapters/ch01.asciidoc
+++ b/chapters/ch01.asciidoc
@@ -233,7 +233,7 @@ When we don't plan in such a long-term form, an interesting thing occurs: our sy
 
 We'll devote an important part of this book to understanding how we can identify and leverage the right abstractions at the right time, so that the risk they incur is minimized.
 
-=== 1.5 Why Modular JavaScript?
+=== 1.5 Modular JavaScript: A Necessity
 
 Due to its history, JavaScript is particularly interesting when it comes to modular design. In the early days of the web, and for a long time, there weren't any established practices and few people knew the language beyond showing alert boxes. As a highly dynamic language that wasn't yet mature enough, JavaScript was at an odd place between statically typed languages like Java or C#, and more heavily used dynamic languages like Python or PHP.
 

From 9b22c0020128cc54c79056417dc424e43e7ae2b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Sun, 23 Sep 2018 20:46:00 -0300
Subject: [PATCH 61/71] fix typo

---
 chapters/ch03.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch03.asciidoc b/chapters/ch03.asciidoc
index 961169d..5f8469c 100644
--- a/chapters/ch03.asciidoc
+++ b/chapters/ch03.asciidoc
@@ -41,7 +41,7 @@ Abstractions aren't free, but they can shield portions of code from complexity.
 
 When we're weighing whether to offer an interface like CSS selectors or callbacks, we're deciding how much we want to abstract, and how much we want to leave up to the consumer. When we choose to let the user provide CSS selectors, we keep the interface short, but the use cases will be limited as well. Consumers won't be able, for example, to decide dynamically whether the element is draggable or not beyond what a CSS selector can offer. When we choose to let the user provide callbacks, we make it harder for them to use our interface, since they now have to provide bits and pieces of the implementation themselves, but that expense buys them great flexibility in how to decide what is draggable and what is not.
 
-As most things in program design, API design is a constant tradeoff between simplicity and flexibility. For each particular case, it is our responsibility to decide how flexible we want the interface to be, but at the expense of simplicity. We can also decide how simple we want an interface to be, but at the expense of flexibility. Going back to jQuery, it's interesting to note how they always favor simplicity, by allowing you to provide as little information as needed for most of their API methods. Meanwhile, they avoid sacrificing flexibility by offering countless overloads for each of their API methods. The complexity lies in their implementation, balancing arguments by figuring out whether they're a `NodeList`, a DOM element, an array, a function, a selector, or something else, -- not to mention optional parameters -- before even starting to fulfill the consumer's goal when making an API call. Consumers observe some of the complexity at the seams, when sifting through documentation and finding out about all the different ways of accomplishing the same goals. And yet, despite all of jQuery's internal complexity, code which consumes the jQuery API manages to stay ravashingly simple.
+As most things in program design, API design is a constant tradeoff between simplicity and flexibility. For each particular case, it is our responsibility to decide how flexible we want the interface to be, but at the expense of simplicity. We can also decide how simple we want an interface to be, but at the expense of flexibility. Going back to jQuery, it's interesting to note how they always favor simplicity, by allowing you to provide as little information as needed for most of their API methods. Meanwhile, they avoid sacrificing flexibility by offering countless overloads for each of their API methods. The complexity lies in their implementation, balancing arguments by figuring out whether they're a `NodeList`, a DOM element, an array, a function, a selector, or something else, -- not to mention optional parameters -- before even starting to fulfill the consumer's goal when making an API call. Consumers observe some of the complexity at the seams, when sifting through documentation and finding out about all the different ways of accomplishing the same goals. And yet, despite all of jQuery's internal complexity, code which consumes the jQuery API manages to stay ravishingly simple.
 
 ==== 3.1.2 Design for Today
 

From c906a28ab1ab541622bf9b01ff37a45613b2516d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20Bevacqua?= <nicolasbevacqua@gmail.com>
Date: Mon, 24 Sep 2018 19:14:24 -0300
Subject: [PATCH 62/71] Update screenshot in readme to reflect MMJ web content

---
 readme.md | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/readme.md b/readme.md
index 1f93376..32d9cd3 100644
--- a/readme.md
+++ b/readme.md
@@ -20,7 +20,7 @@ This book focuses on two aspects of JavaScript development: modularity and lever
 
 The book is publicly available in HTML format and **free forever**. Each book chapter is styled similarly to how Pony Foo blog posts _— such as the [book series launch announcement][announcement] —_ are styled, which makes for a fairly enjoyable read as far as HTML books go.
 
-[<img align='left' src='https://i.imgur.com/8R8wBTQ.png' />][toc]
+[<img align='left' src='https://i.imgur.com/iA9ak4K.png' />][toc]
 
 *Every book in the series will be distributed in this way.*
 
@@ -30,6 +30,10 @@ It took me a bit of time but I've managed to get the `git` repository to trigger
 
 _**Read** the [HTML version of the book][toc] on Pony Foo! 🦄_
 
+<br>
+<br>
+<br>
+
 ## Source Code Repository!
 
 I want this book series to be as widely available as possible, and the best course of action for that purpose was to release the vast majority of its contents to the open-source community.

From d2b22276f3e9fcfdb1887f9f224e09222bad5b28 Mon Sep 17 00:00:00 2001
From: Tiago Hermano <tiagofhermano@gmail.com>
Date: Sun, 30 Sep 2018 19:44:51 -0300
Subject: [PATCH 63/71] fixed grammar typos

---
 chapters/ch06.asciidoc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/chapters/ch06.asciidoc b/chapters/ch06.asciidoc
index c15cf42..f0239ef 100644
--- a/chapters/ch06.asciidoc
+++ b/chapters/ch06.asciidoc
@@ -173,7 +173,7 @@ Every dependency in our application should be explicitly declared in our manifes
 
 Using the information in a package lock file, which contains details about every package we depend upon and all of their dependencies as well, package managers can take steps to install the same bits every time, preserving our ability to quickly iterate and install package updates, while keeping our code safe.
 
-Always installing identical versions of our dependencies -- and identical versions of our dependencies' dependencies -- brings us one step closer to having development environments that closely mirror what we do in production. This increases the likelyhood we can swiftly reproduce bugs that occurred in production in our local environments, while decreasing the odds that something that worked during development fails in staging.
+Always installing identical versions of our dependencies -- and identical versions of our dependencies' dependencies -- brings us one step closer to having development environments that closely mirror what we do in production. This increases the likelihood we can swiftly reproduce bugs that occurred in production in our local environments, while decreasing the odds that something that worked during development fails in staging.
 
 === 6.3 Interfaces as Black Boxes
 
@@ -219,7 +219,7 @@ State is almost ubiquitous, and practically a synonym of applications, because a
 
 When a request results in a long running job (such as sending out an email campaign, modifying records in a persistant database, etc), it's best to hand that off into a separate service that -- again -- mostly keeps state regarding said job. Separating services into specific needs means we can keep web servers lean, stateless, and improve our flows by adding more servers, persistent queues (so that we don't drop jobs), and so on. When every task is tethered together through tight coupling and state, it could become challenging to maintain, upgrade, and scale a service over time.
 
-Derived state in the form of caches is not uncmoon in the world of web servers. In the case of a personal website with some books available for download, for instance, we might be tempted to store the PDF representation of each book in a file, so that we don't have to recompile the PDF whenever the corresponding `/book` route is visited. When the book is updated, we'd recompute the PDF file and flush it to disk again, so that this derived state remains fresh. When our web server ceases to be single-node and we start using a cluster of several nodes, however, it might not be so trivial to broadcast the news about books being updated across nodes, and thus it'd be best to leave derived state to the persistance layer. Otherwise, a web server node might receive the request to update a book, perform the update and recompute the PDF file on that node, but we’d be failing to invalidate the PDF files being served by other nodes, which would have, and continue to serve stale copies of the PDF representation.
+Derived state in the form of caches is not uncommon in the world of web servers. In the case of a personal website with some books available for download, for instance, we might be tempted to store the PDF representation of each book in a file, so that we don't have to recompile the PDF whenever the corresponding `/book` route is visited. When the book is updated, we'd recompute the PDF file and flush it to disk again, so that this derived state remains fresh. When our web server ceases to be single-node and we start using a cluster of several nodes, however, it might not be so trivial to broadcast the news about books being updated across nodes, and thus it'd be best to leave derived state to the persistance layer. Otherwise, a web server node might receive the request to update a book, perform the update and recompute the PDF file on that node, but we’d be failing to invalidate the PDF files being served by other nodes, which would have, and continue to serve stale copies of the PDF representation.
 
 A better alternative in such a case would be to store derived state in a data store like Redis or Amazon S3, either of which we could update from any web server, and then serving precomputed results from Redis directly. In this way we'd still be able to access the latency benefits of using precomputed derived state, but at the same time we'd stay resilient when these requests or updates can happen on multiple web server nodes.
 
@@ -268,13 +268,13 @@ Proper integration testing might catch many of these kinds of mistakes, but that
 
 Eager abstraction can result in catastrophe. Conversely, failure to identify and abstract away sources of major complexity can be incredibly costly as well. When we consume complex interfaces directly, but don't necessarily take advantage of all the advanced configuration options that interface has to offer, we are missing out on a powerful abstraction we could be using. The alternative would be to create a middle layer in front of the complex interface, and have consumers go through that layer instead.
 
-This intermediate layer would be in charge of calling the complex abstraction itself, but offers a simpler interface with less configuration options and improved ease of use for the use cases that matter to us. Often, complicated or legacy interfaces demand that we offer up data that could be derived from other parameters being passed into the function call. For example, we might be asked how many adults, how many children, and how many people in total are looking to make a flight booking, even though the latter can be derived from the former. Other examples include expecting fields to be in a particular string format (such as a date string that could be derived from a native JavaScript date instead), using nomenclature that's relevant to the implmentation but not so much to the consumer, or a lack of sensible defaults (required fields which are rarely changed into anything other than a recommended value that isn't set by default).
+This intermediate layer would be in charge of calling the complex abstraction itself, but offers a simpler interface with less configuration options and improved ease of use for the use cases that matter to us. Often, complicated or legacy interfaces demand that we offer up data that could be derived from other parameters being passed into the function call. For example, we might be asked how many adults, how many children, and how many people in total are looking to make a flight booking, even though the latter can be derived from the former. Other examples include expecting fields to be in a particular string format (such as a date string that could be derived from a native JavaScript date instead), using nomenclature that's relevant to the implementation but not so much to the consumer, or a lack of sensible defaults (required fields which are rarely changed into anything other than a recommended value that isn't set by default).
 
 When we're building out a web application which consumes a highly parametized API in order to search for the cheapest hassle-free flights -- to give an example -- and we anticipate consuming this API in a few different ways, it would cost us dearly not to abstract away most of the parameters demanded by the API which do not fit our use case. This middle layer can take care of establishing sensible default values and of converting reasonable data structures such as native JavaScript dates or case insensitive airport codes into the formats demanded by the API we're using.
 
 In addition, our abstraction could also take care of any follow up API calls that need to be made in order to hydrate data. For example, a flight search API might return an airline code for each different flight, such as AA for American Airlines, but a UI consumer would also necessitate to hydrate AA into a display name for the airline, accompanied by a logo to embed on the user interface, and perhaps even a quick link to their check-in page.
 
-When we call into the backing API every time, with the full query, appeasing its quirks and shortcomings instead of taking the abstracted approach, it will not only be difficult to maintain an application that consumes those endpoints in more than one place, but it will also become a challenge down the road, when we want to include results from a different provider, which of course would have their own set of quirks and shortcomings. At this point we would have two separate sets of API calls, one for each provider, and each massaging the data to accomodate provider-specific quirks in a module which shouldn't be concerned with such matters, but only the results themselves.
+When we call into the backing API every time, with the full query, appeasing its quirks and shortcomings instead of taking the abstracted approach, it will not only be difficult to maintain an application that consumes those endpoints in more than one place, but it will also become a challenge down the road, when we want to include results from a different provider, which of course would have their own set of quirks and shortcomings. At this point we would have two separate sets of API calls, one for each provider, and each massaging the data to accommodate provider-specific quirks in a module which shouldn't be concerned with such matters, but only the results themselves.
 
 A middle layer could leverage a normalized query from the consumer, such as the one where we took a native date and then format it when calling the flight search API, and then adapt that query into either of the backing services that actually produce flight search results. This way, the consumer only has to deal with a single, simplified interface, while having the ability to seamlessly interact with two similar backing services that offer different interfaces.
 

From db428588657e14aaf8aeb86432bd28582a5169d4 Mon Sep 17 00:00:00 2001
From: Tiago Hermano <tiagofhermano@gmail.com>
Date: Sun, 30 Sep 2018 20:02:40 -0300
Subject: [PATCH 64/71] fixed grammar typo

changed 'ellapses' to 'elapses'
---
 chapters/ch04.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch04.asciidoc b/chapters/ch04.asciidoc
index 5f46bcf..bd40f49 100644
--- a/chapters/ch04.asciidoc
+++ b/chapters/ch04.asciidoc
@@ -719,6 +719,6 @@ Splitting logic into a few files under the same directory helps us prevent an ex
 
 The alternative, placing logic related to a particular aspect of our application such as blog posts directly in the components where it's needed, will cause trouble if left unchecked. Doing so might be beneficial in terms of short-term productivity, but longer-term we need to worry about coupling logic, strictly related to blog posts in this case, together with entirely different concerns. At the same time, if we sprinkle a bulk of the logic across several unrelated components, we become at risk of missing critical aspects of functionality when making large-scale updates to the codebase, and because of this we might end up making the wrong assumptions, or mistakes that only become evident much further down the line.
 
-It's acceptable to start out placing logic directly where it's needed at first, when it's unclear whether the functionality will grow or how much. Once this initial exploratory period ellapses, and it becomes clear the functionality is here to stay and more might be to come, it's advisable that we isolate the functionality for the reasons stated above. Later, as the functionality grows in size and in concerns that need to be addressed, we can componentize each aspect into different modules that are still grouped together logically in the file system, making it easy to take all of interrelated concerns into account when need be.
+It's acceptable to start out placing logic directly where it's needed at first, when it's unclear whether the functionality will grow or how much. Once this initial exploratory period elapses, and it becomes clear the functionality is here to stay and more might be to come, it's advisable that we isolate the functionality for the reasons stated above. Later, as the functionality grows in size and in concerns that need to be addressed, we can componentize each aspect into different modules that are still grouped together logically in the file system, making it easy to take all of interrelated concerns into account when need be.
 
 Now that we have broken down the essentials of module design and how to delineate interfaces, as well as how to lockdown, isolate, and drive down complexity in our internal implementations, we're ready to start discussing JavaScript-specific language features and an assortment of patterns that we can benefit from.

From 74c6b8b4256ae9331fa3c58369b66b31ada2b20f Mon Sep 17 00:00:00 2001
From: Mindaugas Macevicius <Mindaugas Macevicius>
Date: Mon, 1 Oct 2018 12:36:49 +0200
Subject: [PATCH 65/71] fix typo

---
 chapters/ch02.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch02.asciidoc b/chapters/ch02.asciidoc
index 2afea77..e27287b 100644
--- a/chapters/ch02.asciidoc
+++ b/chapters/ch02.asciidoc
@@ -353,7 +353,7 @@ Humans excell at identifying patterns, and we do so while reading as well. That'
 
 When a set of functions has the same API shape, consumers can intuitively deduce how the next function is used. Consider the native `Array`, where `#forEach`, `#map`, `#filter`, `#find`, `#some`, and `#every` all accept a callback as their first parameter and optionally take the context when calling that callback as their second parameter. Further, the callback receives the current `item`, that item's `index`, and the `array` itself as parameters. The `#reduce` and `#reduceRight` methods are a little different in that the callback receives an `accumulator` parameter in the first position, but then it goes on to receive the current `item`, that item's `index`, the `array`, making the shape quite similar to what we are accustomed to.
 
-The result is we rarely need to reach for documentation in order to understand how these functions are shaped. The difference lies solely in how the consumer-provided callback is used, and what the return value for the method is. `#forEach` doesn't return a value. `#map` returns the result of each invocation, `#filter` returns only the items for which the callback returned a truthy value. `#some` returns `false` unless the callback returns a truthy value for one of the items, in which case it returns `true` and breaks out of the look. `#every` returns `false` unless the callback returns a truthy value for every item, in which case it returns `true`.
+The result is we rarely need to reach for documentation in order to understand how these functions are shaped. The difference lies solely in how the consumer-provided callback is used, and what the return value for the method is. `#forEach` doesn't return a value. `#map` returns the result of each invocation, `#filter` returns only the items for which the callback returned a truthy value. `#some` returns `false` unless the callback returns a truthy value for one of the items, in which case it returns `true` and breaks out of the loop. `#every` returns `false` unless the callback returns a truthy value for every item, in which case it returns `true`.
 
 When we have different shapes for functions that perform similar tasks, we need to make an effort to remember each individual function's shape instead of being able to focus on the task at hand. Consistency is valuable on every level of a codebase: consistent code style reduces friction among developers and conflicts when merging code, consistent shapes optimize readability and give way to intuition, consistent naming and architecture reduces surprises and keeps code uniform.
 

From 6ab1e1ccc5d2cd1833f241eb0e60a37b4f895bb7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Th=C3=A9o=20Dammaretz?= <theo@dammaretz.fr>
Date: Thu, 4 Oct 2018 11:43:12 +0200
Subject: [PATCH 66/71] Fix chapter 2 forgotten await

Body.json() return a Promise. WIthout the await there, it would log a pending Promise.

https://developer.mozilla.org/en-US/docs/Web/API/Body/json
---
 chapters/ch02.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch02.asciidoc b/chapters/ch02.asciidoc
index e27287b..42a5918 100644
--- a/chapters/ch02.asciidoc
+++ b/chapters/ch02.asciidoc
@@ -464,7 +464,7 @@ If we want to take things a bit further, we can chain onto the response object t
 [source,javascript]
 ----
 const res = await fetch('/api/users/john')
-const data = res.json()
+const data = await res.json()
 console.log(data.name)
 // <- 'John Doe'
 ----

From f3a355afda8f4d87a19e4b65aafcb08ca037b493 Mon Sep 17 00:00:00 2001
From: Mindaugas Macevicius <40419643+api-xplr@users.noreply.github.com>
Date: Wed, 10 Oct 2018 11:41:13 +0200
Subject: [PATCH 67/71] fixed typos and inacurracies (#17)

* added space between words

* correct function name

* fix typo

* Reverted
---
 chapters/ch04.asciidoc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/chapters/ch04.asciidoc b/chapters/ch04.asciidoc
index bd40f49..d4b4ed2 100644
--- a/chapters/ch04.asciidoc
+++ b/chapters/ch04.asciidoc
@@ -48,7 +48,7 @@ When we'd have to repeat ourselves by passing a lot of scope variables as functi
 
 ==== 4.1.3 Frameworks: the Good the Bad and the Ugly
 
-Conventions are useful because they allow for better self-direction amongst developers, without causing lagoons of inconsistency to spread across our codebase as fate would have it were we to allow a team of developers too much freedom without sound design direction and conventions that dictatehow different portions of an application should be shaped. A large number of conventions might hinder productivity, especially if some of our conventions appeared to work as if by magic.
+Conventions are useful because they allow for better self-direction amongst developers, without causing lagoons of inconsistency to spread across our codebase as fate would have it were we to allow a team of developers too much freedom without sound design direction and conventions that dictate how different portions of an application should be shaped. A large number of conventions might hinder productivity, especially if some of our conventions appeared to work as if by magic.
 
 When it comes to conventions, frameworks are a special case. Frameworks are packed to the brim with conventions and best practices. Some of them live in the library and tooling ecosystem around the framework, while many live in the shape our code takes when we rely on said framework. Upon adopting a framework, we're buying into its conventions and practices. Most modern JavaScript frameworks offer ways of breaking our application into small chunks, regardless of whether the framework is for the client or server.
 
@@ -320,7 +320,7 @@ a(function () {
 })
 ----
 
-The foremost problem with this kind of structure is scope inheritance. In the deepest callback, passed to the `g` function, we've inherited the combined scopes of all the parent callbacks. As functions become larger, and more variables are bound into each of these scopes, it becomes ever more challenging to understand one of the callbacks in isolation from its parents.
+The foremost problem with this kind of structure is scope inheritance. In the deepest callback, passed to the `d` function, we've inherited the combined scopes of all the parent callbacks. As functions become larger, and more variables are bound into each of these scopes, it becomes ever more challenging to understand one of the callbacks in isolation from its parents.
 
 This kind of coupling can be reverted by naming the callbacks and placing them all in the same nesting level. Named functions may be reused in other parts of our component, or exported to be used elsewhere. In the following example we've eliminated up to 3 levels of unnecessary nesting, and by eliminating nesting we've made the scope for each function more explicit.
 

From d768a1ef308f00a69d050a76bf2ff08d36a8de70 Mon Sep 17 00:00:00 2001
From: Nick Rance <nick_rance89@hotmail.com>
Date: Tue, 16 Oct 2018 02:25:57 +0100
Subject: [PATCH 68/71] typos (#19)

typos
---
 chapters/ch02.asciidoc | 2 +-
 chapters/ch03.asciidoc | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/chapters/ch02.asciidoc b/chapters/ch02.asciidoc
index 42a5918..13051af 100644
--- a/chapters/ch02.asciidoc
+++ b/chapters/ch02.asciidoc
@@ -446,7 +446,7 @@ On the same vein, we should avoid optional input parameters which transform the
 
 It isn't necessary to treat failure and success with the same response shape, meaning that failure results can always be `null` or `undefined`, while success results might be an array list. However, consistency should be required across all failure cases and across all sucess cases, respectively.
 
-Having consistent data types mitigates surpises and improves the confidence a consumer has in our API.
+Having consistent data types mitigates surprises and improves the confidence a consumer has in our API.
 
 ==== 2.2.4 Simplicity
 
diff --git a/chapters/ch03.asciidoc b/chapters/ch03.asciidoc
index 5f8469c..732eb25 100644
--- a/chapters/ch03.asciidoc
+++ b/chapters/ch03.asciidoc
@@ -1,7 +1,7 @@
 [[module-design]]
 == Module Design
 
-Thinking in terms of API-driven and documentation-driven design will yield more usable modules than not doing so. You might argue that internals are not that important: "as long as the interface holds, we can put anything we want in the mix!". A usable interface is only one side of the equation; it will do little to keep the maintainability of your applications in check. Properly designed module internals help keep our code readable and its intent clear. In this chapter we'll debate what it takes to write modules with scalability in mind, but without getting too far ahead of our current requirements. We'll discuss the CRUST constraints in some more depth, and finally ellaborate on how to prune modules as they become larger and more complex over time.
+Thinking in terms of API-driven and documentation-driven design will yield more usable modules than not doing so. You might argue that internals are not that important: "as long as the interface holds, we can put anything we want in the mix!". A usable interface is only one side of the equation; it will do little to keep the maintainability of your applications in check. Properly designed module internals help keep our code readable and its intent clear. In this chapter we'll debate what it takes to write modules with scalability in mind, but without getting too far ahead of our current requirements. We'll discuss the CRUST constraints in some more depth, and finally elaborate on how to prune modules as they become larger and more complex over time.
 
 === 3.1 Growing a Module
 
@@ -111,7 +111,7 @@ Even when the smaller component isn't being reused anywhere else, and perhaps no
 
 Chopping up internals doesn't merely only work for view components and their children. That said, view components pose a great example that might help us visualize how complexity can remain flat across a component system, regardless of how deep we go, instead of being contained in a large component with little structure and a high-level of complexity or coupling. This is akin to looking at the universe on a macroscopic level and then taking a closer look, until we get to the atomic level, and then beyond. Each layer has its own complexities and intricacies waiting to be discovered, but the complexity is spread across the layers rather than clustered on any one particular layer. The spread reduces the amount of complexity we have to observe and deal with on any given layer.
 
-Speaking of layers, it is at this stage of the design process that you might want to consider defining different layers for your application. You might be used to having models, views, and controllers in MVC applications, or maybe you're accustomed to actions, reducers, and selectors in Redux applications. Maybe you should think of implemeting a service layer where all the business logic occurs, or perhaps a persistance layer where all the caching and persistent storage takes place.
+Speaking of layers, it is at this stage of the design process that you might want to consider defining different layers for your application. You might be used to having models, views, and controllers in MVC applications, or maybe you're accustomed to actions, reducers, and selectors in Redux applications. Maybe you should think of implementing a service layer where all the business logic occurs, or perhaps a persistance layer where all the caching and persistent storage takes place.
 
 When we're not dealing with modules which we ought to shape in a certain way, like views, but modules that can be composed any which way we choose, like services, we should consider whether new features belong in an existing module or in an entirely new module. When we have a module which wraps a Markdown parsing library adding functionality such as support for emoji expansions, and want an API that can take the resulting HTML and strip out certain tags and attributes, should we add that functionality to the Markdown module or put it in a separate module?
 
@@ -155,11 +155,11 @@ We can't prevent this from happening over and over -- not entirely. Unexpected b
 
 What we can do is mitigate the risk of bugs by writing more predictable code or improving test coverage. We can also become more proficient at debugging.
 
-On the predictable code arena, we must be sure to handle every expected error. When it comes to error handling we typically will bubble the error up the stack and handle it at the top, by logging it to an analytics tracker, to standard output, or to a database. When using a function call we know might throw, like `JSON.parse` on user input, we should wrap it with `try`/`catch` and handle the error, again bubbling it up to the consumer if our inability to proceed with the function logic is final. If we're dealing with conventional callbacks that have an error argument, let's handle the error in a guard clause. Whenever we have a promise chain, make sure to add a `.catch` reaction to the end of the chain that handles any errors ocurring in the chain. In the case of `async` functions, we could use `try`/`catch` or, alternatively, we can also add a `.catch` reaction to the result of invoking the async function. While leveraging streams or other conventional event-based interfaces, make sure to bind an `error` event handler. Proper error handling should all but eliminate the chance of expected errors crippling our software. Simple code is predictable. Thus, following the suggestions in chapter 4 will aid us in reducing the odds of encountering unexpected errors as well.
+On the predictable code arena, we must be sure to handle every expected error. When it comes to error handling we typically will bubble the error up the stack and handle it at the top, by logging it to an analytics tracker, to standard output, or to a database. When using a function call we know might throw, like `JSON.parse` on user input, we should wrap it with `try`/`catch` and handle the error, again bubbling it up to the consumer if our inability to proceed with the function logic is final. If we're dealing with conventional callbacks that have an error argument, let's handle the error in a guard clause. Whenever we have a promise chain, make sure to add a `.catch` reaction to the end of the chain that handles any errors occurring in the chain. In the case of `async` functions, we could use `try`/`catch` or, alternatively, we can also add a `.catch` reaction to the result of invoking the async function. While leveraging streams or other conventional event-based interfaces, make sure to bind an `error` event handler. Proper error handling should all but eliminate the chance of expected errors crippling our software. Simple code is predictable. Thus, following the suggestions in chapter 4 will aid us in reducing the odds of encountering unexpected errors as well.
 
 Test coverage can help detect unexpected errors. If we have simple and predictable code, it's harder for unexpected errors to seep through the seams. Tests can further abridge the gap by enlarging the corpus of expected errors. When we add tests, preventable errors are codified by test cases and fixtures. When tests are comprehensive enough, we might run into unexpected errors in testing and fix them. Since we've already codified them in a test case, these errors can't happen again (a test regression) without our test suite failing.
 
-Regardless of how determined we are to develop simple, predictable, and throughly tested programs, we're still bound to run into bugs we hadn't expected. Tests exist mostly to prevent regressions, preventing us from running once again into bugs we've already fixed; and to prevent expected mistakes, errors we think might arise if we were to tweak our code in incorrect ways. Tests can do little to prognosticate and prevent software bugs from happening, however.
+Regardless of how determined we are to develop simple, predictable, and thoroughly tested programs, we're still bound to run into bugs we hadn't expected. Tests exist mostly to prevent regressions, preventing us from running once again into bugs we've already fixed; and to prevent expected mistakes, errors we think might arise if we were to tweak our code in incorrect ways. Tests can do little to prognosticate and prevent software bugs from happening, however.
 
 This brings us to the inevitability of debugging. Using step-through debugging and inspecting application state as we step through the code leading to a bug is an useful tool, but it will not help us debug our code any faster than we can diagnose exactly what is going on.
 

From 0e4544b404f19ce26047d414f7636841380160e1 Mon Sep 17 00:00:00 2001
From: Andrey Pelykh <10947577+andreypelykh@users.noreply.github.com>
Date: Tue, 30 Oct 2018 16:40:36 +0200
Subject: [PATCH 69/71] Update ch04.asciidoc (#20)

---
 chapters/ch04.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch04.asciidoc b/chapters/ch04.asciidoc
index d4b4ed2..dfea173 100644
--- a/chapters/ch04.asciidoc
+++ b/chapters/ch04.asciidoc
@@ -108,7 +108,7 @@ We could've used more variables without creating a function, inlining the comput
 
 [source,javascript]
 ----
-const hasToken = auth === undefined || auth.token === undefined
+const hasToken = auth !== undefined && auth.token !== undefined
 const hasValidToken = hasToken && auth.expires > Date.now()
 if (hasValidToken) {
   return

From 78d23dd0bc4fe9b7e95c70c66c3786381a3e2709 Mon Sep 17 00:00:00 2001
From: Milan Misak <1205297+MilanMisak@users.noreply.github.com>
Date: Thu, 17 Jan 2019 18:45:42 +0000
Subject: [PATCH 70/71] Fix a few chapter 4 typos (#21)

---
 chapters/ch04.asciidoc | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/chapters/ch04.asciidoc b/chapters/ch04.asciidoc
index dfea173..d9c12ba 100644
--- a/chapters/ch04.asciidoc
+++ b/chapters/ch04.asciidoc
@@ -56,7 +56,7 @@ Express has middleware and routes, Angular has directives, services, and control
 
 Eventually, we'll come into requirements that don't exactly fit the mold proposed by our framework of choice. Generally, this means the required functionality belongs on a separate layer. For example, Express in Node.js is a framework concerned with handling HTTP requests and serving responses. If one of our API endpoints needs to result in an email being sent, we could embed email-sending logic in the controller for that API endpoint. However, if an API endpoint controller is already concerned with, say, publishing blog posts, then it would be hardly right to embed email-sending logic on that same controller, since it's a different concern entirely. Instead, what we could do is create a `subscribers` service component, with functionality such as `subscribe` which adds a subscriber after verifying their email, and `notify` which takes care of sending the emails. Taking this idea further still, perhaps most of the work in `subscribers.notify` should occur via yet another service component called `emails`, which takes care of properly configuring our email sending capability, and also has functionality to turn would-be emails into plain `console.log` statements for quick access to the contents of the emails during debug sessions.
 
-Having clearly defined layers is paramount to the design of effective and maintainable applications once we're past the prototyping stages. Layers can be made up of components which follow the conventions proposed by the frameworks we use, or they can be self-imposed like the service layer we discussed in the previous paragraph. Using layers, and as long as we favor function parameters over scope for context-passing, we can introduce horizonal scaling by placing several orthogonal components alongside each other, without letting them run into each others' concerns.
+Having clearly defined layers is paramount to the design of effective and maintainable applications once we're past the prototyping stages. Layers can be made up of components which follow the conventions proposed by the frameworks we use, or they can be self-imposed like the service layer we discussed in the previous paragraph. Using layers, and as long as we favor function parameters over scope for context-passing, we can introduce horizontal scaling by placing several orthogonal components alongside each other, without letting them run into each others' concerns.
 
 === 4.2 Refactoring Complex Code
 
@@ -143,7 +143,7 @@ if (response) {
 
 In the example, we're optimizing readability for the success case, while the failure handling is relegated to the very end of our piece of code. There's several problems with this approach. For one, we have to indulge in unnecessary nesting of every success condition, or otherwise put them all in a huge conditional statement. While it's rather easy to understand the success case, things can get tricky when we're trying to debug programs like this, as we need to keep the conditionals in our head the whole time we're reading the program.
 
-A better alternative is to flip the conditionals, placing all failure handling statements near the top. While counterintuitive at first, this approach has several benefits. It reduces nesting and eliminates `else` branches while promoting failure handling to the top of our code, and this has the added benefit that we'll become more aware of error handling and naturally gravitate towards thinking about the failure cases first, a great trait to have when doing application development, where forgetting to handle a failure case might result in an incosistent experience for end users with a hard-to-trace error on top.
+A better alternative is to flip the conditionals, placing all failure handling statements near the top. While counterintuitive at first, this approach has several benefits. It reduces nesting and eliminates `else` branches while promoting failure handling to the top of our code, and this has the added benefit that we'll become more aware of error handling and naturally gravitate towards thinking about the failure cases first, a great trait to have when doing application development, where forgetting to handle a failure case might result in an inconsistent experience for end users with a hard-to-trace error on top.
 
 [source,javascript]
 ----
@@ -162,7 +162,7 @@ Another benefit of guard clauses is almost implicit: given that they're placed n
 
 Guard clauses don't tell the reader everything they need to know that might go wrong when calling a function, but they give them a peek into expected immediate failure cases. Other things that might go wrong lie in the implementation details of the function. Perhaps we use a different service or library to fulfill the bulk of our function's task, and that service or library comes with its own set of nested guard clauses and potential failure cases that will bubble up all the way to our own function's outcome.
 
-==== 4.2.3 An Interdependency Piramid
+==== 4.2.3 An Interdependency Pyramid
 
 Writing straightforward code is not all that different from writing other straightforward texts. Texts are often arranged in paragraphs, which are somewhat comparable with functions: we can consider their input to be the reader's knowledge and everything else they've read so far in the text, and the output can be what the reader gets out of the paragraph.
 
@@ -237,7 +237,7 @@ function getUserModels(done) {
 }
 ----
 
-Now compare that code to the following bit of code, where we extracted the mapping function and shoved it out of the way. Given the mapping function doesn't need any of the scope from `getUserModels`, we can pull it out of that scope entirely, without the need to place `toUserModel` at the bottom of the `getUserModels` function. This means we can now also reuse `toUserModel` in other routines, we don't have to wonder whether the function actually depends on any of the contaning scope's context anymore, and `getUserModels` is now focused on the higher level flow where we find users, map them to their models, and return them.
+Now compare that code to the following bit of code, where we extracted the mapping function and shoved it out of the way. Given the mapping function doesn't need any of the scope from `getUserModels`, we can pull it out of that scope entirely, without the need to place `toUserModel` at the bottom of the `getUserModels` function. This means we can now also reuse `toUserModel` in other routines, we don't have to wonder whether the function actually depends on any of the containing scope's context anymore, and `getUserModels` is now focused on the higher level flow where we find users, map them to their models, and return them.
 
 [source,javascript]
 ----
@@ -478,7 +478,7 @@ A similar situation occurs when we have a concurrent flow that remains more or l
 
 In other cases, we might notice how there's a few different components that all need the same piece of functionality. Commenting features often fall in this case, where different components like user profiles, projects, or artifacts, might need the ability to receive, show, edit, and delete comments. This case can be interesting because it's the business requirement is not always identified upfront, and we might embed the child feature into the parent component before realizing it'd be useful to extract the feature so that it can be reused in other parent components. While this sounds obvious in hindsight, it's not always clear when we'll need to reuse some functionality somewhere else, and keeping every aspect of functionality isolated just in case we need to reuse them can be costly in terms of time and development effort.
 
-More often than not, however, abstractions can end up complicating matters. It might be that the tradeoff isn't worth it because the code becomes much harder to read, or maybe because the underlying code isn't mature enough yet, or we don't know what special requirements we may end up with for other objects adopting similar functionality, meaning we're not comfortable creating an abstraction that could lead to unforeseen problems in the future.
+More often than not, however, abstractions can end up complicating matters. It might be that the trade-off isn't worth it because the code becomes much harder to read, or maybe because the underlying code isn't mature enough yet, or we don't know what special requirements we may end up with for other objects adopting similar functionality, meaning we're not comfortable creating an abstraction that could lead to unforeseen problems in the future.
 
 Whenever we are uncertain about whether an abstraction is up to muster, it pays to go back to the original piece of code we had before introducing the abstraction, and comparing the two pieces. Is the new piece easier to understand, modify, and consume? Would that still be the case as a newcomer? Try and consider how the outcome to those questions would change if you hadn't looked at this code in a while. Ask your co-workers for their opinion, too; given they haven't seen that code yet and they may end up having to consume it, they're great candidates to help decide which approach is better.
 
@@ -510,15 +510,15 @@ At its heart, state is mutable. Even if the variable bindings themselves are imm
 
 Consider a game of chess, where each of two players starts with 16 pieces, each deterministically assigned a position on a checkerboard. The initial state is always the same. As each player inputs their actions, moving and trading pieces, the system state mutates. A few moves into the game, there is a good chance we'll be facing a game state we haven't ever experienced before. Computer program state is a lot like a game of chess, except there's more nuance in the way of user input, and an infinitude of possible board positions and state permutations.
 
-In the world of web development, a human decides to open a new tab in their favorite web browser and they then google for "cat in a pickle gifs". The browser allocates a new process through a system call to the operating system, which shifts some bits around on the physical hardware that lies inside the human’s computer. Before the HTTP request hits the network, we need to hit DNS servers, engaging in the elaborate process of casting `google.com` into an IP address. The browser then checks whether there’s a ServiceWorker installed, and assuming there isn’t one the request finally takes the default route of querying Google’s servers for the phrase “cat in a pickle gifs”.
+In the world of web development, a human decides to open a new tab in their favorite web browser and they then google for "cat in a pickle gifs". The browser allocates a new process through a system call to the operating system, which shifts some bits around on the physical hardware that lies inside the human’s computer. Before the HTTP request hits the network, we need to hit DNS servers, engaging in the elaborate process of casting `google.com` into an IP address. The browser then checks whether there's a ServiceWorker installed, and assuming there isn't one the request finally takes the default route of querying Google’s servers for the phrase “cat in a pickle gifs”.
 
 Naturally, Google receives this request at one of the front-end edges of its public network, in charge of balancing the load and routing requests to healthy back-end services. The query goes through a variety of analyzers that attempt to break it down to its semantic roots, stripping the query down to its essential keywords in an attempt to better match relevant results.
 
 The search engine figures out the 10 most relevant results for “cat pickle gif” out of billions of pages in its index – which was of course primed by a different system that’s also part of the whole – and at the same time, Google pulls down a highly targeted piece of relevant advertisement about cat gifs that matches what they believe is the demographic the human making the query belongs to, thanks to a sophisticated ad network that figures out whether the user is authenticated with Google through an HTTP header session cookie and the search results page starts being constructed and streamed to the human, who now appears impatient and fidgety.
 
-As the first few bits of HTML being streaming down the wire, the search engine produces its results and hands them back to the front-end servers, which includes it in the HTML stream that’s sent back to the human. The web browser has been working hard at this too, parsing the incomplete pieces of HTML that have been streaming down the wire as best it could, even daring to launch other admirably and equally-mind-boggling requests for HTTP resources presumed to be JavaScript, CSS, font, and image files as the HTML continues to stream down the wire. The first few chunks of HTML are converted into a DOM tree, and the browser would finally be able to begin rendering bits and pieces of the page on the screen, weren't it for the pending, equally-mind-boggling CSS and font requests.
+As the first few bits of HTML being streaming down the wire, the search engine produces its results and hands them back to the front-end servers, which includes it in the HTML stream that's sent back to the human. The web browser has been working hard at this too, parsing the incomplete pieces of HTML that have been streaming down the wire as best it could, even daring to launch other admirably and equally-mind-boggling requests for HTTP resources presumed to be JavaScript, CSS, font, and image files as the HTML continues to stream down the wire. The first few chunks of HTML are converted into a DOM tree, and the browser would finally be able to begin rendering bits and pieces of the page on the screen, weren't it for the pending, equally-mind-boggling CSS and font requests.
 
-As the CSS stylesheets and fonts are transmitted, the browser begins modeling the CSSOM and getting a more complete picture of how to turn the HTML and CSS plain text chunks provided by Google servers into a graphical representation that the human finds pleasant. Browser extensions get a chance to meddle with the content, removing the highly targeted piece of relevant advertisement about cat gifs before I even realize Google hoped I wouldn’t block ads this time around.
+As the CSS stylesheets and fonts are transmitted, the browser begins modeling the CSSOM and getting a more complete picture of how to turn the HTML and CSS plain text chunks provided by Google servers into a graphical representation that the human finds pleasant. Browser extensions get a chance to meddle with the content, removing the highly targeted piece of relevant advertisement about cat gifs before I even realize Google hoped I wouldn't block ads this time around.
 
 A few seconds have passed by since I first decided to search for cat in a pickle gifs. Needless to say, thousands of others brought similarly inane requests. To the same systems. During this time.
 
@@ -526,13 +526,13 @@ Not only does this example demonstrate the marvelous machinery and infrastructur
 
 ==== 4.3.2 Eliminating Incidental State
 
-We've established that the overall state of a system has little to do with our ability to comprehend parts of that same system. Our focus in reducing state-based entropy must then lie in the individual aspects of the system. It’s for this reason that breaking apart large pieces of code is so effective. We’re reducing the amount of state local to each given aspect of the system, and that’s the kind of state that’s worth taking care of, since it’s what we can keep in our heads and make sense of.
+We've established that the overall state of a system has little to do with our ability to comprehend parts of that same system. Our focus in reducing state-based entropy must then lie in the individual aspects of the system. It's for this reason that breaking apart large pieces of code is so effective. We’re reducing the amount of state local to each given aspect of the system, and that's the kind of state that's worth taking care of, since it's what we can keep in our heads and make sense of.
 
-Whenever there's persistance involved, there's going to be a discrepancy between ephemeral state and realized state. In the case of a web application, we could define ephemeral state as any user input that hasn't resulted in state being persisted yet, as might be the case of an unsaved user preference that might be lost unless persisted. We can say realized state is the state that has been persisted, and that different programs might have different strategies on how to convert ephemeral state into realized state. A web application might adopt an Offline-First pattern where ephemeral state is automatically synchronized to an IndexedDB database in the browser, and eventually realized by updating the state persisted on a back-end system. When the Offline-First page is reloaded, unrealized state may be pushed to the back-end or discarded.
+Whenever there's persistence involved, there's going to be a discrepancy between ephemeral state and realized state. In the case of a web application, we could define ephemeral state as any user input that hasn't resulted in state being persisted yet, as might be the case of an unsaved user preference that might be lost unless persisted. We can say realized state is the state that has been persisted, and that different programs might have different strategies on how to convert ephemeral state into realized state. A web application might adopt an Offline-First pattern where ephemeral state is automatically synchronized to an IndexedDB database in the browser, and eventually realized by updating the state persisted on a back-end system. When the Offline-First page is reloaded, unrealized state may be pushed to the back-end or discarded.
 
 Incidental state can occur when we have a piece of data that's used in several parts of an application, and which is derived from other pieces of data. When the original piece of data is updated, it wouldn't be hard to inadvertently leave the derived pieces of data in their current state, making them stale when compared to the updated original pieces of data. As an example, consider a piece of user input in Markdown and the HTML representation derived from that piece of Markdown. If the piece of Markdown is updated but the previously compiled pieces of HTML are not, then different parts of the system might display different bits of HTML out of what was apparently the same single Markdown source.
 
-When we persist derived state, we're putting the original and the derived data at risk of falling out of sync. This isn't the case just when dealing with persistance layers, but can also occur in a few other scenarios as well. When dealing with caching layers, their content may become stale because the underlying original piece of content is updated but we forget to invalidate pieces of content derived from the updated data. Database denormalization is another common occurrence of this problem, whereby creating derived state can result in synchronization problems and stale byproducts of the original data.
+When we persist derived state, we're putting the original and the derived data at risk of falling out of sync. This isn't the case just when dealing with persistence layers, but can also occur in a few other scenarios as well. When dealing with caching layers, their content may become stale because the underlying original piece of content is updated but we forget to invalidate pieces of content derived from the updated data. Database denormalization is another common occurrence of this problem, whereby creating derived state can result in synchronization problems and stale byproducts of the original data.
 
 This lack of synchronization is often observed in discussion forum software, where user profiles are denormalized into comment objects in an effort to save a database roundtrip. When users update later update their profile, however, their old comments preserve an stale avatar, signature, or display name. To avoid this kind of issue, we should always consider recomputing derived state from its roots. Even though doing so won't always be possible, performant, or even practical, encouraging this kind of thinking across a development team will, if anything, increase awareness about the subtle intricacies of denormalized state.
 
@@ -542,7 +542,7 @@ As long as we're aware of the risks of data denormalization, we can then indulge
 
 State is inevitable. As we discussed in section 4.3.1, though, the full picture hardly affects our ability to maintain small parts of that state tree. In the local case -- each of the interrelated but ultimately separate pieces of code we work with in our day to day -- all that matters are the inputs we receive and the outputs we produce. That said, generating a large amount of output where we could instead emit a single piece of information is undesirable.
 
-When all intermediate state is contained inside a component instead of being leaked to others, we're reducing the friction in interacting with our component or function. The more we condense state into its smallest possible representation for output purposes, the better contained our functions will become. Incidentaly, we're making the interface easier to consume. Since there's less state to draw from, there's fewer ways of consuming that state. This reduces the amount of possible use cases, but by favoring composability over serving every possible need, we're making each piece of functionality, when evaluated on its own, simpler.
+When all intermediate state is contained inside a component instead of being leaked to others, we're reducing the friction in interacting with our component or function. The more we condense state into its smallest possible representation for output purposes, the better contained our functions will become. Incidentally, we're making the interface easier to consume. Since there's less state to draw from, there's fewer ways of consuming that state. This reduces the amount of possible use cases, but by favoring composability over serving every possible need, we're making each piece of functionality, when evaluated on its own, simpler.
 
 One other case where we may incidentally increase complexity is whenever we modify the property values of an input. This type of operation should be made extremely explicit, as to not be confused, and avoided where possible. If we assume functions to be defined as the equation between the inputs we receive and the outputs we produce, then the side-effects  are ill-advised. Mutations on the input within the body of a function is one example of side-effects, which can be a source of bugs and confusion, particularly due to the difficulty in tracking down the source for these mutations.
 
@@ -703,7 +703,7 @@ console.log(multiply(add(5, 3), 2)) // <- 16
 
 Taking this concept beyond basic mathematics, we can begin to see how this decoupling of form and function, or state and logic, can be increasingly beneficial. It's easier to serialize plain data over the wire, keep it consistent across different environments, and make it interoperable regardless of the logic, than if we tightly coupled data and the logic around it.
 
-Functions are, to a certain degree, hopelessly coupled to the data they receive as inputs: in order for the function to work as expected, the data it receives must satisfy its contract for that piece of input. Within the bounds of a function's proper execution, the data must have a certain shape, traits, or adhere to whatever restrictions the function has in place. These restrictions may be somewhat lax (e.g "must have a `toString` method"), highly specific (e.g "must be a function that accepts 3 arguments and returns a decimal number between 0 and 1"), or anywhere in between. A simple interface is usually highly restrictive (e.g accepting only a boolean value). Meanwhile, it's not uncommon for loose interfaces to become burdened by their own flexibility, leading to complex implementations that attempt to accomodate many different shapes and sizes of the same input parameter.
+Functions are, to a certain degree, hopelessly coupled to the data they receive as inputs: in order for the function to work as expected, the data it receives must satisfy its contract for that piece of input. Within the bounds of a function's proper execution, the data must have a certain shape, traits, or adhere to whatever restrictions the function has in place. These restrictions may be somewhat lax (e.g. "must have a `toString` method"), highly specific (e.g. "must be a function that accepts 3 arguments and returns a decimal number between 0 and 1"), or anywhere in between. A simple interface is usually highly restrictive (e.g. accepting only a boolean value). Meanwhile, it's not uncommon for loose interfaces to become burdened by their own flexibility, leading to complex implementations that attempt to accommodate many different shapes and sizes of the same input parameter.
 
 We should aim to keep logic restrictive and only as flexible as deemed necessary by business requirements. When an interface starts out being restrictive we can always slowly open it up later as new use cases and requirements arise, but by starting out with a small use case we're able to grow the interface into something that's naturally better fit to handle specific, real-world use cases.
 

From f2ee2e6fbdb8b5666504f76d3cebd500b69e3647 Mon Sep 17 00:00:00 2001
From: Shay Cojocaru <shayc@outlook.com>
Date: Wed, 14 Oct 2020 20:54:41 +0300
Subject: [PATCH 71/71] fix: remove excess 'the' (#22)

---
 chapters/ch02.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chapters/ch02.asciidoc b/chapters/ch02.asciidoc
index 13051af..edbbe96 100644
--- a/chapters/ch02.asciidoc
+++ b/chapters/ch02.asciidoc
@@ -285,7 +285,7 @@ When a commonality can be found, abstractions involve less friction and help avo
 
 Another case where abstractions come in handy might be whenever we are dealing with quirks in cross-browser DOM manipulation. Having a function like `on(element, eventType, eventListener)` would be superior than testing whether `addEventListener` is supported and deciding which of the various event listening options is optimal for each case, every time, as it drastically reduces code duplication while also handling every case consistently, limiting complexity.
 
-The above are clear-cut examples of cases when an abstraction greatly improves poor interfaces, but that's not always the end result. Abstractions can be a costly way of merging use cases when it's unclear whether those are naturally related in the first place. If we merge use cases too early, we might find that the the complexity we're tucking away in an abstraction is quite small -- and thus offset by the abstraction's own complexity. If we merge cases which weren't all that related to begin with, we'd be effectively increasing complexity and end up creating a tighter coupling than needed -- instead of lowering complexity like we set out to achieve, we end up obtaining the opposite result.
+The above are clear-cut examples of cases when an abstraction greatly improves poor interfaces, but that's not always the end result. Abstractions can be a costly way of merging use cases when it's unclear whether those are naturally related in the first place. If we merge use cases too early, we might find that the complexity we're tucking away in an abstraction is quite small -- and thus offset by the abstraction's own complexity. If we merge cases which weren't all that related to begin with, we'd be effectively increasing complexity and end up creating a tighter coupling than needed -- instead of lowering complexity like we set out to achieve, we end up obtaining the opposite result.
 
 It is best to wait until a distinguishable pattern emerges and it becomes clear that introducing an abstraction would help keep complexity down. When such a pattern emerges, we can be confident that the use cases are indeed related, and we'll have better information about whether an abstraction would simplify our code.
 
