New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revisit can-connect #288

Open
chasenlehara opened this Issue May 5, 2017 · 2 comments

Comments

Projects
None yet
4 participants
@chasenlehara
Member

chasenlehara commented May 5, 2017

Epic for a new version of can-connect.

This epic needs to be renamed to the actual version number. 馃槉

Related issues: #247 - superMap should allow overriding behaviors to be added at config time.

@eben-roux

This comment has been minimized.

Show comment
Hide comment
@eben-roux

eben-roux Jul 22, 2017

I noticed this epic issue on gitter and thought I'd give my ZAR0.02.

The can-connect implementation seems to loosely follow the active record pattern. I do not particularly like this but it isn't a train smash. Since I tend to place particular focus on my domain modeling I prefer the repository pattern. We can substitute all the "data access" bits with a rest endpoint. The behaviours appear to be along the lines of pipes and filters.

You may be thinking "this guy is pattern crazy!" but actually I'm not really. It is more a case of these things being around for a while and folks have come up with names for them.

In my service bus and event sourcing mechanism I make use of an observable pipeline that loosely follows the "pipes and filters" pattern. For "significant" processing I make use of a pipeline. For instance, when retrieving a message from a queue I use the InboxMessagePipeline that derives from a ReceiveMessagePipeline.

The issue I had was that a true pipes and filters mechanism isn't easily extendible. In the Asp.Net world the application has a number of events in its pipeline. The idea is that you can register other objects such as handlers and modules that then hook into the pipeline. Even in this mechanism there is no way to add to the events since it is a rather fixed business. This means that when event-x is raised all the objects that listen out for that event are called in the order that they are registered. Now if I need to have finer control over this ordering then things get a bit tricky.

In my pipeline implementation the first thing that is required is to register all the events in the order that they occur. This is the "fixed" portion that is always required. After that I register the observers that listen out for the relevant events. Granted, this is in a typed world where things are related to each other in a way somewhat different from what happens in JavaScript. What this does buy one, however, is that anyone making use of this software can hook into the PipelineFactory to make changes to any newly created pipeline. New events can be added into the pipeline or observers registered.

When the pipeline executes all it does is run through the list of events and calls each observer that listens to that event.

Currently can-connect seems to have a strict ordering of the behaviours (filters). Adding my own behaviour inbetween is going to be tricky. Following an event-based approach one could place then in order also:

connect.events = ["cache","url","parse","cache-requests","combine-requests","constructor","store","map","ref","fall-through-cache",...];

However, one could go a step further and go for a per-pipeline approach since there is somewhat of a difference between POST, GET, and DELETE for instance.

In this way it would be possible to add an event say using something like connect.post.events.add('serialize').before('post'); or some such.

Calling the events on any observers is where it is somewhat more tricky. In C# (or most typed OO languages) we have interfaces so it is a matter of casting an observer to check whether it is listening out for an event. In JavaScript this doesn't exist. Instead there will have to be some other way to do so:

observer.call(this, 'on', event);	// would require switch internally

if (observer['on' + eventName]) {
	observer['on' + eventName].call(this, event); // more of a convention-based approach
}

Perhaps there are other ways also that I cannot think of straight away.

Anyway, I thought I'd put this down and see if it resonantes with anyone :)

I noticed this epic issue on gitter and thought I'd give my ZAR0.02.

The can-connect implementation seems to loosely follow the active record pattern. I do not particularly like this but it isn't a train smash. Since I tend to place particular focus on my domain modeling I prefer the repository pattern. We can substitute all the "data access" bits with a rest endpoint. The behaviours appear to be along the lines of pipes and filters.

You may be thinking "this guy is pattern crazy!" but actually I'm not really. It is more a case of these things being around for a while and folks have come up with names for them.

In my service bus and event sourcing mechanism I make use of an observable pipeline that loosely follows the "pipes and filters" pattern. For "significant" processing I make use of a pipeline. For instance, when retrieving a message from a queue I use the InboxMessagePipeline that derives from a ReceiveMessagePipeline.

The issue I had was that a true pipes and filters mechanism isn't easily extendible. In the Asp.Net world the application has a number of events in its pipeline. The idea is that you can register other objects such as handlers and modules that then hook into the pipeline. Even in this mechanism there is no way to add to the events since it is a rather fixed business. This means that when event-x is raised all the objects that listen out for that event are called in the order that they are registered. Now if I need to have finer control over this ordering then things get a bit tricky.

In my pipeline implementation the first thing that is required is to register all the events in the order that they occur. This is the "fixed" portion that is always required. After that I register the observers that listen out for the relevant events. Granted, this is in a typed world where things are related to each other in a way somewhat different from what happens in JavaScript. What this does buy one, however, is that anyone making use of this software can hook into the PipelineFactory to make changes to any newly created pipeline. New events can be added into the pipeline or observers registered.

When the pipeline executes all it does is run through the list of events and calls each observer that listens to that event.

Currently can-connect seems to have a strict ordering of the behaviours (filters). Adding my own behaviour inbetween is going to be tricky. Following an event-based approach one could place then in order also:

connect.events = ["cache","url","parse","cache-requests","combine-requests","constructor","store","map","ref","fall-through-cache",...];

However, one could go a step further and go for a per-pipeline approach since there is somewhat of a difference between POST, GET, and DELETE for instance.

In this way it would be possible to add an event say using something like connect.post.events.add('serialize').before('post'); or some such.

Calling the events on any observers is where it is somewhat more tricky. In C# (or most typed OO languages) we have interfaces so it is a matter of casting an observer to check whether it is listening out for an event. In JavaScript this doesn't exist. Instead there will have to be some other way to do so:

observer.call(this, 'on', event);	// would require switch internally

if (observer['on' + eventName]) {
	observer['on' + eventName].call(this, event); // more of a convention-based approach
}

Perhaps there are other ways also that I cannot think of straight away.

Anyway, I thought I'd put this down and see if it resonantes with anyone :)

@nlundquist

This comment has been minimized.

Show comment
Hide comment
@nlundquist

nlundquist Aug 1, 2017

Contributor

Thanks for the feedback @eben-roux I'll look through the patterns you've linked and see if there is anything we can learn from them. The terminology is useful at least.

Regarding the difficulty with ordering behaviors (events as you phrase them) and their implementations (observers in your example), this is something we've put some effort into but we haven't yet found a solution we like yet. Your approach is interesting and something we'll keep in mind when revisiting this issue. A difficulty is that we actually have multiple "pipelines" and some stages of a pipeline extend previous ones and other override the previous behaviors altogether.

We hoped to remove the need for a canonical ordering of behaviors altogether, instead algorithmically determining how behaviors need to be ordered, however due to the high difficulty of doing that we may ultimately take another approach.

I've opened #335 to capture further discussion on this particular improvement.

Contributor

nlundquist commented Aug 1, 2017

Thanks for the feedback @eben-roux I'll look through the patterns you've linked and see if there is anything we can learn from them. The terminology is useful at least.

Regarding the difficulty with ordering behaviors (events as you phrase them) and their implementations (observers in your example), this is something we've put some effort into but we haven't yet found a solution we like yet. Your approach is interesting and something we'll keep in mind when revisiting this issue. A difficulty is that we actually have multiple "pipelines" and some stages of a pipeline extend previous ones and other override the previous behaviors altogether.

We hoped to remove the need for a canonical ordering of behaviors altogether, instead algorithmically determining how behaviors need to be ordered, however due to the high difficulty of doing that we may ultimately take another approach.

I've opened #335 to capture further discussion on this particular improvement.

@bgando bgando self-assigned this Aug 2, 2017

@bgando bgando removed their assignment Aug 31, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment