Skip to content
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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discussion: Restructuring of Modules #859

Closed
1 of 3 tasks
jamesplease opened this issue Jan 13, 2014 · 16 comments
Closed
1 of 3 tasks

Discussion: Restructuring of Modules #859

jamesplease opened this issue Jan 13, 2014 · 16 comments
Milestone

Comments

@jamesplease
Copy link
Member

Modules do a lot right now. They can be used for namespacing code and soon as UI/widget components.

There has been discussion about restructuring modules for version 2 of Marionette.

This issue can be used as a place of discussion for what needs to be done. Some questions:

  • What, exactly, are all of the things modules are used for?
  • What's a logical way to break them apart?
  • If breaking apart does occur, what should the names of the new objects be?

// @cobbweb @samccone


TL;DR

I'm still unsure why @derickbailey suggested split them into more than 2 things, but the consensus of this conversation thus far has been that at least 2 things make sense. Modules for code organization; Components for UI widgets.

@jamesplease
Copy link
Member Author

It might make sense to have two distinct things: a name-space / code-organizing class, and a widget class.

Naming

I like Module more for a widget than I do a code-organization, but there might be reluctance to switch up the name for the long-standing role of Modules. If changing the name is an option, one idea would be Sub-Applications and Modules. If the name change isn't deemed a good idea, something like Modules and Components could be used instead. Another option might be Block, but I like that one less.

Some possible properties:

Shared properties
Both are added and removed from Applications in a similar way that Modules are attached currently; a function that exists an arbitrary name and then some definition

Modules (code organizers)
Can't be extended. Basically behave as Modules did before I introduced #837. The recursive creation will occur when you name then with period-separated names, for instance.

Components (widget things)
Can be extended, but don't nest when you name them with period-separated names, making them more like Item Views and so on.

@rhubarbselleven
Copy link
Contributor

What would the definition of a Module be? Proposed vs Current

@jamesplease
Copy link
Member Author

The post I made assumes that a module, currently, has two main functions as part of its definition: it is an object that can be used to namespace code, and it can be used to build a widget with.

The proposed idea is to split these out into two separate things. @derickbailey proposed three separate things in this blog post (read: What's Next), and I'm sure he has a much better understanding of Marionette than I do, so perhaps it would even make sense to split it apart further.

@andru
Copy link

andru commented Jan 17, 2014

I use Modules in the sub-application context you're referring to, and for which the current pattern is well suited.

I use them as lazy-loading sub-applications. I've made some tweaks to Marionette.Module so that Modules can declare dependencies on other modules - ie. Blog requires Users - so when loading Blog, it will automatically load the Users module first. This lazy-loading combined with asynchronous module dependencies ( #792 ) provides a pretty decent platform for managing larger modular applications without just loading everything into memory at init or manually managing module dependencies in code.

I've rolled my own concept of Components which is basically just a controller with it's own view/model/collection objects. It works pretty well for my needs, at least. I don't see the need to use Marionette.Module here, but I certainly support adding some concept of Component to core.
In my case these are usually things like:

  • Simple common UI elements: show/hide password field, modals - for this sort of component I've often just used a View object and a template
  • Complex common UI: Multi-user messaging - a controller with it's own views, templates, models, and collections. User models are attached using adaptors.
  • Common functionality: User sign-in - a controller with it's own views, models, and templates. Again, adaptors are used to connect to Module user models.

For my usage of components, they are not attached to the Application object, but I'm using requirejs to load them where they're needed. I guess without requirejs they would need to be registered somewhere on the application namespace.

It absolutely makes sense that these should be extendable, and indeed I've often done so (ie. LoginModal extends Modal).
Even further, I think ideally Components should be shareable. It should be easy to extend them, easy to use them with any application via the use of adaptors, and easy to style them. There's no reason why a user-chat component I build for my application shouldn't be a more-or-less drop-in component for someone else's application.
A Marionette component library could be a beautiful thing :)

I think Component is a pretty well established term for collections of re-usable ui elements, and Module is equally well established when referring to large chunks of an application. To me Sub-Application for the latter and Modules for the former is a confusing break from what is, to my experience, pretty standard terminology.

@paulovieira
Copy link
Contributor

I totally agree with andru. I always think of "component" as some independent UI piece that can be added to any application. Like a small plug-in. And "module" as something that allows me to organize my code (it might not be related to UI at all).

Other libraries are using the terms with those meanings (Polymer Project, ReactJS, etc).

It's great to see the Marionette.Module growing (both here and in #792), but it's important to choose correct names.

@andrewhubbs
Copy link
Contributor

@andru I'd be interested to know more about how you are extending Module to allow dependencies. Would you mind expanding on that or posting a gist of what you're doing?

@andru
Copy link

andru commented Jan 17, 2014

@andrewhubbs I warn you it's not the prettiest implementation, but it works... It's dependent on the asynchronous initializers in #792 https://gist.github.com/andru/8477224

@andrewhubbs
Copy link
Contributor

Thanks @andru. I'll take a look.

@jamesplease
Copy link
Member Author

@jasonLaster and I had some good chats today about this topic. I realized when using the Module shortcut method to create a deeply-nested Module that it was applying my custom class to every parent module that it was creating.

// If users and profiles don't exist, they will be instantiated as a SettingsModule
app.module( 'users.profiles.settings', {
  moduleClass: SettingsModule
}); 

This is not documented per se, so it's difficult to say whether it's a bug or a feature of Modules. Either way, as @jasonLaster put it it's another nail in the coffin for Modules. For anonymous function Modules users, it's perfectly okay for the parents to be created on the fly. The modules themselves have no properties.

