Up to Main Index                            Up to Journal for August, 2013

                   JOURNAL FOR THURSDAY 22ND AUGUST, 2013
______________________________________________________________________________

SUBJECT: The epiphany - Communicate between packages using interfaces
   DATE: Thu 22 Aug 21:39:17 BST 2013

In my last journal entry I said I didn't think writing about the trials and
tribulations of coding on WolfMUD was a good idea. From the emails I got it
seems that I was wrong - people do want to read about the dead ends and
rewrites and false starts. It lets people see what it takes to create WolfMUD
and why sometimes it takes ages for code changes to appear. Having fresh code
suddenly appear 'fully formed' seems to be of less interest.

As one person put it "If you don't write about the ups and downs what are you
going to write about?". A good question indeed - not writing anything last
week was just a coincidental fluke. I'd been writing project proposals and
specifications for over a week and the last thing I wanted to do was write
even more :(

So now for all you gentle readers out there I will try to explain my epiphany.

In a nutshell the epiphany is: Communicate between packages using interfaces.

It's simple and when you think about it, maybe even quite obvious. Although in
all the reading I did - forum posts, documentation, source code and books - it
was barely even hinted at. Maybe it's so obvious that people just didn't think
to write about it? Or I simply just missed it somewhere?

Anyway, interfaces in Go are a lot more powerful than I initially assumed. If
you keep thinking OOP or try to refer to OOP concepts you probably wont
realise how powerful they are - which is what happened to me.

So how does "Communicate between packages using interfaces" help with WolfMUD
and larger Go projects in general? This is just my take and I've taken it a
little further than the original epiphany so any and all comments are welcome!


 1. I found it easier to avoid cyclic dependencies by putting interfaces into
    their own packages. Other packages can import other packages including
    interface packages but interface packages should only import other
    interface packages. I found this also makes the code less tightly coupled.

    For an example look at io/io.go


 2. If a method is exported it's parameters should be basic types - int,
    string, etc. - or an interface type. This again makes the code feel a lot
    lighter. All you need is an interface with just the methods needed by the
    method you are passing the parameter to. Quite often you are only calling
    one or two methods on a parameter and don't actually need to import the
    parameter's package - just a light interface with a few methods defined
    suffices. But see point 3 next.


 3. If a type is self contained in a package and can only be used by and
    manipulated by methods in that package then using that type as a parameter
    in an exported method should be fine as you are only passing it around.

    A good example of this seems to be bytes.Buffer.


 4. If a method can be defined in terms interfaces only - define it with the
    interfaces as a function. Remember, interfaces cannot be receivers so it
    needs to be a function.

    One example of many in io/io.go is WriteString


As I said this is my take on my epiphany and you can take it with a pinch of
salt[1]. As with any 'rules' there are also times when it might make sense to
break them. Following my own points above seems to be working well although I
have a lot of refactoring to do - at the moment nothing is working and I've
got compiler errors everywhere :(

If you do try using the points above I'd like to hear how it worked out for
you - good :) or bad :(

If I need to update or add to the points above I'll be sure to let everyone
know this time instead of holding back ;)

--
Diddymus

  [1] 'grain of salt' seems more common in the US?


  Up to Main Index                            Up to Journal for August, 2013