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

Backwards compatibility breaks in 0.7.1 #75

Open
creynders opened this issue Sep 26, 2014 · 18 comments
Open

Backwards compatibility breaks in 0.7.1 #75

creynders opened this issue Sep 26, 2014 · 18 comments

Comments

@creynders
Copy link
Contributor

As reported by @mmikeyy in #72

I assigned values to the wiring property in initialize so these values would belong to the context instance, and then these changes were processed by this._configureWirings(wiring);, which was called at the very end of the constructor, after initialize was called.
Now, with 0.7.1, this._configureWirings(wiring) is called before this.initialize.apply(this, arguments).

and

Now, I have a problem with a view class that is sent to a layout that instantiates it and renders it in a region. That used to work well with 0.7.0. Now, with 0.7.1, instead of receiving a view class to instantiate, the layout receives:

function () {
  return applyToConstructor(clazz, _.toArray(arguments));
} 
@creynders
Copy link
Contributor Author

Yes, the execution sequence of _configureWirings and initialize was changed with #45 . Exactly

because the initialize method is now executed in a context that is all wired up.

makes more sense.

Heheh @geekdave 's comment was:

I can't imagine how someone would have written their code such that this would be a breaking change

I agreed. 😁 Lesson learned:

Any change to a code path, will break someone's code

(let's call this camille's law from now on 😉 )

@creynders
Copy link
Contributor Author

This return applyToConstructor(clazz, _.toArray(arguments)); you're seeing is a wrapper for constructors I wrote in #67 specifically created to allow the construction of views in two ways:

context.wireView('view', 'FooView');

//1. as a factory method
var factory = context.getObject('view');
var view = factory(); //an instance of FooView is created

//2. as "class"
var View = context.getObject('view');
var view = new View();

But I tested it pretty extensively and it definitely was meant to be backwards compatible. I upgraded my own projects at work to v0.7.1 (before it was released) without any problem which is why I was pretty confident that backwards compatibility would not break... I'm really curious why this does break your code.

@mmikeyy
Copy link
Contributor

mmikeyy commented Sep 26, 2014

OK... I'm back at it after sleeping on this.

The reason the code breaks seems to be as follows. I rely on examining the view class prototype to determine the kind of class received (by a view, from the execute method of a command that has wiring:['viewThatWillBreakCode']) and to make decisions on how to process it (what layout and/or template to use, what data to supply for initialization) before later instantiating it.

Now it seems that instead of my class prototype, I'm getting this factory method. So there's no way to know what it is before instantiating it (or is there?), which I don't want to do just yet.

It's easy to work around the problem (at the expense of elegance... need to send class + tag identifying class type, instead of the class carrying its own type in its prototype for everyone to see).

I hope I'm making sense. I just woke up 😪 and it suddenly seemed so obvious (and @creynders is so curious!). I'll revisit the issue later this morning and make corrections if needed. I will also change my code and see if it can be fixed as described, without new unforeseen issues arising.

@creynders
Copy link
Contributor Author

I rely on examining the view class prototype to determine the kind of class received and to make decisions on how to process it

That kind of defeats the purpose, no? Whether the command sends a string "fooView" or it sends the prototype doesn't matter, since your receiving view still has a dependency on the fooview class, i.e. you might as well send a string instead, inspect that and construct the view instance there.

In my experience this kind of switch-views are a bad idea, they grow monolithic, know too much about the components their initialising and have dependencies all over the place. It's far better to separate the construction and initialisation of each view into a separate factory.

Anyway... There are obviously solutions to the need of knowing the type of what is sent through. For instance I could expose a type property. Or see what I can do using the constructor property to make the receiving code believe it didn't receive a factory method, but rather a straight constructor function.

@mmikeyy
Copy link
Contributor

mmikeyy commented Sep 26, 2014

In my experience this kind of switch-views are a bad idea

Well... the getTemplate method does not exist for no reason. And when used in a Marionette layout view, we seem to obtain the kind of switch-view that you dislike, but it's just standard Marionette, isn't it?

