8 Make code modular

 

This chapter covers

  • The benefits of modular code
  • Common ways code can be less modular than is ideal
  • How to make code more modular

Chapter 1 discussed how requirements often evolve over the lifetime of a piece of software. In many cases they evolve even before the software is released, so it’s not uncommon to write some code and then have to adapt it only a few weeks or months later. Trying to predict exactly how requirements will evolve is usually a waste of time, because it’s near impossible to do this with any accuracy. But we can usually be more or less certain that they will evolve in some way.

One of the main aims of modularity is to create code that can be easily adapted and reconfigured, without having to know exactly how it will need to be adapted or reconfigured. A key goal in achieving this is that different pieces of functionality (or requirements) should map to distinct parts of the codebase. If we achieve this, and later on one of the software requirements changes, we should need to make nontrivial changes to only the single place in the codebase that relates to that requirement or feature.

8.1 Consider using dependency injection

8.1.1 Hard-coded dependencies can be problematic

8.1.2 Solution: Use dependency injection

8.1.3 Design code with dependency injection in mind

8.2 Prefer depending on interfaces

8.2.1 Depending on concrete implementations limits adaptability

8.2.2 Solution: Depend on interfaces where possible

8.3 Beware of class inheritance

8.3.1 Class inheritance can be problematic

8.3.2 Solution: Use composition

8.3.3 What about genuine is-a relationships?

8.4 Classes should care about themselves

8.4.1 Caring too much about other classes can be problematic

8.4.2 Solution: Make classes care about themselves

8.5 Encapsulate related data together