[Journey with golang] 8. Project Management

本文介绍一些关于golang工程管理相关的东西。首先介绍golang一些重要的环境变量,有关golang的环境变量可以用以下命令查看: go env

  • $GOROOT:golang安装根目录。Linux下默认是/usr/lib/go。如果$GOROOT位于上述位置,则不需要显式设置该环境变量,反之需要设置。
  • $GOPATH:golang工作目录(workspace)。默认值为$HOME/go。
  • $GOBIN:是带有main函数的源程序执行 go install 时生成的可执行程序安装目录,默认是$GOPATH/bin。
  • $GOOS和$GOARCH:用于设置目标平台操作系统和目标平台CPU体系结构。这两个环境变量主要用在交叉编译中。
  • $GOPROXY:用于设置代理。部分go源码包会被墙,可以通过如下设置解决:

    1 # 此设置依赖go版本为1.11或以上
    2 # 打开.bashrc或其他shell配置文件
    3 export GO111MODULE=on
    4 export GOPROXY=https://goproxy.io

$GOPATH环境变量所指定的目录称为go的工作目录,$GOPATH可以配置多个目录,工作目录有相同的目录结构,包含src/pkg/bin三个子目录。

src是工程的源码所在目录,一般src下的第一层目录是工程根目录,工程根目录一般采用公司的域名+工程名或用户名的格式,比如常见的github上的工程源代码组织形式:

$GOPATH/src/github.com/github/
$GOPATH/src/github.com/golang/

工程根目录下才是工程各个项目的目录,项目目录下可以是其源代码文件和各种包的源码,这是一种推荐的代码组织形式。举个例子:$GOPATH/src/github.com/github/go-ost。$GOPATH/src/github.com/github/是github工程根目录,go-ost是具体的项目目录,gh-ost内是该项目的源代码和包。

$GOPATH环境变量可以配置多个目录,使用go get下载第三方的包时,默认会将包下载到$GOPATH的第一个目录里面,很多人喜欢在$GOPATH里配置两个目录,第一个专门用于下载第三方包,第二个目录用于内部工程目录,但官方推荐的做法是只配置一个目录,通过dep来管理。

下面介绍golang的交叉编译方法。golang对交叉编译有很好的支持,唯一的不足是不支持CGO。在go1.4及以前版本中,由于编译器是使用C语言写的,交叉编译比较麻烦,先要在当前平台构建一个目标平台的编译环境,然后才能通过设置$GOOS和$GOARCH进行交叉编译。golang编译工具在1.5及以后版本中完全使用golang重写,golang编译器内置交叉编译的功能,只需要设置$GOOS和$GOARCH就可以进行交叉编译。下面看一个具体示例:

 1 package main
 2
 3 import (
 4     "fmt"
 5     "runtime"
 6 )
 7
 8 func main() {
 9     fmt.Printf("OS: %s\nArchitecture: %s\n", runtime.GOOS, runtime.GOARCH)
10 }

打开终端,执行 CGO_ENABLED=0 GOGOS=linux GOARCH=amd64 go build ./main.go 即可编译。

下面介绍命名空间(namespace)。命名空间在编程语言中常用来表示标识符(identifier)的可见范围。编程语言借助命名空间来解决标识符不能同名的问题,命名空间实际上相当于给标识符添加了标识前缀,使标识符变得全局唯一。另外,命名空间使程序组织更加模块化,降低了程序内部的耦合性。

一个标识符可在多个命名空间中定义,它在不同命名空间中的含义的互不相干的。在一个新的命名空间中可定义任意的标识符,它们不会与位于其他命名空间上的同名标识符发生冲突,当然自定义标识符尽量不要使用语言自身的关键字,这些标识符具有全局作用域。golang继承了命名空间的概念,采用包来组织代码,包名构成go命名空间的一部分,不同的包就是一个独立的命名空间。golang除了包级别显式的命名空间,还有隐式的命名空间。函数、方法、以及if、for、switch等和“{}”一起构成一个个代码块,代码块可以嵌套,每个代码块都构成一个隐式的命名空间。不同命名空间可以声明相同的标识符,所以不同的隐式的命名空间同样允许声明相同的标识符(包括变量),这里就有变量覆盖的问题。在介绍变量覆盖之前,先介绍作用域。

在高级语言编程中,作用域(scope)是指名字与实体(可以理解为特定内存地址)的绑定保持有效的那部分程序逻辑区间。golang是静态作用域的语言。所谓静态作用域就是变量的作用域不依赖程序执行时的因素,变量作用域在编译期就能确定。

golang有三种类型作用域:

  • 全局作用域:在任何地方都可以访问的标识符,称其具有全局作用域。在golang中,全局作用域有两类:

    • golang内置的预声明标识符(包括预声明的类型名、关键字、内置函数等),它们具有全局作用域,在任意命名空间内都可见
    • golang包内以大写字母开头的标识符(包括变量、常量、函数和方法名、自定义类型、结构字段等),它们具有全局作用域,在任意命名空间内都可见
  • 包内作用域:在golang包内定义的以小写字母开头的标识符(变量、常量、函数和方法名、自定义类型、结构字段等),它们在本包可见,在其他包都是不可见的,这些标识符具有包内作用域
  • 隐式作用域:每个代码块内定义的变量称为“局部变量”,这些局部变量只在当前代码块内可见,其作用域属于当前代码块的隐式作用域

