Problems

wolfie edited this page Sep 13, 2010 · 11 revisions
Clone this wiki locally

In addition of going open source, I’ve thought to make Bob open problem also. Others might learn from my problems and their solutions. With a bit of cosmic luck, I might even get contributions and help to my problems. Currently it’s more problem listing than problem solving, though.

Dynamic Loading of Optional Classes, unsolved

Bob’s core should not depend on external libraries. Some build actions (like running JUnit tests) will require a jar, but the core ones must be runnable by Bob alone. If a build target does something that requires an external library, that needs to be read in dynamically. Bundling isn’t really an option, partly due to copyright problems, partly because an unnecessarily large distribution package, partly because the eventual duplication of libraries (many systems already have JUnit somewhere).

While Java does have dynamic classloading, it’s extremely cumbersome to use, as described in my Stack Overflow question.

Plausible Solution: Eat Humble Pie

Do according to the SO answer and wrap all external classes Bob interfaces with into reflection classes.

But

This way throws a lot of (unnecessary) checked exceptions to handle, there’s some performance penalties, the code is tedious and it smells like a hack overall.

Plausible Solution: Copy Ant

Run everything requiring an external jar in another Java process entirely. Call Runtime.exec(), add the external jar into the classpath, and run it.

But

The problem with this is the result collection, calling system methods and coping with various unknown system configurations, needs a lot of code to work robustly, and doesn’t reek much less of a hack than the previous suggestion.

Correction

Ant does that whenever the JUnit test run is asked to be forked. There’s an in-VM option too, that utilizes some kind of custom classloader that seems to be able to load classes properly.

Refer a Class in the Main Project from Build Code, unsolved

This problem is pretty related to the “Dynamic Loading of Optional Classes”-one. The current implementation compiles only what it needs at that very moment. The execution begins by compiling only the build source, and continues from there to, usually, building eventual tests and finally building and packaging the project itself. The problem here is when the build file refers to a class that’s not in the build file (e.g. giving a test suite class as a parameter to a tester action): it’s not built yet at that point, let alone in the classpath, so a NoClassDefError is raised.

Plausible Solution: Stringly Typed Tests

Not really plausible, but listing it here, just to get it out: Don’t use Classes as arguments, but Strings instead.

But

This, however, is idiotic. The whole point of Bob is to enable sane APIs and getting help from the IDE’s autocomplete features.

Plausible Solution: Greedy Compilation

Precompile everything Bob can get its hands on from the project root. This might work if the source directories are known, but unreliable if they’re arbitrary. For example, Ant has two source directories under the project root: src/test and src/main.

But

This becomes a problem when the classes should be added to a classpath: A class with the FQCN “com.example.Foo” will be compiled into a file structure of “com/example/Foo.class”. If that is placed in a root directory called “classes”, the full path would be “/classes/com/example/Foo.class”. To be able to refer that class from other classes, the only correct directory to set in the classpath is “/classes”.

You’d think that the classfiles would contain package information, allowing the addition of single files directly into the classfile, but this isn’t case. Should Bob build Ant, there’s no way for Bob to know that “src” isn’t what should be added into the classpath, but “src/main”. Not without some sourcefile/classfile inspection.

This issue could temporarily be avoided by not supporting other than a standard project layout, but that’s not a long-term solution. Also, Bob can become slow to ‘launch’ in bigger projects (not a big priority, Bob’s not intended for large projects yet).

Plausible Solution: Configuration File

A configuration file that informs Bob of different source paths, that would be loaded by Bob, and used to compile all that’s needed.

But

This would be a second configuration file for the same purpose. Having two disconnected files to maintain is not in the best interests of the user. This also leads to arbitrary strings that can’t be verified compile-time, leading to possible human errors and frustration.

Logging Is Unusably Non-descriptive

The logging does indeed tell what’s happening at that current time, but it’s not terribly informative as to why it’s doing what it’s doing. If a Jar invokes a Compilation, you can’t tell that directly, just by looking at the logs. You probably see some Jar entries, and then some Compilation entries, but not the connection between the two. Ideally, you should be able to figure out with relative ease the whole flow of the build, just by looking at the resulted log entries.

no thought-of solutions currently