『No14: Go 工程管理』

go-14.png
14.png

大家好,我叫谢伟,是一名程序员。

最近比较低效...

今天的主题:工程管理

为了写出这一章节,我翻阅了几本书。书中整理的很好,但对初学者不太友好,意思是可能看完就知道个大概。还是不能理解工程管理的具体做法是什么。所以,我呢,摒弃了书中的组织方式,转而使用示例的形式,从头到尾的把工程管理这事说明白。但是考虑到实际中的使用可能不太会事无巨细。希望大家理解。

工程管理主要包括这两方面内容:Go 命令行工具的使用、工程项目的组织

当然,我们这边使用一个例子来演示:爬虫。

两首页的标题信息抓取下来。

主要的概况如下:

  • 项目的组织
  • 项目库第三方库下载 go get / gopm get -g
  • 编写代码
  • 测试 go test
  • 覆盖率 go tool
  • 编译 go build
  • 编译并运行 go run
  • 编译并生成二进制文件 go install
  • 包管理 govendor / vgo
  • 文档 godoc

整体的流程,大致和我们的开发息息相关。


1. 项目组织

我们第一节已经见过,我们的工程是如何进行组织的?

1、 设置 GOPATH
2、 GOPATH 下设置三个文件夹:bin、pkg、src

工程的组织即在src 目录下创建文件夹。

比如:这个专题所有的项目都组织在 src/go-example-for-live 目录下

├─go-example-for-live
│  ├─eight
│  ├─eleven
│  │  ├─infra
│  │  └─main
│  ├─fifteen
│  │  ├─download
│  │  ├─engine
│  │  ├─main
│  │  └─parse
│  │      ├─jianshu
│  │      └─v2ex
│  ├─five
│  ├─four
│  ├─fourteen_client
│  │  └─main
│  ├─fourteen_server
│  │  ├─main
│  │  └─ui
│  │      └─api-server
│  ├─Image
│  ├─MarkDown
│  ├─nine
│  │  ├─domain
│  │  ├─download
│  │  ├─engine
│  │  ├─infra
│  │  ├─main
│  │  ├─parse
│  │  │  └─gocn
│  │  ├─static
│  │  │  ├─css
│  │  │  ├─html
│  │  │  └─js
│  │  └─ui
│  │      ├─api-server
│  │      └─parse
│  ├─PowerPoint
│  ├─restful
│  ├─second
│  ├─seven
│  │  ├─download
│  │  ├─engine
│  │  ├─infra
│  │  ├─main
│  │  └─parse
│  │      └─github
│  ├─six
│  ├─ten
│  │  ├─app
│  │  ├─config
│  │  │  └─user-cfg
│  │  ├─ConfigResume
│  │  │  ├─1
│  │  │  │  └─Resume
│  │  │  └─2
│  │  │      └─Resume
│  │  ├─domain
│  │  │  ├─constants
│  │  │  ├─objects
│  │  │  └─roles
│  │  ├─infra
│  │  │  └─golang
│  │  │      ├─execadapter
│  │  │      ├─ioutiladapter
│  │  │      ├─jsonadapter
│  │  │      ├─osadapater
│  │  │      │  └─xiewei
│  │  │      └─yamladapter
│  │  ├─main
│  │  ├─ui
│  │  │  └─service
│  │  └─vendor
│  │      ├─github.com
│  │      │  └─olebedev
│  │      │      └─config
│  │      └─gopkg.in
│  │          └─yaml.v2
│  ├─thirteen
│  │  ├─infra
│  │  └─main
│  ├─three
│  ├─twelve
│  │  └─main
│  └─vendor
│      └─github.com
│          └─urfave
│              └─cli

工程组织...

2. 获取第三方库

  • go get
  • gopm get

如果我们使用内置库呢,编写代码的使用,直接import 库路径即可。这个路径是在设置的GOROOT 下的 src 目录下的库。

GOROOT=D:\1_System\2_Installation\G_go

D:\1_System\2_Installation\G_go\src