So I have a collection of items of different kinds displayed. When an item needs to be edited, an event (specific to this event type) is dispatched to parents. Somewhere up in the context ancestry, a context handles all editing requests. It opens a layout view that's initialized with model, parentContext and the class that should be instantiated in a layout region. Some very basic decisions (no arcane switching logic here) such as what template to use are made by looking at the class received. All classes used for this have a "type" property for this purpose.

I don't think there's any bad programming practice here. And if a view constructor must be passed around, isn't it always better to have it contain its own defining properties (e.g. a type) rather than having this info sent along in a separate parameter?

But the solution is very simple. I can send a string to the layout view instead of the view prototype, as you suggest. The layout view will set itself up based on the string, show the view in the appropriate region, this view being simply obtained by this.context.getObject(<the string>).

Ahh.. but I thought that this.context tended to be frowned upon (in the context of a view). I know that I can put wiring: [<the string>] in the layout view and this[<the string>] will give me my view prototype, but this would require me to include and keep up to date the list of all possible views in the wiring list, even though they would be found anyway in the context ancestry by this.context.getObject, rendering any maintenance of the wiring list unnecessary.

Of course, I could dispatch locally to get a command (with context access) to obtain the view with getObject, and then send it back to the layout by triggering a contextEvent or returning it in the payload. But all this triggering back and forth makes the logic difficult to follow when what needs to be achieved is so simple.

Perhaps it's less trouble to send the class prototype to the layout view along with the type as a separate parameter after all... (or keep making the context available to the view, as I'm in the habit of doing, and use this.context.getObject(<the string>)).

If you see me missing an obviously better and easier way of achieving the same result (or saying something completely idiotic 😕 ), do not hesitate to enlighten me!

For instance I could expose a type property.

Not sure about this. May be too specific to the use case we are discussing. Next thing we'll see is someone asking you to expose something else...

Or see what I can do using the constructor property to make the receiving code believe it didn't receive a factory method,

Ahh... that would be a dream... It's a bit frustrating to see my own stuff wrapped to the point that I, its creator, am denied access to its contents!

@creynders
Copy link
Contributor Author

Disclaimer: we're entering opinions-land here, based upon higly individual experience, so what follows is exactly that; opinions.

First of all:

but it's just standard Marionette, isn't it?

There's plenty of things that are "best" or "usual" practices in Marionette that I dislike, which is why I like Geppetto so much, it helps me to avoid a bunch of those things.

Well... the getTemplate method does not exist for no reason.

There's a (big) difference between a) having a single view spawn different templates with getTemplate and b) a view using a switch to spawn other views. The various templates are warranted IMO if they are simply state presentations of the same "thing"(TM). E.g. a template for an empty list, another template for the same list with less than ten items and another one when it has 1000 items. All of this is presentation logic of the same list, thus the view is allowed to switch between those templates. And it doesn't matter whether it uses a literal switch or a template/key map or whatever.

And when used in a Marionette layout view, we seem to obtain the kind of switch-view that you dislike, but it's just standard Marionette, isn't it?

The way I use layouts is always w/o any kind of control logic in the layout view. It simply listens to context events and switches views accordingly. The only "controlly" decisions it can make are decisions like: "on event A show views V1 and V2 in regions R1 and R2" and "on event B close regions R1 and R2 and only show V3 in R2" i.e. layouts are allowed to make decisions on which views are shown on which events, but I never ever let a view vary its presentation upon anything else than different events.

Some very basic decisions (no arcane switching logic here) such as what template to use are made by looking at the class received.

Obviously it's a bit hard to tell without knowing the exact use case or requirements, but sounds to me like that single view should actually be split into several views. But even if that's not the case, there's plenty of ways to circumvent such logic, for instance: you could create a template/view mapping somewhere and inject it into the layout view, then all it has to do is lookup the template using the view constructor (yes this will work even with wrapped constructors, as long as those were used in the template/view mapping as well) or inject the layout view with factories that will create the view instance and return the correct template to the layout view or ... it all depends on what exactly needs to be achieved.

