First - I have a Node struct, which represents a network connection to a 
node.


type Node struct {
    *apiclient.Node
}
func (c *Node) GetStatus() (status *models.Status, err error)
func (c *Node) PostTransaction(signedEncodedTx, signedEncodedTxHash string) 
(err error)
func (c *Node) GetTopBlock() (kb *models.KeyBlockOrMicroBlockHeader, err 
error)
func (c *Node) GetHeight() (height uint64, err error)
func (c *Node) GetCurrentKeyBlock() (kb *models.KeyBlock, err error)
func (c *Node) GetAccount(accountID string) (account *models.Account, err 
error)
func (c *Node) GetNameEntryByName(name string) (nameEntry *models.NameEntry, 
err error)
func (c *Node) GetGenerationByHeight(height uint64) (g *models.Generation, 
err error)
func (c *Node) GetMicroBlockTransactionsByHash(microBlockID string) (txs *
models.GenericTxs, err error)
func (c *Node) GetMicroBlockHeaderByHash(microBlockID string) (txs *models.
MicroBlockHeader, err error)
func (c *Node) GetKeyBlockByHash(keyBlockID string) (txs *models.KeyBlock, 
err error)
func (c *Node) GetTransactionByHash(txHash string) (tx *models.
GenericSignedTx, err error)
func (c *Node) GetOracleByPubkey(pubkey string) (oracle *models.
RegisteredOracle, err error)
func (c *Node) GetOracleQueriesByPubkey(pubkey string) (oracleQueries *
models.OracleQueries, err error)
func (c *Node) GetContractByID(ctID string) (contract *models.ContractObject
, err error)


I want to be able to mock out the node's methods, so for every Node method, 
I make an interface.

type GetStatuser interface
type PostTransactioner interface
type GetTopBlocker interface
type GetHeighter interface
type GetAccounter interface
type GetNameEntryByNamer interface
type GetGenerationByHeighter interface
type GetMicroBlockTransactionsByHasher interface
type GetMicroBlockHeaderByHasher interface
type GetKeyBlockByHasher interface
type GetTransactionByHasher interface
type GetOracleByPubkeyer interface

Sometimes, I just need to return a Node instance. However, to make that 
code testable without an actual Node connection, I have to introduce this 
large interface, which is only used once.

type NodeInterface interface {
    GetAccounter
    GetTopBlocker
    GetStatuser
    GetHeighter
    GetKeyBlockByHasher
    GetOracleByPubkeyer
    GetGenerationByHeighter
    GetTransactionByHasher
    GetNameEntryByNamer
    GetMicroBlockHeaderByHasher
    GetMicroBlockTransactionsByHasher
    PostTransactioner
}





Some functions that build upon Node methods are used quite often, so I put 
them in a Helper struct to avoid having to specify the Node instance every 
time.

Again, to make code above independent from Helpers or an actual Node 
connection, I have to introduce a large interface.

type Helpers struct {
    Node GetHeightAccountNamer
}
func (h Helpers) GetTTL(offset uint64) (ttl uint64, err error)
func (h Helpers) GetNextNonce(accountID string) (nextNonce uint64, err error
)
func (h Helpers) GetTTLNonce(accountID string, offset uint64) (height uint64
, nonce uint64, err error)
func (h Helpers) getAnythingByName(name string, key string) (results []
string, err error)
func (h Helpers) GetAccountsByName(name string) (addresses []string, err 
error)
func (h Helpers) GetOraclesByName(name string) (oracleIDs []string, err 
error)
func (h Helpers) GetContractsByName(name string) (contracts []string, err 
error)
func (h Helpers) GetChannelsByName(name string) (channels []string, err 
error)
type HelpersInterface interface {
    GetTTL(offset uint64) (ttl uint64, err error)
    GetNextNonce(accountID string) (nextNonce uint64, err error)
    GetTTLNonce(accountID string, offset uint64) (height uint64, nonce 
uint64, err error)
    GetAccountsByName(name string) (addresses []string, err error)
    GetOraclesByName(name string) (oracleIDs []string, err error)
    GetContractsByName(name string) (contracts []string, err error)
    GetChannelsByName(name string) (channels []string, err error)
}




The functions that use the Helper struct are always executed in the context 
of a particular address and node, so I make a Context struct that combines 
Helpers and an Address.
// Context stores relevant context (node connection, account address) that 
one might not want to spell out each time one creates a transaction
type Context struct {
    Address string
    Helpers HelpersInterface
}
func (c *Context) SpendTx(senderID string, recipientID string, amount, fee 
big.Int, payload []byte) (tx SpendTx, err error)
func (c *Context) NamePreclaimTx(name string, fee big.Int) (tx 
NamePreclaimTx, nameSalt *big.Int, err error)
func (c *Context) NameClaimTx(name string, nameSalt big.Int, fee big.Int) (tx 
NameClaimTx, err error)
func (c *Context) NameUpdateTx(name string, targetAddress string) (tx 
NameUpdateTx, err error)
...





Problems:
1. After using the `Context` methods to create a Transaction, it is 
necessary to `node.BroadcastTransaction()`. However, because of 
`HelpersInterface`, the code above cannot access the underlying Node 
instance. 
So I either create a new Node above, or return one from `Context`'s 
constructor

func NewContextFromURL(url string, address string, debug bool) (ctx *Context
, node *Node)



which seems inelegant. 

Of course I could add 
Helpers.BroadcastTransaction()

but unlike the other helper methods, BroadcastTransaction() does not need 
any extra code around it.

2. After writing the question it seems like eliminating the Helpers struct 
will solve the problem. But I don't know if it is really THE solution, 
because I used the same pattern with NodeInterface, and sometimes I really 
do need to say that I will pass in a full-featured Node, so I have to have 
this large interface.

3. Somehow I feel like the whole idea of making code easier to write by 
putting frequently used variables into a class/struct (yes I know Go has no 
classes) and calling the methods of that struct is not how Go is supposed 
to be used, but I am not sure.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/3ee266e3-ccb4-401c-a754-addbda544349%40googlegroups.com.

Reply via email to