Tuesday, April 27, 2010

JSON-RPC: a tale of interfaces

I'd like to share a recent instance where Go's interfaces made it easy to refactor some existing code to make it more flexible and extensible. Originally, the standard library's RPC package used a custom wire format called gob. For a particular application, we wanted to use JSON as an alternate wire format.

We first defined a pair of interfaces to describe the functionality of the existing wire format, one for the client, and one for the server (depicted below).

type ServerCodec interface {
    ReadRequestHeader(*Request) os.Error
    ReadRequestBody(interface{}) os.Error
    WriteResponse(*Response, interface{}) os.Error
    Close() os.Error
}


On the server side, we then changed two internal function signatures to accept the ServerCodec interface instead of our existing gob.Encoder. Here's one of them:

func sendResponse(sending *sync.Mutex, req *Request,
        reply interface{}, enc *gob.Encoder, errmsg string)


became

func sendResponse(sending *sync.Mutex, req *Request,
        reply interface{}, enc ServerCodec, errmsg string)


We then wrote a trivial gobServerCodec wrapper to reproduce the original functionality. From there it is simple to build a jsonServerCodec.

After some similar changes to the client side, this was the full extent of the work we needed to do on the RPC package. This whole exercise took about 20 minutes! After tidying up and testing the new code, the final changeset was submitted.

In an inheritance-oriented language like Java or C++, the obvious path would be to generalize the RPC class, and create JsonRPC and GobRPC subclasses. However, this approach becomes tricky if you want to make a further generalization orthogonal to that hierarchy. (For example, if you were to implement an alternate RPC standard.) In our Go package, we took a route that is both conceptually simpler and requires less code be written or changed.

A vital quality for any codebase is maintainability. As needs change, it is essential to adapt your code easily and cleanly, lest it become unwieldy to work with. We believe Go's lightweight, composition-oriented type system provides a means of structuring code that scales.

Tuesday, April 20, 2010

Third-party libraries: goprotobuf and beyond

On March 24, Rob Pike announced goprotobuf, the Go bindings of Google's data interchange format Protocol Buffers, called protobufs for short. With this announcement, Go joins C++, Java, and Python as languages providing official protobuf implementations. This marks an important milestone in enabling the interoperability between existing systems and those built in Go.

The goprotobuf project consists of two parts: a 'protocol compiler plugin' that generates Go source files that, once compiled, can access and manage protocol buffers; and a Go package that implements run-time support for encoding (marshaling), decoding (unmarshaling), and accessing protocol buffers.

To use goprotobuf, you first need to have both Go and protobuf installed. You can then install the 'proto' package with goinstall:

goinstall goprotobuf.googlecode.com/hg/proto

And then install the protobuf compiler plugin:

cd $GOROOT/src/pkg/goprotobuf.googlecode.com/hg/compiler
make install

For more detail see the project's README file.

This is one of a growing list of third-party Go projects. Since the announcement of goprotobuf, the X Go bindings have been spun off from the standard library to the x-go-binding project, and work has begun on a Freetype port, freetype-go. Other popular third-party projects include the lightweight web framework web.go, and the Go GTK bindings gtk-go.

We wish to encourage the development of other useful packages by the open source community. If you're working on something, don't keep it to yourself - let us know through our mailing list golang-nuts.