views:

522

answers:

11

I know that there are already Questions about VB6 migration, but the code base of my project brings some new questions here.

I have to say the Code quality, structure and architecture is just a nightmare. There are 2 Big Projects: Nr.1 with 40 Forms, 40 Modules and a few class files, this EXE is kind of a "base system". Nr.2 with 80 Forms, 20 Modules and a few class files again, this EXE calls functions form the "base system". Then there are ~10 other Projects with GUI (1-3 Forms each) and another 90 non-GUI Projects, most of them EXE Files, some DLLs. The DLLs are written in C, C++ and VB6.

The Code has grown evolutionary since 10 years, and written mostly by 1 (bad) developer at a time.

  • Functions with 500 Lines (and more) are very common.
  • 90% of the GUI components are named text1, command2(1), …
  • copy and paste is all over the place e. g. an EXE project (without GUI) with 5000 lines of code was copied and the only change in the copy was to send files per Mail instead of FTP (there are 2 further copies of the same project also).
  • I once had a small form (15 fields), where I should solve a small problem(max. a half hour thing normally), every time I changed something, it either didn't work, or produced new errors in the form. After 2 days, I decided to rewrite the form completely and from ~20 SQL statements in the old form, only 2 survived in the new one.
  • don't even ask about comments in the code …

I took over the project a few months ago and I'm the only maintainer. There is a constant, (but low) flow of Change Requests and errors and we get a maintenance budget from our customers to keep the software running and "up to date" in terms of legal requirements.

My Options

1) Rewrite from scratch - In that case I could write it in Java for portability. The problem here is that besides some (old) user help, there is no documentation, so the ugly code is the "documentation". There is one Person who has the high level know how what the software should do. Also it's hard to convince management about doing it, even if there are huge cost savings in the long term, there are political issues. I also can't do that one (vb) project at a time because the database structure is no better than the code i.e. has to done from scratch too. So I can only change the whole software at once.

2) Migrate the code to VB.NET / C# Migration of the main Projects first, I tested that already and got ~2000 upgrade comments from Project Nr.1, most of them things like Screen.MousePointer changed, functions with variant return values and so on. My Idea here is after the convert, create classes for DB abstraction, change the code to use these classes and do refactoring, migrate and change the other projects too and when all the code uses the DB classes, change the DB structure.

