Comparing Ember Octane and React
pzuraq.com
pzuraq.com
Comparing things is good and useful, but if you're not qualified to understand both sides of the argument well it's really hard to do a good job. This article fails hard on that count.
Also...
The first thing that is a clear difference with the Ember Octane version is that it's split across multiple files.
The React example is one file because it's an example. The idea is to demonstrate all the moving parts in one place. It's not presented as a representation of what you would build as a production app. If you look at Road To React there's a chapter called "Folder/File Organization" in the appendices that explains how you might progress after working through the tutorial app.
At least the ones I interacted with did not only know React, they knew it well enough to identify its pitfalls, and be able to translate what they believed to be its best parts to EmberJs.
Also, the comment about different files is a thing even outside this example (and is one reason I prefer react over Ember personally). React has no defined file system, and strongly encourages components are written in a single file. Ember, OTOH, does a lot of file separation, and a lot of convention over configuration.
If your language is so verbose that making things explicit is too painful then maybe it's time to reach for a more expressive language instead of hiding everything behind a set of implicit rules.
The Ember team is one of the least dogmatic teams that I have come across, and has been willing to change their entire strategy when presented with a better idea (while providing a well defined and fairly convenient upgrade path).
I still remember when React first came out, and showed how one way binding was so much better than 2 way bindings, and the Ember team was able to quickly switch to this new philosophy via DDAU, while still providing an easy upgrade path for our code. And all this was before 1.0 if I remember correctly.
I'm confused, ember uses standard js imports as well so what's the difference?
When I first started working with ember many years ago, I felt the same way. But now after working on many ember apps, I feel the opposite. The "convention over configuration" really only applies to basic application structure e.g. routing/templates/controllers etc. All it's really doing is creating a standard place to put files, which itself is flexible and more recently allows e.g. colocated components like you'd see in react/vue/etc.
I think the core point from the article is just how much ember.js has changed and matured. If you read to the bottom it looks like single-file components with glimmer are in the pipeline as well.
But it’s definitely not the worst idea. People who like that approach seem to be extremely productive with it.
It’s definitely not my cup of tea though.
Sure, but there's a lot more to the example that a single component. There's the app component, 3 other components, a reducer, and a custom hook. Putting all that in a single file is fine for an extended example explaining how things work together with a further chapter explaining how to break it down in to separate files, but it's not how you'd write a real app. The article author clearly doesn't know that if his criticism is that Ember does it better by using more files, so it not unreasonable to question if his knowledge of React is up to comparing it to Ember. It's quite a fundamental mistake he's making.
As someone who worked with Ember in the past (our company inherited a new product with an acquisition so we were forced to change tech stacks), this comment really comes from the fact that Ember has a very comprehensive file layout system. And one of the major criticisms about Ember classic was how different core pieces for the same component, were located in so many distant folders (hence the comment about colocation of component code, which seems trivial, but is a huge usability gain IMO).
I think that sentence should be read more as a reflection on Ember, than suggesting the author does not think React components can be broken into multiple files, and hence an indication of their knowledge of react.
Typically, when another framework makes a new API that is popular, my first reaction is to do research and try to understand how the API works, what its pros and cons are, and to see what I would like to pull back into our own work. As I noted near then end, there is actually a lot I like about hooks! While it does feel a bit overly granular and tricky to me, especially at the lowest level, it adds a composition primitive that didn't really exist before, and doesn't exist currently in Ember (though we're working on it, like I mention near the end).
I think we may just have a different sense of what drives complexity, and what can cause antipatterns at a high level. I would prefer something just a little bit less expressive, but with many of the same composability benefits.
> The React example is one file because it's an example. The idea is to demonstrate all the moving parts in one place. It's not presented as a representation of what you would build as a production app.
I'm very aware of that! I was actually just pointing out a difference there, and that difference is actually something that is _enforced_ in Ember (and actually something we're looking to change, as I discuss in the last section of the post), so I was mainly pointing it out in case people were wondering why I didn't have a more equivalent example.
I didn't use the later examples because they added too much more functionality for me to address in a single blog post, and I didn't want to split the files out in the example because I didn't want to change anything in general, in case people thought I was making bad-faith changes just to make React look bad.
The argument here is that Ember - true to its frameworkiness - enforces a certain file organization pattern. In React, you _can_ split things into different files, but how _you_ do it might not be the same as how _I_ do it (and one may not even do it depending on the situation, e.g. a one-off Error component in a bundle-split API.)
On a similar account, because Ember is frameworky and convention-over-configuration, then a happy path in it _should_ be less "complicated" than wiring everything up manually in a less opinionated system. That's sorta the whole point. There are certainly arguments to be made about magical-ness and not-so-happy-paths, but I don't think it's fair to characterize the differences in framework philosophies as an author failing.
- this this this, so many this keywords
- not a fan of decorators
- constructor and super
- mutability (unless it hides an immutable nature)
- hbs feels weirder to me than jsx
- the fact that you have yet another filetype in your code means even the tiniest components MUST be in more than 1 file, react lets you choose (edit: i rushed, seems there are template literals one can use)
Would love the possibility to enable a flag to just enable JS-in HBS like
{{#if this.model.isEnabled(this.byOtherVariable}}
{{aHelperCall(this.args.thing)}}
{{/if}}
Kinda like a hybrid of JSX and HBS, but combining the best of both worlds.While it's not possible today, it's definitely possible in principle. (Vue is a great example of this!)
The folks working on TS integration in Ember (of whom I am one) are very well aware both of the problem, what it will take to solve it, and what the state of the art is elsewhere. No timelines, but we're working on it and when we're done the experience should be comparable to TSX. All of us working on it think TSX is a killer bit of DX and it absolutely is a thing we're aiming to match.
[1] https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexic...
You end up with few ugly situations. First, I hate that I have to wrap my components (what if you want different fallback for different components? You end up with many wraps), how my UI will render is not isolated anymore. I often end up returning loading view from the components as we as well using it as a fallback for suspense. It just feels wrong. I lack control.
Example you can create some "task" (promise-like), then in a template you have automatic access to it's state so e.g.
``` {{#if this.fetchStoriesTask.isRunning}} loading... {{else}} <span>Loaded 10 Stories</span> {{/if}} ``` https://github.com/machty/ember-concurrency
I find code enjoyable to read and write when it's like Lego. You build small little self contained pieces and join them together. It makes a big difference when building large applications.
I wrote an example in [Concur](https://github.com/ajnsit/concur) to demonstrate what I mean - https://gist.github.com/ajnsit/f0fee9a83480289a5a052273ce21c.... The "app" is composed of self-contained widgets, each of which are short and easy to read, and have a defined purpose (show the searchbox, render a story etc.) In a larger app, they can be mixed and matched together in logical ways.
https://dev.to/eberfreitas/comparing-elm-to-ember-octane-and...
Did you actually build anything with Hooks? I was pretty turned off by it at first sight as well. It doesn't jive with the sensibilities of a class based OOP developer's natural instincts. But once you start using pure functional components it all makes sense and your code becomes so much cleaner and easier to reason about. No more component lifecycles and massive class files.
This is the "Emperor's new clothes" argument that the FP zealots march out over and over again. I guess I'm among the ranks that can't see the clothes.
I wouldn't call myself a zealot. We chose functional components for a new project on my team as a direct response to problems we were having with maintainability of larger React applications. Specifically that class components tend to get massively bloated over time with business logic, lifecycle based rendering logic, and local state. I was skeptical at first as well. But it turns out that once you start fully separating things out into reducers and actions, the class becomes little more than boilerplate. When you enforce that there are no class members or local state allowed in UI components, it pushes people into proper separation of concerns. The project becomes much more maintainable as you don't have to dig around through components to find out what's going on.
Sure. But the point is that the entire class syntax becomes superfluous once you do that. Everything becomes a pure functional component, and you can just throw in a `useEffect` wherever the need for lifecycle based side effects arises.
You have been doing it wrong. Don't put business logic into visual components. UI technologies tend to be a fad. Business logic needs to live longer than UI technologies, and needs to be separated from UI components for testability, maintainability, reusability and longevity.
I don't think it's that you don't have to worry about lifecycles, in the end. You still do - you have to understand the lifecycles of your functions which are different than those of a component class, but they are lifecycles in there own way. What I think really makes hooks feel nice is you can _close over_ the small, self-contained lifecycles, and introduce them at any point in the program in a composable way. That's pretty neat actually, and what we've taken away from hooks currently.
Maybe that's not the only benefit they have, but it's a pretty large one, so I'm glad hooks decided to explore this new direction, even if I'm not completely sold on it (as in, wouldn't introduce it in Ember just yet).
The proposition of hooks is that they do accomplish the same things as class lifecycle methods do, just in a different way, so all the underlying complexity must still be there by definition.
This discussion reminds of this little parable[1]
> The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures." Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.
> On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.
What I dislike: They promote patterns that go against long-standing "best practices". (Should we really be defining functions over and over and over again?)
So, the biggest advantage, is also my biggest gripe.
something like
examples.reduce((accumulator, example) => {
// logic
return {...accumulator,[example.name]: example.value }
}, {})
Object spreading and destructuring combined with fancy immutable array methods smell..The standard library is also filled with mutating methods and doesn't include proper functional data structures and pure JavaScript implementations of functional data structures, such as immutable.js, are so slow that you might as well just use arrays and objects and repeatedly do shallow copies.
Programs that stress functional purity in JavaScript are becoming hard to meaningfully benchmark because instead of having a few hotspots absolutely everything is incredibly inefficient and slow. Death by a thousand cuts.
And I’m not complaining about its prototypical inheritance either (I actually like it), but the fact that it tries to hide its prototypical nature under a Java like veneer.
And if you look at the .Net side of things, C# has basically been on a path to look increasingly like F# with every release. And of course, LINQ, one of C#’s most popular features, is little more than a functional subset of C#.
Arguably its backend developers moving to the front end who have been trying to bring functional concepts to front end programming.
But when it comes to JavaScript these benefits don't exist. That's not to say there are no benefits at all to incorporating some functional style into JavaScript code, but wholesale replacement of OOP with functional style is not warranted.