golang实践-目录结构与工具

这个话题确实是老调重弹,但确异常重要。
老实说,用go做正式项目之前,写过scala,但那个SBT太折磨人,偶然就上了go。两者语法的差别就不说了,但入坑之后才发现水深:没有模块部署及官方的版本管理工具,会带来很多麻烦。
反复折腾了近一年,基本上形成了一点固有的模式,做一般项目还算能够简单支持。没什么特别的技术点,更多只是一点心得。


一、目录结构

我们的代码以rpc为主,http为辅(调用rpc,也辅助测试),基本上一个项目就按照下面这个目录结构定制。

//project directory
--src  //源代码目录,需纳入vcs
    --package1
        --package1
            --main.go   //package1编译生成的执行文件源代码
        --othersubpackage
    --package2
        --package2
            --main.go  //这么摆放,是因为执行文件默认是[目录名]
        --othersubpackage
    --utils//公共的代码
    --vendor //第三方包目录,glide生成,可不纳入vcs
    glide.yaml  //glide生成的文件,需纳入vcs
    glide.lock  //glide生成的文件,需纳入vcs
--cfg //配置文件存放目录,需纳入vcs
    package1.yaml 
--pkg
--bin
compile.sh  //编译脚本
.bash_profile //工程环境

以上结构,适合于内部项目开发,按照项目进行统一采用glide进行管理。就版本管理工具有很多选择,考虑glide主要是:

  1. 简单,第一次用的时候半分钟搞定。只需要在src目录下,先后执行glide init、glide install;定期用一下glide up,自动升级第三方包。
  2. golang.org不再被墙之后,基本能一次性更新。
    但要特别注意,glide在使用的时候,对tag标签的规则有一定的要求,需要遵循 Semantic Versions 的规则。之前,个别知名的库不是很规范,经常在up的时候反而是老版本,但现在这种问题很少。
    安装glide也很简单,因为用的macos,所以brew install glide 就很容易搞定。
    当然,github上面很多也用godep,如果有精力,可以投入时间去熟悉、使用。

编译脚本
compile.sh是一个代码编译脚本,偶尔进行一下维护就好。

#清理
go clean all
#需要维护的包,只需要列出含有执行文件的包名
MYSERVICE=("package1" "package2")
#生成本地运行文件
 for SERVER in ${MYSERVICE[*]}
        do
        echo "正在编译服务$SERVER mac版"
        go install $SERVER/...
 done
#生成linux运行文件
 for SERVER in ${MYSERVICE[*]}
        do
        echo "正在编译服务$SERVER linux版"
       GOOS=linux GOARCH=amd64 go install $SERVER/...
 done

环境变量设置
.bash_profile是工程的环境变量设置。最初是为了避免不同项目在go get的时候,将该项目的包放入其他项目中【后来用了glide不存在这个问题,但这个习惯继续沿用】。我们采用不同项目的根目录下增加了这个文件。每次进相关项目的时候,加载一下即可。加载很简单:

source .bash_profile //或者
. .bash_profile

暂时该文件的内容很少,最核心的就是gopath的设置,这个将直接影响到go get的包存放地址。

export GOPATH=/Users/xx/dev/code/project

采用这个方式,如果要想不同项目用不同的go版本,也就easy了。

程序配置文件
项目实施过程中,除了用环境变量,先后用了ini、json、yaml三种格式文件作为程序的启动参数配置文件。
json做配置很简单,直接读即可。可以封装一个方法:

func ReadJson(filename string, def interface{}) error {
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        return fmt.Errorf("ReadJson failed: %T %v", def, err)
    }
    if err = json.Unmarshal(data, def); err != nil {
        return fmt.Errorf("ReadJson failed: %T %v %v", def, filename, err)
    }
    return nil
}

最大不足在于无法为配置写描述,这在使用的时候要配合第三方文档。

ini作为配置文件,其实很强悍,可以用第三方库config来调用,支持很全:

  • [x] 可以有备注
  • [x] 可以分章节
  • [x] 可以在值中用变量
  • [ ] idea对ini没有好的编写插件。

最终是因为用glide才开始了解yaml,发现作为配置文件,有很明显的优势:

  • 写作方式类似于ini,相对于json能备注,不用写括号
  • 支持数组,缩进表示内嵌struct
  • ide有yaml编写插件,能够简单的颜色、缩进显示。
  • 绝大部分go代码,都采用yaml,本来就有技术需要。
  • 包的支持不错gopkg.in/yaml.v2,使用简单。配置文件不正确情况下,只影响对应属性的赋值。从而可以用初始值对象,健壮性提升。
    这一点,可以补充一段代码来描述:
package main

import (
    "fmt"
    "gopkg.in/yaml.v2"
)

type T struct {
    F int `yaml:"a,omitempty"`
    B []string
    C int
    D float64
}

func main() {
    var t T
    t.D = 9                                                        //提供一个初始值,判定出错情况下是否改变
    err := yaml.Unmarshal([]byte("a: 1\nb: 12 \nc: 3 \nd: a"), &t) //输入条件中,b和d的值是错误的
    fmt.Println(err)
    fmt.Println(t)
    //output:
    //yaml: unmarshal errors:
    //line 2: cannot unmarshal !!int `12` into []string
    //line 4: cannot unmarshal !!str `a` into float64
    //{1 [] 3 9}   <--可以看出,a、c的识别没有错,t.D依然为原始值。
}

二、常用工具

IDE
对于基本没有专属开发工具的语言而言,go的开发环境反而百花齐放。我自己先后用过LiteIDE、subtext line 3 、atom、eclipse、idea。这几个工具各有特长

  • LiteIDE 功能单一,容易上手,适合新人。
  • Sublime Text 、atom 资源占用少,前者的秒开太无敌。团队中,曾经搞c++、c服务端的玩过。自己用惯IDE,不是很适应同一个语言要装n个插件。
  • eclipse,15年的时候很不错,每次修改代码都会自动build一次,很便于查找问题。但相对于前两者,对go语言没有特别亮点的额外支持。
  • idea,这是神器,除了coding,对yaml、json的维护,写js、sql等都方便(eclpise也有)。人无我有的重构,至今还是所向披靡。

由于工程中除了go,js、sql、yaml都有涉及,实际项目中都选择的IDE。16年开始,因为插件越来越成熟,问题处理及时(晚上提交bug,早上醒来就已经搞定),现在只用idea。只是,由于go的接口实现不用显示声明,它的shift+F6有点不够强悍。
人生苦短。对于有php、python开发经历的,直接选择idea,没必要折腾其他工具。

代码分析
作为还算新的语言,加上没有类似于lightbend这种商用公司,go的配套工具比较少。
平时,内部开发可用go vet、golint这两种辅助工具进行代码分析。虽然效果远远比不上sonar,但可以将就用。
如果在github上共享,则可以用[goreport card][5]网站,通过内嵌常用工具,以网页+链接方式给出语法警告,可当做sonar简化版。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值