
Twelve Go Best Practices - chorola
http://talks.golang.org/2013/bestpractices.slide#1
======
nknighthb

        if err == nil {
            _, err := w.Write([]byte(g.Name))
            if err == nil {
                err := binary.Write(w, binary.LittleEndian, g.Age)
                if err == nil {
                    return binary.Write(w, binary.LittleEndian, g.FurColor)
                }
                return err
            }
            return err
        }
    

Why does anyone have to tell people not to do this? How does it enter anyone's
mind as a thing to do in the first place? I've been known to go _too far_ to
minimize nesting. I get twitchy at the second level. By the third my brain is
trying to crawl out my eyes and strangle me, even on code that doesn't have a
potential exit point at every level.

~~~
lmm
Short circuit returns are the devil - they make it much harder to factor out
part of a function into a smaller function. A function should have one entry
point and one exit point; that's the _whole point_ of structured programming.
If you're going to return from some random point in the middle of your
function you might as well be using goto.

(Of course, good programming languages provide a better solution than pyramid-
of-doom nesting)

~~~
nknighthb
> _Short circuit returns are the devil_

vi!

Naïve, absolutist positions in areas of long-standing debate between
programmers of great experience and the highest imaginable competence just
makes you look ridiculous.

~~~
jemfinch
Naive, absolutist positions in areas of long-standing _consensus_ between
programmers of great experience and the highest imaginable competence makes
one look even more ridiculous.

By and large, the best programmers eschew nesting in favor of early returns.
Invariably (in my experience) those who argue against early returns are
inferior programmers (and not only by virtue of lacking taste in this
particular debate).

~~~
stass
Where did you get that idea of consensus? A lot of languages do not even have
a return statement, neither does lambda calculus. Furthermore, CS community
has long abandoned statement based languages in favor of expressions and
relations which do not feature "return" for onvious reasons in forms other
than equalent to jump.

~~~
jemfinch
I'm talking about programmers, not computer scientists. That is, people who
actually accomplish things in the real world by hacking on software, rather
than pontificating about it from their monadic ivory towers :) The latter have
"abandoned statement-based languages," but the former _absolutely have not_.

~~~
stass
I don't see that distinction. The are languages designed to map directly to
register machines internal operation, like C or C++ or fortran and those are
statement based because that's how the machine works. There are also high
level languages, designed to express computation, and those are expression
based, again, beacause computation is inherently based on expessions. There
are other kinds of languages as well, for other purposes (relations, queries,
etc).

Do you really belive that only people working on low level register transfer
level things "accomplish things"? That's souds like a very old assembler
argument.:-)

------
joshuaellinger
Odd choice of examples...

1\. The file I/O makes the case for including exceptions in the language.
Specifically, adding one-off types to deal with exceptions is a bug, not a
feature. There is a good case against exceptions but that ain't it.

2\. On slide 5, it appears to show that you have to use a switch statement on
a generic to get polymorphism because the language doesn't support
overloading. Again, looks more like a bug than a feature.

Also, is the "break;" implicit in Go? At first glance, it looks like a coding
error.

~~~
bcgraham
W/r/t #2 - you're not familiar with Go but knew exactly what was going on.
That's totally a feature. The language was designed around exactly that kind
of reading.

"break;" is implicit in Go.

~~~
joshuaellinger
Sure, I spend a decade in C. It's not hard to read.

My only problem with using generics in this context is that you can't catch
type-conversion errors at compile time.

Seems like a step backwards with only downside. I get why exceptions are a
double-edge sword. I'm not clear on why undermining compile time type safety
is an feature.

~~~
smosher
> I'm not clear on why undermining compile time type safety is an feature.

I think this is what people will ultimately focus on when considering Go. Many
of the complaints are a product of type weaknesses in the language, voiced by
people who had assumed that a modern static language wouldn't have that fault.
Others tend not to mind because they lack that expectation, and regard the
dynamic behaviour you can get as a feature. The argument about shared mutable
state goes the same way, but for some concurrent but non-parallel code it
might be convenient.

I can easily see people picking Go when moving from Python. But not when
moving from a static language with a stronger, safer type system.

Also, as burntsushi points out, it does require more sophistication in the
type system. I doubt they're trying to sell a naively simplistic type system
(sophistication often makes it easier to use), but when Go was announced the
feature they seemed to be selling the hardest was short compilation times. I
think that feature is the seed of this behaviour.

------
ktt
Interesting that this snippet:

    
    
      func (g *Gopher) DumpBinary(w io.Writer) error {
        err := binary.Write(w, binary.LittleEndian, int32(len(g.Name)))
        if err != nil {
            return err
        }
        _, err = w.Write([]byte(g.Name))
        if err != nil {
            return err
        }
        err = binary.Write(w, binary.LittleEndian, g.Age)
        if err != nil {
            return err
        }
        return binary.Write(w, binary.LittleEndian, g.FurColor)
      }
    

could be written like this:

    
    
      func (g *Gopher) DumpBinary(w io.Writer) {
        binary.Write(w, binary.LittleEndian, int32(len(g.Name)))
        w.Write([]byte(g.Name))
        binary.Write(w, binary.LittleEndian, g.Age)
        binary.Write(w, binary.LittleEndian, g.FurColor)
      }
    

if the language supported exceptions.

~~~
shurcooL
If the language supported exceptions, how would you write this func?

    
    
      func (g *Gopher) DumpBinary(w io.Writer) {
        // Ignore all errors
        _ = binary.Write(w, binary.LittleEndian, int32(len(g.Name)))
        _, _ = w.Write([]byte(g.Name))
        _ = binary.Write(w, binary.LittleEndian, g.Age)
        _ = binary.Write(w, binary.LittleEndian, g.FurColor)
      }

~~~
dragonwriter
The language supports exceptions (panics). You could do something like (this
is untested code):

    
    
      func panicBinaryWrite(w io.Writer, b binary.ByteOrder, data interface{}) {
        if err := binary.Write(w, b, data); err != nil {
          panic("Error in binary.Write")
        }
        return
      }
    
      func panicWrite(w io.Writer, data interface{}) {
        if _,err := w.Write(binary.LittleEndian,data); err != nil {
          panic("Error in io.Writer#Write")
        }
        return 
      }
    
      func ignoreErrors(f func()) {
        defer func() { 
          _ = recover()
        }()
        f()
        return
      }
    
      func (g *Gopher) DumpBinary(w io.Writer) {
        // Ignore all errors
        ignoreErrors(panicBinaryWrite(w, binary.LittleEndian, int32(len(g.Name))))
        ignoreErrors(panicWrite([]byte(g.Name)))
        ignoreErrors(panicBinaryWrite(w, binary.LittleEndian, g.Age))
        ignoreErrors(binary.Write(w, binary.LittleEndian, g.FurColor))
      }

------
frou_dh
Something that doesn't sit right with me is the use of a "channel of bool"
when the receiving goroutine doesn't actually care whether true or false is
sent. It muddies the API to force the sender to choose one of two values when
all that's really wanted is an amorphous signal.

