I have written hundreds of programs and when writing each new program, I think about how to do this and how to do that, and then start writing the program. I then spend some time in debugging or modifying it whenever it becomes necessary. I think that, I need to have a better methodology. How do you write the program, regardless of programming task or programming languages?
--Artist

Replies are listed 'Best First'.
Re: How to write programs?
by jZed (Prior) on May 26, 2005 at 18:03 UTC
    1. Document the behavior the program is meant to exhibit.
    2. Write tests that would work if the program behaved as documented.
    3. Write code that will pass the tests.
    :-)

    update: and sprinkle with liberal amounts of review by peers and refactoring at each step; if the documentation can't be understood, the interface is too complicated, so aim for clear documentation first.

Re: How to write programs?
by mstone (Deacon) on May 27, 2005 at 05:52 UTC

    I tend to work declaratively, and backwards.

    Broadly speaking, there are two kinds of programming: declarative and imperative. Declarative programming lists a sequence of results, and leaves the reader (or the computer) to work out the operations that produce those results. Imperative programming lists a sequence of operations, and leaves the reader (or the computer) to work out the results. Most of what we think of as 'software' falls under the imperative style, while things like SQL and mathematical proods fall under the declarative style.

    Thing is, those two styles link directly to the two questions that are most important to programmers: What? and How? "What does this code do?" is a declarative question. It asks you to identify the result produced by the code, or more generally, to describe the relationship between what goes into the code and what comes out. "How does this code work?" is an imperative question. It asks you to define the procedure that connects what goes in to what comes out.

    Now, as I mentioned earlier, most code is written imperatively, but it's a lot easier to design code declaratively.

    The trouble with imperative code is that it's easy to get bogged down in the details. It makes you to choose a way of representing your data, often before you know exactly what kind of data you really need to represent. Then it makes you write all sorts of representation-support code just so you can work with the values you want to use as inputs and outputs. With all that furniture in the way, the actual logic of your program.. the stuff that actually handles the work of mapping the inputs to the correct outputs.. can get hard to see.

    Choosing a representation early also makes it difficult to change your basic data structures if you decide there's a better way of doing things later on. People will often stick with a representation that doesn't really do what they want, just because they don't want to throw away the code they've already written.

    Declarative programming keeps you from having to code up a representation. Instead, you define a collection of types.. sets that contain valid input values, and valid output values.. then you use those to define the relationships between your inputs (the things you have) and your outputs (the things you need).

    You define types by listing assertions that will always be true for any item in the set:

    • Positive integers are all.. well.. integers.
    • They're all strictly greater than zero.
    • The distance between any two non-equal positive integers will also be a positive integer.
    • The sum of any two positive integers is also a positive integer.
    • .. and so on.

    And the beauty of declarative design is that you don't have to start off with a big long encyclopedia of assertions for each type. You can start with a few very rough ideas, then go back and refine them.. either by making them more specific or adding more assertions to the list.. whenever the new rules become necessary. You're free to evolve your types as the design grows, and you get a better idea of what's actually going on, because you aren't handcuffed to any specific representation.

    The idea of building a design backwards harks back to the old programming maxim: "start with the part that produces output."

    The output is the part of the program you can see. It's the where you find out whether you got the result you expected or not. If you start by generating output in its simplest and most trivial form, you know at least that much of the program works. Then you can work your way back through the design, adding one layer of complexity at a time, and verifying that the new code actually does what you expect.

    That keeps you from creating those really frustrating situations where you've written a whole bunch of code blind, then run into bug after bug after bug when you actually try to run it. It's also a good mood-maintenance trick. It's exhausting to have to write tons of code before you have anything that will actually run. It's much more satisfying to be able to run something every five minutes and see yourself making progress along the way.

    The back-to-front approach also lends itself nicely to declarative design, because the first version of any declarative design is basically:

    {inputs}-->(program)-->{outputs}

    If we start with 'inputs' being 'nothing' and 'outputs' being "hello, world.\n", the imperative version ends up being pretty easy to code. If we want to make things more complicated by saying the program has to write its output to a web browser rather than to STDOUT, we end up doing some more twiddling with "Content-type" headers, HTML formatting, and so on. But the basic principle ends up being the same.

    Back-to-front design also helps you decide exactly what inputs you actually need in order to generate the output you want. If we were to refine the design above to use an HTML template that lives in an external file, the new diagram might end up looking like so:

    {filename} | +-->(file reader) | +-->{HTML template} | {output message}--+-->(formatter)->{program output}

    and at this point, the assertions for the 'HTML template' type require us to think about error handling. If we add a rule that says, "every 'HTML template' must be valid markup," and interpret the diagram above to mean that the 'file reader' part of the program must always return an 'HTML template', then we have to find some way to guarantee valid markup if the file doesn't exist, or the program can't open the file because of permissions problems, and so on. If we really wanted to get finicky about it, we'd even parse and validate the contents of the file if we could read it, just to make sure the file actually contains valid HTML.

    So that leads to a further-refined diagram like so:

    {filename} + {hardcoded error template} | +-->(file reader) | +-->{HTML template} | {output message}--+-->(formatter)->{program output}

    where we assert that 'hardcoded error template' is also a member of 'HTML template'.

    Then we'd go to work on the message itself:

    {inputs}-->(message generator)-->{output message}

    and so on.

    The longer you keep refining the diagram, the closer you get to a set of requirements that are trivially easy to program. And once you know exactly which parts of the program need what information, it's much easier to define object classes or data structures that will carry the information where it needs to go. That's the appropriate time to worry about data representation issues, algorithms, and all the imperative stuff.

    So.. my basic policy is to start with "What?" and work my way back to "How?".

Re: How to write programs?
by 5mi11er (Deacon) on May 26, 2005 at 18:38 UTC
    I tend to try to figure out what the most difficult task is going to be, and solve that, then try to figure out the next most difficult task, etc. In this way, if I run into any show stoppers, I know about them quickly, and have more time to figure out how to get around those problems.

    As the difficult stuff is accomplished, the easy stuff is usually stolen from were ever I can find something that gets me close to what I want, and modified as needed. (not that this is any different for the difficult parts, but the easy stuff is generally more readily available and/or easily found; Perl & CPAN certainly make the difficult stuff a whole lot easier to find and/or accomplish :-)

    I've been told I've a better than average ability to see both the big picture and the details at the same time, but I've always shrugged it off. I can't understand how anyone could be good at programming if they couldn't do both. But, maybe that's part of the reason why the really good programmers are relatively rare?

    -Scott

Re: How to write programs?
by bofh_of_oz (Hermit) on May 26, 2005 at 19:25 UTC
    Here's some pointers transferred/adapted from my driving teacher, my programming teachers and... recommendations on taking <ugh!> Microsoft tests:

    1. Know what you're doing. You should know quite clearly what you want this program for and what it should do. Otherwise, you shouldn't be writing this program...

    2. Write the program logic down (use plain <your language here>, pseudocode, block diagrams etc., but on paper. Not everyone can do it nowadays, but if you can, it will help you...

    3. If you can, write the code down (again, on paper). You can always scan and OCR it later... Often, you will see a design flaw or something that needs redoing, and often it is very hard to find it in code when it's on computer (or maybe, it's just me coming from that old generation of people who actually read paper-based books)

    4. Code (on a computer). Include enough comments so that you won't get lost looking at this program three years later. If you feel like a technical writer and don't care about your job security, make extensive documentation...

    5. Test. If everything goes well on the first try, re-check the program - something is definitely wrong ;) (remember Murfy's laws?)

    6. Put into production. Don't forget to keep the source in case the company will want to fire you later and you will have to use threats and blackmail to get your severance package out of them...

    --------------------------------
    An idea is not responsible for the people who believe in it...

Re: How to write programs?
by mrborisguy (Hermit) on May 27, 2005 at 00:06 UTC

    To be honest, I always start out making something that runs.

    shell$ vi newprog.pl
    #!/usr/bin/perl use strict; print "hey"; ~ ~ ~ ~ :wq
    shell$ chmod u+x newprog.pl shell$ ./newprog.pl heyshell$

    I'm not really sure why, but that's the first thing I do EVERY time I start writing a new program, regardless of what it is supposed to do. Sure, sometimes I use, "hello" or "what's up?", and sometimes I'll even throw in a "\n", but regardless of what I'm making, I always start this way. I think after this is done.

        -Bryan

Re: How to write programs?
by Transient (Hermit) on May 26, 2005 at 19:05 UTC
    Depending upon the program:

    1. Ensure requirements are well-written, fully explained and completed.
    2. Double check that requirements are finalized.
    3. Break down the task into sub-tasks (be that OOP or otherwise)
    4. Pseudo-code tests (documenting major functionality)
    5. Write tests (I admit I don't usually do this)
    6. When the requirements change (and they always do), work at a frantic pace to accomodate, introducing bugs and other undesirable things.
    7. Test until you drop
    8. Repeat 6 and 7 ad nauseum
      Never work at a frantic pace... Better (mis)inform the client on how long it will take you to accomodate changes... If you do it faster, you will be a hero. Don't test for too long... it will fail in production environment anyways ;-) There are subtle undocumented changes between test and production environments that introduce new bugs...

      --------------------------------
      An idea is not responsible for the people who believe in it...

        There are subtle undocumented changes between test and production environments that introduce new bugs...

        Step 0. Remove all changes between test and production environments that introduce new bugs, no matter how subtle or undocumented.

      1. Ensure requirements are well-written, fully explained and completed.
      2. Double check that requirements are finalized.

      Following these rules strictly would probably mean that I would never get to stage 3 :-)

      This is why I like techniques that allow clients to change the requirements in a structured way - because there is nothing like having a partial implementation in front of you to make you realise what you really wanted.

Re: How to write programs?
by redhotpenguin (Deacon) on May 27, 2005 at 07:25 UTC
    UPDATE - this was meant to be a reply to the first comment on this post.

    What is interesting is to see the results of programs built in the opposite order.

    1) Write some code.

    2) Write some tests because your users have told you your code is breaking.

    3) Write some documentation so your users can understand the app, maintainers can maintain, and you can figure out what you have done here.

    This approach is invariably faster to market, and also great a deal more prone to failure and a high incidence of defects. Having used both approaches, I prefer the original order of docs, tests, code, especially when additional requirements arise, because the total cost of development is lower, and the product quality is higher. That documentation is a contract between you and the user.

Re: How to write programs?
by chas (Priest) on May 26, 2005 at 21:50 UTC
    I doubt there is a single methodology which will work well for most people. I usually walk around for several days thinking about a project till I am really "zoned out" on the ideas. Then I start writing; that works well for me. Even so, I don't usually write linearly - rather I implement some main pieces, make sure those work and then add parts, etc. (For example, I once wrote code to emulate a programmable calculator I had; first I implemented a stack and the functions to print it to the screen and read input; then I implemented a few operations and kept adding those over a few days. Finally, I worked on the programmability.) If something doesn't work as expected, I debug by adding print statements, but usually I'm so clear on what I want to do that I don't have to debug too much.
    I used to write English papers by putting a sheet of paper in the typewriter (a machine most of you probably haven't heard of...they're extinct now) and typing - slowly with a lot of thought. I hate writing outlines! But clearly this wouldn't work for everyone.
    Anyhow you do it, it takes a lot of concentration and effort, but if you get results I wouldn't worry much about methodology.
    chas
Re: How to write programs?
by Mutant (Priest) on May 27, 2005 at 09:51 UTC
    On a slightly different tact to most of the responses: there is a limit to how separated your design can be from your implementation. In theory, you can design all the details of an application, then build it exactly according to your spec, the details of the implementation being irrelevant. (Assuming, of course, your requirements don't change. They always do, but that's not my point here).

    Time and again, however, I've found the design wasn't able to forsee all problems, or couldn't achieve the depth of understanding necessary to spec a full implementation. To actually do this requires the application to be implemented. Only then are all issues properly understood.

    Except in very simple applications, your initial spec will almost always have to be altered, even if the requirements are static.
      Or, in the words of Frederick P Brooks (from my blog):

      The incompleteness of our ideas only become evident during implementation.

      True, true.

      /J

        The incompleteness of our implementations only become evident during tests.

        and

        The incompleteness of our tests only become evident during demonstration for important people.

        ;-)

        ihb

        See perltoc if you don't know which perldoc to read!

Re: How to write programs?
by djohnston (Monk) on May 26, 2005 at 19:45 UTC
    I am not blind, but I code in braille. Naturally this is time consuming, but since I do not program for a living I have the luxury of taking years to complete a program if I so choose. In fact, the current program I am working on started out in 1995 as a Perl 4 program. I have had to make some changes in recent years to keep up with Perl 5 and I hope it will be finished before Perl 6 hits the streets, otherwise I fear it may not be finished before I am deceased. One of the downsides to this approach is that many other programs like it have emerged throughout its many years of development and it is unlikely that anyone will care when I am finished with it - I refuse to let it go, however, as it is my legacy. There is an upside to this approach to writing programs, and that is *gawk*..kck..kck..*gasp*

    Ok, kidding aside... There's already alot of good advice posted here, so I will just add my $0.02...

    Having run a BBS in the 80's has instilled in me the appropriate amount of paranoia to always quadruple check user input. I've drawn from that experience to avoid many of the CGI pitfalls without having to experience the shame of falling victim first. But then, I don't do that for a living either.

Re: How to write programs?
by samizdat (Vicar) on May 27, 2005 at 15:25 UTC
    Honestly, artist, I think you can add more details to your methodology, but then you'd have to specify eddy currents in your development path because the input transformations affect the architecture, and the architecture affects the data flow, and the data structures can make program modularization cleaner if you change them slightly... etc.

    In short, I think the ultimate methodology is to keep in mind who you're trying to please the most and how to do that, and then get into Flow and go.

    All else is details and gradually increasing experience. :D