Today, for a demo, I needed to install and run a system on my laptop that hasn’t been run in about 4 years. I was curious going into the exercise how much Software Erosion will have occurred in the intervening 4 years. Wikipedia defines Software Erosion as:
“the slow deterioration of software over time that will eventually lead to it becoming faulty [or] unusable” and, importantly, that “the software does not actually decay, but rather suffers from a lack of being updated with respect to the changing environment in which it runs.” (Emphasis added.)
If you’re interested in the topic, I highly recommend you read the twelve-factor app which is all about steps you can take at design time to reduce the impact of software erosion.
Overall, the experience wasn’t too bad. I was able to get the system up and running in about a day. But it was interesting to see the kinds of problems I ran into.
1. Compiling. 10 minutes
Fortunately, this was a maven project, so all third-party jar version dependencies were explicitly declared in the Project Object Model (pom) file for the project. The only gotcha here was that one of the dependencies was no longer on the repository it used to be–probably due to changing distribution rights (“richfaces” was no longer available on java.net). But I quickly found another repo with the required jar (jboss.org) and had a successful compile using “mvn install” in about 10 minutes.
2. Database. 5 minutes.
The next thing I needed to set up was a database. This part was easy too. I ran the application and it printed a simple error message telling me the name of the database it was looking for. I created the database and reran, and the automated startup database migration scripts automatically created the tables and populated them with the data required for the system.
3. Spring Application Context part 1: 1 hour
The next thing I needed to do was to get the Spring Application Context to successfully load. This is where I hit my first hard environmental dependency. This application was built back when we had an external monitoring system called “devcreek” that was used to monitor performance, build times, etc. etc. Something in devcreek has changed in the past 4 years that caused this dependency to stop working. I didn’t need this monitoring for my demo, so I set about detaching this dependency.
Easier said than done. I tried really hard to do this work without firing up an IDE (just editing ApplicationContext.xml in a text editor) but it became clear after about an hour that I would need to fire up the IDE.
4. Compile in an IDE: 5 minutes
You’d think that if the code compiled in maven that it should compile in eclipse after a simple “mvn eclipse:eclipse.” But I got complaints about a missing XMLConstants field. Fortunately, I’ve seen this sort of error before and knew to move the JRE dependency in the Build Path up to the top of the classpath to fix it. It worked!
5. Spring Application Context part 2: 1 hour
Now that I’m in an IDE, it’s easy to call up bean classes referenced in the ApplicationContext. After reading the source code I tried really hard to change their behaviour by modifying how they were referenced in the ApplicationContext. But after about an hour it became apparent that my quickest path to resolving this problem was to write some new java code to stub out the old devcreek behaviour. Ugh
6. Spring Application Context part 3: 15 minutes
I wrote a “null” implementation of the devcreek PerformanceWriter bean that the Spring Application Context needed. Fired her up and finally my Spring Application Context loaded!
7. Login to the app: 1 minute
I logged in and performed a few basic operations. Everything worked. Yay!
8. Get a transaction to work: 1 hour
I tried to submit a transaction in the application. This application is meant to be run on a collection of network nodes. For demo purposes, the sender and receiver node run on the same machine. The catch is that such communication needs to be secure, and secure communication is ensured through, uh oh, a certificate.
The certificate the system was using expired in 2011. So all I needed was a new certificate. I probably don’t need to tell you why this step was hard, but here are the details in case you’ve never had to deal with certs in an old app.
- Certs are used in 3 different ways in 3 different places in the app. I only needed 1 of these certs to work for my demo. But it wasn’t straightforward to find out which cert file I needed to update. I ended up using process of elimination–deliberately corrupting certificate files one at a time until I found the one that generated a new error message when my app tried to use it.
- Creating a new cert file is a bit of a dark art. I first tried using java keytool.exe but it complained that the cert wasn’t “Initialized”. When I couldn’t figure out how to initialize it in 5 minutes I just tried creating the cert in a different way–first creating a Microsoft pfx file and then using a tool we had written for this project to convert it to a keystore. This worked!
When writing software, think very carefully about your external dependencies and ask yourself will they really be there 5 years from now? 10 years from now? And if they might not be, then how can the system gracefully recover. Specifically:
- I wonder if instead of depending on external repositories, maybe all our projects should depend on an internal repository that we mirror from external sources.
- Devcreek should have probably just logged a warning and turned itself off it it wasn’t able to contact the mothership instead of blocking the Spring Application Context from loading. This should be the case for any external monitoring coupling.
- Certs are a tricky one. They’re going to expire and you’re going to need to make new ones. Maybe always allow the system to run in “Demo mode” that doesn’t require certificates for communication.