Skip to content

Commit fcd3fea

Browse files
committed
expanding on things
1 parent 724096a commit fcd3fea

File tree

1 file changed

+10
-4
lines changed

1 file changed

+10
-4
lines changed

chapters/ch06.asciidoc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,17 @@ A secret service also takes care of encryption, secure storage, secret rotation
141141

142142
==== 6.2 Explicit Dependency Management
143143

144-
It's not practical to include dependencies in our repositories, given these are often in the hundreds of megabytes and often include environment-dependant and operating system dependant files. During development, we want to make sure we get non-breaking upgrades to our dependencies, which can help us resolve bugs and tighten our grip around security vulnerabilities. For deployments, we want reproducible builds, where installing our dependencies yields the same results every time.
144+
The reason why we often feel tempted to check our dependencies into source control is so that we get the exact same versions across the dependency tree, every time, in every environment.
145145

146-
The solution is often to include a dependency manifest, indicating what exact versions of the libraries in our dependency tree we want to be installing. This can be accomplished with npm (starting with version 5) and its `package-lock.json` manifest, as well as through Facebook's Yarn package manager and its `yarn.lock` manifest, both of which we should be publishing to our versioned repository.
146+
Including dependency trees in our repositories is not practical, however, given these are often in the hundreds of megabytes and frequently include compiled assets that are built based on the target environment and operating system, meaning that the build process itself -- the act `npm` executing a `rebuild` step after `npm install` ends -- is environment dependant, and thus not suitable for a presumably platform-agnostic code repository.
147+
148+
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.
149+
150+
The solution is to include a dependency manifest, indicating what exact versions of the libraries in our dependency tree we want to be installing. This can be accomplished with npm (starting with version 5) and its `package-lock.json` manifest, as well as through Facebook's Yarn package manager and its `yarn.lock` manifest, either of which we should be publishing to our versioned repository.
147151

148152
Using these manifests across environments ensures we get reproducible installs of our dependencies, meaning everyone working with the codebase -- as well as hosted environments -- deals with the same package versions, both at the top level (direct dependencies) and regardless the nesting depth (dependencies of dependencies -- of dependencies).
149153

150-
Every dependency in our application should be explicitly declared in our manifest, relying on globally installed packages or global variables as little as possible. Implicit dependencies involve additional steps across environments, where developers and deployment flows alike must take action to ensure these extra dependencies are installed, beyond what a simple `npm install` step could achieve. Here's an example of how a `package-lock.json` file might look:
154+
Every dependency in our application should be explicitly declared in our manifest, relying on globally installed packages or global variables as little as possible -- and ideally not at all. Implicit dependencies involve additional steps across environments, where developers and deployment flows alike must take action to ensure these extra dependencies are installed, beyond what a simple `npm install` step could achieve. Here's an example of how a `package-lock.json` file might look:
151155

152156
```
153157
{
@@ -175,14 +179,16 @@ Always installing identical versions of our dependencies -- and identical versio
175179

176180
==== 6.3 Interfaces as Black Boxes
177181

178-
On a similar note to that of the last section, we should treat our own components no differently than how we treat third party libraries and modules. Granted, we can make changes to our own code a lot more quickly than we can effect change in third party code -- if that's at all possible. However, when we treat all components and interfaces (including our own HTTP API) as if they were foreign to us, we can focus on consuming and testing against interfaces, while ignoring the underlying implementation.
182+
On a similar note to that of the last section, we should treat our own components no differently than how we treat third party libraries and modules. Granted, we can make changes to our own code a lot more quickly than we can effect change in third party code -- if that's at all possible, in some cases. However, when we treat all components and interfaces (including our own HTTP API) as if they were foreign to us, we can focus on consuming and testing against interfaces, while ignoring the underlying implementation.
179183

180184
One way to improve our interfaces is to write detailed documentation about the input an interface touchpoint expects, and how it affects the output it provides in each case. The process of writing documentation often leads us to uncover limitations in how the interface is designed, and we might decide to change it as a result. Consumers love good documentation because it means less fumbling about with the implementation (or often, implementors), to understand how the interface is meant to be consumed, and whether it can accomplish what they need.
181185

182186
Avoiding distinctions helps us write unit tests where we mock dependencies that aren't under test, regardless of whether they were developed in-house or by a third party. When writing tests we always assume that third party modules are generally well-tested enough that it's not our responsibility to include them in our test cases. The same thinking should apply to first party modules that just happen to be dependencies of the module we're currently writing tests for.
183187

184188
This same reasoning can be applied to security concerns such as input sanitization. Regardless of what kind of application we're developing, we can't trust user input unless it's sanitized. Malicious actors could be angling to take over our servers, our customers' data, or otherwise inject content onto our web pages. These users might be customers or even employees, so we shouldn't treat them differently depending on that, when it comes to input sanitization.
185189

190+
Putting ourselves in the shoes of the consumer is often the best tool to guard us against half-baked interfaces. When -- as a thought exercise -- you stop and think about how you'd want to consume an interface, and the different ways in which you might need to consume it, you often end up with a much better interface as a result. This is not to say we want to enable consumers to be able to do just about everything, but we want to make affordances where consuming an interface becomes as straightforward as possible and doesn't feel like a chore. If consumers are all but required to include long blocks of business logic right after they consume an interface, we need to stop ourselves and ask: would that business logic belong behind the interface rather than at its doorstep?
191+
186192
==== 6.4 Build, Release, Run
187193

188194
Having clearly defined and delineated build processes is key when it comes to successfully managing an application across development, staging, and production environments.

0 commit comments

Comments
 (0)