Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Love it. I think the most discussion-worthy quote I found in the docs is this:

> It's currently fashionable to avoid two-way binding on the grounds that it creates all sorts of hard-to-debug problems and slows your application down, and that a one-way top-down data flow is 'easier to reason about'. This is in fact high grade nonsense. It's true that two-way binding done badly has all sorts of issues, and that very large apps benefit from the discipline of a not permitting deeply nested components to muck about with state that might affect distant parts of the app. But when used correctly, two-way binding simplifies things greatly.

I wonder what the author considers "used correctly" and "done badly" and how Svelte approaches this.



My understanding is that there are two issues with two-way binding that are structural, and will be difficult to fix no matter how you approach it.

First is that if you look at the system as a graph of updates, automatically closing all cycles between variable update and widget means that any additional two-way binding links you add become a cycle, which makes it difficult to implement, model, and debug. If the framework only initially links the variable to the widget or the widget to the variable, the graph is a lot less populated to start with and creating a cycle is much harder.

Second is that the developer ends up wanting more and more complicated transforms over time, and having to implement both directions of them at once is much more difficult than having to implement only one direction, because not only are you writing two transforms instead of one, you also really ought to make sure the transforms are able to be roundtripped without data loss, and also that any invalid states on either side of the transform are handled sanely in some manner. Very few developers think this way; it's one of those places in programming where you really need to approach it with a mathematical state of mind, but it's generally being written by the "I don't see how programming is connected to math" types. (Which is something a two-way binding advocate needs to keep in mind when writing their library; you're not going to get your users to deeply understand the way the library works before they can benefit from it, they're going to want to just dive in and get something useful going.)

These are not necessarily insurmountable problems, but they are fundamental problems to having two-way binding. I think these two things are why it has never really taken off despite the fact I've seen at least half-a-dozen attempts over the years. I can imagine programming language tools that could help with both problems, but as what I'm seeing getting sketched up in my head requires a type system at least as strong as Haskell's to be practically usable without so many holes as to be insignificantly different from what we already have, it's not going to take off anytime soon.


Two-way binding is being used without popular mention in some industry-specific areas. The area I'm familiar with is control software for audio processing hardware. Lots of different processing platforms allow the creation of control panels with a drag-and-drop UI, and all widgets assigned to the same hardware state variable are also linked to each other, in all directions.

I also implemented my own two-way/omnidirectional data binding system ages ago (before I knew what it would even be called) in Java Swing for another audio UI, and all the challenges you mention are real, but as you say, not insurmountable. Multiple copies of my UI can be controlling the same hardware, and they will all remain in sync without infinite feedback loops, but getting there took lots of work.


This is a really helpful way of describing the problem. Concretely describing behavioural coupling in terms of graphs is much less hand-wavy than the normal, "things become tightly coupled and which becomes hard to deal with."


That's the core of it - 2 way data binding creates tight coupling.


That's a nice description of the problems.

Dataflow constraints with solvers like DeltaBlue solve these problems and allow you to incrementally add additional constraints.

I show how this works for a simple example in my paper "Constraint as Polymorphic Connectors"[1]. I also show that constraints are useful for expressing the high-level architecture of many interactive systems and suggest how to two might be connected.

[1] https://www.hpi.uni-potsdam.de/hirschfeld/publications/media...


"...you also really ought to make sure the transforms are able to be roundtripped without data loss, ..." In my experience this happens inevitably; either you code it right the first time or end users discover it and it comes back as an issue that gets fixed later. There is little math involved in my experience and it's pretty hard to miss this kind of issue unless you're a complete cowboy coder or have never seen it before. Once it bites you in the ass it's not likely to recurr.


I didn't say it involved math. I said it involved mathematical thinking.

You may have bodged together the relevant concepts by experience. That works perfectly fine. But there is a faster way to learn and teach it... if you can get people past the idea that there's some sort of virtue in bragging (for lack of a better word) about how math has nothing to do with programming and how little they know about the mathematics involved in programming. It's all way easier if you start with the concept of an isomorphism and learn how to compose them from the beginning, rather than having to rewrite the same concepts in your code over and over again without realizing it.


Excellent overview. Definitely helped me understand the issues better.


Yeah...

If not "used correctly" means a buggy app, and it's easy for an inexperienced developer to make those mistakes, you're still in for a world of pain. If you need to be an expert to avoid accidentally screwing everything up, there's still work to be done.

This is the whole "pit of success" thing Facebook talks about, the path of least resistance should be towards a functional nearly bug-free app. Certainly an app where bugs are relatively well-quarantined.


One counter argument to the author's point is that there were many not-very-popular 2WB frameworks, until React and Angular came along. 1-way, top down clearly outcompeted 2WB.

In my own experience, I worked on an app that migrated from a 2WB (forgot the name, sorry) to React, and it was night-and-day difference.


"Used correctly" to me sounds like: "with much knowledge, experience, care, and luck" ie. a footgun, especially for beginners.