But for Components this matters a lot! Every Component has (or should have) properties that are important. And the user should be the one to set this up; you shouldn't be able to just create a super-deeply nested component.

We were throwing around the names Namespace and Component for these two things, respectively. Modules, by that name, would vanish in this hypothetical world.

Here's a quick gist showing possible API.

I like the idea of a component/subcomponent distinction because it is a logical way to break up your apps. Components have certain powers, like communicating on the global channel (app.vent, and so on). Subcomponents, on the other hand, can't. They talk on their own local channel. This distinction would allow subcomponents to be instantiated with their parent's channel automatically.

@andru
Copy link

andru commented Mar 29, 2014

I've been following this issue and I'm with you on the need for a Component package which has it's own views, etc. So far I've been just using a Controller to handle it, but I'm totally onboard with a purpose built structure.

I can't tell from your gist: is this concept of a Component a singleton pattern? If not could you update the gist to show how one creates a new instance of a Component? If so, that is contrary to my expectations for something presented as a re-usable application component.

I don't think it's a good idea to mix this Component concept with the idea of application modules (by which I mean singleton application chunks which can be loaded/unloaded according to need), and I don't see anything in this proposal which provides a suitable structure for this usage.
I would certainly not want to consider an entire application module containing a router, multiple controllers, views, models, and collections, together representing a big chunk of an application (eg. an account management application section) merely a component in the same sense that code for a re-usable modal window, or an application localization library, or a graphing library, etc are a component. That would be confusing two very different concepts.

Namespace is an equally bad fit for the concept. The idea that one can start and stop a namespace is counter-intuitive. To me a namespace is purely an organisational structure; it shouldn't have initialization code.

The current implementation of Module does encompass namespacing, but it also encompasses initialization. The nature of module initialization means it can easily be extended (as I have) to create module-based url routing, memory management, asynchronous resource loading, etc. This makes them much more than a Namespace, and I think that term would be misleading for anyone approaching them for the first time.
This concept of modules as I am describing them should be final singletons and they should have set-up and tear-down code.

Personally I've never use nested modules, so I can't comment on that aspect. My modules are non-reusable application level structures.

@jamesplease
Copy link
Member Author

@andru, great input, thanks! I'll respond more soon, but do you use the anonymous function or object literal definition for modules? Or both? If both, how do you decide when to use which? I'd like to get a feel for all the ways people use Modules to help us figure out the best way to break them up.

@jasonLaster
Copy link
Member

@jmeas, thanks for revitalizing the discussing. I agree that distinguishing between components and namespaces is helpful. I'm a little bit hesitant about the component api you introduce.


At work, we've been using module classes that look like this. There were a couple of reasons why we came to this design:

  1. requirejs
    We use requirejs and are sensative to coupling. We follow this rule: modules depend on data and a layout, layout depends on region views.
  2. reusable
    We would like to reuse our modules in several contexts. For example, if we build a "chat client", we'd like to reuse the client in several contexts. By tying a Module to a namespace and app life-cycle we lose that re-usabilty.

I realize, this is not your typical Marionette setup and is probably closer to a style of Modules as Controller design.


@andru, I liked your examples for components. I also like how you distinguish between namespaces and application life-cyle (super insightful). When I think about this problem, I imagine building the google suite: mail, docs, chat. In this context, I think mail, docs, are modules that can be started and stopped. I see chat and parts of docs and mail as components. For example, chat is a component that's reused and lives inside the larger app. Similarily, a doc attached to an email can be modeled as a component.


I'm glad we're having these discussions, because there are many use-cases for modules that I don't fully understand. I'd love some great examples where people rely on initializers, finalizers. Also, it'd be great to have a discussion about aysnc initializers.

@andru, we use nested modules to describe sub-applications in a larger app. We're currently building a big inventory management app, which is a module that lives along-side, other apps. The inventory manager has several child modules: a quick edit module, bulk edit module, and several single purpose editors.


Lastly, I'm worried about modules for several reasons:

  • attempt to solve too many problems: namespace, dependencies, controller, initialize/start
  • everyone seems to interpret modules differently
  • they're difficult for newcomers
  • the implementation is super confusing

@disruptek
Copy link

I also find the design of the sub-module system very strange; there's no way for modules to share dependencies (unless they depend upon one-another, of course) and it seems counter-intuitive to traverse depth-first. This approach seems extremely limiting, but I cannot see the purpose of the limits. On the contrary, a proper dependency system could be hugely valuable to developers.

I find the indexing of modules via magical strings strange as well, but it's similarly easy to ignore.

One obvious use for addFinalizer and addInitializer is to mix-in functionality without any additional complexity. Surely this is handy for vanilla JavaScript users, but I personally have no need for the whole Namespace/Component structure I see above. CoffeeScript and Backbone.Advice make all manner of inheritance and extension very elegant to read and write, in my opinion.

Finally, I feel it's a mistake to have so many ways to customize modules when they are attached to the Application. One powerful method should be sufficient to meet all needs and reduce confusion.

@jamesplease
Copy link
Member Author

The v2 flag for this has been removed. This is quite a substantial change, so I think we should dedicate a version beyond v2, maybe v3, to just redoing Marionette architecture.

@jasonLaster
Copy link
Member

Completely agree, I think the next step here is to create some best practice recipes for modules and then use their deficiencies to drive a better api.

@jamesplease
Copy link
Member Author

Modules are slated to be removed: ref #1321

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

No branches or pull requests

7 participants