Code that is unused has little value.

If nobody is using your code then how do you know if it is any good?

Presumably you wrote it for a reason.

Don't hide your code away, let it be free!

Collaborative projects are more successful than solo projects.

Having others use your code and provide feedback keeps the project alive.

If others take an interest and provide patches - that is excellent, but having people tell you that they are using your code is excellent motivation for you to scratch some itches yourself.

Make your code easy to use for your target audience.

I don't know the audience for my code, I hope to find out by its reception.

If it turns out I don't have one, then so be it. In this case the code itself isn't the goal, it exists as a vehicle for writing these articles.

Pick a licence

No matter how you want to make your code available you will need to provide a licence so anyone can be provably allowed to use it.

My code is currently licensed under the CC BY-SA 3.0 licence, since that is the licence of all of the blog's contents.

Copyleft

If I were to use a copyleft licence then I would be more likely to attract contributions from people who do not want it to be usable by proprietary software developers who could take it and not contribute any changes back.

This potentially provides an incentive for potential users to contribute any potential improvements back.

The current code is already copyleft since it's CC BY-SA 3.0, but it's less suitable as a licence for code.

Permissive

A permissive licence would allow proprietary software developers to use my code in closed software projects.

This is theoretically a wider audience than those who can use copyleft, but some developers may, with good reason, object to contributing to a project which allows others to use it without contributing anything back.

It also relies on the generosity of developers to contribute any changes back since with a permissive licence there is no licence-provided incentive to do so.

My choice

I sometimes need to write proprietary software. I'd like to be able to have a high quality library to use rather than have to re-implement it all again.

I'd also prefer that people writing proprietary software use high quality code than implement it themselves and get it wrong.

For this reason I'm going to use the ISC licence

Let potential users know what licence the code is under

Put a LICENSE file in your repository to make it clear how the project is licensed so they can know quickly whether they can use your project.

Add the short text of the licence to the header of your source files to make sure there is no doubt that the whole of your project is licenced the same way.

Packaging

The absolute minimum is to have the source code repository publically visible, so anyone who wants a copy can fetch it themselves.

If you then make tags it becomes easier to get a specific version.

If your source code repository has a web UI it can provide snapshots, so users don't need to be proficient with your version control tool and can avoid downloading all the history they don't care about.

You can also make source distributions, which may be different from a snapshot. These usually involve packaging up any generated or derived source files to reduce the number of dependencies required to build the code.

If you have a set of expected target environments then you can provide binary packages for those environments. This can be a set of statically linked or bundled binaries designed to run on every platform. It could be uploaded to the platform's package repository. It could be participating in a distribution's community and packaging in that.

Since my project is too young to even have its first release I'm going to just make the code available. As-is it is compatibly licensed such that users can copy it into their codebase.

For the first release I intend to tidy it up into a library that can be installed by running make install.

Put it somewhere it can be found.

Traditionally this was done by putting it in a software distribution, either yourself or having a member of the community package it.

These days it's more common to add it to the language's package manager, so CPAN for Perl modules, PyPI for Python modules, Ruby Gems for Ruby packages, NPM for Node.js packages and Crates.io for Rust packages.

There is strong feeling about whether this is a good idea, but they do provide a degree of discoverability that I would like.

Unfortunately there is no equivalent for C code, so I'm going to throw it up on GitHub and hope for the best.

GitHub has its faults, the largest of which is that it is centralising a decentralised version control, but like it or not, this is how much free-software is done and in the absence of knowing my audience I'm going to take every advantage.

There's more to a project than a code dump

Now the code is out there. Well done.

But a project is more than just code.

Communication

You need to communicate.

When your project gets big enough you will need more than GitHub providing an issue tracker and an interface for merging patches.

You might need an IRC channel (or other chat protocol) for providing help and coordinating with other developers.

You might need a mailing list to receive patches, discuss important changes, and announce new releases.

Meeting other developers and users face-to-face is important, so if you get big enough you might need to arrange hack days, dev-rooms at conferences, or eventually maybe even your own conference.

It may be advisable to have a code of conduct for your community sooner rather than later, as it may help to have a statement that you wish to handle abuse seriously and it may prevent difficulty retrofitting a code of conduct in later.

Documentation

Code documentation for how something works is handy for developers, more so if there are other developers who won't have your memory.

Documentation of interfaces is also important, both internal interfaces for how implementation details interact and external interfaces for how your users are meant to use it, be it API documentation for libraries, usage text and man pages for command-line applications, or screenshotted guides for GUI applications.

Then you may need more in-depth guides for how your code fits in to the wider context, such as blog articles describing how to integrate your library into a wider framework to achieve a particular goal, use your command-line application in a pipeline or batch script, or an example where your GUI application is used.

Then there's wider-project documentation, such as plans, documentation of how to configure your code, how to set up a developemnt environment, where all the development resources are, etc.

Note that documentation is also a disincentive to change things, since it means there is more work involved in making changes, so it is preferable to prioritise documentation of things that are the least likely to change.

Don't use it as an excuse to not write documentation though, unless it's obvious how it's meant to work or there are numerous examples to crib from a lack of documentation is a huge disincentive from using a project.

Releasing

Taking snapshots of the current version only works for so long.

Users like releases as they mark a point of stability. Users like stability since it means the code behaves consistently.

Releases are not perfect as all code has bugs, so point-releases where improvements are made that don't change behaviour are essential, since even if there is a newer version which is better, users may depend on existing behaviour.

Use semantic versioning so it's clear to users what the compatibility is, and make it easy for existing tooling to reason about your version numbers.

Testing

Having a test suite makes it easier to accept contributions and have some confidence in your code's quality.

Test for use-cases your users use, since you don't want to cause them difficulties.

When you find bugs, write a test first so you can know when it is fixed and this becomes a regression test to ensure it does not break again.

Test at multiple levels so you can make the most appropriate tests. Write unit-tests so the behaviours of your individual modules stay working, and behaviour-level tests tests for use-cases your users care about.

If you depend on a library, look to see how well tested that is, since you depend on it working the way it currently does. Provide tests for the use-cases you care about.

Make these tests able to be run by anyone, so they can be run by contributors to see if their changes break anything and downstream users can use the tests to see whether your code works.

Make these tests run automatically when changes are merged, so you can have some confidence that the code everyone is expected to use works.

Make these tests run automatically for proposed changes. People's development environments are different, not every developer has access to every environment the code is used in. If proposed changes can be run in every expected target environment then you can reduce the risk of it breaking in less common environments.

As with documentation, testing can make it harder to change code, so it's a trade-off between development speed and quality.

Termination

Know when to give up. No project is immune to competition. If you discover another project with compatible goals is competing then it may be better to swallow your pride and join that project instead.

You may have insights that will be of value to that project instead, and if the goal is to have a useful project what does it matter that it was started by someone else?

How did I get here?

I started my article series because on a project I was working on a coworker did the naïve thing and used rename(2) to move a file.

Having spent far too long reading-up on the Linux file system interface I could talk at length about what was necessary to do it properly, but I could not explain this concisely, so I decided to write instead.

I thought it would be a single article, but then it grew larger than I expected and saw no prospect of finishing, so I split it up into another article, and then another, and another.

Now, some 9000 words later I have an 8-article series and a project on GitHub. So the lessons to take away from this are:

  1. Moving files sounds like a trivial thing to do, but is actually a horrible mess of complexity.
  2. Nothing is ever as simple as you intend and at some point you need to call it done so you can move on and do other things.

The code is at https://github.com/fishface60/linux-fsops, yes that is my GitHub account name, legacy and branding can be hard to get rid of.