> 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

Reply via email to