| ## 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. |