Search code examples
rustarchitectureclean-architecture

What are some idiomatic ways to create “dependency inversion” in rust?


I’m looking to create “dependency inversion” in rust (as described in Robert C. Martin‘s Clean Architecture).

I’ve been trying to implement this in my rust projects: Being able to write code thats dependent on the modules that it makes up, rather than vise-versa. (I don't need any actual runtime polymorphism, hence rust.)

What would be some clean ways to implement such a system? Thanks for the help.

My solution to the problem has been to use traits and trait bound generics to act as interfaces.

ie:

struct Car<W: WheelsTrait, S: SeatTrait>{
wheels: [W;4],
seat: S,
}

But this led to generics spreading and building up in higher level modules. Not to mention that trait bounds were cluttering my impls.

I’ve tried some other, increasingly un-idiomatic, methods: like having a type aliases for each struct with the generics removed.


Solution

  • If you want to implement DI with generics, then the generics will spread all throughout the codebase. Furthermore, I am not sure you will even get all the benefits of DI with generics.

    What you want is runtime polymorphism. That is, dynamic dipatch.

    struct Car {
      wheels: [Box<dyn Wheel>; 4],
      seat: Box<dyn Seat>,
    }
    

    With this, you no longer have to deal with generics spreading. But if you do this for all your types, you might as well use Java. At least that runtime is optimised for massive dynamicism.

    Instead, in Rust, what you would do is that you would define domain boundaries. Components that really do make sense to switch around. Structs that make big decisions: which database to use, which output format to use, how to read input. In other words, decisions that affect how your program will interact with the rest of the world.

    For other things, you will probably use DI to mock the internal parts. The solution to that is, use feature-flags, or just, don't. Test your structs end to end, switching out only the boundaries when in different environments.