
Clear is better than clever [pdf] - ngaut
https://dave.cheney.net/paste/clear-is-better-than-clever.pdf
======
userbinator
It's interesting that the comparator function is one of the examples, because
that's something which shows how people often confuse _verbose_ with _clear_ ;
I think it's best written in a single line:

    
    
        return a < b ? -1 : a > b ? 1 : 0;
    

That's one line, compared with the 10(!) of his proposed method using a switch
statement. Having worked with some "modern" codebases, I think verbosity is a
bigger problem that's become especially prevalent recently, since the idea of
making a simple thing simple is so enticing and easy, but emphasising "micro-
readability" to that extent (that's 10 lines of code for two simple decisions)
will bloat the code and make "macro-readability" harder, and it's the latter
that really matters for the understanding of complex software.

Anyone who has the experience of reading lots of highly trivial functions like
those, and gotten the feeling "I've read a _lot_ of code, and I understand
what each little bit does, but what is the whole thing trying to do?" That's a
symptom of excessive verbosity.

To offer another (subjective) point, I think the lack of semicolons or other
statement delimiters does make code harder to read, as it makes it look
similar to a run-on sentence. Natural languages have punctuation for a similar
reason --- you can quickly scan over sentences by finding their delimiters.

Also, the counterargument:
[https://www.linusakesson.net/programming/kernighans-
lever/in...](https://www.linusakesson.net/programming/kernighans-
lever/index.php)

~~~
illys
Fully agree!

Combinations of if/else can seriously damage readability and maintainability.

I (all the time) face verbose code that pretend to be readable and that
requires lots of attention just to find out you are setting a single variable
across 10-20 lines.

Example:

    
    
      if (cond1)
      {
        myVar = 1;
      }
      else if (cond2)
      {
        if (cond3) 
        {
          myVar = 10;
        } 
        else
        {
          myVar = 100;
        }
        ...
      }
      else
      {
        myVar = defaultValue;
      }
    

* huge number of lines

* not obvious (until we read all) that we setup a single variable

* combination of conditions difficult to trace for each given value

* high risk of forgetting cases...

Instead of

    
    
      myVar =
        (cond1)             ?   1 :         // comment case blabla
        (cond2) && (cond3)  ?  10 :         // comment case bla
        (cond2) && (!cond3) ? 100 :         // comment case blablabla
        ...
                              defaultValue; // comment default
    

* one line per given value

* operation on a single variable obvious

* match between conditions and values obvious

* high visibility on all the cases

* even more readable with proper vertical alignment

* a comment can be added on each line to document the case

[sorry for the multiple edits: I had a hard time getting { } properly display,
they ate up the new lines]

~~~
hotBacteria
You can write it without resorting to one-line conditionals:

    
    
      if(cond1){
       myVar = 1;
      }
      else if(cond2 && cond3){
       myVar = 10;
      }
      else if(cond2 && !cond3){
       myVar = 100;
      }
      else {
       myVar = 4;
      }
    
    
    

But when I encounter this kind of situations I have other problems than code
formatting anyway:

with 3 conditions you have 2^3 possibilities to check: are you really really
sure (!cond1 && !cond2 && cond3) should give you defaultValue ? Do you really
want 1 even if !cond2 ? etc...

When possible these conditions should be avoided in the first place (depending
on context of course)

~~~
tabtab
That makes code formatting inconsistent because many prefer the other way. The
VB.Net style is more compact and readable in my opinion:

    
    
            if cond1 then
                myVar = 1
            else if cond2 and cond3 then
                myVar = 10
            else if cond2 and not cond3 then
                myVar = 100
            else
                myVar = 4
            end if
    

The VB.Net style also makes it easier to identify mismatched blocks because
the "enders" are named differently. (One can also put the assignment on the
same line as the conditional, but I generally don't recommend it.)

Some may complain it's slightly verbose, but few if any will claim it's not
clear.

~~~
elcritch
IMHO, better but it’s still confusing when you have multiple places where you
name the variable. Functional programming style forces you to be more explicit
and pushes you to separate out the assignment expression. In Elixir I’d do:

    
    
        myVar = 
          cond do
           cond1 -> 1
           cond2 && cond3 -> 10
           cond2 && !cond3 -> 100
           true -> 4
          end
    

ML languages have similar constructs.

~~~
tabtab
Maybe, but that misaligns the values. I'd rather see them lined up. And often
more complex logic may be added to the sub-blocks such that the simple pattern
goes away. Code should be able to "degenerate well", meaning it shouldn't
require lots of rework when the initial pattern fades or changes in the
future. It's one of the reasons I often use If/else instead of switch/case
statements.

------
auggierose
> To be clear, I don’t mean to dismiss the work of a lone programmer toiling
> on programs without anyone to pair with or learn from. I’ve been that person
> many times in my career as a programmer, it’s not fun.

I'd say it's a lot of fun.

~~~
ahartmetz
It completely depends on the quality of your collaborators. Are they good
developers, do they have somewhat compatible views, and are they reasonably
friendly? I prefer working in a highly capable group.

~~~
zeroxfe
Yeah, working with other good devs is fun too, but working alone is a special
kind of fun. :-)

------
MichailP
This reminds of a quote by Nikola Tesla: “The scientists of today think deeply
instead of clearly. One must be sane to think clearly, but one can think
deeply and be quite insane.” I always preferred clarity over "cleverness" not
just in programming, but also when say reading a book on a technical subject.
Clarity evokes feeling of beauty I would dare say.

~~~
hu3
“Simplicity is a great virtue but it requires hard work to achieve it and
education to appreciate it. And to make matters worse: complexity sells
better.” - Dijkstra

