标签 https 下的文章

Gopher Daily改版了

本文永久链接 – https://tonybai.com/2023/08/06/gopherdaily-revamped

已经记不得GopherDaily是何时创建的了,翻了一下GopherDaily项目的commit history,才发现我的这个个人项目是2019年9月创建的,最初内容组织很粗糙,但我的编辑制作的热情很高,基本能坚持每日一发,甚至节假日也不停刊

该项目的初衷就是为广大Gopher带来新鲜度较高的Go语言技术资料。项目创建以来得到了很多Gopher的支持,甚至经常收到催刊邮件/私信以及主动report订阅列表问题的情况。

不过近一年多,订阅GopherDaily的Gopher可能会发现:GopherDaily已经做不到“Daily”了!究其原因还是个人精力有限,每刊编辑都要花费很多时间。但个人又不想暂停该项目,怎么办呢?近段时间我就在着手思考提升GopherDaily制作效率的问题

一个可行的方案就是“半自动化”!在这次从“纯人工”到“半自动化”的过程中,顺便对GopherDaily做了一次“改版”。

在这篇文章中,我就来说说结合大语言模型和Go技术栈实现GopherDaily制作的“半自动化”以及GopherDaily“改版”的历程。

1. “半自动化”的制作流程

当前的GopherDaily每刊的制作过程十分费时费力,下面是图示的制作过程:

这里面所有步骤都是人工处理,且收集资料、阅读摘要以及选优最为耗时。

那么这些环节中哪些可以自动化呢?收集、摘要、翻译、生成与发布都可以自动化,只有“选优”需要人工干预,下面是改进后的“半自动化”流程:

我们看到整个过程分为三个阶段:

  • 第一阶段(stage1):自动化的收集资料,并生成第二阶段的输入issue-20230805-stage1.json(以2023年8月5日为例)。
  • 第二阶段(stage2):对输入的issue-20230805-stage1.json中的资料进行选优,删掉不适合或质量不高的资料,当然也可以手工加入一些自动化收集阶段未找到的优秀资料;然后基于选优后的内容生成issue-20230805-stage2.json,作为第三阶段的输入。
  • 第三阶段(stage3):这一阶段也都是自动化的,程序基于第二阶段的输出issue-20230805-stage2.json中内容,逐条生成摘要,并将文章标题和摘要翻译为中文,最后生成两个文件:issue-20230805.html和issue-20230805.md,前者将被发布到邮件列表gopherdaily github page上,而后者则会被上传到传统的GopherDaily归档项目中。

我个人的目标是将改进后的整个“半自动化”过程缩短在半小时以内,从试运行效果来看,基本达成!

下面我就来简要聊聊各个自动化步骤是如何实现的。

2. Go技术资料自动收集

GopherDaily制作效率提升的一个大前提就是可以将最耗时的“资料收集”环节自动化了!而要做到这一点,下面两方面不可或缺:

  • 资料源集合
  • 针对资料源的最新文章的感知和拉取

2.1 资料源的来源

资料源从哪里来呢?答案是以往的GopherDaily issues中!四年来积累了数千篇文章的URL,从这些issue中提取URL并按URL中域名/域名+一级路径的出现次数做个排序,得到GopherDaily改版后的初始资料源集合。虽然这个方案并不完美,但至少可以满足改版后的初始需求,后续还可以对资料源做渐进的手工优化。

提取文本中URL的方法有很多种,常用的一种方法是使用正则表达式,下面是一个从markdown或txt文件中提取url并输出的例子:

// extract-url/main.go

package main

import (
    "bufio"
    "fmt"
    "os"
    "path/filepath"
    "regexp"
)

func main() {
    var allURLs []string

    err := filepath.Walk("/Users/tonybai/blog/gitee.com/gopherdaily", func(path string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }

        if info.IsDir() {
            return nil
        }

        if filepath.Ext(path) != ".txt" && filepath.Ext(path) != ".md" {
            return nil
        }

        file, err := os.Open(path)
        if err != nil {
            return err
        }
        defer file.Close()

        scanner := bufio.NewScanner(file)
        urlRegex := regexp.MustCompile(`https?://[^\s]+`)

        for scanner.Scan() {
            urls := urlRegex.FindAllString(scanner.Text(), -1)
            allURLs = append(allURLs, urls...)
        }

        return scanner.Err()
    })

    if err != nil {
        fmt.Println(err)
        return
    }

    for _, url := range allURLs {
        fmt.Printf("%s\n", url)
    }
    fmt.Println(len(allURLs))
}

我将提取并分析后得到的URL放入一个临时文件中,因为仅提取URL还不够,要做为资料源,我们需要的是对应站点的feed地址。那么如何提取出站点的feed地址呢?我们看下面这个例子:

// extract_rss/main.go

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "regexp"
)

var (
    rss  = regexp.MustCompile(`<link[^>]*type="application/rss\+xml"[^>]*href="([^"]+)"`)
    atom = regexp.MustCompile(`<link[^>]*type="application/atom\+xml"[^>]*href="([^"]+)"`)
)

func main() {
    var sites = []string{
        "http://research.swtch.com",
        "https://tonybai.com",
        "https://benhoyt.com/writings",
    }

    for _, url := range sites {
        resp, err := http.Get(url)
        if err != nil {
            fmt.Println("Error fetching URL:", err)
            continue
        }
        defer resp.Body.Close()

        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            fmt.Println("Error reading response body:", err)
            continue
        }

        matches := rss.FindAllStringSubmatch(string(body), -1)
        if len(matches) == 0 {
            matches = atom.FindAllStringSubmatch(string(body), -1)
            if len(matches) == 0 {
                continue
            }
        }

        fmt.Printf("\"%s\" -> rss: \"%s\"\n", url, matches[0][1])
    }
}

执行上述程序,我们得到如下结果:

"http://research.swtch.com" -> rss: "http://research.swtch.com/feed.atom"
"https://tonybai.com" -> rss: "https://tonybai.com/feed/"
"https://benhoyt.com/writings" -> rss: "/writings/rss.xml"

我们看到不同站点的rss地址值着实不同,有些是完整的url地址,有些则是相对于主站点url的路径,这个还需要进一步判断与处理,但这里就不赘述了。

我们将提取和处理后的feed地址放入feeds.toml中作为资料源集合。每天开始制作Gopher Daily时,就从读取这个文件中的资料源开始。

2.2 感知和拉取资料源的更新

有了资料源集合后,我们接下来要做的就是定期感知和拉取资料源的最新更新(暂定24小时以内的),再说白点就是拉取资料源的feed数据,解析内容,得到资料源的最新文章信息。针对feed拉取与解析,Go社区有现成的工具,比如gofeed就是其中功能较为齐全且表现稳定的一个。

下面是使用Gofeed抓取feed地址并获取文章信息的例子:

// gofeed/main.go

package main

import (
    "fmt"

    "github.com/mmcdole/gofeed"
)

func main() {

    var feeds = []string{
        "https://research.swtch.com/feed.atom",
        "https://tonybai.com/feed/",
        "https://benhoyt.com/writings/rss.xml",
    }

    fp := gofeed.NewParser()
    for _, feed := range feeds {
        feedInfo, err := fp.ParseURL(feed)
        if err != nil {
            fmt.Printf("parse feed [%s] error: %s\n", feed, err.Error())
            continue
        }
        fmt.Printf("The info of feed url: %s\n", feed)
        for _, item := range feedInfo.Items {
            fmt.Printf("\t title: %s\n", item.Title)
            fmt.Printf("\t link: %s\n", item.Link)
            fmt.Printf("\t published: %s\n", item.Published)
        }
        fmt.Println("")
    }
}

