Why a network connection becoming writable when it succeeds makes sense
When I talked about how Go deals with canceling network connection attempts, I mentioned that it's common for the underlying operating system to signal you that a TCP connection (or more generally a network connection) has been successfully made by letting it become writable. On the surface this sounds odd, and to some degree it is, but it also falls out of what the operating system knows about a network connection before and after it's made. Also, in practice there is a certain amount of history tied up in this particular interface.
If we start out thinking about being told about events, we can ask what events you would see when a TCP connection finishes the three way handshake and becomes established. The connection is now established (one event), and you can generally now send data to the remote end, but usually there's no data from the remote end to receive so you would not get an event for that. So we would expect a 'connection is established' event and a 'you can send data' event. If we want a more compact encoding of events, it's quite tempting to merge these two together into one event and say that a new TCP connection becoming writable is a sign that its three way handshake has now completed.
(And you certainly wouldn't expect to see a 'you can send data' event before the three way handshake finishes.)
The history is that a lot of the fundamental API of asynchronous network
IO comes from BSD Unix and spread from there (even to non-Unix systems,
for various reasons). BSD Unix did not use a more complex 'stream of
events' API to communicate information from the kernel to your program;
instead it used simple and easy to implement kernel APIs (because this
was the early 1980s). The BSD Unix API was
select(), which passes
information back and forth using bitmaps; one bitmap for sending data,
one bitmap for receiving data, and one bitmap for 'exceptions' (whatever
they are). In this API, the simplest way for the kernel to tell programs
that the three way handshake has finished is to set the relevant bit
in the 'you can send data' bitmap. The kernel's got to set that bit
anyway, and if it sets that bit and also sets a bit in the 'exceptions'
bitmap it needs to do more work (and so will programs; in fact some of
them will just rely on the writability signal, because it's simpler for
Once you're doing this for TCP connections, it generally makes sense for all connections regardless of type. There are likely to be very few stream connection types where it makes sense to signal that you can now send (more) data partway through the connection being established, and that's the only case where this use of signaling writability gets in the way.