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

If you could change Backbone at will, how would you? #4290

Open
jgonggrijp opened this issue May 17, 2024 · 17 comments
Open

If you could change Backbone at will, how would you? #4290

jgonggrijp opened this issue May 17, 2024 · 17 comments
Labels

Comments

@jgonggrijp
Copy link
Collaborator

Sooner or later, there will be a Backbone 2.0. Major releases are disruptive for users, so I prefer to make them as infrequently as possible. But when we do one anyway, we might as well use it to its full potential.

This is a "wild ideas" ticket, where you can suggest any backwards-incompatible changes that you would like to see in a future release of Backbone. Please keep it brief, but do explain why you would like to see the change(s) that you suggest.

You are also welcome to highlight anything that you want to stay the same. Again, please with reasons.

Some rules of the game:

  • State your reason for wanting the change (or non-change)! It does not need to be a "good" or "smart" reason.
  • All ideas are valid, bearing in mind that there are always tradeoffs. Please keep it very civil and do not enter competition with other suggesters over whose idea should "win".
  • The fact that an idea is mentioned here does not say anything about its likelyhood to make it into Backbone, even if that idea seems popular. In the end, the decisions are made by the people who do the work, with me and @jashkenas having the final word because we are publishing the package and we need to assure its quality.

The following prior tickets are somewhat related: #4274, #4245, #3560.

@jdittrich
Copy link

jdittrich commented May 29, 2024

What to keep: It seems that backbone is the only MVC-Framework for JavaScript that is still updated, so I would not change anything about that paradigm.

What to keep/Improve: Use of ESModules without introducing the Backbone global or a build tool – #4274

What to improve: Use of ES6 classes (So I can class myModel extends BackboneModel{…})and staticmethods when using Backbone (instead of _extend(…)).
Caveat: That might work already, but #4213 and #3560 seem to point to some possible problems and are still open. We have preinitialize but it is not obvious when to use it (for me at least) and, in general, there seems to be no examples of ES6 modules in the documentation.

What to improve: Not a huge problem for me, but using modern JavaScript (not cutting edge, just anything that works since a couple of years) and, with that, make underscore optional? Many functional-style methods has been added to JavaScript arrays by now, so maybe this is sufficient? Similarly Map and Set might be helpful in some occasions. Reasons: Size and code-readability for people not familiar with underscore.

@jashkenas
Copy link
Owner

☝️ I endorse these suggested changes for a Backbone 2.0.

@jgonggrijp
Copy link
Collaborator Author

So far, we have one response, which only suggests evolutionary changes, rather than anything radical. Would it be safe to conclude that Backbone users just want the library to be updated with recent JavaScript and otherwise stay mostly the same? If anyone thinks otherwise, please don't hesitate to respond.

@jdittrich
Copy link

Not radical, either but:

  • A standard way to manage child views might be great
  • I already pointed out that I would love a code update to ESM, ES6. In a similar vain: I wonder if code readability/learning/extending could be a focus in an update? That is not limited to code itself but also to documentation. It would not be a strong departure (though I find the event handling code difficult to understand sometimes) and might entail some potential compromizes where ease-of-understanding might be favored over performance, as well as architectural documentation (something between the line comments and the current documentation)

@jgonggrijp
Copy link
Collaborator Author

@jdittrich

  • A standard way to manage child views might be great

A possible radical way to implement this, would be to unify Backbone.View with the custom elements standard. In that case, child views are managed by declaring them in the template HTML. Child views managed by the parent itself are in the custom element's shadow DOM, while child views inserted from the outside would go in a <slot>. I have an idea for a total redesign of the library that involves this change and others (still preserving MVC and loose coupling through events), but I've been holding off from sharing that idea because it would be a lot of work and I'm not sure people are waiting for it.

A possible non-radical way would be to absorb the core functionality from backbone-fractal into Backbone itself. That would probably amount to introducing a new CompositeView class. Such a feature could be added without a 2.0 release.

Yet another option is to just leave it to external libraries, as is currently the case. Marionette provides its own way to compose views, so how to do it in Backbone itself would probably be somewhat controversial.

  • I already pointed out that I would love a code update to ESM, ES6. In a similar vain: I wonder if code readability/learning/extending could be a focus in an update? That is not limited to code itself but also to documentation. It would not be a strong departure (though I find the event handling code difficult to understand sometimes) and might entail some potential compromizes where ease-of-understanding might be favored over performance, as well as architectural documentation (something between the line comments and the current documentation)

Could you elaborate a bit on how you would like to see this intermediate documentation? In any case, pure documentation changes are never breaking, so this could be done before a 2.0 update already.

Perhaps related: I have been wanting to deepen the indentation, which might already improve the readability. Such a change would best go together with a modularization, because that keeps all obfuscating changes in one batch.

@jdittrich
Copy link

intermediate documentation

