How do you design your Rust projects?

Let's assume you're building a user-facing application, not just a proof-of-concept or a crate for others to use. Where do you start? Assuming you've figured out your customer's journey, how the application would be used and which features would be available, how do you design your architecture?

Coming from a JS / Dart prototyping background, it's hard not to notice that Rust doesn't (generally) encourage rapid prototyping - but it's one hell of a tool to build pretty much anything (except for a GUI or a mobile app, perhaps - for now) once you've figured out what it is exactly that you're building.

My question is - how do you get there?

All the zero-cost abstractions make all the low-level programming much easier, but they also inadvertently force you to focus on lower-level details before properly grasping the higher-level structure. Therefore - are there any tips / tricks / suggestions / guidelines you might recommend to follow? Or is it just about experience? I just can't help but feel that I'm doing something wrong after repeatedly trying to dive heads-on into a project only to get extremely confused after a while with a hell of a mix of higher-level functions and lower-level tokio::spawn-s, which force me to start the whole thing from scratch all over again.

4 Likes

First of all, I would start by asking myself what kind of project am I trying to design? Once I have answered that question, I would go to the corresponding "Are we X" website for each of the development areas that are covered by Rust, and then start looking at similar projects / repositories for inspiration.

When I think of zero-cost abstractions in Rust, I'm definitely not thinking on whatever you meant by here. Zero-cost abstractions are, well, zero-cost, meaning that you get them for free. They are there to make your like as a coder easier and your code more correct and with better performance.

I think a huge part of it is managing to shush the part of your brain that constantly says "but you could use lifetimes here" or "I bet there's a way you could not copy that".

Rust is awesome because it has all those things, but as someone here once put, in Python everything's a Arc anyway. So if you'd be willing to prototype in something like that, just don't worry about a bunch of these things. And if you just accept a few more .to_owned()s so you're dealing in owned things instead of having to fence with the borrow checker, your life can be way easier.

Not to mention that copying a String is faster than you might expect, so in most places it's probably completely fine even for the longer term.

5 Likes

This is probably a topic for at least a book or two. Short version:

  • There are some Rust-specific design patterns and API guidelines.

  • Rust really likes tree-like data structures, and dislikes parent-child or anything-references-anything designs. This means it will help a lot if you can figure out how to make your program and your data tree-shaped.

  • Passing context to functions as an argument is usually more borrow-checker friendly than using self.context.

  • Be conscious of which data is shared, because it has to be shared due to requirements of the design/domain. Avoid accidental sharing for convenience or from following design patterns of other languages. When it's shared, it needs Arc and likely Mutex or Atomic*.

  • If you identify parts of your program (especially "leaf" ones) that should be separate (e.g. avoid mixing business logic with your compression algorithm or drawing routines for buttons), make them separate crates (use Cargo Workspaces). Rust will help enforce separation of concerns there, and thinking in terms of APIs may help separating data and avoiding ball-of-references designs that borrow checker doesn't like.

  • You can't make a big complex application by writing a big complex application from scratch. Make something smaller that works, and expand/refactor later. Rust with rust-analyzer are very refactoring-friendly.

11 Likes

Wonderful set of guidelines - thank you. I'm still more than open to any new suggestions, of course.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.