Skip to content

Guidelines for Structure and Styles

Gilbert Kwan edited this page May 10, 2024 · 49 revisions

Contents

Follow these guidelines to write concise, well-organized guides.


Language

Be concise.

Edit your first draft to remove redundant information.

Why?

  • A long guide is off-putting to even the most eager reader.
  • You're wasting the user's time if they're reading words that don't add to their understanding. They're here to learn, not to read your prose.

Explain concepts clearly.

Explain unfamiliar concepts. Ask yourself what users wouldn't already know or what might confuse them.

Use present tense.

Use the present tense most of the time. Stick with the present tense even if you describe the functioning of code when it's compiled, but it's not strictly compiled yet.

Other tenses, such as the future tense and the past perfect tense, add extra words, such as "will" or "had," into your sentences. Tenses other than the present can make your sentences longer and difficult to read.

Use active voice.

Write primarily in active voice. Make the subjects of your sentences perform the actions instead of being acted upon. Passive sentences are often longer and harder to read and understand. They might also hide the actual actor of the sentence.

Example:

  • Active voice: Implement the @GET annotated methods:
  • Passive voice: The @GET annotated methods are implemented in the following code:

Use second person pronouns; limit first person pronouns.

Avoid using first person pronouns like 'we' and 'I' in guides. First person pronouns are generally unnecessary, and their identity is unclear.

Use "you" to refer to the reader, but this pronoun can also be unnecessary. For example, when giving instructions, state them in the imperative, such as, "Upload the file." The pronoun "you" is implied.

Use common contractions.

Use common contractions, such as "it's," to make your writing more conversational, but don't use clumsy contractions, such as "wouldn't". Try not to use "Let's", because you want to limit the first person pronoun "us".

Types of guides

There are two types of guides: single pane and multipane. Single pane guides are for guides that don't have any code. Multipane guides are guides that contain code. This can be determined by setting the following in the guide-attribution:

Single pane

:page-layout: guide

Multipane

:page-layout: guide-multipane

Multipane Specifics

Code column

The code column indicates files that will show in the right pane of the guide. Any files that are mentioned in hotspots or code commands are included as a code column. You must also include linenums in order for the code column to appear. There should not be any code in the middle panel of the guide. The general format of including a file in the right pane is:

Filename
[source, Java, linenums, role='code_column hide_tags=copyright'] 
---- 
include::finish/src/main/java/io/openliberty/guides/inventory/Filename[]
---- 

Example:

InventoryManager.java
[source, Java, linenums, role='code_column hide_tags=copyright']
----
include::finish/src/main/java/io/openliberty/guides/inventory/InventoryManager.java[]
----

Code highlighting supporting the following file formats: Java, xml, yaml, properties, gradle, groovy, and text.

On the site, it would look like:

Don't list utility classes, files, and content that helps with the main implementation and does not need to be covered in detail. Instead, mention that the content exists, briefly state what it is used for, and tell the users where they can find it. Add comments into these files so users can learn more if they are interested.

Example:

Finally, we are giving you two utility components: a `InventoryUtil` 
class and the `JsonMessages` enum. Both of these can be found under 
`src/main/java/io/openliberty/guides/microprofile/util`.

- The `InventoryUtil` class is responsible for communicating with 
the `system` service to retrieve JVM system properties for a particular 
host that exposes them. Read the Javadoc provided in this class for
more information about its methods.
- The `JsonMessages` enum is used to build JSON Java objects for various 
error cases. Currently its only used to build an error JSON whenever a 
particular host does not exist or is not running the `system` service.

Code command

A code command is an action arrow that will indicate to readers that they need to make an action with a file. There are three types of action arrows: Create, Replace and Update.

  1. Create

In the case where you are asking readers to create the file, make sure the file path to where they are supposed to create the file is already created in your start directory. The format to ask readers to create a file is the following:

  • For a Java class:
[role="code_command", subs="quotes"] 
---- 
#Create this `Filename` class.#
`src/main/.../Filename`
---- 

Filename 
[source, Java, linenums, role='code_column hide_tags=copyright'] 
---- 
include::finish/src/main/java/io/openliberty/guides/inventory/Filename[]
---- 
  • or if your file isn't a Java class:
