A topic that comes up every once in a while on the forums is how to share code among several projects with more than one developer. Quite often what users try to do is to export classes and modules to a shared folder and have everyone include those in their projects. There can be issues with this technique, especially when using shared services like DropBox.
Because of the latency involved, external items shared in a shared folder on a server or a file sharing service are never truly in-sync with one another. While this technique works with a single developer across two or three projects, it gets more and more complicated as you add more projects and even more-so if you try to add more developers.
One of the largest issues with this type of system is that everything must be kept in sync all the time. Making one little change to a shared file or method which works fine in the current project could completely break a project that you haven’t worked on in a year. When you do get around to working on it again, there’s three possibilities:
- The project compiles and everything works just like it did before.
- The project doesn’t compile.
- The project compiles and doesn’t work like it did before.
With careful planning, you’ll probably hit #1 75% of the time, but the other two are wrought with problems. If the project compiles but doesn’t work correctly, you may not find out until you’ve given it to your users, with the worst case being unrecoverable data corruption. If it doesn’t compile, then what? The shared code is now required to be different in two different projects and you may have no history as to what was changed.
Thankfully the folks at who are maintaining Subversion at the Apache Software Foundation made it super easy to create shared code repositories using a feature called Externals. (For those of you that are using Git, I suggest looking into Submodules. Of the two techniques I’ve encountered, Submodules seem to require the least individual overhead.)
SVN Externals
SVN Externals are exposed as a property (svn:externals) on the containing folder and is set up using the svn propset or svn propedit commands, but most SVN visual clients have an interface for creating an SVN External to make the process easier. Once it’s set on a versioned directory, everyone who checks out or updates the working copy also gets the external definition.
It’s worth keeping in mind that because an SVN External definition points to a specific place within another repository, that this other location is also versioned. That is, you can (and probably should) point an external definition at a particular revision within that repository unless there’s a very good reason to always be pointing at the latest/greatest version. This helps alleviate the problems with shared library changes. Once you have it working for a particular version, you can lock-in to a particular date/time until you’re ready to check with a newer version.
Externals in Xojo
Setting up externals for use with a Xojo Text Project is fairly simple to do. As an example, let’s say you have two projects … ProjectX and ProjectY. ProjectX contains some items that you’d like to share with ProjectY.
- Within Xojo, Open ProjectX and make a folder named “Shared_Items” and move any items you wish to share into this folder.
- Save ProjectX and close it.
- Quit the IDE.
- Depending on whether you’re using a visual SVN client or the SVN command line the steps are similar:
- Go to the directory above where the “Shared_Items” folder is located in ProjectY
- Remove the empty “Shared_Items” folder.
- Add an SVN external with the name “Shared_Items” which points to the Shared_Items in the other repository (or branch or wherever it is).
- If you’re doing this using the command line, the command is:
svn propset svn:externals "Shared_Items https://path/to/other/Shared_Items" .
If you want to lock the project to a particular revision, you’ll need to tell SVN which revision to use:
svn propset svn:externals "Shared_Items -r12345 https://path/to/other/Shared_Items" .
Each of these commands are basically saying: Create a new external named “Shared_Items” using the https://path/to/other/Shared_Items source in the local directory (.), with the second one specifying that you want to use revision 12345. - If you’re using a GUI client you usually select the parent folder and then add an external definition from there. There are usually fields for specifying the Local Path (Shared_Items), URL (https://path/to/other/Shared_Items) and Revision (either HEAD or a specific revision number)
- If you’re doing this using the command line, the command is:
- Now you need to update the contents of the folder.
svn update Shared_Items
- Open ProjectY.
- Drag the “Shared_Items” folder from the project folder directly into your project. DO NOT SAVE YET. Any modules which contained other items will be represented by a Module in the project and an identically named Folder which contains the items that should be put inside the module.
- Referring back to Project X, drag each of the items in Shared_Items to its corresponding location in ProjectY. It’s very important that the on-disk representation in both projects be identical, so make sure you’re using the same version of Xojo in both projects. For example, if after dragging in the Shared_Items folder, you might have:
Shared_Items Module1 (Module) Module1 (Folder) Class1 Module2 (Module) Module2 (Folder) Class2
- If you have multiple levels of nested modules, I suggest working from the bottom up, that is from the lowest directories up to the highest ones to avoid confusion. Once you’ve emptied a folder, delete it. Using the example above:
- Drag Class2 from the Module2 folder directly into the Module2 module.
- Delete the Module2 folder.
- Drag Class1 from the Module1 folder directly into the Module1 module.
- Drag Module2 module into the Module1 module.
- Delete the Module1 folder.
- Once the structure looks the same between the two projects, Save ProjectY. You’ll notice that on disk the folders are still there. That’s exactly what you should see. Check your SVN client, there should be no changes to be checked in. If there are, make sure they’re not file additions and/or deletions.
From now on (if you’re using a non-revision specific external), whenever you make a change to one of the items in this Shared_Items folder and check them in, they’ll be available to any other projects that use them, whether it’s the original items or any project where this folder is defined as an external.
While this looks really complicated to set up, once it’s done using the external will work and feel just like any other folder in your project.
A few things to remember:
- Make sure you’ve named the shared items container so that it’s obvious that the items are shared between projects, so things don’t get inadvertently dragged into the folder if they’re not needed anywhere else and not dragged out of the folder if they are.
- Make sure everyone on your team understands that this code is shared among projects.
- Write Unit Tests for your shared items so when making changes you can verify that you’re not breaking other projects or inadvertently changing their behavior.