Brent Simmons has some thoughts on managing shared code. Those ideas are a good start, the most important being that this code needs to be under some kind of source code management tool, preferably one with good branching/merging facilities.
There are a couple of other ideas to keep in mind. Brent’s further bifurcation of code into Foundation and UIKit sub-sections is a good idea. Indeed, it’s not a bad idea to start thinking of the relationship between your app and the OS as being the meat (tofu for the vegans out there) in a sandwich. The Foundation code is the bottom slice of bread, and the UIKit/NSFramework stuff is the top slice of bread.
However, I’d take it a step further and break the code up into functional units. In Brent’s case, I’d imagine that there’s a networking stack, some XML parsing/XML RPC code and some data store manipulation just in the Foundation tree alone. I’d keep those separate from each other.
I’d also reconsider the idea of building static libraries. The shared code, along with the unit tests and any other acceptance testing code, should be in at least one separate project, but it’s even better to have each functional unit of code in its own project. The linker should be able to dead-strip anything that any given client doesn’t use, especially if these are static libraries, and having separate projects ensures that the code is always built the same way regardless if which client is using it. Managing the build settings for one shared project is much simpler than trying to ensure that the build settings are consistent across all the projects that use the shared code.
If debugging is a problem, then create separate build and debugging/development projects. The latter can help reduce the time required for the edit/build/debug cycle to complete, yet still retain the functional separation that is beneficial to code that’s shared.
Once you’ve separated pieces out into projects according to functional units, have each project build a framework that exports the symbols that are “public” for that shared piece. You can still link the static libraries for actual distribution bits. Indeed, the target that builds the framework should have a single, dummy source file while the framework links in the static library that’s actually shared. Doing this will tell you what the interdependencies are between the various functional units. You’ll discover whether or not some circular dependencies have crept into your code, and those will almost certainly end up causing you headaches in the future (if they aren’t already causing you headaches now).
Remember, agile programming isn’t about you being agile. It’s about making your code agile. And, if you’re sharing code, it really needs to be agile enough to work in the variety of contexts in which its shared.
Currently playing in iTunes: Lost In the Flood by Bruce Springsteen & The E Street Band