Merge pull request #4756 from adangel:issue-995-api-doc
[doc] ADR 3 - API evolution principles #4756
This commit is contained in:
@ -9,7 +9,7 @@ adr_status: "Accepted"
|
||||
last_updated: September 2022
|
||||
---
|
||||
|
||||
# Context
|
||||
## Context
|
||||
|
||||
PMD has grown over 20 years as an open-source project. Along the way many decisions have been made, but they are not
|
||||
explicitly documented. PMD is also developed by many individuals and the original developers might
|
||||
@ -33,7 +33,7 @@ by Michael Nygard.
|
||||
There are many templates around to choose from. <https://github.com/joelparkerhenderson/architecture-decision-record>
|
||||
gives a nice summary. The page <https://adr.github.io/> gives a good overview on ADR and for adr-related tooling.
|
||||
|
||||
# Decision
|
||||
## Decision
|
||||
|
||||
We will document the decisions we make as a project as a collection of "Architecture Decision Records".
|
||||
In order to keep it simple, we will use only a simple template proposed by Michael Nygard.
|
||||
@ -49,11 +49,11 @@ The change can be to amend the ADR or to challenge it and maybe deprecate it. A
|
||||
"Change History" section should be added to summary the change. When maintainer consensus is reached
|
||||
during the PR review, then the PR can be merged and the ADR is updated.
|
||||
|
||||
# Status
|
||||
## Status
|
||||
|
||||
{{ page.adr_status }} (Last updated: {{ page.last_updated }})
|
||||
|
||||
# Consequences
|
||||
## Consequences
|
||||
|
||||
Explicitly documenting decisions has the benefit that new developers joining the projects know about the decisions
|
||||
and can read the context and consequences of the decisions. This will likely also improve the overall quality
|
||||
@ -61,7 +61,7 @@ as the decisions need to be formulated and written down. Everybody is on the sam
|
||||
|
||||
However, this also adds additional tasks, and it takes time to write down and document the decisions.
|
||||
|
||||
# Change History
|
||||
## Change History
|
||||
|
||||
2022-09-30: Status changed to "Accepted".
|
||||
|
||||
|
@ -9,7 +9,7 @@ adr_status: "Accepted"
|
||||
last_updated: September 2022
|
||||
---
|
||||
|
||||
# Context
|
||||
## Context
|
||||
|
||||
We currently use Kotlin only for unit tests at some places (e.g. pmd-lang-test module provides a couple of base
|
||||
test classes). We were cautious to expand Kotlin because of poor development support outside JetBrain's
|
||||
@ -26,7 +26,7 @@ However - PMD is a tool that deals with many, many languages anyway, so this is
|
||||
|
||||
Nevertheless, extending the usage of Kotlin within PMD can also increase contributions.
|
||||
|
||||
# Decision
|
||||
## Decision
|
||||
|
||||
We are generally open to the idea to increase usage of Kotlin within PMD. In order to gain experience
|
||||
and to keep it within bounds and therefore maintainable we came up with the following rules:
|
||||
@ -50,11 +50,11 @@ and to keep it within bounds and therefore maintainable we came up with the foll
|
||||
not make incompatible changes. If compatibility (binary or source) can't be maintained, then that would be a
|
||||
major version change.
|
||||
|
||||
# Status
|
||||
## Status
|
||||
|
||||
{{ page.adr_status }} (Last updated: {{ page.last_updated }})
|
||||
|
||||
# Consequences
|
||||
## Consequences
|
||||
|
||||
Allowing more Kotlin in PMD can attract new contributions. It might make it easier to develop small DSLs.
|
||||
In the future we might also consider to use other languages than Kotlin, e.g. for `pmd-scala` Scala might make sense.
|
||||
@ -64,7 +64,7 @@ when Kotlin is used. Eclipse can't be used practically anymore.
|
||||
|
||||
Maintaining a polyglot code base with multiple languages is likely to be more challenging.
|
||||
|
||||
# Change History
|
||||
## Change History
|
||||
|
||||
2022-09-30: Changed status to "Accepted".
|
||||
|
||||
|
187
docs/pages/pmd/projectdocs/decisions/adr-3.md
Normal file
187
docs/pages/pmd/projectdocs/decisions/adr-3.md
Normal file
@ -0,0 +1,187 @@
|
||||
---
|
||||
title: ADR 3 - API evolution principles
|
||||
sidebar: pmd_sidebar
|
||||
permalink: pmd_projectdocs_decisions_adr_3.html
|
||||
sidebaractiveurl: /pmd_projectdocs_decisions.html
|
||||
adr: true
|
||||
# Proposed / Accepted / Deprecated / Superseded
|
||||
adr_status: "Proposed"
|
||||
last_updated: December 2023
|
||||
---
|
||||
|
||||
<!-- https://github.com/joelparkerhenderson/architecture-decision-record/blob/main/templates/decision-record-template-by-michael-nygard/index.md -->
|
||||
|
||||
## Context
|
||||
|
||||
The API of PMD has been growing over the years and needed some cleanup. The goal is, to
|
||||
have a clear separation between a well-defined API and the implementation, which is internal.
|
||||
This should help us in future development.
|
||||
|
||||
Until PMD 7.0.0, all released public members and types were implicitly considered part
|
||||
of public PMD API, including inheritance-specific members (protected members, abstract methods).
|
||||
We have maintained those APIs with the goal to preserve full binary compatibility between minor releases,
|
||||
only breaking those APIs infrequently, for major releases.
|
||||
|
||||
PMD is used and integrated in many different tools such as IDE plugins or build plugins. These plugins
|
||||
use our public API and rely on it being stable, hence we tried to break it only infrequently.
|
||||
|
||||
In order to allow PMD to move forward at a faster pace, this implicit contract will
|
||||
be invalidated with PMD 7.0.0 and onwards. We now introduce more fine-grained distinctions between
|
||||
the type of compatibility support we guarantee for our libraries, and ways to make
|
||||
them explicit to clients of PMD.
|
||||
|
||||
The actual API development and marking some part of the API as internal or add new API is an ongoing task,
|
||||
that will need to be done everytime. We won't just define an API and then are done with it.
|
||||
The API will change as new features want to be implemented.
|
||||
|
||||
This decision document aims to document principles and guidelines that are used for PMD development.
|
||||
|
||||
## Decision
|
||||
|
||||
### Semantic Versioning
|
||||
|
||||
PMD and all its modules are versioned together. PMD uses [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html).
|
||||
This means, that each PMD version consists of MAJOR.MINOR.PATCH components:
|
||||
|
||||
* MAJOR version is incremented for incompatible API changes
|
||||
* MINOR version is incremented for added functionality in a backwards compatible way
|
||||
* PATCH version is incremented for backward compatible bug fixes
|
||||
|
||||
Additional labels for release candidates might be used.
|
||||
|
||||
Incompatible API changes shouldn't be introduced lightly. See
|
||||
[FAQ: If even the tiniest backward incompatible changes to the public API require a major version bump, won’t I end up at version 42.0.0 very rapidly?](https://semver.org/spec/v2.0.0.html#if-even-the-tiniest-backward-incompatible-changes-to-the-public-api-require-a-major-version-bump-wont-i-end-up-at-version-4200-very-rapidly).
|
||||
|
||||
### Project structure and Java base packages names
|
||||
|
||||
PMD is mainly developed in the Java programming language. The build tool is Maven and the PMD build consists
|
||||
of several maven modules.
|
||||
|
||||
* All packages belonging to a given module should have a common package prefix.
|
||||
* Given a package name, it should be easy to figure out to which module this package belongs. There is a 1:1 mapping
|
||||
between maven module and package. This rule helps to find the source code for any fully qualified (Java) class name.
|
||||
* Two modules must not define the same packages. That means, it is not allowed that any given package spans more than
|
||||
one module. Otherwise, the mapping between module and package wouldn't be unambiguous.
|
||||
* The base package for all PMD source code is `net.sourceforge.pmd`. There are many different sub packages.
|
||||
* The core module `pmd-core` uses directly the base package as the only module. All other modules must use
|
||||
specific sub packages.
|
||||
* Language modules use the base package `net.sourceforge.pmd.lang.<language id>`.
|
||||
E.g. `pmd-java` uses the package `net.sourceforge.pmd.lang.java`.
|
||||
* All other modules use the base package `net.sourceforge.pmd.<module>`,
|
||||
E.g. `pmd-cli` uses the package `net.sourceforge.pmd.cli`.
|
||||
|
||||
### Criteria for public API
|
||||
|
||||
Public API is
|
||||
|
||||
* API needed to execute PMD analysis
|
||||
* Renderers
|
||||
* RuleSet XML Schema
|
||||
* Configuration
|
||||
* Ant Tasks
|
||||
* API needed to implement custom rules
|
||||
* AST structure and classes of languages (incl. AST structure for XPath rules)
|
||||
* XPath functions
|
||||
* Language Symbol Table / Metrics / Type Resolution (Not the implementation)
|
||||
|
||||
**Not** public API is
|
||||
|
||||
* Anything in packages `internal` and `impl`
|
||||
* Inheritance-specific members of AST related classes and interfaces. E.g. adding a member to an
|
||||
interface shouldn't be considered API breaking
|
||||
* Setters in AST classes are private. They are only used in the parser.
|
||||
|
||||
### Separation between public API, internal and implementation
|
||||
|
||||
All packages are considered to be public API by default, with **two exceptions**:
|
||||
|
||||
* Any package that contains an `internal` segment is considered internal. E.g. `net.sourceforge.pmd.internal`.
|
||||
*Internal API* is meant for use *only* by the main PMD codebase. Internal types and methods
|
||||
may be modified in any way, or even removed, at any time without a MAJOR version change.
|
||||
|
||||
The `@InternalApi` annotation will be used for types that have to live outside of
|
||||
these packages, e.g. methods of a public type that shouldn't be used outside PMD (again,
|
||||
these can be removed anytime).
|
||||
|
||||
* Any package that contains an `impl` segment is considered internal. E.g. `net.sourceforge.pmd.lang.impl`.
|
||||
These packages contain base classes that are needed for extending PMD (like adding a new language).
|
||||
These can change at any time without a MAJOR version change.
|
||||
|
||||
In a later version, the `impl` packages could be promoted as a public API for implementing new
|
||||
languages for PMD outside the main monorepo. In that sense, e.g. the module `pmd-java` is allowed
|
||||
to depend on `impl` packages of `pmd-core`, but ideally it doesn't depend on `internal` packages of
|
||||
`pmd-core` (or any other module). However, for now, the `impl` packages are **explicitly considered
|
||||
internal** until this decision is revised.
|
||||
|
||||
### Deprecation and removing of old APIs
|
||||
|
||||
* APIs can be deprecated at any time (even in PATCH versions). Deprecated APIs are marked with the
|
||||
`@Deprecated` annotation.
|
||||
* Deprecations should be listed in the release notes.
|
||||
* Deprecated APIs can only be removed with a MAJOR version change.
|
||||
|
||||
### Experimental APIs
|
||||
|
||||
* New features often introduce new APIs. These new APIs can be marked with the annotation `@Experimental` at
|
||||
the class or method level.
|
||||
* APIs marked with the `@Experimental` annotation are subject to change and are considered **not stable**.
|
||||
They can be modified in any way, or even removed, at any time. You should not use or rely
|
||||
on them in any production code. They are purely to allow broad testing and feedback.
|
||||
* Experimental APIs can be introduced or removed with at least a MINOR version change.
|
||||
These experimental APIs should be listed in the release notes.
|
||||
* Experimental APIs can be promoted to Public APIs with at least a MINOR version change.
|
||||
|
||||
### Guidelines for AST classes
|
||||
|
||||
AST classes of the individual language modules are used by custom rule implementations and are considered
|
||||
Public API in general. Rules only read the AST and do not need to modify it.
|
||||
|
||||
In order to minimize the public API surface of AST classes, the following guidelines apply:
|
||||
|
||||
* Concrete AST classes should be final, to avoid custom subclasses.
|
||||
* Concrete AST classes should only have a package private constructor to avoid manual instantiation.
|
||||
Only the parser of the language (which lives in the same package) should be able to create new instances
|
||||
of AST classes.
|
||||
* Concrete AST classes should not have public setters. All setters should be package private, so that
|
||||
only the parser of the language can call the setters during AST construction.
|
||||
|
||||
Non-concrete AST classes (like base classes or common interfaces) should follow similar guidelines:
|
||||
* Only package private constructor
|
||||
* Only package private setters
|
||||
|
||||
### Summary of the annotations
|
||||
|
||||
* `@InternalApi` (`net.sourceforge.pmd.annotation.InternalApi`)
|
||||
|
||||
This annotation is used for API members that are not publicly supported API but have to live in
|
||||
public packages (outside `internal` packages).
|
||||
Such members may be removed, renamed, moved, or otherwise broken at any time and should not be
|
||||
relied upon outside the main PMD codebase.
|
||||
|
||||
* `@Experimental` (`net.sourceforge.pmd.annotation.Experimental`)
|
||||
|
||||
API members marked with the `@Experimental` annotation at the class or method level are subject to change.
|
||||
It is an indication that the feature is in experimental, unstable state.
|
||||
The API members can be modified in any way, or even removed, at any time, without warning.
|
||||
You should not use or rely on them in any production code. They are purely to allow broad testing and feedback.
|
||||
|
||||
* `@Deprecated` (`java.lang.Deprecated`)
|
||||
|
||||
API members marked with the `@Deprecated` annotation at the class or method level will remain supported
|
||||
until the next major release, but it is recommended to stop using them. These members might be
|
||||
removed with the next MAJOR release.
|
||||
|
||||
## Status
|
||||
|
||||
{{ page.adr_status }} (Last updated: {{ page.last_updated }})
|
||||
|
||||
## Consequences
|
||||
|
||||
* Clearly defining the API PMD provides will help to further modularize PMD using the
|
||||
Java [Module System](https://openjdk.org/jeps/261).
|
||||
* Simpler decisions when to increase MAJOR, MINOR of PATCH version.
|
||||
* Refactoring of the implementation is possible without affecting public API.
|
||||
|
||||
## Change History
|
||||
|
||||
2023-12-01: Proposed initial version.
|
@ -11,23 +11,23 @@ last_updated: July 2022
|
||||
|
||||
<!-- https://github.com/joelparkerhenderson/architecture-decision-record/blob/main/templates/decision-record-template-by-michael-nygard/index.md -->
|
||||
|
||||
# Context
|
||||
## Context
|
||||
|
||||
What is the issue that we're seeing that is motivating this decision or change?
|
||||
|
||||
# Decision
|
||||
## Decision
|
||||
|
||||
What is the change that we're proposing and/or doing?
|
||||
|
||||
# Status
|
||||
## Status
|
||||
|
||||
{{ page.adr_status }} (Last updated: {{ page.last_updated }})
|
||||
|
||||
# Consequences
|
||||
## Consequences
|
||||
|
||||
What becomes easier or more difficult to do because of this change?
|
||||
|
||||
# Change History
|
||||
## Change History
|
||||
|
||||
YYYY-MM-DD: Add xyz.
|
||||
|
||||
|
@ -110,6 +110,7 @@ in the Migration Guide.
|
||||
* [#4717](https://github.com/pmd/pmd/issues/4717): \[core] XSLTRenderer doesn't close report file
|
||||
* [#4750](https://github.com/pmd/pmd/pull/4750): \[core] Fix flaky SummaryHTMLRenderer
|
||||
* doc
|
||||
* [#995](https://github.com/pmd/pmd/issues/995): \[doc] Document API evolution principles as ADR
|
||||
* [#3175](https://github.com/pmd/pmd/issues/3175): \[doc] Document language module features
|
||||
* [#4659](https://github.com/pmd/pmd/pull/4659): \[doc] Improve ant documentation
|
||||
* [#4669](https://github.com/pmd/pmd/pull/4669): \[doc] Add bld PMD Extension to Tools / Integrations
|
||||
@ -590,6 +591,7 @@ See also [Detailed Release Notes for PMD 7]({{ baseurl }}pmd_release_notes_pmd7.
|
||||
* [#4685](https://github.com/pmd/pmd/pull/4685): \[cli] Clarify CPD documentation, fix positional parameter handling
|
||||
* [#4723](https://github.com/pmd/pmd/issues/4723): \[cli] Launch fails for "bash pmd"
|
||||
* doc
|
||||
* [#995](https://github.com/pmd/pmd/issues/995): \[doc] Document API evolution principles as ADR
|
||||
* [#2501](https://github.com/pmd/pmd/issues/2501): \[doc] Verify ANTLR Documentation
|
||||
* [#3175](https://github.com/pmd/pmd/issues/3175): \[doc] Document language module features
|
||||
* [#4294](https://github.com/pmd/pmd/issues/4294): \[doc] Migration Guide for upgrading PMD 6 ➡️ 7
|
||||
|
@ -557,49 +557,10 @@ The API of PMD has been growing over the years and needed some cleanup. The goal
|
||||
have a clear separation between a well-defined API and the implementation, which is internal.
|
||||
This should help us in future development.
|
||||
|
||||
This however entails some incompatibilities and
|
||||
deprecations, see also the sections [New API support guidelines](#new-api-support-guidelines) and
|
||||
[API removals](#api-removals) below.
|
||||
This however entails some incompatibilities and deprecations.
|
||||
|
||||
### New API support guidelines
|
||||
|
||||
Until now, all released public members and types were implicitly considered part
|
||||
of PMD's public API, including inheritance-specific members (protected members, abstract methods).
|
||||
We have maintained those APIs with the goal to preserve full binary compatibility between minor releases,
|
||||
only breaking those APIs infrequently, for major releases.
|
||||
|
||||
In order to allow PMD to move forward at a faster pace, this implicit contract will
|
||||
be invalidated with PMD 7.0.0. We now introduce more fine-grained distinctions between
|
||||
the type of compatibility support we guarantee for our libraries, and ways to make
|
||||
them explicit to clients of PMD.
|
||||
|
||||
**`.internal` packages and `@InternalApi` annotation**
|
||||
|
||||
*Internal API* is meant for use *only* by the main PMD codebase. Internal types and methods
|
||||
may be modified in any way, or even removed, at any time.
|
||||
|
||||
Any API in a package that contains an `.internal` segment is considered internal.
|
||||
The `@InternalApi` annotation will be used for APIs that have to live outside of
|
||||
these packages, e.g. methods of a public type that shouldn't be used outside of PMD (again,
|
||||
these can be removed anytime).
|
||||
|
||||
**`@ReservedSubclassing`**
|
||||
|
||||
Types marked with the `@ReservedSubclassing` annotation are only meant to be subclassed
|
||||
by classes within PMD. As such, we may add new abstract methods, or remove protected methods,
|
||||
at any time. All published public members remain supported. The annotation is *not* inherited, which
|
||||
means a reserved interface doesn't prevent its implementors to be subclassed.
|
||||
|
||||
**`@Experimental`**
|
||||
|
||||
APIs marked with the `@Experimental` annotation at the class or method level are subject to change.
|
||||
They can be modified in any way, or even removed, at any time. You should not use or rely
|
||||
on them in any production code. They are purely to allow broad testing and feedback.
|
||||
|
||||
**`@Deprecated`**
|
||||
|
||||
APIs marked with the `@Deprecated` annotation at the class or method level will remain supported
|
||||
until the next major release, but it is recommended to stop using them.
|
||||
See [ADR 3 - API evolution principles](pmd_projectdocs_decisions_adr_3.html) and
|
||||
[API changes](#api-changes) below.
|
||||
|
||||
### Small Changes and cleanups
|
||||
|
||||
|
@ -8,10 +8,10 @@ import java.lang.annotation.Documented;
|
||||
|
||||
|
||||
/**
|
||||
* Indicates the feature is in experimental state: its existence, signature
|
||||
* or behavior might change without warning from one release to the next.
|
||||
* The only clients that are "safe" using experimental APIs are the sources
|
||||
* of PMD itself.
|
||||
* Tagged API members are subject to change.
|
||||
* It is an indication that the feature is in experimental, unstable state.
|
||||
* The API members can be modified in any way, or even removed, at any time, without warning.
|
||||
* You should not use or rely on them in any production code. They are purely to allow broad testing and feedback.
|
||||
*
|
||||
* @since 6.7.0
|
||||
*/
|
||||
|
@ -8,10 +8,11 @@ import java.lang.annotation.Documented;
|
||||
|
||||
|
||||
/**
|
||||
* Tags API members that are not publicly supported API.
|
||||
* Such members may be removed, renamed, moved, or otherwise
|
||||
* broken at any time and should not be relied upon outside
|
||||
* of the main PMD codebase.
|
||||
* Tags API members that are not publicly supported API but have to live in
|
||||
* public packages (outside `internal` packages).
|
||||
*
|
||||
* <p>Such members may be removed, renamed, moved, or otherwise broken at any time and should not be
|
||||
* relied upon outside the main PMD codebase.
|
||||
*
|
||||
* <p>Members and types tagged with this annotation will remain
|
||||
* supported until 7.0.0, after which some will be moved to internal
|
||||
|
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
/**
|
||||
* Indicates that subclassing this type is not publicly
|
||||
* supported API. Abstract methods may be added or removed
|
||||
* at any time, which could break binary compatibility with
|
||||
* existing implementors. Protected methods are also part of
|
||||
* the private API of this type.
|
||||
*
|
||||
* <p>The API that is not inheritance-specific (unless {@linkplain InternalApi noted otherwise},
|
||||
* all public members), is still public API and will remain binary-
|
||||
* compatible between major releases.
|
||||
*
|
||||
* <p>Types tagged with this annotation will remain supported
|
||||
* until 7.0.0, at which point no guarantees will be maintained
|
||||
* about the stability of the inheritance hierarchy for external
|
||||
* clients.
|
||||
*
|
||||
* <p>This should be used for example for base rule classes that
|
||||
* are meant to be used in PMD only, or for AST-related interfaces
|
||||
* and abstract classes.
|
||||
*
|
||||
* @since 6.7.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
public @interface ReservedSubclassing {
|
||||
}
|
Reference in New Issue
Block a user