Exploring an Outdated Java System

I am tasked with maintaining and reorganizing an outdated Java system. I am currently involved in C # and .NET, although I am familiar with Java.

The legacy system uses RMI, a client / server architecture, and is designed for 1.4 JVMs. It uses Swing and AWT for the user interface (as far as I can tell).

My question is this: what is the best way to reconcile with the code base that I just transferred? I look at the flowcharts of the screens, defining the boundaries between RMI calls and writing down unit tests (for bits that can be checked).

What do you do in a situation where an unfamiliar code base is passed to you?

Thanks!

-Jarrod

+6
java maintenance legacy
source share
10 answers

The first thing I do with any new code I have passed is to look at the existing unit tests. Writing new tests is usually the second.

+5
source share

It very much depends on the quality of the code base. In fact, you can define it even more narrowly - it depends on how clear the code is and how well commented on it (and I write it as a person who has repeatedly been in the position of inheritance of poorly documented outdated code bases).

The worse the code base, the more you will need to get its functioning outside - if you cannot understand what the function is doing, you can at least figure out what the GUI seems to imply that it does. Having an RMI interface can be a blessing in that it gives you a simplified picture of what a GUI should see - abstracting from a remote interface is a very good idea.

If the code base is really bad, unit tests are unlikely to help you, as you can test for something wrong, even if it is implemented correctly. An example from the last thing I inherited: (names and descriptions are deleted intentionally - they were not useful in the original in any case)

public static int[] a (List<int[]> input){ ... lots of opaque rubbish return b(input); } public static List<int[]> b{ List<int[]> input) { ... more crap.... return some horribly mangled list of int[]; } 

As it turned out, to execute a, it was necessary to sort arrays by the value of their second element. Testing b to behave correctly would be futile in this case.

Suggestions to help you stay smart:

  • remove code that is not explicitly used.
  • Try to specify any "magic numbers"
  • find the links to the hardcode file, path or resource, and add them to properties or any other central, general way to deal with them.
  • try to find out if the application really works as it should have been - it’s not uncommon for some really complex function that you cannot force the head or tail to actually represent something that users felt “never worked correctly” " .
  • Find the original documentation or specifications when it was first developed.
  • Since you mentioned 1.4, summary maps can clarify which objects pass. if you have an object supported by HashMap, and how it is filled is a mystery, it can really simplify your life to determine that it is actually a line map for integers - which is often much easier to understand than what actually supposed to do.

Of course, most of this is not required if the code is well written, but then your work will be much easier anyway. And good luck.

+4
source share

One thing that helps me work with new code for me - it is much less necessary for well-written code - is to massively reorganize it for a day or two, and then discard all my changes. This process helps me understand what code does; working with code helps me figure this out. He also begins to teach me which parts of the code are fragile.

If you have the opportunity to upgrade to a newer version of Java, then a generalization of all collections will help to understand what types of data are transferred.

Of course, I do this after installing the software in a test lab and play a little with him to understand what he is doing.

Edit: reflecting on my answer, it is also useful to include all diagnostic traces and logging, use the system, and then examine the logs. If a trace of the communication protocol exists, then viewing this trace will help to understand the communication protocol used by the code, possibly with the Wireshark trace of the same test.

Another useful migration is moving from the old Concurrency library to the new Java 5 (and 6) Concurrency library. This will help you understand where the threads are and when they are started and when they will be closed.

Of course, with any changes to the code on an unfamiliar code base, I assume that nothing is broken for testing! However, to balance this out, I found out that after refactoring poorly written code, errors that were recently introduced are often much easier to find than errors that existed before refactoring.

+2
source share

The first thing I do when I get a new code is to "try to get it to work"! By this I mean:

  • first install it (according to the installation, if any)

  • then read it (by reading the user manual and launching some important use cases)

  • and then reverse engineering to find out the basic layers. classes and dependencies

  • then I can think of writing new test cases (first at the adoption level, which will be useful for testing regression)

  • then I give myself some "problems" about adding this function (even if it is not required) or improving the performance of this existing function: which is a good way to delve into the existing code base

  • of course, if there are some known pending errors / RFE, I will work on these first

