Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I've been reading and thinking a lot lately, and I've come to the conclusion that I maybe I should rethink my web development strategy. I'm doing a lot of on-the-fly programming, and in the 2 years I've been working on a PHP web application, what might have begun as a little tool became quite the big project. But there is a ton of legacy code from me and my predecessor, snippet of code that might have make sense at the time, but now I'm questioning the usefulness of said code in the form it is actually. Furthermore so such things like unit testing and Test-Driven Development wasn't in my scope until quite recently.

So how would you approach refactoring the web application? What would be the things I should look for and in which order? What about browser game versus functional web app? Would there be then difference in the approach?

share|improve this question
3  
If it ain't broke, don't fix it. Spend more time writing tests, and less time making unnecessary changes. –  Macneil Dec 17 '10 at 15:17
    
Just out of interest. What language/technologies have you used to write your application? What kind of site is it? See welie.com/patterns -> Context of design -> Site types –  JW01 Dec 19 '10 at 20:25
    
@JW01 I use PHP for internal logic and AJAX for view management and form validation. This would be a variant of the Web-based Application pattern but only available in a given environment, as it is an internal tool. –  Eldros Dec 20 '10 at 9:11
    
I had a completely different picture of your app in my head when I answered the question. You have so much more freedom to change the API than if it were in the public domain. –  JW01 Dec 20 '10 at 9:58
    
@JW01 I didn't want to be too specific, as I wanted this question to be useful to others too. –  Eldros Dec 20 '10 at 10:02

5 Answers 5

up vote 6 down vote accepted

Pretty much the same way you approach any kind of legacy code. You find a piece that's testable, you write tests for it, and refactor.

If you can't find a piece readily testable, you'll need to make it testable without the safety harness of a test suite, in which case you very carefully change some almost-testable piece of code so that it is testable.

Code that doesn't render things to the browser - "infrastructure" code, models, database-touching stuff - might be a good place to start.

Edit: UI testing: With the warning that I have little experience here, a friend of mine does this: he runs some piece of HTML-generating code. Then he hacks on his code, and compares the newly-generated code against the old version (using diff; he hasn't automated all the way). Changes in the HTML means your refactoring broke.

share|improve this answer
    
How would you recommend testing the "view" portion of a legacy application - IE, the HTML/JavaScript/CSS/etc portion? I agree unit testing is the way to go, but the testing of application code seems difficult to automate. –  Justin Ethier Dec 17 '10 at 18:26
    
when creating tests for a web UI - comparing old HTML to new HTML is a kinda fragile way of doing things. I tend to identify the semantics of a web page and test that. I.e. ask "Has the web imprint (page title, headline, keywords, outbound links, forms) changed?" not "Has the HTML changed?". –  JW01 Dec 18 '10 at 21:56
    
You can test web apps with a 'headless browser' - basically a library that is for a unit test what a browser is for a QA guy. In the java world, there are HTMLUnit (pure java, self-contained) and WebDriver (remote-controls a real browser like FireFox). My project has a suite of hundreds of tests written like this. –  Tom Anderson Dec 19 '10 at 13:44
    
@JW01 You're absolutely right - it's very fragile. It's great for testing a refactoring in a once-off kind've way: you can check that the refactoring didn't change the output, but every time you change the HTML generated, you have to save the "new expected" HTML. –  Frank Shearar Dec 19 '10 at 15:00

There's a great book about this called "Working Effectively with Legacy Code" by Michael Feathers. Let's face it, we all have legacy code.

The main thing is to test-drive the new code that you're creating. As you have to touch other pieces of code, you'll find opportunities to get those under test as well. It's a long slow process, but if you go about it systematically, you can really improve the overall product over time.

share|improve this answer
3  
"Let's face it, all we are doing is writing tomorrow's legacy software today." -- Martin Fowler –  Frank Shearar Dec 18 '10 at 17:10
1  
+1 Excellent book. It's helped me out before. –  Grant Palin Dec 18 '10 at 19:53
  • Yes - Web Applications are different to Web Sites

I would treat them separately. If you have one part of your site that is simply a collection of documents (that look the same to anonymous users and logged-in users alike) - then the best method of structuring it is very different from a web app that serves dynamically different pages to each user. Split those two parts of the site up into two apps / components and tackle each part differently.

  • Start Using Version Control

Once your code is under version control, you can go through and, confidently, remove all unnecessary code that you had previously kept 'just in case' etc. I don't know how I survived without version control.

  • Reduce the infinities

If four different urls all point to the same resource, then the problem is much bigger. You end up dealing with an infinite amount of urls. As soon as you can, ensure that you have an URL Normalisation policy in place. Once that is done, you can start attaching semantic meanings to URLs and be able to do reverse lookups from resource-to-url. This allows you to separate the 'web imprint' from the 'resources' of the site.

You have to ask yourself, "given an url what is its normalised form?". Once you have got this pinned down. Then then 50,0000+ urls on your site can be reduced to say, 2,000. which is a lot easier to comprehend and manage in your mind.

see: http://www.sugarrae.com/be-a-normalizer-a-c14n-exterminator/

  • Start by modelling 'what is', not 'what you want it be'

If you are tidying up a legacy site, that was not designed with best practice in mind from the start, then it is tempting to jump from 'a mess' to 'the ideal design'. I believe that you need to do it in at least two steps: 'mess' -> 'well modelled legacy code' -> 'ideal new code with added features'. Stop adding features. Concentrate on fixing the mess or encapsulating it behind an anti-corruption layer. Only then, can you start to change the design into something better.

See: http://www.joelonsoftware.com/articles/fog0000000069.html

See: http://www.laputan.org/mud/

  • Putting it under test is a good idea.

Create a test suite / framework and start adding tests. But, its quite tricky to test some legacy code. So, don't get too hung up over it. As long as you have the framework there, you can add tests little by little.

See: http://www.simpletest.org/en/web_tester_documentation.html

  • Have courage in your convictions

Most of the literature on best practices of software development is desktop-centric/Enterprise App Centric. While your site is in a mess you read these books and you can be in awe of the wisdom that exudes from them. But, do not forget that most of this best practice has been accrued in times before the web/SEO became important. You know a lot about the modern web, more than is mentioned in classic books like POEA, Gof etc. There is a lot to take from them, but do not completely discard your own experience and knowledge.


I could go on. But those are some things that I have picked when refactoring an old legacy site into a shiny new one.

share|improve this answer
    
Good reference links! –  Nilesh May 20 '11 at 14:13

Before doing anything, it is best to have your project in source control. This way, you can rollback changes, or work on major changes on a seperate branch, as well as tag milestones.

Next, write tests for any code you plan to change. You don't need to go all out all at once, writing tests for everything. Just what you plan to be immediately working on. The theory goes that given enough time, most of the code base will be covered by tests. Note that some refactorings are "safe" to do without tests - these are documented in the Legacy Code book mentioned earlier, and doubtless elsewhere.

With tests in place for a section of code, change the code. Do whatever you need to, as long as the tests still pass.

Even with legacy code, you can do TDD if making additions or changes. Just write tests first for your anticipated changes, see them fail, and then make the changes.

Some tools may be useful here. NDepend can point out highly coupled code and other smells. NCover tracks your code coverage levels. FxCop is essentially a code correctness checker, beyond what the compiler does. These are all useful tools to have handy for a project of any real size, especially the legacy variety.

Ultimately, it's a multi-step process. Don't try to do it all at once, just take it a bit at a time.

share|improve this answer

If it's ugly enough to piss me off, it's ugly enough for me to delete the entire thing and write a drop in replacement.

You'll find that more often than not, it takes the same amount of time to do this, as it does to sit there and tip-toe around an unorganized and undocumented mess and caress it gently.

share|improve this answer
1  
I disagree (although i did not give you -1 ). joelonsoftware.com/articles/fog0000000069.html –  JW01 Dec 18 '10 at 20:37
    
It's really too much of a situational decision to accurately defend myself. I might not do this when I'm working on a massive Objective-C library, however, I have no qualms about writing an entirely new javascript library. –  Sneakyness Dec 24 '10 at 16:51

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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