Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Comparing Ember Octane and React (pzuraq.com)
63 points by mokkol on May 12, 2020 | hide | past | favorite | 53 comments


The author has taken an Ember app they wrote themselves, and compared it to a React example that includes code from the 19th chapter of a guide to learning React, "React Custom Hooks (Advanced)", without working through the first 18 chapters. It's no wonder they found it complicated.

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.


Hey there! Author here. I actually did work through all of the examples and am very familiar with all of the hooks, I have done a lot of in-depth research while designing and working on Ember in order to understand the pros and cons of hooks.

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 React example is one file because it's an example

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.


I didn’t get the sense that the author was passing a value judgment against react for being in a single file. Later on he mentions that he likes the ability to colocate component and template, as it is more flexible.


Having interacted with Core Ember devs I would be very surprised if the author didn’t know anything about React. I’d wager that he indeed knows a lot about React.

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.


Having worked with React/Hooks for the past few months - I think he did a good job of identifying the benefits and problems of hooks. In a production application, you are likely to use something like redux or xstate to keep the state in your components minimal which in turn allows you to avoid a lot of the complexity that hooks have.


React has no defined file system, and strongly encourages components are written in a single file.

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.


I don’t think that’s what he is talking about here though. And note, his point about the multiple files isnt even a complaint.

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.


Convention over configuration is one of the worst ideas ever in software in my opinion. All it means is that you have to memorize all the implicit assumptions about how an app is put together before you can work productively. It makes for great convention talk demos but in production what you really want is very explicit and obvious relationships between pieces. For example, this is the reason I find a React/Typescript codebase vastly easier to understand than Rails.

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.


> Convention over configuration is one of the worst ideas ever in software in my opinion.

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.


I dislike convention over configuration big time. It’s the reason I could never do RoR as much as I tried to learn it when moving from C/C++ dev to more web dev.

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.


No, it means that there's a way things are usually done, but if, in you situation, a different way works better, you are free to use it without having to fight the framework.


In a React codebase, for example, I can look at the imports and see immediately where everything in play in that file came from. In real production codebases this is invaluable.


I definitely agree with this! In large codebases especially. This is ultimately why Ember has decided to move toward using JS imports to stitch components together as well, we recently merged an RFC to do just that.


This was my favorite part about Ember, and what I miss the most.

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 can look at the imports and see immediately where everything in play in that file came from.

I'm confused, ember uses standard js imports as well so what's the difference?


This is an excellent writeup. Something that sticks out to me is that the Ember code feels much more readable than React with hooks. The "future" component at the bottom using inline glimmer templates with @use is especially exciting! To be honest I think that could be a game changer and get more developers excited about Ember.js.


I'd agree that React Hooks is a big shift towards unhealthy coding practices. But used wisely it can simplify the trivial scenarios. Only problem is to find wise javascript devs...


From a perspective of someone who codes react, what i dont like in ember:

- 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)


Tbf, I would gladly take mutability or impureness over unnecessarily complicated approach. One example of it is the suspense api in react. Suspense uses a promise throw approach opposed to generators. Your code throws a promise and suspense catches it to render fallback until it is resolved.

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.


for things like loading state with ember we use a library called ember-concurrency that uses the generator approach. It's very nice!

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


ember-concurrency is probably at the top of the list for things I miss most when writing javascript outside of ember.


A lot of these apply to other frameworks too especially Angular, which has a very unhealthy love affair with decorators.


I am curious where decorators make sense. I find them unreadable with little to gain back so I avoid writing them myself. Class extensions works for most of the use cases of decorators. I guess they are helpful when you need to modify class methods and properties.


I like and use Ember a lot, but the one gripe I have is that Handlebars uses s-expressions instead of just inline JS. The constant context switch is massive and it’s not possible to hook into Typescript types, and I doubt it ever will.

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.


> it’s not possible to hook into Typescript types, and I doubt it ever will

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.


Really cool, didn't know Vue had this. It's great that it's in the works, and I'm really really looking forward to it. Will it be statically typed s-expression or more like regular JS? I spoke a bit to pzuraq about this on Reddit and it seems to be still s-expressions going forward?


What we're aiming for at this point is 100% TS support for the current Glimmer syntax—we expressly want to support Ember and Glimmer usage as they are today. If Glimmer/Ember itself were to move toward supporting something more like the way Svelte's templates work (which is closer to what we could support while maintaining the tradeoffs Glimmer makes relative to JSX), we'd of course move to support that as well, but there's nothing like that planned at the moment.


This is amazing


Honest question, what's so bad about `this`?


Dynamic scope[1] is generally considered to be harder to reason about since their values are not determined by where they appear in a file (but rather by how the code executes at runtime)

[1] https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexic...


OP doesn't like coding in javascript to feel like coding in javascript, I guess.


I expected a flamewar trigger but it was a nice writeup. It's nice to see that compared to a few years ago (remembers rails dramas, Node.js is *, ASI in Bootstrap), hackers have stopped the "biggest dick contest" posts. Guess it's on twitter now...


I find all this code so hard to read, because there are very few elements being composed together. It reads like one monolithic chunk of code (and with a global state!).

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.


I wrote the Elm counterpart of the same example...

https://dev.to/eberfreitas/comparing-elm-to-ember-octane-and...


The functional zealotry stink permeates every corner of React. The Ember approach seems much more aligned with my preferences.


Please don't break the site guidelines like this. Make your substantive points thoughtfully.

https://news.ycombinator.com/newsguidelines.html


I don't get why so many JavaScript developers thing functional is cool. Functional has been around for 30+ years. OOP won against functional because OOP is easier to understand and leads to more maintainable code. These days people are taking a second look at functional because functional avoids state, which makes it easier to write concurrent code with no locks. (This has suddenly become important because Moore's law is coming to an end, and CPUs are adding more cores instead of making cores faster and faster.) But this advantage of functional is not applicable to JavaScript because there are no locks in JavaScript in any case!


JavaScript is also an extremely bad functional language unless you don't mind ridiculous memory bloat and inefficiency. To be even reasonably efficient you're basically forced to use classes because the primary ergonomic alternative is objects that contain functions that close over lexical scope. This is ridiculously inefficient because functions that would normally have a single instance on the prototype chain are now duplicated for every single object. Modern JavaScript engines can't optimize this without breaking the spec which they obviously won't do. You can resort to just using plain functions and objects that contain nothing but data but this quickly becomes quite ugly without a pipeline operator.

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.


To be fair, JavaScript is also an extremely bad OOP language.

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.


It’s hardly JS developers who think functional programming is cool. Scala became huge in the JVM world because of its functional nature. Kotlin includes a lot of functional programming, and Java itself continues to add functional capabilities.

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.


Functional programming actually brings some benefits to backend code. To take advantage of the extra cores in a CPU you add threads, but if these threads are continually needing to lock in order to access shared state then concurrency is diminished. The more cores you have, the more threads you have, and then the more you have to lock. Functional style solves this problem by not having mutable state, thus eliminating the need to lock.

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.


Yeah. I have noticed few instances of badly optimised functional code.

something like

  examples.reduce((accumulator, example) => {

    // logic
   
    return {...accumulator,[example.name]: example.value }

  }, {})
Object spreading and destructuring combined with fancy immutable array methods smell..


+1. I think hooks is what finally pushed me over the edge towards saying to myself, enough with this insanity.


>I think hooks is what finally pushed me over the edge towards saying to myself, enough with this insanity.

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.


Isn't that just comparing old code (i.e. code that has grown organically) vs new code (code that hasn't yet)? Surely given enough time you'll end up with just as large/complex a function as an olden class?

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.

[1] https://news.ycombinator.com/item?id=926140


When hooks first came out and I started playing with the API, I had the same feeling! It felt refreshing, but I couldn't quite nail down why.

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).


> "once you start using pure functional components it all makes sense and your code becomes so much cleaner and easier to reason about"

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.


> This is the "Emperor's new clothes" argument that the FP zealots march out over and over again.

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.


> Specifically that class components tend to get massively bloated over time with business logic

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.


Couldn't you do the same thing with class components though? From what you've mentioned it seems you've mostly moved complicated logic into reducers. I may misunderstand though.


>Couldn't you do the same thing with class components though?

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.


What I like about hooks: They ask us to question some long-standing "best practices". I feel like we should do this every so often as it promotes progress in our thinking.

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.




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

Search: