Skip to content

Deprecate Ember.K#178

Closed
cibernox wants to merge 20 commits intoemberjs:masterfrom
cibernox:deprecate-ember-k
Closed

Deprecate Ember.K#178
cibernox wants to merge 20 commits intoemberjs:masterfrom
cibernox:deprecate-ember-k

Conversation

@cibernox
Copy link
Copy Markdown
Contributor

@cibernox cibernox commented Nov 18, 2016

@vvscode
Copy link
Copy Markdown

vvscode commented Nov 18, 2016

Never use chaining with Ember.K. In my experience - it's an alternative to non-existing nop ( or I should "implement" it in each project? ) at places where function should be, but I'm not sure about implementation in children, and won't check typeof / use tryRun - so didn't see any pros ( or lets add nop operation instead of )

@kimroen
Copy link
Copy Markdown

kimroen commented Nov 18, 2016

I remember coming over this function the first time in this blog post, which was published in July, 2014: "What the hell is Ember.K?".

The description of what it is useful for in that blog post is summarized in these bullets:

  • Making methods safe to call in the event that they might be undefined at the time of calling.
  • Providing hooks for subclasses to implement in a safe way.
  • Creating stand in action event handlers until you are ready to implement the necessary logic, and avoid Ember.js throwing an error.

So essentially, temorary code or hooks for subclasses.

Is this still useful? Is the suggested change in this RFC an acceptable replacement for Ember.K? I think it is. There are other ways of accomplishing the same goals.


While doable, any possible benefit in code size or allocations obtained by reusing
the exact same Function instance everywhere would be greatly smashed by the
overhead both in space and CPU cycles of importing it in AMD-transpiled modules.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't necessarily seem true. Using Ember.K through a large app is almost certainly fewer allocations that creating lots of one-off functions.

If there is a performance argument for this it should be better made and benchmarked, IMO. I don't think you need a performance argument for this RFC though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code wise the transpiled output is bigger.

Perhaps I was overconfident that the overhead of adding one extra import (the more imports the more work this.reify() has to do to create the this.reified) will overcome function allocations without a proof, but I can run some benchmarks to check it.

Copy link
Copy Markdown
Contributor Author

@cibernox cibernox Nov 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've ran some benchmarks, importing with requireJS with two modules VS importing only one and creating the functions inline.

With 100k iterations the diference are despicable. Depending on the run on wins over the other (2.3s)

I'm going to remove the performance concern from the reasoning.

Byte-wise declaring the function inline is shorter unless you use Ember.K more than 3 times per per import.


The second downside of reusing the same instance in many places is that if for
some reason the VM deoptimizes that function, that deoptimization is spreaded
across all the usages of `Ember.K`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never seen this when profiling. Is it a real-world issue you've seen?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rwjblue mentioned it in slack and here an some smart fellows 👍 'd it

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...but is it a real-world thing? Or just an idea that it might sometimes be an issue?

I'd like to keep RFCs rigorous by including, as justification for a decision, things which we know to be true when possible. There are some constraints that are based on intuition (does this API feel good) and some that are analytic. Performance is almost always an analytic constraint we can understand and test.

I'm wary of an off comment by @rwjblue being cargo-culted into a learned fact. We should be careful in RFCs we don't perpetuate assumption.

@mmun
Copy link
Copy Markdown
Member

mmun commented Nov 18, 2016

I haven't used it in 3 years. Coupled with being trivial to reimplement where needed, 👍 for removal.

@ghost
Copy link
Copy Markdown

ghost commented Nov 18, 2016

I am 💯% fine with killing this.

Let's also celebrate that we're having an RFC for deprecating a three line 'no-op' function 🎉

cibernox and others added 6 commits November 19, 2016 00:09
After some local benchmark, the performance differences are despicable one way or another.
With 100k iterations depending on the run one approach wins over the other.
Update 0000-deprecate-ember-k.md
Update 0000-deprecate-ember-k.md
@simonihmig
Copy link
Copy Markdown
Contributor

I have actually used it and still using it in a number of apps. Almost exclusively for noop default actions in components, in case the component consumer does not provide its own (closure) action, so I can safely do this.get('onSomething')(); without having to put this in a guard (so to not get an undefined is not a function exception).

