-
Notifications
You must be signed in to change notification settings - Fork 210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fixed grammar typos #11
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed 'implmentation' to 'implementation' |
||
|
||
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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed 'accomodate' to 'accommodate' |
||
|
||
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. | ||
|
||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed 'uncmoon' to 'uncommon'