该程序分别解析三个feed地址,并分别输出得到的文章信息,包括标题、url和发布时间。运行上述程序我们将得到如下结果:

$go run main.go
The info of feed url: https://research.swtch.com/feed.atom
     title: Coroutines for Go
     link: http://research.swtch.com/coro
     published: 2023-07-17T14:00:00-04:00
     title: Storing Data in Control Flow
     link: http://research.swtch.com/pcdata
     published: 2023-07-11T14:00:00-04:00
     title: Opting In to Transparent Telemetry
     link: http://research.swtch.com/telemetry-opt-in
     published: 2023-02-24T08:59:00-05:00
     title: Use Cases for Transparent Telemetry
     link: http://research.swtch.com/telemetry-uses
     published: 2023-02-08T08:00:03-05:00
     title: The Design of Transparent Telemetry
     link: http://research.swtch.com/telemetry-design
     published: 2023-02-08T08:00:02-05:00
     title: Transparent Telemetry for Open-Source Projects
     link: http://research.swtch.com/telemetry-intro
     published: 2023-02-08T08:00:01-05:00
     title: Transparent Telemetry
     link: http://research.swtch.com/telemetry
     published: 2023-02-08T08:00:00-05:00
     title: The Magic of Sampling, and its Limitations
     link: http://research.swtch.com/sample
     published: 2023-02-04T12:00:00-05:00
     title: Go’s Version Control History
     link: http://research.swtch.com/govcs
     published: 2022-02-14T10:00:00-05:00
     title: What NPM Should Do Today To Stop A New Colors Attack Tomorrow
     link: http://research.swtch.com/npm-colors
     published: 2022-01-10T11:45:00-05:00
     title: Our Software Dependency Problem
     link: http://research.swtch.com/deps
     published: 2019-01-23T11:00:00-05:00
     title: What is Software Engineering?
     link: http://research.swtch.com/vgo-eng
     published: 2018-05-30T10:00:00-04:00
     title: Go and Dogma
     link: http://research.swtch.com/dogma
     published: 2017-01-09T09:00:00-05:00
     title: A Tour of Acme
     link: http://research.swtch.com/acme
     published: 2012-09-17T11:00:00-04:00
     title: Minimal Boolean Formulas
     link: http://research.swtch.com/boolean
     published: 2011-05-18T00:00:00-04:00
     title: Zip Files All The Way Down
     link: http://research.swtch.com/zip
     published: 2010-03-18T00:00:00-04:00
     title: UTF-8: Bits, Bytes, and Benefits
     link: http://research.swtch.com/utf8
     published: 2010-03-05T00:00:00-05:00
     title: Computing History at Bell Labs
     link: http://research.swtch.com/bell-labs
     published: 2008-04-09T00:00:00-04:00
     title: Using Uninitialized Memory for Fun and Profit
     link: http://research.swtch.com/sparse
     published: 2008-03-14T00:00:00-04:00
     title: Play Tic-Tac-Toe with Knuth
     link: http://research.swtch.com/tictactoe
     published: 2008-01-25T00:00:00-05:00
     title: Crabs, the bitmap terror!
     link: http://research.swtch.com/crabs
     published: 2008-01-09T00:00:00-05:00

The info of feed url: https://tonybai.com/feed/
     title: Go语言开发者的Apache Arrow使用指南:读写Parquet文件
     link: https://tonybai.com/2023/07/31/a-guide-of-using-apache-arrow-for-gopher-part6/
     published: Mon, 31 Jul 2023 13:07:28 +0000
     title: Go语言开发者的Apache Arrow使用指南:扩展compute包
     link: https://tonybai.com/2023/07/22/a-guide-of-using-apache-arrow-for-gopher-part5/
     published: Sat, 22 Jul 2023 13:58:57 +0000
     title: 使用testify包辅助Go测试指南
     link: https://tonybai.com/2023/07/16/the-guide-of-go-testing-with-testify-package/
     published: Sun, 16 Jul 2023 07:09:56 +0000
     title: Go语言开发者的Apache Arrow使用指南:数据操作
     link: https://tonybai.com/2023/07/13/a-guide-of-using-apache-arrow-for-gopher-part4/
     published: Thu, 13 Jul 2023 14:41:25 +0000
     title: Go语言开发者的Apache Arrow使用指南:高级数据结构
     link: https://tonybai.com/2023/07/08/a-guide-of-using-apache-arrow-for-gopher-part3/
     published: Sat, 08 Jul 2023 15:27:54 +0000
     title: Apache Arrow:驱动列式分析性能和连接性的提升[译]
     link: https://tonybai.com/2023/07/01/arrow-columnar-analytics/
     published: Sat, 01 Jul 2023 14:42:29 +0000
     title: Go语言开发者的Apache Arrow使用指南:内存管理
     link: https://tonybai.com/2023/06/30/a-guide-of-using-apache-arrow-for-gopher-part2/
     published: Fri, 30 Jun 2023 14:00:59 +0000
     title: Go语言开发者的Apache Arrow使用指南:数据类型
     link: https://tonybai.com/2023/06/25/a-guide-of-using-apache-arrow-for-gopher-part1/
     published: Sat, 24 Jun 2023 20:43:38 +0000
     title: Go语言包设计指南
     link: https://tonybai.com/2023/06/18/go-package-design-guide/
     published: Sun, 18 Jun 2023 15:03:41 +0000
     title: Go GC:了解便利背后的开销
     link: https://tonybai.com/2023/06/13/understand-go-gc-overhead-behind-the-convenience/
     published: Tue, 13 Jun 2023 14:00:16 +0000

