Skip to content

Commit 227ee95

Browse files
committed
follow old review
1 parent 3621532 commit 227ee95

File tree

3 files changed

+13
-12
lines changed

3 files changed

+13
-12
lines changed

chapters/ch02.asciidoc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ A flawed API is a lot harder to repair. There may be several implementations whi
173173

174174
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.
175175

176-
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.
176+
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.
177177

178178
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.
179179

@@ -387,7 +387,7 @@ Though it's not uncommon for JavaScript libraries to offer a getter and a setter
387387

388388
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.
389389

390-
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.
390+
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.
391391

392392
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.
393393

@@ -399,7 +399,7 @@ $('{div}')
399399

400400
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.
401401

402-
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.
402+
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.
403403

404404
[source,javascript]
405405
----
@@ -409,7 +409,7 @@ await fetch('/api/users/rob', {
409409
})
410410
----
411411

412-
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.
412+
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.
413413

414414
[source,javascript]
415415
----
@@ -482,7 +482,7 @@ The `fetch` function can't do much without a specified resource, which is why th
482482

483483
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`.
484484

485-
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.
485+
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.
486486

487487
==== 2.2.5 Tiny surface areas
488488

chapters/ch03.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[[module-design]]
22
== Module Design
33

4-
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.
4+
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.
55

66
=== 3.1 Growing a Module
77

@@ -41,7 +41,7 @@ Abstractions aren't free, but they can shield portions of code from complexity.
4141

4242
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.
4343

44-
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.
44+
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.
4545

4646
==== 3.1.2 Design for Today
4747

0 commit comments

Comments
 (0)