不同写法之间的可读性和优雅度差异

saastaskon ,一个随机选DNS地址的功能

我之前的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
const (
// cloudflare dns
DNSUpstreamCloudFlare = "1.1.1.1:53"
DNSUpstreamGoogle = "8.8.8.8:53"
)
// Randomly select a DNSUpstream
DNSUpstream := DNSUpstreamCloudFlare
rand.Seed(time.Now().UnixNano())
randomIndex := rand.Intn(2)
if randomIndex == 0 {
DNSUpstream = DNSUpstreamGoogle
}

ry改的:

1
2
3
4
5
6
7
8
var (
DNSUpstreams = []string{DNSUpstreamCloudFlare, DNSUpstreamGoogle}
)


idx := rand.New(rand.NewSource(time.Now().Unix())).Intn(len(DNSUpstreams))

r, err := dns.ExchangeContext(ctx, msg, DNSUpstreams[idx])

在这两种写法中,核心目的是从一组 DNS 服务器中随机选择一个作为 DNSUpstream。两种方法都能达到相同的功能,但在代码简洁性、可读性和灵活性方面存在差异。我们可以分别分析这两种写法的优缺点,然后得出结论。

第一种写法:

1
2
idx := rand.New(rand.NewSource(time.Now().Unix())).Intn(len(DNSUpstreams))
DNSUpstreams := []string{DNSUpstreamCloudFlare, DNSUpstreamGoogle}

优点:

  1. 简洁:这段代码利用了一个 []string 数组来存储多个 DNS 地址,并通过 rand.Intn 的随机索引简洁地从其中选择一个。
  2. 灵活性:可以很容易地扩展到更多的 DNS 地址,只需向 DNSUpstreams 数组中添加新的 DNS 地址,而不需要修改代码的其他部分。
  3. 清晰的索引:通过数组索引,代码清晰地表达了随机选择的意图。

缺点:

  1. 冗余的随机数生成器rand.New(rand.NewSource(time.Now().Unix())) 重复创建了一个新的随机数生成器,这在大多数情况下是不必要的。Go 提供了全局的 math/rand 包,可以直接用 rand.Seed() 初始化种子并使用全局的 rand.Intn() 来生成随机数。
  2. 稍微多余的初始化:每次都需要创建一个新的 rand.Source,这相对较为冗长且不必要,特别是当只需要一个简单的随机数时。

第二种写法:

1
2
3
4
5
6
7
8
9
10
11
const (
// Cloudflare DNS
DNSUpstreamCloudFlare = "1.1.1.1:53"
DNSUpstreamGoogle = "8.8.8.8:53"
)
DNSUpstream := DNSUpstreamCloudFlare
rand.Seed(time.Now().UnixNano())
randomIndex := rand.Intn(2)
if randomIndex == 0 {
DNSUpstream = DNSUpstreamGoogle
}

优点:

  1. 直接且清晰:通过 if 语句明确表达了随机选择的逻辑,代码更容易理解,尤其是对初学者。
  2. 使用全局随机数生成器rand.Seed(time.Now().UnixNano()) 初始化了全局的随机数生成器,避免了每次创建新的 rand.Source,使代码更加高效和简洁。
  3. 常量定义更清晰:将 DNS 地址定义为常量,并且在代码中直接使用,这样可以避免魔法字符串(magic string)的使用,增加了可读性和代码的维护性。

缺点:

  1. 扩展性不强:如果未来需要添加更多的 DNS 地址,则需要修改 if 逻辑并增加新的条件判断,这会使代码变得冗长且不够灵活。
  2. 硬编码的随机范围rand.Intn(2) 是基于硬编码的 2,如果 DNS 地址增加到 3 个或更多,就需要手动修改代码。

总结:

  • 灵活性:第一种写法更灵活,适合需要扩展的场景。如果未来可能会有更多的 DNS 选项,第一种方法更容易维护和扩展。
  • 简洁性和性能:第二种写法更直接,且在只需要从两个选项中选择时显得更加简单和高效。它使用了全局的随机数生成器,避免了不必要的对象创建。

个人建议:

  • 如果 DNS 选项是固定的且不会增加:第二种写法更好,因为它更简洁且性能更佳。
  • 如果 DNS 选项会扩展:第一种写法更合适,因为它更具灵活性,添加新的 DNS 地址时无需修改随机选择逻辑。

你也可以通过对第一种写法稍作改进,避免重复创建随机数生成器,从而获得更好的性能:

1
2
3
4
rand.Seed(time.Now().UnixNano())
DNSUpstreams := []string{DNSUpstreamCloudFlare, DNSUpstreamGoogle}
idx := rand.Intn(len(DNSUpstreams))
DNSUpstream := DNSUpstreams[idx]

这样结合了两者的优点,既保持了灵活性,又使用了全局的随机数生成器,避免了不必要的初始化过程。