Julia: Project Workflow Recommendations

The term "project" in this post corresponds to the term "application" in package manager glossary

Rationale

Some ideas on basic julia workflow are given here. For a larger project, structuring of the project code is essential for many reasons, some of them are:

Recommendations

The following recommendations are partially inspired by B. Kaminski's post on project workflow and the DrWatson.jl package by G. Datseris.

Generate the project directory itself as a package

Name this e.g. MyProject. UsePkg.generate or PkgTemplates.jl. Unlinke a published Julia package, this project-package will remain not be registered in a Julia package registry, its code will be shared directly via git repository urls. Developing the project in such a project-package has the following advantages:

New packages can evolve from the project code

For this purpose, optionally you can have a folder packages which contains other sub-packages which potentially can evolve into standalone, even registered packages. As relative paths are recorded in Manifest.toml, these are made available within the project via Pkg.develop(path="packages/MySubPackage"). Starting wit Julia 1.11, Project.toml can have a [sources] section which can contain a relative path for a subpackage. Either way, using this approach, the whole project tree including sub-packages will stay relocateable.

Manifest or not ?

Should the Manifest.toml be checked into the project repository or not ? The answer is - your mileage may vary.

Pro Checking in the manifest file:

Pro not checking in the manifest file:

Always start Julia from the package root

Activate the project environment in notebooks

Project specific Pluto notebooks would reside in a notebooks subdirectory and call Pkg.activate(joinpath(@__DIR__,"..")) in their respective Pkg cell to activate the MyProject environment. As a consequence, Pluto's in-built package manager will be disabled and the project specific notebooks will share the MyProject environment and cannot be shared independent from the MyProject tree (If independent sharing is desired, common project code can be collected into a package residing in packages and registered in a registry; registering MyProject itself as a package is not recommended. – More about this in another post).

Consider using DrWatson.jl

You may use DrWatson.jl for managing subdirectory access, simulation results and version tagging. By explicitely activating the project environment at the start of Julia or in the notebook Pkg cell, you can avoid @quickactivate and avoid putting using DrWatson into script files and notebooks for the sole purpose of activating the common environment. See also this discussion.

A sample project tree

A sample project tree could e.g. look like this

MyProject
├── LICENSE
├── Manifest.toml
├── notebooks
│   └── demo-notebook.jl
├── packages
│   └── MySubPackage
│       ├── Manifest.toml
│       ├── Project.toml
│       ├── src
│       │   └── MySubPackage.jl
│       └── test
│           └── runtests.jl
├── papers
├── Project.toml
├── README.md
├── scripts
│   └── demo-script.jl
├── src
│   └── MyProject.jl
└── test
    └── runtests.jl

You can download the Julia script genproject.jl and generate this structure a subdirectory on your computer via

julia --compile=min genproject.jl name_of_your_project

Feel free to adapt the generated directory tree to your needs and don't forget to make a git repository out of it as early as possible.

Summary

By taking advantage of Julia's best-in-class package management facilities, the proposed approach goes a long way in the direction of maintaining sustainable research software. From a talk by A. Zeller:

  1. Have a repo ✓

  2. Anyone can build ✓

  3. Have tests ✓

  4. Be open for extensions ✓

  5. Have examples ✓


Update history