Low level design

In the software business we tend to speak of design as though it
only exists at the highest level, and precedes all construction not
to be revisited. How often have you heard "The design phase is done."?
Not coincidentally, we speak of implementation in the opposite voice,
and "high level implementation" is not a commonly heard phrase.

What might we mean by low level design and be able to distinguish
the meaning from low level implementation?

What's the problem?

As is probably obvious from the content of this site, I spend a lot
of my time working fearlessly near the bare metal of Linux and UNIX. My
code calls a lot of operating system functions, and for the most part
they are quite regular and predictable in their behavior. For example,
the read function, described this way in section 2 of the man
pages:

ssize_t read(int fd, void *buf, size_t count);

The description of normal operation is described as
"On success, the number of bytes read is returned (zero indicates end of file),
and the file position is advanced by this number. On error, -1 is returned,
and errno is set appropriately."

read represents the type of low level design principle that might
be described as functions return the number of successful operations, and provide
negative values to indicate errors. I am comfortable with this, and it is
easy to remember and logical.

You do not have to look very far in the documentation to see that this
principle is hardly observed with any consistency. Yes, write works
exactly the same way as read, but if you are reading and writing you probably
have the good sense to call close when you are done.

How does close work?
"close() returns zero on success. On error, -1 is returned, and errno
is set appropriately."
The opposite low level design principle of return zero for OK is even more
widespread within the worlds where X is the final letter.

Guidelines for a solution

Here are my suggestions:

For functions that return an integer of some type, decide on what is meant
by positive numbers, zero, and negative numbers. My suggestion implies that where it is
reasonable to do so, all return values should have sign.

Decide on value semantics or reference semantics, and loudly call out the
exceptions to your chosen principle.

It does not matter how the functions in a source code file are organized,
but order them the same way in all files. Alphabetic can be good or bad, and
there are alternatives.

Either freeze on a version of the language you are using, or roll all the
code to each new version as it comes out.

Order the parameters of a function consistently: for example sources
come before destinations, and optional or defaulted parameters are only at the end.

Use the entire language, and express the programming in the most direct
and unambiguous way possible. There is a lot to be said for brevity.

Unfortunately, the above priniciples are incomplete, and each one could
easily be expanded into a longer article. Additionally, there is very little
evidence that anyone agrees with me, at least not if the code written by other
programmers is a guide to any sense of intuitive adoption by the hoi polloi.
But ... failure to have some operating principles of low level design turns
every programming exercise into an Easter egg hunt; if you are writing the
code, then you are hiding the eggs, and if you are maintaining the code you are doomed to
crush them with your shoes.