In your particular case, I would also try to document RMI calls, which call or sequence of calls to do something, and associate it with usage level capabilities when possible.

In addition (and this should come first), it is important to know the main goals of this system (why does your client have this system?). Knowing the goals and keeping them will not allow you to part with these goals while saving the code.

+1
source share

There was a conversation at which I attended Mike Hill, in which he talked about the process that he uses to deal with bad obsolete code. He called it "microtesting," and it basically isolates every thing you want to test (in its own function or in a small object), and by writing tests around it. These tests do not mean statements of things in a business sense - they are intended only to fix the state in which the system is left after the test lines are executed. Typically, he claimed that the variables had the meanings they had in the debugger. Naturally, these tests will pass at the initial stage, but after he wrote enough of them, he could get a snapshot of the system.

After these tests were in place, he could start reorganizing this piece of code to try to understand what he was trying to do. He could do it safely because his “microtests” failed if he changed the way the function (or object) behaved a little. Although this meant that he could not make big design changes, he could eliminate a lot of noise, and he could get an idea of ​​what the system was doing. Once he has a clear idea of ​​what the code is doing, he can begin to improve it, find errors, etc.

There are few resources for this, so I do not provide links. Hope I have managed to describe enough to give you some ideas.

+1
source share

Experience has shown me that when studying an outdated system, there are three main goals.

  • Find out what code should do
  • Find out how to do it.
  • (critically) Find out why he does it the way he does.

All three parts are very important, and there are several tricks to help you get started.

First, don't be tempted to just ctrl-click (or whatever your IDE uses) throughout the code to understand everything. You probably won’t be able to keep everything in your imagination this way, especially when each line makes you look at several other classes to understand what it is.

Read where possible documentation; it usually helps you quickly get the mental foundation on which to build everything that follows.

Run test cases where possible.

Do not be afraid to ask someone who knows if you have a question. Of course, you should not waste the time of other employees on crazy requests, but if there is something that you simply don’t understand (this is especially true for more conceptual questions like “It would not be more advisable to implement this as ___” or something like that), it might be worth finding out the answer before you tear something up and don't know why.

When you finally start reading the code, start from the logical “main” place and go from there. Don't just read the code from top to bottom, either alphabetically, or anything (this is probably obvious).

+1
source share

Java 1.4 with RMI is not obsolete, it is practically new by some standards!

Do your best to get to know what is happening - unit tests, code / call tracing, processing of some UML diagrams, etc.

Try starting with a smaller section and tracking code paths to see where things are or assign yourself some small fixes / improvements that require you to view the code.

0
source share

Build and run this would be my first step. Begin to understand the meaning of the problem you were trying to solve.

Perhaps you can import it into a UML tool like JUDE and get an idea of ​​how classes interact.

Writing JUnit tests is a great offer. I would like to see how a layered application was. If this is difficult to verify, perhaps it is too related. Unit testing will tell you this. They will also provide you with a security system if you decide that some kind of refactoring is in order.

JDK 1.4? It ended with his support. I would also like to know if the code will build and run under JDK 5 at least, preferably JDK 6. Maybe you could hit some of these JUnit tests in JMeter and do a quick check of the load on a person with 5 simultaneous users.

If you have a data model, drag it into ERWin and start to see how tables, objects, and screens work together.

0
source share

Of course you can try to get through. Its slow, but a day spent on code can save a week finding bugs later ...

You can also try the approach to finding a scavenger, make a list of each function and go in search of code for it ...

0
source share

First skip the code to understand its structure. Then run the application in debug mode and skip it a couple of times. This will show you the flow and structure.

Use Netbeans to reverse engineer class diagrams.

0
source share

All Articles