If answer %NOTFOUND soon, please kill me, else...
February 4, 2012 4:42 PM   Subscribe

I have to code some fairly complicated logic involving nested loops, etc. I am a mere (mortal) student. Please tell me how YOU plan out the coding of complex logic in your programming.

We were taught how to use flow charts, but I barely remember how they work. However, if you think they are simply wonderful, I'll take the time to re-learn. All I know is that I've been working on this problem for hours and still can't get it down. I formulate some of it in my head, code a little, formulate some more, revise code...I need an intervention along the lines of: you're doing this wrong.
posted by kitcat to Computers & Internet (24 answers total) 11 users marked this as a favorite
I don't know about "flowcharts" per se, but what about writing pseudo-code with lots of arrows on paper?

The problem is a logic problem, not a code problem, so writing code before you have the logic down can be wasteful or frustrating. But if you get the basic

"if this
that happens"

down on paper in English, I bet it all falls into place.
posted by drjimmy11 at 4:52 PM on February 4, 2012 [2 favorites]

Flowcharts are an abomination unto god. They're worse than GOTO. Published Studies (in real journals even) have proven that they do nothing for productivity or comprehension.
posted by Yowser at 4:52 PM on February 4, 2012 [2 favorites]

"formulate some of it in my head, code a little, formulate some more, revise code" is basically what I do and I'm pretty sure is what most people do.

Are you using a debugger?

Or, I guess the more fundamental question is, is part of the problem that you aren't exactly certain what the code is doing when it goes wrong? Because debugging tools are generally intended to help you with this and let you see what's going on in memory as you step through the program.

If there isn't any debugger available for the platform you're using, what I usually do is add in checks that output voluminous state information to stderr (or whatever).

Another basic approach is to break what you're doing down into blocks of code or functions that can be tested separately so that you can confirm in isolation that they do what you expect them to do.
posted by XMLicious at 4:57 PM on February 4, 2012 [1 favorite]

Came to say what drjimmy said already - so instead i'll add... Go look at other coders examples. google the problem and see what others have done. The online communities are rich and knowledgeable and they're there for a reason. Can't tell you how much i have learned that way.
posted by h0p3y at 4:58 PM on February 4, 2012

I prefer the lexical simplicity of switch-case trees to if-else. You are literally delineating what occurs for each case, so that the code can essentially comment itself. That kind of development can help focus your mind on breaking the problem into smaller pieces — within a smaller piece, a nested condition, you break it down further, and so on.
posted by Blazecock Pileon at 4:59 PM on February 4, 2012 [1 favorite]

Flow charts are useless - I can't believe that they are still being taught. My advice is if you have a lot of nested loops, start from the inside and work out, putting code into separate functions if possible. Each function should do one thing.

For instance, if you have to run through a string reversing the letters in each word I would first write a function the reverses a single word, then call that function from a loop that iterates through a string looking for spaces.

This approach does not typically produce the best performing code, but understandable and correct code is much more important.
posted by AndrewStephens at 5:21 PM on February 4, 2012

First, write an outline in english, as comments in the code. But don't code anything yet. Something like:

* my confusing application

// get input data from DB

// convert to list of Foo objects

// foreach Foo, apply transform

// do fancy analysis of all Foo's to create result

// format result and output it

That helps keep things clear and organize. You don't have to fill it all in at once.

Now start with the first section - get input data from DB - and get it working. Repeat until done.

Of course, when you get to do fancy analysis that may actually be more involved - flesh it out when you get to it. But don't worry about it until you need to. Heck, it's probably going to be some library that you have to write, which you'll start in exactly the same way:

* fancy analysis library

// take set of Foo objects and sum all the Bar properties

// apply Fourier transform

// calculate ANOVA

// call mom

// return result set

As you fill in the outline with code, add more details to the comments. Also, if you suddenly remember something else that needs to be done, go make a comment about it in the appropriate place and then immediately return to finish what you were working on. Don't get distracted or you'll loose your train of thought.

Good luck!
posted by jpeacock at 5:29 PM on February 4, 2012 [1 favorite]

Build unit tests, and then work backwards from there.

To wit, it's often fairly easy to say "for these values, I should get this result," even if you're not quite sure of how to structure the code. Having a suite of unit tests can help you be confident that you're doing the right thing in lieu of formally proving your logic. Just make sure that you cover edge cases, invalid input, etc.