I can see different styles of guards against this, like inline (https://github.com/cibernox/ember-power-select/blob/master/addon/components/power-select.js#L324-L327) or using a utility function for that (https://github.com/offirgolan/ember-light-table/blob/master/addon/utils/call-action.js).

I am happy to learn if that is not considered a good style for whatever reason, but until then just declaring the action as noop (when importing Ember.K as noop) and simply calling it straight away seemed to me the style with the least boilerplate code and good readability.

Redefining noop with () => {} (never used it for chaining) is certainly no big deal, but just keeping Ember.K is not either. And until now I thought reducing function allocations would be a good thing.

On that matters, is the function allocations vs. import overhead argument still valid if rollup.js style module inlining should eventually land in ember-cli?

@cibernox
Copy link
Copy Markdown
Contributor Author

cibernox commented Nov 19, 2016

@simonihmig I ran some benchmarks with 100K imports/allocations and performance difference is negligible either way.
Transpiled code is mover verbose unless you use Ember.K a quite few times on the file, although in that case doing const noop = ()=>{}; and reusing it is still shorter. Still on the big picture that verbosity is probably a drop in the ocean.

I'm going to shift the tone of the RFC away of the performance topic because it's not a big deal either way, and focusing it on removing from the public API low level utility that is trivial to replace.

@workmanw
Copy link
Copy Markdown

I'm going to shift the tone of the RFC away of the performance topic because it's not a big deal either way, and focusing it on removing from the public API low level utility that is trivial to replace.

I too use Ember.K a lot for base and interface classes. And while it would be simple for me to replace in my app with my own helper or just use inlined functions, if the purpose of this RFC is not performance, is it really necessary at all to deprecate it? To be perfectly honest, this is the kind of churn that so many people complain about. It's not a huge deal and it really doesn't effect anything, but now they have to learn to do something a little bit differently. They have to replace an old pattern with a new and things are exactly the same.

@locks
Copy link
Copy Markdown
Contributor

locks commented Nov 19, 2016

@workmanw

is it really necessary at all to deprecate it? To be perfectly honest, this is the kind of churn that so many people complain about.

The performance argument isn't the only one that can be done for a deprecation. Ember has been trying to slowly prune unnecessary APIs from the core library, and this is a good candidate due to being a very small, easily replaceable API. You might have noticed how FastBoot, Engines and more are mostly being done outside the core library :D I'm currently trying to gather some data so we have an idea of its usage, and will post an update when possible.

Opening this up for discussion with y'all :)
@cibernox
Copy link
Copy Markdown
Contributor Author

cibernox commented Nov 20, 2016

@workmanw

is it really necessary at all to deprecate it?

Obviously no, it's not the end of the world if we keep Ember.K around. However with ember deciding as we speak its future module API, it is the perfect time to remove or make private APIs in ember that are sort-of outdated to simplify it as much as possible. If there is a lot of pushback we can keep it.

If this helps you feel better about the churn, there will be an ember-watson task to automatically remove usages of Ember.K, the very deprecation will point to the entry in the guides about how to do it and we can automatically create PRs for all ember-addons removing it.

If this goes ahead, it will be a very smooth process.

@workmanw
Copy link
Copy Markdown

@cibernox Just to be clear, it's not only about modifying the existing code, it's also about learning a new way to do things. And again, I completely acknowledge this is a trivial change technically. IMO it's more about the casual user who doesn't follow all these RFCs, read every blog post, and isn't a full time ember dev. Sometimes they're project contracting folks, or backend guys floating to the frontend for a sprint. They try to use Ember.K, get a deprecation, then the go read about the change and figure out what the new pattern is. At the end of it all, if you can't demonstrate an upside to a change, it just looks like churn to a user.

@locks
Copy link
Copy Markdown
Contributor

locks commented Nov 20, 2016

IMO it's more about the casual user who doesn't follow all these RFCs, read every blog post, and isn't a full time ember dev.

How do they come upon Ember.K?

They try to use Ember.K, get a deprecation, then the go read about the change and figure out what the new pattern is.

That seems fine? There are still some improvements we could do to get the deprecation guides closer to the user.

@workmanw
Copy link
Copy Markdown

How do they come upon Ember.K?

Just something that has already been learned. Either by looking at other parts of the application, or by looking at an addon's implementation or even seeing it via debugging through Ember.

I'm just trying to highlight that when something new replaces something old, which is often the case with an evergreen framework like Ember, if there isn't a clear benefit it can feel it can just feel like churn. Additionally, ember-watson is great for refactoring, but that is only one consequence of change. Relearning / retraining is another important consideration.

@cibernox
Copy link
Copy Markdown
Contributor Author

We'll run a search to see how widespread is the usage of Ember.K.

@stefanpenner
Copy link
Copy Markdown
Member

stefanpenner commented Nov 20, 2016

if there isn't a clear benefit it can feel it can just feel like churn

Some quick thoughts:

  • if removed we should be sure to provide a 1 step tool to remove this from code (the churn concern is real, we left this is the framework for so long, users have grown to use it).
  • by not offering it in the framework, it is a small win in curriculum reduction.
  • it is unlikely to pass the litmus test for a new feature today.
  • alternative foo: Ember.K -> foo() { } in classes or () => ()
  • the chaining aspect of the K combinator has been a source of confusion, and unexpected bugs. For example someone uses foo: Ember.K the caller of foo can now chain, foo must then continue to always support chaining, even though it may not have been expected.
  • quick note: as we work hard to make ES6 classes first class, this will continue to have less value.

Relearning / retraining is another important consideration.

Ya totally, to complement that there is an additional cost and that is the cost new users learning, etc.


[edit]

Sorry, I just realized my list may have come off not as intended. It was truly intended as a quick brain dump, not as a "long list to stop the discussion". My opinion though is likely obvious, hopefully my list provides insight as into why I would prefer to see this leave.


The second downside of reusing the same instance in many places is that if for
some reason the VM deoptimizes that function, that deoptimization is spreaded
across all the usages of `Ember.K`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya, if this happens. Large chunks of inlined code could be evicted, making many things sad. Although this risk does seem to continue to reduce as JITs get better, if we can avoid it I would recommend we do.


# Transition Path

The obvious first step is to make sure Ember, Ember-data and other pieces of the
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ember-data I believe has some use-cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a PR pending which might not even be necessary, as @runspired goes through the codebase.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A wild @runspired unleashed upon a codebase you say?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merged

derp.foo().bar().baz(); // O_o
```

# Transition Path
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When do we plan to drop? 3.0 or..

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, as any regular feature. Although it will not have a export path in ember-core/source, but it will be present in the bundled version until 3.0

Update 0000-deprecate-ember-k.md
torii/tests/unit/services/popup-test.js: close: Ember.K
```

## Addendum 2 - `Ember.K` usage via destructuring across published addons
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to change ;P


While doable, the transpiled output is actually bigger then defining the functions
inline, specially with the ES6 shorthand method syntax, and the perf difference
of saving a few function allocations is despicable.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"despicable" means "deserving of hatred and contempt" - Perhaps you meant "debatable"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a false-friend word I suppose, I meant negligible. Fixing it

@mixonic
Copy link
Copy Markdown
Member

mixonic commented Nov 28, 2016

@locks I think you're requested changes are still blocking.

@workmanw I'm surprised that you aren't convinced by the idea that Ember.K is a hurdle for new developers learning the framework. I've worked with a number who found this to be a massive gotcha, or even worse something they cargo culted through their codebases without understanding it at all. If you saw it in another framework you went to learn, I expect you would be befuddled at what the authors were thinking, right?

We're always trying to balance support for current users with making the framework as attractive as possible for new users. 💯. Part of this is to have a multi-pronged approach for existing users:

  • Communicate changes about recommended patterns in the blog posts as they change.
  • Permit users to upgrade at their own pace by providing LTS releases (upgrades only twice a year).
  • Allow users to address changes at their own pace by permitting them to ignore whatever deprecations they want and ensuring most releases (all minor releases) are backwards compatible.
  • Publish a deprecation guide explaining the motivation for a deprecation and the way to refactor around it.
  • Attempt to automate as much of the upgrade process as we can via ember-watson (and this is something we can get much better at).

You're definitely a contributor who surfs the cutting edge of Ember, and as such you likely perceive change to happen more rapidly than other users. I've worked as plenty of shops that have deprecations from Ember 2.2 they still haven't bothered to look at even as they upgrade to 2.10.

Change is inevitable in software. If Ember doesn't improve, we all end up rewriting in something else anyway. The tradeoff our community strives for is constant improvement with as much process and tooling as possible to pick-your-own-pace.

I want to address your concerns, but they also seem pretty vague. Perhaps there is another discussion we can have some time about ways to better the communication for deprecations, especially around their motivation. I think for sure we should expect the deprecation guide PR to explain motivation.

In general I'd like to advance this RFC and go into FCP sometime this week. I've added it to the core team agenda for Friday, so it will be discussed then if no sooner.

@workmanw
Copy link
Copy Markdown

workmanw commented Dec 8, 2016

@mixonic I was just trying to add a little friction to this discussion because I think Ember.K is unique situation in that it's really does nothing. Unlike virtually every feature ever, there is some variable amount of on going maintenance and that is often valid justification for removal of cruft. This case is very unique in that it doesn't rely on any other code in the framework at all. Nor can its behavior be debatable.

Following through this RFC, before my initial comment, it seemed to be about performance. Which in general is a great reason to remove cruft. But then it kind of shifted from being about performance to being about removing something that was a no-op. That's when I wanted to raise my hand and ask if it was even beneficial to do this given that it will create deprecation warnings throughout the ecosystem and could seem like churn to some.

... even worse something they cargo culted through their codebases without understanding it at all.

Bahauaha. Too funny. I think it was more about the fact that it is already there, and it has been for a really long time, than it was about the value of it overall. My comments were not meant to be a last stand to save Ember.K. My sole purpose of piping up was to just to call out that many casual users I know and talk to (folks who don't read the RFCs, don't write ember full time and don't hit every upgrade) often express some frustration over little changes that seem to offer no benefits to them. It can make things feel unstable when lots of little things change and there is no perceived benefit.

@mixonic
Copy link
Copy Markdown
Member

mixonic commented Dec 10, 2016

@cibernox Thanks for the final edits regarding --empty and --return-this. That change addresses the last open issue I know of here, so I'm going to move this RFC into FCP today 🎉

@workmanw I think we're pretty aligned in our goals. Removing K is definitely a simplification, and though simplification changes are a win for new users, they have a higher cognitive cost to existing users. This RFC and the codemod provide tools to help lower that cost. Good deprecation guide content and messaging can further ease the impact. Thanks for raising the feedback! 👏

@john-kurkowski
Copy link
Copy Markdown

though simplification changes are a win for new users, they have a higher cognitive cost to existing users

There are new users to Ember.js and new users to Ember.K, i.e. they develop in Ember.js but never bothered to learn this API morsel. I think this identifies even more who would benefit from the deprecation.

Our team has Ember.js code going back almost 4 years. Somewhere in history, there's sure to be sprinkles of Ember.K that seemed like a good fit at the time. More recently, we prefer native syntax. If you know JavaScript, the native version is immediately grokkable. No RTFS. Those un/familiar with Ember.K both benefit.

If users new to Ember.K go back in our code history and encounter its deprecation, that's a relief. It's apparent at a glance that it was "a massive gotcha." It generally remains one less thing they have to keep in their heads. They follow the one-time instructions how to replace Ember.K, and move on with their lives.

@mixonic
Copy link
Copy Markdown
Member

mixonic commented Dec 21, 2016

As there have been no issues raised in the FCP period that this RFC does not address, we will consider it accepted. I've rebased the commits down and merged into master: rfc commit, merge commit, commit renaming the file.

🎉 Thank you for your input and discussion! 🎉

@bstro
Copy link
Copy Markdown

bstro commented Jun 7, 2018

Would love to read the RFC but it looks like the link is broken

@locks
Copy link
Copy Markdown
Contributor

locks commented Jun 7, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.