…for me would usually involve

  • What is already in "getting started"
  • And then, for the larger code modules how to read and understand the respective code. For event handling (since that is the part that I know best) something like: What are the contracts/interfaces for an __Api-Function/Reducer, how is this._events structured, which "private" attributes are added to an object that uses the Events mixin (These are all focussed on the current way events work)
    • JSDoc might help with the contracts/interfaces?

Basically, something that helps understanding how different parts of the code work together and how to read the code.

composite views

No strong opinion, for me the fractal integration sounds most meaningful.

@jgonggrijp
Copy link
Collaborator Author

@jdittrich I created a new issue (#4291) for your point about code understanding. It is a very good point and I think it does not need to (and perhaps should not) wait until the 2.0 release.

@sgravrock
Copy link

I haven't written any Backbone applications in ages, so take this with the appropriate amount of salt.

Change:

  • Good support for view composition. I liked Marionette back when I was using Backbone, but it looks to me like Marionette moved on from Backbone and then work stopped.
  • Some way to determine what inputs a model or view expects just by reading the model or view definition. My experience reading Backbone application code was that the "everything is a bag of attributes" approach meant that the source of truth for what a class needed was often several files away in one direction or the other. React propTypes is one example of solving this problem without static types.
  • Drop the underscore and jQuery dependencies unless they still provide significant value on modern browsers.

Keep:

  • MVC.
  • Relatively light weight.
  • Usable without bundling. (Shipping Backbone as an ES module is probably fine these days.)

@markduncanawp
Copy link

  • Remove JQuery
  • Add life cycle handling, eg i may have thousands of view coming and going during the day, of which i can not be confident that i have the best approach with regards to memory management.
  • Keep it very similar with regards to not imposing a style. Our implementation is probably unique to us and is only possible because backbone lets you build in your own way

Backbone has saved us a lot of time and give us a clear starting point. Greatly appreciate your work!

@paulfalgout
Copy link
Collaborator

I would push back against adding view functionality.. Marionette's team at one point intended on dropping backbone as a strict dependency as extending the view to allow for other renders was difficult. A big ask had been dropping jQuery, and that meant making backbone optional. Making that easier would be good. In order to do it now it feels like a hack or just large copy-pastes from the backbone source. You can generally see those modifications here: marionettejs/backbone.marionette#3679

Beyond that ESM would be great.. not sure if we've overcome the breaking issues of switching to class as far as how that changes patterns overall.

@jgonggrijp
Copy link
Collaborator Author

I would push back against adding view functionality..

For utmost clarity: which added functionality are you referring to here?

@paulfalgout
Copy link
Collaborator

absorb the core functionality from backbone-fractal in particular, but even the shadow DOM / custom elements.. backbone views should allow for that as a possibility without adding that as a required opinion.

@jgonggrijp
Copy link
Collaborator Author

@paulfalgout absorbing backbone-fractal would mean adding a new class (CompositeView) without changing anything about the original View base class. Would you still object to that?

The custom element thing is not so much a feature addition but a radical total redesign of the library. So far, I don't have the impression that a lot of people would want that.

@paulfalgout
Copy link
Collaborator

It adds opinion to the library handled by other 3rd party libraries that now may be expected to support the new stuff. It would make more sense to me if a significant portion of backbone users had already adopted it, but historically a light View layer opinion was characteristic of Backbone, and I'm not certain how at this point in time embedding a particular solution is any better than just saying "if you need to do X, here are a few options"

@enjikaka
Copy link

enjikaka commented Nov 29, 2024

We had a big codebase with Backbone.js, Grunt for building, BEM for scoping CSS and plates for the view rendering. The latter was probably the biggest pain point.

We rewrote that application to ES6 + react + redux many years ago now. I still think we've got performance regressions from the rewrite, not in small part to React being hard to grasp even though the initial DSL seems small and simple - but rewrites, hooks and memos will eventually come get you.

I haven't used Backbone.js since our refactor, but have done quite a lot of work with web components. And I can't stop to think how Backbone.js combined with ES modules, template literals and web components (w/ CSS isolation in Shadow DOM) would be such a delightful stack now! The only work needed on the Backbone-side for that would be to support ES modules.

@prust
Copy link
Contributor

prust commented Dec 5, 2024

@jgonggrijp: Our company has been heavily using Backbone for well over a decade, but (like most devs & companies) we no longer choose Backbone for new projects and we have been slowly converting large codebases to React. React's size, complexity and conceptual surface area are frightening and make it the polar opposite of Backbone ("smaller ... less conceptual surface area ... read and understand the source in an afternoon"). But React (and most recent UI frameworks) address a major pain point with Backbone: seamless view reactivity.

Backbone views are reactive (they typically re-render in response to model changes), but this is not seamless in two ways:

  1. Coarse-grained Reactivity: When a Backbone View re-renders, it blows away anything stateful that the user is doing -- where their cursor is in a text field, the current scroll position of scrollable content, unsaved text, a drop-down menu being open, etc. Technically, Backbone is render-agnostic, so you could avoid these issues by rendering with a vdom (or using a vdom-less lib that maps data directly to the DOM, as lit-html and SolidJS do). While the Backbone docs explicitly say you can do this, it isn't exactly encouraged or common.

  2. View Composition: Backbone doesn't provide any help with view composition, so the view either destroys & recreates child views on every re-render, or it has custom code to track and re-use child views. Sometimes this is trivial, but in a number of common situations, it is painful. One example is when you have child views that map to models in a collection. When one or more models are inserted or removed from the collection, the view needs to insert or remove child views at corresponding locations in the DOM.

The above shortcomings aren't that important when most changes are initiated by the current user, but we write applications for teams, so there are often incoming changes from other members of the team. These trigger re-renders, which either result in bugs or requires a good bit of code workaround to manage. In contrast, React & most recent UI frameworks handle this seamlessly (though I'll be the first to admit that these frameworks bring a boatload of other problems).

