Obsolete in Isolation
The question of how to deal with a brown field project came up in the ALT.Net mailing list. Here is the description of the project:
You've inherited a software project that has deeply rooted dependencies, business logic embedded in the presentation layer (and elsewhere), 'unit' testing that tests databases with hard-coded strings for primary keys, no actual unit testing but contrived integration/functional tests...
Sounds like one of my projects, from several years back, as a matter of fact. Oh, the things we did to System.Web.UI.GridView...
Oh, I was supposing to talk about how to deal with such a project, not reminisce about old projects.
My approach for such projects is called: Obsolete in Isolation.
Basically, I say that the existing software is there, and presumably it is valuable to the business. However, trying to continue development using the existing approach would cost too much time and effort. Typically, maintaining such a project is a big pain, and cost more than keeping my old car running (it was older than me, so take a guess).
Trying to restructure it is possible, but again, costly. As such, I declare the whole thing obsolete and decide that this is a green field project. Now, after having successfully escape a lynching by the customer for suggesting such a thing as throwing away "Working Code" because "I am being uppity", let me try to explain what I mean.
The code is here and it is working. It is not written in a way that make maintainability and extending it easy. We need to maintain and extend the code. We would like to avoid the pain during the process. Throwing the code away is a bad decision in most scenarios. So we will keep it, but we will not continue developing on it.
Instead, we will do all development on a new project, which is built to be maintainable and easily extendible. The old project will stand as it is. Any new features will go to the new project, any minor bug fixes will be done in the old project. With the old "tested with F5" if no other approach is viable. Major bug fixes means porting the code to the new approach.
Over time, what will happen is that we move all the parts of the application that are unstable and buggy to the new approach, which will allow us to test it properly. Any new features will be in the new application as well. The stable parts of the old application are going to remain there, and they are going to keep on working. We aren't going to lose the existing investment in them.
There are issues with this approach, of course. For example, there is a cost of integrating the systems, but it is generally a minor one. And you need to introduce new developers to both systems, the old and the new.
Even with those issues, I find that this is a good way to deal with legacy projects without too much pain.
Comments
Gee.... it's like dejavu. I have the same exact situation. As the architect it is my job to figure out how the ideal architecture would look and then how to get there.
So, I have the same basic thought... start from scratch.
But, how do you do this with the database. The database is also not well designed and normalized. And, changing the database means every think cascades from there. Most access is done with SP's... so I figured I could refactor the db by changing the tables and modifying the SPs to work with the new schema so that old stuff will still work.
Also, I am looking at moving to Silverlight for the UI rather than HTML. But, I don't think they are going to be happy with some Silverlight UI and some the old hodgepodge IE6 only UI.
Heck, any ideas anyone have would be gladly accepted.
Thanks,
BOb
Obsolete the DB as well, I would suggest.
Don't let legacy stuff hinder you back.
Use ETL processes to sync the data between the DBs, don't share the DB between the applications
I've been involved on a project, a large B2B website, that it's first incarnation was a quick hacked webforms with some generated DAL and tons of SProcs.
as you said - every new feature was built as a MR controller/views + Repository/NH/AR data access + service layer, all wrapped in Windsor.
slowly the services and repositories started to propagate into the WebForms, and on any major update to a WF part, it got rewritten into a MR chunk of code.
About a year ago it was about 20% of MR/IoC and 80% WF/Sproc/StaticLogicClasses
nowadays it's 95%/5% in favour of the good stuff.
hoora
Same on my current project. The legacy code still exists on a branch and is still maintained when necessary (bug fixes only),. The legacy code also still exists on trunk but only as a source of code that we can move into our new structure and bring up to snuff when we touch that area of the system.
The above said, I am more and more tempted all of the time to nuke the legacy code from the trunk and instead require that developers look back into the branch when they need or want to see how something was done on it. We have the luxury of doing this because we are still shipping entirely from the legacy branch until late this year but I can easily imagine situations where legacy-on-branch, greenfield-on-trunk isn't quite so doable for a lot of projects out there.
ok, so imagined a winforms app that runs entirely on a core framework enterprisey beast. The business logic is somewhat separated from the UI but has infected the UI in many areas. The core framework is not testable with unit tests because the whole framework needs to be warmed up and logged into a sql backend, which also contains a large amount of business logic. There is lots of use of Oren's favorite access modifier "internal", and there is a management stipulation to not break the public SDK which is obviously exposed with public methods.
How in the world do you make this testable? I've tried... can't mock it, and the entire very large database needs reset/built each time you want a single test run in isolation.
We could start new project(s) and implement features in there, but those would be expected to support the SDK. It would also require porting/copying large amounts code to support the data access for each feature in the new project. This is a shipping product with major releases every 12 months. It's a real spaghetti code at a suicidal pace.
sry for the long comment.
This is pretty much the way I handled a previous project. The only problem was that I during 3 years of constantly adding and changing features the system had 3 ways of doing things, "the old old way, the old way, the new way" :) There was never enough time to refactor the application to the new design and way of doing things (NHibernte, IoC, TDD), although in the end I was able to convert all data access to go via nhibernate entites and repositories using NHQ :)
Ha ha... you do realize that is ALOT harder said than done. This will also require all of our customers to run two databases (or even if all the tables are in one database) and some type of sync daemon.
I will give this some consideration, but this will add alot of overhead to the project. Although we will need to ETL to move to the new database anyhow... it is the ETL to go from new to old that will add the overhead.
BOb
@Torkel,
I have the exact same problem. :D
I worked on a system that was always due in the next two months. After two+ years of this, it has literally 3 ways to do things. My problem is that I am still having to maintain it and cannot convince the powers that be that it needs to be scraped and re-built.
How do you convince the customer/manager/boss whatever, that the cost maintaining a system like this is much more expensive than scrapping and rebuilding it?
I joined a project like this a year ago. I there is too much business logic in the UI, well you are pretty screwed. If there is a decent amount of code in something resembling objects you are in a much better spot. Here is the approach I took: take what you can from the non-ui objects and wrap it in a service layer. You might have to deal with some threading issues, but you can run services single process / single thread or fix them as they come with simple locking. By wrapping existing functionality in a service layer, you don't have to throw it out, but you can reduce it's impact on code going forward. When you have time to start replacing code, you only have to replace the things behind the service contract, but at least now you can proceed one step at a time without rewriting the whole app before adding a line of new functionality.
Josh,
Don't bring in anything that is painful to use.
If you have a public SDK, keep it around, wrap that in integration tests, and start adding you functionality on the sidelines.
Bring in new API, and keep the old SDK as legacy only
Bob,
If it was easy, they would do it in Access.
ETL isn't really hard, and having two DB is generally not a problem, you aren't running two different servers, just two DB in the same server. You could even do it with the same DB, if you kept different schema.
I would say that it doesn't. Mark the bad ways as [obsolete] and deal with them appropriately. As long as you have a right way of handling things at a certain point, there is little issue with that
Migrating a schema in sql server is pretty easy with linqpad...
While (aiming for) rewriting an application might be worthwhile once in a while, I don’t think it pays off rarely as often as most developers would like to think. Sure it’s more fun/efficient to write code for an application based on an architecture you happen to like and know well, but will it save your employer so much time and resources that it all-in-all will be less expensive than maintaining the existing application? Do you have some basic quantifiable data that a decision can be made on, or is it just a hunch or wishful thinking? (The Valence effect... http://en.wikipedia.org/wiki/Valence_effect)
Among many things, you’ll need to consider:
The total future need of maintenance, the kind of maintenance, etc. Maybe the application won’t change much in the future. Ask the business manager, not just the old dev.
Could you study and analyze the current application, so that you at least can develop fairly risk-free and time efficient? It might not be nearly as fun, but could you? Could someone else?
Is the added complexity worth it (which is true until everything has been rewritten)? Does everyone involved agree? The other developers? The DBA? The QA?
Is Oren Eini on your team? Most teams aren't that lucky.
And so on. It’s hardly ever a clear-cut decision. Also, one thing that I have observed over the years is that young developers tend to want to rewrite pretty much everything they haven’t written themselves during the last two years or so, whereas seasoned developers rarely want to change any more than what’s absolutely necessary. You might have a different experience, of course.
I think it would be good to see a follow up post on how to sell it to pmo, as people are understandibly reluctant in rewriting something that already works.
We're practising this to a limited extent on our product - All our newer code has fantastic and well designed test suites.
Our older code, however, is not so blessed. And there are over 10 million lines of it.
The nature of the project, is much like device drivers (financial transaction processing integrating with various acquiring instituations each with their own quirks and a working - term used loosely - and stable body of code built up over years of integration and moving from spec version to spec version, supporting new features such as encryption / chip cards).
The book 'Working Effectively with Legacy Code' by Michael Feathers is worth a read.
ISBN 978-0131177055
The brownfield projects a have come across usualy have grown fat, because it was easier to add the functonality to an existing application. So the application has several more or less related functionality all wrapped together in a nice spaghetti dish.
I usually break down the application to more manageble pices, one by one. Move the database tables related to the functionality and provide an interface (database level SP/View or some sort of remoting) for the old application. Then Im free to move towards more testable code, because I dont have an entire application dragging behind me.
An example could be a CRM application.
It consists of many reponsibilities. GUI, Mail and Calender to Exchange, Binary Documents etc.
I could then move the Mail and Calendar service tables and code to a new application, and provide acces to it via a SP or a WebService. From there on I could apply sound OOP principles to the code and it could move forward in its own pace, not dependent on the main application - exept if the interface change.
I dunno, it's a tough call. Often, our tendency is to re-write from scratch because we don't want to deal with someone else's problem. (Incidentally, politics has the same problem when a new government is elected.)
But we are also throwing away a lot of bug fixes and minor enhancements by starting over. Yes, you can't save every project but we should ask ourselves, "Do I want to start over because it'll be cheaper for the business? Or because I don't like dealing with the code?"
http://www.joelonsoftware.com/articles/fog0000000069.html
Why couldn't you compromise -- come up with what you what the system to look like and start slowly refactoring and TDD/unit testing your way towards that? This way your new stuff is solid and your old stuff is still usable and slowy progressing (slouching) towards decent as you merge your improvements in.
Re: . The database is also not well designed and normalized. And, changing the database means every think cascades from there.
Could you restructure your data base and create view that replicate the old database design and the old apps/stored procs just point to the views.
Comment preview