views:

111

answers:

4

I have inherited an ASP.NET application that is a disaster architecturally, however it works and it is in live production use. In order to enhance the application in the future I need to totally re-architect it, but I need to preserve the existing front-end functionality - the changes that are being asked of me are more backend integration than front-end functional or user interaction.

The basic issue is this - the bulk of the business logic is in stored procs (and the rest is in UI codebehind files) - there is no business domain model of which to speak. I need to refactor logic out of the database (and down from the UI) into code, but the behaviour of the application is fundamentally bound up in these stored procs. So the question is this - how do you go about a complete re-architecting of this kind?

I understand refactoring in small steps, I've read fowler etc. I am really looking for practical advice from people who have been through a similar process.

Thanks!

Edit I should have said, ideally I want to re-engineer iteratively, during a multiple release cycle.

+3  A: 

IMHO the most important thing to do is to develop a lot of good tests that would cover entire functionality you want to preserve.

I know that writing tests is extremely hard in messy codebase, but it is still possible through some dependency breaking techniques. I would recommend "Working effectively with legacy code" since it is all about practical side of refactoring.

piotrsz
A: 

I would strongly agree with piotsrz's answer - a good, comprehensive set of unit tests is exactly what you need to help preserve behaviour while refactoring. Add these tests to a continuous integration system so that you get fast feedback on every commit from every developer.

Another good book on this subject is Refactoring to Patterns, which describes several iterative techniques for architectural transformations that preserve behaviour.

Dan Vinton
+2  A: 

It's painful, but the first big question is: do you really need to do this rearchitecting? If the database design is more or less OK can you instead architect the new stuff and leave the old alone? Every reflex yearns to tidy up the mess, but from the business user's point of view what level of investment is required and what's the payback?

You've already identified iterative change as an approach. For this to work, it implies that there is some level of granularity in the system that allows you change some pieces without affecting others. Your idea presumably is deliver some new business value and clean up some portion of the application at the same time - effectively amortizing the cost of change across many valuable deliverables, a "garbage collection tax" on delivery of new stuff. Is that "tax" acceptable?

So I think that the granularity assumption is something you need to check. Identify a small piece. Attempt the refactoring. Does you find it to be as isolated change as you hope? Was the cost as you expected? and importantly ... what down sides are there? There's some possibility that your code performs less well than the existing stored procedures. Development "tax" is one thing, runtime performance "tax" is a whole different thing.

djna
Interesting answer - the best yet. The granularity is a big problem here because of multiple SP and code dependencies on the database. It is going to be very hard to isolate at this level, and that is exactly what I am worried about..
flesh
+1  A: 

Tackle the business logic of the stored procedures and of the UI separately. And take on the SP's first. One at a time:

  • write a procedure that invokes the SP
  • test the hell out of it
  • redirect any code from the SUT to call that procedure instead of the SP
  • write the business logic into that procedure (continuing to pass all tests, of course)
  • drop the SP

Approach the UI similarly. In neither case is it quite as simple as it sounds - the mapping between SPs and "regular" code is imperfect at best - but I don't know a better approach.

I'm advocating not writing a slew of unit tests, then refactoring; rather, test-cover the code to be refactored today. A few unit tests, a little refactoring; lather, rinse, repeat. You can interrupt at any time and have a better system than when you started; there's no great latency between undertaking the changes and seeing results.

Carl Manaster