9 Make code reusable and generalizable

 

This chapter covers

  • How to write code that can be safely reused
  • How to write code that can generalize to solve different problems

Chapter 2 discussed how, as engineers, we often solve a high-level problem by breaking it down into a series of subproblems. As we do this on one project after another, we often find that the same subproblems come up again and again. If we or other engineers have already solved a given subproblem, then it makes sense to reuse that solution. It saves us time and reduces the chance of bugs (because the code is already tried and tested).

Unfortunately, just because a solution to a subproblem already exists, it doesn’t always mean that we can reuse it. This can happen if the solution makes assumptions that don’t fit our use case, or if it’s bundled together with some other logic that we don’t need. It’s therefore worth actively considering this and deliberately writing and structuring code in a way that will allow it to be reused in the future. This can require a bit more upfront effort (although often not much more) but will usually save us and our teammates time and effort in the long run.

9.1 Beware of assumptions

9.1.1 Assumptions can lead to bugs when code is reused

9.1.2 Solution: Avoid unnecessary assumptions

9.1.3 Solution: If an assumption is necessary, enforce it

9.2 Beware of global state

9.2.1 Global state can make reuse unsafe

9.2.2 Solution: Dependency-inject shared state

9.3 Use default return values appropriately

9.3.1 Default return values in low-level code can harm reusability

9.3.2 Solution: Provide defaults in higher level code

9.4 Keep function parameters focused

9.4.1 A function that takes more than it needs can be hard to reuse

9.4.2 Solution: Make functions take only what they need

9.5 Consider using generics

9.5.1 Depending on a specific type limits generalizability

9.5.2 Solution: Use generics