views:

209

answers:

9

Hello, everyone!

I have a project (related to graph algorithms). It is written by someone else.

The code is horrible:

  • public fields, no getters/setters
  • huge methods, all public
  • some classes have over 20 fields
  • some classes have over 5 constructors (which are also huge)
  • some of those constructors just leave many fields null
    (so I can't make some fields final, because then every second constructor signals errors)
  • methods and classes rely on each other in both directions

I have to rewrite this into a clean and understandable API.

Problem is: I myself don't understand anything in this code.

Please give me hints on analyzing and understanding such code.

I was thinking, perhaps, there are tools which perform static code analysis and give me call graphs and things like this.

+2  A: 

Well, the clean-up wizard in eclipse will scrape off a noticable percentage of the sludge.

Then you could point Sonar at it and fix everything it complains about, if you live long enough.

bmargulies
Well, that wizard says "The refactoring does not change any source code" ;) This wizard seams to concentrate on missing or redundant things, not bad architecture.
java.is.for.desktop
Source/Clean Up sure does change code. It will, for example, add getters and setters.
bmargulies
Ok, I've ran it after I had encapsulated fields already ;)
java.is.for.desktop
But Sonar looks nice!
java.is.for.desktop
@java.is.for.desktop - no tool can automagically fix bad architecture. You have to do the thinking yourself.
Stephen C
I wast not expecting automagical tools ;) But such that would help to do the thinking.
java.is.for.desktop
+5  A: 

WOW!

I would recommend: write unittests and then start refactoring

* public fields, no getters/setters

start by making them private and 'feel' the resistance on compiler errors as metric.

* huge methods, all public

understand their semantics, try to introdue interfaces

* some classes have over 20 fields

very common in complex appilcations, nothing to worrie

* some classes have over 5 constructors (which are also huge)

replace them by by buider/creator pattern

* some of those constructors just left many fields null

see above answer

* methods and classes rely on each other in both directions

decide whether to to rewrite everything (honestly I faced cased where only 10% of the code was needed)

stacker
You've to understand the business requirements, this will give you the skill to refactor the code nothing else could do so, sorry for bad news
stacker
I definitely agree that unit testing is the place to start. I want to see how it runs, if it really runs before altering anything. Paraphrasing Tyrell in movie Blade Runner "I want to see it work on a person. I want to see a negative before I provide you with a positive."
Vinny
+2  A: 

For static analysis and call graphs (no graphics, but graph structures), you can use Dependency Finder.

Damien B
Looks not bad, I'll give it a try. But I'm afraid, only a bit of my problems can be solved with it.
java.is.for.desktop
Indeed. I'm not sure you'll find a single tool / approach to solve all of those problems :-)
Damien B
+1  A: 

The answer may be: patience & coffee.

Andrei Ciobanu
+1  A: 

This is the way I would do it:

  1. Start using the code , e.g. from within a main method, as if it were used by the other classes - same arguments, same invocation orders. Do that inside a debugger, as you see each step that this class makes.
  2. Start writing unit tests for that functionality. Once you have reached a reasonable coverage, you will start to notice that this class probably has too many responsibilities.

while ( responsibilities != 1 ) {

  1. Extract an interface which expresses one responsibility of that class.
  2. Make all callers use that interface instead of the concrete type;
  3. Extract the implementation to a separate class;
  4. Pass the new class to all callers using the new interface.

}

Robert Munteanu
+1  A: 

Not saying tools like Sonar, FindBugs etc. that some have already mentiones don't help, but there are no magic tricks. Start from something you do understand, create a unit test for it and once it runs green start refactoring piece by piece. Remember to mock dependencies as you go along.

ponzao
+6  A: 

Oh dear :-) I envy you and not at the same time..ok let's take one thing at a time. Some of these things you can tackle yourself before you set a code analyzing tool loose at it. This way you will gain a better understanding and be able to proceed much further than with a simple tool

  • public fields, no getters/setters
    • make everything private. Your rule should be to limit access as much as possible
  • huge methods, all public
    • split and make private where it makes sense to do so
  • some classes have over 20 fields
    • ugh..the Builder pattern in Effective Java 2nd Ed is a prime candidate for this.
  • some classes have over 5 constructors (which are also huge)
    • Sounds like telescoping constructors, same pattern as above will help
  • some of those constructors just left many fields null
    • yep it is telescoping constructors :)
  • methods and classes rely on each other in both directions
    • This will be the least fun. Try to remove inheritance unless you're perfectly clear it is required and use composition instead via interfaces where applicable

Best of luck we are here to help

Yiannis
+2  A: 

Use an IDE that knows something about refactoring, like IntelliJ. You won't have situations where you move one method and five other classes complain, because IntelliJ is smart enough to make all the required changes.

Unit tests are a must. Someone refactoring without unit tests is like a high-wire performer without a safety net. Get one before you start the long, hard climb.

duffymo
A: 

Sometimes it is easier to rewrite something from scratch. Is this 'horrible code' working as intended or full of bugs? It is documented?

In my current project, deleting my predessor's work nearly in its entirety, and rewriting it from scratch, was the most efficient approach. Granted, this was an extreme case of code obfuscation, utter lack of meaningful comments, and utter incompetence, so your mileage may vary.

meriton