Control flow

Control flow is one of those things that may seem simple at first, but later one may see the messy bits. Or not, because pretty much everything in programming is controversial.

Newbie (or simply less careful) programmers tend to write the code that would only work in perfect conditions at best, since covering all the possibilities seems to be overwhelming and excessive (a similar thing happens with UIs, by the way). And then things don't work as they should.

Programming languages and libraries tend to encourage this: usually the most straightforward way to define a program is to define its behaviour in the most desired/expected/perfect conditions, optionally covering the others. In dependently typed languages, there are attempts to assist verification, though not necessarily to make it easier to define correct programs than incorrect ones.

Some methods to handle the situations that are different from the most desirable path in a flowchart:

An unpleasant thing in languages with built-in exceptions, such as Haskell, is that those exceptions could pop up just anywhere. Even if one prefers a different approach (such as ExceptT), chances are that other approaches are used in the used libraries, so one ends up dealing with every available kind of branching, possibly wrapping it into something unified along the way. There even are libraries to assist that, such as errors.

Probably one of the reasons of this rather unpleasant situation is that a correct control flow can be represented with a directed graph, a flowchart, while it is tempting/easier to think of programs as of mere sequences of actions, and to write them down in text as such (even in dot it's not that handy to describe flowcharts). State machines may be more suitable to describe control flow precisely, yet it's rather awkward to use them in high-level languages; well, actually might even be nicer than in low-level ones, but hardly idiomatic.