Plugin architecture

2 views
Skip to first unread message

Jacob Wright

unread,
Sep 16, 2009, 11:30:26 AM9/16/09
to reflex-steer...@googlegroups.com
First off, let me say that I feel we're going in the right direction with the MVC component approach, and though we haven't solidified the details yet, the rest of the features should be decoupled enough that it doesn't matter the implementation. I just had this thought this morning and so wanted to get it out there first. Hope you don't mind. I'll get back to the mvc discussion next email. ;)

Problem
Flex has tried to build in all the common features they thought everyone would want to use. We know they've missed some: the ones we need for project X. We also know they've added to many: the ones we don't need for project X. If you want to add a new feature to all components in Flex you have to monkey patch it.

We need a plugin architecture. Something very simple and small that can listen to the component events and can also add API to the component.

Possible Solution
We could add features at runtime that initialized when set on the component and added API through a lookup. The implementation could be a small proxy object (hash map/associative array) called features. When you assign an "IFeature" to it, it will set the target of the IFeature to be the component. An example of how it would work is this:

list1.features.drag = new DragFeature();
list1.features.drag.enabled = true;
list1.features.drag.moveEnabled = true;

list2.features.drop = new DropFeature();
list2.features.drop.enabled = true;

and

mybutton.features.cursor.current = "busy";

The reason we would make the features object a proxy that sets the target rather than passing the target into the constructor would be so features could be added via styling, and/or so we could have a features factory that allowed setting up all the features for your system you want to be able to use.

Then you have pay-as-you-go, and you still have the ability to add new functionality to the entire component set. No more monkey patching. No more bloat for unused features. And the features object with a factory could probably be 1/2k or less I would bet. One small proxy class.

What do you think?

Jacob


Side note for Ben:
Tyler and I have talked about behaviors at times as add-on features. That's why we originally wanted an array of behaviors. But really, there is usually just one controller (behavior) per component that hooks up to the skin and handles user interaction. The add-on functionality is covered in this "features" concept or whatever other plugin architecture we end up going with.

Ryan Campbell

unread,
Sep 16, 2009, 11:47:34 AM9/16/09
to reflex-steer...@googlegroups.com
I don't see the difference between features and behaviors. There is no reason a component couldn't have multiple behaviors and would be the case 90% of the time.

Jacob Wright

unread,
Sep 16, 2009, 12:16:18 PM9/16/09
to reflex-steer...@googlegroups.com
I don't see the difference between features and behaviors. There is no reason a component couldn't have multiple behaviors and would be the case 90% of the time.

If we clump them together as the same thing, then we need to do behaviors in a way that you can easily access them for their API such as component.behaviors.drag.start() or something.

If we keep them separate, then one way to separate them mentally is to say, behaviors only deal with user-interaction and don't extend a component's API. Features extend the API, could deal with user-interaction or not, and act as plugins, not just MVC controllers.

If we want to put them together that could work, but I think it would be easier to keep them separate. A button can't be a button without its behavior. But it can be a button without drag-and-drop, or custom cursors, or special layout, etc. Maybe we even have tooltips be an extra feature that isn't included in the compile if you don't use them.

Are behaviors our plugin architecture?

Tyler Wright

unread,
Sep 16, 2009, 12:44:58 PM9/16/09
to reflex-steer...@googlegroups.com
This is a good discussion. Even though I know the general idea behind Behaviors I'm not entirely sure, on an implementation level, where everything belongs.

Ben Stucki

unread,
Sep 16, 2009, 4:54:19 PM9/16/09
to reflex-steer...@googlegroups.com
Yes, I think behaviors are our plugin architecture. We need to come up with a method of accessing them easily in both MXML and AS3, but I think there should only be one Behaviors/Controllers/Mixins/Whatever concept.

Jacob Wright

unread,
Sep 16, 2009, 5:03:33 PM9/16/09
to reflex-steer...@googlegroups.com
Yes, I think behaviors are our plugin architecture. We need to come up with a method of accessing them easily in both MXML and AS3, but I think there should only be one Behaviors/Controllers/Mixins/Whatever concept.

Ok, fair enough. I'd suggest the proxy implementation I was recommending for features. Then you can simply say component.behavior.dragndrop.dragEnabled = true; or component.behavior.selectable.selected = true;

