logo python and rust

Why am I using Rust instead of Python for my new CLI or API?

Why is it the right move?

Python

I firstly moved complex scripts from Bash to Python due to the simplicity to handle errors and a clear way to manage arguments.

Main libraries used:

  • Python Standard Library
    • argparse: Parser for command-line options, arguments, and sub-commands
    • json: JSON encoder and decoder
    • multiprocessing: Process-based parallelism
    • subprocess: Spawn new processes, connect to their input/output/error pipes, and obtain their return codes
  • Requests: Elegant and simple HTTP library for Python, built for human beings

This easy way has a drawback: Python needs to be installed with all libraries that we’re using.

Rust

Recently, I rewrote a quick shell script in Rust because I wanted real portability and the easiest way to parallelize tasks.

Main libraries used:

  • clap: Command Line Argument Parser
  • attohttpc: Lightweight and simple HTTP client
  • rayon: Data-parallelism library that makes it easy to convert sequential computations into parallel
  • Rust Standard Library
    • collections::HashMap: A hash map implemented with quadratic probing and SIMD lookup
    • process::Command: Process builder, providing fine-grained control over how a new process should be spawned
  • serde: Framework for serializing and deserializing Rust data structures efficiently and generically
  • serde_json: Strongly typed JSON library
  • ureq: Simple, safe HTTP client

I use attohttpc or ureq depending on licenses denied due to the project’s license.

Also, for big projects where requests can’t be handled directly/easily with them, I switch to reqwest

This way, I have the perfect portability:

  • multi-platform (FreeBSD, Linux, macOS, Windows & co.)
  • multi-architecture (aarch64, riscv, x86-64)
  • can do a static build (environment variable RUSTFLAGS="-C target-feature=+crt-static") to put the binary into a scratch OCI image

Is it the right move?

I think that it’s the perfect move.

When you build some tools that can be deployed and used by people using different operating systems, also if they’re not administrators of their workstation, we need to use the right programming language.

In this case, I can’t require the installation of an entire environment (ex: the Python interpreter with the virtual environment for the tool).

In the case of OCI image, it’s about the size… so how many seconds is needed to start/run it.

Why will I request the user to use a 200+ MB image when the same tool statically compiled is around 10-20 MB?

Why not Go?

I haven’t chosen Go due to Rust’s safety guarantee:

The safety guarantee is one of the most important aspects of Rust; Rust is memory-safe, null-safe, type-safe, and thread-safe by design. - source

Also for its immutability by default, I like to have some Functional Programming style.

Finally, the performance because Go isn’t so optimized.