Skip to main content

Command Palette

Search for a command to run...

Review Structural Changes in Java Code

Updated
3 min read

How to avoid ending up with your Java project as a big ball of tangled classes interconnected in no sensible way.

Code Review is a proven practice that helps keep your code clean. Doing it means nitpicking the details of each method and class: naming, length, responsibility, algorithm, style, and so on. Everything that helps the lines of code to be understood not only by the machine (compiler) but also by humans. As humans — you or your fellow programmers — will have to maintain the code.

What about the bigger picture? For sure there’s some architecture of the system. Possibly it just sits in the heads of your team, possibly it is properly documented, but generally, people know which applications or microservices are integrated with each other and in what direction the data flows between them. Somebody cares about this highest level of modularity.

But I think there’s a grey area between those two, the method and class level changes, and the whole system architecture changes. Namely, the inner composition of a single application or microservice. Or to be more precise, the composition of a lump of code that is built together as a unit, for a lack of better word, let’s call it a module.

Look after the composition of modules

Granted, nowadays everybody does microservices. If each module is really small, if it contains only a couple dozen classes or so, the composition of a module doesn’t matter. Maybe you don’t even bother grouping module’s classes into separate packages.

But if you do, for example, if you do monolith-first development, or if your microservice is not so micro, then you should care how the code inside your module is structured. In the first case, so that you have clearly defined components constituting your monolith that can be later promoted to microservices, without risking that your code will become a big ball of tangled classes. In the second case, if just to be able to work on one component at a time, and not having to understand the entire big module.

To ensure this, you need to keep an eye on how the classes are grouped, and how those groups of classes — components — depend on each other:

Sample visualisation of dependencies between components of a module.

So do you analyze package declarations and import statements, while you are reviewing code changes? I bet you don’t. When writing code, you just type the class name and IDE kindly adds the import statement for you, and you don’t notice that you’ve just added a new dependency between components. When reviewing code, you out of custom skip this seemingly boilerplate information without a second thought.

Tools to the rescue

That’s why I’ve written Socomo. It’s a tool that screams that a new component has been added, or more importantly, a new dependency introduced. It does so by keeping a socomo.html file with such information in your project, which changes along with the code. This way in a single commit, besides actual code changes, you’ll see also the higher level view of structural changes:

Diff that includes Socomo supplied information about newly introduced dependencies.

A functionality similar in its principle is also provided by a commercial product Softagram. It integrates with your version control system, and to each pull request it adds a report with a summary of the impact of the changes:

Pull request comment added by Softagram about introduced structural changes.

You can even go a step further — pro-actively guard composition changes by declaring the rules of the composition and using tools like ArchUnit to enforce them:

Compositon rules declared as unit test with the help of ArchUnit.

However, sometimes it can be hard to know upfront how the code should be structured. Rather the composition of an application or service is a kind of emergent design. So please, keep an eye on it while you are adding more code so that the design emerges in the correct direction.