http://qs321.pair.com?node_id=59189

Fingo has asked for the wisdom of the Perl Monks concerning the following question:

I have decided to rewrite a badly written program of mine (A Good Thing). The main reason it was so badlywritten was that I did not fully plan out how the program would work. I hacked together a system for reading data, and created all of the algorithms on the fly (A Bad Thing). Here is my question, does anybody know of some good techniques to plan out code? Which ones work, and which don't?

Thanks

Replies are listed 'Best First'.
Re: Rewriting some code
by athomason (Curate) on Feb 18, 2001 at 05:27 UTC
    It's great you realize that planning will help you. The urge to dive into a project is frequently hard to resist, as anyone who enjoys programming knows. But the best ways to plan a project depend on a great many things. Some common factors that can affect your strategy:
    • Architecture - language, platform, etc.
    • Program size - programs with 500 lines and 500,000 require totally different approaches
    • Timeframe - did you need the program yesterday, or do you have a year to get it right?
    • Number of collaborators - it's much less hassle to do things yourself, but large projects require coworkers, and the red tape that comes with them

    You need to know all these things before you start writing any code. Don't just think about them; write them down, or explain them to someone else. Structuring your thoughts in a more concrete manner will force you to really understand what you're doing. Getting the requirements right is the first thing you'll need to do. Next, look in more detail at what languages, algorithms, libraries, etc you can reuse. Compare a variety of them and see which fits your project best. Flowcharts and other graphical diagrams, as non-computer-esque as they seem, can frequently help you organize your ideas and find fundamental problems very early. The right design decision can save you enormous cost down the line.

    Once you've got a good idea of how you want to structure your program, start looking at how to implement it in general terms without actually writing code. Most coders I know tend to itch to start writing code as soon as it's fairly obvious how to implement a routine, but restrain yourself until you know that the obvious way is the best way. My favorite tool for good program design is writing an initial draft in a sort of formal pseudocode called PDL (Program Design Language... see the book link below). Before ever writing a scrap of code, map out in detailed English (or whatever natural language you prefer) what your routines will do. This frees you from syntactical constraints of your target language and allows you to tell at a glance what routines do. Recursively revise your draft with increasing detail until you can go almost directly from that to code. Any logical flaws are much easier to correct if you uncover in the planning phase than once you've started coding. As an added bonus, once you fill in the code, you've got comments already there in the form of the PDL.

    Your question relates mainly to the planning stage, but maintainability is also greatly influenced by how you write the code itself. Structuring routines and classes for maximum understandability and flexibility will always help you in the future.

    One of the most valuable books on my shelf is Steve McConnell's Code Complete, because it address exactly these issues. I've had it for seven years and reread it every so often just to remind myself of how I should be doing things. Amazon has a list of related titles (which I can't vouch for personally, but look similar) that you might find useful.

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Rewriting some code
by chromatic (Archbishop) on Feb 18, 2001 at 23:32 UTC
    To expand on what salvadors is saying, the approach I like is to describe the main features of the program as stories. Stories tend to be a paragraph or less, describing what the user can do with the program. For example, "Users should be able to add new data to the system by filling out a simple form for the type of data to add."

    When you have your stories, break them up into tasks. The example story means we'll have to have an editing form, some mechanism to constrain input to the proper fields, and a way to update data. Estimate the amount of time it will take to perform each task.

    Depending on the customer, someone will have to decide which stories need to be done first. I do a lot of free software work, so that's usually the lead developer or the dev team. In commercial or contract work, it's whoever pays the bills.

    The hard part is doing the estimates -- but with experience, it gets easier to say "I can code the input and scrubbing routines in a lazy afternoon" and "Putting stuff in the database will take three days." The customer evaluates the estimates and the stories and arranges them in best business value order.

    Then you do the most important things first. If you know that in the future you'll need to store data in a database, but it's more important to get the input routines working now, just do the input routines. You can always add complexity to software later, but it's hard to reduce it. So do the simplest thing that could possibly work now.

    (XP fans will recognize this as a variant of The Planning Game. It is not appropriate in all circumstances, but it has helped my software. Your mileage may vary, and you didn't pay me for this advice anyway.)

Re: Rewriting some code
by salvadors (Pilgrim) on Feb 18, 2001 at 21:31 UTC

    I have decided to rewrite a badly written program of mine ... The main reason it was so badly written was that I did not fully plan out how the program would work.

    Although I greatly support your desire to rewrite, I wouldn't beat yourself up too much on this. In fact I'd probably argue that this isn't why your program ended up badly written.

    It's intensely diffiuclt to properly plan out software. If you're lucky enough to have a detailed specification of exactly what's required, excellent. But even then, are you sure it'll never change. This applies whether you're writing for your employer or for yourself. Requirements always change. So don't worry too much about planning for that.

    Just develop what you need, when you need it. The important thing is to never hack yourself into a corner. Any time you're developing and you think "If only this piece of code had been more abstract / less tightly coupled / whatever", resist the temptation to hack around it. If you do that, then very soon you have unwieldly code that'll be a nightmare to maintain.

    Instead, refactor that piece of code so that it works for what you had, and also for what you now need. (Good tests are essential). If you do this relentlessly at each stage then you always have a 'good enough' code base.

    Does anybody know of some good techniques to plan out code? Which ones work, and which don't?

    I'd argue that any technique to plan out code doesn't work! Do what you need as you need it, and keep improving your code as you go. That's all there is.

    Tony

      Well since I designed the code while I wrote it some of the most important parts did not fully work with each other since I did not plan out their interaction fully. Also I have about 4 pairs of subs where the diffirence between the pair is in one symbol(+ or -)! There is also a subroutine that has to find the integer componenent of a quotent, I did not kow I could do this in one line, so I subtracted the rmainder I would get from the divident and then divided it by the diviser!I figured this code is beyond saving anyway

        Well since I designed the code while I wrote it some of the most important parts did not fully work with each other since I did not plan out their interaction fully.

        I have to admit I find this difficult to believe. Why did you need to plan out their interaction? If you coded their interaction for one thing, and it didn't work properly, then that's not a planning issue, it's a coding issue. So why would it be any different for other interactions?

        If you need to add another interaction, and the previous code doesn't fully allow that, then rewrite the previous code to continue doing what it used to do, whilst also allowing what you now need to. This is the essence of refactoring.

        Also I have about 4 pairs of subs where the diffirence between the pair is in one symbol(+ or -)! I figured this code is beyond saving anyway

        Not at all. The standard way of dealing with these pairings (say sub do_a and sub do_b) is to create sub do_c which is the 'more correct' version that will cope with both versions, taking whatever parameters you need to supply to ensure it does the right thing.

        Then, once that is tested, you change sub do_a and sub do_b to delegate to sub do_c in the correct manner.

        Then, once you've tested this, you can step through the remainder of your codebase, either now or over any period of time you like, changing all instances of do_a and do_b to the relevant do_c calls.

        When you think you've them all cleared out you can change do_a and do_b to issue warnings, or even die, if they get called, just to make sure, and eventually remove the subs.

        The speed at which all this can happen depends on the size of your codebase and the time you've got to do all the tidying up after yourself. But stages 1 and 2 are fairly straightforward, and they're all that are required to ensure that your code still runs correctly. Everything after that is just tidying up.

        Sometimes it's definitely good to start from scratch ("build one to throw away", and all that), but there's very little code that's beyond saving, and the skills you can develop through saving unsaveable code can come in handy when you need to maintain code that you can't just start again from scatch!

        Tony

Re: Rewriting some code
by Fingo (Monk) on Feb 19, 2001 at 03:40 UTC
    Maybe I should get Code Complete. I was in barnes and Noble today, and I saw it, forgot to get it tho.. :(