Project hierarchy guidelines

Abstract

One thing that every growing software project has to deal with at some point is organizing files in their repository: where to put source files? Where to put tests? Packaging templates (.spec, debian/control)? Build scripts? Project guidelines?

What I've seen most often is generally one of these:

  • Just don't care and drop everything in the root directory.

  • This code is part of a project which already has guidelines so just follow them.

  • Platform this code built upon already has guidelines so just follow them.

  • Don't try to solve that, it's a waste of time.

  • Try to solve that iteratively: every now and then, realize that the hierarchy is confusing so start. Twiddle, tweak, frobnicate, tweak, frobnicate, twiddle...

Each of above approaches has its cons and (arguably) pros, the mere decision which approach to apply is not easy, so one easily gets into a decision paralysis.

This document is an attempt to help people avoid that and get at least some starting point when putting things together.

Guidelines

Root (README et al.)

It's good to keep as little files here as possible, but few names are already become de-facto standard.

Every decent project has a README file in the root folder. You can name it README.md, README.rst, but it should be the first thing everyone reads. Normally, a brief introduction and installation instructions, unless they are already provided under INSTALL file.

Among other common files here are LICENSE, Makefile, CHANGELOG or similar files that are chiefly related to a project as a whole.

src

Everything that is supposed to be (directly or in some "built" form) deployed on the target host goes under src.

Under this folder, it makes sense to have files divided in sub-folders named reminiscent to the target paths. For example, host configuration files should be under src/etc, library source files under src/lib, future binaries under src/bin, future manpages to src/man...

Note that it does not matter whether there is some significant build procedure to happen; it's OK if most of the files here are just verbatim copies ready to be deployed to the target.

tests

Your test suite goes here. How to structure files under this directory will most probably depend on the test framework you use.

artifacts

If your test suite creates files that you usually need to review, this is a good place. Subdirectories here should bear a timestamp in a human-readable and sortable timestamp format (such as ISO 8601).

Note that normally this directory will never exist in a freshly cloned repository and it's likely to be excluded from version control system via file such as .gitignore.

notes

Documentation related to your project. Evertything from guidelines to newcomer howtos, style guides, design notes, philpsophy articles...

utils

Any build scripts and utilities that are only useful for your project developers and testers.

packaging

Templates to help package maintainers. Templates for RPM SPEC files, debian control directories or similar data can live here.

Note that in many cases distributions like Debian or Fedora may not be able to directly use these files, but they can be a good start for e.g. creating unofficial .deb files.

MKit already provides features that can help generate such files.

Example

A "living" example: shellfu:

.
├── LICENSE             # \
├── Makefile            #  Pretty much standard files...
├── README.md           # /
├── artifacts
│   ├── artifacts-inigrep_inigrep-20161202-073432
│   │   ├── TF_ENUMERATED_SUBTESTS
│   │   ├── TF_FILTERED_SUBTESTS
│   │   ├── TF_RUN
│   │   ├── oracle      # \
│   │   │   └── ...     #   artifacts are now huge since 
│   │   ├── result      #   I ran a lot of tests recently
│   │   │   └── ...     # /
│   │   └── test
│   │       └── ...
│   └── artifacts-shellfu_api-20161202-081440
│       └── ...
├── mkit.ini            # <- MKit meta-data file
├── notes               # <- my design notes, although
│   └── style.md        #    most are still in my head :)
├── packaging
│   ├── debian          # \
│   │   ├── changelog   #   only used for ad-hoc, testing and
│   │   ├── control     #   alpha RPMs and .deb's
│   │   └── ...         #   (so far, probably for good)
│   └── shellfu.spec    # /
├── src
│   ├── bin                     # \
│   │   ├── shellfu-doc         #   here most of the "meat" lives,
│   │   └── shellfu-get.skel    #   only about two files really need
│   ├── complete-devel.bash     #   any "building"
│   ├── complete.bash           #
│   ├── include-bash            #   notice that tree here does
│   │   └── ...                 #   not attempt to strictly follow
│   ├── include-sh              #   final placement, jsut hinting
│   │   └── ...                 #   is enough
│   └── shellfu.sh.skel         # /
├── tests                   # \
│   ├── TF_HEADER           #   another "huge" directory
│   ├── inigrep_inigrep     #   structure, the test suite
│   │   ├── TF_RUN          #
│   │   ├── oracle          #   hierarchy is influenced by TFKit
│   │   │   └── ...         #   which itself is actually embedded
│   │   └── test            #   under `utils` directory below
│   │       └── ...         # /
│   └── ...                 #
└── utils           # \
    ├── mkit        #   all build scripts live here; actually just
    │   └── ...     #   MKit and TFKit; note that TFKit lives apart
    └── tfkit       #   from the suite (they meet often, though ;))
        └── ...     # /