Stable interface policy/T255803 Draft

The stable interface policy for MediaWiki PHP code defines what parts of the software are considered stable and safe for use outside of MediaWiki core, e.g. by extensions and skins. Code that is considered part of the "stable interface" is subject to the deprecation process.

Terminology

 * Authors: You are working on something that others will use. For example, a class in MediaWiki core that extensions can use.
 * Users: You are working on something that uses a stable interface. For example, a class in an extension that interacts with MediaWiki core.

Best practices for authors
When changing existing code:


 * Keep public methods and hook signatures backwards compatible for callers. Follow the deprecation process when removing them.
 * Keep constructor signatures backwards compatible, if the class was marked.
 * Keep method signatures compatible for subclasses that overrides them, if the method is marked.
 * Do not add new methods to classes or interfaces that are marked.

When creating new code:


 * When defining hooks, keep the signature minimal, and expose narrow interfaces, ideally only pure value objects.
 * When allowing extensions to create additional classes that follow an interface, consider providing a base class that is stable to extend.
 * Mark interfaces as  by default. To allow use in typehints, mark the interface stable to type. To allow direct implementations, see stable to extend.

Stable to call
Stable to call applies to methods or functions. It means they stay backwards compatibility between releases. This stability applies to both the behavior (or "contract") and the signature. Breaking changes that would impact callers must follow the deprecation policy.

Note that methods are not stable to override by default. For the purpose of this policy, constructors are not considered methods (see Stable to construct instead).

Included:


 * Public methods in any class are safe to call.
 * Global functions of which the name starts with the "wf" prefix are are safe to call. Other global functions are unstable by default.
 * Protected methods in a class stable to extend are also safe to call.
 * Protected methods in other classes, if the protected method is marked, are safe to call.

Not included:


 * Any protected or private method, unless marked.
 * Any method or function marked,   or.
 * Legacy class methods that do not have explicit visibility modifiers. These are implicitly public, but considered unstable.

Stable to extend
Stable to extend can apply to classes or interfaces. It means they will stay backward-compatible between releases and may be subclassed or implemented anywhere. Changes that affect subclasses or implementations will be done in a backwards compatible manner and follow the deprecation policy. Protected methods of extendable interfaces and classes are automatically safe to call, unless they are marked,   or. Note that methods are not stable to override by default.

Included:


 * Only interfaces that are marked  are safe to implement.
 * Only classees that are marked  are safe to extend in a subclass.

For authors:


 * It is recommended that all interfaces not marked as stable to extend, are explicitly marked  to avoid confusion.
 * It is recommended that you mark extendable classes also as stable to construct.
 * Note that it is not possible to use deprecation in an interface. If an interface is stable to extend, it means its method signatures can never change, and no new methods can ever be added unless the interface as a whole is deprecated. As such, it is recommended that public interfaces that extensions should implement are provided in the form of an abstract base class instead of an interface.

Stable to override
Stable to override can apply to class methods hooks. It means the core code will continue to call this method as-needed to let its behavior have the expected influence at run-time. Changes to that contract must follow the deprecation policy.

Included:


 * Any hooks that is documented. For the sake of this policy, hook handler callbacks are treated as implementations of abstract methods.


 * Methods that are declared as, in classes that are not  ,   or.
 * Any method marked.

Exceptions:


 * Any method marked,   or.

Stable to construct
Stable to construct applies to the constructor method of a class. A class marked this way is safe to instantiate using the  operator in any code.

For complex classes that may involve dependency injection, you should avoid making the class stable to construct, as this means adding or changing dependencies would constitute a breaking change that requires following the deprecation policy.

Included:


 * Only classes marked.

For authors:


 * It is recommended that extendable classes are also marked.

Stable to type
Stable to type can apply to interfaces. An interface marked this way may be used in typehints anywhere, even outside the original module. And when you get an object that implements this interface, you may call methods on it (following the other stability definitions).

Included:


 * Only interfaces marked.

For authors:


 * Use this to reserves the right to add new methods to the interface. This would break classes that implement the interface directly. In other words, the interface does not act as an extension point. Consider providing a base class as extension point instead.

Global variables
There is no official way to mark global variables as stable for any purpose. Global variables are not stable, not even those with the "wg" prefix.

For users:


 * To access site configuration, use  instead.
 * To access service objects, use  methods instead.

For authors:


 * When access to global state cannot be avoided, static methods SHOULD be used.

It's generally not safe to rely on global variables from MediaWiki. Use methods such as MediaWikiServices::getInstance or MediaWikiServices::getMainConfig instead.

Add guarantees

 * : See Stable to call.
 * : See Stable to extend.
 * : See Stable to override.
 * : See Stable to construct.
 * : See Stable to type.

The  annotations can be followed by a   segment to indicate that a particular use of the class or method is only supported since a specific version. Such restrictions can e.g. be used in cases where extensions should continue to be able to call methods on a class, but should no longer subclass it. Similarly, they can be used to indicate that a protected method on an extensible class may still be called, but should no longer be overwritten. For example:

Remove guarantees

 * : Do not use outside the original module. It my change without notice.
 * : Do not use outside the original module. It may change without notice. Similar to, except that unstable things are intended to become stable in the future.  : This means something should not be used as this may be removed in a future release, per the deprecation process. This must include a   segment, and must include instructions for what to use instead (or state that there is no alternative). For example:

Deprecation process
All code that falls within the scope of this policy and defines a stable interface is subject to the deprecation process defined in this section.

Deprecation is typically considered when code needs to be refactored in order to add new functionality, improve general architecture, or fix bugs. Developers SHOULD consider the impact of their proposed changes by searching for existing usage in extensions using tools such as Grep, Ack, or Codesearch.

Extension developers are encouraged to develop their code in Wikimedia Gerrit, to mirror it to Wikimedia's Gerrit or GitHub to make it easier for core developers to identify usage patterns. Extensions that are open source will be given more consideration than those that core developers cannot see.

Deprecations MUST first take place on the master branch. It is NOT RECOMMENDED to backport deprecations to stable branches.

Developers SHOULD consider deprecating similar parts of code together so affected code can be updated all at once.

Deprecation
There are two steps to deprecation: a soft deprecation, and then a hard deprecation.

A soft deprecation occurs when a developer adds a  annotation to the documentation comment of a method, function, class, or interface.


 * The documentation comment MUST mention what the alternative method or migration path is. If there is no alternative, it should state that.
 * The documentation comment MUST state what MediaWiki core version the deprecation occurred in.
 * If code is only soft deprecated, it SHOULD function the same as prior to deprecation. (This is only a SHOULD not MUST as sometimes it is only possible to provide similar functionality, which is enough for practical purposes, but technically not equal functionality.)
 * Any relevant documentation in the Git repository or on mediawiki.org MUST be updated once the change is approved.
 * The deprecation MUST also be mentioned in the relevant RELEASE-NOTES file, and MAY also be mentioned in the "Upgrade notices for MediaWiki administrators" section of the wiki release page depending upon severity. Deprecation of hooks MUST be mentioned in docs/hooks.txt.
 * Developers SHOULD update MediaWiki core to no longer use the deprecated functionality.
 * Developers SHOULD update any extension or skin bundled with the MediaWiki tarball when soft deprecating, and MAY update popular extensions (WikiApiary.com and ExtensionDistributor can be used as indicators of extension popularity).
 * If they don't submit patches, developers MUST file bugs about bundled extensions/skins using deprecated functions so their maintainers can work on updating them.

A hard deprecation occurs, when a  call is added to the function or method in question, or by supplying the $deprecatedVersion parameter to Hooks::run. This emits deprecation warnings and causes things like unit tests to fail.


 * Code that is hard deprecated MUST also be soft deprecated.
 * The version number in the  call MUST match the one in the @deprecated annotation, even if the hard deprecation occurs in a different release.
 * Often code is soft deprecated first, and hard deprecated at a later date, but they MAY occur at the same time.
 * Hard deprecated code MAY act as no-ops instead of actually functioning, though this is not recommended.
 * MediaWiki core code that triggers hard deprecation warnings MUST NOT be reachable from non-deprecated core code using non-deprecated configuration settings
 * Extensions and skins bundled with the MediaWiki tarball MUST NOT trigger hard deprecation warnings and MUST be updated to use the new code.


 * Developers MAY email wikitech-l or mediawiki-l about the soft or hard deprecation depending about severity.
 * When a bug report or a task is related to a deprecation, it is RECOMMENDED to tag it specifically in the bug tracker; for instance with the "Technical Debt" tag, column "Deprecate / Remove" in Phabricator.

Removal

 * Code MUST emit hard deprecation notices for at least one major MediaWiki version before being removed. It is RECOMMENDED to emit hard deprecation notices for at least two major MediaWiki versions. EXCEPTIONS to this are listed in the section "Removal without deprecation" below.
 * Developers SHOULD consider how difficult it is to support and maintain the deprecated code when determining how urgent removal is. In addition, developers SHOULD consider usage statistics in extensions.
 * Developers MAY consider the LTS cycle in removing deprecated code (removals may be accelerated to avoid deprecated code being included in LTS versions, requiring an extended support period).
 * The removal MUST also be mentioned in the relevant RELEASE-NOTES file, and MAY also be mentioned in the "Upgrade notices for MediaWiki administrators" section of the wiki release page depending upon severity.

Caveat: As one of the principles of MediaWiki, developers should ensure any removals will not cause issues in the Wikimedia setup and extensions deployed there. If they do, developers should expect to be reverted by Wikimedia system administrators.

Removal without deprecation
The deprecation process may be bypassed for code that is unused within the MediaWiki ecosystem. The ecosystem is defined to consist of all actively maintained code residing in repositories owned by the Wikimedia foundation, and can be searched using the code search tool.

In some cases rare, it may be necessary to remove code without deprecating it in a major MediaWiki version beforehand, because the old behavior cannot reasonably be emulated. In such a case, developers MUST email wikitech-l ahead of time, explaining why deprecation is not possible or not reasonable, and providing an opportunity for affected parties to raise concerns and propose alternatives.

In any case, all steps about documenting deprecations and removals MUST still be followed, as applicable.

Meta
This policy explicitly defines the stable interfaces for use by extensions, to accompany the best practices for extensions. The policy applies from MediaWiki 1.35 onward. The policy for MediaWiki 1.34 and earlier is given in the section Stable interfaces up to MediaWiki 1.34 below.

Motivation
The motivation for this policy is two-fold:


 * Offer guarantees to extension developers, providing guidance on what aspects of MediaWiki core they can safely rely upon.
 * Provide guarantees to developers working on MediaWiki core, telling them what aspects of the code they can safely change without having to worry about breaking extensions.

This policy is designed to make extensions more robust against changes in MediaWiki core, and provide more freedom for MediaWiki core code to evolve.

Scope
This policy applies to the following:


 * PHP code of MediaWiki core (mediawiki/core.git) as published in official releases. It does not apply to unreleased code, or to other aspects of MediaWiki core like the HTTP interface of api.php, or client-side JavaScript, HTML output, or database tables. Those may have their own policies and practices for maintaining stable interfaces. As with all policies, developers should apply their best judgement when following it.
 * Libraries and extensions maintained as part of the Wikimedia ecosystem.

This policy is mainly written to define a contract between MediaWiki core and MediaWiki extensions, but it also applies to the relationship between MediaWiki and libraries it uses. In this case, it is the libraries that expose parts of their code as a stable interface, and MediaWiki core binds to that stable interface, following the rules set out by this policy. A "library" in this context is any separately released code that is maintained as part of the Wikimedia ecosystem, as well as any directory inside the repository that is identified as a separate library by convention, such as the directories under.

These rules also govern dependencies between libraries, or between extensions, or between extensions and libraries.

Stable interface up to MediaWiki 1.34
''The following definition of stable interfaces (when this page was called Deprecation policy) remains applicable to MediaWiki 1.34 and earlier. Once MediaWiki 1.35 is removed, this section becomes obsolete and should be removed.''

The stable part of the PHP API is comprised of all code in MediaWiki core that is explicitly marked public, and has been included in at least one stable release. In addition, some classes expect to be subclassed in extensions; in those cases protected functions also are included in the API. These classes should have a note in their documentation comment that they expect subclassing. If no note is present, it SHOULD be assumed that the class is not expected to be subclassed. Hooks are considered part of the PHP API.

Classes and/or functions with public visibility MAY also have,   or   annotations to indicate they are not stable interfaces that SHOULD NOT be depended upon.

Some legacy code may not have any visibility modifiers, in which case it is not considered to be part of the stable interface. Developers SHOULD add visibility modifiers as soon as possible, and use judgement when making this code protected or private. Where known users exist, developers SHOULD still consider following the full deprecation process. New code MUST have explicit visibility set on all properties and functions.