Jigsaw prototype, take 2
greggwon at cox.net
Sat Sep 7 07:55:40 PDT 2013
Tim, I appreciate a non-circular dependency graph. But, that should be my decision to want that, not something that tools demand. What happens typically, is that it forces you to actually make the wrong decision about how to create that graph and then requires extra work to build a non-circular view which eventually deteriorates into a huge mess because there are too many branches that attempt to introduce an interface to decouple the circular dependency for compiling, but you still have to create a circular dependency in class loading because that's how the beast fits together.
The JVM is indeed a great example of how it's inseparable because of inter package dependencies. A dependency analysis tool can help you draw the picture, and I use one to create downloadable jars with minimal content to reduce download and disk storage overhead.
Drawing the dependency graph to understand how separation works at interface boundaries is a fine idea. The reality is that there is never a non-circular dependency situation in mature software from a class loading perspective.
Collections are the typical implementation that is everywhere. Well, things like logging are also everywhere. Just because logging uses collections to hold records of loggers, properties, handlers etc., and collections uses logging to allow insight into it's behaviors doesn't mean that they need to always be in the same package.
Indeed, interfaces could allow them to be independent, yet, they are not because there are not interfaces that describe all the behaviors that each uses from the other.
If we had interfaces everywhere, it would be nightmarish to keep up with all of the interface definitions and use those when there isn't any real ability to do that because of construction not being done with factories everywhere. But then you'd have dependencies on factory classes and it would still not work.
So in the end, it's pointless to use the circular dependency concept as a problem statement. It's unsolvable! The right answer is to actually make tools which can deal with the concept of incomplete dependency graphs so that you can move on.
The fact that Java doesn't deep resolve all class dependencies on the first class loaded is partially a solution to incomplete dependency graphs. It allows all kinds of flexibility it what can happen to resolve classes.
There are so many other tooling issues that Java needs to address to be able to be fully exploited for the power that the class loading mechanisms really provide.
Why isn't there a mechanism in the platform for the jar to define invisible dependencies (classes loaded with Class.forName(), or otherwise invisible dependencies)?
Why isn't there a dependency tool set that builds minimal sized jar files?
Why aren't nested jars possible so that I could just put everything I needed into one jar and use jar:jar:jar:… urls to load them?
Why has the entire java industry prolifically dictated that their jars (by licensing) can not be pulled apart into just the needed components?
What is most frustrating is that the monolithic assembly of Java-EE has caused people to focus on all of the wrong solutions to creating a Java "application".
OSGi tries to solve the packaging problem by introducing so many bits and pieces of the system, replicated over and over in multiple places. It's supposed to make tooling be the mechanism for solving dependency problems, yet its not part of the development process in such a way that the dependency graph is always visible.
That's what is actually needed. Dependencies should be a primary thing as part of the development process, and development time dependencies should not become the deployment time dependencies.
On Sep 6, 2013, at 10:22 PM, Tim Boudreau <niftiness at gmail.com> wrote:
> We've worked together and I respect your judgement. That said, I have to disagree pretty strongly with the idea of *not* enforcing that dependencies be a directed acyclic graph as the default.
> Fundamentally, if you are developing two things, and there is a circular dependency between them, you do not have *two* things - you have one thing which you enjoy pretending is two. If neither can exist without the other, their independence is in illusion.
> I agree that sometimes you need that sort of thing, dealing with legacy software and so forth. Not too long ago, I did some detangling of a project for a company that could only compile their software if they compiled against (and shipped) two historical versions of their own product, and not a soul there actually knew what got loaded and linked at runtime. Terrifying but true.
> But that being the default is the source of a *lot* of problems. And having to understand dependencies teaches understanding of dependencies, which affects how developers think about designing software.
> And explicit, non-cyclical dependencies make possible - trivial, even - very useful sorts of static analysis.
> I've developed a similar attitude toward Maven. Flexibility can be harmful, especially when there's no obvious right way to do things - it gives you enough rope to hang yourself. I've seen so many Make and Ant based projects where there was only one person in the organization who understood how their build system worked. Maven is inflexible in the extreme - there's a lot I really dislike about it. But it is utterly unambiguous.
> Managed dependencies are like that. You *want* inflexibility as a default. Sure, you also want the ability to write your own classloader (IMO, bytecode-over-the-wire is still one of the actually interesting things about Java) and do what you want - the occasions are rare, but when you need it, you need it. But even when you *do* need it, what are you loading those classes *from*? If it's non-trivial and you want it to work, you need...its dependencies! So I suspect even when you're doing wild-west classloading, there are still benefits to having this stuff be explicit and unambiguous.
> I understand that for a lot of people, this JSR is about making the JDK leaner and meaner. But I think there are opportunities here to do things that dramatically reduce the maintenance cost of new software written in Java, and it would be a pity not to seize the opportunity to kill two birds with one stone.
More information about the jigsaw-dev