------
xixixao
Nice intro, which then jumps to an absolutely arbitrary (for someone who
hasn't coded in Go) set of recommendations, which are (imo) poorly argued from
the perspective of clarity. Especially the case of "var person int", how is it
cleaner than "var person int = 0" \- and why are we even talking about zero
values when the variable was not supposed to be intialized. Many decent
imperative languages let you not intiialize a variable, and then not allow you
to reference it until it's been initialized in all branches.

Mant things are left on the table. First of all, the audience. If you're
explaining something to someone, you must consider the audience to be
successful. So are we writing code to be read by Go experts? Go noobs?
Software Engineers with general background in many lanaguages, but perhaps not
go? Noob programmers? You want to assume the lowest level of understanding
that is imaginable, and that's probably the last but one I listed in corporate
environment.

Now that you have your audience, you gotta wrestle with some high level issues
that then trickle down to concrete code. Explicit over implicit. Purity over
mutable state. Small code units over monolithic code units. DRY. Verbose
naming (that doesn't violate DRY). You gotta agree on the right level of code
documentation - especially important for anything that resembles library code
(or is an "abstraction").

The hard parts (like good naming) are not Lintable (of course Lint anything
you can, use auto-formatter etc.), they are cultured through countless
interactions between people in your organization. Getting third opinions is a
valuable method here.

~~~
jerf
'Especially the case of "var person int", how is it cleaner than "var person
int = 0"'

Because they're equivalent. There no uninitialized values in Go; everything
not given an explicit initializer is zeroed out.

"So are we writing code to be read by Go experts? Go noobs? Software Engineers
with general background in many lanaguages, but perhaps not go? Noob
programmers?"

One of the nice things about Go not particularly appreciated by a lot of the
HN community (as evidenced by a lot of the other comment threads) is precisely
that code targeted to those various targets will not differ that much.

I also program in Perl 5 a lot, unfortunately, and to make it professionally
palatable, I do indeed have to program in a dialect of Perl that has been
chosen to be something that can be read even if you are not a Perl expert. I
tend to avoid dragging in huge rewrites of the object system, for instance, in
favor of the built-in support, which I can reasonably expect everyone to know.
I avoid using autovivification, etc. I often see code written by a Perl expert
in the code base, and have at times even torn it apart and put it back in the
LCD dialect we locally use, just so we don't have this sudden, confusing chunk
of code. The code is messy for many of the other reasons I've come to dislike
large dynamic-language codebases, but you won't encounter $% +=
$(-/\\#/[[]]/l; in our code base.

In Go, there's not much need to cut back to a subset of the language. There's
only a handful of constructs you need to avoid, and it's the same code for
almost every level. The "programmer who only knows half of Go" isn't that big
a deal, because anyone who knows half of Go can finish the rest of it in a
couple of hours.

I value this professionally. I understand why people who seek other things
from their programming do not, because I also have times I seek those things.
My personal codebase is much more mixed. But when I'm being _paid_ to produce
code, I'm not being paid to feel like I'm really clever for stringing one line
together that downloads a web page, parses it through an HTML parser, and
strips out all the text, returning the text nodes as a stream of strings or a
concatenated string or whatever. Yes, I _can_ do that, in several languages,
but except in certain specialized circumstances, that is low quality
_professional_ code, even if it "works", because when I expect someone with
two years of experience to make a change to that code base, I'd like them to
be able to do it in a reasonable period of time, and with a reasonable
understanding of the consequences and tradeoffs, not as a modification of an
incantation.

(Every time someone tells some story about the one guy who has been around a
long time and knows all the things and is the only one who can make any
changes to any production system because it's all his code and only he can
understand it because it's all crazy nonsense to anyone else, and all the
schedules are busted because even he no longer can keep up with the mess, we
all have a good laugh and condemn him. But when we get told that in order to
avoid that, we may have to not write the cleverest possible code that we can,
and that we need to prefer simple, effective code that works, and is easy to
understand, a lot of us get all offended at the infringement of our rights to
cleverness. Well... it's the same thing, just two different angles.)

~~~
jlokier
> > Especially the case of "var person int", how is it cleaner than "var
> person int = 0"'

> Because they're equivalent. There no uninitialized values in Go; everything
> not given an explicit initializer is zeroed out.

Using equivalence is often regarded as _less_ clean.

Because it relies on the reader to be familiar with language-specific quirks.
Even if they are, it adds a touch of cognitive overhead until it's become
habitual.

In a language like Go, I think the performance will be identical in both cases
because it has a basic data flow optimiser.

I program a lot in Perl5 too, and like you, I tend to favour the built-in
support for things. I also really recommend the "experimental" function
signatures, which make it read a lot more like other languages, and removes
boilerplate. However, for better or worse, performance matters in some things
I write, and Perl5's optimiser doesn't bother with much dataflow optimisation
(improving the interpreter seems to have stalled for decades). So when
performance matters, I do write things like 'my $x;' instead of 'my $x =
undef;', relying on familiar equivalences. I would prefer the interpreter made
them identical so I could state the intent more clearly without penalty,
especially because performance-sensitive code tends to be difficult algorithms
where clarity is more important.

------
piinbinary
When you are talking about making code "clear," I think it's important to ask
"clear about what?"

Is it:

* Clear about what the machine is doing?

* Clear about what the possible error cases are?

* Clear about the purpose of the code?

Go often prioritizes making it clear what the machine is doing over making the
purpose of the code clear. In some languages you might write `newList =
map(myFunc, myList)`. This is clear about what I intend, but not how it is
accomplished[0]. The equivalent for-range loop in Go is clear about what it
does at the expense of diluting the intent.

[0] for example, that map function could apply to the first element first, or
the last element first, or it could apply to all the elements in parallel.

------
buu700
I agree with the sentiment, but not with Go's interpretation. To me, higher-
order functions like map and reduce are much easier to read than the
equivalent for loops and are less likely to have subtle bugs (off-by-one
errors, etc.) because they more directly capture the author's intent.

~~~
revvx
I agree 100%.

In my experience, loops and recursion are lower level constructs that should
ideally be used only in libraries (map, filter, limit, sum, distinct, etc [1])
and in hot code paths (for optimization).

Kevlin Henney makes a good observation on one of his talks about how "you have
written all the loops you will never need in your life" [2], and those are
constructs such as map/filterand friends, present in LINQ, Java Streams, Ruby
Enumerables, etc.

His argument is that code made with those primitive is clearer than code made
than procedural loops, because when you read it you don't have to "execute the
code in your head".

I'd argue that using procedural loops is what's actually "too clever" here,
despite being more verbose!

-

[1] I have mixed feelings about "Reduce". It is hard to use and, most of the
time, hard to read as well. It's too low-level.

[2] [https://youtu.be/APUCMSPiNh4?t=3317](https://youtu.be/APUCMSPiNh4?t=3317)

~~~
buu700
_I have mixed feelings about "Reduce". It is hard to use and, most of the
time, hard to read as well. It's too low-level._

Fair enough. I'd certainly always prefer a special case like `.sum()` over
something like `.reduce((a, b) => a + b, 0)` where applicable.

I don't think reduce is overly complicated, but it's not much of a step up
over a for loop and can be abused to write code that's more confusing to
reason about than an equivalent loop.

------
Verdex
I'm fairly sure that we as a community can come up with an objective measure
for the phrase "clever code". Something like: Exploits implicit and/or hidden
details to correctly function.

However, I've never seen a convincing and objective description of clear code.

Sometimes people mean that clear code is verbose code.

Sometimes people mean that clear code is uniformly formatted code. [For best
results we should manually format the code the same. This builds character.
Automatically formatting will not be considered.]

Similarly, sometimes people mean code smells are unfamiliar code. Or that code
smells are patterns that they misused once and it bit them.

Objective methods of describing the ability for people to comprehend code when
all else is equal do not exist as far as I have been able to see. The best we
have is cyclomatic complexity, but there's some reason to believe that line
count may be a better indicator (which can't be good). And cyclomatic
complexity completely misses the effect of mutable or immutable state, the
presence of bad APIs, poor variable naming, etc.

~~~
revvx
All IMO:

> However, I've never seen a convincing and objective description of clear
> code.

I take "clever code" to mean "code that looks pretty on surface the but
requires the reader to dig in in order to understand the intent".

The problem with clever code is that it is misleading. It lacks empathy. You
assume the next programmer will understand it at first glance just because it
looks cool or pretty, but they'll struggle to parse it.

\---

> Sometimes people mean that clear code is verbose code.

I also consider some verbose code to be "clever code" too. Most of the time it
is just people using hammers where screwdrivers would be more appropriate:

\- Unnecessary structures - eg: classes that could be functions taking 2x or
3x more space

\- Unnecessary usage of polymorphism - eg: inheritance chain that could be a
simple if

\- Excessive indirection - eg: layered code where most of the time the layers
don't do anything

\- Plain wrong abstractions - eg: using query builders to build queries that
would be smaller and more readable in SQL

\- Fear of making classes too big - eg: instead of adding a method to a class,
making a second class that knows too much about the innards of the first one

\- Procedural code disguised as OOP - eg: breaking up a method into multiple
private ones, but ending up having a lot of instance variables that were local
variables before. When everything could be a single function.

\---

> The best we have is cyclomatic complexity, but there's some reason to
> believe that line count may be a better indicator (which can't be good). And
> cyclomatic complexity completely misses the effect of mutable or immutable
> state, the presence of bad APIs, poor variable naming, etc.

Great observations. I agree 100%.

Since you mentioned it, I find cyclomatic complexity a bit too easy to game. I
always wanted to have a metric that prevented people doing that, and took
multiple methods into account.

When you break a method in three or four without adding REAL abstractions
(a.k.a. "things you don't have to follow with the debugger to understand"),
you're not making it easier to read, in fact you're making it harder because
the reader has to jump around your code.

Of course, it's harder for machines to know the difference between good and
bad abstractions. But I think we should take that into account in code reviews
and such.

~~~
Verdex
> When you break a method in three or four without adding REAL abstractions
> (a.k.a. "things you don't have to follow with the debugger to understand"),
> you're not making it easier to read, in fact you're making it harder because
> the reader has to jump around your code.

Yeah, there's competing forces involved. If you push too many things together
that do not belong together, then you end up with code that is hard to
comprehend. Additionally, if you spread too many things apart that should
otherwise be together, then you end up with code that is hard to comprehend
(your point). Finally, what things belong together and what things ought to be
separated will depend on the domain and even the specific constraints within
the domain.

In order to objectively determine when things have gone poorly you have to
factor in a _lot_ of external details.

For example, manual memory management is a detail that should almost always be
someplace else because it isn't relevant to solving the problem at hand. So we
did this with garbage collectors. However, sometimes we need this detail
present (high performance computing and/or constrained hardware ie video games
etc).

~~~
revvx
> For example, manual memory management is a detail that should almost always
> be someplace else because it isn't relevant to solving the problem at hand.
> So we did this with garbage collectors. However, sometimes we need this
> detail present (high performance computing and/or constrained hardware ie
> video games etc).

That's a great example.

IMO looping is another case: I think it is clearer to use constructs like
map/filter/group/sum/reduce instead of for/while/break/continue/etc. You only
really need the procedural ones in hot-paths and such.

Concurrency too: in Javascript you had to nest callbacks and promises, and
they were also "too noisy". Async/await helps you keep your code more
readable. I think Fibers in Ruby (and other languages) were a good idea too.

-

> If you push too many things together that do not belong together, then you
> end up with code that is hard to comprehend.

That sums it up nicely.

Cross-cutting concerns should be abstracted (but not hidden), as they don't
belong together.

------
coldtea
> _To be clear, I don’t mean to dismiss the work of a lone programmer toiling
> on programs without anyone to pair with or learn from. I’ve been that person
> many times in my career as a programmer, it’s not fun._

Wait, what? That's the most fun!

------
lopatin
I love Go and respect the philosophy of the language, but I do agree with
userbinator that the question of how to achieve that becomes much more
interesting and less bike-sheddy when talking about macro readability.

I’d also like to point out the irony of how an article about readability is
borderline unreadable on a mobile device. The font size is microscopic on page
load, and after zooming in to normal font size on a standard iPhone screen, I
can only fit 1/3 of the width of the text without scrolling horizontally. If
your content is in paragraph form, please just use html.

------
scraegg
To a certain degree. I'd say it like this:

Too clear is not clear at all.

Too clever is not clever anymore.

------
del_operator
Reminds me of an early code review that preferred applying De Morgan’s law and
being initially surprised. It was a small chat that started talks of the
clever vs readability on a small team.

Similar things would happen with say map(f) |> map(g) vs map(f |> g). My clev-
dar just reminds me to ping the reviewer or leave a note.

~~~
revvx
Yeah. I always see the De Morgan's Law being used to make the code look
prettier or look less complicated.

I'd say it's objectively prettier most of the time, but unfortunately that's
exactly what introduces double negatives or other ambiguous stuff and makes
the code more confusing.

It's a nice refactoring step, though: apply it, extract the condition into a
well-named variable and test that condition.

------
olah_1
Sometimes clever means succinct. And maintaining less lines of code can also
lead to less bugs.

~~~
Consultant32452
I'm not disagreeing with you, and maybe this is just my personal experience,
but there seems to be a movement that promotes succinctness over all other
qualifications. It's as if someone's comp-sci class had a competition for who
could accomplish some task with the fewest bytes of code and a whole
generation of programmers never got out of that mode.

I've heard comedians talk about a set not having any fat in it... every
phrase, every short pause, etc. is exactly what is needed to make the bit
funny. To stretch this analogy a bit, you can trim so much fat that you start
taking the meat and the audience can no longer follow the joke. We need that
kind of philosophy in coding.

~~~
olah_1
On the contrary, I think the zeitgeist for the last 5-10ish years has been the
opposite. "Verbose and explicit > Succinct and implicit".

I think python and golang are largely responsible for this kind of movement in
recent years. Because of that, I find languages like Perl 6 to be a breath of
fresh air.

~~~
Consultant32452
That's interesting. I wonder if that's influenced by the languages we use, as
they might have different cultures. I primarily work in Java, which is
famously verbose.

~~~
Chris_Newton
Reading this discussion, I think one inescapable conclusion is that personal
experience has a great influence on what people consider a desirable coding
style. Among other things, people often infer something that isn’t actually
there, because such an inference would hold in the programming language(s) or
the more general programming model(s) they are familiar with.

For example, there’s a big thread about the three-way comparison function in
this discussion. Lots of people don’t like nesting ?: syntax to implement the
required behaviour as a one-liner, but the objections essentially seem to be
about the syntax of the ternary-if operator in C family languages. In another
language, with a more intuitive syntax for this behaviour that doesn’t look
like operator soup, the underlying idea of testing a series of conditions in
order and yielding a single output value based on the first condition that
matches might be perfectly intuitive to those same people.

Someone else in that thread commented that using a switch statement with
conditions rather than specific values was unwelcome because then the more
general conditions might overlap. Again, that view seems to be based on what
the keyword “switch” means in a lot of established programming languages.
There are other languages with features that test a series of potentially
overlapping conditions in order and act based on the first match, and perhaps
that same person might not have had the same objection to the same behaviour
if it didn’t come with the baggage of the term “switch”.

At this point, I personally wish I could concentrate more on the intent when
I’m programming. For example, do we need an expression or a statement here, or
are our conditions a set of mutually exclusive options or potentially
overlapping? My ideal programming language today would provide ways to express
differing intents with some — _any_ — reasonable syntax, but with very clearly
defined semantics. Whether a language uses semicolons or syntactic whitespace
or Lispy parentheses has long since stopped mattering to me. But that’s the me
who’s been doing this for a long time and got tired of debates about minor
details because in the end they mostly don’t matter. A younger me, one in the
early years of his programming adventures who hadn’t yet seen these
discussions a hundred times before and didn’t yet think in the same ways,
would probably have delighted in the language lawyering and syntactic quibbles
in that thread, and would no doubt have had a strong opinion on each
suggestion.

And that brings us neatly back to where we came in, because it means the
properties of code that is clear and desirable to me today are _very_
different to the properties that would have made code clear and desirable to
me, say, twenty years ago. So if I were writing code today and trying to be as
clear as possible, my target audience would be a huge factor in the choices
I’d make.

~~~
olah_1
I think the semantics of the language is also important.

A ternary operator in a C like language probably is frustrating because it's
some magic that was just shoehorned into the language with no rhyme or reason
behind it.

However, in a language like Perl 6, each magical operator has an intelligible
semantic meaning behind it almost like a natural language. So when you mix and
combine different operators, it starts to make sense to you. See this post for
an example [https://perl6advent.wordpress.com/2017/12/11/all-the-
stars-o...](https://perl6advent.wordpress.com/2017/12/11/all-the-stars-of-
perl-6/)

~~~
Chris_Newton
_I think the semantics of the language is also important._

Yes. I suppose I’m arguing here that the importance of semantics is much
greater than the importance of syntax. It’s not that syntax doesn’t matter,
but these days I find myself much more concerned with what features a
programming language offers than exactly what they look like.

 _A ternary operator in a C like language probably is frustrating because it
's some magic that was just shoehorned into the language with no rhyme or
reason behind it._

I’m not sure I can agree with that. The big difference between the ternary-if
operator and if-else statements in the C family languages is that the former
is used in expressions while the latter is used with statements. Sometimes
that distinction is useful.

------
arhyth
just new to Golang (in programming in general, actually) and this bug me. in
the slide, it's indicated they are semantically the same. but how?

(1) var thing Thing json.Unmarshall(reader, &thing)

(2) var thing *Thing = new(Thing) json.Unmarshall(reader, thing)

in (1) thing is a variable for a value of type Thing, while in (2) thing is a
variable for a Thing pointer

shouldn't thing (2) need to be dereferenced first?

~~~
eraxley
You are right that (2) needs to be dereferenced first, however, in go a
pointer is autmatically dereferenced when accessing its properties or
"methods". What I mean by this is that if you want to access a property on
thing, it would look the same.

In C++ it would look like this:

    
    
      (1) x = thing.Property;
      (2) x = thing->Property; (or (*thing).Property)
    

but in go, both would look the same, like this:

    
    
      (1) x = thing.Property
      (2) x = thing.Property
    

So there is a difference syntactically, and the compiler will handle them
differently, but whether the difference is semantically relevant is debatable.

~~~
saagarjha
Rust does this too, I think.

~~~
steveklabnik
(Yes, it does.)

------
kazinator
Using the keyword _switch_ for successive condition testing is a travesty.
Switching means taking one of several code paths based on a value. The problem
with using a _switch_ syntactic sugar for conditional testing is that the
cases are not exclusive:

    
    
      switch {
        a > 5:
             ...
        a > 3:
             ...
      }
    

Here a > 3 is not reachable: it tests a condition that overlaps with a > 5
completely, and a > 5 is earlier.

This form of _switch_ would be useful (and actually live up to the name) if
the compiler were required to diagnose against overlapping cases, and also
incomplete cases.

    
    
      switch {
        a < 3: ...
        a > 5: ...  error: domain of variable "a" not covered in switch without a default: clause
      }
    
      switch {
        a > 10: ...
        a > 5: ...  error: overlapping cases in switch
      }

~~~
0xffff2
Either my minimal understanding of Go is showing, or this just proves your
point, but don't you have your conditions backwards? `a == 4` would fail the
`a > 5` condition and so execute the `a > 3` case, right?

~~~
kazinator
Yes, I should have a > 3 first, since I was trying to say that the values of a
that would trigger a > 5 are caught by a > 3\. If a clause is obviously
unreachable, that's likely a bug. But it doesn't mean that reversing the
clauses is the right fix, either. They continue to overlap; and if that is
allowed, this is not a "switch" in any sense.

------
irrational
This is my mantra for JavaScript. So much of the post ES6 code I see seems
more clever than clear.

~~~
commandlinefan
I have noticed that ES6+ is a lot more functional, so there’s a lot more
map/reduce stuff in modern Javascript. Although it’s definitely more succinct
than the equivalent for loop implementations, I often find myself having to
copy and paste it somewhere else and run it in stages to see what it’s doing
whereas with the for loop variation, I could just step through the actual code
as is with a debugger to make sense of it.

------
xyproto
There is a mistake in the presentation. This compiles, even without a return
after the if/else block.

    
    
      func comp(a, b int) int {
        if a < b {
          return -1
        } else if a > b {
          return 1
        } else {
          return 0
        }
      }

------
atoav
Clear is indeed better than clever, but clear and clever are not mutually
exclusive poles. You can be clear and stupid, clever and stupid clever and
clear, all is possible.

------
picacho
kinda funny... the talk is precise, touche, and cliche. Like software
engineering 101 from top-notched software companies. Especially from those
top-notched software companies which writing C++ code. That is, if C++ were
not coded in this way mentioned in this talk, the project is just doomed to
fail. But for Go Lang, even you don't coded in these mind sets, the project
still works, and maintainable, just that, it's shit code.

------
sly010
From the second slide: "To be clear, when I say I, I don’t mean me, I mean
you. And when I say, your code, I also mean you, but in the third person."

------
qgadrian
The message is clear, and clever

------
29athrowaway
Ambiguous proverbs.

------
eternalban
"When declaring and initializing do ...".

Thank you Dave but some of us prefer explicit 'vars' all the time and reserve
:= for quickie peripheral variables.

~~~
humblebee
Do you have some examples of this style in go? This was once a gripe of mine
with go, but I have since just gotten use to the lack of clarity around types
I'm working with.

I came from JavaScript so it wasn't too hard, but I was writing mostly with C
when I first encounter go. With JavaScript I heavily leaned on properly named
variables to understand the underlying type within the context of the code I
was working on. In go however, short and nondestructive variables are common
place, with the lack of types in declarations I have to reply on properly
named functions and general context of the code I'm working in.

I'd be curious to see what go looks like with explicit vars for most things.

------
jodrellblank
_Programs must be written for people to read, and only incidentally for
machines to execute. –Hal Abelson and Gerald Sussman_

Often quoted, and I wonder if there's much evidence supporting it? Let's
replace "machines execute it" with "people use it without reading the source
code", and we can say that code is run many many more times than it is read.

Focusing on readability of the code and putting "machine execution" second,
means putting the user experience second, after the developer experience.
Imagine a race car engine which is designed first to be simple for an
unfamiliar contract mechanic to repair, and secondly to power a race car, with
the justification that the engine "will be repaired more often than it will be
built". I have my suspicions that software which is fast, responsive, and a
pleasure to use is designed by people who put the machine first; even if that
means using difficult languages and low levels of abstraction and requires
high levels of skill.

 _The most important skill for a programmer is the ability to effectively
communicate ideas_

Iverson Notation was designed as an improved way for people to communicate
ideas, years before it got turned into the programming language APL. Look
where that got it.

 _Go programmers realise that code is written to be read and so place the act
of reading code above the act of writing it. Go goes so far as to enforce, via
tooling and custom, that all code be formatted in a specific style._

Books are created to be read, not written. That doesn't happen by enforcing
that all books have the same style and formatting.

 _If software cannot be maintained, then it will be rewritten; and that could
be the last time your company will invest in Go._

Pushing a cult is the last word in the slides?

~~~
zaphar

        Focusing on readability of the code and 
        putting "machine execution" second, 
        means putting the user experience 
        second
    

Nothing kills a users experience like buggy code. Nothing contributes more to
buggy code than unreadable or unclear code. This is why another proverb often
quoted is "First make it correct, then make it fast". Fast but buggy code will
lose to slower but correct code everytime.

~~~
jodrellblank
_Nothing kills a users experience like buggy code. [..]Fast but buggy code
will lose to slower but correct code everytime._

Remind me how Chrome took over the browser market with "Chrome Fast" as its
slogan? How did nginx grow so popular against Apache? Was it promoted as "less
buggy" or "faster"? How MySQL became so prominent, was that people choosing
"slower but more correct"? How MongoDB became so popular - "slower but more
correct" winning out?

Cite some instances of when "slower but more correct" has ever won out,
assuming the faster system does work?

 _Nothing contributes more to buggy code than unreadable or unclear code._

That's quite likely false. Ten characters of unreadable code written by an
expert will have fewer bugs than 100,000 lines of "readable, clear" C++ code
written by a novice.

Nothing contributes more to buggy code than simply _more code_. To quote
Arthur Whitney: " _The only program which stands a chance of being correct is
a short one._ "

~~~
zaphar

         Ten characters of unreadable code written by an expert 
         will have fewer bugs than 100,000 lines of "readable, 
         clear" C++ code written by a novice.
    

Everytime this topic comes up someone brings up this point. The counter to it
is always the same. In the lifetime of those ten characters someone who is not
the original author will have to modify it. Because it is not clear what
exactly the code is doing they will probably introduce a subtle bug. Iterate
on that a few times and eventually you will have code that literally no one
can safely touch and the only way to fix it will be to rewrite it.

If the person doing the rewrite is smart and looks at why the rewrite was
necessary they will change those "ten characters" to however many it takes to
make it understandable for the future maintainer. It should be exactly as
short as necessary to be clearly correct and no shorter. Then you can work at
making it faster with appropriate comments about why this particular speed
hack is necessary and what you need to know before you modify it.

~~~
jodrellblank
You want a large amount of code, because you're afraid of maybe having to
rewrite a small amount of code? How does that make sense, and why won't the
large amount go through the same iterative adjustment and subtle bugs until it
needs rewriting?

 _Because it is not clear what exactly the code is doing_

A ten character English which name vaguely describes what a function hidden in
another file might have been doing (assuming you understand the word in the
same way the author did when they chose it) at the time it was written - but
it might not be doing the same thing now since it was edited so many times, is
not exact. By contrast, ten dense characters right there under your nose is
exact - as much as a programming language can be. There's nothing hidden, no
surprises, no unseen side effects, no uncertainty about whether it handles
edge cases.

Code is as exact as it gets - it does what the language does. Abstractions are
less exact - they do some version of what the previous chain of developers
intended the words to imply that they do, in the best case. In worse cases
they also do unrelated and surprising things.

And you dodged every question about when slow but correct code won out over
faster, more buggy code.

~~~
zaphar
It's not about the length of the code. It's about how understandable it is. I
think we are talking past each other so I'll bow out now. We can agree to
disagree.