It's easily stylable (when using styling), accessible, and easy to work with at runtime. Though, I'd be interested to hear other ideas. I know you've talked about using a utility Ben. Could you show examples of how that might work? Or any other ideas you've had.

Jacob

Jacob Wright

unread,
Sep 16, 2009, 6:58:52 PM9/16/09
to reflex-steer...@googlegroups.com
So, with a plugin architecture and having everything be pay-as-you-go, should we just make layouts be behaviors? You would then add VerticalLayout (an IBehavior) to a component and it would layout the children vertically. Why have a separate layout property. Why not drink our own cool-aid. If we add all our component features through the plugin architecture, then it will be easy for others to see how it is done and people won't feel they have to extend all the time to add functionality.

Jacob

Ben Stucki

unread,
Sep 16, 2009, 7:17:31 PM9/16/09
to reflex-steer...@googlegroups.com
I've heard this argument from Ryan too, who's been doing some experimenting with layouts and non-DisplayObject containers. I think the largest reason is because layout is not a behavior. It doesn't respond to user input or effect the data. In fact layout only effects how a component looks, so I would argue it belongs on the skin. The component should mostly care less about it (with some loosely coupled exceptions for measurement). - or to put it another way, just because you can doesn't mean you should. We are already drinking our own cool-aid by providing the default behaviors, and if anything I think this concept just makes me weary of how easy it is to abuse the mixin approach.

Jacob Wright

unread,
Sep 16, 2009, 7:52:09 PM9/16/09
to reflex-steer...@googlegroups.com
First, let me say I'm ok with putting layout on component or skin or wherever.

So, are behaviors plugins/add-on functionality, or are they controllers or both? Do we only support add-on functionality that is controller-like? We should have a plugin architecture that people can use for any type of added functionality. If we want to keep behaviors to a certain definition or standard, we should have some other way to add plugin functionality to components that is meant to be abused. We could still have the features object that adds non-behavior-like plugins. Just need a way to keep people from needing to monkey-patch when they want additional functionality.

As for layout, whether we consider that additional functionality or part of the core, I'm not really particular. It just occurred to me that layout could be considered an add-on and it might be interesting to explore that idea.

Jacob

Ben Stucki

unread,
Sep 16, 2009, 8:14:13 PM9/16/09
to reflex-steer...@googlegroups.com
What's a feature for the plugin architecture that adds functionality other than changing how a component looks, how it manages data, or how it responds to user input? :) For instance I would argue that the drag feature you referenced is a behavior - it responds to user interaction and likely effects the component data.

Jacob Wright

unread,
Sep 16, 2009, 8:22:40 PM9/16/09
to reflex-steer...@googlegroups.com
Tyler has written a "layout" object that isn't a layout in the traditional or Flex sense. It lays out the component it targets, not the component's children. It is outside the bounds of what our layout probably will cover, but is way useful. I would want to add it via a plugin architecture to many of my applications (personally I'd rather it just be built into the base component, but not everyone may like that). I don't know all the ways that people want to extend their components, but I would assume there may be other types.

Ben Stucki

unread,
Sep 16, 2009, 8:53:29 PM9/16/09
to reflex-steer...@googlegroups.com
I think this probably proves my earlier point. This custom layout would be specific to how a component looks, so it should be in the skin. Skin's are the plugin architecture for how a component looks. Otherwise we could just put skins into the behaviors object too right? (I'm hoping nobody jumps onboard with that idea)

Jacob Wright

unread,
Sep 16, 2009, 10:20:37 PM9/16/09
to reflex-steer...@googlegroups.com
I think this probably proves my earlier point. This custom layout would be specific to how a component looks, so it should be in the skin. Skin's are the plugin architecture for how a component looks. Otherwise we could just put skins into the behaviors object too right? (I'm hoping nobody jumps onboard with that idea)

Oooh, good idea! ;)

I would say that the functionality we want part of our component API, the functionality which is common enough that everybody will probably use it, we add to the component. Skin is obviously central to a component. The layout is almost always used and should be on component. Tooltip, maybe, maybe not. Cursors, probably not. Drag and drop, no.

So what are we looking at for our base Component class? Skin, behaviors, and layout? We can add others when they come up I suppose. Focus management methods may be there or in behaviors, but that will come later.

So we need to fill out the behaviors and interfaces for some basic components, right? Make sure it works well like we're planning. Then solidify the white paper a little more.

I'm excited about the way were going.

Ryan Campbell

unread,
Sep 17, 2009, 10:04:05 AM9/17/09
to reflex-steer...@googlegroups.com
I really think the base Component class should handle behaviors, skin, invalidation and stop at that. If you want to bake any layout logic in to the core it should be done at the skin level.

We also might want to reconsider a layout as a behavior (applied to the skin, not the component). Although it's not responding to user input it is listening for resize/redraw events and updating the position/size data. Behaviors are a great common way to not only to have plugin functionality but also allow them to be used on any object even completely independent of the Reflex framework.

Jacob Wright

unread,
Sep 17, 2009, 11:40:38 AM9/17/09
to reflex-steer...@googlegroups.com
On Thu, Sep 17, 2009 at 8:04 AM, Ryan Campbell <safari....@gmail.com> wrote:
I really think the base Component class should handle behaviors, skin, invalidation and stop at that. If you want to bake any layout logic in to the core it should be done at the skin level.

We also might want to reconsider a layout as a behavior (applied to the skin, not the component).

Behaviors have auto-wiring to the skin as well as the component, such as the thumb and track in a scrollbar skin. It wouldn't be difficult or a stretch. The problem with layout as a behavior is more with how you might feel about where it is at. I don't foresee any actual problems with it. Just might give some the heeby jeebies because they feel in the grand scheme of MVC it doesn't belong in the "C". But it seems we're not keeping behaviors to the strict Controller paradigm. And that's ok if it works.

If layout isn't a behavior, I would say we put it on the component. If it is part of the skin and you swap out your skin for a new theme, you've lost all your layouts.

Jacob

Tyler Wright

unread,
Sep 17, 2009, 1:31:09 PM9/17/09
to reflex-steer...@googlegroups.com
Behaviors have auto-wiring to the skin as well as the component, such as the thumb and track in a scrollbar skin. It wouldn't be difficult or a stretch. The problem with layout as a behavior is more with how you might feel about where it is at. I don't foresee any actual problems with it. Just might give some the heeby jeebies because they feel in the grand scheme of MVC it doesn't belong in the "C". But it seems we're not keeping behaviors to the strict Controller paradigm. And that's ok if it works.

I'm not so sure our Behaviors aren't within the Controller paradigm - only the Layout feature is something that deals with visual representation only and not user feedback.

Here is what I understand are the different pieces we've been discussing (not official to the reflex)

Component: the model, representing primary data and methods (and events), also including "skin" and "behavior" tie-in

Behavior: a controller, dealing with user interaction and updating the Component model, targets the Component via Interfaces

Feature: also a controller, dealing with user interaction but represented by its own model, has its own data and methods (and events)

Layout: as in Flex, targets children to visually arrange them uniformly, does not respond directly to user interaction, would always be part of the skin, unless some sort of Component-as-a-Container concept is developed (this has not been part of on-list discussions or established in the white paper)


Please clarify on any differences from your understanding.

Tyler

Jacob Wright

unread,
Sep 17, 2009, 1:58:44 PM9/17/09
to reflex-steer...@googlegroups.com
Component: the model, representing primary data and methods (and events), also including "skin" and "behavior" tie-in

Behavior: a controller, dealing with user interaction and updating the Component model, targets the Component via Interfaces

Feature: also a controller, dealing with user interaction but represented by its own model, has its own data and methods (and events)

Feature: Any add-on functionality that can be added to the components. Because they are user-interface components these often deal with user interaction, but it needs to be remembered that they don't always. An example might be adding advanced 3D support to the components. This is visual, not user interaction. We wouldn't want 3D to be added to the base because that would bloat it for the applications that don't use 3D. If we feel behaviors are being abused in scenarios like this, we should look at providing another place where plugins can be added. Features != controllers, but we could use the same mechanism to support both as long as we understand that a behavior can be anything, controller or not.
 
Layout: as in Flex, targets children to visually arrange them uniformly, does not respond directly to user interaction, would always be part of the skin, unless some sort of Component-as-a-Container concept is developed (this has not been part of on-list discussions or established in the white paper)