[role="code_command", subs="quotes"] 
---- 
#Create this `Filename` configuration file.#
`src/main/.../Filename`
---- 

Filename 
[source, XML, linenums, role='code_column'] 
---- 
include::finish/src/main/.../Filename[]

---- 

On the site, it would look like:

  1. Replace

In the case where you are asking readers to replace a file, make sure you describe the changes that are made in the file in the paragraph below your action arrow. We ask users to replace a file when there are major changes introduced in an existing file. The format to ask readers to replace a file is the following:

[role="code_command", subs="quotes"] 
---- 
#Replace this `Filename` class.#
`src/main/.../Filename`
---- 

Filename 
[source, Java, linenums, role='code_column hide_tags=copyright'] 
---- 
include::finish/src/main/java/io/openliberty/guides/inventory/Filename[]
---- 

On the site, it would look like:

  1. Update

Note: It is not recommended because users will easily make mistake. Instead, use Replace.

We ask users to update a file when there are minor changes introduced to an existing file and when they might need change certain lines of code multiple times and we don't want to include multiple versions of the file in the guide. This action arrow will be able to highlight lines of code in the file that the reader is updating and will include a text section below it that gives the details on the exact changes the reader will be making.

For example in the opentracing guide, we ask users to disable and enable Tracing on a method: https://openliberty.io/guides/microprofile-opentracing.html#enabling-explicit-distributed-tracing

The format to ask readers to update a file is the following:

[role="code_command", subs="quotes"] 
---- 
#Update this `Filename` class.#
`src/main/.../Filename`
---- 
[role="edit_command_text"]
Specific instructions on how to update the file with [hotspot=sections]`sections` hotspotted.

Filename 
[source, Java, linenums, role='code_column hide_tags=copyright'] 
---- 
include::finish/src/main/java/io/openliberty/guides/inventory/Filename[]
---- 

On the site, it would look like:

When you hover over on a "Create"/"Replace"/"Update" action arrow, the codepane should display the corresponding file that is being mentioned in the action arrow. If you include multiple files in the same section, the action arrows might not point to the correct file. So, you need to specify which file in the "code_command" role for the action arrow.

For example, if you included 3 files in the same section:

Filename0
[source, Java, linenums, role='code_column hide_tags=copyright']
----
include::finish/src/main/java/io/openliberty/guides/inventory/Filename0[]
----

Filename1
[source, Java, linenums, role='code_column hide_tags=copyright']
----
include::finish/src/main/java/io/openliberty/guides/inventory/Filename1[]
----

Filename2
[source, Java, linenums, role='code_column hide_tags=copyright']
----
include::finish/src/main/java/io/openliberty/guides/inventory/Filename2[]
----

You need to specify file=1 to use Filename1 in the action arrow:

[role="code_command file=1", subs="quotes"] 
---- 
#Replace this `Filename1` class.#
`src/main/.../Filename1`
----

When you click on a "Create"/"Replace"/"Update" action arrow, and want the codepane on the right to automatically redirect to the file that the action arrow is talking about, you need to add hotspot inside the role="code_command":

[role="code_command hotspot file=0", subs="quotes"] 
---- 
#Create this `Filename` class.#
`src/main/.../Filename`
---- 

Hotspots

Hotspots are used to highlight parts of the code when describing the code to readers and also for referencing code files.

To reference an entire file, use [hotspot] before a backticked word. Example:

Take a look at your [hotspot]`pom.xml`.

To reference a few lines of code, use [hotspot=uniqueTagName] before a backticked word, where uniqueTagName is a defined in the file that the hotspot is referencing. Example:

The [hotspot=uniqueTagName]`list()` methods lists the contents of the bucket.

Tag names must be unique within the file that they are referencing and the syntax for tagging a syntax of code would be a comment in the language of the file in the following format:

Code or comments that will not be highlighted

// tag::uniqueTagName[]

hot spotted code 

// end::uniqueTagName[]

This is an example for a java file:

    @BeforeClass
    public static void oneTimeSetup() {
        String invServPort = System.getProperty("inv.http.port");
        String sysServPort = System.getProperty("sys.http.port");

        // tag::systemServiceIp[]
        systemServiceIp = System.getProperty("system.ip");
        // end::systemServiceIp[]

        invUrl = "http://localhost" + ":" + invServPort + "/inventory/systems/";
        sysUrl = "http://localhost" + ":" + sysServPort + "/system/properties/";
    }

