canonical pattern for transactional library state manipulation
Go does have a strong opinion on the use of mutexes vs. channels. In fact, the sync package states: "Other than the Once and WaitGroup types, most are intended for use by low-level library routines. Higher-level synchronization is better done via channels and communication." (See https://golang.org/pkg/sync/ )

This opinion clearly implies your first implementation is suboptimal. I agree, so I'm not going to even review that implementation.

The second implementation is more intriguing, it uses channels, but it's got issues.... and it's not a "canonical" example of what I would expect with a "communication" implementation for concurrency in Go.

The "Stateful" go-routine is one which only that single go-routine accesses, or modifies the state. All interaction with the state is done by communicating with that routine, and communication happens through channels.

You have one channel to communicate the request for accessing the state, and another for returning the response. This is a problem... The request channel command is OK, but the response channel is broken. If you have multiple concurrent commands issued, you won't be able to send the right response to the right command, and things will get mixed up.

The solution to this is to dedicate a channel for each command to get the responses on. Add the channel to the commandDoSomething struct, so that your code looks something like:

func (l *LibraryState) DoSomething(arg int) error {

    // dedicated response channel for communication (of error type, not interface{})
    resp := make(chan error, 1)

    // Perform operation transactionally
    l.command &lt;- commandDoSomething{arg, resp}
    res := &lt;-response
    return res
}


Now your state handler would look like:

func (l *LibraryState) reallyDoSomething(arg int, respondto chan&lt;- error) {

    defer close(respondto)

    // Do something
    fmt.Println("Hello, playground")
    var err error = nil
    respondto &lt;- err
}


and be called like:

for {
    switch c := (&lt;-l.command).(type) {

    case commandDoSomething:
        l.reallyDoSomething(c.arg, c.respondto)
    }
}


Note that you can remove the l.response channel completely.

Edit: Note that by dedicating a response channel for each command, you can do things like return the actual channel from the DoSomething function, like:

func (l *LibraryState) DoSomething(arg int) &lt;-chan error {

    // dedicated response channel for communication (of error type, not interface{})
    resp := make(chan error, 1)

    // Perform operation transactionally
    l.command &lt;- commandDoSomething{arg, resp}
    return resp
}


and as a consequence, "clients" can call the DoSomething method and then potentially do other work while the state is changing, and get the possible error condition later... like:

resp := DoSomething(input)
//... work on other activities
if err := &lt;-resp; err != nil {
    // handle error - perhaps undo some previous optimistic code....
}