Readplace

Why Do You Need To Know Package Coupling Fundamentals?

fagnerbrack.com 5 min read
View original
  • current
Summary (TL;DR)
Package coupling principles help manage dependencies in JavaScript projects. The Acyclic Dependencies Principle (ADP) states that package dependencies must form a directed acyclic graph with no cycles. The Stable Dependencies Principle (SDP) says packages should depend only on packages more stable than themselves. The Stable Abstractions Principle (SAP) requires that stable packages be abstract and unstable packages be concrete. Violating these principles makes code harder to change, understand, and reuse. The article uses a fictional Node.js app called 'The Plumber's Logbook' to illustrate each principle with examples and fixes.

Why Do You Need To Know Package Coupling Fundamentals?

A picture of the pipes and mechanical systems of an aircraft jet engine.

Last time I wrote about how JavaScript doesn’t have a proper concept of package. Yet, you can still use packaging principles to increase the cohesion of its files and directories.

While cohesion principles refer to the degree in which the files inside a package belong together, coupling refers to the degree of interdependence between files in relation to their package.

Let's say you're a solo plumber using an application built with NodeJS called The Plumber's Logbook. The purpose of the application is for you to see additional information about your jobs in order to improve your solo business.

Important Note 1: Similar to what I mentioned earlier, “files” in this context is a generic term that can also represent a “module”.

Important Note 2: You'll see in the examples that there's one file per package. That was done for the sake of brevity and to reduce the noise. Imagine that each package can have many files related to the same functionality, like mapping functions, helper classes, filter functions… even HTML. templates and bash scripts.

A file structure showing the path of the files for The Plumber’s Logbook and their dependencies represented in square brackets.
  • The /list-plumbing-work-events package lists all the “events” for the jobs you provided. For the purpose of this example, an “event” can be anything that happens while you’re at work.
  • The /admin/list-plumbing-work-complaints.js file lists all the events related to the negative feedback the customers have forwarded to you after a job.
  • The /admin package is a self-deployable server meant to be managed by yourself as an administrator. It shows a list of complaints and job events.

The Acyclic Dependencies Principle (A.D.P.) states that:

The dependency structure between packages must be a Directed Acyclic Graph (DAG). That is, there must be no cycles in the dependency structure.

The “Granularity” paper by Bob Martin (Uncle Bob)

That means if you start to trace all dependencies starting from a single file, you should never be able to come back to the same file again.

In The Plumber’s Logbook, there's a clear violation of this principle.

The /admin package contains index.html, which has a dependency on /list-plumbing-work-events/list-plumbing-work-events.js. The /list-plumbing-work-events package contains the list-work-events-with-complaints.js file, which has a dependency on /admin/list-plumbing-work-complaints.js.

A diagram showing how the “/admin” package has a dependency on the “/list-plumbing-work-events” package. The “/list-plumbing-work-events” package has also a dependency on “/admin".

If you start from the/admin package and follow the dependencies of any of its files, you'll eventually find yourself in the /admin package again ad infinitum.

What you can do is to organize the dependencies in a way it doesn’t contain cycles:

A file structure showing the “list-plumbing-work-complaints.js” file moved from the “/admin” package to a new one called “/list-plumbing-work-complaints”.

If the packages contain cyclic dependencies, it will be hard to move them around as a whole and understand how they connect to each other. When making a change, it will increase the risk of having unintended side-effects due to the dependency complexity.

The Stable Dependencies Principle (S.D.P.) states that:

The dependencies between packages in a design should be in the direction of the stability of the packages. A package should only depend upon packages that are more stable that it is.

The “Granularity” paper by Bob Martin (Uncle Bob)

Stable packages should not depend on packages that change a lot. If they do, changes in their dependencies will carry more risks of breaking the system.

In The Plumber’s Logbook, the /list-plumbing-work-events package has a lot of technical debt. It also has very low test coverage. It’s very hard to change that file without breaking the system.

In this case, instead of being depended upon less stable and volatile packages, it’s depending on /list-plumbing-work-complaints, which is new and changes often.

That violates the Stable Dependencies Principle.

One way to fix this is to create a new package for the list-work-events-with-complaints.js functionality and move the related dependencies there instead:

A file structure showing the “list-work-events-with-complaints.js” file moved to a package called “list-work-events-with-complaints”.

If you don’t do this, changes in the list-plumbing-work-complaints.js file may require changes in the list-work-events-with-complaints.js file that is inside the list-plumbing-work-events package, which is riskier to touch.

The Stable Abstractions Principle (S.A.P.) states that:

Packages that are maximally stable should be maximally abstract. Instable packages should be concrete. The abstraction of a package should be in proportion to its stability.

The “Stability” paper by Bob Martin (Uncle Bob)

The more stable a package is, the more its interface should be generalized. If you do that, they can be easily depended upon by many different parts of the system, as mentioned by S.D.P.

In The Plumber’s Logbook, the /list-plumbing-work-events package is stable (hard to change) and yet it’s too specific for plumbing work events:

A file structure showing a new “list-events” package with the “list-all-events.js” file created inside it. The “list-all-events.js” file is being used as a dependency for the work complaints and work events packages.

If you make /list-plumbing-work-events more generic by renaming it to /list-events, another package called /list-plumbing-work-events will be responsible for dealing only with plumbing work. The same goes for /list-plumbing-work-complaints, which is another volatile package that can depend upon the files from /list-events.

However, there’s no silver bullet.

The system can also function with a legacy stable package that is concrete and specific. The tradeoff is that you may not be able to easily reuse it’s functionality somewhere else. If you do, you’ll have to duplicate the code or make frequent changes to it, which effectively ignores the stability attributes of the package.

Here’s an example of how everything would look like with more files added to each package:

A file structure showing all the packages with additional helper files inside them: filters, ordering functions, etc.

The Acyclic Dependencies Principle states that there must be no cycles in the package dependency structure. If they do, it will be harder for you to understand how the packages connect to each other.

The Stable Dependencies Principle states a package should only depend upon packages that are more stable that it is. If they don't, changes in an unstable package can have side-effects in a stable one.

The Stable Abstractions Principle states the abstractness of a package should be in proportion to its stability. If it isn't, then it will be hard to apply S.D.P. and depend upon stable packages.

These principles of cohesion and coupling can also be applied to a single file containing many functions. In that case, the file is the package and the functions are the files inside the package.

These principles can also be applied to how you structure your personal photos, videos, and documents (see an example). The more cohesion and less coupling they have, the more organized they’ll be.

Packaging principles are fundamentals. They don't depend on language. They can be applied anywhere.

The connection between files and directories are more important than it may seem at first. And just like if you were a plumber, it’s up to you to make sure the pipes connect seamlessly with each other.

This way you might not even need to worry about work complaints.

If you liked this, you might like readplace.com, built for exactly this kind of reading.

Thanks for reading. If you have some feedback, reach out to me on LinkedIn, Reddit or by replying to this post.