Structurally, I'm personally quite fond of delegating to helper functions and flattening things as much as possible, including returning early as soon as an error condition is detected. Sometimes other people disagree with structuring code like that; it might be worth looking at what your team currently does.
posted by SemiSophos at 5:30 PM on February 4, 2012 [1 favorite]

A few general tips:

Loop Invariants - if you can explicitly work out key invariants relating to the algorithm you're using, I find that often makes writing the actual code much easier.

Use logical equivalences to simplify conditionals.

State diagrams may be useful if your system has multiple clearly-delineated states.

Once you've got it planned out, start by typing out detailed comments for the whole algorithm. Then turn these into pseudo-code, and then finally into code that actually works.

Write tests first - this is good because it makes you really work out what it is you're trying to do. And as a bonus, you get some tests to use!
posted by d11 at 5:31 PM on February 4, 2012 [1 favorite]

drjimmy11 has it -- when you get stuck like this you should get off the computer and write the logic out on paper. It's a lot easier to implement something that's already been planned out, and planning it out will help you get better at applying logic on-the-fly, too.

Also, don't be afraid to ask for help! It's amazing how another pair of eyeballs helps you to find your mistakes. Another thing which really helps is to explain your logic (or the bug you're trying to find, etc) to someone; the process of putting things into words often reveals errors and blind spots. Tell your potted plant about it if you have to.
posted by vorfeed at 5:34 PM on February 4, 2012

I formulate some of it in my head, code a little, formulate some more, revise code.

That's good, but don't try to design your program at the keyboard. Do an outline on paper. You can work from the outside in, and from the inside out, alternately or not as you feel inclined (i.e. get the overall shape, and get the shape of the bits inside)

If you can, move the stuff which comes between IF and END-IF out into a function, so you can write

IF (something)

where DO-MY-FUNCTION can contain more IFs, ELSEs, etc., because it's much easier to keep mental track of a few lines than hold a whole page in your head.
posted by anadem at 5:45 PM on February 4, 2012 [1 favorite]

I write tests that assert what the expected behavior is. It sure makes finding the logical flaws a lot faster. I really wish they had taught this when I was in school, it would have made me a much better coder much earlier.
Pen and paper is also useful (and I do this for bigger system design), but without tests, you never really know if it works.
posted by ch1x0r at 6:00 PM on February 4, 2012

If it's too complicated to understand, it's too big. Break down your hard problem into smaller, easier to understand pieces and you can move the world.
posted by billjings at 6:10 PM on February 4, 2012 [2 favorites]

You are doing it wrong.

If you have a complicated problem (especially with nested loops) you have no business starting to code until you can explain the problem on paper or a whiteboard. If you can't explain it to yourself, there's no way that you're going to be able to write it down explicitly enough to be understood by a computer.

The last time I had a really complex nested-loop algorithm, I wound up grabbing a colleague and heading to a whiteboard. While explaining the problem I needed to solve wasn't enough to help me figure it out (like in the recent "rubber duck debugging" ask), working through the algorithm with somebody else really really helped.

In other less-frustrating examples, I'll usually use the inside-out approach. If I try to write and test code all at once with three or more loop variables, I'm guaranteed to make a simple error somewhere that's a bear to track down. Instead, write the innermost loop first. Test that. When it works, add the next loop around it.

I don't have enough information to be sure that this is what you're doing, but I can say that the incessant cycle of "think I understand the problem" -> "write some code" -> "it doesn't work" -> "tweak some things by trial and error" -> "guess some more" .... is what made my first coding attempts so painful. When I gained the self-discipline to code on paper first, coding actually became a lot more rewarding, and my designing time (fun!) to debugging time (ugh!) ratio improved drastically.

If all this is too abstract and you want more specific advice of how to attach a particular type of problem, post an example!
posted by Metasyntactic at 6:11 PM on February 4, 2012 [1 favorite]

You have to break the problem down into parts that are big enough for you to chew. There's a lemma, a subroutine, an interface somewhere in there. Find it and separate it out and solve that subproblem. This is the big thing programmers do. On preview: as many others have pointed out.

Also, try explaining it to someone else in layman's terms. Even if there's no one there, just imagine trying to explain from top to bottom what the problem is, what the solution is, and how your code implements that solution. The best studying I ever did in school was trying to teach what I was learning to someone else.
posted by fleacircus at 6:12 PM on February 4, 2012

You might want to give us the specific example you're working on.

In the absence of that:

DRY -- Don't Repeat Yourself. If you're finding yourself typing the same thing over and over again, split it out into a separate function (or method or whatever).

Break it into pieces. Start from the end -- figure out what input you need to get to the end, figure out what you need to get that, and so on.

Do a first draft and just get something working. Even if its an unholy hacked together mess. You'll probably get some ideas on how to split things up properly as you're going.

Don't be afraid to start over. Especially if you're just prototyping to get something working. Take a step back, and see if you have a way of re-organizing it in a sensible way.

Use google and look at other people's code. Don't just copy and paste code, but I can guarantee you that someone else has solved whatever problem you're stuck on. Even if they did it in a different language, you can probably learn something from picking it apart.
posted by empath at 11:23 PM on February 4, 2012

If, as jpeacock suggested above, starting with an outline of the logic in comments doesn't work, a flow chart actually might help. Especially if you're like me and drawing a picture of your problem will help you understand it. In my experience, the more complicated a problem is, the more important it is to use formal methods. Depending on the problem I might use either old-fashioned flow charts or Yourdon/DeMarco DFDs.

I'd likely stick with graph paper, but if I wound up making a lot of erasures I'd probably wish I had used yEd instead.
posted by ob1quixote at 1:05 AM on February 5, 2012

Lots of good advice already. I would only add:
- try not to use too many explicitly nested loops - use constructs like for each and hide the inner loops inside member functions / functors
- do outline the top level logic and then mock up the functions you need to get the overall flow right. i.e. just write dummy methods that return a known value until you have figured out how to code those bits. Then you know what is definitely working.
- if possible, write unit tests for the lowest level methods, and make those methods very simple so you know exactly what they do. You can always optimize later, but every time your logic starts to look a bit complex, try to split out a method that will let you think about it at a higher level of abstraction.
posted by crocomancer at 4:15 AM on February 5, 2012

Great advice as usual, I'd add "step away" for a bit. Sometimes, NOT thinking about it over a night or weekend puts the problem in perspective. Step back and see if there is an entirely different approach.

Then finding the right balance of breaking out complexity into separate functions verses large chunks of logic. Can some parts be computed prior to entering the main logic?

Occasionally a nested loop is the best approach (a matrix), but it should be very clear whats being computed.

I mostly see flow charts use to explain steps to others, not as an analysis tool. If there's more than five or six blocks, it's probably too complex to use for anything (well there are some great joke flowcharts)
posted by sammyo at 7:01 AM on February 5, 2012 [1 favorite]

These are all wonderful answers and I will certainly employ them now and in the future. I'm working with a cursor inside a procedure in PL/SQL, so as far as I know, I can't put the stuff inside the cursor into other subroutines. Otherwise, that would be a great idea and I long for it to be possible. Anyhow, thanks.
posted by kitcat at 8:21 AM on February 5, 2012

Presuming you have CREATE FUNCTION permission in some schema in the database you're working in, you can write functions to off-load some of the logic from your cursor loop.
posted by ob1quixote at 9:45 AM on February 5, 2012

I don't know if you are the one who opened the cursor, but I do remember putting a cursor in a variable in (Oracle) PL/SQL. It was a while back so I don't remember the details - I think I had to declare a variable type, and use a slightly different syntax when opening the cursor.

But once that was done I'm sure I was able to pass the cursor to subroutines which examined the current row.
posted by benito.strauss at 7:29 PM on February 5, 2012

So if you want to pass a cursor into a subroutine, this is how you do it.

The other things I remember from working with cursors is that you can declare a single variable to hold a a row from a cursor with a %ROWTYPE modifier, and I might have had to have the DBA load and extra Oracle-provided package to use ref cursors. Good luck!
posted by benito.strauss at 8:05 PM on February 5, 2012

anadem: "I formulate some of it in my head, code a little, formulate some more, revise code.

That's good, but don't try to design your program at the keyboard. Do an outline on paper. You can work from the outside in, and from the inside out, alternately or not as you feel inclined (i.e. get the overall shape, and get the shape of the bits inside)

If you can, move the stuff which comes between IF and END-IF out into a function, so you can write

IF (something)

where DO-MY-FUNCTION can contain more IFs, ELSEs, etc., because it's much easier to keep mental track of a few lines than hold a whole page in your head.

I hate it when my code throws an unexpected condition...
posted by Samizdata at 10:21 PM on February 5, 2012

« Older How often do you finish a bottle of lotion?   |   Help me turn off Windows 7 security Newer »
This thread is closed to new comments.