And if a view constructor must be passed around, isn't it always better to have it contain its own defining properties (e.g. a type) rather than having this info sent along in a separate parameter?

I'd say "yes", I don't think it's a good idea to pass two defining values.

Ahh.. but I thought that this.context tended to be frowned upon.

Inside views? Definitely. Then you switch from using DI to the service locator pattern. It's not totally unavoidable, but definitely has no business being in views.

but this would require me to include and keep up to date the list of all possible views in the wiring list,

Yeah, I understand you want to keep the layout view ignorant of the views it receives. However, having a switch-statement is an implicit declaration of dependencies, i.e. you might as well (or better even) declare them in wiring. If you want to have a truly "agnostic" layout view you need to get rid of any control logic and supply the layout view with the appropriate template and view.

Of course, I could dispatch locally to get a command (with context access) to obtain the view with getObject, and then send it back to the layout by triggering a contextEvent or returning it in the payload.

Insane, I say, insane! 😉

Again, it's a bit hard w/o seeing the code, but sounds to me that you need another set of views.

Ahh... that would be a dream... It's a bit frustrating to see my own stuff wrapped to the point that I, its creator, am denied access to its contents!

Yeah, maybe. I need to think about that.

@mmikeyy
Copy link
Contributor

mmikeyy commented Sep 26, 2014

opinions... yes, of course. And I hope I'm not coming out as too much of a whiner... 😳 :

At any rate, my application is fixed now and I'm moving forward from here.

Finally, I had only two problems and the fix was quick and easy. Thanks for the numerous comments: it gives me ideas on ways to improve my code.

I remain a bit puzzled by a few things such as the announced phasing out of bindContext (ouch! I use it in every single view! must eventually figure out how to live without it!) or the wrapping of view constructors that makes their prototype unreachable (no big deal, btw. I frowned a little when that broke my app, but no one ever died of frowning after all..). When I'm finished converting this application I'm working on, I'll need to make another pass to improve a few things. Hopefully, Geppetto won't have evolved to the point of making a complete rewrite necessary! 😉

Thanks again.

@creynders
Copy link
Contributor Author

@mmikeyy it seems like I can fix it, i.e. you could still use your type property if you want.
I created a small POC
The modification consists out of the _.extend(factory, clazz); line in createFactory which lets the factory method inherit all static properties from the original clazz. I.e. it's still not the "real" thing, but comes pretty close.

As you can see Foo has a static type property (that's how you're doing it in youre views as well, right?) and the last three console logs verify that it's accessible in the original class (duh), the wrapped one and the factorised one.

Would this suffice?

@creynders
Copy link
Contributor Author