3) Refactor the code in VB6 whenever I have to change something there anyway (I'm already doing this partly) and at some point refactor also the rest. That way it's more easy to see the original functionality, because it's original code and when there are errors, it's obvious that they can't be results of the migration. When the code is refactored (I assume it will be 50-75% smaller then also) it's easier to migrate it to .NET. Then change DB structure (and then do another round of refactoring…).

There are some bigger changes to do in the future (make it compatible with Win7, and another big CR which affects big parts of the code), so there would be a good opportunity to do these changes, as I'll have to go through lot's of the code anyway.

My Question is who has experience / hints for migrating bad, ugly code? Which options would you suggest?

+13  A: 

I had to go through the same thing (Massive VB6 app with no documentation and horrible code.). The only safe and reasonable route you can take is number 3. To improve something you must first understand it. If you take route 1 or 2 you are guaranteed to be left with a horrible mess.

Remember to always keep the idea in the back of your mind that your end goal is a full migration to .NET. As you are refactoring think about how VB6s awful OO support will look like in VB.NET or C#. If possible shift your code around to make the migration easier.

You may want to consider shifting a lot of your core functionality into a .NET DLL and exposing it to VB6 through COM. This will remove a ridiculous amount of code from your VB6 and will hopefully leave mostly business logic.

The most important thing you need to remember is don't be a cowboy.

  1. Write tests for a module.
  2. Refactor a module.
  3. Test the module.
  4. Release your app.
  5. GOTO 1
ChaosPandion
At the risk of starting a religious war, I might suggest adding step 0: Write tests and change 4 to GOTO 0
Michael Paulukonis
The lame list feature doesn't support 0.
ChaosPandion
I'm already doing this (move ini and registry handling, which exist as code copy in every project to dlls, exchange the code of FileExists() function with FileSystemObject.FileExists, and so on) but I see a big Block there: the Database.I can't change the DB structure that way. The DB calls are simple calls mostly, but they are everywhere.Any Hints on that?As a teaser: There is code which loops through a folder and sends a query to every access db it finds, to look for some values ...
marcus
Oh boy, getting rid of all the inline SQL calls was the meat of our conversion. We actually wrote a Core library in C# and exposed a COM interface to VB6. Then we were able to abstract the database calls through the Core.
ChaosPandion
I have done exactly the same thing. Unit tests are paramount (I used VBUnit). I eventually settled on a pattern of 'combing through the app' each time I was required to make a change, fixing one type of issue each time. I would refactor certain tasks in each module rather than the entire module (lets say, creating a function that would reset the font, or something. If I had to do it once, I would then search through the app looking for any other code that changed the font, so now all font changes would go through my new function) I wound up getting very good knowledge of the app,
KevinDeus
What did you use as a testing framework? As ComUnit and other VB6 test frameworks kinda suck...
Kris Erickson
+1 For ruling out option 1. My addition would be to have a plan for going to .Net, and even if you go for option 3, make sure you are making conversion to .Net easier. When considering .Net conversion have a look at the 3rd party tools you can buy. It sounds like they thrash the Visual Studio migration wizard. www.vbmigration.com, www.artinsoft.com
MarkJ
@MarkJ - Thanks for pointing that out.
ChaosPandion
+8  A: 

Does the code absolutely have to be migrated? If it doesn't, still serves it's purpose, and is halfway maintainable, just leave it alone and move on.

Your motivation to move the code to a newer language will soon fade after countless hours, weeks, and months of code migration -- especially on the scale that you mentioned.

The idea of code migration is a fantastic idea, conceptually. In all probability, it is a terrible mess and you will hate life doing it.

Think about it, do you hate your life now while fixing a defect? Escallate that by 100x for the migration project.

Most businesses could really care less about what's under the hood as long as it works. Remember, they aren't developers, don't care about how much of a pain it is to fix it (as they aren't the ones doing it) and motivating a the business to spend tens-of-thousands of dollars to bring code up to date, simply doesn't make any business sense.

George
I disagree refactoring and then migrating to C# was the BEST thing we ever did.
ChaosPandion
I think you mean "probability" not "actuality." Good point +1, although it may be totally wrong as Chaos Pandion points out.
Yar
@yar Yep, you're right!
George
I now agree with your main point. A code migration project is a massive commitment but if you don't take on too much at once and remain committed to a consistent migration process the results can be seen by all (Non-coders included).
ChaosPandion
Yes, I DO hate my life now while fixing a defect.It often takes an hour just to find the right place where the errors occur (errorhandling in vb6 is horrible and a reason for migration alone). And when I see the function (where the error occurs) starts with 3 pages of variable declarations, I hate my life even more. Ok when I've found the error it's normally easy to correct it. But then it takes me quite some time to find the _other_ places where the same error was copied. And then I have to be extremely careful how to solve the problem without damaging other existing code.
marcus
So it sounds like you don't have a very solid understand of the business logic? If it was written by 10 different developers over 10 years, who would have the appropriate knowledge to guide you through a migration? That's the entire issue.
George
You don't need a solid understanding if you refactor first.
ChaosPandion
now, if you want to evolve the application, it's better to migrate it in .NET that increase the horror for the next generations: a day will come and anyway someone will move it from procedural to OO language.
serhio
Depends ...I migrated our entire business logic VB 6 COM+ objects in one day, there were barely any problems in converting ... that was lucky. Yes there could be a ton of bugs. But it compiles. UI is harder, but with strategically created extension methods (what a life saver), the big burdens are 1) array indexes starting at 1, 2) crappy error handling, 3) subs/functions with missing parameters that require regexes to search/replace with that become quite complicated, but doable 4), property setters (method is often changed to get_X and set_X, but set_X now takes a parameter, which is a pain.
Richard Hein
Unfortunely, my work was wasted, because the dev manager doesn't want to use it. He's afraid that it won't work, so it hasn't gone into QA, or VSS even for that matter. VSS makes me sad too. Also note that there is way too much business logic in the forms, which makes it not so big a deal. The logic stuck in the forms is the biggest problem as usual, but it's not just because it's VB 6, it's bad anywhere, anytime.
Richard Hein
A: 

Don't rewrite it from scratch. It sounds like it will take you ages and you'll most likely introduce new(old) bugs into the code.

I would look at refactoring the code slowly but simply. Start small. Its surprising how quickly you can refactor the code in to something which is much more manageable. And you should be able to keep the code 'working' at the end of each block of refractoring you do.

UPDATE: Its worth noting that automated migration will only move your problems to a different language.

Matt Joslin
The more I see / understand of the code, the more I belief the real functionality is quite small. I see the same or nearly the same code everywhere. I found a function (cutting backslash at string end) which exists 3 times with the same name and the same code inside one VB project.I found the code for logging in a dll, changed it, no effect, and found a copy of the code in one of the Main EXE's.Some SQL Statements I find with small variations in every second project.And I could continue this list endlessly.
marcus
do you know where the previous dev lives?... release the hounds!!or more seriously - just get stuck into the code and start deleting chunks of it that dont do anything. start to rationalise the beast and get it back under control. Good luck.
Matt Joslin
It's true that "automated migration will only move your problems to a different language" but also Refactoring is alot easier in .NET where you have access to Linq, Hashtables, Generics etc. Thousands of lines of code simply fall away but much of this is not possible until you get the code across in a working state.
PeanutPower
I agree with PeanutPower, I'd also add that moving to VB.Net removes worries about Microsoft's support for VB6 in future versions of Windows, and it gives you more tools for automatic testing - solid automatic tests are essential before any refactoring effort IMHO. They can be added piecemeal as you deal with your "(low) flow of change requests"
MarkJ
+6  A: 

Experienced similar migrating 14 year old code to VS2008

Here are some tips:

  1. Remove dependancies on 3rd party components.
  2. Consider staged migration e.g. using reverse interop.
  3. Colours and Fonts need to be dealt with by hand.
  4. Watch out for uninitialised objects in arrays after migration to .NET
  5. Change On error to Try Catch
  6. Make use of Microsoft.VisualBasic.Compatibility.VB6 Namespace where needed.
  7. Keep refactoring to a minimum until all code converted to .NET
  8. Watch out for non zero based arrays in your VB6 code.
  9. Refactor (minimal) your code in VB6 so it can go through the code conversion wizard.
  10. Watch out for 1 based VB6 controls e.g. ListView
  11. Use synclock to avoid threading issues.
  12. If you are doing manual refactor of a sub then be careful of the changes in data type sizes especially if you are working with file IO.

There is a company which can help you out with the whole process (although we didn't use them) http://www.vbmigration.com/

PeanutPower
I'd really suggest refactoring before an automated migration. Understanding and reducing the codebase first is a good idea. Both of these tasks are still required, and now the added complexity of a new environment has been added. It makes it difficult to tell what is the source of errors -- the original "design" or the migration.
Michael Paulukonis
Automated migration will only move your problems to a different language.
Matt Joslin
Good shout on the array indexing though - minefield if you're not careful
Matt Joslin
We found that alot of legacy got broken if someone refactored something at the same time as migrating although sometimes it was unavoidable. Especially parts of the code that were poorly understood and "refactoring" was sometimes descoping. We moved everything across first and refactored for .NET afterwards so as to avoid loss of functionality.
PeanutPower
We were also moving over 100k LOC across on a code base with new functionality going in on a daily basis. The conversion project was always playing catch up. This is why we kept refactoring to a minimum until we could switch over proper.
PeanutPower
+4  A: 

Check out M. Feathers' "Working Effectively with Legacy Code" -- it discusses the pitfalls of enhancing, refactoring and migrating and untested code.

Michael Paulukonis
+2  A: 

Compared to some of the stuff I've worked on it sounds quite small. Nevertheless there is another approach which which will work in conjunction with that shown by PeanutPower above.

The answer is to build a framework that will allow you to cut out sections of the program at a time and convert them one by one.

e.g. Insert a database adapter 'layer' that handles all calls to the database, then one by one, remove each but of SQL and replace it with a call to the db layer. Old calls will still go direct while new calls go through the layer. Eventually all calls will go through the layer and you can change the backend DB.

You can do the same with any other section of the code by expanding the framework 'layer' to cover that functionality.

The key to shifting it from VB6 to VB.NET (for example) is to use the Interop library - here's one article: http://support.microsoft.com/kb/817248

Robin
A: 

Lots of great answers here, and even by people who have done this before. 1-based to zero-based arrays... screwing that up would be costly and hard to track down.

Anyway, just wanted to mention that refactoring legacy code is a history project, as well (if you want to enjoy it). VB 6 came out in mid-1998, and at that point... well, the first iPod came out in 2001, just to give you an idea. Hard disks were small (you could get a 5GB for about $300), computers were big (generally)... Wifi was invented but not use.... etc.

I remember that VB6 was where I first learned about OO, since I think it was Microsoft's first honest attempt to make VB object oriented.

There are a whole bunch of fun tangents that could be interesting to check out. None of which will help you with the decision to migrate... or will they?

Should you decide to migrate, aside from being a fun side project, checking out the history might give you an idea of what kind of extraterrestrials you are dealing with. you know, people who wrote code in 2000 :)

Yar
+1  A: 

From your description of this project, it sounds like it might be possible for you to refactor and migrate at the same time. You're clearly going to be taking the large amount of redundant code and consolidating it; it's likely that as part of the consolidation, you can also rewrite it (the redundant code, that is) in .NET.

This won't work for UI stuff. But it will for database and business-logic stuff. For instance, I haven't seen your code, but I'll bet folding money that most combo boxes in your application that get populated by methods in their form (probably copied and pasted into Form_Load) that create ADO recordsets and loop through them. That's something that can be refactored into a .NET data-access class and integrated into existing forms with ease. It will also probably allow you to introduce the magical world of caching into this application, which will be nice because that will probably result in visible performance improvements.

And visible improvements are important. Unless your management completely buys into the necessity of doing this, this is a very high-risk endeavor. It's very bad if you find yourself telling your management that a given CR is going to take longer to implement than they expect because of issues in your refactoring. Even if you have complete support, you don't want this situation to arise, but it's a lot worse if your support is partial. Visible improvements will do a lot to mitigate this.

Also, there's a growing body of literature on the problem of refactoring legacy code. You need to be on top of it. The more you know before you dive into this, the better your experience will be. I haven't read Michael Feathers's book myself, but if I were in your shoes it's the first thing I'd do.

Robert Rossney
+2  A: 

Hi marcus, you did a great job formulating this question. Thanks for asking! And thanks to the stackoverflow community for posting thoughtful responses (as usual).

If this is a fairly large codebase, and it sounds like it is (50-100 inter-related VBPs, 200-500K LOC) then you should consider investing in migration tools. Consider this analogy: if you had a large amount of data to convert, even if the source data was dirty and very different from the desired format, you would use tools. If someone suggested you should just re-enter the data, or even do a rough cut conversion and then fix it by hand, you would think they were nuts. Also with 120 forms, the application sounds like it provides a fairly significant amount of business functionality. That business functionality has emerged over many years of use, and, like it or not, the VB6 code represents a complete, formal, and production-tested specification of that functionality as well as myriad technical facts about how the app works behind the scenes. Regathering, recoding, and retesting all those functional/technical requirements "from scratch" is very expensive and difficult. In order to manage the cost and risk of the project you must "cash in" the legacy code. The question is: how to do this and also ensure lower cost of ownership after the migration.

The challenge has less to do with the size of the codebase than with the details of redesign needed to adapt to and take advantage of .NET. You need to identify the specific things that make the VB6 code "ugly" code, why it is "ugly", and how you must/should/want to do those things differently in .NET. Once you start formulating these redesign requirements you can begin implementing them in your conversion process so they show up in your .NET code. The general approach we advocate is called the "tool-assisted rewrite" and it is done follows:

  1. run the translation
  2. build/review/test the generated code to identify/refine needed code improvements
  3. if the generated code is "good enough", goto finish the job in .NET
  4. reconfigure the translator to implement the needed improvements (if appropriate)
  5. goto 1

The output of the tool does not need to be "perfect" (software never is...) it just needs to be "good enough". What is "good enough" mentioned in step 3 is a critical question. In essence it means the code quality -- in terms of being verified as functionally correct and conformant to your standards – is such that the development team knows what it will take to finish the migration and then continue operating/maintaining the application – AND they are confident they can do this within the given time and resource constraints. For a very large codebase "good enough" is "very good" because it is just too expensive and risky to try to finish and subsequently maintain a low-quality migration. In general, the larger the code, and the smaller the budget, the more efficient your migration process must be.

Also some thoughts on "finish the job in .NET": Having a well-formed code in .NET is a major milestone. There are good refactoring, analytics, and unit testing tools from the .NET community that can help you accelerate you efforts to finish the migration. You will be using Visual Studio very early in the process to experiment with and refine redesign, and debug/test the app. Being able to work with your entire codebase in .NET and with Visual Studio early in the migration effort is a key benefit (and a critical part) of the tool-assisted approach.

Of course for this to be feasible, you need to be able to invest in a migration toolset that is specifically designed to support the tool-assisted rewrite. The tool from Great Migrations is the only tool that I know of in this category.

Disclaimer: I work for Great Migrations. There is much more information on our site – including case studies for how the tool was used to help migrate over 1M LOC of VB6 to re-engineered C#, and the gmStudio User's Manual that describes the product and methodology in detail.

mark
Nothing wrong with a shameless plug. :)
ChaosPandion
Thanks ChaosPandion. Yes, its a plug, and I believe every word I wrote. I use this technology everyday to do my job and I am inspired by how well it works. I think it is important that the community knows about this technology.
mark
A: 