The info of feed url: https://benhoyt.com/writings/rss.xml
     title: The proposal to enhance Go's HTTP router
     link: https://benhoyt.com/writings/go-servemux-enhancements/
     published: Mon, 31 Jul 2023 08:00:00 +1200
     title: Scripting with Go: a 400-line Git client that can create a repo and push itself to GitHub
     link: https://benhoyt.com/writings/gogit/
     published: Sat, 29 Jul 2023 16:30:00 +1200
     title: Names should be as short as possible while still being clear
     link: https://benhoyt.com/writings/short-names/
     published: Mon, 03 Jul 2023 21:00:00 +1200
     title: Lookup Tables (Forth Dimensions XIX.3)
     link: https://benhoyt.com/writings/forth-lookup-tables/
     published: Sat, 01 Jul 2023 22:10:00 +1200
     title: For Python packages, file structure != API
     link: https://benhoyt.com/writings/python-api-file-structure/
     published: Fri, 30 Jun 2023 22:50:00 +1200
     title: Designing Pythonic library APIs
     link: https://benhoyt.com/writings/python-api-design/
     published: Sun, 18 Jun 2023 21:00:00 +1200
     title: From Go on EC2 to Fly.io: +fun, −$9/mo
     link: https://benhoyt.com/writings/flyio/
     published: Mon, 27 Feb 2023 10:00:00 +1300
     title: Code coverage for your AWK programs
     link: https://benhoyt.com/writings/goawk-coverage/
     published: Sat, 10 Dec 2022 13:41:00 +1300
     title: I/O is no longer the bottleneck
     link: https://benhoyt.com/writings/io-is-no-longer-the-bottleneck/
     published: Sat, 26 Nov 2022 22:20:00 +1300
     title: microPledge: our startup that (we wish) competed with Kickstarter
     link: https://benhoyt.com/writings/micropledge/
     published: Mon, 14 Nov 2022 20:00:00 +1200
     title: Rob Pike's simple C regex matcher in Go
     link: https://benhoyt.com/writings/rob-pike-regex/
     published: Fri, 12 Aug 2022 14:00:00 +1200
     title: Tools I use to build my website
     link: https://benhoyt.com/writings/tools-i-use-to-build-my-website/
     published: Tue, 02 Aug 2022 19:00:00 +1200
     title: Modernizing AWK, a 45-year old language, by adding CSV support
     link: https://benhoyt.com/writings/goawk-csv/
     published: Tue, 10 May 2022 09:30:00 +1200
     title: Prig: like AWK, but uses Go for "scripting"
     link: https://benhoyt.com/writings/prig/
     published: Sun, 27 Feb 2022 18:20:00 +0100
     title: Go performance from version 1.2 to 1.18
     link: https://benhoyt.com/writings/go-version-performance/
     published: Fri, 4 Feb 2022 09:30:00 +1300
     title: Optimizing GoAWK with a bytecode compiler and virtual machine
     link: https://benhoyt.com/writings/goawk-compiler-vm/
     published: Thu, 3 Feb 2022 22:25:00 +1300
     title: AWKGo, an AWK-to-Go compiler
     link: https://benhoyt.com/writings/awkgo/
     published: Mon, 22 Nov 2021 00:10:00 +1300
     title: Improving the code from the official Go RESTful API tutorial
     link: https://benhoyt.com/writings/web-service-stdlib/
     published: Wed, 17 Nov 2021 07:00:00 +1300
     title: Simple Lists: a tiny to-do list app written the old-school way (server-side Go, no JS)
     link: https://benhoyt.com/writings/simple-lists/
     published: Mon, 4 Oct 2021 07:30:00 +1300
     title: Structural pattern matching in Python 3.10
     link: https://benhoyt.com/writings/python-pattern-matching/
     published: Mon, 20 Sep 2021 19:30:00 +1200
     title: Mugo, a toy compiler for a subset of Go that can compile itself
     link: https://benhoyt.com/writings/mugo/
     published: Mon, 12 Apr 2021 20:30:00 +1300
     title: How to implement a hash table (in C)
     link: https://benhoyt.com/writings/hash-table-in-c/
     published: Fri, 26 Mar 2021 20:30:00 +1300
     title: Performance comparison: counting words in Python, Go, C++, C, AWK, Forth, and Rust
     link: https://benhoyt.com/writings/count-words/
     published: Mon, 15 Mar 2021 20:30:00 +1300
     title: The small web is beautiful
     link: https://benhoyt.com/writings/the-small-web-is-beautiful/
     published: Tue, 2 Mar 2021 06:50:00 +1300
     title: Coming in Go 1.16: ReadDir and DirEntry
     link: https://benhoyt.com/writings/go-readdir/
     published: Fri, 29 Jan 2021 10:00:00 +1300
     title: Fuzzing in Go
     link: https://lwn.net/Articles/829242/
     published: Tue, 25 Aug 2020 08:00:00 +1200
     title: Searching code with Sourcegraph
     link: https://lwn.net/Articles/828748/
     published: Mon, 17 Aug 2020 08:00:00 +1200
     title: Different approaches to HTTP routing in Go
     link: https://benhoyt.com/writings/go-routing/
     published: Fri, 31 Jul 2020 08:00:00 +1200
     title: Go filesystems and file embedding
     link: https://lwn.net/Articles/827215/
     published: Fri, 31 Jul 2020 00:00:00 +1200
     title: The sad, slow-motion death of Do Not Track
     link: https://lwn.net/Articles/826575/
     published: Wed, 22 Jul 2020 11:00:00 +1200
     title: What's new in Lua 5.4
     link: https://lwn.net/Articles/826134/
     published: Wed, 15 Jul 2020 11:00:00 +1200
     title: Hugo: a static-site generator
     link: https://lwn.net/Articles/825507/
     published: Wed, 8 Jul 2020 11:00:00 +1200
     title: Generics for Go
     link: https://lwn.net/Articles/824716/
     published: Wed, 1 Jul 2020 11:00:00 +1200
     title: More alternatives to Google Analytics
     link: https://lwn.net/Articles/824294/
     published: Wed, 24 Jun 2020 11:00:00 +1200
     title: Lightweight Google Analytics alternatives
     link: https://lwn.net/Articles/822568/
     published: Wed, 17 Jun 2020 11:00:00 +1200
     title: An intro to Go for non-Go developers
     link: https://benhoyt.com/writings/go-intro/
     published: Wed, 10 Jun 2020 23:38:00 +1200
     title: ZZT in Go (using a Pascal-to-Go converter)
     link: https://benhoyt.com/writings/zzt-in-go/
     published: Fri, 29 May 2020 17:25:00 +1200
     title: Testing in Go: philosophy and tools
     link: https://lwn.net/Articles/821358/
     published: Wed, 27 May 2020 12:00:00 +1200
     title: The state of the AWK
     link: https://lwn.net/Articles/820829/
     published: Wed, 20 May 2020 12:00:00 +1200
     title: What's coming in Go 1.15
     link: https://lwn.net/Articles/820217/
     published: Wed, 13 May 2020 12:00:00 +1200
     title: Don't try to sanitize input. Escape output.
     link: https://benhoyt.com/writings/dont-sanitize-do-escape/
     published: Thu, 27 Feb 2020 19:27:00 +1200
     title: SEO for Software Engineers
     link: https://benhoyt.com/writings/seo-for-software-engineers/
     published: Thu, 20 Feb 2020 12:00:00 +1200

注:gofeed抓取的item.Description是文章的摘要。但这个摘要不一定可以真实反映文章内容的概要,很多就是文章内容的前N个字而已。

Gopher Daily半自动化改造的另外一个技术课题是对拉取的文章做自动摘要与标题摘要的翻译,下面我们继续来看一下这个课题如何攻破。

注:目前微信公众号的优质文章尚未实现自动拉取,还需手工选优。

3. 自动摘要与翻译

对一段文本提取摘要和翻译均属于自然语言处理(NLP)范畴,说实话,Go在这个范畴中并不活跃,很难找到像样的开源算法实现或工具可直接使用。我的解决方案是借助云平台供应商的NLP API来做,这里我用的是微软Azure的相关API。

在使用现成的API之前,我们需要抓取特定url上的html页面并提取出要进行摘要的文本。

3.1 提取html中的原始文本

我们通过http.Get可以获取到一个文章URL上的html页面的所有内容,但如何提取出主要文本以供后续提取摘要使用呢?每个站点上的html内容都包含了很多额外内容,比如header、footer、分栏、边栏、导航栏等,这些内容对摘要的生成具有一定影响。我们最好能将这些额外内容剔除掉。但html的解析还是十分复杂的,我的解决方案是将html转换为markdown后再提交给摘要API。

html-to-markdown是一款不错的转换工具,它最吸引我的是可以删除原HTML中的一些tag,并自定义一些rule。下面的例子就是用html-to-markdown获取文章原始本文的例子:

// get-original-text/main.go

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"

    md "github.com/JohannesKaufmann/html-to-markdown"
)

