Hacker News new | ask | show | jobs
by danabramov 4152 days ago
>We want to apply values to variables and get the DOM updated. The popular two-way data binding should not be a feature, but a must-have core functionality.

Strongly disagree. I find one-way bindings and one-way data flow much easier to reason about. A little less boilerplate code is not worth mental overhead, cascading updates and hunting down the source of wrong data in my experience.

What is important is not updating the DOM from the code and instead describing it with a pure function. React, Cycle, Mithril, Mercury do it, and it's time we get used to this. This is the real timesaver, not two-way bindings.

`Object.observe` is the wrong way to approach this problem. If you own the data, why invent a complex approach to watch it, if you could update it in a centralized fashion in the first place? Here is a great presentation on that topic: http://markdalgleish.github.io/presentation-a-state-of-chang.... I strongly suggest you read it ("Space" to switch slides) if these ideas are still alien to you.

Even Angular is abandoning two-way bindings. http://victorsavkin.com/post/110170125256/change-detection-i...

I, for one, welcome our new immutable overlords.

5 comments

While I have been using React since it launched in May 2013 and I agree with a lot of what you said, using words like "right" and "wrong" doesn't help. React is a great way to write applications but it isn't the most mature library ever, and the junior developers I worked with had quite a bit of trouble working with it for a while because functional programming is so different. The ecosystem is filling in, things are great, but "you are wrong and I am right" harms as much as it helps.
Of course there isn't a “right” or “wrong” way. I'm sorry I didn't write it more clearly.

Approaches like jQuery soup or making SQL queries from PHP templates aren't “wrong” either. They are friendlier to beginner, too.

When I wrote “wrong” I meant “in my experience, inferior for building applications with complex stateful user interfaces and later maintaining them for a period more than several months in the face of changing requirements”.

Also, I'm not talking specifically about React. Of course it has its own shortcomings. All I'm saying is that relying on `Object.observe` and giving out global state to all components to mutate is the same as using global variables throughout the program. I don't know whether it is helpful to call global variables “right” or ”wrong” but I'd certainly stay away from them when there are ways to achieve the same without future maintenance nightmare.

You don't need to understand functional programing to use React.
Yep the Ember team also seem to have come to the same conclusion on 2-way bindings.

My dumb takeaway is something like '2-way bindings demo well but are rarely what you actually want in real apps'.

I think (not 100% sure) Tom & Yehuda (of Ember) talk about how they became disenfranchised with 2-way bindings in their recent Changelog podcast episode on Ember 2 [1].

[1] http://thechangelog.com/131/

I think marketing is also a problem here. Even frameworks that realize shortcomings of two-way bindings feel compelled to support them because it's hard to educate newcomers to abandon their old ways.

“Two” looks better than “one” on a feature checklist.

Quoting Sebastian Markbåge from React, “Angular is intuitively better to most engineers based on previous experience and ideals. React is better in practice. This is a biased opinion, but based one large org's experience of trying both models extensively.”

Two-way data binding is not inherently a bad idea. In fact, it's awesome in many cases, especially forms and form-like elements.

The problem is that people have a habit of misusing them and start using two-way bindings where they should be using events or similar patterns.

If I remember correctly, the Ember team isn't planning on abandoning two-way bindings. They simply want to give the developer control on when to use two-way bindings and they are going to make one-way bindings the default. That way you can decide if you need live updates or if data-flow control is better.
Also, data bindings assume you are working with a DOM which isn't always the case. If you make a video game using canvas built-in data bindings just get in the way.
Even when you are working with DOM, if you are on a device with limited capabilities (e.g. mobile devices), depending on the number of elements on the screen the bindings can cause the DOM to take a long time to render.

Normally not a huge issue, but it helps put AngularJS + Phonegap in an even worse position than before against native apps.

It is a shame to conclude two way data-binding should be a casualty in the maturation of frameworks. Like one way data-binding, it can be misused.

Two-way data binding to properties is generally not good. It increases likelihood of problems as updates to one value have to be observed to adjust other values. It is easy for bugs to slip in and hard to reason about the code.

Two-way data binding to methods is better. Methods that aren't focused on setting one value. In effect not direct data binding. It creates easy to reason about explicit code paths for changing of values. Observation of the change of properties is no longer required.

It is a useful tool and should continue to be seen as such.

What is two-way binding to a method? Can you give me an example? I can only think of this[1] but despite being similar to two-way binding, this is one-way and explicit.

[1]: http://facebook.github.io/react/docs/two-way-binding-helpers...

What you are linking to is still two-way data binding. Which enforces a one-way flow of data.

Two-way binding: Read & Write. Read & Write happens through getter/setter methods.

One-way binding: Read only. Writes happen by external event listeners.

Both can be used to enforce one way flow of data. Just as one way binding can be used to have a uni-directional flow of data.

A pseudo code example with two-way data binding with one-way flow of data:

  <input type="text" value=getOrSetValue() />

  function getOrSetValue(newValue) {
     if (newValue) {
        // Send an event to a dispatcher with updated value.
     } else {
        return value // can be single value from model or derived value, such as calculation of multiple values.
     }
  }
I believe the intention is basically "bind to a setter method, not a field." I'm guessing for much the same reasons the same is used in Java: You can change methods. You can add sanity checks, new behavior, etc.
When I was creating a UI library, I tried to pick up on the trend of data-binding, but I found it difficult to use. Now these discussions remind me of it.

I don't even know how the second option is better to be honest. I may research it further.

:-)

What's with the immutability stuff?

Shouldn't updates just be event driven?

Is it really so hard for developers of parent components to subscribe to events of child components?

I would argue that a parent component listening to events on its child is an unnecessary level of indirection. The parent creates the child (or at least it should, in my opinion). The parent should just give the child the callbacks it wants directly.

I've become more or less convinced that over-reliance on events is a big anti-pattern. Combined with mutable state, you get a lot of difficult to track changes in state. Some describe it as COMEFROM-based programming, the dual of the much-maligned GOTO paradigm. The COMEFROMs are your listeners and event triggers are labels they reference. The downfalls of each are pretty much the same: code that becomes increasingly difficult to reason about as it scales, because you have arbitrary global movement in control flow. COMEFROM is even worse because it introduces concurrency. Concurrency + shared mutable state is a recipe for subtle bugs.

So much of the time in a web app, an event only really has one listener. In these cases, a simple callback passed to the child component suffices. But even when you might need to have more than one component react to an event in a child component, I would argue that whatever is responsible for creating the child should still pass a single callback, which might simply be an entry point to dispatch logic on a controller whose only job is to mediate that behavior. Said controller might use or something else as its mechanism.

Why is it hard to reason about event based code? A framework will need the flexibility to enable any developer of any component to do what they need when something happens. That is what an event system enables.

If you want the events to be a directed tree, that's basically what angular 2 implements. Immutabilty is optional.

I can easily visualize a tree and reason about it. Gotos are very different. What you wrote seems like a bit of equivocation.

The parent creates the child (or at least it should, in my opinion). The parent should just give the child the callbacks it wants directly

That's what setting event listeners is. The parent knows about the interface of the child, not necessarily the other way around. So the child won't be able to know what callbacks to call. That is also why inversion-of-control leads to more stable platforms.