Having worked on several migration projects the first thing to do is be clear on what your migration goals are. These can vary significantly from organization to organization, but they help set priorities during the actual migration project. It also helps better evaluate the benefits against the risks and costs.

Like others have mentioned, it's important to realize that the migration process won't automatically improve the quality of the code. So if your main goal is to refactor (and nothing else) then you should be aware that it might be weeks or months before you have functionally equivalent code (depending on the code size and migration complexity).

That being said, .NET does have some very nice tools for refactoring and code analysis, in addition to unit test suites. Automated conversion tools like ArtinSoft's Visual Basic Upgrade Companion can be customized to enforce coding standards or improve the code significantly during conversion. This mixed with other code modification tools like ReSharper will greatly speed up your transition to .NET.

In my experience a migration project is a manageable project as long as you're aware that there is manual effort involved. Commercial tools have assessment modes which can help quantify the migration effort, and give you an idea of what challenges you might face in a migration.

If you prefer a low risk and cost solution, I'd stick to refactoring the code with an eye towards an eventual migration. I have had customers for whom this approach worked. So when it came time to migrate their code several things had been solved already.

Basically, any new custom controls should be written in .NET and exposed as ActiveX controls to be used by the VB6 app. Likewise, new DLL functions should be placed in .NET assemblies that can be used through COM. That way when it comes time to migrate you won't have to worry about those controls or libraries.

Migration Specialist
A: 

To migrate vb6 code , a tool that help to understand the existing code could be useful, for example VBDepend is a useful to understand the vb6 code base.

Issam