golang编译器解析变量名到引用实体采用的是从里到外的搜索模式,里层的局部变量能够覆盖外层变量,使得外层的同名变量不可见,这种现象称为变量覆盖。

golang是使用包来组织源代码,并实现命名空间的管理。任何源代码文件必须属于某个包。源码文件第一行必须是package packageName,通过该语句声明自己所在的包。golang的包借助了目录树的组织形式,一般包的名称就是其源文件所在目录的名称,虽然golang没有限制包名必须和其所在目录名同名,但还是建议同名,这样结构更清晰。包可以定义在很深的目录中,包的定义是不包括目录名称的,但是包的引用一般是全路径引用。

标准包的源码位于$GOROOT/src/下面,标准包可以直接引用。自定义的包和第三方包的源码必须放到$GOPATH/src/目录下才能被引用。包引用路径有两种写法,一种是全路径,另一种是相对路径。全路径就是“$GOROOT/src/和$GOPATH/src/”后面包的源码的全路径。相对路径只能用于引用$GOPATH下的包,标准包的引用只能使用全路径引用。

包引用有四种引用格式,以fmt标准库为例:

  • 标准引用格式: import "fmt" 。此时可以用“fmt”作为前缀引用包内可导出元素
  • 别名引用格式: import F "fmt" 。此时相当于给包“fmt”起了个别名F
  • 省略引用格式: import . "fmt" 。此时相当于把包fmt的命名空间直接合并到当前程序的命名空间中,不再需要前缀“fmt”
  • 仅执行包初始化函数init: import _ "fmt" 。使用标准格式引用包,但代码中却没有使用包,编译器会报错。如果包中有init初始化函数,则通过此种方式引用包,仅执行初始化函数。即使包没有init初始化函数,编译器也不会报错。注意:一个包可以有多个init函数,包加载会执行完所有的init函数,但不保证执行顺序,所以不建议在一个包内放入多个init函数;包不能出现环形引用,否则编译不能通过,但包的重复引用是允许的,被重复引用的包会被保证只执行一次init函数

golang包的初始化有以下特点:

  1. 包初始化程序从main函数引用的包开始,逐级查找包的引用,直到找到没有引用其他包的包,最终生成一个包引用的DAG
  2. golang编译器会将DAG转化为一棵树,然后从树的叶子节点开始逐层向上对包进行初始化
  3. 单个包的初始化过程是,先初始化常量,再初始化全局变量,最后才是init函数

golang的版本管理直到go1.5引入vendor才有。vecdor机制就是包中引入vecdor目录,将依赖的外部包复制到vecdor目录下,编译器在查找外部依赖包时,优先在vecdor目录下查找。整个查找第三方包的流程如下:

  1. 如果当前包下有vecdor目录,则从其下查找第三方包
  2. 如果当前包下没有vecdor目录,则沿当前包目录向上逐级查找vendor目录,直到找到$GOPATH/src/下的vendor目录,只要找到vendor目录就去其下查找第三方包
  3. 在$GOPARH下寻找第三方包
  4. 在$GOROOT下寻找第三方包

vecdor将原来放在$GOPATH/src/的第三方包放到当前工程的vecdor目录中进行管理。它为工程独立的管理自己依赖的第三方包提供了保证,多个工程独立地管理自己的第三方依赖包,它们之间不会相互影响。vecdor将原来包共享模式转换为每个工程独立维护的模式,vendor的另一个好处是保证了工程目录下代码的完整性,将工程代码复制到其他go编译环境,不需要再去下载第三方包,直接就能编译,这种隔离和解耦的设计思路是一大进步。

然而vendor有一个重要的问题没有解决,那就是对外部依赖的第三方包的版本管理。通常使用go get -u更新第三方包。默认的是将工程的默认分支的最新版本拉取到本地,并不能指定第三方包的版本。go官方的包依赖管理工具dep就是为了解决该问题而出现的,与此同时社区也有很多包管理工具,如godep、govendor、glide等。目前dep并不会取代go get,go get只是一个便捷的方式。

建议使用以下方式安装dep:

curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh

如果需要,请使用proxychains(笔者就是这么做的)。

使用dep init命令初始化工程,该命令可以用于新项目,也可以用于已存在的项目。该命令会在当前目录创建三个文件: Gopkg.toml Gopkg.lock vecdor 。dep通过两个元文件来管理依赖:manifest文件Gopkg.toml和lock文件Gopkg.lock。Gopkg.toml可以由用户自由配置,包括依赖的source、branch、version等。Gopkg.lock仅描述工程当前第三方包版本视图。Gopkg.toml可以通过命令产生,也可以被用户手动修改;Gopkg.lock是自动生成的,不可以手动修改;vendor目录下存放具体依赖的外部代码。