I agree with the rest.

Tyler Wright

unread,
Sep 17, 2009, 2:24:16 PM9/17/09
to reflex-steer...@googlegroups.com
On Thu, Sep 17, 2009 at 11:58 AM, Jacob Wright <jacw...@gmail.com> wrote:
Component: the model, representing primary data and methods (and events), also including "skin" and "behavior" tie-in

Behavior: a controller, dealing with user interaction and updating the Component model, targets the Component via Interfaces

Feature: also a controller, dealing with user interaction but represented by its own model, has its own data and methods (and events)

Feature: Any add-on functionality that can be added to the components. Because they are user-interface components these often deal with user interaction, but it needs to be remembered that they don't always. An example might be adding advanced 3D support to the components. This is visual, not user interaction. We wouldn't want 3D to be added to the base because that would bloat it for the applications that don't use 3D. If we feel behaviors are being abused in scenarios like this, we should look at providing another place where plugins can be added. Features != controllers, but we could use the same mechanism to support both as long as we understand that a behavior can be anything, controller or not.

Are there any "Features" that are not driven by user-interaction that we will release with our components? If not, I think 3D, Physics, Effects and other features are something that are up to the developer to tie in through extension or composition and not a plugin-in framework.

As for all features that deal with user interaction I keep going back to the same thought. Rather than making Behaviors completely dependent on a component model with a required Interface, the Behavior could be more encapsulated and independent. If the Behavior had all the data and methods it needed to function it could be 1) added to any DisplayObject, 2) added to a Component that doesn't care so much about implementing its Interface - Jac's example of dragging - and 3) testable. When a Behavior is added to a Component that shares an Interface then its properties are automatically bound. Components can become more capable but without cluttering their API with less-essential properties/methods.

thoughts?


Jacob Wright

unread,
Sep 17, 2009, 2:54:18 PM9/17/09
to reflex-steer...@googlegroups.com
Are there any "Features" that are not driven by user-interaction that we will release with our components? If not, I think 3D, Physics, Effects and other features are something that are up to the developer to tie in through extension or composition and not a plugin-in framework.

So the plugin framework is only for what we will add, and other features people are out in the cold? The whole reason for a plugin framework is to make it easy for developers to add things to the components that we didn't think of. Whether we clump it together with behaviors or make it a separate features object, we ought to have it and support it. The reason why I originally suggested a features object on component was so that behaviors could be the controller part of the MVC component and there didn't have to be a merging of the two concepts.

If we want behaviors to be the plugin framework, then one way we could organize it to keep things clear is we would have IBehavior, a base Behavior class that implements it, and then a base Controller class that extends Behavior and adds on the handy metadata listeners and skin hookups etc. Then a "behavior" is any add-on functionality, and a "controller" is just what you'd expect. Would that be an acceptable way to compartmentalize things?

If not, then I would like to have a features object on Component that allows for new functionality (physics would be cool!) without the concern of what their role is or where they fit into MVC.
 
As for all features that deal with user interaction I keep going back to the same thought. Rather than making Behaviors completely dependent on a component model with a required Interface, the Behavior could be more encapsulated and independent. If the Behavior had all the data and methods it needed to function it could be 1) added to any DisplayObject, 2) added to a Component that doesn't care so much about implementing its Interface - Jac's example of dragging - and 3) testable. When a Behavior is added to a Component that shares an Interface then its properties are automatically bound. Components can become more capable but without cluttering their API with less-essential properties/methods.

thoughts?

I like the interfaces. I think the controller should know the component's interface and be able to change its stage directly. I don't think two-way binding would buy us anything. If a component doesn't extend the IScrollable interface than what is a ScrollBehavior going to be able to do for it anyway?

Some behaviors will probably target display objects such as the DragBehavior because it only needs the interface of a display object. But others, such as ScrollBehavior ought to target IScrollable. IMO.

Jacob 

Jacob Wright

unread,
Sep 17, 2009, 5:35:56 PM9/17/09
to reflex-steer...@googlegroups.com
I was just trying to separate what adds API to a component vs what only responds to user interaction and updates component state/properties. I'm ok if we just use behaviors like we've talked about. We don't need to do anything special. I'm happy with it.
Reply all
Reply to author
Forward
0 new messages