5

Edit: Assume that I will stay on this project until "the end".

The Problem

I'm currently working on a legacy interesting Java project(s).  A full rewrite is currently out of the question, as I am working alone, and the current desired functionality was due months ago (before I came onto the project).   

It is rather large, and includes:

  1. JDK 1.5 
  2. Essentially 0% test coverage
  3. 7 separate Java projects that contain a very circular build
  4. Ant and Maven (which I want to upgrade into Gradle)
  5. A Java Webstart GUI app
  6. Drools 5.5 (manages almost all important functionality)
  7. 3 Apache Tomcat servers (running Apache Axis, which was last updated in 2006) 
  8. and many other deprecated libraries that... do things

I have gotten it compiling and running correctly in a new development environment, and have upgraded the JDK off of 1.5 and have started using 1.6/1.7/1.8 where I can.  I have also updated Drools to 5.6.  I have just barely gotten the project to a point where it is possible to make changes and verify it in a somewhat sane manner while having it run in a non-deprecated env.  However, there are many areas of the code where large chunks have been copy pasted into the other projects, and have since been maintained differently.  I am largely unsure of what anything does - outside of the "main flow".

What the @!#$? did I get myself into?

What I want, is to refactor this thing in a way that makes sense, but doesn't take me too long.  I was thinking of just ripping all the types and whatever that functionality are making it circular out into a separate "SharedJunk" project?

But, what I need, is to get new functionality, and it was asked for yesterday.

Do I just slam my face into churning out more of the same quality of work that has led this project into this near-unmaintainable-death-state?  Or do I refactor?  There is an infinite amount of cleaning to do.

My boss is very patient, and wants this "done the right way", however, he is fighting off pressure from other areas of the company and I feel he might not hold out forever.

The options

  1. Refactor forever
  2. Refactor the bare minimum
  3. Slam my face into banging out new code
  4. Cry

Any general advice on what to do on this sort of project would be greatly appreciated.  I am currently rereading through Working Effectively With Legacy Code and Refactoring to Patterns. I can clarify this, but I am unsure what to add.

Thank you.

7
  • 4
    You try 2 so management will ask new functionality and you end 3 but bugs happens and you 1. At this point you will much be switching between 1 and 3 until you 4 and quits
    – jean
    Dec 1, 2017 at 17:27
  • @gnat should I edit to add more specifics? I.e. how to replace a overly bloated rule engine? Or just post a more specific question to SO?
    – Nathan
    Dec 1, 2017 at 17:39
  • Just by upgrading the JDK you are going too far. You have been requested to maintain It, not to do what you would like to do. You have to choose wisely your battles. This one is not the right one.
    – Laiv
    Dec 1, 2017 at 19:40
  • Upgrading to JDK 8 is currently the next requirement down the road. I did not spend more than a couple days on this.
    – Nathan
    Dec 1, 2017 at 20:20
  • 1
    My (limited) experience upgrading from JDK 4 to 6 to 8 has been surprisingly painless. I think that's a good first step to see how many problems exist. Perhaps should be added to the question as part of OP's effort to avoid the "duplicate" tag.
    – user949300
    Dec 1, 2017 at 23:34

2 Answers 2

3

Because you have no requirements, your requirements essentially become: make it do what the old thing does, until you are told otherwise. I only know of one way to successfully deal with this.

You need to create/acquire/find as much data as you can related to the usage of this system. That is, you need tons of input data. Volume is key in this strategy. Run all the input data that you can get your hands on through the existing code. Capture all the output organized in a way that you can relate an inputs to resulting outputs.

Depending on the system, this could be easy or it could be hard. If it's a stateless system (doesn't modify state) then it's generally pretty easy. Otherwise, updating state is an output and you need to capture that too.

Then take the exact same inputs (database state included) and run that through the new version and capture it the same way as with the old. Diff every new output with the corresponding old output (with a script) You may need to ignore/rationalize certain fields such as timestamps and UUIDs. Any change you find should be due to your new requirements. Anything else is either regression error or a 'happy accident' where you fixed a bug unintentionally. These might not be worth keeping due to the time they can add to reviewing the results. The key here is to maximize the amount of tests that match exactly and minimize the number of things you need to evaluate by eye. If you can automate the non-match validations, that's a big win.

This is not bulletproof by any means. It's only as good as the inputs you push into it. If you miss scenarios, you could get a clean everything matches result and still have regression issues. Since you don't know what the scenarios are (code may clue you in) there's not much you can do but try to get a lot of varied inputs. If something slips through, don't despair. Just find some data that tests the missed scenario(s) and repeat. I've used this approach many times and had excellent results. Often this will expose more issues than standard testing practices do.

5

Do not refactor.

"done the right way" is just ass covering and not yours!

  • Get clear requirements and implement them with the minimum number of code changes.

  • Get sign off that the app works and the requirements are met.

8
  • Previously there were only verbal requirements. I have tried to get more clarity, and so have gotten my requirement capture signed off by my boss.
    – Nathan
    Dec 1, 2017 at 17:31
  • write them down and email the boss "are these the requirements?"
    – Ewan
    Dec 1, 2017 at 17:32
  • If I do not refactor I need to black box only. However because of the rule engine bloat... It is very difficult to get new functionality functional. Thus far it has been outside my ability.
    – Nathan
    Dec 1, 2017 at 17:41
  • at this stage its more of a #theworkplace issue. you have an impossible task, try to do it without breaking existing stuff and move on to another project asap
    – Ewan
    Dec 1, 2017 at 17:45
  • 2
    It is not impossible to do what the business has required. Getting the functionality adds/changes in does not require a refactor. The argument may be, that the code changes will take longer because the code is hard to follow and work with, but you would face those same challenges trying to refactor. Plus, it would take longer to refactor all versus fully understand the parts you need to change. What is impossible is to satisfy the requirements and also end up with an ideally structured code base for future maintainability. Get the requirements done and circle back to transform the code. Dec 1, 2017 at 19:05

Not the answer you're looking for? Browse other questions tagged or ask your own question.