views:

187

answers:

9

I had a piece of work thrown out due to a single minor spec change that turned out not to have been spec'ed correctly. If it had been done right at the start of the project then most of that work would have never have been needed in the first place.

What are some good tips/design principles that keep these things from happening?

Or to lessen the amount of re-working to code that is needed in order to implement feature requests or design changes mid implementation?

+6  A: 

Modularize. Make small blocks of code that do their job well. However, thats only the beginning. Its usually a large combination of factors that contribute to code so bad it needs a complete rework. Everything from highly unstable requirements, poor design, lack of code ownership, the list goes on and on.

Adding on to what others have brought up: COMMUNICATION.
Communication between you and the customer, you and management, you and the other developers, you and your QA department, communication between everyone is key. Make sure management understands reasonable timeframes and make sure both you and the customer understand exactly what it is that your building.

Corey Sunwold
+4  A: 

Take the time to keep communication open with the customer that your building the product for. Make milestones and setup a time to display the project to the customer at each milestone. Even if the customer is completely disappointed with a milestone when you show it, you can scratch what you have and start over from the last milestone. This also requires that your work be built in blocks that work independent of one another as Csunwold stated.

Points...

  1. Keep open communication
  2. Be open and honest with progress of product
  3. Be willing to change daily as to the needs of the customers business and specifications for the product change.
Gnatz
In other words read Code Complete by Steve McConnell.
Copas
A: 

Like csunwold said, modularizing your code is very important. Write it so that if one piece falls prone to errors, it doesn't muck up the rest of the system. This way, you can debug a single buggy section while being able to safely rely on the rest.

Beyond this, documentation is key. If your code is neatly and clearly annotated, reworking it in the future will be infinitely easier for you or whoever happens to be debugging.

Using source control can be helpful too. If you find a piece of code doesn't work properly, there's always the opportunity to revert back to a past robust iteration.

Evan Meagher
A: 

Although it doesn't directly apply to your example, when writing code I try to keep an eye out for ways in which I can see the software evolving in the future.

Basically I try to anticipate where the software will go, but critically, I resist the temptation to implement any of the things I can imagine happening. All I am after is trying to make the APIs and interfaces support possible futures without implementing those features yet, in the hope that these 'possible scenarios' help me come up with a better and more future-proof interface.

Doesn't always work ofcourse.

jerryjvl
+2  A: 

Software requirements change, and there's not much one can do about that except for more frequent interaction with clients.

One can, however, build code that is more robust in face of change. It won't save you from throwing out code that meets a requirement that nobody needs anymore, but it can reduce the impact of such changes.

For example, whenever this applies, use interfaces rather than classes (or the equivalent in your language), and avoid adding operations to the interface unless you are absolutely sure you need them. By building your programs that way you are less likely to rely on knowledge of a specific implementation, and you're less likely to implement things that you would not need.

Another advantage of this approach is that you can easily swap one implementation for another. For example, it sometimes pays off to write the dumbest (in efficiency) but the fastest to write and test implementation for your prototype, and only replace it with something smarter in the end when the prototype is the basis of the product and the performance actually matters. I find that this is a very effective way to avoid premature optimizations, and thus throwing away stuff.

Uri
+2  A: 
  • iterate small

  • iterate often

  • test between iterations

  • get a simple working product out asap so the client can give input.

Basically assume stuff WILL get thrown out, so code appropriately, and don't get far enough into something that having it be thrown out costs a lot of time.

Ape-inago
I second this. And make sure you don't "marry" your code.
Subtwo
Agree getting married with your code is a very horrible mistake. Generally I like to write a full draft then completely start over. You're code comes out so much cleaner afterwards because you really know what you are doing at that point.
jim
+2  A: 

modularity is the answer, as has been said. but it can be a hard answer to use in practice. i suggest focussing on:

  • small libraries which do predefined things well
  • minimal dependencies between modules

writing interfaces first is a good way to achieve both of these (with interfaces used for the dependencies). writing tests next, against the interfaces, before the code is written, often highlights design choices which are un-modular.

i don't know whether your app is UI-intensive; that can make it more difficult to be modular. it's still usually worth the effort, but if not then assume that it will be thrown away before long and follow the iceberg principle, that 90% of the work is not tied to the UI and so easier to keep modular.

finally, i recommend "the pragmatic programmer" by andrew hunt and dave thomas as full of tips. my personal favourite is DRY -- "don't repeat yourself" -- any code which says the same thing twice smells.

Partly Cloudy
+1  A: 

G'day,

Looking through the other answers here I notice that everyone is mentioning what to do for your next project.

One thing that seems to be missing though is having a washup to find out why the spec. was out of sync. with the actual requirements needed by the customer.

I'm just worried that if you don't do this, no matter what approach you are taking to implementing your next project, if you've still got that mismatch between actual requirements and the spec. for your next project then you'll once again be in the same situation.

It might be something as simple as bad communication or maybe customer requirement creep.

But at least if you know the cause and you can try and help minimise the chances of it happening again.

Not knocking what other answers are saying and there's some great stuff there, but please learn from what happened so that you're not condemned to repeat it.

HTH

cheers,

Rob Wells
Thanks, very valid points. (my issue was mainly just seeing it fully implemented and deciding they didn't want that anymore after using it, I guess thats cust creep in a way.)
jim
+1  A: 

Sometimes a rewrite is the best solution!
If you are writing software for a camera, you could assume that the next version will also do video, or stereo video or 3d laser scanning and include all hooks for all this functionality, or you could write such a versatile extensible astronaut architecture that it could cope with the next camera including jet engines - but it will cost so much in money, resources and performance that you might have been better off not doing it.

A complete rewrite for new functionality in a new role isn't always a bad idea.

Martin Beckett
My boss would slap you. haha. But you are right, complete re-writes are sometimes needed. But they take a lot of resources, most of the time it just can't be done.
jim
Have you seen code that has been 'extended' without a rewrite. The ones where a SSN starting with 99 means that the last name field is now the account number of the partner.
Martin Beckett