On Dec 14, 2009, at 8:56 AM, Emmanuel Lcharny wrote:
Not necessarily, for three reasons :
1) if the chain is fixed at startup, you can't anymore inject a
LoggingFilter when the server is running. You can only activate or
desactivate it. Not that it's realy a big issue, but it may help
in some case (that also mean we have a way to control the
execution. JMX ?)
One normally doesn't turn on and off things like that on a per
message basis. What I mean by that is that each filter decides to
do what it needs to do. That includes logging. Constantly
injecting logging filters on an ad hoc basis is a very, very, poor
practice.
A very, very rare practice, hopefully :) Here, i'm not sure it worth
it anyway. I really think it's better to enable the filter instead
of injecting it dynamically. In any case, I'm ready to lose this
"feature"...
Agreed, not a very compelling use case.
2) Most important, if we don't have a clue about which is the next
filter in the chain, that leads to problem when debugging, as you
can't know which filter will be called. Ennoying
Sure you do. The chains are fixed. If you know what filter you
are and what state you're in you know what filter gets called next
from the perspective of the framework. From the perspective of the
filter you shouldn't care what's next, if you do then you've
introduce a brittle dependency. For me that;s usually a red flag
that I haven't thought through a design and it needs to be revisited.
Let me clarify my mind : when stepping through filters while
debugging, I want to be able to jump directly to the next filter. In
order to do that, code like :
Filter nextFilter = computeNext( session );
nextFilter.call( session );
is mandatory. I don't want to experiment the same pain as with
Spring, when I have to open two editors, one for my java code, and
another one to see what is supposed to be my SM. I went through this
pain so many times in the past with MINA that I don't want to suffer
such a pain again...
Yeah, nothing is more frustrating than stepping though layers of
container code. That's why I configure my debugger to skip those
chunks of code so it lands directly in my POJOs. Anyway, since the
chains are fixed the filter dispatching code is quite simple:
Filter current = filterChain[state, i++];
current.call(session);
3) Last, not least, we want to be able to call the next filter in
the middle of a processing :
messageReceived() {
do blah();
if ( condition ) {
do anotherBlah();
call Next filter();
} else {
do yetAnotherBlah();
call nextFilter();
}
do endingBlah();
}
That just tells me that you have mixed up two states into one and
that you need to expend a little more effort into your state
machine design.
From the user POV, it's way more easy to write code this way than to
create two (or more) states. The idea is to combine the state
machine vision with the chain vision. You can express everything
with a SM, and implement it in a simpler way...
Easy, yes, initially and if you're the only developer but not so much
more easier that your point is self evident. But remember, we all
agreed that the developer is doing this to create a state machine.
The above code is brittle and lacks the explicit states. I would
argue that it's an anti-pattern.
Not sure this is possible in another way than with those computed
nextFilter() inside the filters.
I agree but it's my contention that it's a bad practice that
supports an ill thought out protocol.
The biggest advantage is that it eases the implementor work most of
the cases.
IMO, it's sloppy and error prone and obfuscates code. If no one else
agrees then I'm happy to drop my point.
Now, it does not preclude that we should not allow someone to
implement his protocol using a complete state machine. May be we
should provide both mechanisms :
- one which is driven by the code (ie, the code 'pull' the next step),
- one which is driven by the state machine (your way).
I would argue against this. Mina is afflicted w/ bloat. One the
goals should be to get rid of as many useless "helpful" classes and
methods as we can. Either we all agree that adding filters in an ad
hoc manner is a best practice for network protocol state machines and
we loose the state machine or we agree that it's an anti-pattern that
should be avoided. If the community thinks that ad hoc filters are a
best practice I'm happy to drop my point.
(well, t's always possible to express this with more transitions
and states, but t would be more complicated to write filters
then...)
I'm looking at your messageReceived() method and am thinking that
you have provided me with a perfect example for state programming.
Only the original author of that method would know what's going on.
Most certainly :) However, this was a complex example, usually, it's
way more simple.
I don't think it's complex. The point I was trying to make is that
it's a brittle and obfuscated implementation of a state machine by its
very nature.
I don't say that you are plain wrong, in fact, I share most of your
vision, but I'm just wondering if this would not render the protocol
implementors way more complex.
I may try to see what would be the impact of the plain SM approach
when applied on the current implemented protocols.
I totally agree with this approach to deciding on the API and am happy
to help out w/ some protocols, e.g. HTTP and SSL.
I am curious, what project feels that it needs to do an "implicit"
state machine? I would love to take a peek at the code.
Regards,
Alan