【问题标题】:Splitting client/server code拆分客户端/服务器代码
【发布时间】:2016-08-10 13:36:01
【问题描述】:

我正在用 golang 开发一个客户端/服务器应用程序,并且客户端和服务器上都存在某些逻辑实体(列表有限)

我想确保此实体的某些代码仅包含在服务器部分中,而不包含在客户端中(反之亦然很好,但不是那么重要)。

天真的想法是依赖死代码消除,但根据我的简短研究,这不是处理任务的可靠方法...go build 根本不会消除死代码,因为它可能是通过反射使用(没有人关心它不是,也没有选项可以调整它)

更可靠的方法似乎是将代码拆分到不同的包中并适当地导入,这似乎可靠但过度复杂的代码迫使您在不同的包之间物理拆分某些实体并始终牢记这一点...

最后还有构建标签允许在同一个包下为客户端和服务器有条件地构建多个文件

使用构建标签的动机是我希望在不引入任何合成实体的情况下保持代码尽可能干净

用例: 有一定的密码学例程,客户端使用公钥,服务器使用私钥操作......代码逻辑上属于同一个实体

你会选择什么选项,为什么?

【问题讨论】:

    标签: go server client


    【解决方案1】:

    这种“死代码消除”已经部分地由 go 工具完成。 go 工具不包含导入包中的所有内容,仅包含需要的内容(或更准确地说:它排除了可以证明无法访问的内容)。

    例如这个应用程序

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

    与以下相比,可执行二进制文件(在 windows amd64 上)小了近 300KB:

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

    排他性的东西包括函数、类型,甚至是未导出和导出的变量。这是可能的,因为即使使用反射,您也无法调用函数或“实例化”类型或仅通过将包变量的名称作为 string 值来引用包变量。所以也许你不应该那么担心。

    编辑:随着 Go 1.7 的发布,它变得更好了:阅读博文:Smaller Go 1.7 binaries

    因此,如果您设计好您的类型和函数,并且您没有创建枚举函数和类型的“巨大”注册表(显式生成对它们的引用并因此使它们不可排除),编译的二进制文件将只包含从导入的包中实际使用。

    我不建议对此类问题使用构建标签。通过使用它们,您将有额外的责任自己维护包/文件依赖项,否则由 go 工具完成。

    您不应该将代码设计和分离到包中以使您的输出可执行文件更小。您应该根据逻辑设计和分离代码包。

    我会在真正需要的时候将东西分成包,并适当地导入。因为这确实是您想要的:一些代码仅用于客户端,一些仅用于服务器。在设计和编码阶段您可能需要多考虑一些,但至少您会看到结果(实际属于/编译到客户端和服务器中的内容)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-22
      • 1970-01-01
      • 2019-08-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多