github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/doc/articles/json_rpc_tale_of_interfaces.html (about)

     1  <!--{
     2  "Title": "JSON-RPC: a tale of interfaces"
     3  }-->
     4  
     5  <p>
     6  Here we present an example where Go's
     7  <a href="/doc/effective_go.html#interfaces_and_types">interfaces</a> made it
     8  easy to refactor some existing code to make it more flexible and extensible.
     9  Originally, the standard library's <a href="/pkg/net/rpc/">RPC package</a> used
    10  a custom wire format called <a href="/pkg/encoding/gob/">gob</a>. For a
    11  particular application, we wanted to use <a href="/pkg/encoding/json/">JSON</a>
    12  as an alternate wire format.
    13  </p>
    14  
    15  <p>
    16  We first defined a pair of interfaces to describe the functionality of the
    17  existing wire format, one for the client, and one for the server (depicted
    18  below).
    19  </p>
    20  
    21  <pre>
    22  type ServerCodec interface {
    23  	ReadRequestHeader(*Request) error
    24  	ReadRequestBody(interface{}) error
    25  	WriteResponse(*Response, interface{}) error
    26  	Close() error
    27  }
    28  </pre>
    29  
    30  <p>
    31  On the server side, we then changed two internal function signatures to accept
    32  the <code>ServerCodec</code> interface instead of our existing
    33  <code>gob.Encoder</code>. Here's one of them:
    34  </p>
    35  
    36  <pre>
    37  func sendResponse(sending *sync.Mutex, req *Request,
    38  	reply interface{}, enc *gob.Encoder, errmsg string)
    39  </pre>
    40  
    41  <p>
    42  became
    43  </p>
    44  
    45  <pre>
    46  func sendResponse(sending *sync.Mutex, req *Request,
    47  		reply interface{}, enc ServerCodec, errmsg string)
    48  </pre>
    49  
    50  <p>
    51  We then wrote a trivial <code>gobServerCodec</code> wrapper to reproduce the
    52  original functionality. From there it is simple to build a
    53  <code>jsonServerCodec</code>.
    54  </p>
    55  
    56  <p>
    57  After some similar changes to the client side, this was the full extent of the
    58  work we needed to do on the RPC package. This whole exercise took about 20
    59  minutes! After tidying up and testing the new code, the
    60  <a href="http://code.google.com/p/go/source/diff?spec=svn9daf796ebf1cae97b2fcf760a4ab682f1f063f29&amp;r=9daf796ebf1cae97b2fcf760a4ab682f1f063f29&amp;format=side&amp;path=/src/pkg/rpc/server.go">final changeset</a>
    61  was submitted.
    62  </p>
    63  
    64  <p>
    65  In an inheritance-oriented language like Java or C++, the obvious path would be
    66  to generalize the RPC class, and create JsonRPC and GobRPC subclasses. However,
    67  this approach becomes tricky if you want to make a further generalization
    68  orthogonal to that hierarchy. (For example, if you were to implement an
    69  alternate RPC standard). In our Go package, we took a route that is both
    70  conceptually simpler and requires less code be written or changed.
    71  </p>
    72  
    73  <p>
    74  A vital quality for any codebase is maintainability. As needs change, it is
    75  essential to adapt your code easily and cleanly, lest it become unwieldy to work
    76  with. We believe Go's lightweight, composition-oriented type system provides a
    77  means of structuring code that scales.
    78  </p>