Client / Server Code Separation

I am developing a client / server application in golang, and there are certain logical entities that exist on both the client and the server (the list is limited)

I would like to ensure that certain code for these objects is included ONLY in the server side, but NOT in the client (a reasonable option is good, but not so important).

The naive thought was to rely on eliminating dead code, but from my brief research this is not a reliable way to cope with the task ... go build just will not eliminate dead code due to the fact that it may have been (no one cares that it was not, and there is no way to configure it)

A firmer approach, apparently, is the separating code in different packages and the corresponding import, which seems reliable, but unduly complicates the code, forcing you to physically separate certain objects between different packages and keep that in mind ...

And finally, there are build tags that allow you to have several files under the same package, created conditionally for the client and server

The motivation using build tags is that I want the code to be as clean as possible, without any synthetic objects

Use case: there are certain cryptography procedures, the client works with the public key, the server works with the private ... The code logically belongs to the same entity

Which option would you choose and why?

+1
go server client
source share
1 answer

This "dead code removal" has already been done - in part - by the go tool. The go tool does not include all of the imported packages, only what is needed (or, more precisely, eliminates things that might not be possible).

For example, this application

 package main; import _ "fmt"; func main() {} 

leads to a minimum executable binary of almost 300 KB (on amd64 windows) compared to the following:

 package main; import "fmt"; func main() {fmt.Println()} 

Exceptional things include functions, types, and not even exported and exported variables. This is possible because even with reflection, you cannot call a function or "instantiate" types or refer to package variables by simply having their names as a string value. So maybe you should not worry so much about it.

Edit: With the release of Go 1.7, this is even better: read the blog post: Smaller Go 1.7 binaries

So, if you design your types and functions well and you don’t create “giant” registries where you list functions and types (which explicitly generate references to them and therefore make them inactive), the compiled binaries will contain only what actually used from imported packages.

I would not suggest using build tags for this problem. Using them, you will be additionally responsible for maintaining dependencies between packages and files that are otherwise executed by the go tool.

You should not create and separate code from packages to make your executable files smaller. You must develop and split the code into packages based on logic.

I would like to divide things into packages when it is really necessary, and import accordingly. Because this is really what you want: some code intended only for the client, and only one for the server. You may have to think a bit at the design and coding stage, but at least you will see the result (what actually belongs / compiles to the client and server).

+2
source share

All Articles