imag/doc/src/03010-conventions.md
Matthias Beyer 29b04a269a doc: Rewrite section on error handling in libraries
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
2019-04-26 16:15:34 +02:00

4.4 KiB

Conventions, best practices

This section explains conventions used in the imag codebase. It is mainly focused on developers, but a user may read it for getting to know how imag works.

Lets work our way up from the store and how to extend it to the commandline user interface.

Versioning

All imag crates are versioned with the same version number until we reach some "1.0.0" version. This means that all imag tools are only tested for compatibility with libraries and such if their version numbers match. It might not be possible to import one imag library in version 0.3.0 and another one in 0.4.0 and make them work together. It also means that if new tools are introduced into the imag codebase, they might start with their first version not at 0.1.0 but at something like 0.5.0.

Store and Entry functionality

A Entry does not offer much functionality by itself. So its the job of libraries to extend its functionality. This should never be done by wrapping the Entry type itself but by providing and implementing an extension trait on it.

Same goes for extending the Store type: never wrap it, always provide an extension trait for it.

These two rules ensure that the type does not lose any functionality from a wrapping. Deref could do that, but not over muliple levels, so extension traits it is. It also most likely results in functions inside the extension trait which all return a Result<_, _>.

Libraries

In the next few sections, conventions and best practices for writing a imag library are written down.

A developer of imag should read this carefully, a user may skip this section or cross-read it for better understanding of the imag project.

Library naming

Libraries which provide functionality for entries or the store but no domain-functionality should be named "libimagentrything" whereas "thing" stands for what the library provides.

All domain libraries should be prefixed with "libimag".

Library scope

A library should never introduce utility functionality which could be useful for other libraries as well. If there is no such functionality available, the "libimagutil" or "libimagentryutil" might be a place where such a function would go to.

If a library has to introduce free functions in its public interface, one should think hard whether this is really necessary.

Library error types/kinds

Libraries must use "failure" to create error objects.

Libraries with commandline frontends

Libraries with commandline frontends provide end-user functionality. They are called "domain" libraries. Normally, they depend on one or more "libimagentrything" libraries. They should be named "libimagthing", though. For example: "libimagdiary", "libimagtimetrack" or "libimagwiki", whereas the commandline frontends would be "imag-diary", "imag-timetrack" and "imag-wiki", respectively.

If such a library needs to depend on another "libimagthing", for example if "libimagdiary" needs to depend on "libimagnote", one should think about this and whether the functionality could be outsourced to a more general "libimagentrything".

Library testing

All libraries should be tested as much as possible. Sometimes it may not be possible without a lot of effort, but still: more tests = better!

Commandline tools

The commandline tools are the CLI-frontends for their respective libraries. So libimagdiary has a CLI frontend imag-diary.

Those CLI frontends use functionality from libimagrt to build a commandline interface which is consistent with the rest of the ecosystem.

Commandline applications use the runtime interfaces for receiving IDs from the CLI or IDs which are piped into the application. Commandline applications use the 'stdin'/'stdout'/'stderr' wrappers provided by the runtime (see section below).

Commandline applications are only interactive when specified by the user (normally via a --interactive flag). An application must provide the full functionality via its commandline interface, thus it is not allowed to provide functionality which is only usable in interactive mode.

IO

There are minor restrictions how imag tools should do IO. A good rule of thumb is (but most certainly only applicable when programming an imag tool in Rust): use libimagrt to do IO of any kind.

For more information, or if not using Rust as programming language: the documentation of libimagrt describes how IO should happen (which output stream to use, how input should be done).