Readers' Questions: "Are there plans to improve the experience for using Data Down, Actions Up in the future?"

Hello everyone and welcome back to another edition of Readers’ Questions presented by the folks from The Ember Times :sparkling_heart: ! This week I’m going to answer the following question by @erikrothoff (1):

It’s really true that DDAU is the Ember way, yet Ember itself does quite little to make this way of working easier/safer/more robust. Are there any plans or ideas to improve the experience with DDAU?

The so-called “Data Down, Actions Up (DDAU)” paradigm has been a popular practice in Ember applications since the early 1.x era (2). It is used to ensure that data flows unidirectionally between routes, controllers, parent and child components. Unidirectional data flow contributes to application state that is easier to manage and debug. If you want to learn more about what DDAU is and how it is applied, be sure to check out our answer to a previous Readers’ Question explaining the pattern (3). You might also find the EmberJS Guides about triggering application changes with actions to be another useful resource to learn more about it (4).

But are there any plans to improve the developer experience for DDAU in Ember apps though? The clear answer is: Yes.

With Ember Octane, the upcoming first edition of Ember, the Glimmer Components API for building modern components will improve the developer experience for DDAU in your app significantly: in Glimmer components, arguments (properties which are passed into the component at its invocation site) are immutable (5). This means that any properties passed down to a component from a parent component or a controller cannot be directly modified on the child component, but instead need to be modified by the data owner - e.g. by triggering an action passed down from said data owner. There are exceptions to this behaviour though; to guarantee backwards compatibility, in Ember Octane it will still be possible to mutate arguments directly by 2-way-bound, classic components such as the built-in <Input /> when used inside of a Glimmer component (6).

The Named Arguments Syntax makes it easier to recognise immutable data, by clarifying where they are coming from (7). Immutable arguments (i.e. data passed down) are identified as @toto in our component templates and as this.args.toto in our component .js file, whereas properties defined on the component itself are explicitly referred to as this.toto. This makes it easier for you to track down data in your components that need an update via DDAU.

Autotracking via the Tracked Properties feature on the other hand encourages us to write side-effect free getters and avoid state updates using observers, ultimately promoting unidirectional data flow in our Ember apps (8, 9).

Finally, the way in which we can define and pass around state-modifying methods in our application is being simplified with Ember Octane. The fn helper, combined with the on modifier will leverage the same functionalities that we are already used to when using the {{action}} helper in classic Ember apps (10). In addition to that, fn allows for more advanced use cases, including the application of several arguments to a method. Using fn allows for the application of arguments in a clearer and more predictable fashion than the previous method of currying arguments with closure-based actions in classic Ember apps(11, 12).

And another reminder: You can already try out Ember Octane and the new DDAU experience in your apps today! Since Ember 3.13, the framework is feature-complete in regards to Octane. You can check out the Octane Edition Page (13) to review the emerging new Guides for the edition and enable its feature set in your app using the instructions from the official Ember 3.14 release announcement (14).

Last, but not least, a :sparkles: big thank you :sparkles: goes to @void_malex, @ijlee2, @jenweber and @pzuraq who helped answering this Readers’ Question!

Sources


This answer was published in Issue #125 of The Ember Times . Don’t forget to subscribe to the newsletter to get new Readers’ Questions and other development news right in your inbox. You can also submit your own questions! You will find a link at the bottom of the newsletter.

Do you feel up to answer community questions for another edition of The Ember Times yourself? Ping us anytime on the #support-ember-times channel on the Ember Discord! :sparkles:

See you in the next issue! :sparkling_heart:

11 Likes

I think we could take it a bit further though by demonstrating some architectural patterns.

Data down, actions up, (while the clearest way possible to show the flow of data at a glance!) can very easily lead to prop drilling… Which is an anti pattern where you pass args through many layers of components, which can make maintenance difficult.

Techniques for resolving that could be:

  • wrap args in an object, so you’re defining less things to pass at each layer.
  • manage your state in a service to access at the endpoints of where the state needs to be interacted with
  • something I’ve been meaning to explore and make an add-on for is local services – sometimes the state you want isn’t really app level state, and you want it private to the route. Imagine, you fetch data in a route’s model hook. Define a local service to hold that data, maybe have some crud actions in that local service. Then, you’d be able to inject that service at any layer of component below where you defined the local service, allowing you to avoid prop drilling for a very common data pattern in ember. I have an idea for implementation… Just need to find the time.
8 Likes

Another promising related project is GitHub - pzuraq/ember-box

And while it says “two-way-binding” in its description, it’s really another flavor of API for solving the same problem we’re discussing here.

6 Likes

Since immutability is a complicated subject with a wide variability of potential meaning I want to clarify for future readers that when Jessica discusses @args being immutable above that it specifically refers to shallow (or referential) immutability.

In pure JS terms: args are const. If they are an object, properties on them could still be mutated, but the primary reference cannot be changed.

const myArg = { status: 'clean' };

// errors because you cannot change the reference myArg
myArg = { status: 'dirty' };

// works because you have not changed the reference myArg
myArg.status = 'dirty';

The shallow immutability of args is about providing strong visual cues and a small amount of insurance, it’s not a full immutability guarantee.

Hopefully this doesn’t start a let vs const debate for args :sweat_smile:

4 Likes

Have you seen ember-provider?

Yeah, it puts everything in app/providers, which I’m shortly against, as it spreads concerns to distant places. Similar concerns / the usage of those concerns must be co-located. Also, it only works with ember/component. I’m full glimmer in my side projects :wink: