I have an Android library used by a decent amount of people, let's call it library A.
I am building a second library, library B.
The two libraries are conceptually related, they solve different problems in the same domain. It's likely that the two libraries will be used together, but it's not mandatory.
The problem: library A contains some classes and interfaces I'd like to reuse in library B.
Are there any best practices on how to do this? This is the first time I encounter this problem and, being the libraries used by other people, I'd like to implement the solution that makes more sense.
I can see three approaches:
Are there more possible approaches I am not considering?
Problems I can see with this solutions:
com.libraryA.Interface1
and com.libraryB.Interface1
. This doesn't allow for nice interaction between library A and B.Are there any more problems I am not seeing?
Whether your third option is the correct one depends on the situation. The basic question is whether A currently contains two things that really are reasonably separate and each is useful as a distinct entity.
For example, if you break A apart into two pieces, and have a core with both A and B as clients, is it likely that the core would also do a good job of supporting C, D and E?
Or, with A broken into Core and A-prime, would you end up with a single thing that's basically broken down the middle, and most likely a C, D or E would still need to use pieces of both the Core and A-prime?
Once you've determined that, the conclusion probably becomes pretty obvious: if A really does represent two separate things that happen to (currently) live in the same library, and separating them gives a Core that's likely to be more cleanly usable on its own, then go ahead and separate them.
On the other hand, if it just happens that almost any client of A is likely to use 80% (or whatever) of what it provides, but each will use a different 80%, then it makes more sense to leave it as a whole.
As for versioning: whether you leave A as a single piece or break it into two, you have pretty much the same problem: one library with (at least) one other that depends on it.
One fairly common strategy is to break versioning into two categories: minor changes are things like bug-fixes, but for a client that depends only on documented behavior, a newer version of the library should act as a substitute for any older version. This means you can fix bugs and add features, but not make any material changes to documented behavior.
If you make a change to documented behavior, that would be a major version change. It requires that a client be aware of the change.
So, whether you break A in half or not, you have B depending on something else. For minor versions, some client might depend on having 1.1 or newer, and another client might depend on having 1.2 or newer (but in both cases, the "or newer" only includes 1.x, not some possible 2.x).
Having the same version numbers for all of them is mostly an advantage when you have a number of libraries that clearly are separate, but are (for whatever reason) used together sufficiently often that it's easier for a user to keep track of them together, so if s/he's using both A and B, they don't have to keep track of three separate version numbers.