API_Development
Overview
The NetBeans project provides a rich set of APIs that is being developed as part of work of various groups. By distributing development of the APIs to multiple people we can increase the amount of designed, reviewed, implemented, tuned and maintained contracts but as each module is developed by a different person, there is a challenge in providing APIs of the same quality, designed by using the same patterns and documented in a common way. This document describes the practices that should be used during the API development, so NetBeans can produce APIs that will stand the test of time and preserve investments made by its customers.
Describing APIs
We understand the APIs as every aspect another piece of system can depend on and not just method signature. That is why providing documentation in form of javadoc is not usually be enough. Instead NetBeans projects use document generated from answers to Architecture Questions as main entry point. The questions provide guidance to the module owner and help him investigate architecture of his own module. By answering them the owner is supposed to realize and discover various aspects that others might depend on and remove them or document them. Based on the detailed answers (especially the <api/>
tag) we generate overview tables like the one shown below that are incorporated into the Javadoc.
Interface Name | Stability Classification | Specified in What Document? |
---|---|---|
ProviderRegistrationRemoval |
||
LookupAPI |
||
LookupSPI |
||
Set of property APIs |
Individual |
Setting up the infrastructure
If you write a NetBeans module you may want to setup the right layout of files first.
The default infrastructure (nbbuild/templates/common.xml and nbbuild/templates/projectized.xml) let you do various tweaks, but usually it is easier to just use the expected default layout (currently described in harness/apisupport.harness/release/README).
The documentation related files shall be organized as follows:
module_dir/src/ - directory with your sources
module_dir/src//package.html - description of each package
module_dir/src//doc-files/ - directory for special javadoc files
module_dir/arch.xml - answers to architecture questions (see bellow)
module_dir/apichanges.xml - description of the history of changes
module_dir/nbproject/project.xml - project file with dependencies and other informations
The locations of arch.xml and apichanges.xml moreover has to be specified in nbproject/project.properties as follows:
javadoc.arch=${basedir}/arch.xml
javadoc.apichanges=${basedir}/apichanges.xml
Writing the documentation
-
Generate arch.xml - open your project in NetBeans and select <em>Generate Architecture Description</em> from a context menu in projects tab. An empty, skeleton file will be generated. You can always reinvoke this target, if your answers are old, unanswered questions will be generated to the end of the file (the file shall stay well formated). When editing the file you can use <b>HTML tags</b>. Some of the answers may have autogenerated default answers (currently arch-where and dep-nb) for cases where the information is already recorded anywhere else (for example in project.xml file). They may or may not be accurate. You can <b>accept</b> the generated answer while surrounding it with your additional comments or you can <b>suppress</b> it. Just include
<defaultanswer generate='here' />
or<defaultanswer generate='none' />
in the answer of for your question. If you do not use the<defaultanswer/>
element at all the default answer is <b>apended</b> to your own answer. If you generate the defaultanswer, the source code for it is put into the comments in the html file, so if you are not satisified with the defaults, you can easily copy the output modify it and<defaultanswer generate='none' />
. -
Use <api/> tag - this tag is one of the most important in the architecture file. Each use of the <api> tags generates new item into a table of API interfaces. This is the main entry point to the documentation, so use the tag a lot. Not just for a description of javadoc interfaces, but for everything. Remember that an api is any feature that someone else rely on. Describe DTDs, properties, files or layers you read, formats or protocols that you communicate, etc. The
<api/>
tag syntax is described by its DTD and consists of:-
name - the name of the API, DTD or property
-
group - the group that this API belongs. For example "property", "java", "dtd", "layer" and possibly others. As we are writing in java the attribute can be omitted and the default value is "java".
-
type - you can either use someone else API ("import") or offer someone else dependency on your behavior ("export").
-
category - shall contain a name from the enumeration (
official
,stable
,devel
,third
,standard
,friend
,private
,deprecated
) in the meaning described here. -
url - shall refer to a document describing the API, if available otherwise one can insert additional comments into the body between the
<api>
and</api>
.
-
An example is available here:
<api name="identification"
group="dtd"
type="import or export"
category="stable"
url="where is the description">
Possibly some additional description to the API which may be skipped.
</api>
The interfaces in the table are grouped by the group of the API and marked in
the HTML text as <a name="group-name" />
so a reference to these tables can
be made by using <a href="#group-name" />
.
-
Use <usecase> tag - when answering "arch-usecases" question, surround the paragraphs describing the way to use your API with
<usecase name="…" id="…">
and</usecase>
. That way your paragraph will get correct heading in the How to use certain NetBeans APIs page. . Answer "arch-what" - the first sentence of your answer to "arch-what" is used as a short description in the overview page so write it meaningfully. The full answer is then used in the details section, so again, make it real and useful description of your module. -
Link between documents - important part of documentation is the description of context. It is not enough to say: "find this interfacein lookup". The reader may not know what "lookup" is, so it is better to hyperlink to its definition. You can use regular
<a href>
tag to link to other documents, for root of your javadoc use @TOP@. So link to lookup would be@TOP@/org/openide/util/Lookup.html
. -
Link between classes - consider making the prose section part of
package.html
file. Then you can use @{link classname} to address any class of your module or from modules you depend on. -
Link between Javadoc sets - the context is often split between multiple modules. To allow links between them, the root of each module javadoc can be referred to as @org-netbeans-the-module-code-base-name@. So to link to lookup from another module one can use
@org-openide-util@/org/openide/util/Lookup.html
(the list of all currently known module name substitutions is available at nbbuild/javadoctools/replaces.xml). -
Use Relative Links - please remove as much as possible of usages of non-relative links like https://bits.netbeans.org/dev/javadoc/ and replace them with @TOP@, @org-netbeans-module-name@ or @JDK@ root points. The javadoc is being scanned for allowed and disallowed links (defined in nbbuild/javadoctools/disallowed-links.xml) and violations cause the build run from IDE to fail. It is generally not recommended to refer to NetBeans website as the documentation shall be self contained, but if you find a URL that makes sence, feel free to add it to the nbbuild/javadoctools/disallowed-links.xml) yourself. Btw. it seems better to use such pseudo root point than directly relative link as for example content of package.html is usually duplicated into more directories.
-
Create apichanges - important part of any api is history of its changes. That is why create and maintain the apichanges.xml as described in NetBeans VersioningPolicy. When you refer to a class that no longer exists inside an API change, you can use
<class … link="no"/>
. -
Validate your documentation - make sure the documentation format is correct (links point to valid places, XML files has valid syntax, etc.). This can be checked by invoking "Generate Javadoc" from the context menu. This builds the Javadoc and (in addition to invoking
ant javadoc
from command line) also checks for broken links and fails if there any - so make sure all Javadoc of modules you are referring to has already been generated.
Publishing Javadoc
All NetBeans project Javadoc sets are being daily regenerated and uploaded to the central NetBeans API List. When your module can successfully build javadoc as described in previous section, it is time to consider adding it to the API list as well.
To add it, you have to modify
nbbuild/build.properties
and add own module into config.fixedmodules.javadoc
property.
Use
ant -f nbbuild/build.xml check-module-configs
cvs -q diff nbbuild
to review your changes. Then verify that everything works correctly by rebuilding all Javadoc:
ant -f nbbuild/build.xml build-javadoc`
and if the build succeeds and really contains your module, prepare for
committing your changes into CVS (check in the new moduleconfigs.txt
too).
Please note that three files in nbbuild/javadoctools
shall be modified by
addition of references to your module root. Verify that the additions are sane
(e.g. contain no local references and look like the other lines in the files)
and then commit the modified
nbbuild/build.properties,
nbbuild/javadoctools/replaces.xml,
nbbuild/javadoctools/links.xml and
nbbuild/javadoctools/properties.xml.
Javadoc Tips
By default the basic overview page is generated based on content of your arch.xml, apichanges.xml and project.xml.
To see an example, check the overview page of component palette api, that has the following structure:
-
Title and description is taken from the
arch.xml
's answer to questionarch-overall
.-
List of javadoc packages is added by the default javadoc doclet.
-
what is new section lists five recent api changes listed in
apichanges.xml
. Always add at least one change as this document is used to generate what is new for the whole release. -
List of usecases is taken from the
arch.xml
answer toarch-usecases
question. It shall contain the main introduction into the meaning and usage of the API. Links to javadoc classes and methods are welcomed. Also notice that the answer contributed to global page with usecases for all NetBeans APIs. -
Implementation details close the summary page. The contain answer to
arch-where
question, which shall contain link to NetBeans WebCVS with the module sources like https://github.com/apache/netbeans/blob/master/java/project/ for the java/project module. Also an answer todeploy-dependencies
arch question is generated so other modules know how to express dependency on this one.
-
XXX need to describe: {@link …}
, what package.html
can and cannot do, @inheritDoc
, etc.
Reviewing APIs
In order to ensure good enough quality of produced APIs there is a service provided to module writers - they can ask for an API review.
It is required that every new API will be reviewed prior to integration into
trunk. The exception from this rule is a friend
API that is used only by
modules within the same cluster (the module has to explicitly list its
friends). In this case the review is recommended but not required.
Why?
The short answer to question why you should be interested in an architecture review is "because it will be useful". Useful to you, as you discover new possible solutions to your problems or mistakes in your design, that might appear later, when integrated together with the whole system or even in later versions, when problems with maintainability and extensibility can show up. It will be useful to the whole system as it will be composed from more stable components integrated in better ways. It will be useful to whole your project as it will get better.
Nobody knows everything, but there is a lot of knowledge spread around. Architecture review is a way to get the people with pieces of knowledge together and cooperate in preventing us from repeating known mistakes and solving problems in the wrong way.
Ask for advice through architecture review. It cannot hurt and it is likely going to be useful.
What?
It is unlikely that the review team will do some coding for you. It is also unlikely that the reviewers are going to become domain experts and help you understand your users or your requirements. This is your task and you have to prepare these materials for the reviewers, as it is very likely they will ask you about these questions in order to verify that your way of solving problems of your users is really the right one.
As a result of architecture review you can expect advices and help in identification of
-
apis that someone else could depend on,
-
design or implementation that might have performance problems,
-
influences of your solution on existing products or
-
influences of other products on your solution in future,
-
solutions that are solving something different than was the original goal and
-
other projects or efforts going around that might help you in solving your problems.
More or less expect "just" a high level help.
When?
Whenever you need architecture advice or clarification and because the charter of the team is mostly high level, it is reasonable to come for the initial opinion as soon as the architecture is visible so it can be reviewed. This usually means after answering the first (more general) set of the architecture questions which should be done before the actual start of implementation. At this point the high level advices are of some use, later it is always hard to change implementation that has been written.
Of course things are likely change during implementation, but the high level direction given during this inception stage are likely not going to be questioned then and only the newly discovered facts and differences from the original suggestions are going to be evaluated during the before-commit review.
Testing APIs
Why?
If an API is supposed to stand the test of time it has to preserve the functionality that others are using, it has to be backward compatible. Some tests for compatibility are easy, some require more work, but the testing is necessary otherwise nobody can guarantee quality when the API is evolving.
Signature tests are simple starting point, unit tests are very good for verifying the "contract" between a public API and its clients. Some people claim that unit tests are poorly named since they imply that they are QA’s responsibility, but the development engineer is the one that really benefits with several advantages:
-
the tests provide an example of how the developer expects the API to be used.
-
Another is that when you run code coverage against a unit test suite, it shows surprising areas where there is code that isn’t necessary to support the API, so one can easily remove those extra bits
-
Another interesting feature of unit tests is support of arrogance (which is part of all good programmers). So here’s the best, most compelling reason for creating and relying on unit tests: you can much more confidently tell another engineer how wrong he is when he claims your code is breaking his!
Read more about possible test patterns that we use and how they can contribute to improvements in quality of your module.
Signature Tests
There is an automated verification task that is executed after every daily build that checks signature of classes and their fields and methods and sends reports to api-changes mailing list. Its reports contain both incompatible and compatible changes. So one gets notified not only when something is broken, but also in case of accidental API change like addition of a method by forgetting to make it
private
.
By default the tests check all classes in official packages. E.g.
org.openide.
, org.netbeans.api.
and org.netbeans.spi.*
and recently
also org.netbeans.jmi
that are part of modules included in daily build of
standard IDE and also those that are daily uploaded to Alpha Update Center.
That is why in order to have these tests running on own module one has to package the API into one of the official package (or request his own package to be added into the test) and make the module part alpha autoupdate configuration.
Any questions related to the sigtest framework can be either sent to the dev mailing list.
Unit Tests
Very important verification of quality of an API is an automated test suite. Most of NetBeans modules uses our test harness called xtest which is based on JUnit and enhances it with a few additional features (tests should inherit from NbTestCase) and configuration framework.
The simplest way how to make your module testable is to copy the test
directory from a small modules that already provide some tests and modify it
(e.g. html). The needed
changes include classpath modifications for compilation and execution in
build.xml
, correcting the list of tests in cfg-unit.xml
and of course the
placing your own tests into unit/src
directory.
The last step is to include the suite in daily execution of unit tests. For that it is enough to modify the xtest/instance/master-config.xml to include your module in the unit-nb test config. Verify that you have done everything correctly by running<pre>ant -f nbbuild/build.xml unit-validation</pre>
and checking that your tests were successfully executed. Since then make sure that your module tests really run and pass, as since then other people start to use these tests to verify validity of their own commits. And you should not cause false alarms by problems in your code.
Also consider to subscribe to notification framework to get email notifications about automatic failures, if you can reach the URL.
Deploying the APIs
The important part in a life cycle of an API (as well as any other product) is the feedback from the users. In order to get it one should let your users know that there is an API and allow they to try it. For that purpose NetBeans use its "Alpha Update Center". Curious users may enable it and that way be informed about latest development achievements.
To get a module into the "Alpha Update Center" one needs to make sure that the module’s build.xml
file has netbeans
, clean
, and nbm
targets that work in the normal way - normally this is accomplished trivially by making a projectized module and not overriding any targets from the default build harness.Then one can add entries for the new module to nbbuild/build.properties
in the list config.modules.daily-alpha-nbms
. Use<pre>
ant -f nbbuild/build.xml check-module-configs
cvs diff ide/golden/moduleconfigs.txt
</pre>to review your changes (check in the new moduleconfigs.txt
too).
One should test the NBM building process on local disk by making sure you have everything of interest checked out from CVS, opening nbbuild
as a project in the IDE, and selecting Build Daily Alpha NBMs from its context menu. If something is messed up, mail gets sent to broken_builds@netbeans.org
so it can be corrected. It is a good idea to notify
aumasters@netbeans.org
too.
Publishing New Versions
The content of "Alpha Update Center" is refreshed every day. The new version of module NBM is build from trunk and specification version in its module manifest is compared to the specification version of already uploaded module. If the new one is greater, the new version of the module replaces the old one.
This means that one can consciously and automatically upload new versions of an API from trunk to its users just by increasing the specification version in the CVS manifest file.
Stabilize the APIs
Usually an attempt to produce an API requires longer development time and it is useful to mark it as not being finished yet. NetBeans use a set of stability categories for that.
The expected scenario is that a module with an API starts its development in a CVS sandbox (contrib.netbeans.org) or as a regular netbeans.org project (like xml.netbeans.org) but is not part of the regular build. Then it is offered on Alpha or Beta AutoUpdate (early access mode) and one can work on its finalization. As the module is not part of a stable release, it can be modified in incompatible way. As soon as one thinks that the API is fine and it satisfies quality criteria, it can be put on "Stable Update Center" or even find its way into standard distribution.
Official APIs Restrictions
There is however one restriction. In order to make it easy for API users to find out what is stable API we have come with a simple description: "If a class is in org.netbeans.api.
or org.netbeans.spi.
packages, and is part of a stable release, then it is stable". Such API is then called NetBeans Official API.
This rule is not meant to block anyone in producing APIs. One can always create an API in less prominent package (say org.netbeans.modules.ant.api), publish it on netbeans.org as stable one and use all the infrastructure for API development that is available. Moreover this approach is not as strict and allows the API to be part of a release even if it has not reached enough stability for unlimited amount of time.
Support for Early Adoption
There can be situations when strictly following the "official namespace restriction" may cause a lot of troubles to early adopters and hurt NetBeans acceptance and competitiveness. Sometimes one needs to provide an API quickly, cannot guarantee that it is that stable, but is strongly willing to stabilize it in <em>close future</em>. In such case it may be acceptable to release the API in official packages, mark it as under development (by warning in javadoc and special name of the module) and stabilize it in next release. In such cases it may be possible to allow a temporary release of an API under development in official namespace if following is guaranteed:
The purpose of this "temporary release" is to encourage early adopters to test the APIs in real world and provide feedback to make them better. The publishers of the APIs in return promise to stabilize them soon and do that carefully considering the user impact. As a result NetBeans should be able to deliver important APIs as soon as possible, offer them to early adopters and increase API quality by incorporating the feedback. The adopters could be sure that the APIs will be stabilized in a given time frame and that they will not need to do major changes (like repackaging of all import statements, which was the current strategy) when the API becomes stable. In order to clearly communicate the exceptional state of the APIs, there should be a visible and non-ignorable stamp that such APIs are under development:
-
the javadoc documentation headers shall contain visible warnings
-
the module name shall indicate that it is not stable yet. This shall be done using "/0" in module name, for example
org.netbeans.api.projects.ant/0
. As this string has to be used by every module writer to specify module dependency it forms appropriate warning. When stable version of the module is produced and is incompatible with the "/0" version, the name should change toorg.netbeans.api.projects.ant/2
. If the stable version remains compatible the name of the module should beorg.netbeans.api.projects.ant/1
and appropriate ModuleAutoDeps shall be provided to upgrade dependencies of modules that used the "/0" version.
These suggestions shall ensure that the right balance is achieved between produces and consumers of any NetBeans API. It should however be stated that nobody shall be restricted by "Official namespace restriction" or bound by a time limit of the "temporary release", because if one does not want to create stable API, one does not have to. Contributing to official API set shall be a privilege as such effort requires more attention and increased amount of work that only those who really care are willing to invest.
Comments or corrections to dev@netbeans.apache.org