Episode 1 – how to organize lost code and deal with it without panic.
There is a nightmare that keeps haunting and haunting developers. It’s called refactoring of an existing product. It is not a secret to anyone, that a legacy code is often considered to be developer’s worst enemy, but at the same time we all know there are situations when there is no room for developing the project from scratch, e.g. because it’s an existing commercial product or simply because it has been continuously developed for 10 years already and the client does not have another 10 years or any other means to develop it again. It’s not a secret that such kind of jobs are not the most desirable, but they happen and give you a choice: to sit down and cry or to take it and find a solution.
Fortunately, you are not alone – since we have already saved a number of projects since the beginning of our company in 2002, we consider saving somebody’s butt as one of our core expertises. Fighting for a better world for developers, we have decided to share our knowledge, experience and interesting cases to write a series of blog posts about refactoring and taking over development of existing products, which appears to be one of the most hated problems in modern software development.
Let us start then, enjoy responsibly!
In the first article we should obviously start the first steps to follow when starting to work with an existing codebase developed in Java.
So, there is a nightmare out there that keeps haunting java developers – you are taking over an existing project with a huge codebase provided by the client in the form of ZIP archive. Not scary enough? Good, but what if we add that the project is already in the production stage and it is unknown which version of the code is installed on the production server?
Since it is a production environment, you cannot afford the risk of overwriting the existing working copy by something new and possibly breaking it.
And of course, as it usually happens in such kind of jobs, the developers who originally developed the project vanished, so you are in a major trouble.
Of course, we all agree it is better to avoid getting such projects in the first place, but at the same time we all agree as well that sometimes shit happens and you have to do your best to deal with it.
But don’t worry, you are not alone. Below you can find our time-proven practises coming out of experience in dealing with such situations for more than 10 years already.
Step 1: Don’t panic
First of all, understand and accept the fact that in order to sort this puzzle out, you will have to spend some time on investigation. This work is in some part related to the work of an archeologist, who is moving step by step toward the translation of the cuneiform he found.
Remember to stay very careful and for no reason on earth should you hurry. You should backup everything that is possible to backup – folders on the server, etc. and only then proceed with the next actions.
Below you can find some battle-tested recommendations that will help you to solve this issue with no one harmed.
Step 2: Information
Get from your client all the information possible about the source code structure, technologies used and exact versions of the libraries. It often happens that customers has some indirect information on this topic, probably in any correspondence with previous developers – emails, chats and calls.
Take a look at what is currently working on the production server, like which application server, which version of Java, exact versions of libraries (a hint: in some cases you can calculate that by the names of jar files).
In great majority of cases, the project was most likely created and compiled in the same version of Java as the one on which the production server is running. But, there is a chance that it was not.
To make sure, take any of the classes from the server and use JDK’s utility javap.
If you run this command:
javap -verbose <YOUR_CLASS>.class, you will be able to find in the output something like that:
minor version: 0
major version: 50
Now, the meaning of major versions is following:
J2SE 11 = 55
J2SE 10 = 54
J2SE 9 = 53
J2SE 8 = 52
J2SE 7 = 51
J2SE 6.0 = 50
J2SE 5.0 = 49
JDK 1.4 = 48
JDK 1.3 = 47
JDK 1.2 = 46
JDK 1.1 = 45
Thus, you now know the Java version in which the project was compiled.
Step 4: Is our source code valid?
Knowing the correct version, now is the time to make sure the source code that you have corresponds with the classes installed on the production. To do this, apply the following trick:
- Compile the source code in the version of java in which the classes on the server were compiled.
see previous step
- Use the decompiler and decompile the resulting classes to a folder. For example, using decompiler plugin built into JetBrains IDEA you can run:
java -cp java-decompiler.jar org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler FOLDER_WITH_COMPILED_CLASSES FOLDER_TO_DECOMPILE_TO.
FOLDER_TO_DECOMPILE_TOmust exist before you run this.
- Use the decompiler and decompile the classes taken from the server to another folder.
- Use any folder comparison tool to compare files obtained as a result of decompilation.
For example, you can use WinMerge utility.
As a result, you will receive a list of files in which mismatches are found. If you are lucky, then there will be only a few or no such files at all.
Step 5: Recover the source code
As the next step, you need to work with each file separately. Where the difficulty lies, is that at this stage of the project you probably still don’t know how everything is arranged within it and which version should be kept. You can use the following methods:
- Save a list of such files somewhere and remember to give them special attention in the future and be very careful about them.
- If possible, make changes to the source code in a way that will make it as close to the state of production as possible. It is better and safer to spend time on re-implementing the lost changes than to install unverified and unpredictable code to the production.
- Use a version control system (such as GIT) so that you can later understand what you changed and what the initial state was.
The above methods should give you a better orientation in project’s codebase and most importantly make you feel more confident and convenient with the project as a result. Now, when you finally can understand that mess and see the correlations with it, it will make it a lot easier to work with the project and move to the next big stage, which is refactoring. However, since that’s a topic not only for a separate article but rather a series of articles, we will give some more recommendations on it in the following chapters.