blob: bad40a9c1f7fe806c4f976a8448551a1a1e02f90 [file] [log] [blame] [view]
## Sample code in Kotlin modules
### Background
Public API can (and should!) have small corresponding code snippets that
demonstrate functionality and usage of a particular API. These are often exposed
inline in the documentation for the function / class - this causes consistency
and correctness issues as this code is not compiled against, and the underlying
implementation can easily change.
KDoc (JavaDoc for Kotlin) supports a `@sample` tag, which allows referencing the
body of a function from documentation. This means that code samples can be just
written as a normal function, compiled and linted against, and reused from other
modules such as tests! This allows for some guarantees on the correctness of a
sample, and ensuring that it is always kept up to date.
### Enforcement
There are still some visibility issues here - it can be hard to tell if a
function is a sample, and is used from public documentation - so as a result we
have lint checks to ensure sample correctness.
Primarily, there are three requirements when using sample links:
1. All functions linked to from a `@sample` KDoc tag must be annotated with
`@Sampled`
2. All sample functions annotated with `@Sampled` must be linked to from a
`@sample` KDoc tag
3. All sample functions must live inside a separate `samples` library
submodule - see the section on module configuration below for more
information.
This enforces visibility guarantees, and make it easier to know that a sample is
a sample. This also prevents orphaned samples that aren't used, and remain
unmaintained and outdated.
### Sample usage
The follow demonstrates how to reference sample functions from public API. It is
also recommended to reuse these samples in unit tests / integration tests / test
apps / library demos where possible to help ensure that the samples work as
intended.
**Public API:**
```
/*
* Fancy prints the given [string]
*
* @sample androidx.printer.samples.fancySample
*/
fun fancyPrint(str: String) ...
```
**Sample function:**
```
package androidx.printer.samples
import androidx.printer.fancyPrint
@Sampled
fun fancySample() {
fancyPrint("Fancy!")
}
```
**Generated documentation visible on d.android.com / within Android Studio**
```
fun fancyPrint(str: String)
Fancy prints the given [string]
<code>
import androidx.printer.fancyPrint
fancyPrint("Fancy!")
<code>
```
Warning: Only the body of the function is used in generated documentation, so
any other references to elements defined outside the body of the function (such
as variables defined within the sample file) will not be visible. To ensure that
samples can be easily copy and pasted without errors, make sure that any
references are defined within the body of the function.
### Module configuration
The following module setups should be used for sample functions:
**Per-module samples**
For library groups with relatively independent sub-libraries. This is the
recommended project setup, and should be used in most cases.
Gradle project name: `:foo-library:foo-module:foo-module-samples`
```
foo-library/
foo-module/
samples/
```
**Group-level samples**
For library groups with strongly related samples that want to share code and be
reused across a library group, a singular shared samples library can be created.
In most cases this is discouraged - samples should be small and show the usage
of a particular API / small set of APIs, instead of more complicated usage
combining multiple APIs from across libraries. For these cases a sample
application is more appropriate.
Gradle project name: `:foo-library:foo-library-samples`
```
foo-library/
foo-module/
bar-module/
samples/
```
**Samples module configuration**
Samples modules are published to GMaven so that they are available to Android
Studio, which displays referenced samples as hover-over pop-ups.
To achieve this, samples modules must declare the same MavenGroup and `publish`
as the library(s) they are samples for.