Similar things have been said about memory allocation in 'do whatever you want' languages like C++.


Yes.

I have the feeling most programmers are just lazy, that's why they use 2WB.

And I can't blame them. Redux is much more boilerplate than MobX, for example.


Trying to avoid boilerplate is in my experience not about laziness - especially when you consider the extreme lengths a lot of developers will go to to eliminate duplication and boilerplate from their codebases. Copying a Redux reducer that implements a standard set of CRUD actions is lazier in my mind than trying to abstract common patterns away.

For me at least, the reason boilerplate bothers me so much is that it impacts the readability of my code. Ideally, I'd like my codebase to express the business requirements of my solution as succinctly as possible - every line of boilerplate code I need to include to express yet again how to make an AJAX call, or update a piece of state, is a distraction from what I'm actually trying to accomplish with the application.


"the reason boilerplate bothers me so much is that it impacts the readability of my code"

But if you hide boilerplate you not really improve readability. Not seeing what is really happening just creates the illusion of readability.


If the thing that I'm abstracting is routine, and unrelated to the business problem I'm solving, I don't need to know what's happening (at least in the sense of me or someone else coming back to read the code later). I don't need to know how an HTTP server, or the particulars of an AJAX request work most of the time.


true, but when there is something unexpected about how the AJAX request or the HTTP server are working then debugging is going to be harder because of the abstraction.


No, the work in fact will be easier - because something unexpected will either happen above, below or on abstraction boundary - as opposed to "somewhere in this big blob of function invocations". Also, you'll get to fix the bug in one place instead of having to hunt down every similarly looking piece of code because it may contain the same issue.


Is it really? If there is an error it's either the abstraction or the concrete usage it stems from.


I guess I agree with that; I was thinking specifically in framework defined abstraction / usage.

And if the framework has abstracted away something that you end up needing to understand - well bad framework or bad usage I guess, but still difficult to figure out what's going on.


Taken to its extreme, that argues for writing everything in assembly language.

React's virtual DOM diffing makes components more readable than the previous style of writing code to explicitly manipulate the DOM and totally hides what's really happening. However, we trust that it's going to do the right thing, just as we trust that the JavaScript engine will do the right thing when it JITs and interprets our code.


The point is, don't take things to the extreme :)

It's not that people said "Everything is bad, do assembly". It's just that people identified 2WB as problematic and you just shouldn't do that one thing.


What I find interesting is that while I actually agree that 2WB as was done before was problematic, MobX which looks like previous-generation 2WB may actually be just fine because of features specific to its implementation of the idea (actions, and better tools for use in development)


Currently JS frontend folks also classify MVC as "problematic", yet a lot of successful software was written that way. So along with J2EE folks, this isn't really the community to look for style standards by default.


Honestly, given that I know of no two developers that have the same understanding of what MVC is and how the code should be divided, I have a feeling there's something wrong with the pattern itself, too.


I don't have a link handy, but I read a piece by one of the original MVC pioneers claiming that the pattern was designed for encapsulated components, usually fairly small, not entire applications. I suspect many of the quirks and disagreements between different MV* architectures derive from this fundamental misapplication of the pattern.


'illusion' and 'readability' are interesting choices for words, given that both refer to how something is perceived.

The argument I'd make is that the illusion is the point when you're writing well abstracted code. The abstraction makes it possible to write code with the assumption that some specific detail is taken care of automatically. While it's true that the detail is hidden, that lets the author and reader of the code focus on other details that might be more important.

Of course, this doesn't absolve anybody from needing to be at least somewhat aware of the abstractions, but hopefully most of the abstractions can fade into the background most of the time. (Anybody who's ever worked with a buggy compiler can attest to how frustrating it can be when this is not the case.)


Hard to say when his only argument is "is in fact high grade nonsense". He's missing the big picture though: performance matters but not completely, it's not two way binding that makes two way binding bad, its developers using two way binding that makes it bad.

I also think it's ignorant to say it's fashionable to avoid two way binding, I've seen teams greatly benefit from avoiding it, teams with less experienced devs and devs who I've previously seen write terrible code. Maybe now two way binding would be easier for them, though I don't know; I'm unlikely to suggest they 180 on tech that has made them much more successful.


Redux fixes two way binding by forcing the developer to emulate it using such a convoluted mechanism that there's no way to see that it's still broken; great job, FB rockstars!


Redux is to manage state across the app.


If u don't like it you don't have to use it. And redux is nothing like that. It reduces a tonne of bugs among a lot of not so smart developers or beginners.


> If u don't like it you don't have to use it

Don't write things like that, it always reads like "Noone cares about your opinion, so stop using X and also stop writing about how bad X is"


Wow. How can someone even understand it like that! No way. I actually meant what I wrote and im not really worried about what someone else might think about my comment. Cause it's way way softer.


Even if someone doesn't like it AND doesn't use it, they can still tell the world how they think about it.

You could have written your comment without that sentence and it would still convey your opinion :)


hmm good point though




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: