loader

Chapter 8 of “Clean Code” tackles the reality that we rarely write all the code ourselves. We often rely on libraries and frameworks created by other teams or individuals. This chapter discusses how to manage these “boundaries” between our code and third-party code in a clean and effective way, minimizing potential headaches down the line.

Chapter 8 – Boundaries

  • Using Third-Party Code: The book starts by acknowledging that using third-party code is almost inevitable. These libraries can provide valuable functionality and save us a lot of development time. However, it also points out that there’s a risk involved. We don’t control this external code, and changes or issues within it can impact our own system.
  • Exploring and Learning Boundaries: When you start using a new third-party library, it’s important to invest some time in exploring and understanding its boundaries – how it works, what its limitations are, and what kind of errors it might throw. Don’t just jump in and start using it blindly. Writing some exploratory code or “learning tests” can be a really good way to get a feel for how the library behaves.
  • Learning log4j: The book uses the example of learning a logging library like log4j. It suggests that instead of directly integrating log4j’s specific classes and methods throughout your code, it’s often better to create an intermediary interface or adapter within your own system. This adapter then handles the interaction with log4j. The benefit of this approach is that if you ever decide to switch to a different logging library in the future, you only have to change your adapter, not all the code that uses logging.
  • Learning Tests Are Better Than Free: This is a key concept. When you’re exploring a new third-party library, writing learning tests – small tests that exercise the library’s features and behavior – is invaluable. These tests not only help you understand how to use the library but also act as a safety net. If the library gets updated or you need to upgrade to a new version, these tests can help you quickly identify if any of your assumptions about how it works have changed. They’re like free documentation that’s specific to how you’re using the library.
  • Using Code That Does Not Yet Exist: This might seem a bit counterintuitive, but the chapter also touches on the idea of defining your own interfaces for functionality that you expect a third-party library (or even another part of your own system that isn’t finished yet) to provide. By coding to your own interface, you decouple your code from the specific implementation. This makes it easier to integrate the actual third-party code later and also makes your code more testable in isolation (you can easily create mock implementations of your interface).
  • Clean Boundaries: The overarching theme of this chapter is the importance of having clean boundaries between your code and external code. By using adapters or interfaces, you isolate your system from the specifics of the third-party library. This provides several benefits:
    • Reduced Coupling: Your code doesn’t depend directly on the third-party library’s implementation details.
    • Easier to Change: If the third-party library changes or you decide to switch to a different one, the impact on your codebase is minimized.
    • Improved Testability: You can easily mock or stub out the adapter for testing your own code in isolation.
    • Better Understanding: Creating an adapter forces you to think about how you’re actually using the third-party code and what parts are relevant to your system.

Boundaries are inevitable, but messy ones aren’t. Chapter 8 reminds us that we can harness the benefits of third-party libraries while minimizing their risks. By creating thoughtful abstractions and writing learning tests, we insulate our code from volatility and make future changes far less painful. Clean code respects its edges and defines them well.