英文:
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 < len(ips) && !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 < len(ips) && !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 "github.com/nsqio/go-nsq"
// 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, "")
}
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, "")
}
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 < len(ips) && !success; i++ {
err := f(ips[i])
if err == nil {
success = true
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论