views:

108

answers:

6

I've got a project (about 80K LOC) that I'm working on, and I've got nearly a full month of luxury refactoring and feature adding time prior to release so long as I'm careful not to break anything. With that being said, what can I do to improve maintainability. Please not there was no unit testing in place with this project and I'm not really PLANNING to add unit tests to this, however if it is the common consensus I will take it under consideration.

What are the key things I should look for and consider revising or refactoring to improve software maintainability and quality?

Edit: It's been made clear to me I need unit testing. This is not something I've ever really done, what are some good resources for a developer new to unit testing (preferably via VS2008's unit testing framework)?

A: 

Find places which are likely to change in future and make it more flexible maybe.

ratatosk
+1  A: 

I would look at the wiki article on Code Smells on this site, its a great place to start!

Jrud
+1 - alongside and often superior to http://wiki.java.net/bin/view/People/SmellsToRefactorings (linked from Martin Fowler's code smell bliki entry http://martinfowler.com/bliki/CodeSmell.html).
Jeff Sternal
+3  A: 

The key thing to consider is why you want to refactor your code. Answer that question, and you'll have half your answer already.

You mention wanting to improve maintainability, which is a very common reason for refactoring. Given that as a goal, here are some things that I would specifically target:

1) Remove duplicate code. Most programmers try to avoid this anyway, but large projects (especially projects with large teams) tend to accumulate it anyway. This is an easy target for refactoring.

2) Make simplicity your goal. Is each function/method/class clearly defined? Can you look at it and know very well exactly what it's doing? If not, it's a good target for a refactor. Good examples are modules that do lots of things (or have lots of side effects). Consider breaking them into smaller modules of logically grouped functionality.

3) Variable/class/function names. Are they clear? They don't necessarily need to be long, but they should make it very clear to you (or whomever is maintaining the code) exactly what the variable is for or what the function does. If there are some that are unclear, consider renaming them.

4) Do you have code that's never getting called? It could be worth leaving if you think you'll use it later. Otherwise, it's just a red herring for any maintainers. It's worth considering getting rid of it.

5) Performance enhancements. You may or may not have the time for full up algorithmic rewrites (the best performance enhancement). However, this is a good time to check for simple things. As a C++ example, are you passing classes as const references or by value? The former is much more efficient when you can get away with it (which is 95% of the time).

Good luck on your refactoring!

[Edit] Also, I second everybody below with a recommendation that you write unit tests before refactoring to ensure that your code remains correct.

Russell Newquist
Not to be too pedantic, but performance enhancements are not refactoring. (Though the first four are good suggestions.)
Jeff Sternal
Technically true, but it's something I'd look for, were I in the bowels of the code anyway.
Russell Newquist
Also, I second everybody below with their recommendations of unit tests. I meant to include a comment on that myself in my initial answer.
Russell Newquist
+2  A: 
  • Even though you said no unit tests I am going to plug them anyways. Wrap complicated logic up in tests before refactoring them.
  • Jrud's answer of code smells is good.
  • Also, study up on the S.O.L.I.D. principals.
Jeremy Roberts
+5  A: 

Please not there was no unit testing in place with this project and I'm not really PLANNING to add unit tests to this, however if it is the common consensus I will take it under consideration.

Frankly, if your goal is to improve maintainability, there is no substitution for unit testing.

This would be step one. The problem is, without unit testing, there's no way to know if you "break" something during the refactoring process.

Unit tests provides a layer of safety around your refactoring. It's difficult to feel comfortable refactoring, especially doing large-scale refactoring, if you have no way to verify that your refactoring isn't going to change behavior.

You can do some minor refactoring - small renames to improve understanding, etc, but any large-scale refactoring, or any design-style refactoring to improve long term maintainability should come after designing and writing tests that help you protect yourself.

Reed Copsey
Though it's often necessary to refactor just to enable proper unit testing.
Jeff Sternal
Well, to me, they often go hand in hand. I'd do as little refactoring as possible to get good unit tests, then refactor the tested portion, and then move onto the next area of code and repeat.
Reed Copsey
+1  A: 

Having a project well covered with solid tests (both unit-tests, using mocking &c to run blazingly fast so you can run them all the time, AND integration-tests to be run more rarely that actually interface with real databases, etc, etc) is the key to maintainability: the single most important thing you can do to make a project easily maintainable for whatever purpose (features, bug removal, performance, porting, etc, etc). A strong test suite gives you confidence in the correctness of any further specific change you may want to try down the road, plus, code refactored to be well-testable (highly modular, dependency injection, etc, etc) intrinsically also becomes more flexible and maintainable.

I highly recommend Feathers' Working Effectively With Legacy Code (both the PDF I'm pointing to, and the book by the same title and author) for a thorough and highly practical guide to how best to proceed in such situations.

Alex Martelli