DEV Community

Cover image for Understanding Clean Code: Boundaries ⚡
Ali Samir
Ali Samir

Posted on

Understanding Clean Code: Boundaries ⚡

When writing software, a key challenge is managing the boundaries between your code and external systems such as third-party libraries, APIs, or frameworks.

Chapter 8 of "Clean Code" guides handling these boundaries effectively to maintain clean, maintainable code.


📌 The Challenge of Boundaries

Boundaries in code represent the points where your system interacts with external components. These can be:

  • Third-party libraries: Tools and utilities that provide functionality outside your core codebase.

  • APIs: Interfaces provided by other systems that your code communicates with, often over the network.

  • Frameworks: Larger structures that provide a foundation for your application but impose certain patterns or constraints.


The challenge with boundaries is that they often come with uncertainty.

External systems can change, behave unexpectedly, or introduce bugs that are hard to control.

Therefore, managing these boundaries well is crucial to keeping your codebase clean.


📌 Using Interfaces to Manage Boundaries

One of the main strategies for managing boundaries is to use interfaces or abstractions.

By defining an interface between your code and the external system, you can isolate the dependency and reduce the impact of any changes or issues in the external system.

⚡ Example: Wrapping a Third-Party Library

Imagine you're using a third-party library to format dates. Instead of scattering calls to the library throughout your code, you can create a wrapper function:

// Third-party library usage
import moment from 'moment';

// Wrapper function
function formatDate(date) {
  return moment(date).format('YYYY-MM-DD');
}

// Usage in your code
const myDate = new Date();
console.log(formatDate(myDate));
Enter fullscreen mode Exit fullscreen mode

By using a wrapper, you can easily swap out moment for another date library if needed, without changing the rest of your codebase.


📌 Boundary Testing with Fake Implementations

Testing code that interacts with external systems can be tricky.

You don't want your tests to depend on the actual external system, as this can make them brittle and slow.

Instead, you can use fake implementations or mocks to simulate the behavior of the external system.

⚡Example: Mocking an API

Suppose your application makes HTTP requests to an external API. Instead of making real network calls in your tests, you can mock the API:

// Real API call
async function fetchData(apiUrl) {
  const response = await fetch(apiUrl);
  return response.json();
}

// Mocked API for testing
function mockFetchData() {
  return Promise.resolve({ data: 'mocked data' });
}

// Test using the mock
(async () => {
  const data = await mockFetchData();
  console.log(data); // Output: { data: 'mocked data' }
})();
Enter fullscreen mode Exit fullscreen mode

Using a mock, you can test how your code behaves without relying on the actual API, making your tests more reliable.


📌 Boundaries Are Temporary

Make sure that boundaries are often temporary. As your understanding of the system grows, you may find that you need to adjust or eliminate certain boundaries.

It's important to keep your code flexible and adaptable, allowing for these changes.

⚡ Example: Moving from a Library to Native JavaScript

At the start of a project, you might use a library for a particular task because it's quick and easy.

However, as the project evolves, you might decide to replace that library with custom or native JavaScript code.

// Initial implementation with a library
import _ from 'lodash';

const numbers = [1, 2, 3, 4, 5];
const sum = _.sum(numbers);

// Later replaced with native JavaScript
const sumNative = numbers.reduce((total, num) => total + num, 0);
Enter fullscreen mode Exit fullscreen mode

In this example, you start by using Lodash's sum function. Later, you replace it with the native reduce method, eliminating the dependency on Lodash for this particular task.


Conclusion

Managing boundaries in your code is essential for writing maintainable software.

Using interfaces, wrappers, and mocks can help isolate external dependencies and keep your code flexible and testable, even as your project evolves.

These principles are outlined in Chapter 8 of Clean Code and can help maintain a cleaner and more robust codebase.

Happy Coding!

Top comments (0)