func main() {
    s, err := getOriginText("http://research.swtch.com/coro")
    if err != nil {
        panic(err)
    }
    fmt.Println(s)
}

func getOriginText(url string) (string, error) {
    resp, err := http.Get(url)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)

    converter := md.NewConverter("", true, nil).Remove("header",
        "footer", "aside", "table", "nav") //"table" is used to store code

    markdown, err := converter.ConvertString(string(body))
    if err != nil {
        return "", err
    }
    return markdown, nil
}

在这个例子中,我们删除了header、footer、边栏、导航栏等,尽可能的保留主要文本。针对这个例子我就不执行了,大家可以自行执行并查看执行结果。

3.2 提取摘要

我们通过微软Azure提供的摘要提取API进行摘要提取。微软Azure的这个API提供的免费额度,足够我这边制作Gopher Daily使用了。

注:要使用微软Azure提供的各类免费API,需要先注册Azure的账户。目前摘要提取API仅在North Europe, East US, UK South三个region提供,创建API服务时别选错Region了。我这里用的是East US。

注:Azure控制台较为难用,大家要有心理准备:)。

微软这个摘要API十分复杂,下面给出一个用curl调用API的示例。

摘要提取API的使用分为两步。第一步是请求对原始文本进行摘要处理,比如:

$curl -i -X POST https://gopherdaily-summarization.cognitiveservices.azure.com/language/analyze-text/jobs?api-version=2022-10-01-preview \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: your_api_key" \
-d \
'
{
  "displayName": "Document Abstractive Summarization Task Example",
  "analysisInput": {
    "documents": [
      {
        "id": "1",
        "language": "en",
        "text": "At Microsoft, we have been on a quest to advance AI beyond existing techniques, by taking a more holistic, human-centric approach to learning and understanding. As Chief Technology Officer of Azure AI services, I have been working with a team of amazing scientists and engineers to turn this quest into a reality. In my role, I enjoy a unique perspective in viewing the relationship among three attributes of human cognition: monolingual text (X), audio or visual sensory signals, (Y) and multilingual (Z). At the intersection of all three, there’s magic—what we call XYZ-code as illustrated in Figure 1—a joint representation to create more powerful AI that can speak, hear, see, and understand humans better. We believe XYZ-code will enable us to fulfill our long-term vision: cross-domain transfer learning, spanning modalities and languages. The goal is to have pre-trained models that can jointly learn representations to support a broad range of downstream AI tasks, much in the way humans do today. Over the past five years, we have achieved human performance on benchmarks in conversational speech recognition, machine translation, conversational question answering, machine reading comprehension, and image captioning. These five breakthroughs provided us with strong signals toward our more ambitious aspiration to produce a leap in AI capabilities, achieving multi-sensory and multilingual learning that is closer in line with how humans learn and understand. I believe the joint XYZ-code is a foundational component of this aspiration, if grounded with external knowledge sources in the downstream AI tasks."
      }
    ]
  },
  "tasks": [
    {
      "kind": "AbstractiveSummarization",
      "taskName": "Document Abstractive Summarization Task 1",
      "parameters": {
        "sentenceCount": 1
      }
    }
  ]
}
'

请求成功后,我们将得到一段应答,应答中包含类似operation-location的一段地址:

Operation-Location:[https://gopherdaily-summarization.cognitiveservices.azure.com/language/analyze-text/jobs/66e7e3a1-697c-4fad-864c-d84c647682b4?api-version=2022-10-01-preview]

这段地址就是第二步的请求地址,第二步是从这个地址获取摘要后的本文:

$curl -X GET https://gopherdaily-summarization.cognitiveservices.azure.com/language/analyze-text/jobs/66e7e3a1-697c-4fad-864c-d84c647682b4\?api-version\=2022-10-01-preview \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: your_api_key"
{"jobId":"66e7e3a1-697c-4fad-864c-d84c647682b4","lastUpdatedDateTime":"2023-07-27T11:09:45Z","createdDateTime":"2023-07-27T11:09:44Z","expirationDateTime":"2023-07-28T11:09:44Z","status":"succeeded","errors":[],"displayName":"Document Abstractive Summarization Task Example","tasks":{"completed":1,"failed":0,"inProgress":0,"total":1,"items":[{"kind":"AbstractiveSummarizationLROResults","taskName":"Document Abstractive Summarization Task 1","lastUpdateDateTime":"2023-07-27T11:09:45.8892126Z","status":"succeeded","results":{"documents":[{"summaries":[{"text":"Microsoft has been working to advance AI beyond existing techniques by taking a more holistic, human-centric approach to learning and understanding, and the Chief Technology Officer of Azure AI services, who enjoys a unique perspective in viewing the relationship among three attributes of human cognition: monolingual text, audio or visual sensory signals, and multilingual, has created XYZ-code, a joint representation to create more powerful AI that can speak, hear, see, and understand humans better.","contexts":[{"offset":0,"length":1619}]}],"id":"1","warnings":[]}],"errors":[],"modelVersion":"latest"}}]}}%

大家可以根据请求和应答的JSON结构,结合一些json-to-struct工具自行实现Azure摘要API的Go代码。

3.3 翻译

Azure的翻译API相对于摘要API要简单的多。

下面是使用curl演示翻译API的示例:

$curl -X POST "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=zh" \
     -H "Ocp-Apim-Subscription-Key:your_api_key" \
     -H "Ocp-Apim-Subscription-Region:westcentralus" \
     -H "Content-Type: application/json" \
     -d "[{'Text':'Hello, what is your name?'}]"

[{"detectedLanguage":{"language":"en","score":1.0},"translations":[{"text":"你好,你叫什么名字?","to":"zh-Hans"}]}]%

大家可以根据请求和应答的JSON结构,结合一些json-to-struct工具自行实现Azure翻译API的Go代码。

对于源文章是中文的,我们可以无需调用该API进行翻译,下面是一个判断字符串是否为中文的函数:

func isChinese(s string) bool {
    for _, r := range s {
        if unicode.Is(unicode.Scripts["Han"], r) {
            return true
        }
    }
    return false
}

4. 页面样式设计与html生成

这次Gopher Daily改版,我为Gopher Daily提供了Web版邮件列表版,但页面设计是我最不擅长的。好在,和四年前相比,IT技术又有了进一步的发展,以ChatGPT为代表的大语言模型如雨后春笋般层出不穷,我可以借助大模型的帮助来为我设计和实现一个简单的html页面了。下图就是这次改版后的第一版页面:

整个页面分为四大部分:Go、云原生(与Go关系紧密,程序员相关,架构相关的内容也放在这部分)、AI(当今流行)以及热门工具与项目(目前主要是github trending中每天Go项目的top列表中的内容)。

每一部分每个条目都包含文章标题、文章链接和文章的摘要,摘要的增加可以帮助大家更好的预览文章内容。

html和markdown的生成都是基于Go的template技术,template也是借助claude.ai设计与实现的,这里就不赘述了。

5. 服务器选型

以前的Gopher Daily仅是在github上的一个开源项目,大家通过watch来订阅。此外,Basten Gao维护着一个第三方的邮件列表,在此也对Basten Gao对Gopher Daily的长期支持表示感谢。

如今改版后,我原生提供了Gopher Daily的Web版,我需要为Gopher Daily选择服务器。

简单起见,我选用了github page来承载Gopher Daily的Web版。

至于邮件列表的订阅、取消订阅,我则是开发了一个小小的服务,跑在Digital Ocean的VPS上。

在选择反向代理web服务器时,我放弃了nginx,选择了同样Go技术栈实现的Caddy。Caddy最大好处就是易上手,且默认自动支持HTTPS,我无需自行用工具向免费证书机构(如 Let’s Encrypt或ZeroSSL)去申请和维护证书。

6 小结

这次改版后的Gopher Daily应得上那句话:“麻雀虽小,五脏俱全”:我为此开发了三个工具,一个服务。

当然Gopher Daily还在持续优化,后续也会根据Gopher们的反馈作适当调整。

摘要和翻译目前使用Azure API,后续可能会改造为使用类ChatGPT的API。

此外,知识星球Gopher部落的星友们依然拥有“先睹为快”的权益。

本文示例代码可以在这里下载。


“Gopher部落”知识星球旨在打造一个精品Go学习和进阶社群!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!2023年,Gopher部落将进一步聚焦于如何编写雅、地道、可读、可测试的Go代码,关注代码质量并深入理解Go核心技术,并继续加强与星友的互动。欢迎大家加入!

img{512x368}
img{512x368}

img{512x368}
img{512x368}

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻) – https://gopherdaily.tonybai.com

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx
  • 微博2:https://weibo.com/u/6484441286
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • Gopher Daily归档 – https://github.com/bigwhite/gopherdaily

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

