I am struggling on how to organize the best way my code into modules. I never know if my modules and structures are well organized and if my modules are too "general" or too "specific". Moreover should I put some code into a specific crate ?
From my point of view, one of my main concern is whether a specific structure can be well found within all of my code ? Is this a good question as in does it tell one how to organize it's code ?
How do I know if my code is well organized / structured ?
Just so you know I come from a language that doesn't have modules. One file mostly (not all of the time) represents one class.
Some very general advice that I've heard repeated here and that I use:
start with a single module or a small number of modules, don't try to predict ahead of time what will be needed later since you can easily refactor
separate code by functional area, meaning the semantic areas of your overall program model (e.g., don't separate structs from traits from constants, keep them together when they are semantically related)
Modules are the basis of encapsulation and privacy in Rust: Things that are private are always private to a particular module (rather than private to a particular type like in many OO languages). You should use a module anywhere you want to create some interface that hides its internals.
So if you have some code with private fields or functions for its internal use, and you want to encapsulate them (i.e. limit which parts are visible/callable by other pieces of your code), you should enclose them in a module. Where you might write a class with private members/methods in Java- or C++-like languages, in Rust you should frequently write a module instead. This is especially important in unsafe code.
Modules also form the namespace of your Rust crate, letting you group similar things together (much like C++ or Java namespaces). This lets you organize the documentation of your library crates, for example. But this is a bit of a secondary concern, since you can always use re-exports to make your public namespace structure different from your “real” code structure if desired.
Thank you all for your time and great explanations.
So if I understand well your answers, in summary it mostly comes out of practice and depending on the context ?
How, in general, is the division of modules considered ? Is it better, when possible, to divide it into smaller, more specific, files (knowing the module can grow and have more struct) ?
Is it bad if someone else reading my code, takes some time to search for the location / definition specific struct ?
From the way I see it, and I'm quite sure it's wrong, it's better to have more specific modules then less and each one being bigger (maybe to big)
Yes. Don't try to perfectly predict what modules you need; adapt to where you find yourself.
Don't create modules in anticipation of growth. Having too many modules means you spend more effort on writing out the correct paths and updating your uses, in addition to potentially hurting readability by making the reader have to jump through more files. Wait until either the file is big, or you know that splitting into another module would make more sense to the users of these modules.
The time to create a module that isn't about size is when it's about abstraction/encapsulation/loose-coupling — when you're saying: these particular parts are implementation details, so they’re private within this module and the rest of the program doesn't care and can't see them.
My own rules for this sort of thing are:
I split a file into more files (which are also more modules) when the file becomes so long that I get lost navigating it, or when I am trying to add something and I can't decide where in the file it belongs. However, as modules, these split-off files usually have their contents reexported, so they don't form part of the hierarchy that is visible outside of this module:
mod control;
pub use control::*;
mod storage;
pub use storage::*;
#[cfg(test)]
mod tests;
When choosing how big a public module should be, I run cargo doc and look at the documentation for the module in its current state, and consider whether that list is coherent and useful. Are there things listed that are irrelevant to the usual goal of using this module? Are there things that are frequently needed, but are buried in submodules? If so, that is evidence for a split or merge/reexport.