Make.dist         bootstrap.bash  clean.bat  context   expvar  image         make.bash      nacltest.bash  race.bat  runtime  testing
all.bash          bufio           clean.rc   crypto    flag    index         make.bat       net            reflect   sort     text
all.bat           buildall.bash   cmd        database  fmt     internal      make.rc        os             regexp    strconv  time
all.rc            builtin         cmp.bash   debug     go      io            math           path           run.bash  strings  unicode
androidtest.bash  bytes           compress   encoding  hash    iostest.bash  mime           plugin         run.bat   sync     unsafe
archive           clean.bash      container  errors    html    log           naclmake.bash  race.bash      run.rc    syscall  vendor

那获取第三方库呢,我们之前已经讲过,使用 go 的命令行工具即可:

go get ****

比如, 我们爬虫借助了第三方库:

go get github.com/PuerkitoBio/goquery

如果下载速度太慢呢,我们可以使用这个工具,gopm。

首先它也是go 的一个第三库,首先需要下载 gopm

go get -u github.com/gpmgo/gopm

再使用 gopm 下载

gopm get ****

一个字:快

3. 编写代码和测试

  • download
  • parse
  • engine
  • main

好,经历前面的学习,项目组织会了,下载第三方库也会了。就差会写代码了。

首先我们分析下需求:抓取信息。

  • 获取网页信息:http 请求,返回信息
  • 解析需要的信息:正则、xpath、css 等获取网页字段

核心大概就这两点,便可以完成任务。但是我还是建议新手,在写代码之前都能有一套好的项目的组织。

好的项目组织有什么好处呢?

可以参看下这个视频:https://www.youtube.com/watch?v=MzTcsI6tn-0

我提几点:

1、养成好的项目组织风格
2、更好的写代码
3、更好的理解(读)代码

经过上文的分析:我们项目组织成这样(之前的文章也提到过):

下载器:即获取网页源代码

download
   download.go
   download_test.go
package download

import (
    "errors"
    "net/http"

    "github.com/PuerkitoBio/goquery"
)

var (
    ErrRequest  = errors.New("request error")
    ErrResponse = errors.New("response error")
)

func GetHtmlResponse(url string) (*goquery.Document, error) {
    var (
        request *http.Request
        err     error
    )
    request, err = http.NewRequest("GET", url, nil)
    if err != nil {
        return nil, ErrRequest
    }

    request.Header.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36")

    var client *http.Client
    client = http.DefaultClient

    var response *http.Response
    response, err = client.Do(request)
    if err != nil {
        return nil, ErrResponse
    }

    defer response.Body.Close()
    return goquery.NewDocumentFromReader(response.Body)
}


解析器:即解析网页信息

parse
   v2ex
       job_parse.go
       job_parse_test.go
    jianshu
       info_parse.go
       info_parse_test.go
package v2ex

import (
    "github.com/PuerkitoBio/goquery"
)

func JobParse(response *goquery.Document) []string {

    var title []string

    response.Find("div#Main div.box div.cell.item").Each(func(i int, selection *goquery.Selection) {
        text := selection.Find("table tbody tr td").Eq(2).Find("span a").Text()
        //fmt.Println(text)
        title = append(title, text)
    })
    return title
}

调度器:即调度下载器和解析器,完成指定的网页信息的解析

engine
   engine.go
   engine_test.go
package engine

import (
    "go-example-for-live/fifteen/download"

    "errors"
    "fmt"

    "github.com/PuerkitoBio/goquery"
)

type Request struct {
    Url       string
    ParseFunc func(*goquery.Document) []string
}

type Requests []Request

var (
    ErrDownload = errors.New("download err")
)

func Run(seeds ...Request) {
    var requests Requests
    for _, seed := range seeds {
        requests = append(requests, seed)
    }

    for len(requests) > 0 {
        r := requests[0]
        requests = requests[1:]

        body, err := download.GetHtmlResponse(r.Url)
        if err != nil {
            fmt.Println(ErrDownload)
            continue
        }
        fmt.Println(r.ParseFunc(body))

    }

}

程序入口:main.go

main
   main.go
package main

import (
    "go-example-for-live/fifteen/engine"
    "go-example-for-live/fifteen/parse/jianshu"
    "go-example-for-live/fifteen/parse/v2ex"
)

func main() {
    engine.Run(
        engine.Request{
            Url:       "https://www.v2ex.com/?tab=jobs",
            ParseFunc: v2ex.JobParse,
        },
        engine.Request{
            Url:       "https://www.jianshu.com/u/58f0817209aa",
            ParseFunc: jianshu.InfoParse,
        },
    )
}

单元测试,我们不详细列举了。可以使用传统的方法也可以使用表格驱动法,也可以使用第三方库 GoConvey.

4. 运行相关

  • go fmt
  • go build
  • go install
  • go run
  • go test
  • go tool

1、优化代码

go fmt ****
  • 调整语句位置
  • 调整缩进
  • 调整花括号的位置
  • 调整空格等

2、构建
好,在上文我们编写完代码和测试用例之后,我们如何把程序分发出去给别人使用的呢?

go build

go build ****

根据库的名称自动编译出符合平台的二进制文件。

比如 在 main 目录下

go build 

则目录下自动生存 main.exe 文件。运行即可。

main.exe

[应届生在深圳找不到工作求职DeweyLiuwinglight2016 [杭州][可远程] 一只公司招聘前端...

go install

如何你设置了GOBIN ,即GOPATH 目录下的bin 文件夹。

则运行该命令,自动会在 GOBIN 目录下编译出同文件的二进制文件

# GOBIN
main.exe

go run

编译后运行。即编译完成后,立即执行程序。

go run main.go

好。上文都是编译和运行相关的命令。那测试如何运行?

go test

go test download_test.go 只运行这一个测试文件

go test ./... 运行整个项目下测试文件

λ go test ./...
ok      go-example-for-live/fifteen/download    1.436s
ok      go-example-for-live/fifteen/engine      0.701s
?       go-example-for-live/fifteen/main        [no test files]
ok      go-example-for-live/fifteen/parse/jianshu       0.690s
ok      go-example-for-live/fifteen/parse/v2ex  0.761s
go test -run=TestDownload -v  download_test.go 根据匹配规则运行厕所文件内的测试函数

go test -v ./... -cover

获取测试代码覆盖率。

5. 包管理

  • govendor
  • vgo

项目中使用到了第三方库,如果代码分发出去,不把第三方库文件置入项目中,则他们不能使用,除非重新下载第三方库。

那么如何进行库或者包的管理?

  • govendor

1、下载 govendor
2、 项目下 govendor init
3、govendor add +external

即将第三方库拷贝至项目内新建的目录 vendor 下。

├─download
├─engine
├─main
├─parse
│  ├─jianshu
│  └─v2ex
└─vendor
    ├─github.com
    │  └─PuerkitoBio
    │      └─goquery
    └─golang.org

  • vgo

官方主推的工具,我还不太会用。

https://zhuanlan.zhihu.com/p/33926171

6. 文档

  • godoc -http=:6060 -goroot="."

如果你写的代码注释比较好,或者你go 官网上不去,仅仅只是想离线观看 go 源代码的文档。

godoc -http:=6060

本地访问 localhost:6060 即可查看所有项目(包括内置库)的文档。


有任何疑问,可以查看所有工具的帮助文档。

  • go help
  • go tool help
  • govendor help
  • vogo help
  • gopm help

本节完,再会。

希望你们喜欢。我是谢伟。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,441评论 25 707
  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生_x阅读 15,967评论 3 119
  • 月饼甚多,吃之. 久嚼生香,津液肆下,馅油香而不腻,饼干酥而不硬。 我不知道月饼这个东西是不是也和我的普通话一样带...
    大丑猪阅读 367评论 0 0
  • 德国有一本非常出名的绘本《一生气就大吼大叫的妈妈》,是一只可爱的企鹅宝宝向我们讲述了它和它妈妈之间的非凡经历。 “...
    孙瑞华阅读 186评论 0 0
  • 用瑞士奶酪法来充分利用零碎时间。 1.嵌入式:当人们从一线工作转向另一项工作时,中间往往会出现一片空白地带,对于这...
    静静的叶子阅读 163评论 0 0