[erlang-questions] dialyzer output help
Mon Aug 10 17:32:02 CEST 2015
I wanted to comment here on specific points, so I've taken your email
apart and reassembled it for what I felt fit a better narrative for my
stuff. Please don't see some dishonesty in the argument there (creating
a strawman or whatever) as this isn't my intent :)
On 08/10, Garrett Smith wrote:
>Back to comments - my point is that your *code* is the docs, as far as
>implementation. If your code is not clear, make it clear. If you can't
>make it clear, try harder. There are some very rare cases where some
>code is just hard and some comments can help clarify what's going on -
>but these are *unicorn rare* in my experience.
I've conducted a poll a few years ago (2012) on Erlang and Maintenance
in this community (http://ferd.ca/poll-results-erlang-maintenance.html)
and one of the interesting results was in the following image (also
The idea that comments are not required tends to decrease with
experience in the language and familiarity with it. At the very least,
there was decent correlation.
I like to think of it as someone learning to read: you first start by
reading out loud as you read; it helps build connections and solidify
your grasp on language. As you get a more profficient reader, you
subvocalize more and more up to the point where speed readers do not
even 'mentally read' words -- they just glance over the text and can
understand meaning from it anyway.
Newcomers writing comments in the code, as far as I can rationalize it,
tends to be about writing down a translation of what the code should be
doing against the actual implementation.
As you get more familiar, that translation takes place automatically and
the comments become more useless.
If I had to give a tip to newcomers, it would be that it's fine to write
these comments first -- they act as a bit of a specification or pseudo
code. As you go on, the refactoring Garrett mentions would be to try, as
much as possible, to make the logic in your code look like the comments
you wrote, so that they become obsolete and can be dropped.
Let's take some fake code as an example:
%% Verify that only adults (18 years or older) can enter
can_enter(Age) when Age >= 18 -> true;
can_enter(_) -> false.
So that's a decent specification, and a newcomer gets to go "oh okay,
Age is the variable, >= is how they compare here, not =>, and apparently
the clauses are alternatives".
As you get more used to it, you lose the interest for the comment, but
there's still a lot of interesting stuff left untold:
- The function assumes that age is the accepted factor for adulthood
- The function assumes that the program runs in a jurisdiction where
adulthood is defined as 18, rather than 16, 19, or 21, for example, or
- The function only expects numbers to be passed in.
So a more complete form could be imagined to be written like:
%% Age of adulthood in Quebec
-type age() :: number().
%% Age verification is required by the government
%% on online betting websites; credit cards would work
%% but can sometimes be granted to minors and isn't sufficient
%% for proper verification. However, just asking for age
%% can legally be considered good enough.
-spec can_enter(age()) -> boolean().
can_enter(Age) when Age >= ?ADULT_AGE -> true;
can_enter(_) -> false.
And now the code has more criteria encoded. You'll noticed I pulled a
bunch of information out of my rear end just to add comments, but
really, those are the tricky things in code that bite us and are worth
putting in there, on top of everything else.
Why? Because the next time someone comes in and refactors, they know why
the code was added, and it makes it so, so much easier to make a good
decision on whether it should be removed or not without having to hope
it's somewhere in source control.
What should be kept in comments? The stuff that is hard to represent in
- Why you picked a given algorithm or implementation details
- Gotchas are how to use the code
- Edge conditions that cannot be represented otherwise (through type
specifications and whatnot) in your language of choice
- The rationale for broader design decisions. "We picked UUIDs for
identifiers because the system requires sharding and it is easier
with them than sequential ids" Hell: should the ids be considered
opaque or not?
Details about what the code *does* are interesting to newcomers, still,
so part of the question you have to ask yourself is: who is my target
audience? Who will read this code?
Even if the need is not there for veteran Erlangers, it might be there
for newcomers. If you're the senior member (or consultant) on a team
with a lot of new people, it might be interesting to put these 'useless'
comments in to onboard everyone else.
Development is extremely human, and knowing that such comments are
important to some people means that they *should* be in your toolbox if
you work with them, or want them to work with you.
>Documenting user facing functions, on the other hand, is important to
>help your users understand how to use a function. It doesn't
>necessarily cover each and every implementation detail - for that you
>can always read the code - but it should provide what a user needs to
>use the function as it was intended to be used.
Yes! But "read the code" is a pisspoor thing to tell almost *anyone*.
The reason is that there are many types of documentation for different
Newcomers: what does it do, why did you write it, who should or
shouldn't use this piece of code, where can additional info be found,
short examples, etc.
Regulars: Reference manuals, examples, edoc, wikis, websites, api
Contributors: architecture, project structure, principles guiding the
design ("we favor the users on errors", "the state on disk cannot be
left inconsistent and we prefer to lose data", etc.), tests: where to
find them and how to run them, issue tracker, **the source**.
If anyone but a contributor (or someone looking for contributor-level
information) has to read the source, your doc is not good enough.
Regulars and newcomers shouldn't have to care about your code and how it
does things; they care about whether they should use it, what it does,
and how to use things.
Only contributors or people debugging your stuff tend to care about
*how* it does things or *why* it does it.
I did expand a bunch on this in a blog post before, so I'll just link to
it rather than filling everyone's mailboxes even more:
More information about the erlang-questions