structure and pattern for events

Enrique's Avatar

Enrique

06 Jun, 2011 06:38 PM

When we use robotlegs we necessary end with a lot of classes, and many of then event classes.
I'm really bad for organizing things (not only in code, you should see my room/house/garden/life ).
So I was looking for a good structure folder, pattern, and conventions for names, classes, etc.

I found this for folder structure:
http://knowledge.robotlegs.org/kb/reference-mvcs-implementation/rob...
and I'm using that, with some modifications, but after seeing some of the robotlegs examples I saw that structure is not always respected, I see very different structures too (something like modules I guess, with a MVC triad inside each principal component, I don't know).

I'm afraid I will end changing a lot of things or with a big mess, but for now I'm intrigued in how you organize your events.
I saw you often put an events folder inside "view", "model" and "service", I think you are putting events dispatched for those classes there. But I see there's an event folder in the root too, at the same level that "view" "model" etc.
What are the events saved there? that folder it's not present in the above recommended structure. Are these events dispatched by many classes?

Also, what is the reason for having different events folders? I think you have a reason for that, because for example flash is grouping all the events inside "flash.events"

Thanks!

  1. Support Staff 1 Posted by Stray on 06 Jun, 2011 06:46 PM

    Stray's Avatar

    Hi Enrique,

    I tend to ask the question "who owns this event?" and then use the answer to determine where I want to put the event.

    Sometimes an event is specific to a type of service - in which case putting that event inside the services package (or the services package within that feature package) seems like a good idea.

    However - if you have cross-feature events, and you're using the

    feature
        api
        restricted
    

    structure, then you need any events which are going to be used within another feature to be inside the api package and not the restricted package.

    I tend to use this set up, so my events generally end up in the api package by feature, and if there is much in that package then I'll sub package them however I think best describes the dichotomy. Perhaps just in an events package, or perhaps in `events / flow' etc.

    In the end, the first function of packages is to help the developer understand the relationships between the classes in the application. Any method that makes sense is viable IMO.

    Stray

  2. 2 Posted by Enrique on 10 Jun, 2011 04:27 PM

    Enrique's Avatar

    Hi @Stray, I was thinking in your suggestion, but I think I can't get it :(
    I feel that I'm duplicating classes, or making a real spaghetti, maybe with an example is easier:

    I have an event ProductEvent with a type GET, this event is saved in root / [events] folder. When I dispatch ProductEvent.GET a command is executed and get productos from a service.

    Then the command updates the model, and the model dispatch another event: ProductModelEvent.UPDATED, I'm saving ProductModelEvent inside [model] / [events].

    Then the user can change something in the view, and I need to update the model too. I need to dispatch an event from my mediator with the ProductVO, and that event should execute a command which updates the model.
    But what is this event?.
    a ViewEvent? [view] / [events] because is dispatched from mediator...
    a ModelEvent? [model] / [events] because is updating the model, and my ModelEvent has a "ProductVO" in it (as load).
    a CommandEvent? [events] because it executes a command and is similar to GET data.

    If I choose ViewEvent I feel that I'm messing the things, because I'm using ViewEvents for events dispatched from the view to the mediator.

    If I choose ModelEvent I feel that I'm messing the things, because I'm using the ModelEvents for events dispatched from the model.

    If I choose CommandEvent (ProductEvent) then I need to add a load data to that event, that is not needed for example in ProductEvent.GET. So it feels like those events are not of the same class...
    And the data load that I need to add is the same data load that have my ModelEvent ( ProductModelEvent ). So it feels like I'm repeating myself.

    And if I create a new CommandEvent, I feel that I will end with thousands of event classes with probably just one type.
    Even more, I don't know what name to use for that "new" event, ProductEvent2 ?

    Can you help to clear this mess? :(

  3. Support Staff 3 Posted by Stray on 10 Jun, 2011 08:25 PM

    Stray's Avatar

    Hi Enrique,

    I think first of all it would help to be more descriptive in naming your events.

    eg: Not ProductModelEvent, but ProductUpdateEvent

    Then I would choose names such as

    ProductRequestEvent (has no payload) and
    ProductCreatedEvent (when the data comes back from the service - containing the payload of the data.)

    It's ok to have a lot of different events. And the package you end up putting them in doesn't really matter.

    For myself - unless an Event is very clearly only for use in/by the view, or is very specific to the model or service that fires it, I just stick them in my controller package - not within model, view or service.

    If the nature of the Event is really different then I think it's better to have a new event than to make one event serve two purposes. The flash.events events are all messed up IMO.

    Stray

  4. 4 Posted by Enrique on 10 Jun, 2011 10:24 PM

    Enrique's Avatar

    really? it's OK if I have a lot of different Event classes? I mean, do you have a lot of Event classes with just one string constant inside that class?

    I don't know, maybe there's nothing wrong with having a different class for each type of event. But I don't know, DRY is surrounding my mine...

    this is what I have now:
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    src / events / ProductEvent
    types:
    GET: dispatched by mediator executes command for retrieving data from the service (I'm listening the result in my command with a promise).
    EDIT: dispatched by mediator executes command for editing model with local data.
    data load: Array (used only in EDIT)

    src / model / ProductModelEvent types:
    UPDATED: dispatched by model when data is setted
    EDITED: dispatched by model when data is edited
    data load: Array

    is your suggestion to change that to this?:
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    src / events / ProductRequestEvent type:
    REQUEST dispatched from mediator, executes command and retrieve data from service
    data load: none

    src / events / ProductEditEvent type:
    EDIT dispatched from mediator, executes command and edit model
    data load: Array

    // this is not changed:

    src / model / ProductModelEvent types:
    UPDATED: dispatched by model when data is setted
    EDITED: dispatched by model when data is edited
    data load: Array

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    I just one to find some type of pattern or convention, so I don't need to think everytime if I need to write a new event, and how should it be called, and where should I save it (package), etc.
    And also if in a few days I need to find an Event I know where to search, and what name to search (approximately at least).
    More if I need to work in a team.

  5. Support Staff 5 Posted by Stray on 11 Jun, 2011 09:40 AM

    Stray's Avatar

    Hi Enrique,

    I have hundreds of events in my larger projects. An event represents a change in state / user action / application incident etc.

    Adobe gave us the rather rubbish String based event system. Many of us don't really trust this approach (where you can accidentally have two events with the same name) and so the Robotlegs event system is built on strong typed events.

    This means that the event class is the most important indicator of the purpose of an event, and then the String Event.SOMETHING_HAPPENED constants are sub-divisions of that event class.

    Naming events is hard - it will never be easy, so I'd just go with the most descriptive names you can think of, and make sure you have good refactoring tools :)

    My own naming-refactoring policy is that if I accidentally type or think something different from what I've currently named the variable, class or function, often this is a good indicator to change its name.

    For example - yesterday I was writing some code for a mosaic application. I had TileView and one of the parameters was dimensions:Number. Then in my tests I automatically started writing tileSize instead of dimensions and I realised that this was a better description.

    I would still rename ProductModelEvent to ProductUpdateEvent - and also there's a convention that your type constants should be in past tense, so I would go with:

    ProductRequestEvent.PRODUCT_REQUESTED
    ProductEditEvent.PRODUCT_EDITED
    

    Because these read like real conversation and less like code.

    But that's just my preference.

    In terms of where to put them, if you are worried about it then I would just put all your events in packages like this:

    com/project/controller/events/product
    com/project/controller/events/startup
    com/project/controller/events/... etc
    

    This way if someone is looking for them then they are only going to be moving between one layer of folders.

    HTH

    Stray

  6. 6 Posted by Enrique on 11 Jun, 2011 03:11 PM

    Enrique's Avatar

    Well, maybe I need to be less paranoid and to lose my fear about having hundreds of classes with just one type of event inside it.

    About using Past Tense, I was using irregular verbs for noting that an action is not made yet, if I follow your Past Tense rule the I have two events with the same name:

    I need to convert this:
    ProductEvent.EDIT (execute command for editing model)
    ProductModelEvent.EDITED (dispatched by model after edition)
    to just this?
    ProductEditEvent.PRODUCT_EDITED

    I think to have the events in the same folder is better (and make the separation with subfolders there).
    I just started in the other way because this article:
    http://knowledge.robotlegs.org/kb/reference-mvcs-implementation/rob...
    Maybe we need to change that :(

    Thanks @Stray !

  7. 7 Posted by krasimir on 04 Sep, 2011 06:12 PM

    krasimir's Avatar

    Hello,

    I think that it is better to put all the events in one folder. I mean, of course, you can create sub-directories for better organization but to store them in one place. For me, the good named event is better then the good file path (i.e. ProductsActionsEvent looks better then com.project.services.products.events.ActionEvent). Of course we can't generalize and just say what is right or wrong. It's more like a personal choice and project specifics. Usually my events are stored in com.project.controllers.events.
    Sometimes I prefer to add an additional parameter to the constructor of the class. For example:
    public class ProductEvent(type:String, data:* = null) { ...
    So if you have an event ProductEvent.GET you will discard the data parameter. If you have an event ProductEvent.UPDATED then you will use the "data" to send the updated information. Using that method you will not need to create a new event for every action. It just depends on your project. The workflow described above is not always useful. Sometimes is really wrong. Especially if you mix the responsibilities of your classes ;)

  8. Support Staff 8 Posted by Joel Hooks on 04 Sep, 2011 10:55 PM

    Joel Hooks's Avatar

    I think that it is better to put all the events in one folder

    I disagree with this. I've seen what this approach leads to, and it is never pretty in a non-trivial app. I want my events (and all of my classes really) as close to their owner as possible. Events that are part of the model (announcing changes to the model) BELONG to the model, and not to the feature. The length of the package/namespace is completely aesthetic. If it is long because it is descriptive of where the event is owned, I favor clarity of looks every time.

    I'm a strident single TYPE event class user. Allowing arbitrary/optional arguments leads to conditional logic leads to muddled code and complete disregard for SRP. Event classes become dumping grounds for any marginally related behavior. I don't have a problem with many classes as much as I have a problem with classes that have too much responsibility or are not easily describable in terms of the behaviors they express. I don't want "this event is dispatch when something happens to x" - I want "this event is dispatched when z happens to x" - specificity. mmm

    So I end up putting the events package in the model/view/controller/service packages and evaluate where the event should be owned. It prevents the MONOLITHIC event packages that are hard to understand and provides clear cognitive separation between the events in a given functional area.

  9. 9 Posted by krasimir on 07 Sep, 2011 06:53 AM

    krasimir's Avatar

    Hi Joel, good points. I'll use your advice in my next project ;)

  10. 10 Posted by visnik on 09 Sep, 2011 01:44 AM

    visnik's Avatar

    I jumped back and forth between placing all events in one package and placing them with their owner. After reading Stray's and Joel's book, I am fully convinced they should be placed with their owners. I am currently planning the package structure for a very large project, I will be using a events to their owner approach. My 2 cents

  11. Ondina D.F. closed this discussion on 16 Nov, 2011 09:19 AM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac