-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Developer Experience: There's ~280 __experimental APIs. Let's stabilize them! #40316
Comments
Interesting idea. What possibly could go wrong? 😃 I think the biggest concern here would be the documentation which might be missing in many cases. The automated PR could serve as s good way to find out how many undocumented APIs we have. I bet that the lack of good explanation of how to use those APIs is the biggest issue because, at this time, extenders probably learned how to work with experimental prefix 😅 |
The numbers aren't quite right as that script lists many duplicates. It shows any existence of Doing some quick sorting and removing duplicates gives a number around 280. It might be a little higher because there are probably some APIs that are actually defined in multiple places with the same name. Still quite high. I think the tricky thing is prioritizing the ones that are actually useful to developers. The age of an experimental API is also an interesting measurement. If an API is going to sit around for years as experimental, perhaps it'd be better being switched to edit: sorry for closing and reopening accidentally. |
Some brain storming... Another thought is to focus on stabilizing experimental APIs for a 6.x version where main focus is stabilization. It would then need to be posted on make core well ahead of time to get developers ready for the shift from experimentation to stabilization. |
when I recently added notable we don't list |
Can we approach this in a more gradual manner from oldest to newest? Doesn't make sense to treat APIs introduced in the last couple releases the same as those introduced a couple years ago. APIs that are already part of major releases should be prioritized.
Which ones? Identifying those seems like a good start to me. |
Getting the age of these tokens would be useful. Could probably hack my script to do this using |
To share my thoughts from Slack in a less ephemeral form. WordPress Core is considered the stable version of the block editor. It has a long standing commitment. to maintaining backward compatibility of public APIs. Any of the Discussing how the block editor is used by developers, in order to provide a native feeling experience plugins are required to use the private functions. This is reflected in a rudimentary search of the plugins directory and themes directory. Maintaining deprecated private APIs has been a long standing practice of WordPress, as reflected in deprecated.php. Basically, hard deprecating in WordPress Core is a no-go. Instability between versions is already beginning to alienate some of the block-editors biggest external advocates so a concerted effort of deprecation would simply expedite the alienation. As Gutenberg is considered a bleeding edge product, hard deprecation is acceptable. I'd suggest a soft deprecation of a short period of time (three to six months) before hard deprecation. If it doesn't already include it, adding the hard deprecation version number to soft deprecation console messages would be ideal. |
All great notes @peterwilsoncc! It's an interesting situation:
In other words, releasing an |
Actually, that doesn't seem to be possible. At least these two kinds of APIs cannot be made private before a major release:
There must be a way to ship them and retain the ability to remove them. If anything that's made public cannot be easily removed, there's no point in maintaining Gutenberg as a separate repository. I now err on the side of keeping the ability to hard-deprecate experimental APIs even if they made it as public to WordPress core. This is consistent with the following handbook page: We could, though, make sure that the __experimental prefix keeps working for some time after stabilizing the underlying API (cc @gziolo @dmsnell). |
I feel like @peterwilsoncc is much better at I than articulating here, but it should be noted that the handbook page you are referencing is the contributor guidelines for the Gutenberg plugin, and not the implementor guidelines for developers using what actually lands in core. If the worry is that experimental features are needed for a feature to be put into core, would it then not stand to reason that that feature is not actually ready for core yet, because it is in part experimental? (I'm being intentionally direct here, I know there are nuances, but would this not improve developer experiences as well if not even core relied on experimental or unstable components?) |
I believe that the intention of I know Core has historically maintained backwards compatibility for APIs marked private but I'd push back on that precedent a little bit as the majority of this has been for APIs written in PHP. Keeping PHP around for backwards compatibility carries a maintenance burden but not much else. Keeping JavaScript around for backwards compatibility, however, carries a maintenance burden and a user experience burden as it increases the bundle size. |
I think it's worth dividing it up into two things—the user facing feature and the developer API. The user facing feature is usually ready for release, but developer APIs still somewhat open to change. It's often possible to change developer APIs with no effect on the user experience. On the other hand 'ready' is a relative term. User interfaces do naturally change over time. It can be difficult to do that if the underlying APIs all require an endless commitment to backwards compatibility, and I think that's the main reason to consider something experimental. |
I accept that was the intention but once these APIs started shipping in the stable product the promise to maintain backward compatibility was made. These APIs have only ever been documented as removed without notice in the plugin contributor guide.
This is before considering themes and custom builds in which use these items too. I am getting DMs since joining this ticket. Yup, there's a maintenance burden to maintain backward compatibility. That's the cost of working on a project that strives to maintain it. Yup, shipping these APIs in the stable product has introduced a user experience burden too. Realistically, the APIs should not have been shipped in an unstable/experimental form. |
The current policy is that We don't really have a way of picking and choosing which code lands from Gutenberg into Core which is a large part of why I would prefer that we improve how we communicate what our policy is for For experimental APIs that are very frequently used (e.g. the ones you list) I think it makes sense to be pragmatic and mark those APIs as deprecated for a few releases. Not guaranteeing backwards compatibility doesn't mean that we can't do it anyway. But I disagree completely that any |
I think there can be a stronger commitment to not include
I also see two things at play here: the use and abuse of experimental APIs during the API design (generally to be used and tested in the Gutenberg plugin) and the lack of a diligent process for stabilizing them when they satisfy design criteria. The ones that are to be considered de facto public are those that have existed for many releases in a stable form despite their nomenclature. |
@m @josephahaden Has WordPress dropped the core philosphy to maintain backward compatibility? Is the project now willing to break millions of plugin installs per my comment above? |
@peterwilsoncc pardon me, but that seems quite the leap. Where do you see the argument to break millions of plugin installs? There's a nuanced discussion to be had when it comes to how much code we are willing to ship to users on the client in the name of keeping APIs working that's collateral to the discussion of how experimental APIs are introduced, how they are refined, how they are stabilized, and what it means when these end up in major releases. Among those, there are some very concrete things to pursue that's what we should focus effort on. |
I'll try to summarize what I see as more concrete items.
|
As a plugin author that is currently using many |
in my opinion crashing the editor or a block is a much bigger user experience burden than adding a few extra tens of gzip'd bytes which is what the cost is going to amount to by leaving in deprecation notices on the old function names.
this also feels like quite the leap @mtias. we're discussing ~280 functions and a rename of those functions. when we mark code as deprecated we don't really leave clues in the source itself on when to pull them out, but I wonder about this, if we decided a deprecation policy of six months or so and leave some kind of export const ButtonBlockerAppender = forwardRef( ( props, ref ) => {
deprecated( `wp.blockEditor.ButtonBlockerAppender`, {
alternative: 'wp.blockEditor.ButtonBlockAppender',
since: '5.9',
removeAfter: '2022/01/01'
} );
return ButtonBlockAppender( props, ref );
} ); it just seems that overall a few months transition window (or one in which we can monitor usage in real plugins) that adds almost no cost to the generated build but prevents the editor from crashing (or a block from crashing) is an obvious choice to make.
Just a reminder @noisysocks that |
@Clorith I feel a bit tense and irritated after reading your response because I didn't say that. I asked how would you technically remove these API from core releases after you proposed to do that. I also said that, to me, secrets come close. We do seem to have a few different topics going on in parallel here. I'm happy to talk about the larger need to include the experimental features, but would you mind answering my original question? |
My intent was not to irritate, but to flip it around; You're saying that these experimental features are needed to making other components in the block editor work, so then we need to look at it from the position of someone trying to extend the editor, and understand that they are also bound by that same need. So if we did set a hard block on experimental functions for core moving forward, we would then add a bit more work, because related features would also need to be stabilized before a feature lands. I don't see this as a bad thing necessarily, as it would help ensure that what lands in core is something everyone can rely on as an implementation that can be used, extended, or whatever else one might want to do with it. Do I have a perfect solution, probably not, I'm just trying to spark a discussion and make sure that we move in the right direction :) |
Adding a note to call for a bit of pragmatism here: we're discussing a lot of ideological values and I get the sense that those risk leading us astray. In summary of some of the comments above, we don't have to be discussing if developers have lost trust in the API stability because we're specifically talking about a move that does break that trust. In other words, we're talking about removing code that we know many plugins depend on because we can see that in their source code. Good or bad we expose these APIs and people depend on them and to that matter it's we as the project that haven't adhered to the policy, and not through active intention. It's just how software works that any element that gets exposed becomes part of the public API. I'm in favor of stabilizing experimental APIs. I'm not in favor of needlessly breaking code that people have come to depend upon. It's not considerate; it's not gaining us anything other than a few bytes that are insignificant in comparison to other changes in bundle sizes. How long is too long to leave deprecations in place? I don't know, but I'd rather risk leaving them in a little too long while we can still see that a large part of the community is using them. "You shouldn't have done it that way" is never going to be consoling to someone who suddenly starts fielding support calls from people whose content is broken after a WP update. So for the sake of this issue, I frame it on this question: would you rather suddenly break a lot of code that people have used that we didn't want them to but which we gave them in order to maintain a philosophical purity about a policy we kind of made or would we rather prefer slowing down transitions to communicate to people that we have already slated for certain hooks and functions to be removed and they should use X instead? Again, there's almost no cost associated to stabilizing without breaking existing code and we win trust and favor. Why are we arguing about intentionally breaking integrations we know are out there and in use? Why would we rather have the editor crash when someone's just trying to write their content than to have an experimental API stick around as a deprecation for a little while longer? |
👍 thanks for clarifying! You're making some good points, it's just a very hot topic and I found that surfacing and labeling the emotions often makes it easier to talk.
@Clorith Are you talking about the stale, long-present __experimental APIs? I do agree. Are you talking about the fresh ones that are actually internal functions that happened to be exposed in public API because of technical limitations of JS? In this case, I disagree. Bear with me, I'll address that in details later in this comment. That's the culprit I think – we're having many different discussions at the same time here:
No wonder it's confusing and conflicting – that's such a huge discussion scope! I didn't really expect it will go in this direction. I'm not sure whether linear discussion in GitHub issues is the best format to untangle all of that – it's hard to address the abundance of issues that got conflated here. I wonder whether we should use the To me, the two most actionable problems are: Dealing with the existing
|
Hi 👋 I am I also agree with @Clorith that the plugin is the place to iterate on the editor, not Core. Regarding this...
I think this is the opposite as to how I would assess the problem. The plugin exists to iterate and stabilize before merging into Core, no different than any other feature plugin. I disagree with this sentiment...
Finally, I think it's clear that there's a huge disconnect between what is considered policy. My understanding is that any documentation appearing in the Block Editor Handbook applies only to developing with the editor. Plugins and Themes also have their own handbook for development, but their APIs that appear in Core must abide by the Core Handbook. |
I have to admit I haven't read all the comments up until now but I wanted to share an idea that I had around this: Could we by default hide experimental APIs behind a getter like in #41278 and add the Gutenberg version when it was introduced as a variable? Then we could give experimental APIs a certain number of Gutenberg versions to mature (say 5) and after that it would start to I know this might ignore some of the previous discussion, I just wanted to share this idea as a possible path. |
After some more discussions, I believe this solution comes close to everyone’s goals: Remove the
|
@adamziel Something wasn't clear to me, so it'd be good to clarify. Is the idea to selectively ship Gutenberg features to core? Or are you proposing that every API is stabilised when a WordPress release approaches? |
@talldan The idea is to ensure no new gutenberg/packages/block-library/src/index.js Lines 290 to 292 in afaa4a6
Perhaps this could be automated further with a webpack plugin to automatically remove the |
I think something like that would be needed, but perhaps a bit more evolved. A proper configurable feature flagging system. To be honest, I think it may be a good idea to consider feature flagging a lot of new work anyway. Whether we like it or not, the Gutenberg plugin has widespread usage in production, and the number of bugs and regressions that are shipped currently is very uncomfortable (at least to me). I don't think the risk of using the plugin is adequately conveyed. Feature flagging doesn't necessarily mean that all experimental features are disabled by default, but perhaps it could work like this:
|
True the plugin is used in production. I think this is becoming less common as features get shipped in Core based on anecdotes I am hearing from agencies. I agree with @adamziel's comment that Gutenberg is a WordPress Early Access release channel and needs a more relaxed attitude to backward compatibility that WordPress Core. Possibly the Early Access section in the readme needs to be earlier and be less ambiguous about not being production ready. As indicated by my 👍 vote, I support Adam's proposal and think it an excellent way to move forward. |
I'd like to echo the sentiment from @peterwilsoncc (and also, huge thanks to @adamziel for summarizing this discussion really well, to what I believe is the right path forward); Let's make it more obvious that the Gutenberg plugin is a alpha/beta-channel for upcoming changes to certain areas of core, instead of hiding things behind feature flags, which some may not even know are there. I use the plugin for experimenting, but I honestly never remember to visit the experiments page to turn on things, so if they're off at any stage, they're not as discoverable as we would like (or that's my perception at least). And as an agency, I can confirm, we've moved completely away from using the plugin in production. it was a necessity for a while, to get your hands on features that would not be ready for a few core releases, but we've found that we're past that hurdle, the editor as it stands has most of the flexibility an agency needs at least by now. |
Gutenberg should not be anything core, let alone " Basically, anything new, conceptually (experimental) or progressive enough as a page builder or ecommerce attachment should stay away from core 101%. So my vote is to not promote use of anything interim or temporary into core. Core is for stable. Plugins are for experimental. |
Make the __experimental APIs private by introducing a dealer mechanism that only grants access to core WordPress packages. It solves the problem of leaking private experimental APIs to extenders in public stable releases. See #40316 for more details. Usage example: ```js // in @wordpress/data import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/experiments'; const experiments = __dangerousOptInToUnstableAPIsOnlyForCoreModules( 'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.', '@wordpress/data' ); export const __experiments = experiments.register({ __experimentalFunction: () => { /* ... */ }, }); ``` ```js // In @wordpress/core-data: import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/experiments'; import { __experiments as __dataExperiments } from '@wordpress/data'; const experiments = __dangerousOptInToUnstableAPIsOnlyForCoreModules( 'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.', '@wordpress/core-data' ); // Get the experimental APIs registered by @wordpress/data const { __experimentalFunction } = experiments.unlock( __dataExperiments ); __experimentalFunction(); ```
With the introduction of the Thanks @adamziel for figuring out a solution that allows for an early-access channel to co-exist with the stable product. |
Yay indeed @peterwilsoncc! Now that there is a way forward, the next steps would be: Tame new experimental APIs
Related to number 2 above, here's a PR to enable experimental selectors. Other than that there are:
Stabilize the existing experimental APIsWork through the existing __experimental APIs to add deprecations and provide stable versions when applicable. |
Update: Private APIs are now separate from experimental APIs 🎉 Private APIsPrivate APIs are now shared internally inside the Gutenberg codebase using the new lock and unlock utilities. They can't be imported from the outside. The contributors started using I reviewed the Experimental APIsExperimental APIs are like early access feature previews that require community feedback to mature. New experimental APIs should not be merged into WordPress core, but they will continue to be released in the Gutenberg plugin. Next stepsThis issue had two goals:
The first goal is now largely achieved. The remaining follow-up work is tracked separately in #47786. As for the second goal, let's track it separately in #48743. It will require a case-by-case assessment of a few hundred I really appreciate the discussion we've had here and what it achieved – thank you, everyone! |
Great work here folks, thanks for all your efforts! |
The problem
Rob's script detectes the following number of
__experimental
APIs:__experimental
APIs__experimental
APIs__experimental
APIs__experimental
APIs__experimental
APIs__experimental
APIs__experimental
APIs__experimental
APIs__experimental
APIsIt is a generous estimate and, as @talldan pointed, the actual number is 280 as of Gutenberg 13.0. Still, the progression above demonstrates the problem.
The Audit Experimental APIs WP 6.0 issue I've created for WordPress 6.0 initially exceeded GitHub's characters limit:
And that's just the
__experimental
ones! There are also__unstable
,__internal
, and probably other prefixes..So what?
Plugin and theme authors are forced to rely on the
__experimental
features that could get removed or changed in a backwards incompatible way at any time. It is a serious maintenance burden. Every new Gutenberg/WordPress release means potentially breaking changes.Also, shipping essential features as experimental sends the wrong message to the developers: With all these
__experimental
APIs around, adding another one surely can't be a big deal. What does "experimental" even mean at this point? What is a valid use case, and what isn't?The discussion
Let's find a way to harness this growth!
There are two parts of this:
Stabilize the existing __experimental APIs
Many are de-facto stable, we just never marked them as such.
One idea to get there would be to:
Some PRs would get closed, some ignored, and others merged. Once that happens, we regroup and figure it out from there.
Upsides:
Downsides:
To me, that's a worthy trade-off. Is it to you? What other ways do you see?
Side note: Plugins relying on these "permanently __experimental" names would break – these names would have to keep working with a deprecation notice.
Create less new __experimental APIs
The number will continue to grow until something slows it down.
It could be a project policy, but policies need enforcement. It is hard, creates extra work, and may feel discouraging on the receiving end.
How about a soft nudge? Perhaps a CI check or a bot that detects new __experimental APIs and tries to educate the PR author? Ideally, it would also propose an alternative.
cc @gziolo @Mamaduka @noisysocks @mtias @youknowriad @andronocean @ciampo @aaronrobertshaw @c4rl0sbr4v0 @jorgefilipecosta @mcfs @paaljoachim @scruffian @draganescu @getdave @talldan @oandregal @ntsekouras @ellatrix @ndiego @priethor @annezazu @dmsnell
The text was updated successfully, but these errors were encountered: