You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@maven.apache.org by Phillip Hellewell <ss...@gmail.com> on 2010/11/05 15:27:17 UTC

The joys of dependencies

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?

Phillip

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Jörg Schaible <jo...@gmx.de>.
Phillip Hellewell wrote:

> On Fri, Nov 5, 2010 at 3:22 PM, Jon Paynter <ki...@gmail.com> wrote:
>>
>> So do you have parallel streams of development all shooting for a common
>> release date?  Or do you have parallel releases with  seperate dates --
>> usually one occurring after the next in time.
> 
> Usually most devs working on a given product are working on the same
> branch, or at most two branches, but there are also several different
> products, all of which make use of certain shared components.
> Sometimes products are released together, but often there are
> different release dates.
> 
>> If parallel development, just put each stream in its own branch, and set
>> the affected version to a snapshot.  Hand that off to a developer and
>> wait. When the developer hands the completed code back, merge the branch
>> into the trunk/main/master branch and increment or change the version of
>> the artifacts they updated.    Repeat until everyone is done, then hand
>> it over to QA.
> 
> That's fine.  Yeah, having developers work on a branch until finished
> then merge back to the trunk is a good practice I think.  But I don't
> think that necessarily solves the issues with dependency management
> we've been talking about.
> 
>> The key here is to let your SCM keep track of the various versions of pom
>> files and dependencies via braching, and then merge it all back together
>> when the development task is done.
> 
> But while work is being done on several different branches, what do we
> do with the parent pom?  If we have dependency management in there, we
> either have to create several branches to maintain it (seems really
> complicated), or try to manage information about all dependencies on
> all branches at once (also seems complicated).

No, not really. Note, the parent pom does normally not reflect a physical 
parent. Therefore branching the "parent pom project" is normally one file - 
the pom. Keep in mind that this single file manages then all the 
dependencies of your branch. Merging the pom of the branch back, you can see 
immediately about the versions changed (of the artifacts in the branch and 
all their dependencies). At least if you do what Jon suggests and what we do 
also: No version in any dependency declaration.

> I'm thinking it will be easier to just manage the dependency versions
> inside the individual poms, which of course the SCM keeps track of on
> all the different branches.

Believe it, it will be more difficult to maintain the versions.

- Jörg


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Phillip Hellewell <ss...@gmail.com>.
On Fri, Nov 5, 2010 at 3:22 PM, Jon Paynter <ki...@gmail.com> wrote:
>
> So do you have parallel streams of development all shooting for a common
> release date?  Or do you have parallel releases with  seperate dates --
> usually one occurring after the next in time.

Usually most devs working on a given product are working on the same
branch, or at most two branches, but there are also several different
products, all of which make use of certain shared components.
Sometimes products are released together, but often there are
different release dates.

> If parallel development, just put each stream in its own branch, and set the
> affected version to a snapshot.  Hand that off to a developer and wait.
>  When the developer hands the completed code back, merge the branch into the
> trunk/main/master branch and increment or change the version of the
> artifacts they updated.    Repeat until everyone is done, then hand it over
> to QA.

That's fine.  Yeah, having developers work on a branch until finished
then merge back to the trunk is a good practice I think.  But I don't
think that necessarily solves the issues with dependency management
we've been talking about.

> The key here is to let your SCM keep track of the various versions of pom
> files and dependencies via braching, and then merge it all back together
> when the development task is done.

But while work is being done on several different branches, what do we
do with the parent pom?  If we have dependency management in there, we
either have to create several branches to maintain it (seems really
complicated), or try to manage information about all dependencies on
all branches at once (also seems complicated).

I'm thinking it will be easier to just manage the dependency versions
inside the individual poms, which of course the SCM keeps track of on
all the different branches.

Phillip

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Jon Paynter <ki...@gmail.com>.
On Fri, Nov 5, 2010 at 2:10 PM, Phillip Hellewell <ss...@gmail.com> wrote:

> On Fri, Nov 5, 2010 at 3:00 PM, Phillip Hellewell <ss...@gmail.com>
> wrote:
> > Thanks Jeorg.  I will look into having a dependencyManagement section
> > in parent pom as you and Jon suggested.  That should at least help
> > alleviate things a bit...
>
> Sorry to reply to myself, but I have a really big question about all
> this.  How do you handle dozens of artifacts, all of which may have
> several versions going concurrently, like on different branches.  Is
> there a single parent pom that contains all dependency versions for
> all artifacts on all branches?  That seems like it could get very
> complicated.  Or would have a bunch of different parent poms
>  (actually, that seems even more complicated.)


So do you have parallel streams of development all shooting for a common
release date?  Or do you have parallel releases with  seperate dates --
usually one occurring after the next in time.

If parallel development, just put each stream in its own branch, and set the
affected version to a snapshot.  Hand that off to a developer and wait.
 When the developer hands the completed code back, merge the branch into the
trunk/main/master branch and increment or change the version of the
artifacts they updated.    Repeat until everyone is done, then hand it over
to QA.

The key here is to let your SCM keep track of the various versions of pom
files and dependencies via braching, and then merge it all back together
when the development task is done.

Re: The joys of dependencies

Posted by Phillip Hellewell <ss...@gmail.com>.
On Fri, Nov 5, 2010 at 3:20 PM, Thiessen, Todd (Todd)
<tt...@avaya.com> wrote:
> That’s jar hell man. It’s a problem that exists whether or not maven is involved.

Actually it's dll hell I guess, since we mainly C++ projects :)

> I forget the exact formula maven uses if 2 versions of the same jar are found. It will pick one of the two.  If you decide it picked the wrong one, you can override it using the dependencyManagement section of the top pom.

The problem is putting in place a strategy and enlightening all
developers to follow the strategy that prevents the most serious
problems, like when using the "wrong one" means random runtime
crashes.

Phillip

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


RE: The joys of dependencies

Posted by "Thiessen, Todd (Todd)" <tt...@avaya.com>.
That’s jar hell man. It’s a problem that exists whether or not maven is involved.

I forget the exact formula maven uses if 2 versions of the same jar are found. It will pick one of the two.  If you decide it picked the wrong one, you can override it using the dependencyManagement section of the top pom.

> -----Original Message-----
> From: Phillip Hellewell [mailto:sshock@gmail.com]
> Sent: Friday, November 05, 2010 5:11 PM
> To: Maven Users List; joerg.schaible@gmx.de
> Subject: Re: The joys of dependencies
> 
> On Fri, Nov 5, 2010 at 3:00 PM, Phillip Hellewell <ss...@gmail.com>
> wrote:
> > Thanks Jeorg.  I will look into having a dependencyManagement section
> > in parent pom as you and Jon suggested.  That should at least help
> > alleviate things a bit...
> 
> Sorry to reply to myself, but I have a really big question about all
> this.  How do you handle dozens of artifacts, all of which may have
> several versions going concurrently, like on different branches.  Is
> there a single parent pom that contains all dependency versions for
> all artifacts on all branches?  That seems like it could get very
> complicated.  Or would have a bunch of different parent poms
> (actually, that seems even more complicated.)
> 
> Phillip
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
> For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Phillip Hellewell <ss...@gmail.com>.
On Fri, Nov 5, 2010 at 3:00 PM, Phillip Hellewell <ss...@gmail.com> wrote:
> Thanks Jeorg.  I will look into having a dependencyManagement section
> in parent pom as you and Jon suggested.  That should at least help
> alleviate things a bit...

Sorry to reply to myself, but I have a really big question about all
this.  How do you handle dozens of artifacts, all of which may have
several versions going concurrently, like on different branches.  Is
there a single parent pom that contains all dependency versions for
all artifacts on all branches?  That seems like it could get very
complicated.  Or would have a bunch of different parent poms
(actually, that seems even more complicated.)

Phillip

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Phillip Hellewell <ss...@gmail.com>.
Thanks Jeorg.  I will look into having a dependencyManagement section
in parent pom as you and Jon suggested.  That should at least help
alleviate things a bit...

Phillip

On Fri, Nov 5, 2010 at 12:37 PM, Jörg Schaible <jo...@gmx.de> wrote:
> Hi Phillip,
>
> Phillip Hellewell 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).
>
> First: With a dependencyManagement section, you can overwrite the version od
> C used for A even if it is "only" a transitive version.
>
>> #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.
>
> The nice case.
>
>> #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.
>
> At Apache commons we have meanwhile a consensus to change artifactId and
> package name, i.e. the next version of commons lang will be
>
> org.apache.commons:commons-lang3:3.0
>
> and the Java classes reside in package
>
> org.apache.commons.lang3
>
> This approach basically allows an older version to be used at the same time
> with the new one, but of course this is no longer a drop-in replacement.
>
> For C++ this would mean changing the namespace and the artifactId.
>
> However, the project maintaining a library must be aware of the problem and
> act accordingly. If they ignore the problem, their users are in trouble
> (happened in Java world e.g. for ASM 1.5.x to ASM 2.0 and a lot of stuff
> broke because).
>
>> #3 is the kind of change that unfortunately will likely not manifest
>> itself until the middle of runtime, probably with an unexpected
>> crash!!
>
> This again is in the responsibility of the project team to spot such things.
> In Java world we have tools like CLIRR that explicitly report binary
> incompatibilities and at Apache commons such changes are nor done for minor
> releases. The policy of the team has to be strict.
>
> [snip]
>
>> 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.
>
> In combination with a dependencyManagement you can avoid version ranges at
> all, but it requires that the rules above are respected.
>
> Maven cannot magically solve the compatibility problems that have been
> ignored by the teams, but it can help you to manage the versions if the
> teams act properly.
>
>> 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?
>
> It's always the same: Shit in ==> shit out :)
>
> - Jörg
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
> For additional commands, e-mail: users-help@maven.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Jörg Schaible <jo...@gmx.de>.
Hi Phillip,

Phillip Hellewell 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).

First: With a dependencyManagement section, you can overwrite the version od 
C used for A even if it is "only" a transitive version.

> #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.

The nice case.

> #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.

At Apache commons we have meanwhile a consensus to change artifactId and 
package name, i.e. the next version of commons lang will be

org.apache.commons:commons-lang3:3.0

and the Java classes reside in package

org.apache.commons.lang3

This approach basically allows an older version to be used at the same time 
with the new one, but of course this is no longer a drop-in replacement.

For C++ this would mean changing the namespace and the artifactId.

However, the project maintaining a library must be aware of the problem and 
act accordingly. If they ignore the problem, their users are in trouble 
(happened in Java world e.g. for ASM 1.5.x to ASM 2.0 and a lot of stuff 
broke because).

> #3 is the kind of change that unfortunately will likely not manifest
> itself until the middle of runtime, probably with an unexpected
> crash!!

This again is in the responsibility of the project team to spot such things. 
In Java world we have tools like CLIRR that explicitly report binary 
incompatibilities and at Apache commons such changes are nor done for minor 
releases. The policy of the team has to be strict.

[snip]

> 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.

In combination with a dependencyManagement you can avoid version ranges at 
all, but it requires that the rules above are respected.

Maven cannot magically solve the compatibility problems that have been 
ignored by the teams, but it can help you to manage the versions if the 
teams act properly.

> 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?

It's always the same: Shit in ==> shit out :)

- Jörg


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


RE: The joys of dependencies

Posted by "Yanko, Curtis" <cu...@uhc.com>.
But in a CI system, the latest B is always built. In fact, in our Build Management system we use push style dependencies instead of pull. So, instead of a build of A seeing in B needs to be built, When B builds it tells A. In this way, any change will ultimately trigger all of the dependent apps.

-----Original Message-----
From: Phillip Hellewell [mailto:sshock@gmail.com] 
Sent: Friday, November 05, 2010 5:20 PM
To: Maven Users List
Subject: Re: The joys of dependencies

On Fri, Nov 5, 2010 at 3:13 PM, Jon Paynter <ki...@gmail.com> wrote:
> On Fri, Nov 5, 2010 at 1:57 PM, Phillip Hellewell <ss...@gmail.com> wrote:
>> In many of my cases, yes A actually does need C to compile.
>>
> In that case - my suggestion wont work for you.
>
> Also - after re-reading this thread it seems your assuming something 
> very simmilar to what I assumed when starting with maven:  namely ive 
> I have changed B while working on A, and I build from within project 
> A, maven will also pickup the changes from B -- this is not true.  
> What will actually happen is A will be compiled based on the last 
> installed version of B.  IMO the better option is to Always build from 
> the top level of your project, then changes across modules are always 
> built together with dependencies in the right order.

Actually, we don't use multi-module projects at all.  All our project/components live in their own source trees in SVN and depend on each other using transitive dependencies.  So yeah, building A can't possibly pick up a new version of B until B is built and installed/deployed.

Phillip

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


This e-mail, including attachments, may include confidential and/or
proprietary information, and may be used only by the person or entity
to which it is addressed. If the reader of this e-mail is not the intended
recipient or his or her authorized agent, the reader is hereby notified
that any dissemination, distribution or copying of this e-mail is
prohibited. If you have received this e-mail in error, please notify the
sender by replying to this message and delete this e-mail immediately.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Ron Wheeler <rw...@artifact-software.com>.
On 05/11/2010 5:20 PM, Phillip Hellewell wrote:
> On Fri, Nov 5, 2010 at 3:13 PM, Jon Paynter<ki...@gmail.com>  wrote:
>> On Fri, Nov 5, 2010 at 1:57 PM, Phillip Hellewell<ss...@gmail.com>  wrote:
>>> In many of my cases, yes A actually does need C to compile.
>>>
>> In that case - my suggestion wont work for you.
>>
>> Also - after re-reading this thread it seems your assuming something very
>> simmilar to what I assumed when starting with maven:  namely ive I have
>> changed B while working on A, and I build from within project A, maven will
>> also pickup the changes from B -- this is not true.  What will actually
>> happen is A will be compiled based on the last installed version of B.  IMO
>> the better option is to Always build from the top level of your project,
>> then changes across modules are always built together with dependencies in
>> the right order.
> Actually, we don't use multi-module projects at all.  All our
> project/components live in their own source trees in SVN and depend on
> each other using transitive dependencies.  So yeah, building A can't
> possibly pick up a new version of B until B is built and
That is a good way to do it.
We find that this works very well and makes life simpler for everyone.

> installed/deployed.
>
> Phillip
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
> For additional commands, e-mail: users-help@maven.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Phillip Hellewell <ss...@gmail.com>.
On Fri, Nov 5, 2010 at 3:13 PM, Jon Paynter <ki...@gmail.com> wrote:
> On Fri, Nov 5, 2010 at 1:57 PM, Phillip Hellewell <ss...@gmail.com> wrote:
>> In many of my cases, yes A actually does need C to compile.
>>
> In that case - my suggestion wont work for you.
>
> Also - after re-reading this thread it seems your assuming something very
> simmilar to what I assumed when starting with maven:  namely ive I have
> changed B while working on A, and I build from within project A, maven will
> also pickup the changes from B -- this is not true.  What will actually
> happen is A will be compiled based on the last installed version of B.  IMO
> the better option is to Always build from the top level of your project,
> then changes across modules are always built together with dependencies in
> the right order.

Actually, we don't use multi-module projects at all.  All our
project/components live in their own source trees in SVN and depend on
each other using transitive dependencies.  So yeah, building A can't
possibly pick up a new version of B until B is built and
installed/deployed.

Phillip

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Jon Paynter <ki...@gmail.com>.
On Fri, Nov 5, 2010 at 1:57 PM, Phillip Hellewell <ss...@gmail.com> wrote:

> On Fri, Nov 5, 2010 at 12:16 PM, Stephen Connolly
> <st...@gmail.com> wrote:
> >
> > This could be a bad thing.
> >
> > If A actually needs C to compile, then keep the dependency on C as the
> > transitive deps pulling in C could change and no longer pull in C.
>
> In many of my cases, yes A actually does need C to compile.
>
In that case - my suggestion wont work for you.

Also - after re-reading this thread it seems your assuming something very
simmilar to what I assumed when starting with maven:  namely ive I have
changed B while working on A, and I build from within project A, maven will
also pickup the changes from B -- this is not true.  What will actually
happen is A will be compiled based on the last installed version of B.  IMO
the better option is to Always build from the top level of your project,
then changes across modules are always built together with dependencies in
the right order.

Re: The joys of dependencies

Posted by Phillip Hellewell <ss...@gmail.com>.
On Fri, Nov 5, 2010 at 12:16 PM, Stephen Connolly
<st...@gmail.com> wrote:
>
> This could be a bad thing.
>
> If A actually needs C to compile, then keep the dependency on C as the
> transitive deps pulling in C could change and no longer pull in C.

In many of my cases, yes A actually does need C to compile.

> If A does not need C to compile itself, i.e. none of A's classes
> reference any of C's classes _at_compile_time_ then it is correct to
> remove C from A's deps

Yep, agreed.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Stephen Connolly <st...@gmail.com>.
On 5 November 2010 17:43, Jon Paynter <ki...@gmail.com> wrote:
> On Fri, Nov 5, 2010 at 7:27 AM, Phillip Hellewell <ss...@gmail.com> 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.

This could be a bad thing.

If A actually needs C to compile, then keep the dependency on C as the
transitive deps pulling in C could change and no longer pull in C.

If A does not need C to compile itself, i.e. none of A's classes
reference any of C's classes _at_compile_time_ then it is correct to
remove C from A's deps

-Stephen
>
> 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.
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Brian Topping <to...@codehaus.org>.
On Nov 5, 2010, at 4:56 PM, Phillip Hellewell wrote:

> I'm guessing you also update the parent pom's version each time the
> dependency management section changes, yes?

Are you keeping in mind the impact that SNAPSHOT versions have on your build?  A released version is like a point on a line or an instant in time, whereas snapshots are the distance between points.  Snapshots can be for your own use only (with the 'install' goal) or to share with others who have access to a shared remote repository (with the 'deploy' goal).  If I am using snapshots, I don't have to change the version every time I make a change, since someone else's build that depends on the snapshot I deployed to our shared repository will check that repository with every build to make sure it has the latest.  In other words, if I deploy a new snapshot with a changed dependency management section, it will be picked up by others (including CI) when they run a build.

I've found CI systems to be the easiest way to manage this complexity, but I haven't found a self-maintaining way to get them to trigger with the granularity necessary to just build based on changes.  For instance, I can add one SCM repository trigger to a top-level build, but that just triggers CI to rebuild everything.  I believe this is not what you want because if CI deploys new snapshots for everything, the binaries for everything built will look stale to all the developer desktops that share the repository that CI pushed to.  On the other hand, if I have hundreds of modules and I need to create a separate SCM triggers for each one of them, the effort to maintain the build shoots way up.  It would create the desired granularity, but I haven't had a case that this would be worth it yet.

But I think your original observation of using version ranges is correct.  

Anyway, if you have a build that is this complex, you may need someone to wear the release management hat.  Maven doesn't make the problem less complex, it just does most of the work for the solution.  It won't stop people from having variations on what the correct answers are (i.e. when to change versions), hence the need to have a single authority that manages procedure the same way every build.

Brian
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Phillip Hellewell <ss...@gmail.com>.
On Fri, Nov 5, 2010 at 11:43 AM, Jon Paynter <ki...@gmail.com> wrote:
> I would do 2 things:
> First - remove the direct dependancy from A => C.  Let maven pick up 'C' via
> transitive dependencies.

I think in my case I actually want it to be there...

> 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.

I like this idea, but I'm not sure it really solves this problem.  If
I wanted to ensure everything in the dependency tree was always
building with the exact same version, I could lock them all down with
[VER].  But the idea was to be able to update C and be able to build A
with the new C without having to rebuild B.

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

So if I build a new C and put that new version in the parent pom, that
doesn't automatically make anything rebuild B.  So then when I go to
build C, does that mean C will continue to use the old B which used
the old A, or will it give me an error so then I know I have to go
redeploy B?

I'm guessing you also update the parent pom's version each time the
dependency management section changes, yes?

Phillip

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: The joys of dependencies

Posted by Jon Paynter <ki...@gmail.com>.
On Fri, Nov 5, 2010 at 7:27 AM, Phillip Hellewell <ss...@gmail.com> 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.