phasing out of bindContext (ouch! I use it in every single view!

Why exactly ? For the automatic closing of the view? Or simply for the automatic injection of context into views?
Do you think you could sketch out a bare bones example of why you feel you have to use bindContext? It doesn't really have to function, just that I get an idea of why you do it and am able to either advise on a better way or have a good reason not to phase out bindContext.

@mmikeyy
Copy link
Contributor

mmikeyy commented Sep 27, 2014

The modification consists out of the _.extend(factory, clazz); line in createFactory which lets the factory method inherit all static properties from the original clazz. I.e. it's still not the "real" thing, but comes pretty close.

I see that the POC works, but if I implement the same change in Geppetto, it does not work. It may be due to clazz being a wrapped constructor in Geppetto. (the _.extend(...) statement just tries to extend a function with another function, which does nothing).

Anyway, I find that it works well with this instead:

_.extend(factory, clazz.prototype);

I don't know if there would be unanticipated side effects.

The advantage is obviously that the resulting object can be inspected for certain characteristics, but someone could lose sight of the fact that anything that he sees in that object is just a prop that will be cast aside when the class is instantiated (so don't change anything before instantiating: it's useless. Upon instantiation, original prototype properties/methods will come back and overwrite any changes made). I guess the documentation should mention something about this, especially for users who expect to be able to use the library without reading and understanding the code behind.

What is the advantage of the factory function anyway? I'm sure it's not there just for the pleasure of not having to type new to instantiate the view...

In any event, I'm not sure it's worth the trouble to load the object with props, if that's all they are (props), given the risk of confusion later when someone thinks he's handling his own object, while actually it's been secretly taken away from him and he's just playing with a copy. For that reason, I think it's better if I play it safe and just send the view type as a separate parameter. And as a trade-off, I guess I'll be able to enjoy the benefits of a factory method when I understand what they are (yeah... I know... I'm not the most sophisticated programmer around here 😕 ).

Why exactly ? For the automatic closing of the view? Or simply for the automatic injection of context into views?

Hmm... automatic closing of views? no... you probably mean automatic destruction of context upon vlew closing. That's one thing. BTW, I extend the Geppetto prototype to react to a view being destroyed, not closed. Marionnette no longer closes views (Unless I'm mistaken, I don't think close is present now anywhere in Backbone or Marionette).

ok, what else... well it's probably just ignorance on my part, but I read the documentation, it was there, and I just started using it. I found a way of doing things that worked well for me and I just kept going. Not a problem to adjust if bindContext disappears. I'll just have to revisit every single view, but it's just there once per view, always in the same place, always used the same way. So it won't be difficult to do. Theoretically!

But here's my standard way of doing things: (for each view, I have 3 files. I don't like the idea of one file per command for example: too many files to handle, too many tabs in IDE). I name them in a way that makes it obvious that they're related.

// file example_CMD.js
define([list],
    function (list) {
        return ({
            command1: function () {

            },
            command2: function () {
            }
        }

        )
    })

// file example_CNTXT
define(['geppetto', 'example_CMD', etc],
    function (Geppetto, cmd, etc) {
        return Geppetto.Context.extend({
                initialize: function (data) {
                    data.view.context = this; // in case the view needs it
                    // + some wiring done manually
                },
                wiring: {
                    commands: {
                        command1: cmd.command1
                        // etc...
                    }
                }
            }
        )
    })

// file example_VIEW
define(['marionette', 'geppetto', 'example_CNTXT'], function(Marionette, Geppetto, context){
    return Marionette.ItemView.extend(
        {
            initialize: function(opts){
                this.wiring = [list]
                Geppetto.bindContext(
                    {
                        view: this,
                        parentView: opts.parentView,
                        context: context
                    }
                )
                // this.context available from now on if ever needed
            }
        }
    )
})

I hate these parentheses and brackets... Coffeescript is such a pleasure to work with...

Ok... now from the execute method of a command elsewhere I just instantiate this view as follows:

  wiring: ['example_VIEW']
  execute: function(){
    new this.example_VIEW({
      parentContext: this.context
      })
  }

Pretty basic and boring, but... you asked for it! You can throw 🍅's now...

What is the "recommended" way of doing things now?

@creynders
Copy link
Contributor Author

Anyway, I find that it works well with this instead

Ah, so type is an instance property, not a static one?

What is the advantage of the factory function anyway?

Simply to leave out the new as you wrote. It's a stylistic choice. But also has the advantage that the composing view, i.e. the one calling it, doesn't need to know how it's constructing the view. It's all about flexibility. For instance using factories I can wire views to container views and let them call those straight away, but if requirements change and the views need additional configuration when they are instantiated all I need to do is write the new constructing code, use that for wiring instead of the view class and in my container view I don't need to change a thing. Far easier, more decoupled and arguably more elegant.

In any event, I'm not sure it's worth the trouble to load the object with props, if that's all they are (props), given the risk of confusion later when someone thinks he's handling his own object

I agree. Either I'll drop the constructor wrapper or we leave it as is.

you probably mean automatic destruction of context upon vlew closing.

Yes, that's what I meant.

What is the "recommended" way of doing things now?

Well, there are as many ways as there are developers. A simple example of how I handle views can be found in the geppetto todomvc app

In a nutshell: I configure their dependencies outside the views themselves, in this case in BootstrapUI
On L29 I pass the views the AppView needs to show to properties, e.g. createHeaderView
Then in AppView itself it simply calls this.createHeaderView when necessary.

If you want a more "real" example, this is the project I'm working on ATM. It's nowhere near completion, so there's tons of things that need to be refactored to proper best practices. I tend to write the code to get things done and then when I'm certain that's the approach I'll be taking, I refactor.

@mmikeyy
Copy link
Contributor

mmikeyy commented Sep 28, 2014

so type is an instance property, not a static one?

nope... it is static. (was actually, now that I've given up on inspecting the prototype to identify the class type before instantiation. No big deal: there are many ways to obtain the same result.)

Thanks for the comments. In the apps you mention, unless I missed something, you seem to have a single context to which everything is wired. Of course, if you were to use bindContext in a view here, you'd have a problem with this shared context being destroyed with the closing of any view linked to it this way. Also, the code seems to have been written with Geppetto in mind right from the start. The show really seems to be run from the context, with very dumb views just being told what to do from a distance (the name "Geppetto" being very appropriate here). This way of structuring the app may not be easily implemented when Geppetto is integrated to an existing application. With bindContext, we can add the context and some wiring without disturbing the existing control flow. The problem then is that it allows one to become comfortable with a way of doing things that is probably not optimal.

Perhaps this is the good thing about bindContext: it provides an easily understood and implemented way of integrating Geppetto to an existing app with very little rewriting required. Is this making sense??

Anyway, I'll try to get rid of it in some parts of my application just to see how painful it is to do this...

@creynders
Copy link
Contributor Author

nope... it is static.

Sorry, I don't mean to be overly pedantic or autistic, but want to get to the bottom of this, because if you're right then something's horrible wrong with how the factories are created. How are you attaching the type property? To the prototype? Or do you just add it in the extend call, like this:

Backbone.View.extend({
    type : "FooView"
});

And how do you check it? Like this:

switch(viewClass.prototype.type){
}

If you use any of these, then it's not a static, but an instance property.

you seem to have a single context to which everything is wired.

Yes, I have a single context per bundle. I.e. everything that's concatenated into a single js file has one context. And granted, that's definitely one of my blind spots, I tend to see everything from the single-context POV.

Also, the code seems to have been written with Geppetto in mind right from the start.

Yes and no. I knew right from the start I'd be using Geppetto for this project, but I am writing all actors (views, models and service) to be Geppetto-independent. This is a 3-year project and I have no idea how it'll evolve in the next years, so it needs to be as flexible and adaptable as possible. For instance, most probably I'll be creating a Titanium app as well, which uses its own Backbone like framework (Alloy). However I have no idea how easy it would be to add/adapt/port Geppetto to it, which is why my actors need to be as independent as possible. A long winded way of saying that if I weren't using Geppetto my actors would look (almost) exactly the same. And TBH that's what one should aim for. I can't ditch the direct dependencies on Backbone and Marionette unfortunately (due to their bad architecture I'm afraid to say) or at least can't ditch them w/o jumping through ridiculous hoops, but if I could, I'd definitely would.

This way of structuring the app may not be easily implemented when Geppetto is integrated to an existing application.

That's an interesting point you raise. Yesterday evening I took the time to look at some of my past projects that don't use Geppetto and tried to estimate how much work it would be to add Geppetto to them and came to the conclusion that in almost all of them it would be pretty trivial, but probably that's because in this chicken-and-egg scenario (what shapes what? Does the usage of Geppetto shape the way I build my projects or the other way around?) I'd say the chicken definitely came first, i.e. the way I architect my projects shapes my contributions to Geppetto.
Anyway, it definitely is something I need to keep in mind (how easy it is to integrate Geppetto into an existing application)

So, coming back to bindContext, based upon the example you wrote above, I'd say it will be totally painless to remove the bindContext calls, except for the auto-destruction of the context. But. As I wrote in one of the other issues, maybe we could provide a Geppetto.Migrate module, which makes sure that v0.8 is backwards compatible with v0.7, it could inject a bindContext method into Geppetto for instance.

And @mmikeyy I really want to thank you for these conversations, they're hugely useful both as feedback on the usage of Geppetto, but also because they make me rethink and question my habits.

@mmikeyy
Copy link
Contributor

mmikeyy commented Sep 30, 2014

Sorry, I don't mean to be overly pedantic or autistic

Don't be so humble! Your the knight here and the humble part is mine! 😉

Ok, let's see if I ridicule myself with some misconception. 😳

First, I never use class.extend({}) to extend a class, because I program in coffeescript and coffeescript makes it so easy to extend any class with next to nothing to write that there's no reason to look for ways (such as the extend method) to reduce the amount of boilerplate code. (which is the reason given in the Geppetto documentation for using extend, if I remember well). < coffeescript_apostle_mode="off" />

This being said, I may be wrong (possibly because of something I never fully grasped in JS's prototypical inheritance model), but I've always considered any extended class (among which classes extended via the extend method) to be just that, that is a class (ok... classes don't really exist in JS, but let's not make things too complicated). So the object obtained with the extend method is not an instance as you write, because it still needs to be instanciated.

Therefore in my (simple - but it's worked so far!) view of the world, any property extending a class with the extend method or otherwise is static, that is, it is part of the class prototype and each instance will receive a fresh copy of it (in general).

Was I using this?

viewClass.prototype.type

yes, originally, with Geppetto 0.7.0. But it no longer worked with 0.7.1.

And yes, viewClass was a simple extension of Marionete.ItemView:

in Coffeescript:

class viewClass extends Marionette.ItemView
  type: 'whatever'

in Javascript:

viewClass = Marionette.ItemView.extend({
  type: 'whatever'
});

Anyway, that's it. I don't see why type is an instance property. How can it be an instance property if nothing has been intanciated just yet?:confused:

Concerning my attempt at removing bindContext from my class initialize method to prepare for its eventual disappearance, I've spent a few hours on this and it's not necessarily so obvious (but I was tired that day and perhaps I'll do it in the snap of a finger when I'm back at it). I must say that bindContext makes it very natural and easy to have one context per view, and to have a context hierarchy that matches that of the various views, which in turn makes it easy to share data between views without having to pass data to children and grand-children etc in initialization parameters (with any break in the chain being catastrophic, while a child can get data from its great-grand-parents through context ancestry with parent and grand-parent not knowing the data even exists - I add this for the benefit of a newcomer reading this who's curious about some benefits of Geppetto - as I see them anyway...). So if one has one context per view, either the application is view-driven (we're opening views as needed, and each view takes care of creating its own context) or it is context-driven (same thing, but the other way around). Finally, does it not just come down to how strictly one wants to adhere to some conception of what best practice is, but in the end, it's basically the same thing? Yes, I know the usual answer is that the views are supposed to be dumb and just show stuff reacting to events etc etc. But when the application exists already and a context is something new to be added to it, bindContext seems to be an easy way to slap the context on the view and enjoy the benefits of Geppetto with absolutely no restructuring of the code (just immediate relief when one can dispose of an object added to the parameter list, that included data that came from some ancestor views - and with layouts, sub-layouts, collection views, child views etc, a view's ancestry can be quite deep sometimes.).

Anyway, I'll finish the job of getting rid of bindContext in a part of my application, just to see what the world looks like from that vantage point.

everything that's concatenated into a single js file has one context

OK, I know that you're humbly conceding a blind spot here, but I can't resist mentioning that I found this quite surprising!! All components are carefully designed to be this and that-agnostic etc, but they are designed with the source files in mind!? 😛

Happy to read that you're getting something from these conversations too!

@creynders
Copy link
Contributor Author

Ok, let's see if I ridicule myself with some misconception

What you don't know, you don't know. There's no shame in that. For example: only last week I figured out why many hrefs these days start with "//" instead of the protocol.

First, I never use class.extend({}) to extend a class

But you do. 😄 This:

class viewClass extends Marionette.ItemView

is exactly that. Wel probably, not exactly, but it's the same thing. You copy the prototype of Marionette.ItemView and add members to it.

it is part of the class prototype and each instance will receive a fresh copy of it (in general).

That's correct. The only misconception is in the terminology I think.

How can it be an instance property if nothing has been intanciated just yet?

They're called "instance properties" since that's the scope in which they are to be accessed. In CoffeeScript "static members" (or using the more proper term "class members") are declared with @

class ViewClass extends Marionette.ItemView
    @type: "whatever"

This means you can't use ViewClass.prototype.type, but instead use ViewClass.type.

I must say that bindContext makes it very natural and easy to have one context per view, and to have a context hierarchy that matches that of the various views

I on the other hand must confess I've never understood the need for/use of a context-per-view approach. What's to be gained?

which in turn makes it easy to share data between views without having to pass data to children and grand-children etc in initialization parameters

You don't need a context-per-view for that. That's what the DI is for. On the contrary, having lesser contexts is easier since you don't have to deal with setting up any kind of context hierarchy (or far less). Also, IMO a view hierarchy should be exactly that: a view hierarchy. Nothing else has no business with how views relate to each other and whether a view has sub-views or not. Even the subviews themselves should have no knowledge whatsoever what their place in the hierachy is, which makes hierarchy changes lightning fast.

But when the application exists already and a context is something new to be added to it, bindContext seems to be an easy way to slap the context on the view and enjoy the benefits of Geppetto with absolutely no restructuring of the code

Seriously, you don't need multiple contexts nor bindContext for this. If you really want to access the context inside your views (which I'd definitely not recommend) You can simply register the (single) context with itself and it will be accessible to any view that declares it as a dependency:

//file: AppContext
this.wireValue('context', this);
this.wireView('FooView', FooView);
//file: FooView
Marionette.ItemView.extend({
    wiring : ['context'],
    initialize : function(){
        console.log("context received:", "undefined" !== typeof this.context);
    }
});

All components are carefully designed to be this and that-agnostic etc, but they are designed with the source files in mind!?

On the contrary. Since they're this and that-agnostic I can delay the high-level decisions until they're needed. I always start out with a single context (and bundle) and then when the need arises I start splitting it up. Since my components are totally agnostic it's very trivial to do so.
For instance, the project I linked to in one of my previous replies is ATM a single bundle/context, but somewhere along the road I'll need to split it up. I already know this, but I don't have to care about it one bit yet. Before I knew how to properly decouple components and make them as agnostic as they can be I needed to make those kinds of decisions up-front: thinking about how I'll be splitting my code up and how the various parts will communicate with each other, since it was very painful to do that later on. But each and every time I got it "wrong", since requirements change, functionality changes and therefore architecture changes. And then I had to deal with very painful cutting operations. No more so.

Happy to read that you're getting something from these conversations too!

Of course. And I just love discussing stuff like this.

@creynders
Copy link
Contributor Author

As a final note: I'm convinced now we should create a Geppetto.Migrate module and dump bindContext into it. Not only to allow backwards-compatibility, but also to allow people who feel they need to use bindContext to migrate an existing application to Geppeto.

@creynders creynders mentioned this issue Sep 30, 2014
16 tasks
@mmikeyy
Copy link
Contributor

mmikeyy commented Sep 30, 2014

Here I am opening my eyes at 3:30 AM : "oh... I think I understand what he meant by "static"...
walk to the computer like a zombie, need to fix my comment a bit before he...Arrgh!! Too late! 😬

@creynders
Copy link
Contributor Author

😆

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

No branches or pull requests

2 participants