Rich Hickey describes paradigms from Clojure and Haskell in his talk Simple Made Easy. As a ruby/rails programmer (that's all I truly know), I loved his ideas, but didn't understand 2 of them:
Rich Hickey描述了Clojure和Haskell的范例,在他的《简单使轻松》一书中。作为一个ruby/rails程序员(这是我真正知道的),我喜欢他的想法,但不理解其中的两个:
- Using Queues, not Method Chaining
- 使用队列,而不是方法链接
- Rules instead of Conditionals
- 规定的条件
Using Queues instead
使用队列而不是
Obviously, in Rails we love method chaining, but I wanted to understand what a Queue would look like in Ruby the way he described it (54:54
in the Video):
显然,在Rails中我们喜欢方法链接,但是我想理解Ruby中队列的样子,就像他描述的那样(视频中54:54):
If thing A calls thing B, you just complected it. You have a when and where thing. A has to know where B is in order to call B. When that happens is whenever that happens is when A does it. Stick a Queue in there.
如果它是一个叫B的东西,你只是对它进行了补充。你有时间和地点。A必须知道B在哪里才能调用B。在里面插一个队列。
Rules vs Conditionals
规则和条件
He talks about not using conditionals or switch statements but Rules instead (30:00
in Video).
他谈到不使用条件句或交换语句,而是使用规则(视频中的30:00)。
This I simply don't get at all in terms of Ruby. How do I make decisions without using conditionals?
这一点我根本就不理解Ruby。我如何在不使用条件句的情况下做出决定?
Thanks all, Justin
谢谢,贾斯汀
3 个解决方案
#1
16
Hello, Queues
The idea here is that, instead of passing a value directly from one object to another, we can decouple them by sticking a queue between them.
这里的想法是,我们可以通过在它们之间插入一个队列来解耦,而不是直接将值从一个对象传递到另一个对象。
Let's say we were modelling a farmer collecting the eggs from a chicken. The chicken produces eggs, the farmer collects them. A farmer's shift is finished when they've collected five eggs. Normally, we might write something like this:
假设我们在模拟一个农民从一只鸡身上收集鸡蛋。鸡产蛋,农民收集它们。一个农民的轮班结束时,他们已经收集了五个鸡蛋。通常,我们可以这样写:
class Chicken
def initialize(name)
@name = name
end
def lay_egg
sleep random(3)
"an egg from #{@name}"
end
end
class Farmer
def initialize(name, chicken)
@name = name
@chicken = chicken
end
def work_shift
5.times do
egg = @chicken.lay_egg
puts "#{@name} got #{egg}"
end
end
end
betsy = Chicken.new "Betsy"
fred = Farmer.new "Fred", betsy
fred.work_shift
So, the farmer waits by the chicken and picks up eggs as they come. Great, problem solved, go to the fridge and get a beer. But what if, say, we bought a second chicken to double our egg production? Or, what if we wanted to test our farmer's dexterity by having them pick up eggs from a carton?
于是,农夫就在鸡旁边等着,等它们来的时候就把鸡蛋捡起来。很好,问题解决了,去冰箱拿瓶啤酒。但是,如果我们买了第二只鸡,让我们的鸡蛋产量翻倍呢?或者,如果我们想让我们的农民从一个纸盒里拿起鸡蛋来测试他们的灵巧性呢?
Because we've coded the farmer to require a chicken, we've lost the flexibility we need to make these kind of decisions. If we can decouple them, we'll have a lot more freedom.
因为我们编码农民需要一只鸡,我们失去了做出这些决定所需的灵活性。如果我们能解耦它们,我们就有更多的*。
So, let's stick a queue between them. The chicken will lay eggs at the top of a chute; the farmer will collect eggs from the bottom of the chute. Neither party relies directly on the other. In code, that might look like this:
让我们在它们之间排个队。鸡会在溜槽顶部产卵;农民将从溜槽的底部收集鸡蛋。任何一方都不能直接依赖另一方。在代码中,可能是这样的:
class Chicken
def initialize(name, chute)
@name = name
@chute = chute
Thread.new do
while true
lay_egg
end
end
end
def lay_egg
sleep rand(3)
@chute << "an egg from #{@name}"
end
end
class Farmer
def initialize(name, chute)
@thread = Thread.new do
5.times do
egg = chute.pop
puts "#{name} got #{egg}"
end
end
end
def work_shift
@thread.join
end
end
chute = Queue.new
betsy = Chicken.new "Betsy", chute
fred = Farmer.new "Fred", chute
fred.work_shift
Except that now, we can easily add a second chicken. This is the stuff dreams are made of:
除了现在,我们可以很容易地添加第二个鸡肉。这就是梦的组成部分:
chute = Queue.new
betsy = Chicken.new "Betsy", chute
delores = Chicken.new "Delores", chute
fred = Farmer.new "Fred", chute
fred.work_shift
You could imagine how we might also, say, load up a chute with a bunch of eggs to test the farmer. No need to mock a chicken, we just prep a queue and pass it in.
你可以想象我们如何,比如说,装上一堆鸡蛋去测试农夫。没有必要嘲笑鸡,我们只是准备好队列,然后把它传递进去。
Good-bye, Conditionals
My answer to this is maybe a little more contentious, but a lot shorter. You could take a look at multimethods in Ruby, but the crux of the idea is forgoing closed, hardcoded logic paths in favour of open ones and, in fact, plain ol' polymorphism achieves exactly this.
我对此的回答可能更有争议,但要短得多。您可以查看Ruby中的多方法,但是这个想法的关键是放弃封闭的、硬编码的逻辑路径,而选择开放的逻辑路径,事实上,plain ol的多态性实现了这一点。
Whenever you call some object's method instead of switching on its type, you're taking advantage of Ruby's type-based rule system instead of hardcoding a logic path. Obviously, this:
每当您调用某个对象的方法而不是打开它的类型时,您都是在利用Ruby的基于类型的规则系统,而不是硬编码逻辑路径。显然,这样的:
class Dog
end
class Cat
end
class Bird
end
puts case Bird.new
when Dog then "bark"
when Cat then "meow"
else "Oh no, I didn't plan for this"
end
is less open than this:
不像这样开放:
class Dog
def speak
"bark"
end
end
class Cat
def speak
"meow"
end
end
class Bird
def speak
"chirp"
end
end
puts Bird.new.speak
Here, polymorphism's given us a means of describing how the system behaves with different data that allows us to introduce new behaviour for new data on a whim. So, great job, you're (hopefully) avoiding conditionals every day!
在这里,多态性为我们提供了一种方法来描述系统使用不同数据时的行为,这些数据允许我们为突发奇想的新数据引入新的行为。所以,干得好,你(希望如此)每天都避免使用条件句!
#2
4
Neither of these two points are terrifically well-embodied by Haskell. I think Haskell still leads to somewhat uncomplected code, but approaches the whole problem with both a different philosophy and different tools.
这两点都不是哈斯卡尔完美地体现出来的。我认为Haskell仍然会导致一些不完整的代码,但是使用不同的哲学和不同的工具来解决整个问题。
Queues
队列
Roughly, Hickey wants to point out that if you are writing a method on an object which calls another object
大致说来,Hickey想指出,如果您正在一个对象上编写一个方法,该对象调用另一个对象
class Foo
def bar(baz)
baz.quux
end
end
then we've just hard-coded the notion that whatever gets passed into Foo#bar
must have a quux
method. It's a complection in his point of view because it means that Foo
's implementation is inherently tied to the implementation of how an object passed to Foo#bar
is implemented.
然后我们硬编码了输入Foo#bar的任何东西都必须有一个quux方法。在他看来,这是一种补充,因为这意味着Foo的实现本质上与传递给Foo#bar的对象是如何实现的实现相关联。
This is less a problem in Ruby where method invocation is much more like a dynamically dispatched message being send between objects. It simply means that an object passed to Foo#bar
must somehow respond responsibly when given the quux
message, not much more.
这在Ruby中不是什么问题,在Ruby中,方法调用更像是在对象之间发送的动态发送消息。它只是意味着传递给Foo#bar的对象在给定quux消息时必须以某种方式负责任地响应,而不是更多。
But it does imply sequentiality in message handling. If you instead sent the message down a queue to eventually be delivered to the resulting object then you could easily place an intermediator at that seam---perhaps you want to run bar
and quux
concurrently.
但它确实意味着消息处理的顺序性。如果相反,您将消息发送到一个队列中,以便最终交付给结果对象,那么您就可以轻松地在该seam中放置一个中间体——也许您希望同时运行bar和quux。
More than Haskell, this idea is taken to a logical extreme in Erlang and I highly recommend learning how Erlang solves these kinds of issues.
除了Haskell,这个想法在Erlang中达到了逻辑的极限,我强烈建议学习Erlang是如何解决这些问题的。
spawn(fun() -> Baz ! quux)
Rules
规则
Hickey repeatedly stresses that particular, hard-coded methods of doing branching complect things. To point, he doesn't enjoy case statement or pattern matching. Instead, he suggests Rules, by which I assume he means "production rules" systems. These produce choice and branching by allowing a programmer to set up a set of rules for when certain actions "fire" and then waiting until incoming events satisfy sufficient rules to cause actions to fire. The most well-known implementation of these ideas is Prolog.
Hickey反复强调,做分支的特定硬编码方法与事情相辅相成。要指出的是,他不喜欢案例陈述或模式匹配。相反,他提出了规则,我认为他指的是“生产规则”系统。通过允许程序员为特定的动作“触发”设置一组规则,然后等待传入的事件满足足够的规则,从而产生选择和分支。这些想法最著名的实现是Prolog。
Haskell has pattern matching built deeply into its soul, so it's hard to argue that Haskell immediately decomplects in this way... but there is a really good example of a rules system alive in Haskell—type-class resolution.
Haskell的灵魂深处已经有了模式匹配,所以很难断言Haskell会立即以这种方式分解……但是有一个很好的例子说明在Haskell-type-class解析中存在一个规则系统。
Probably the best known notion of this is mtl
-style typeclasses where you end up writing functions with signatures like
最著名的概念可能是mtl样式的类型设置,您最终将使用签名编写函数
foo :: (MonadReader r m, MonadState s m, MonadIO m, MonadCatch m)
=> a -> m b
where foo
is completely polymorphic in the type m
so long as it follows certain constraints—it must have a constant context r
, a mutable context s
, the ability to execute IO
, and the ability to throw and catch exceptions.
如果foo在类型m中完全是多态的,只要它遵循一定的约束——它必须有一个常量上下文r,一个可变的上下文,执行IO的能力,以及抛出和捕获异常的能力。
The actual resolution of which types instantiate all of those constraints is solved by a rules system often (fondly or otherwise) called "type class prolog". Indeed, it's a powerful enough system to encode entire programs inside of the type system.
实际的解决方案类型实例化所有这些约束是通过一个规则系统来解决的,这个规则系统通常被称为“类型类prolog”。实际上,它是一个足够强大的系统,可以在类型系统中对整个程序进行编码。
It's actually really nice and gives Haskell a sort of natural dependency-injection style as described by the mtl
example above.
它实际上非常好,并给Haskell提供了一种像上面的mtl示例所描述的自然依赖注入风格。
I think, though, that after using such a system for a long time most Haskellers come to understand that while rules systems are clever sometimes... they also can easily spin out of control. Haskell has a lot of careful restrictions to the power of type class prolog which ensure that it's easy for a programmer to predict how it will resolve.
然而,我认为,在长期使用这种系统之后,大多数Haskellers逐渐认识到,虽然规则系统有时很聪明……它们也很容易失去控制。Haskell对prolog类型的功能有很多谨慎的限制,这确保程序员很容易预测它将如何解析。
And that's a primary problem with rules systems at large: you lose explicit control over what actions end up firing... so it becomes harder to massage your rules to achieve the kind of result you expect. I'm not actually certain I agree with Rich here that rules systems thus lead to decomplection. You might not be explicitly branching off information tied to other objects, but you're setting up a lot of fuzzy, long-range dependencies between things.
这是整个规则系统的一个主要问题:你失去了对最终触发行为的明确控制……因此,要想达到你所期望的结果,你就很难按照你的规则行事。我不确定我是否同意Rich的观点规则系统会导致分解。您可能没有显式地将与其他对象绑定的信息进行分支,但是您正在设置许多模糊的、长期的依赖关系。
#3
1
Queues
Using queues means split program into several processes. For example one process that receive emails only and push them into "processing" queue. The other process pull from "processing" queue and transform message somehow, put into "outgoing" queue. This allows to easily replace some parts without touching other. You can even consider doing processing in other language if performance is bad. If you write e=Email.fetch; Processor.process(e)
you are couple all processes together.
使用队列意味着将程序分成几个进程。例如,一个进程只接收电子邮件并将它们推入“处理”队列。另一个进程从“处理”队列中取出并以某种方式转换消息,放入“传出”队列。这样可以很容易地替换某些部分而不触及其他部分。如果性能不好,您甚至可以考虑使用其他语言进行处理。如果你写e = Email.fetch;过程。过程(e)你是把所有的过程结合在一起。
Another advantage of queues is there may be many producers and consumers. You can easily "scale" processing part just by adding more "processing" processes (using threads, other machines etc). On the other hand you can launch more "email fetcher" processes too. This is complicated if you complect all in one call.
排队的另一个好处是可能有很多生产者和消费者。只需添加更多的“处理”进程(使用线程、其他机器等),就可以轻松地“扩展”处理部分。另一方面,您也可以启动更多的“电子邮件提取”过程。如果你在一个电话里把所有的电话都连接起来,这就很复杂了。
There is a simple queue in ruby http://ruby-doc.org/stdlib-1.9.3/libdoc/thread/rdoc/Queue.html and many others (rabbitmq, db-based etc)
ruby http://ruby-doc.org/stdlib-1.9.3/libdoc/thread/rdoc/Queue.html中有一个简单的队列(rabbitmq,基于db的等等)
Rules
Rules makes code uncomplicated. Instead of if-then-else you are encouraged to create a rules . Take a look at clojure core.match lib:
使代码简单的规则。看看clojure core。与*:
(use '[clojure.core.match :only (match)])
(doseq [n (range 1 101)]
(println
(match [(mod n 3) (mod n 5)]
[0 0] "FizzBuzz"
[0 _] "Fizz"
[_ 0] "Buzz"
:else n)))
You can write if(mod3.zero? && mod5.zero?) else if .... but it will be not so obvious and (more important) hard to add more rules.
你可以写如果(mod3.zero ?& & mod5.zero ?)else if ....但这并不是显而易见的,(更重要的)增加更多的规则也很难。
For ruby take a look at https://github.com/k-tsj/pattern-match although I didn't use such libraries in ruby.
对于ruby,请查看https://github.com/k-tsj/pattern-match,尽管我在ruby中没有使用这些库。
UPDATE:
更新:
In his talk Rich mentioned that prolog-like system can be used to replace Conditions with Rules. core.match is not so powerful as prolog but it can give you an idea of how conditions can be simplified.
Rich在他的演讲中提到,prologlike系统可以用来用规则替换条件。核心。match没有prolog那么强大,但它可以让您了解如何简化条件。
#1
16
Hello, Queues
The idea here is that, instead of passing a value directly from one object to another, we can decouple them by sticking a queue between them.
这里的想法是,我们可以通过在它们之间插入一个队列来解耦,而不是直接将值从一个对象传递到另一个对象。
Let's say we were modelling a farmer collecting the eggs from a chicken. The chicken produces eggs, the farmer collects them. A farmer's shift is finished when they've collected five eggs. Normally, we might write something like this:
假设我们在模拟一个农民从一只鸡身上收集鸡蛋。鸡产蛋,农民收集它们。一个农民的轮班结束时,他们已经收集了五个鸡蛋。通常,我们可以这样写:
class Chicken
def initialize(name)
@name = name
end
def lay_egg
sleep random(3)
"an egg from #{@name}"
end
end
class Farmer
def initialize(name, chicken)
@name = name
@chicken = chicken
end
def work_shift
5.times do
egg = @chicken.lay_egg
puts "#{@name} got #{egg}"
end
end
end
betsy = Chicken.new "Betsy"
fred = Farmer.new "Fred", betsy
fred.work_shift
So, the farmer waits by the chicken and picks up eggs as they come. Great, problem solved, go to the fridge and get a beer. But what if, say, we bought a second chicken to double our egg production? Or, what if we wanted to test our farmer's dexterity by having them pick up eggs from a carton?
于是,农夫就在鸡旁边等着,等它们来的时候就把鸡蛋捡起来。很好,问题解决了,去冰箱拿瓶啤酒。但是,如果我们买了第二只鸡,让我们的鸡蛋产量翻倍呢?或者,如果我们想让我们的农民从一个纸盒里拿起鸡蛋来测试他们的灵巧性呢?
Because we've coded the farmer to require a chicken, we've lost the flexibility we need to make these kind of decisions. If we can decouple them, we'll have a lot more freedom.
因为我们编码农民需要一只鸡,我们失去了做出这些决定所需的灵活性。如果我们能解耦它们,我们就有更多的*。
So, let's stick a queue between them. The chicken will lay eggs at the top of a chute; the farmer will collect eggs from the bottom of the chute. Neither party relies directly on the other. In code, that might look like this:
让我们在它们之间排个队。鸡会在溜槽顶部产卵;农民将从溜槽的底部收集鸡蛋。任何一方都不能直接依赖另一方。在代码中,可能是这样的:
class Chicken
def initialize(name, chute)
@name = name
@chute = chute
Thread.new do
while true
lay_egg
end
end
end
def lay_egg
sleep rand(3)
@chute << "an egg from #{@name}"
end
end
class Farmer
def initialize(name, chute)
@thread = Thread.new do
5.times do
egg = chute.pop
puts "#{name} got #{egg}"
end
end
end
def work_shift
@thread.join
end
end
chute = Queue.new
betsy = Chicken.new "Betsy", chute
fred = Farmer.new "Fred", chute
fred.work_shift
Except that now, we can easily add a second chicken. This is the stuff dreams are made of:
除了现在,我们可以很容易地添加第二个鸡肉。这就是梦的组成部分:
chute = Queue.new
betsy = Chicken.new "Betsy", chute
delores = Chicken.new "Delores", chute
fred = Farmer.new "Fred", chute
fred.work_shift
You could imagine how we might also, say, load up a chute with a bunch of eggs to test the farmer. No need to mock a chicken, we just prep a queue and pass it in.
你可以想象我们如何,比如说,装上一堆鸡蛋去测试农夫。没有必要嘲笑鸡,我们只是准备好队列,然后把它传递进去。
Good-bye, Conditionals
My answer to this is maybe a little more contentious, but a lot shorter. You could take a look at multimethods in Ruby, but the crux of the idea is forgoing closed, hardcoded logic paths in favour of open ones and, in fact, plain ol' polymorphism achieves exactly this.
我对此的回答可能更有争议,但要短得多。您可以查看Ruby中的多方法,但是这个想法的关键是放弃封闭的、硬编码的逻辑路径,而选择开放的逻辑路径,事实上,plain ol的多态性实现了这一点。
Whenever you call some object's method instead of switching on its type, you're taking advantage of Ruby's type-based rule system instead of hardcoding a logic path. Obviously, this:
每当您调用某个对象的方法而不是打开它的类型时,您都是在利用Ruby的基于类型的规则系统,而不是硬编码逻辑路径。显然,这样的:
class Dog
end
class Cat
end
class Bird
end
puts case Bird.new
when Dog then "bark"
when Cat then "meow"
else "Oh no, I didn't plan for this"
end
is less open than this:
不像这样开放:
class Dog
def speak
"bark"
end
end
class Cat
def speak
"meow"
end
end
class Bird
def speak
"chirp"
end
end
puts Bird.new.speak
Here, polymorphism's given us a means of describing how the system behaves with different data that allows us to introduce new behaviour for new data on a whim. So, great job, you're (hopefully) avoiding conditionals every day!
在这里,多态性为我们提供了一种方法来描述系统使用不同数据时的行为,这些数据允许我们为突发奇想的新数据引入新的行为。所以,干得好,你(希望如此)每天都避免使用条件句!
#2
4
Neither of these two points are terrifically well-embodied by Haskell. I think Haskell still leads to somewhat uncomplected code, but approaches the whole problem with both a different philosophy and different tools.
这两点都不是哈斯卡尔完美地体现出来的。我认为Haskell仍然会导致一些不完整的代码,但是使用不同的哲学和不同的工具来解决整个问题。
Queues
队列
Roughly, Hickey wants to point out that if you are writing a method on an object which calls another object
大致说来,Hickey想指出,如果您正在一个对象上编写一个方法,该对象调用另一个对象
class Foo
def bar(baz)
baz.quux
end
end
then we've just hard-coded the notion that whatever gets passed into Foo#bar
must have a quux
method. It's a complection in his point of view because it means that Foo
's implementation is inherently tied to the implementation of how an object passed to Foo#bar
is implemented.
然后我们硬编码了输入Foo#bar的任何东西都必须有一个quux方法。在他看来,这是一种补充,因为这意味着Foo的实现本质上与传递给Foo#bar的对象是如何实现的实现相关联。
This is less a problem in Ruby where method invocation is much more like a dynamically dispatched message being send between objects. It simply means that an object passed to Foo#bar
must somehow respond responsibly when given the quux
message, not much more.
这在Ruby中不是什么问题,在Ruby中,方法调用更像是在对象之间发送的动态发送消息。它只是意味着传递给Foo#bar的对象在给定quux消息时必须以某种方式负责任地响应,而不是更多。
But it does imply sequentiality in message handling. If you instead sent the message down a queue to eventually be delivered to the resulting object then you could easily place an intermediator at that seam---perhaps you want to run bar
and quux
concurrently.
但它确实意味着消息处理的顺序性。如果相反,您将消息发送到一个队列中,以便最终交付给结果对象,那么您就可以轻松地在该seam中放置一个中间体——也许您希望同时运行bar和quux。
More than Haskell, this idea is taken to a logical extreme in Erlang and I highly recommend learning how Erlang solves these kinds of issues.
除了Haskell,这个想法在Erlang中达到了逻辑的极限,我强烈建议学习Erlang是如何解决这些问题的。
spawn(fun() -> Baz ! quux)
Rules
规则
Hickey repeatedly stresses that particular, hard-coded methods of doing branching complect things. To point, he doesn't enjoy case statement or pattern matching. Instead, he suggests Rules, by which I assume he means "production rules" systems. These produce choice and branching by allowing a programmer to set up a set of rules for when certain actions "fire" and then waiting until incoming events satisfy sufficient rules to cause actions to fire. The most well-known implementation of these ideas is Prolog.
Hickey反复强调,做分支的特定硬编码方法与事情相辅相成。要指出的是,他不喜欢案例陈述或模式匹配。相反,他提出了规则,我认为他指的是“生产规则”系统。通过允许程序员为特定的动作“触发”设置一组规则,然后等待传入的事件满足足够的规则,从而产生选择和分支。这些想法最著名的实现是Prolog。
Haskell has pattern matching built deeply into its soul, so it's hard to argue that Haskell immediately decomplects in this way... but there is a really good example of a rules system alive in Haskell—type-class resolution.
Haskell的灵魂深处已经有了模式匹配,所以很难断言Haskell会立即以这种方式分解……但是有一个很好的例子说明在Haskell-type-class解析中存在一个规则系统。
Probably the best known notion of this is mtl
-style typeclasses where you end up writing functions with signatures like
最著名的概念可能是mtl样式的类型设置,您最终将使用签名编写函数
foo :: (MonadReader r m, MonadState s m, MonadIO m, MonadCatch m)
=> a -> m b
where foo
is completely polymorphic in the type m
so long as it follows certain constraints—it must have a constant context r
, a mutable context s
, the ability to execute IO
, and the ability to throw and catch exceptions.
如果foo在类型m中完全是多态的,只要它遵循一定的约束——它必须有一个常量上下文r,一个可变的上下文,执行IO的能力,以及抛出和捕获异常的能力。
The actual resolution of which types instantiate all of those constraints is solved by a rules system often (fondly or otherwise) called "type class prolog". Indeed, it's a powerful enough system to encode entire programs inside of the type system.
实际的解决方案类型实例化所有这些约束是通过一个规则系统来解决的,这个规则系统通常被称为“类型类prolog”。实际上,它是一个足够强大的系统,可以在类型系统中对整个程序进行编码。
It's actually really nice and gives Haskell a sort of natural dependency-injection style as described by the mtl
example above.
它实际上非常好,并给Haskell提供了一种像上面的mtl示例所描述的自然依赖注入风格。
I think, though, that after using such a system for a long time most Haskellers come to understand that while rules systems are clever sometimes... they also can easily spin out of control. Haskell has a lot of careful restrictions to the power of type class prolog which ensure that it's easy for a programmer to predict how it will resolve.
然而,我认为,在长期使用这种系统之后,大多数Haskellers逐渐认识到,虽然规则系统有时很聪明……它们也很容易失去控制。Haskell对prolog类型的功能有很多谨慎的限制,这确保程序员很容易预测它将如何解析。
And that's a primary problem with rules systems at large: you lose explicit control over what actions end up firing... so it becomes harder to massage your rules to achieve the kind of result you expect. I'm not actually certain I agree with Rich here that rules systems thus lead to decomplection. You might not be explicitly branching off information tied to other objects, but you're setting up a lot of fuzzy, long-range dependencies between things.
这是整个规则系统的一个主要问题:你失去了对最终触发行为的明确控制……因此,要想达到你所期望的结果,你就很难按照你的规则行事。我不确定我是否同意Rich的观点规则系统会导致分解。您可能没有显式地将与其他对象绑定的信息进行分支,但是您正在设置许多模糊的、长期的依赖关系。
#3
1
Queues
Using queues means split program into several processes. For example one process that receive emails only and push them into "processing" queue. The other process pull from "processing" queue and transform message somehow, put into "outgoing" queue. This allows to easily replace some parts without touching other. You can even consider doing processing in other language if performance is bad. If you write e=Email.fetch; Processor.process(e)
you are couple all processes together.
使用队列意味着将程序分成几个进程。例如,一个进程只接收电子邮件并将它们推入“处理”队列。另一个进程从“处理”队列中取出并以某种方式转换消息,放入“传出”队列。这样可以很容易地替换某些部分而不触及其他部分。如果性能不好,您甚至可以考虑使用其他语言进行处理。如果你写e = Email.fetch;过程。过程(e)你是把所有的过程结合在一起。
Another advantage of queues is there may be many producers and consumers. You can easily "scale" processing part just by adding more "processing" processes (using threads, other machines etc). On the other hand you can launch more "email fetcher" processes too. This is complicated if you complect all in one call.
排队的另一个好处是可能有很多生产者和消费者。只需添加更多的“处理”进程(使用线程、其他机器等),就可以轻松地“扩展”处理部分。另一方面,您也可以启动更多的“电子邮件提取”过程。如果你在一个电话里把所有的电话都连接起来,这就很复杂了。
There is a simple queue in ruby http://ruby-doc.org/stdlib-1.9.3/libdoc/thread/rdoc/Queue.html and many others (rabbitmq, db-based etc)
ruby http://ruby-doc.org/stdlib-1.9.3/libdoc/thread/rdoc/Queue.html中有一个简单的队列(rabbitmq,基于db的等等)
Rules
Rules makes code uncomplicated. Instead of if-then-else you are encouraged to create a rules . Take a look at clojure core.match lib:
使代码简单的规则。看看clojure core。与*:
(use '[clojure.core.match :only (match)])
(doseq [n (range 1 101)]
(println
(match [(mod n 3) (mod n 5)]
[0 0] "FizzBuzz"
[0 _] "Fizz"
[_ 0] "Buzz"
:else n)))
You can write if(mod3.zero? && mod5.zero?) else if .... but it will be not so obvious and (more important) hard to add more rules.
你可以写如果(mod3.zero ?& & mod5.zero ?)else if ....但这并不是显而易见的,(更重要的)增加更多的规则也很难。
For ruby take a look at https://github.com/k-tsj/pattern-match although I didn't use such libraries in ruby.
对于ruby,请查看https://github.com/k-tsj/pattern-match,尽管我在ruby中没有使用这些库。
UPDATE:
更新:
In his talk Rich mentioned that prolog-like system can be used to replace Conditions with Rules. core.match is not so powerful as prolog but it can give you an idea of how conditions can be simplified.
Rich在他的演讲中提到,prologlike系统可以用来用规则替换条件。核心。match没有prolog那么强大,但它可以让您了解如何简化条件。