> That is good convention. But while the function is so big, it is harder > to read. > > >You then also need to shovel > >data back and forth between these functions. > > Not necessarily. When the program is this tiny, single file source, > it may not so bad thing to use global scope for that shared data.
Don't you see the irony in claiming that main is too big and that the variable definitions are too far away, while at the same time saying the program is tiny and proposing to move some variables into file scope? That should say something about paying too much attention to per-function metrics... > I don't say that this code is bad. I think it is good gode, but there is > plenty of room to improve readability. I could bikeshed about it too, plenty. It's harder to make up changes with real substenance into a program that is tiny and already "good code". > > Much in the same manner that splitting the function into > > a few dozen would only make it harder to see the code for what it is. > > And when the lower level details are hidden, it is easier to see what > the code does. This is idea of abstraction. And you can go too far. You could break things into smaller and smaller pieces until you have a set of functions that resemble the instruction set of some virtual CPU. Yes, absraction is a core element of programming, and a critical one at that. However, all abstraction comes at a cost, and sometimes that cost may be greater than the value. A program is the sum of its parts, and by splitting parts of it into smaller pieces the program doesn't always grow simpler or more understandable. On the contrary; all but the best and most generic of abstractions tend to be leaky and flawed, and the programmer needs to keep many details about them in mind in order to underdstand what the code really does. Also, hiding low-level details can be the exact opposite of what you want in order to make it easy to see what the code does. I've seen this pattern with aspiring hackers who learn from contrived textbook examples with excessively annotated & commented code snippets. They learn to give every little thing a name, and call it an abstraction. What they don't learn is idioms known to experienced programmers. So they hand that code to an experienced programmer and after removing layers upon layers of unneeded abstraction (or obfuscation), including all the extra machinery needed to communicate program state between those layers, the experienced programmer finally sees the code for all its bugs. Alternatively, he can try to keep all the made-up abstractions in his head, but that can be quite a burden. He'll end up constantly jumping back and forth between them and re-checking details. Cohesion? You wanted local variables to be nearby so that they are easy to find. That's one detail. Functions hide other details which you might also want to keep nearby. Typedefs and macros make yet another way to hide details that really matter. Try looking for subtle arithmetic overflows when you don't see the operators and don't know the *real* types of the operands. If you have the time, take a look at what kind of layers were removed in LibreSSL. By reading lots and lots of code, you'll start to pick up patterns and idioms. Code becomes easier to read, and you'll spend less time trying to understand specific parts. And because you do not need to explain these parts to yourself, you also won't need to single them out and give them a name to remind yourself of what they do. The result is that you'll find larger functions perfectly readable and understandable. And perhaps you'll start to see why extra layers would actually make it harder to read. That's not to say that small functions are bad, or that larger functions are always better, or that chmod shouldn't ever be split into smaller parts. But the ability to say which abstractions are good and which are useless (or outright harmful) is something that grows with experience. And not all functions are alike; a long function can really read like a list of instructions where you can forget the past steps as soon as they are behind. A small thirty-line function with some twisted logic (add recursion?) could be a real brain teaser. > > Mind you, the code isn't written for a first-year comp sci course > > where the students need annotated twenty-line snippets to help them > > come to grips with the basic syntax and structure of a computer > > program. > > I like to write self documenting code. My practice is to comment ~all > functions with block comments, all parameters (with ranges), return > values, exceptions, external effects, all variable declarations (with > ranges). That sounds like dogma. It's not a terrible attitude to start with, but as you pick up idioms and conventions, you'll find that some things are so obvious that comments add absolutely nothing. And useless comments do not make the code prettier or easier to read. On the other hand, you'll learn to add comments in seemingly obvious parts where something less obvious needs to be considered. > > Again trying to please some quality metric? > > Yes, cyclomatic complexity. If that is high, it is usually good sign that > code needs refactoring. That you're enthusiastic and trying to make use of tools is all cool. But you also need to understand that tools ultimately don't read and write the code. Maybe your tool can help you and tell you where to look, but evidently it can't be the final judge, nor can it tell how the code really should look. And frankly, telling tech@ what your tool thinks about some piece of code doesn't really help anyone (unless it's pointing out an actual bug -- but you need to screen for false positives). When you agree with the tool and the code should be improved, you should cook a diff and send it here. > > Did you intend to achieve better cohesion and lower coupling by > > breaking the function into a dozen small functions that appease > > whatever metric you're using? > > No, lower CC index per function instead. This kind of refactoring > often reveals opportunities to increase cohesion in more complex > programs and helps to reduce the amount of code. You can artificially lower some metric per function without making the entire program a single bit less complex. You can artificially lower some metric per function and make the entire program more complex. "Cohesion" sounds nice but if you achieve it by splicing the logic of a large program into countless tiny functions, and then shovel data between these functions via file scope variables, it's not as cool as it sounds. > I think that it is not defined enough unambiguously, how ideal code > looks like. It reduces motivation to improve code better, if it is not > defined, what is better. Mr. Schwarze already explained why this is hard to do so I'm not going to bother. I'll just repeat that you need to read lots and lots of code. You need experience. You'll get a feel for it. Once you're on to something, send a diff. You usually get helpful feedback, but don't take it personally if the idea is shot down. Since I'm not sitting on any diffs right now, I'll shut up. It's tech@. -Henri
