• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Rob Spoor
  • Tim Cooke
  • Junilu Lacar
Sheriffs:
  • Henry Wong
  • Liutauras Vilda
  • Jeanne Boyarsky
Saloon Keepers:
  • Jesse Silverman
  • Tim Holloway
  • Stephan van Hulst
  • Tim Moores
  • Carey Brown
Bartenders:
  • Al Hobbs
  • Mikalai Zaikin
  • Piet Souris

refactoring without test units

 
Ranch Hand
Posts: 995
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi!

I was wondering what can be done in the following scenario:
- large project
- refactoring required on the main business logic of the project (aprox. 1/4 of the no. of sources)
- no unit testing available
- no written documentation about the requirements
- no guys that initially worked on the project

./pope
 
author
Posts: 11962
5
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Start small?

First try to look for a place where you can write unit tests around the legacy code. Then, try to figure out how to extend unit test coverage to the neighbouring code, slowly making your way towards a big enough safety net to allow you to move fast (refactoring without needing to test everything manually after each small edit).
 
Alexandru Popescu
Ranch Hand
Posts: 995
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Lasse Koskela:
First try to look for a place where you can write unit tests around the legacy code.



How can you do this when you don't know the real expectations? You have no means to guarantee that the original code was performing correctly, and so the tests may show you fake results.

./pope
 
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ah, if you don't know if the prior code was returning correct results the safest thing may be to return identical reesults until you've refactored into something you can understand better and look for somebody who can help write acceptance criteria.

Are you in a language or architecture that doesn't support unit testing as we know and love with JUnit? You may have to do manual tests. Any kind of automation would be better than that but you'll have to figure out if it could be cost effective.
 
blacksmith
Posts: 1332
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There are some modifications that can be done without too much risk of breaking the code, even without automated tests.

Usually the first problem one runs into when trying to fix legacy code is that it's difficult to understand, and even after one figures out a section of code, one forgets when one moves on to another sections of code. When one comes back to the first section, one has to figure it out all over again.

In this case, whenever you've figured out a section of code, add a comment to document it. That way, when you come back, you can just read your comment and save a lot of time. Put dates and initials by your comments so you'll later be able to tell how reliable they are - early comments may be wrong, but later ones may be based on more knowledge. And adding comments rarely breaks the code.

The next thing that's often useful is to start doing some renaming. As long as you avoid using names that are already taken, renaming of local variables is safe. You can use those comments you wrote as a guide to finding better names. You'll know when you've got sufficiently good names when the comments become redundant. And in long functions full of spaghetti code, renaming variables can be extremely useful, since it will help identify cases where a variable that's used for one thing at the beginning of the function is reused for something different a few hundred lines later in the function.

Once you've identified multiple use variables, you can then start splitting variable scopes. When a variable starts getting used for something different, replace it with a new variable. This will reduce the the unnecessary coupling in those long functions. As distant parts of the longer functions start getting decoupled, you can then start decomposing them into multiple shorter funtions.

With more functions available, it will then be easier to start writing tests. Once you start getting the tests written, things will start going faster. You'll be able to refactor in bigger steps and take a few chances. Soon you'll be making real visible progress.

Anyway, that's my advice. Tests are an excellent tool, but it's not impossible to make progress without them.
 
Alexandru Popescu
Ranch Hand
Posts: 995
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Interesting point Warren. I will describe shortly 2 of my experiences: 1 completed successdully and the 2nd just starting now :-).
The condition for both are the same as described in my 1st post.

1. Fully refactoring of the core framework.
The main thing used as a target of the refactoring was to finally present the same open API (to present the same exposed interfaces). A nice step done during this process was to reduce in fact the exposed interfaces to only the used ones. I did this cause the dev was going on in the other teams and I wouldn't like to block the other guys, but also allow me to work on the real needs. One by one I've passed through all of the publics and in small-medium steps I have refactored almost all of 'em (and at a later stage even reimplement 'em). The result was the same API but the backend changed in aprox. 65%. The plus of this work: the core was reduced from aprox 200 objects to just 100, LOC reduced by 60% and 22% improvement in performance ;-).

2. Main business logic refactoring
I must say that I am planning on this for some time. I intend to preserve the actual behavior moving it in some test units - not exactly JUnit alike.
Than I will leave as exposed interface only what is used at this moment. In the final step I intend to slice it down and fully refactor it slice by slice.

./pope
 
Ranch Hand
Posts: 103
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Three additional tips from my experience:

- get a good refactoring browser - it will be invaluable;

- write system level, end-to-end tests - they don't depend on the testability of the code as much as unit tests, don't need to be adapted to design changes as much, and make sure that the whole system works as expected (not only single units);

- assess the code quality and the cost of new bugs. One of the projects I am working on is the maintenance of a product with a very bad bug history, which isn't yet used much in production. Even if with a refactoring I introduce a new bug, I will fix ten others at the same time and the customer will be happy because of the increased stability. He still doesn't like it when bugs reappear, though - therefore see the previous tip...
 
Alexandru Popescu
Ranch Hand
Posts: 995
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Daniel Mayer:
Three additional tips from my experience:

- get a good refactoring browser - it will be invaluable;



What do you have in mind when you're saying refactoring browser? Any examples? (I think I never used one :-( ).

./pope
 
Lasse Koskela
author
Posts: 11962
5
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ali Pope:
What do you have in mind when you're saying refactoring browser? Any examples? (I think I never used one :-( ).


I believe the term "refactoring browser" originates from the SmallTalk "IDEs" that supported refactoring by letting the developer know how a given change would ripple through to other files. I've never done any SmallTalk so I might be blatantly wrong, but I assume that the refactoring wizards of modern Java IDEs are pretty close to what the SmallTalk refactoring browsers were.
 
Alexandru Popescu
Ranch Hand
Posts: 995
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Lasse Koskela:

I believe the term "refactoring browser" originates from the SmallTalk "IDEs" that supported refactoring by letting the developer know how a given change would ripple through to other files. I've never done any SmallTalk so I might be blatantly wrong, but I assume that the refactoring wizards of modern Java IDEs are pretty close to what the SmallTalk refactoring browsers were.



10x Lasse. I was asking mr.google for some java refactoring browsers but no results, so I guess your opinion is right.

./pope
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic