I have been using Rust on and off for the past five years or so, first picking it up around the time release 1.0 dropped. I then seriously learned the language in 2019, and, thanks to coding events such as Advent of Code, found a reason to make (arguably) beautiful code that trained me to make simple data structures work efficiently together to solve problems. Nowadays, I scale my development towards multi-threaded, asynchronous programs, in particular web server toys and active projects (to be announced soon).

My workflow in Rust has increasingly involved a tool that my peers find funny (for good reasons), and which has helped me tremendously when it came to writing Rust that works but also works well and is pleasant to read: pain.

Clippy

Clippy is Rust's official linter program to "catch common mistakes and improve your Rust code". Rust is, contrary to what people feel, extremely friendly towards new developers: the compiler spits out nice error messages with suggestions for fixes that are almost always right, the Book is the greatest piece of documentation I have ever read, the community of developers is extremely friendly and ready to explain concepts that are indeed hard to grasp for a lot of developers at first, etc.

Clippy can be installed into cargo, Rust's project management tool, using the rustup toolchain manager. It integrates perfectly in the environment of other tools cargo provides, and it can be integrated in your linting routine to show you common mistakes.

The Lint Groups

Clippy groups its linting rules into groups, or categories that you can find on their search engine and allow/deny/warn as a whole. The most notable groups are:

  • complexity: catches common errors that make your code needlessly complex for tasks that you are trying to make
  • correctness: catches code that is grammatically correct but results in nonsensical, typically unintended actions
  • deprecated: catches usage of deprecated methods
  • nursery: catches errors newcomers to Rust often make
  • pedantic: catches common errors that developers who are more familiar with Rust make that could be turned into better code
  • perf: catches resource-wasting patterns (creating default objects ahead, etc)
  • suspicious: catches code that looks suspiciously like the first step towards a bug or bad manipulation of the code base

Other categories exist, but these are the ones I think about the most. Another one I have to mention is restriction, which is hilarious to me. It is meant to restrict usage of patterns forbidden for a specific project (either because of style policies, or constraints). In fact, it is so thorough and unforgiving that you literally cannot act on it as a whole, since some of the lints in there are contradictory (see the AT&T and Intel asm flavour lints, for example).

Pain

The seven groups I mentioned above, along with clippy::style and clippy::cargo, are completely denied in most, if not all of my projects. They will typically also include more lints from standard Rust. As of the writing of this post, my linting header is as follows:

// Make clippy quite nasty
#![deny(clippy::cargo)]			// Checks for garbage in the Cargo TOML files
#![deny(clippy::complexity)]	// Checks for needlessly complex structures
#![deny(clippy::correctness)]	// Checks for common invalid usage and workarounds
#![deny(clippy::nursery)]		// Checks for things that are typically forgotten by learners
#![deny(clippy::pedantic)]		// Checks for mildly annoying comments it could make about your code
#![deny(clippy::perf)]			// Checks for inefficient ways to perform common tasks
#![deny(clippy::style)]			// Checks for inefficient styling of code
#![deny(clippy::suspicious)]	// Checks for potentially malicious behaviour
// Add some new clippy lints
#![deny(clippy::use_self)]		// Checks for the use of a struct's name in its `impl`
// Add some default lints
#![warn(unused_variables)]		// Checks for unused variables
// Deny missing documentation
#![deny(missing_docs)]
#![deny(rustdoc::missing_crate_level_docs)]

This is pain incarnate. People I talk with who are starting out in Rust would rather bang their head against a wall than try and satisfy such draconian requirements. By all means, I tell them, they could be far worse!

Yet this approach forces you to write code that is not only valid, and correct, but good. I started out simply denying clippy::pedantic, which is enough to get a good grasp of good practices in Rust. Once no lints typically fire after you are finished writing a piece of code, try and deny another category, like nursery. Then, correctness, or perf. After a while, you will learn about the common mistakes you make, and recognize the patterns, and catch yourself in the act, before Clippy can yell at you. After that, learn about the mistakes you do from a new group!

At some point you end up with code that is functional, efficient and good-looking. Rust code already looks beautiful in general, but good Rust code is pleasant to read (especially if you literally force yourself to write good documentation with the documentation lints).

With time, you learn to love that nasty paperclip. 📎