dep init会做如下的事情:

  • 检查是否有其他版本的依赖管理工具,如果有则尝试转换
  • 检查是否已经用dep管理了,如果有则退出
  • 如果本地有vendor目录,则备份之
  • 分析工程源码,分析生成外部依赖包列表
  • 下载依赖包到$GOPATH/pkg/dep/sources下,切换到每个依赖包的最高兼容版本
  • 生成Gopkg.toml和Gopkg.lock源信息文件
  • 复制最高依赖版本的代码到工程的vendor目录下

下面来看一下Gopkg.toml的几个配置项。

[[constraint]]:指定直接依赖的包的相关元信息,是用户重点维护的信息,其格式为:

[[constraint]]
   name = "github.com/user/project"
   version = "1.0.0"
[[constraint]]
   name = "github.com/user/project2"
   branch = "dev"
   source = "github.com/myfork/project2"

[[constraint]]必须指定依赖包的如下属性中的一个:version(相当于git中的tag)、branch、revision(相当于git中的commit)、source(备选仓库源)

[[override]]:强制设置包的版本元信息,既可用于直接依赖,也可用于间接依赖。通过override声明的包信息会覆盖所有constraint声明的包信息,在实际工程中尽量避免使用override管理依赖包

constraints和overrides被用户用来指定依赖包的哪些版本是需要管理的,以及从哪里获取该版本的包。required和ignored被用来控制哪些包纳入管理,哪些被忽略。

dep的整个工作流如下:

  • 首次初始化运行dep init,dep自动分析并构建Gopkg.toml和Gopkg.lock,默认的是拉取依赖包的最新版本
  • 后续工程开发中可以手动编辑Gopkg.toml来调整依赖,通过运行dep ensure更新Gopkg.lock和vendor的依赖包源码
  • 要保证Gopkg.toml、Gopkg.lock和vendor下的代码一致

原文地址:https://www.cnblogs.com/JHSeng/p/12250615.html

时间: 2024-10-07 05:54:38

[Journey with golang] 8. Project Management的相关文章

Project Management: 敏捷开发纵横谈

摘要:在IT界中,“敏捷”是一个很酷的词汇,“敏捷”的相关理论可谓铺天盖地.“敏捷”一词实质没有统一定义,各家有自家的说法,本教程将让你了解“敏捷”的来龙去脉,抓住“敏捷”本质,并能在工作中实践“敏捷”. 特别声明:如需转载此文,请给出指向本网站的连接,如下:作者:张传波摘自:http://www.umlonline.cn如不能按此要求,请不要转载此文. 大纲:“敏捷”陷阱为什么会有“敏捷”这个说法?极限编程敏捷开发RUP敏捷开发的实质是什么?如何才能敏捷起来? 正文: “敏捷”陷阱 小甲想到某

Managing Human Factors in IT Project Management

Managing Human Factors in IT Project Management James Graham, PMP Ta' l-Ibrag, Malta AS SoFTWARE PRojECT MAnAgERS, we obsess over the schedule details. We huddle with our teammates to try to anticipate risk factors that could derail our projects. We

Project Management: 挣值管理不是搞数字游戏

摘要:要考PMP(Project Management Professional ),挣值管理是必考的知识.软件项目有很大的特殊性,不少人认为挣值管理不太适用于软件项目.挣值管理相关资料也比较超多,但一般都难以读懂,本文将会以轻松.易懂.实用的角度为你讲解. 大纲:1.挣值管理无用论2.从搬石头的故事说起3.三大基本要素:PV,AC,EV4.成本偏差(CV),进度偏差(SV)5.成本指标(CPI),进度指标(SPI)6.成本预测(EAC)7.挣值管理不是搞数字游戏,要让挣值管理实用! 特别声明:

The Simplified Project Management Process

One of the challenges of explaining project management to people who are unfamiliar with the approach, is that descriptions are often either so high-level as to be meaningless, or so detailed that they are overwhelming. Over the years, I have come to

Introduction to Project Management(II)

Introduction The purpose of this paper is to gain an understanding of project management and to give a brief overview of the methodology that underpins most formally run projects. Many organisations do not employ full time Project Managers and it is

Project Management Process

Project Management ProcessDescription .......................................................................................................................................................................................1STAGE/STEP/TASK SUMMARY LIST

Introduction to Project Management

Project management in the modern sense began in the early 1950s, although it has its roots further back in the latter years of the 19th century. The driver for project management was businesses realising the benefits of organising work around project

Software Engineering: 2. Project management

resources:"Software Engineering" Ian Sommerville For most projects, important goals are: Deliver the software to customer at the agreed time. Keep overall costs within budget. Deliver software that meets the customer's expections. Maintain a hap

Project management and planning

no.14 Wx D3 As an engineering student,  I often have to deal with projects. Today, I will make some conclusion from what I’ve experienced. Task definition manual Task and purpose are  foremost at the whole project. A clear description of project, wil