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 01/24] 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 02/24] 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 03/24] 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 04/24] 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 05/24] 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 06/24] 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 07/24] 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 08/24] 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 09/24] 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 10/24] 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 11/24] 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 12/24] 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 13/24] 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 14/24] 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 15/24] 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 16/24] 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 17/24] 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 18/24] 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 19/24] 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 20/24] 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 21/24] 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 22/24] 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 23/24] 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 24/24] 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.
 