and an example for a Dockerfile:

# tag::from[]
FROM open-liberty
# end::from[]

# tag::add[]
ADD --chown=1001:0 target/*.tar.gz /opt/ol
# end::add[]

To hide sections of code (such as copyright), add the hide_tags=copyright annotation as shown:

server.xml
[source, xml, linenums, role='code_column hide_tags=copyright']
----
include::finish/src/main/liberty/config/server.xml[]
----

To reference a few lines of code that are non-consecutive, use [hotspot=uniqueTagName hotspot=uniqueTagName..] before a backticked word. Example:

The [hotspot=uniqueTagName hotspot=uniqueTagName hotspot=uniqueTagName]`@Test` annotation indicates which methods are tests.

If there are multiple files in one subsection, you have to specify which file you are referring to when hotspotting. Use file=x where x is the priority in which the file was included in the subsection starting at 0. Example:

The [hotspot=uniqueTagName file=0]`Filename0` class communicates with [hotspot=uniqueTagName file=1]`Filename1` class.

Filename0
[source, Java, linenums, role='code_column hide_tags=copyright'] 
---- 
include::finish/src/main/java/io/openliberty/guides/inventory/Filename[]
---- 

Filename1
[source, Java, linenums, role='code_column hide_tags=copyright'] 
---- 
include::finish/src/main/java/io/openliberty/guides/inventory/Filename[]
---- 

On the site, it would look like:

Commands

If there are any commands that you want to ask the reader to run in the command prompt, include them in the following format:

[role='command']
----
command
----

Example:

[role='command']
----
git clone https://github.com/openliberty/guide-docker.git
cd guide-docker
----

Also be sure to add [role='command'] in front of any sections that you include from guide-commons because they may have commands in them. Example:

[role='command']
include::{common-includes}/gitclone.adoc[]

On the site, it would look like:

Some Tips:

  • Use $(cmd) instead of 'cmd' Windows does not support command substitutions at this moment.
  • For instructions that require the user to view the header of a webpage, ask the user to use the curl command instead of Postman. For Windows users who don't have curl, ask them to use the web-based tool Postwoman.io, which has the same functionality as Postman, but does not require an installed client which deters users.

XML Elements

Any mentions of xml elements should be updated to the format below (no triangular brackets):

This `element` does so on...

Links

Links that have titles and are meant to be visited must be hyperlinked. Example:

http://website.com[Website Title]

Links that are being described but do not need to be clickable can be made unclickable with a backslash:

This test case makes a GET request to the \http://localhost:9080 URL.
You will then visit the \http://localhost:9080/{YOUR_NAME} URL.

Links must be opened in a new tab, this can be accomplished with ^. Example:

URL[URL_Title^]

or

URL[^]

OS Specific Tabs

You can define OS-specific tabs in the guide when your application requires OS-specific commands on the OS it is being ran on.

Example:

[.tab_content.windows_section]
--
[role='command']
----
cd start 
mvnw.cmd package
----
--

OS that share the same commands can also be combined and defined as follows:

[.tab_content.mac_section.linux_section]
--
[role='command']
----
cd start
./mvnw package
----
--

On the site, it looks like:

Listing Blocks

Put outputs and similar content in single listing blocks.

Example: You should see information about the Gradle installation similar to this example:

------------------------------------------------------------
Gradle 4.1
------------------------------------------------------------

Build time:   2017-08-07 14:38:48 UTC
Revision:     941559e020f6c357ebb08d5c67acdb858a3defc2

Groovy:       2.4.11
Ant:          Apache Ant(TM) Version 1.9.6 compiled on June 29 2015
JVM:          1.8.0_144 (Oracle Corporation 25.144-b01)
OS:           Mac OS X 10.12.6 x86_64

Styling the listing blocks

  • Add role="no_copy" to listing blocks that users don't need to copy.

Example:

[source, role="no_copy"]
----
this is not important
----
  • Don't add a dollar sign ($) to the start of all commands in listing blocks, unless the command output is also included in the same listing block.

Example:

$ docker ps
CONTAINER ID        IMAGE               CREATED             STATUS              NAMES
2720cea71700        ol-runtime          2 seconds ago       Up 1 second         rest-app

Explaining the code

You can refer to pieces of code from your listing block with method names, class names, annotations, and more. If you cannot refer to a piece of code by a name, list that part of the code again. However, try not to repeat pieces of code that are more than three lines long.

If you extend a file from an earlier guide, follow this approach and take a look at the example.

  • Don't include the file in the start directory.
  • Provide the whole file in the guide instructions.
  • Instruct the reader to create the file in the start directory.
  • Describe only the pieces of the file that are relevant to the current guide.
  • Reference the guide where the rest of the code is described.

Project Structure

Include the following files and directories in your guide repository:

  • The start directory contains the starting point of the guide with all the base code that the user needs. This directory can include the base application and any utility components.
  • The finish directory contains the finished application and the code for the application that the user will build. Ensure that a user can go into this directory and execute a build without any failures.
  • The README.adoc file (your guide in AsciiDoc).
  • The LICENSE file contains the license agreement for the guide.

Include these additional files and directory if they are necessary.

  • Add the .gitignore in the root of the repository.
  • Add the .gitkeep in each directory that is meant to be empty.
  • Add the resources directory in the root of the repository to store any images or other resources that are needed to compile the AsciiDoc.

Organize your finish directory structure like the example:

finish
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── io
    │   │       └── openliberty
    │   │           └── guides
    │   │               ├── common
    │   │               │   └── JsonMessages.java
    │   │               ├── inventory
    │   │               │   ├── InventoryApplication.java
    │   │               │   ├── InventoryManager.java
    │   │               │   ├── InventoryResource.java
    │   │               │   └── util
    │   │               │       └── InventoryUtil.java
    │   │               └── system
    │   │                   ├── PropertiesResource.java
    │   │                   └── SystemApplication.java
    │   ├── liberty
    │   │   └── config
    │   │       └── server.xml
    │   └── webapp
    │       ├── META-INF
    │       │   └── MANIFEST.MF
    │       ├── WEB-INF
    │       │   └── web.xml
    │       └── index.html
    └── test
        └── java
            └── it
                └── io
                    └── openliberty
                        └── guides
                            └── inventory
                                └── EndpointIT.java
  • Create the main build file, such as a pom.xml file or a gradle.build file, in the root of the finish directory.
  • Place each module in its own directory in the src/io/openliberty/guides/ directory so that it resembles src/io/openliberty/guides/{module_name}. e.g. src/io/openliberty/guides/inventory
  • Use the src/io/openliberty/guides/common common directory to keep any common files for all modules.
  • Each module can either overwrite the common files in the common directory or include its own utility files. Store these files in the util directory in the src/io/openliberty/guides/{module_name}/util module directory or in another similar directory. e.g. src/io/openliberty/guides/inventory/util

Organize your start directory structure like the example:

start
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── io
    │   │       └── openliberty
    │   │           └── guides
    │   │               ├── common
    │   │               │   └── JsonMessages.java
    │   │               ├── inventory
    │   │               │   └── util
    │   │               │       └── InventoryUtil.java
    │   │               └── system
    │   │                   ├── PropertiesResource.java
    │   │                   └── SystemApplication.java
    │   ├── liberty
    │   │   └── config
    │   │       └── server.xml
    │   └── webapp
    │       ├── META-INF
    │       │   └── MANIFEST.MF
    │       ├── WEB-INF
    │       │   └── web.xml
    │       └── index.html
    └── test
        └── java
            └── it
                └── io
                    └── openliberty
                        └── guides
                            └── inventory
                                └── .gitkeep
  • Create all the directories for the user, but do NOT create the files that you want the user to add.
  • To enable Git to track empty directories, place an empty .gitkeep file into those directories.

Writing Tests

  • When you use the assertEquals() method, always define the expected and actual results as separate variable.

Example:

int expected = 3;
int actual = <your code>;
assertEquals(expected, actual, "Message here");

Formatting

  • Format section headers without code phrases. Don't use backquote marks (``) in section headers. For example, instead of writing "Creating a filename class", write "Creating a filename class".
  • Wrap lines at 88 characters to maintain readability in editors and on the website.
  • Use 4 spaces instead of tabs for indentation.