9

I've been researching Java package structure and dependency patterns over the last few weeks. One of the common threads across the writings on the subject is the simple rule that package dependencies should form a directed acyclic graph (DAG). Author Robert Martin even formalized the Acyclic Dependencies Principle (ADP), which states

The dependency structure between packages must be a directed acyclic graph (DAG). That is, there must be no cycles in the dependency structure.

A few Java libraries do adhere to this simple rule. Namely, Spring Framework libraries (spring-core, spring-web, etc) and Google Guava.

However, to my surprise, the majority of leading open-source Java projects do not!

The following open-source projects have circular dependencies among packages:

  • Netflix Hystrix (every package is part of a cycle!)
  • AWS SDK
  • Commons-Lang
  • Commons-Collections
  • Dagger
  • Google Gson
  • Google Guice
  • Hibernate ORM
  • Hibernate Validator
  • Jackson Core
  • Joda Time
  • Play Framework
  • Junit
  • Logback
  • Jetty
  • AspectJ
  • Netty
  • java.util
  • java.lang

Have I misunderstood the software engineering principle? Or do developers discount this package organization technique?

References:

Elliot
  • 189
  • 8
  • How did you come to the conclusion that there are circular dependencies in those APIs and not in Spring? – Tunaki Nov 19 '15 at 16:56
  • A simply analysis of imports! That is all! – Elliot Nov 19 '15 at 16:58
  • (I asked that because I wondered if you used any tools). Can you show a simple example, for example in `java.lang`? – Tunaki Nov 19 '15 at 16:59
  • Yes, I will attach a few images and GraphML files... – Elliot Nov 19 '15 at 17:00
  • 2
    This "rule" is useful if you plan to release one of the packages as a self-contained library, and it's a sign of a good organization, but in practice, having cyclic dependencies between packages is not a real problem, and avoiding them can be a hard task, without any concrete benefit other than the good feeling of obeying a rule. – JB Nizet Nov 19 '15 at 17:13
  • "Good organization" seems like a benefit! In a project like [Hystrix](https://s3-us-west-1.amazonaws.com/circular-dependencies/hystrix-default.jpg), where every package is part of cycle, it's difficult to reason about the responsibility and hierarchy of packages. – Elliot Nov 19 '15 at 17:20

1 Answers1

2

I can confirm that after the analysis of many java projects using JArchitect, many of them contains circular dependencies between packages, the reason is that many of them choose the "package by feature" rather than the "package by layer" approach.

Here's a good article talking about the difference between these two approachs.

Let's take as example some packages from the JDK

enter image description here

These packages are designed by feature, the regex feature is grouped in the java.util.regex package which need some security features from the java.security package and the security classes need also some regex functionalities.

  • 1
    How did you arrive at that theory? Package-by-feature does not guarantee or lead to circular dependencies. Just have a look at spring-core [[GraphML](https://s3-us-west-1.amazonaws.com/circular-dependencies/springcore-default.graphml)] [[JPG](https://s3-us-west-1.amazonaws.com/circular-dependencies/springcore-default.jpg)] or guava [[GraphML](https://s3-us-west-1.amazonaws.com/circular-dependencies/guava-default.graphml)] [[JPG](https://s3-us-west-1.amazonaws.com/circular-dependencies/guava-default.jpg)]. – Elliot Nov 20 '15 at 16:38
  • 1
    Not all "package by feature" designed projects have the circular dependencies, but when you decide to group by feature the first goal is not to have a layered code ( package by layer approach). and in many cases one feature could use the other and vice versa. – James from CppDepend Team Nov 20 '15 at 18:54