几乎在重复自己

huangapple go评论121阅读模式
英文:

Almost Repeating Myself

问题

"组合爆炸"是指你有很多几乎做同样事情的代码,只是数据或行为上有微小的变化。这可能很难重构,也许可以使用泛型或解释器来解决这个问题。- Jeff Atwood via Coding Horror

在这种情况下,虽然不是很多代码,但它仍然困扰着我。我有一个共享的问题,就是当尝试连接到一个IP时,如果失败了,我应该重试下一个IP。

我有一个生成NSQ生产者的函数:

//由于我们处于一个关键系统中,我们尝试每个IP,直到获得一个生产者
var err error
for i, success := 0, false; i < len(ips) && !success; i++ {
publisher, err = nsq.NewProducer(ips[i], nsq.NewConfig())
if err == nil {
success = true
}
}

另一个几乎相同的代码是一个接受NSQ消费者并连接的函数:

var err error
for i, success := 0, false; i < len(ips) && !success; i++ {
err = consumer.ConnectToNSQD(ips[i])
if err == nil {
success = true
}
}

我想摆脱这个几乎重复的代码,同时又不牺牲可读性。有什么想法吗?

英文:

> Combinitorial Explosion You have lots of code that does almost the same thing.. but with tiny variations in data or behavior. This can be difficult to refactor-- perhaps using generics or an interpreter? - Jeff Atwood via Coding Horror

In this case it is not lots of code, but it is still bugging me. I have a shared problem, that is when trying to connect to an IP, if it fails, I should retry with the next IP.

I have one function which generates a producer for NSQ:

//Since we are in a critical system, we try with each IP until we get a producer
var err error
for i, success := 0, false; i &lt; len(ips) &amp;&amp; !success; i++ {
    publisher, err = nsq.NewProducer(ips[i], nsq.NewConfig())
    if err == nil {
        success = true
    }
}

The other function that almost shares the same code is one which takes a NSQ consumer and connects it:

var err error
for i, success := 0, false; i &lt; len(ips) &amp;&amp; !success; i++ {
	err = consumer.ConnectToNSQD(ips[i])
	if err == nil {
		success = true
	}
}

I would like to get rid of this almost repeated code without sacrificing legibility. Ideas?

答案1

得分: 4

你弄反了。你的解决方案应该遵循问题的形状,而不是特定解决方案的形状。解决方案中没有值得重构的东西。这只会增加无意义的复杂性。

例如,

package main

import "github.com/nsqio/go-nsq"

// NewProducer 是带有地址列表重试的 nsq.NewProducer。
func NewProducer(addrs []string, config *nsq.Config) (producer *nsq.Producer, err error) {
    if len(addrs) == 0 {
        addrs = append(addrs, "")
    }
    for _, addr := range addrs {
        producer, err = nsq.NewProducer(addr, config)
        if err == nil {
            break
        }
    }
    return producer, err
}

// ConnectToNSQD 是带有地址列表重试的 nsq.ConnectToNSQD。
func ConnectToNSQD(c *nsq.Consumer, addrs []string) (err error) {
    if len(addrs) == 0 {
        addrs = append(addrs, "")
    }
    for _, addr := range addrs {
        err = c.ConnectToNSQD(addr)
        if err == nil {
            break
        }
    }
    return err
}

func main() {}
英文:

You have it backwards. Your solution should follow the shape of the problem, not the shape of a particular solution. There's nothing in the solution that's worth refactoring. It's just going to add pointless complexity.

For example,

package main

import &quot;github.com/nsqio/go-nsq&quot;

// NewProducer is nsq.NewProducer with retries of an address list.
func NewProducer(addrs []string, config *nsq.Config) (producer *nsq.Producer, err error) {
	if len(addrs) == 0 {
		addrs = append(addrs, &quot;&quot;)
	}
	for _, addr := range addrs {
		producer, err = nsq.NewProducer(addr, config)
		if err == nil {
			break
		}
	}
	return producer, err
}

// ConnectToNSQD is nsq.ConnectToNSQD with retries of an address list.
func ConnectToNSQD(c *nsq.Consumer, addrs []string) (err error) {
	if len(addrs) == 0 {
		addrs = append(addrs, &quot;&quot;)
	}
	for _, addr := range addrs {
		err = c.ConnectToNSQD(addr)
		if err == nil {
			break
		}
	}
	return err
}

func main() {}

答案2

得分: 1

也许可以这样写:

var publisher *nsq.Producer

connectToWorkingIP(ips, func(ip string) error {
    var err error
    publisher, err = nsq.NewProducer(ip, nsq.NewConfig())
    return err
})

connectToWorkingIP(ips, func(ip string) error {
    return consumer.ConnectToNSQD(ip)
})


func connectToWorkingIP(ips []string, f func(string) error) {
    for i, success := 0, false; i < len(ips) && !success; i++ {
        err := f(ips[i])
        if err == nil {
            success = true
        }
    }
}

这段代码的作用是连接到可用的 IP 地址。首先,通过 connectToWorkingIP 函数连接到一个可用的 IP 地址,并创建一个 nsq.Producer 对象。然后,再次使用 connectToWorkingIP 函数连接到另一个可用的 IP 地址,并将 consumer 对象连接到 NSQD。connectToWorkingIP 函数会遍历给定的 IP 地址列表,直到成功连接或遍历完所有 IP 地址为止。

英文:

Maybe something like this?

var publisher *nsq.Producer

connectToWorkingIP(ips, func(ip string) error {
	var err error
	publisher, err = nsq.NewProducer(ip, nsq.NewConfig())
	return err
})

connectToWorkingIP(ips, func(ip string) error {
	return consumer.ConnectToNSQD(ip)
})


func connectToWorkingIP(ips []string, f func(string) error) {
	for i, success := 0, false; i &lt; len(ips) &amp;&amp; !success; i++ {
		err := f(ips[i])
		if err == nil {
			success = true
		}
	}
}

huangapple
  • 本文由 发表于 2015年9月21日 15:41:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/32689816.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定