Four Strategies for Organizing Code

The Whys and Whats of Organizing Code

It is a funny thing that most of the advice you will hear and read on how to develop software basically prescribes how you should organize your code, a topic that doesn’t matter to the computer. As far as the machine is concerned all this talk about coupling and cohesion is mostly irrelevant; it doesn’t care if you put all your code in a single million line method, sort your classes alphabetically, or give all your variables single letter names. Code organization is not about communicating with the computer but rather all about trying to make sure that people can understand the code well enough that they will be able to maintain and evolve it with some degree of efficiency and confidence.

Strategy #1 — by Component

Organization by component minimizes complexity by emphasizing external and internal cohesion of code units, e.g. packages. The former means that the package has a minimal interface which exposes only concepts which are strongly related to the service the component provides. The latter means that the code in the package is strongly interrelated and thus strongly related to the provided service.

Perfectly isolated components

“…packages which have mutual dependencies should not be considered separate units of code at all…”

In theory this process might sound fairly easy but it takes a lot of experience to learn to identify suitable components and strategies for isolating them. It is quite common to start the process only to find out that you didn’t quite get the abstraction right and need to back out of the change. The rewards for properly isolating components are great however: code which is easy to understand, easy to improve, easy to test, and — incidentally — easy to reuse.

Strategy #2 — by Toolbox

Organization by toolbox focuses on external cohesion, providing a consistent toolbox which the consumer can chose from. This strategy is weaker than organizing by component as it drops the requirement for strong internal cohesion, e.g. that the constituents are all strongly interrelated. The parts of a toolbox are often complementary implementations of the same interface(s) which can be usefully chosen from or combined, rather than sharing a lot in the way of implementation.

  • Collection libraries are typically organized as toolboxes with a set of complementary implementations of a set of collection interfaces with varying characteristics with regards to areas such as time complexity and memory consumption. There might also be a unifying theme to the toolbox, such as only containing disk-based data structures.
  • Logging libraries are not necessarily toolboxes in their entirety but often contain a toolbox of e.g. log-writer implementations which target different destinations.
Toolbox with a facade for DiskList for the sake of external consistency

Strategy #3 — by Layer

Organization by layer favors workflow cohesion instead of trying to control complexity by minimizing cross-unit coupling. The code is split along layer boundaries defined by issues such as deployment scenarios or areas of contributor responsibility. This strategy is different from organization by toolbox in that layers don’t present a single, minimal, and coherent interface to the other layers but instead a wide interface with many constituents which are accessed piecemeal by the corresponding constituents of the consuming layer.

Component coupling across layers
Layers nailed together into a single — very complex — unit
  • Don’t let references to language resource files infiltrate your entire code base but rather map all results and errors from your internal components to language resource messages in a single place near the presentation layer.
  • Don’t use the value objects generated from your JSON schema beyond your service layer, translate them into proper domain objects and calls at the earliest time possible.

Strategy #4 — by Kind

Organization by kind is a strategy which tries to bring order to overly complex units of code by throwing the parts into buckets based on which kind of class (or interface, …) it is deemed to be. In doing this it ignores dependencies and conceptual relationships and typically produces packages with names such as exceptions, interfaces, managers, helpers, or entities.

Project organized by kind

“…package size isn’t the main problem, the number of interdependent parts is.”

I consider organization by kind a code smell but in my experience from commercial projects — mainly in Java and C# — it is quite common. I believe that this happens because it seems to provide an easy way to partition large packages and most people aren’t aware that package size isn’t the main problem, the number of interdependent parts is.

Summary

Organizing code is a core skill for software developers and as with all skills the most effective way to improve is to reflect on your previous choices and the fallout from them. There are a wide array of different strategies for organizing code and learning to recognize both the useful and the dangerous ones is very important.

More

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Martin Sandin

Martin Sandin

I'm a software engineer based in Lund, Sweden who occasionally put things into writing to ensure that at least I myself understand why I code the way I do.