Folder structure

jadd's Avatar

jadd

08 Mar, 2010 04:45 PM

Hello all.
I know It could be a silly question but I would like to know how do you organize your folder structure in RL. I've seen in all the examples around many different implementations. Is there a best practice folder structure? Could be nice to have a common structure. Thanks.

  1. 1 Posted by Samuel Asher Ri... on 09 Mar, 2010 02:19 PM

    Samuel Asher Rivello's Avatar

    I'm a PureMVC expert converting to RL. Here is the structure I'm using. I'd love to hear from others too.

    [com.domain.projects.projectname] [controller] * * MyCustomCommand.as [model] * * [events] * * * MyCustomModelEvent.as * * MyCustomModel.as [service] * * MyCustomService.as [view] * * [events] * * * MyCustomViewEvent.as * * [components] * * * MyCustomComponentUseInAUISomewhere.as * * [ui] * * * MyCustomComponentUI.as * * MyCustomComponentUIMediator.as *MyCustomContext.as

  2. 2 Posted by Samuel Asher Ri... on 09 Mar, 2010 02:22 PM

    Samuel Asher Rivello's Avatar

    [com.domain.projects.projectname]

    • [controller]

      • MyCustomCommand.as
    • [model]

      • [events]
        • MyCustomModelEvent.as
      • MyCustomModel.as
    • [service]

      • MyCustomService.as
    • [view]

      • [events]
        • MyCustomViewEvent.as
      • [components]
        • MyCustomComponentUseInAUISomewhere.as
      • [ui]
        • MyCustomComponentUI.as
      • MyCustomComponentUIMediator.as
    • MyCustomContext.as

  3. Support Staff 3 Posted by Joel Hooks on 09 Mar, 2010 05:25 PM

    Joel Hooks's Avatar

    I also add an events package under Services, but Samuel's structure is what I'd consider to be proper.

  4. 4 Posted by Samuel Asher Ri... on 10 Mar, 2010 10:08 PM

    Samuel Asher Rivello's Avatar

    Joel,

    Sounds good. Can you give an example or link to an example of why you'd need service events? I imagine a mediator and/or command calls methods on the service, the service calls methods on the model and the model is what sends events out (not the service.

    -Sam

  5. 5 Posted by rob on 11 Mar, 2010 11:22 PM

    rob's Avatar

    @Samuel,

    It's discussed at the very end of the Best Practices doc:

    "After the data has been converted to the objects specific to the application domain events are sent with strongly typed payloads to be immediately utilized by interested actors.

    Service Events

    The final corner of the service triad is the custom event. Without events, services are mute. Any work they might do will go unnoticed by the other application actors. A service will make use of custom events to provide itself with a voice to the broader application. Events [do] not have to be singular in purpose. If the service is transforming the data it can make use of a common event to dispatch strongly typed data to interested application actors."

    Services are like Models in that they manage data however a Service is going to be reaching outside of the application to get that data (like to Facebook or Flickr) whereas the Model is going to be dealing with data inside the application (a user's score for example). The example provided in the Best Practices describes a Service class which calls the Flickr API to retrieve some photos. When the photos are returned the Service uses a little factory method to turn those photos into something that the application can understand; in this case a Gallery object. The Service then dispatches a custom event to the rest of the app with the Gallery object as the payload. In this scenario the model is not involved at all.

  6. 6 Posted by Samuel Asher Ri... on 12 Mar, 2010 04:33 AM

    Samuel Asher Rivello's Avatar

    @Rob Dodson,

    Wow, killer information. My years of MVCS, led me to the practice of 'a model holds stuff', 'a view edits/requests the stuff', and if externalized data, 'the service fetches and fills the model with the stuff'.

    I see from your example there are two data-stores; a model for client-side data, and a service for server-fetched data. Thanks for the new perspective.

    Between MVCS where would a SQLite database sit for an AIR app? I am new to SQLite, but was thinking a service would hold the database. Methods on ther service fetch data from the DB and then pack it into the model. THe model dispatches 'stuff is ready for use' events.

  7. Support Staff 7 Posted by Joel Hooks on 12 Mar, 2010 04:40 AM

    Joel Hooks's Avatar

    http://github.com/joelhooks/robotlegs-examples-AddressBook/blob/mas...

    This is how I recommend handling SQLite access. Short answer is as a Service. Essentially any "outside" contact occurs in a service.

    I am going to strongly recommend against the concept of "two data stores". Your MVCS approach is correct. The service fetches and parses, but pushes it to the model as quickly as possible. The need for a service event would come into play if you wanted the service to announce that data was retrieved (to trigger a command that fills the model for example).

  8. 8 Posted by rob on 12 Mar, 2010 05:01 AM

    rob's Avatar

    So in the Best Practices example when the Service dispatches the following:
    dispatchEvent(new GalleryEvent(GalleryEvent.GALLERY_LOADED, gallery));
    That would trigger a command which would drop the gallery into a Model and then the Model would dispatch another event alerting the Mediator(s) to update their views?

  9. Support Staff 9 Posted by Joel Hooks on 12 Mar, 2010 05:11 AM

    Joel Hooks's Avatar

    http://github.com/robotlegs/robotlegs-demos-Bundle/blob/master/Flic...

    Ya, that is what it is doing in the actual demo app. A mediator also intercepts it and updates the view. I'm going to update the best practices soon to use the Address Book that I linked to above actually. I think it is a better app.

    Mainly the Service classes should store no state. That is the role of the model.

    (the service in the Image Gallery doesn't store state either, for what it is worth)

  10. 10 Posted by odoe on 12 Mar, 2010 07:39 AM

    odoe's Avatar

    I've started adopting a similar structure of the address book app linked above. In a particular case, what I've done is broken my app into main and module folders.
    com.domain.projectName.main
    com.domain.projectName.module1
    com.domain.projectName.module2 and so on.

    They aren't flex modules, just "tools" of the app.
    Each one has it's on mvcs structure. I finally broke it down this way after my folders got unwieldy and my context blew up like veruca salt.

  11. 11 Posted by Stray on 12 Mar, 2010 07:44 AM

    Stray's Avatar

    Just out of interest, do you use the restricted/ api folder split?

    I find the flex PMD check of restricted package classes being used outside their own package pretty reassuring!

  12. Support Staff 12 Posted by Stray on 12 Mar, 2010 07:54 AM

    Stray's Avatar

    On the same subject - I got into a query yesterday about whether a class which wraps a couple of timers and fires some custom events at intervals is a Model or a Service.

    There are a few different ways you can split those two.

    As Joel says - anything reaching outside the app is a Service.

    But what about async self-driven objects that don't contain any logic (ie aren't controller)?

    I like the second distinction that a Model doesn't update itself. Basically, unless you poke it, the model remains as it was the last time you checked it. It also never listens for framework events, so the only way to change a model is via its API.

    This makes the timer container a TimerService.

    It would be kind of fun to gather together all of this into a decision tree... uh... did I say fun? I mean useful... obviously.

  13. 13 Posted by jadd on 12 Mar, 2010 08:16 AM

    jadd's Avatar

    I'm glad to see that my initial "stupid" question provokes an interesting debate and the final note of Stray sounds very ... yes fun/useful.

  14. 14 Posted by odoe on 12 Mar, 2010 08:23 AM

    odoe's Avatar

    I'm not sure what you mean by restricted / api split. But I basically move all factory/helper/components that aren't app/framework specific to a library file, as all the apps I make are the same type of apps. I'm still fairly new to Flex/Flash and dev in general. Learning as I go and grow. I try to use internet osmosis to make me smarter.

    With the Timer situation, I would think that if the events being fired ultimately modify a Model, that would lead me to think of it as a Service.

  15. Support Staff 15 Posted by Stray on 12 Mar, 2010 08:40 AM

    Stray's Avatar

    Jadd - it sounded like such a simple question, eh? I think I will do that chart now...

    Odoe: Internet osmosis FTW! Agreed on the generics - they sit in a library for me too.

    The api / restricted split goes like this:

    com.domain.app.module1.api
         // contains events and interfaces which are 
         // to be accessed from other functional areas / modules
    
    com.domain.app.module1.restricted
        // contains mvcs packages which are for use 
        // within this functional area / module only
    

    The main benefit is that if you're collaborating (or even just busy!) then when module1 needs something relating to module2, the module2 dev (which could be you as well) doesn't need to dig in the mvcs packages of module1 to find which event/interface they should use... it's sitting in the api package. Usually my api packages don't have sub-packages, because there are only a few classes. Sometimes I further split them into events/interfaces.

    Also, you can use the (free) FlexPMD java tool to find any classes where you've imported a restricted class outside of its functional area. Particularly handy if you're co-developing - you can double check that you can change anything inside your module without impacting on the other modules around it.

  16. jadd closed this discussion on 15 Nov, 2010 09:44 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