Skip to content

Commit d768a1e

Browse files
uknickbevacqua
authored andcommitted
typos (#19)
typos
1 parent f3a355a commit d768a1e

File tree

2 files changed

+5
-5
lines changed

2 files changed

+5
-5
lines changed

chapters/ch02.asciidoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ On the same vein, we should avoid optional input parameters which transform the
446446

447447
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.
448448

449-
Having consistent data types mitigates surpises and improves the confidence a consumer has in our API.
449+
Having consistent data types mitigates surprises and improves the confidence a consumer has in our API.
450450

451451
==== 2.2.4 Simplicity
452452

chapters/ch03.asciidoc

+4-4
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; 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 elaborate on how to prune modules as they become larger and more complex over time.
55

66
=== 3.1 Growing a Module
77

@@ -111,7 +111,7 @@ Even when the smaller component isn't being reused anywhere else, and perhaps no
111111

112112
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.
113113

114-
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.
114+
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.
115115

116116
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?
117117

@@ -155,11 +155,11 @@ We can't prevent this from happening over and over -- not entirely. Unexpected b
155155

156156
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.
157157

158-
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.
158+
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.
159159

160160
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.
161161

162-
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.
162+
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.
163163

164164
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.
165165

0 commit comments

Comments
 (0)