On Fri, Nov 5, 2010 at 7:27 AM, Phillip Hellewell <[email protected]> wrote:

> Hi,
>
> I need some advice on how to handle dependency compatibility issues.
> E.g., if A => B => C (and A => C directly too), my understanding is
> that Maven will allow me to update A to depend on a new version of C,
> even though B still depends on the old version.
>
> But what if B is incompatible with the new version of C?
>
> Here are some ways C might be changed:
> 1. An implementation change (e.g., a function in a .cpp file).
> 2. An interface change (e.g., class definition in a .h file).
> 3. A data structure change (e.g., a data member inside a class).
>
> #1 is the kind of change that usually doesn't cause any problems at
> all.  A can depend on a new version of C and that doesn't cause any
> problems for B.
>
> #2 is the kind of change that (hopefully) will cause a compile or
> linker error when building A.  If so, that's fine.  If not, this could
> be a serious problem.
>
> #3 is the kind of change that unfortunately will likely not manifest
> itself until the middle of runtime, probably with an unexpected
> crash!!
>
> An example of #3 is a custom string class.  Suppose I change the
> internal structure of the string class to include other data members.
> Suppose that the string class is used heavily as parameters and return
> values in the interfaces of A and B.  Obviously "very bad things" will
> happen if A is using one version of the string class whereas B is
> using another.
>
> One way to mitigate #3 in C/C++ projects is to stick with strictly
> plain C types (int, char*, etc) in all interfaces.  But suppose we
> have way too much code to go back and change that now...
>
> Another example I didn't mention yet is what if C produces dlls and
> headers, and some functions are inlined in the headers.  Updating A to
> a new version of C means that B would use a mixture of implementation
> from C.  It would use the new implementation in C's dlls, but it would
> use the old implementation of C's inline functions that got inlined
> into B's dlls.
>
> What is the best way to handle all this to avoid serious runtime
> issues?  One way I know of is to lock down versions with a range like
> [1.0.0.1].  But if my dependency tree is very tall, that means I may
> have to spend a lot of effort rebuilding many components when a
> low-level component changes.  Since most changes are
> implementation-only changes (#1), it would be nice to avoid that most
> of the time.
>
> Is it a common practice to solve this problem using version ranges
> such as [1.0.0-1.0.1), i.e., 1.0.0.x, and bump the 4th number for
> implementation-only changes, and bump the 3rd number for interface or
> other breaking changes?  But what if a programmer makes a breaking
> change and forgets to update the 3rd number, or they don't even
> realize that what they are changing constitutes as a breaking change?
> There's nothing you can do to prevent this, right?
>

I would do 2 things:
First - remove the direct dependancy from A => C.  Let maven pick up 'C' via
transitive dependencies.

2nd, update your parent pom with a dependency management section to secify
exact version numbers of all your artifacts.  Then update the POM in A, B
and C to Remove their version numbers. This causes the version numbers
listed in your dependency management section to be used.

Then when its time to update things, just change the version # in your
dependency management section.  build and your done.

Reply via email to