I do appreciate how Backbone is rendering-agnostic. Here are a couple possible ways to address the above issues while remaining render-agnostic:

  • In the docs, we could highlight one or more rendering layers that support fine-grained reactivity and view composition, and provide examples of how to use these with Backbone (or, if it requires more code than can comfortably fit in an example, link to it). lit-html supports fine-grained reactivity (without a vdom, so +1) and is fairly lightweight. But for composition, I think it requires that your View be a web component (I would prefer a solution that supports non-web component views on an equal footing with web component views, perhaps with an API/syntax like Preact's htm).
  • We could write our own rendering layer (Backbone.Reactive?), perhaps even in a separate repo, that does fine-grained reactivity and composition. This would be optional -- it would be highlighted and mentioned in the docs, without discouraging or deprecating the use of other renderers (especially for situations when all you need is a simple _.template()).

Less important requests:

  • Drop jQuery in favor of fetch() and native DOM
  • Convert sync/fetch/save/destroy to async functions

@jgonggrijp
Copy link
Collaborator Author

@prust thank you for chiming in. Please allow me to comment on what you wrote:

Backbone views are reactive (they typically re-render in response to model changes), but this is not seamless in two ways:

1. **Coarse-grained Reactivity:** When a Backbone View re-renders, it blows away anything stateful that the user is doing (...). Technically, Backbone is render-agnostic, so you could avoid these issues (...). While the Backbone docs explicitly [say you can do this](https://backbonejs.org/#View-rendering), it isn't exactly encouraged or common.

Backbone is indeed render-agnostic, so I would not agree that coarse-grained reactivity is an intrinsic trait. That being said, I understand that people might often end up implementing their own rendering logic in a coarse-grained way.

2. **View Composition:** Backbone doesn't provide any help with view composition, so the view either destroys & recreates child views on every re-render, or it has custom code to track and re-use child views. Sometimes this is trivial, but in a number of common situations, it is painful. One example is when you have child views that map to models in a collection. When one or more models are inserted or removed from the collection, the view needs to insert or remove child views at corresponding locations in the DOM.

backbone-fractal and (slightly more bluntly) Marionette.CollectionView already handle this perfectly.

The above shortcomings (...) either result in bugs or requires a good bit of code workaround to manage. In contrast, React & most recent UI frameworks handle this seamlessly (though I'll be the first to admit that these frameworks bring a boatload of other problems).

It's a tradeoff. Backbone gives you all the tools you need to write an efficient application with fine-grained reactivity (if needed), but leaves it (mostly) to you to figure out how to do that. React and other component frameworks give you one low-effort approach to update the DOM that works well most of the time, but they will actively hinder you if you need to manage the DOM in a different way and they don't provide a good model layer.

I do appreciate how Backbone is rendering-agnostic. Here are a couple possible ways to address the above issues while remaining render-agnostic:

* In the docs, we could highlight one or more rendering layers that support fine-grained reactivity and view composition, and provide examples of how to use these with Backbone (...).

I think this is a good suggestion. Since it is a documentation change, it would not need to wait until a 2.0 release.

* We could write our own rendering layer (`Backbone.Reactive`?), perhaps even in a separate repo, that does fine-grained reactivity and composition. This would be optional -- it would be highlighted and mentioned in the docs, without discouraging or deprecating the use of other renderers (especially for situations when all you need is a simple `_.template()`).

As I wrote above, backbone-fractal and Marionette already do this. I agree there is added value to mentioning them prominently in the documentation, though.

Less important requests:

* Drop jQuery in favor of `fetch()` and native DOM

A common request, but I must point out that delegated events are both very efficient (so desirable to keep) and hard to implement without jQuery.

* Convert `sync`/`fetch`/`save`/`destroy` to `async function`s

These return promises (i.e., jqXHR) already; you can await them.

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

No branches or pull requests

8 participants