e.g. in
[http://talks.golang.org/2013/bestpractices.slide#25](http://talks.golang.org/2013/bestpractices.slide#25)
, the first case in the select will trip regardless of which value arrives,
yet the sender was still made to choose one.

~~~
shurcooL

      A channel may be closed with the built-in function close; the multi-valued
      assignment form of the receive operator tests whether a channel has been closed. [1]
    

Given that is available, why is the use of a separate bool quit channel
preferred?

[1]
[http://golang.org/ref/spec#Channel_types](http://golang.org/ref/spec#Channel_types)

~~~
frou_dh
In the link, the quit is acknowledged, so one side closing the channel
straight off the bat wouldn't allow for that.

------
hannibalhorn
The type cast as part of the switch is really cool, I hadn't seen that before.

    
    
        switch v := v.(type) {
        case string:
            w.Write(int32(len(v)))
            w.Write([]byte(v))
        default:
            w.err = binary.Write(w.w, binary.LittleEndian, v)
        }
    

Great way to alter control flow based on the type, without a ton of ugly casts
cluttering things up.

~~~
deskamess
Of all the code in there this part confused me. What exactly is being switched
on? It looks like v is being reassigned to the type of v, then the type of v
is written out (instead of the value).

~~~
gertef
"type" is a magic word in Go, and in that example. It's highly idiomatic --
it's inconsistent with the rest of the language (Using "type" instead of an
actual type), but it makes sense once you memorize the idiom. Sort of perlish
-- there are two different operations that look basically the same, and the
correct one is chosen based on context (in this case, the context is "is there
a type name, or "type" literally?)

Perhaps it would have been cleaner to use "*" or some other operator symbol
instead of the reserved word "type"

~~~
dragonwriter
> "type" is a magic word in Go, and in that example.

Specifically, type switches are a specific syntax construct that look very
similar to normal switches, but switched on something that _looks like_ a type
assertion with "type" in place of an actual type.

------
conroy
Meta comment: does anyone know what software is used to generate these slides?
I've seen a few slide decks in the same format and they're impossible to use
on mobile. I'd like to fix that

~~~
campoy
Hi,

I created these slides using code.google.com/p/go.talks You can actually find
the source code and the slides in it.

~~~
conroy
Thanks for the link. I'll take a look and see if I can make it work better on
mobile.

------
alec
"Deploy one-off utility types for simpler code" can be called a monad or
Optional. I wonder if the language developers will add more formal support for
that; it looks impossible to add Optional as a library due to lack of user-
configurable generics.

~~~
gertef
I'm sort of hoping someone forks Go to provide at least a few single-depth
generics like Optional/Maybe, to match Map and Slice.

~~~
rybosome
If it had been done at the very beginning, I think it would have been
wonderful...but given that legal, idiomatic nil is already out in the wild I
think it's too late. Such a shame - in the example of error handling,
returning an Option doesn't appreciably increase verbosity:

    
    
        _, err := potentiallyErroringOperation()
    
        // with idiomatic nil
        if err != nil {...}
    
        // with monadic Option
        if err.isDefined() {....}
    

EDIT: fix typo

------
jdmichal
Didn't read, because mouse scroll wheel doesn't work.

Honestly, who thinks this stuff is a good idea?

~~~
dragonwriter
> Didn't read, because mouse scroll wheel doesn't work.

You don't need the scroll wheel to navigate the presentation. Click on the
right side of the slide to go forward, on the left side to go back.

> Honestly, who thinks this stuff is a good idea?

People who are making presentations to deliver in an in-person setting where
putting them on the web for everyone is a secondary use, not the primary use?
I mean, looking at that, it would be a _lot_ better as the visual component of
an in-person presentation than it is on its own (though its not without value
on its own.)

~~~
freyr
Also, you can use the arrow keys to go back and forth through the slides.

~~~
buerkle
Yes all those options work. But why remove a common method of navigation? In
addition, the format makes it impossible to search for text within the
presentation.

~~~
mbell
Because it wasn't 'removed', rather it wasn't 'created'. You seem to be
missing that supporting this feature is extra work and not 'built in' to the
way the project is constructed. The author didn't sit there and say, well,
fuck the wheel, I'll just throw in a line of code here to disable it, just to
piss people off.

------
jamesaguilar
Thirteen: don't try to sort, it's going to be painful if you do.

[http://golang.org/pkg/sort/](http://golang.org/pkg/sort/) (See example 1 --
you have to write that for every concrete slice type you want to sort; it's
not enough to write it once. And god help you if you also want to sort other
collection types.)

~~~
gertef
Project Lombok for Go would be relative easy, and so nice.

~~~
jamesaguilar
Wow, that's magnificent, although I don't think Go's reflection capabilities
are quite sufficient to fix this particular language bug with decorators. But
maybe my imagination just isn't sufficient.

------
schoper
He starts dropping errors in "Type switch to handle special cases"

------
tomgagnier
Slide deck is good idea - but does not work with swipe on OS/X - a clue to
click on the right side would be nice.

~~~
millstone
The interface is quite bad. I was able to scroll right to see a total of three
slides, with no indication that there were any others. I thought that was the
end!

I tried hitting space, and another slide scrolled in! But I wasn't done
reading, so I hit shift-space, which is the common idiom to reverse the
direction of space. But it scrolled in the same direction. Now I'm two slides
behind. After some more thrashing, I found that I could use the arrow keys to
navigate. Delete also goes back.

Please don't make me use trial and error to figure out your UIs, Google!

------
workhere-io
UI best practice: Avoid horizontal scrolling.

------
rorrr2
Holy shit that function adapters example is convoluted. I'd say fewer than 5%
of my programmer coworkers would figure out what's going on.

    
    
        func init() {
            http.HandleFunc("/", errorHandler(betterHandler))
        }
    
        func errorHandler(f func(http.ResponseWriter, *http.Request) error) http.HandlerFunc {
            return func(w http.ResponseWriter, r *http.Request) {
                err := f(w, r)
                if err != nil {
                    http.Error(w, err.Error(), http.StatusInternalServerError)
                    log.Printf("handling %q: %v", r.RequestURI, err)
                }
            }
        }
    
        func betterHandler(w http.ResponseWriter, r *http.Request) error {
            if err := doThis(); err != nil {
                return fmt.Errorf("doing this: %v", err)
            }
    
            if err := doThat(); err != nil {
                return fmt.Errorf("doing that: %v", err)
            }
            return nil
        }

~~~
zeeboo
Less than 5% of your coworkers understand decorators? I don't want to sound
snooty but this is a pretty trivial application of higher order functions.

~~~
icebraining
I have to agree; it's basic stuff even for a Python weenie like me.

~~~
marssaxman
It's basic stuff _because_ you're a Python weenie; I don't see much use or
discussion of decorators outside the Python world.

~~~
dragonwriter
Decorators are a special Python syntax for this use, the more general term for
what is going on is "higher-order functions".

Which are pretty important, and not specific to python.

~~~
marssaxman
yes, of course, but the discussion I replied to was talking about this
specific idiom, this application of higher order functions, and not about the
use of higher order functions generally.

------
nine_k
If #6 is among best practices, I'm sad. I could take a dynamically-typed
language instead.

[http://talks.golang.org/2013/bestpractices.slide#6](http://talks.golang.org/2013/bestpractices.slide#6)

~~~
dscrd
They allow dynamically typed methods when you need them. Why does that make
you sad?

~~~
nine_k
Loss of strong typing and runtime type detection is what makes me sad.

Well, Go 1 has some of the problems of Java 1: no generics, typecasts from
interface{} here and there, simplistic GC. Reasons are probably similar: this
all is good enough for version 1, and can later be improved upon.

~~~
kristianp
"Well, Go 1 has some of the problems of Java 1: no generics, typecasts from
interface{} here and there, simplistic GC. Reasons are probably similar: this
all is good enough for version 1, and can later be improved upon."

Except I doubt we're going to see generics in Go version 2, whenever that may
be. The sentiment against it has been pretty strong in the golang-nuts mailing
list.