GoCN社区Go读书会第二期:《Go语言精进之路》

本文永久链接 – https://tonybai.com/2022/07/07/gocn-community-go-book-club-issue2-go-programming-from-beginner-to-master

本文是2022年6月26日我在GoCN社区的Go读书会第二期《Go语言精进之路》直播的文字稿。本文对直播的内容做了重新整理与修订,供喜欢阅读文字的朋友们在收看直播后的揣摩和参考。视频控的童鞋可以关注GoCN公众号和视频号看剪辑后的视频,也可以在B站GopherChina专区下收看视频回放(https://www.bilibili.com/video/BV1p94y1R7jg)。


大家晚上好,我叫白明,是《Go语言精进之路》一书的作者,也是tonybai.com的博主,很荣幸今天参加GoCN社区Go读书会第二期,分享一下我个人在写书和读书方面的经验和体会。

今天的分享包括三方面内容:

  • 写书的历程。一些Gopher可能比较好奇,这么厚的一套书是怎么写出来的,今天就和大家聊一聊。
  • 《Go语言精进之路》导读。主要是把这本书的整体构思与大家聊聊,希望通过这个导读帮助读者更好地阅读和理解这套书。
  • 我个人的读书方法与经验的简要分享。

首先和大家分享一下写书的历程。

一. 写书的历程

1. 程序员的“小目标”与写书三要素

今天收看直播的童鞋都是有追求的技术人员,可能心底都有写一本属于自己的书的小目标。这样可以把自己学习到的知识、技能和经验以比较系统的方式输出给其他人,可以帮助其他人快速学习和掌握本领域的知识、技能和经验。

当然写书还有其他好处,比如:提升名气、更容易混技术圈子、可能给你带来更好的职业发展机会,当然也会给你带来一些额外的副业收入,至于多少,还要看书籍的口碑与销量。

那怎么才能写书呢?作为“过来人”,我总结了三个要素,也是三个条件。

第一个要素是能力

这个很容易理解。以Go为例,如果你没有在Go语言方面的知识、技能的沉淀,没有对Go语言方方面面的较为深入的理解,你很难写出一本口碑很好的书籍。尤其是那种有原创性、独到见解的著书。而不是对前人资料做系统整理摘抄的编书。编书更常见于教材、字典等。显然著书对作者水平的要求更高。

第二个要素是意愿

写过书的同学都有体会,写书是一件辛苦活。需要你在正式工作之余付出大量业余时间伏案创作。并且对于小众技术类书籍来说,写书能带来的金钱上的收益和你付出的时长和精力不成正比。就这个问题,我曾与机械工业出版社的营销编辑老师聊过,得到的信息是:Go技术书籍的市场与Java、Python还没法比,即便是像Go语言圣经《Go程序设计语言》的销量也没法与Java、Python的头部书籍销量相比。

第三个要素是机会

记得小时候十分羡慕那些能出书的人,觉得都是大神级的人物。不过那个时候出书的确很难,机会应该很少,你要不是在学术圈里混很难出书。如今就容易地多了,渠道也多了。每年出版社都有自己的出版计划,各个出版社的编辑老师也在根据计划在各种自媒体上、技术圈子中寻觅匹配的技术作者。

如果你有自己的思路,也可以整理出大纲,并通过某种方式联系到出版社老师,如果匹配就可以出。

另外国外流行电子自助出版,这也给很多技术作者很好的出版机会。比如国内作者老貘写的Go 101系列就是在亚马逊leanpub上做的自助出版,效果还不错。

以上就是我总结的出书的三个要素,一旦集齐这三个要素呢,出书实际就是自然而然的一件事了。以我为例。

从能力方面来说呢,我大约从2011年开始接触和学习Go语言,算是国内较早的一批Go语言接纳者。Go语言2012年才发布1.0版本,因此那时我接触的Go时还是r60版本,还不是正式的1.0版本。从那时起就一直在跟踪Go演化,日常写一些Go项目的小程序。

Go 1.5实现自举并大幅降低GC延迟,我于是开始在一些生产环境使用Go,并逐渐将知识和经验做了沉淀,在自己的博客上不断做着Go相关内容的输出,反响也不错。

随着输出Go内容的增多,我发现以博客的形式输出,内容组织零散,于是我第一次有了将自己的Go知识系统整理并输出的意愿和想法。

我在实践Go的过程中收到很多Go初学者的提问:Go入门容易,但精进难,怎么才能像Go开发团队那样写出符合Go思维和语言惯例的高质量代码呢?这个问题引发了我的思考。在2017年GopherChina大会我以《go coding in go way》为主题,以演讲的形式尝试回答这个问题,但鉴于演讲的时长有限,很多内容没能展开,效果不甚理想。这进一步增强了我通过书籍的形式系统解答这个问题的意愿。

而当时我家大宝已经长大了,我也希望通过写书这个行动身体力行地给孩子树立一个正面的榜样。中国古语有云:言传身教,我也想践行一下。

机会就这样自然而然的来了!2018年初,机械工业出版社副总编杨福川老师在微信联系到我,和我探讨一下是否可以写一本类似于“Effective Go”的书,当时机械工业出版社华章出版社策划了Effective XXX(编写高质量XXX)系列图书,当时已经出版了C、Python等语言版本的书籍,还差Go语言的。我的出书意愿与出版社的需求甚是匹配,于是我答应的杨老师的要求,成为了这套丛书的Go版本的作者。

2. 写书的过程

我是2018下旬开始真正动笔的。

真正开始码字的时候,我才意识到,写书真不容易,要写出高质量书稿,的确需付出大量时间和汗水。每天晚上、早上都在构思、码字、写代码示例、画插图,睡眠时间很少。记得当时每周末都在奋笔疾书,陪伴家人尤其是孩子的时间很少。

另外我这个人还习惯于把一个知识点讲细讲透,这样每一节的篇幅都不小。因此,写作进展是很缓慢的,就这样,进度一再延期。好在编辑老师比较nice,考虑到书稿质量,没有狠狠催进度。

2020年11月末,我正式向出版社交了初稿,记得初稿有66条,近40w字。

又经过一年的排期、编辑、修订、排版,2021年12月下旬正式出版。

2022年1月《Go语言精进之路》正式上架到各个渠道货架。

到今天为止,出版了近六个月,这本书收获了还不错的口碑,在各个平台上的口碑都在8分以上(注:口碑分数还在动态变化,下图仅为当时的快照,不代表如今的分数)。


能获得大家的认可,让我很是欣慰,觉得写书过程付出的辛苦没有白费。

以上就是我的写书历程。总的来说一句话:写书不易,写高质量的书更难

接下来我来进行一下《Go语言精进之路》一书的导读。

二. 《Go语言精进之路》导读

也许是“用力过猛”,《Go语言精进之路》一书写的太厚了,无法装订为一册。编辑老师建议装订为两册,即1、2册。很多同学好奇为什么不是上下册而是1、2册,这里是编辑老师的“高瞻远瞩”,目的是为后续可能的“续写”(比如第3册)留足空间,毕竟Go语言还在快速演进,目前的版本还不包含像泛型这样的新语法。不过,目前第3册还尚未列入计划。

本套书共分为10个部分,66个主题。第一册包含了前7个部分,后3部分在第二册中。

1. 整体写作思路

整套书围绕着两个前后关联的思路循序展开。

第一个思路我叫它:精进之路,思维先行

第二个思路称为:践行哲学,遵循惯例,认清本质,理解原理

我们先来看看第一个思路。

2. 精进之路,思维先行

收看直播的童鞋都不止学过一门编程语言。大家可能都有过这样的经历:你已经精通A语言,然后在学习B语言的时候用A语言的思维去写B代码,你会觉得写出的B代码很别扭,写出的代码总是感觉不是很地道,总觉得不是那种高质量的B语言代码。

其实,不仅学习编程语言是这样,学自然语言也是一样。最典型的一个例子,大家都学过十几年的英语,但毕业后能用地道的英语表达自己观点的人却不多,为什么呢?那就是我们总用中文的思维方式去组织英语的句子,去说英语,这样再怎么努力也很难上一个层次。

其实,很多语言大师早就意识到了这一点。下面是我收集的这些大师的关于语言与思维的论点,这里和大家分享一下:

“语言决定思维方式” – 萨丕尔假说

“我的语言之局限,即我的世界之局限” – 路德维希·维特根斯坦,语言哲学的奠基人

“不能改变你思维方式的语言,不值得学习” – Alan Perlis(首届ACM图灵奖得主)

我们看到:无论是自然语言界的大师,还是IT界的大佬,他们的观点异曲同工。总之一句话:语言要精进,思维要先行

3. Part1:进入Go语言编程思维导引

正是因为意识到语言与思维的紧密关系,我在书的第一部分就安排了Go语言编程思维导引,希望大家意识到Go编程思维在语言精进之路上的重要性。

一门编程语言的思维也不是与生俱来的,而是在演进中逐步形成的。所以在这一部分,我安排了Go诞生与演进、Go设计哲学:简单、组合、并发、面向工程。这样做的目的是让大家一起了解Go语言设计者在设计Go语言时的所思所想,让读者站在语言设计者的高度理解Go语言与众不同的设计,认同Go语言的设计理念。因为这些是Go编程语言思维形成的“土壤”

这一部分最后一节是Go编程思维举例导引,书中给出了C, Haskell和Go程序员在面对同一个问题时,首先考虑到的思维方式以及不同思维下代码设计方式的差异。

知道Go编程思维的重要性后,我们应该怎么做呢?

4. 怎么学习Go编程思维?

学习的本质是一种模仿。要学习Go思维,就要去模仿Go团队、Go社区的优秀项目和代码,看看他们怎么做的。这套书后面的部分讲的就是这个。而“践行哲学,遵循惯例,认清本质,理解原理”就是对后面内容的写作思路的概要性总结。

  • 践行哲学

把Go设计哲学用于自己的项目的设计实践中,而不是仅停留在口头知道上。

  • 遵循惯例

遵循Go团队的一些语言惯例,比如“comma,ok”、使用复合字面值初始化等,使用这些惯例你可以让你的代码显得很地道,别人一看就懂。

  • 认清本质

为了更高效地利用语言机制,我们要认清一些语言机制背后的本质,比如切片、字符串在运行时的表示,这样一来既能帮助开发人员正确使用这些语法元素,同时也能避免入坑。

  • 理解原理

Go带有运行时。运行时全程参与Go应用生命周期,因此,只有对Goroutine调度、GC等原理做适当了解,才能更好的发挥Go的威力。

这套书的part2-part10 就是基于对Go团队、Go社区优秀实践与惯例的梳理,用系统化的思路构建出来并循序渐进呈现给大家的。

5. Part2 – 项目基础:布局、代码风格与命名

这部门的内容是每个gopher在开启一个Go项目时都要考虑的事情。

  • 项目布局

我见过很多Gopher问项目布局的事情,因为Go官方没有给出标准布局。本书讲解了Go项目的结构布局的演进历程以及Go社区的事实标准,希望能给大家提供足够的参考信息。

  • 代码风格

针对Go代码风格,由于代码风格在Go中已经弱化,所以这里主要还是带大家理解gofmt存在的意义和使用方法。

  • 命名惯例

关于命名,我不知道大家是否觉得命名难,但对我来说是挺难的,我总是绞尽脑汁在想用啥名(手动允悲)。所以我的原则是“代码未动,命名先行”。 对于Go中变量、标识符等的命名惯例这样的“关键的问题”,我使用了“笨方法”:我统计了Go标准库、Docker库、k8s库的命名情况,并分门别类给出不同语法元素的命名惯例,具体内容大家可以看书了解 。

6. Part3 – 语法基础:声明、类型、语句与控制结构

第三部分讲的很基础,但内容还是要高于基础的。

  • 一致的变量声明

我们知道Go提供多种变量声明方式,但是在不同位置该用哪种声明方式可读性好又不容易造坑呢(尤其要注意短变量声明)?书中给出了系统阐述。

  • 无类型常量与iota

大家都用过常量,但很多人对于无类型常量与有类型常量区别不了解,书中帮你做了总结。还有,很多人用过iota,但却不理解iota的真正含义以及它能帮你做啥。书中对iota的语义做了说明,对常见用途做了梳理。

  • 零值可用

Go提倡零值可用,也内置了有很多零值可用类型,用起来很爽,比如:切片(不全是,仅在append时是零值可用,当用下标访问时,不具备零值可用)、sync包中的Mutex、RDMutex等

其实类比于线程(thread),goroutine也是一种零值可用的“类型”,只是Go没有goroutine这个类型罢了。

如果我们是包的设计者,如果提供零值可用的类型,可以提升包的使用者的体验。

  • 复合字面值来初始化

使用复合字面值对相应的变量进行初始化是一个Go语言的惯例, Go虽然提供了new和make,但日常很少用,尤其是new。

  • 切片、字符串、map的原理、惯用法与坑

Go是带有runtime的语言,语法层面展示的很多语法元素和runtime层真实的表示并不一致。要想高效利用这些类型,如果不了解runtime层表示还真不行。有时候还有很严重的“坑”。懂了,自然就能绕过坑。

  • 包导入

Go源文件的import语句后面跟着的是包名还是包路径?Go编译是不是必须要有依赖项的源码才可以,只有.a是否可以?这些问题书中都有系统说明

  • 代码块与作用域

代码块与作用域是Go语言的基础概念,虽然基础,如果理解不好,也是有“坑”的,比如最常见的变量遮蔽等。一旦理解透了,还可以帮你解决意想不到的语法问题和执行语义错误问题。

  • 控制语句

Go倡导“一个问题只有一种解决方法”。Go针对每种控制语句仅提供一种语法形式。虽然仅有一种形式,用不好,一样容器掉坑。本套书总结了Go控制语句的惯用法与使用注意事项。

7. Part4 – 语法基础:函数与方法

我们日常编写的Go代码逻辑都在函数或方法中,函数/方法是Go程序逻辑的基本承载单元。

  • init函数

init函数是包初始化过程中执行的函数,它有很多特殊用途。并且其初始化顺序对程序执行语义也有影响,这方面要搞清楚。书中对init函数的常见用途做了梳理,比如database/sql包的驱动自注册模式等。

  • 成为“一等公民”

在Go中,函数成为了“一等公民”。函数成为一等公民后可以像变量一样,被作为参数传递到函数中、作为返回值从函数中返回、作为右值赋值给其他变量等,书中系统讲解了这个特性都有哪些性质和特殊应用,比如函数式编程等。

  • defer语句的惯用法与坑

defer就是帮你简化代码逻辑的,书中总结了defer语句的应用模式。以及使用defer的注意事项,比如函数求值时机、使用开销等。

  • 变长参数函数

Go支持变长参数函数。大家可以没有意识到:变长参数函数是我们日常用的最多的一类函数,比如append函数、fmt.Printf系列、log包中提供的按日志严重级别输出日志的函数等。

但变长参数函数可能也是我们自己设计与实现较少的一类函数形式。 变长参数函数能帮我们做什么呢?书中讲解了变长参数函数的常见用途,比如实现功能选项模式等。

  • 方法的本质、receiver参数类型选择、方法集合

方法的本质其实是函数,弄清楚方法的本质可以帮助我们解决很多难题,书中以实例方式帮助大家理解这一点。

方法receiver参数类型的选择也是Go初学者的常见困惑,这里书中给出三个原则,参照这三个原则,receiver类型选择就不是问题了。

怎么确定一个类型是否实现接口?我们需要看类型的方法集合。那么确定一个类型方法集合就十分重要,尤其是那些包括类型嵌入的类型的方法集合,书中对这块内容做了系统的讲解。

8. Part5 – 语法核心:接口

  • 接口的内部表示

接口是Go语言中的重要语法。Russ Cox曾说过:“如果要从Go语言中挑选出一个特性放入其他语言,我会选择接口”。可见接口的重要性。不过,用好接口类型的前提是理解接口在runtime层的表示,这一节会详细说明空接口与非空接口的内部表示。

  • 接口的设计惯例

我们应该设计什么样的接口呢? 大接口有何弊端?小接口有何优势?多小的接口算是合理的呢?这些在本节都有说明。

  • 接口与组合

组合是Go的设计哲学,Go是关于组合的语言。接口在面向组合编程时将发挥重要作用。这里我将提到Go的两种组合方式:垂直组合和水平组合。其中接口类型在水平组合中起到的关键性的作用。书中还讲解了通过接口进行水平组合的几种模式:包裹模式、适配器函数、中间件等。

很多初学者告诉我,他们做了一段时间Go编码了,但还没有自己设计过接口,我建议这样的同学好好读读这一部分。

9. Part6 – 语法核心:并发编程

  • 并发设计vs并行设计

学习并发编程首先要搞懂并发与并行的概念,书中用了一个很形象的机场安检的例子,来告诉大家并发与并行的区别。并发关乎结构,并行关注执行

  • 并发原语的原理与应用模式

Go实现了csp模型,提供了goroutine、channel、select并发原语。

理解go并发编程。首先要深入理解基于goroutine的并发模型与调度方式。书中对这方面做了深入浅出的讲解,不涉及太多代码,相信大家都能看懂。

书中还对比了go并发模型,一种是csp,一种是传统的基于共享内存方式,并列举了Go并发的常见模式,比如创建、取消、超时、管道模式等。

另外,channel作为goroutine间通信的标准原语,有很多玩法,这里列举了常见的模式和使用注意事项。

  • 低级同步原语(sync和atomic)

虽然有了CSP模型的并发原语,极大简化并发编程,但是sync包和原子操作也不能忘记,很多性能敏感的临界区还需要sync包/atomic这样的低级同步原语来同步。

10. Part7 – 错误处理

单独将错误处理拎出来,是因为很多人尤其是来自java的童鞋,习惯了try-catch-finally的结构化错误处理,看到go的错误处理就让其头疼。

Go语言十分重视错误处理,但它也的确有着相对保守的设计和显式处理错误的惯例。

本部分涵盖常见Go错误处理的策略、避免if err != nil写太多的方案,更为重要的是panic与错误处理的差别。我见过太多将panic用作正常处理的同学了。尤其是来自java阵营的童鞋。

11. Part8 – 编程实践:测试、调试与性能剖析

本部分聚焦编码之外的Go工具链工程实践。

  • Go测试惯例与组织形式

这部分首先和大家聊聊go test包的组织形式,包括是选择包内测试还是包外测试?何时采用符合go惯例的表驱动的测试用例组织形式?如何管理测试依赖的外部数据文件等。

  • 模糊测试(fuzzing test)。

这里的模糊测试并非基于go 1.18的原生fuzzing test进行,写书的时候go 1.18版本尚未发布,而是基于德米特里-维尤科夫的go-fuzz工具

  • 性能基准测试、度量数据与pprof性能剖析

Go原生提供性能基准测试。这一节讲解了如何做性能基准测试、如何编写串行与并行的测试、性能基准测试结果比较工具以及如何排除额外干扰,让结果更准确等方面内容。在讲解pprof性能剖析工具时,我使用一个实例进行剖析讲解,这样理解起来更为直观。

  • Go调试

说到Go调试,我们日常使用最多的估计还是print大法。但在print大法之外,其实有一个事实标准的Go调试工具,它就是delve。在这一节中,我讲解了delve的工作原理以及使用delve如何实现并发调试、coredump调试以及在线挂接(attach)进程的调试。

12. Part9 – 标准库、反射与cgo

go是自带电池,开箱即用的语言,拥有高质量的标准库。在国外有些Gopher甚至倡导仅依赖标准库实现go应用。

  • 高频使用的标准库包(net、http、strings、time、crypto等)

在这一节,我对高频使用的标准库包的原理和使用进行拆解分析,net、http、标准库io模型、strings、time、crypto等以帮助大家更高效的运用标准库。

  • reflect包使用的三大法则

reflect包为go提供了反射能力,书中对反射的实现原理做了讲解,重点是reflect使用的三大法则。

  • cgo使用

cgo不是go,但是cgo机制是使用go与c交互的唯一手段。书中对cgo的用法与约束做了详细讲解,尤其是在cgo开启的情况下如何做静态编译值得大家细读。

  • unsafe包的安全使用法则

事实证明unsafe包很有用,但要做到安全使用unsafe包,尤其是unsafe.Pointer,需要遵循一定的安全使用法则。书中对此做了举例详细说明。

反射、cgo、unsafe算是高级话题,要透彻理解,需要多阅读几遍书中内容并结合实践。

13. Part10 – 工程实践

  • go module

go module在go 1.11版本中引入go,在go 1.16版本中成为go官方默认构建模式。go程序员入门go,精进go都跨不过go module这道坎儿。书中对go module构建模式做了超级系统的讲解:从go构建模式演进历史、go module的概念、原理、惯例、升降级major版本的操作,到使用注意事项等。不过这里还有有一些瑕疵,那就是go module这一节放置的位置太靠后了,应该往往前面提提。如果后面有修订版,可以考虑这么做。

  • 自定义go包导入路径

书中还给出了一个自定义go包导入路径的一种实现方案,十分适合组织内部的私有仓库,有兴趣的同学可以重点看看。

  • go命令的使用模式详解

这一节将go命令分门别类地进行详细说明。包括:

- 获取与安装的go get/go install
- go包检视的go list
- go包构建的go build
- 运行与诊断的GODEBUG、GOGC等环境变量的功用
- 代码静态检查与重构
- 文档查看
- go代码生成go generate
  • Go常见的“坑”

这一节将Go常见的“坑”进行了一次检阅。我这里将坑分为“语法类”和“标准库类”,并借鉴了央视五套天下足球top10节目,对每个坑的“遇坑指数”与“坑害指数”做了点评。

14. 具备完整的示例代码与勘误表

这套书拥有具备完整的示例代码与勘误表,它们都被持续维护,让大家没有读书的后顾之忧。

三. 读书的实践与体会

下面我再分享一下我个人是怎么读书的,包括go技术书籍的读书历程,以及关于读书的一些实践体会。

读书是千人千面的事,没有固定标准的。我的读书方法也不见得适合诸位。大家听听即可,觉得还不错,能借鉴上就最好了。

今天收看直播估计以gopher为主,所以首先说说Go语言书籍的阅读历程

1. Go语言书籍阅读历程:先外后内

对于IT技术类图书,初期还是要看原版的。这个没办法,因为it编程技术绝大多数来自国外。

我读的第一本Go技术书就是《the way to go》,至今这本书也没有引入国内。这是一本Go语言百科全书,大多数内容如今仍适用。唯一不足是该书成书于Go 1.0发布之前,使用的好像是r60版本,有少部分内容已经不适用。

后来Go 1.0发布后,我还陆续读过Addison-Wesley出版的《programming in go》和《The Go Programming Language Phrasebook》,两本书都还不错。

2015年末的布莱恩.克尼根和go核心团队的多诺万联合编写的《The Go Programming Language》,国内称之为Go圣经的书出版了,这让外文go技术书籍达到了巅峰,后来虽然也有go书籍书籍陆续出版,但都无法触及go圣经的地位。

说完外文图书,我再来说说中文Go图书的阅读历程。

我读过的第一本中文Go书籍是2012年许式伟老师的《Go语言编程》,很佩服许老师的眼光和魄力,七牛云很早就在生产用go。

第二本中文Go书籍是雨痕老师的《go学习笔记》,这也是国内第一本深入到go底层原理的书籍(后半部分),遗憾的是书籍停留在go 1.5(还是go 1.6)的实现上,没有随Go版本演进而持续更新。

柴大和曹大合著的《go高级编程》也是一本不错的go技术书籍,如果你要深入学习cgo和go汇编,建议阅读此书。

后面的《Go语言底层原理剖析》和《Go语言设计与实现》也都是以深入了解Go运行机制为目标的书籍,口碑都很好,对这方面内容感兴趣的gopher,可以任意挑一本学习。

2. 自己的读书方法

我的读书方法其实不复杂,主要分为精读和泛读。

  • 阅读方式:好书精读,闲书泛读

好书,集中一大段时间内进行阅读。 闲书(不烧脑),通常是 碎片化阅读。

  • 精读方法:摘录+脑图+行动清单

摘录就是将书中的观点和细节摘录出来,放到读书笔记,最好能用自己的语言重新描述出来,这样印象深刻,理解更为透彻。

脑图,概括书的思维脉络,防止读完就忘记。 通过脑图,我至少看着脉络能想起来。

行动清单:如果没有能输出行动清单,那这本书对你来说意义就不大。 什么是好书,好书就是那种看完后很迫切的想基于书中的观点做点什么。行动清单将有助于我在后续的行动中反复理解书中内容,提高知识的消化率和理解深度。

  • 泛读方法:碎片化+听书

泛读主要是碎片化快读或听书,主要是坐地铁,坐公交,散步时。开车时在保证安全的前提下,可以用听书的方式。

四. 小结

本次分享了三块内容,这里小结一下:

  • 写书历程和写书三要素:能力 + 意愿 + 机会;
  • Go精进之路导读:思维先行,践行哲学,遵循惯例,认清本质,理解原理;
  • 读书方法:选高质量图书精读(脑图+细节摘录+行动清单)。

五. Q&A

  • 在实际开发中有没有什么优雅的处理error的方法?

建议看《Go语言精进之路》第一册第七部分中关于error处理的内容。

  • 是否在工作中使用过六边形架构以及依赖注入的处理经验?

暂没有使用过六边形架构,生产中没有使用过Go第三方依赖注入的方案。

  • 后面会有泛型和模糊测试的补充么?

从书籍内容覆盖全面性的角度而言,我个人有补充上述内容的想法,但还要看现在这套书的销售情况以及出版社的计划。目前还没列入个人工作计划。

  • 作者总结一系列go方法论、惯例等很实用,这种有逻辑的思考和见解是怎么形成的?

没有特意考虑过是怎么形成的。个人平时喜欢多问自己几个为什么,形成让自己信服的工作和学习逻辑。(文字稿补充:同理心、多总结、多复盘、多输出)。

学习Go惯例、方法论,可以多多看Go语言开源项目自身的代码评审,看看Go contributor写代码的思路和如何评审其他贡献者的代码的。(文字稿补充:在这一过程中,潜移默化的感受Go编程思维)。

  • 如何阅读大型go项目的源码?

我个人的方法就是自上而下。先拆分结构,然后找入口。如果是一个可执行的go程序,还是从入口层层的向后看。然后通过一些工具,比如我个人之前开发的函数调用跟踪工具,查看程序执行过程中的函数调用次序。

更细节的内容,还是要深入到代码中去查看。

  • 对Go项目中的一些设计模式的看法?如何使用设计模式,使用时注意哪些事项?

设计模式在go语言中并不是一个经常拿出来提的东西。我之前的一个观点:在其他语言中,需要大家通过一些额外细心的设计构建出来的设计模式,在Go语言中是自然而然就有的东西。

我在自己的日常编码过程中,不会太多从如何应用设计模式的角度思考,而是按照go设计哲学,去考虑并发设计、组合的设计,而不是非要套用那23个经典设计模式。


“Gopher部落”知识星球旨在打造一个精品Go学习和进阶社群!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!2022年,Gopher部落全面改版,将持续分享Go语言与Go应用领域的知识、技巧与实践,并增加诸多互动形式。欢迎大家加入!

img{512x368}
img{512x368}

img{512x368}
img{512x368}

我爱发短信:企业级短信平台定制开发专家 https://tonybai.com/。smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。2020年4月8日,中国三大电信运营商联合发布《5G消息白皮书》,51短信平台也会全新升级到“51商用消息平台”,全面支持5G RCS消息。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博:https://weibo.com/bigwhite20xx
  • 博客:tonybai.com
  • github: https://github.com/bigwhite

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats