<!--
  SPDX-License-Identifier: Apache-2.0
  SPDX-FileCopyrightText: 2021 The Elixir Team
-->

# Library guidelines

This document outlines general guidelines for those writing and publishing
Elixir libraries meant to be consumed by other developers.

## Getting started

You can create a new Elixir library by running the `mix new` command:

    $ mix new my_library

The project name is given in the `snake_case` convention where all letters are lowercase and words are separate with underscores. This is the same convention used by variables, function names and atoms in Elixir. See the [Naming Conventions](naming-conventions.md) document for more information.

Every project has a `mix.exs` file, with instructions on how to build, compile, run tests, and so on. Libraries commonly have a `lib` directory, which includes Elixir source code, and a `test` directory. A `src` directory may also exist for Erlang sources.

The `mix new` command also allows the `--sup` option to scaffold a new project with a supervision tree out of the box. For more information on running your project, see the official [Mix & OTP guide](../mix-and-otp/introduction-to-mix.md) or [Mix documentation](`Mix`).

## Publishing

Writing code is only the first of many steps to publish a package. We strongly recommend developers to:

  * Choose a versioning schema. Elixir requires versions to be in the format `MAJOR.MINOR.PATCH` but the meaning of those numbers is up to you. Most projects choose [Semantic Versioning](https://semver.org/).

  * Choose a [license](https://choosealicense.com/). The most common licenses in the Elixir community are the [MIT License](https://choosealicense.com/licenses/mit/) and the [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/). The latter is also the one used by Elixir itself.

  * Run the [code formatter](`mix format`). The code formatter formats your code according to a consistent style shared by your library and the whole community, making it easier for other developers to understand your code and contribute.

  * Write tests. Elixir ships with a test-framework named [ExUnit](`ExUnit`). The project generated by `mix new` includes sample tests and doctests.

  * Write documentation. The Elixir community is proud of treating documentation as a first-class citizen and making documentation easily accessible. Libraries contribute to the status quo by providing complete API documentation with examples for their modules, types and functions. See the [Writing documentation](../getting-started/writing-documentation.md) chapter of the Getting Started guide for more information. Projects like [ExDoc](https://github.com/elixir-lang/ex_doc) can be used to generate HTML and EPUB documents from the documentation. ExDoc also supports "extra pages", like this one that you are reading. Such pages augment the documentation with tutorials, guides, references, and even cheat-sheets.

  * Follow best practices. The Elixir project documents [a series of anti-patterns](../anti-patterns/what-anti-patterns.md) that you may want to avoid in your code. The [process-related anti-patterns](../anti-patterns/process-anti-patterns.md) and [meta-programming anti-patterns](../anti-patterns/macro-anti-patterns.md) are of special attention to library authors.

Projects are often made available to other developers [by publishing a Hex package](https://hex.pm/docs/publish). Hex also [supports private packages for organizations](https://hex.pm/pricing). If ExDoc is configured for the Mix project, publishing a package on Hex will also automatically publish the generated documentation to [HexDocs](https://hexdocs.pm).

## Dependency handling

When your library is used as a dependency, it runs by default in the `:prod` environment. Therefore, if your library has dependencies that are only useful in development or testing, you want to specify those dependencies with the `:only` option. You can also specify `:optional` dependencies in your library, which are not enforced upon users of your library. In such cases, you should also consider compiling your projects with the `mix compile --no-optional-deps --warnings-as-errors` in your test environments, to ensure your library compiles without warnings even if optional dependencies are missing. See `mix deps` for all available options.

Keep in mind your library's [lockfile](`Mix.Project#module-configuration`) (usually named `mix.lock`) is _ignored by the host project_. Running `mix deps.get` in the host project attempts to get the latest possible versions of your library’s dependencies, as specified by the requirements in the `deps` section of your `mix.exs`. These versions might be greater than those stored in your `mix.lock` (and hence used in your tests / CI).

On the other hand, contributors of your library, need a deterministic build, which implies the presence of `mix.lock` in your Version Control System (VCS), such as `git`.

If you want to validate both scenarios, you should check the `mix.lock` into version control and run two different Continuous Integration (CI) workflows: one that relies on the `mix.lock` for deterministic builds, and another one, that starts with `mix deps.unlock --all` and always compiles your library and runs tests against latest versions of dependencies. The latter one might be even run nightly or otherwise recurrently to stay notified about any possible issue in regard to dependencies updates.

### Dependency Version Requirements

When depending on other libraries, the dependency version requirements are ultimately up to you. However, you should consider the effects that an overly strict dependency requirement can have on users of your library. Most dependencies adopt [Semantic Versioning](https://semver.org/), and therefore provide reasonable guarantees about what each release contains. For instance, if you use `{:some_dep, “== 0.2.3”}`, this prevents users from using any other version but the one that you specified, which means that they cannot receive bug fix upgrades to that package. When in doubt, use a dependency in the format of `"~> x.y"`. This prevents the user from using a higher major version of the library, but allows them to upgrade to newer minor and patch versions, which should only include bug fixes and non-breaking improvements.

The exception to this is pre 1.0 libraries using [Semantic Versioning](https://semver.org/), which provide [no guarantees](https://semver.org/spec/v2.0.0.html#spec-item-4) about what might change from one version to the next. In this scenario, depending on the full patch version, i.e `"~> 0.1.2"` is a better default.

A common mistake is to use a dependency in the format of `"~> x.y.z"` to express "a version greater than `x.y.z`". For example, if you are depending on `"~> 1.2"`, and the dependency publishes a fix in version `1.2.1` that you need for the next version of your library. If you use `"~> 1.2.1"` to express that dependency, you are preventing users from upgrading to `"1.3.0"` or higher! Instead of `"~> 1.2.1"`, you should use `"~> 1.2 and >= 1.2.1"` as the version requirement. This allows users to use any version less than `2.0`, and greater than `1.2.1`.
