Rust Hexagonal Architecture

trait IMongoRepo {
    fn get_user_by_id(&self);
}

trait IKafkaRepo {
    fn publish(&self);
}

struct MongoRepo;
struct KafkaRepo;

impl KafkaRepo {
    pub fn new() -> Self {
        Self
    }
}

impl IKafkaRepo for KafkaRepo {
    fn publish(&self) {
        println!("[KafkaRepo] publish data.");
    }
}

impl MongoRepo {
    pub fn new() -> Self {
        Self
    }
}

impl IMongoRepo for MongoRepo {
    fn get_user_by_id(&self) {
        println!("[MongoRepo] GetUserById.");
    }
}

trait IUserService {
    fn get_user_by_id(&self);
    fn user_publish(&self);
}

struct UserService {
    mongo_repo: Box<dyn IMongoRepo>,
    kafka_repo: Box<dyn IKafkaRepo>,
}

impl UserService {
    pub fn new(mongo_repo: Box<dyn IMongoRepo>, kafka_repo: Box<dyn IKafkaRepo>) -> Self {
        Self {
            mongo_repo: mongo_repo,
            kafka_repo: kafka_repo,
        }
    }
}

impl IUserService for UserService {
    fn get_user_by_id(&self) {
        println!("[UserService] getUserById.");
        self.mongo_repo.get_user_by_id();
    }

    fn user_publish(&self) {
        self.kafka_repo.publish();
    }
}

fn main() {
    let mongo_repo: Box<dyn IMongoRepo> = Box::new(MongoRepo::new());
    let kafka_repo: Box<dyn IKafkaRepo> = Box::new(KafkaRepo::new());
    let user_service = UserService::new(mongo_repo, kafka_repo);
    user_service.get_user_by_id();
    user_service.user_publish();
}

(Playground)

Why use trait objects instead of concrete types? Why use traits in your example at all? I.e. you might as well could implement the methods of IMongoRepo directly on MongoRepo.

4 Likes

What's the question?

3 Likes

I want to implement a hexagonal architecture please review my example code

That's a term of art with which I'm not familiar. Can you either describe what that is or provide a reference so that we can understand what you're trying to do?

Also, this code is obviously unfinished as it doesn't actually communicate with either MongoDB or Kafka yet. This makes it extremely hard to critique without more context regarding which parts of it you consider complete and which parts you still intend to change.

3 Likes

Hexagonal architecture is basically a high-level design pattern for developing applications/services. The main abstraction is that you have a core part that implements your business logic, surrounded by adapters. These adapters are stuff like your database connection, your HTTP API, a UI, connection to a message broker, etc., basically all the different components of your system you use to get the data from the core out into the world. It is a design pattern that facilitates loose coupling and has become quite popular for developing services in a microservice application.

1 Like

After scanning that page, I have a few random thoughts:

  • Is this implementation supposed to be for a single service, or a simulation of running multiple connected services?
  • What ports and external services are planned, and what sort of protocols will they use? That seems like something to get sorted out before diving into the code.
  • I assume that the traits are supposed to represent the port interfaces. If so, they seem to be named too specifically: Instead of IMongoRepo, name it for the type of data that's stored there in case you elect to change storage technologies later.
  • It's unclear how the overall control flow is supposed to work. At the moment, it looks like a process-per-request model, which works but may not be the best choice these days.
  • Do you intend to block execution waiting for external responses, or use some kind of async mechanism to work on other requests while one is waiting for a reply?
  • What's your strategy for dealing with failures of external services? Panic, retry with backoff, etc...
    • Be particularly careful with state-changing requests; how do you intend to prevent accidentally double-publishing, for example, if you send a publish request out but a communication error happens during the confirmation?
3 Likes

Yet another self proclaimed software engineering guru comes up with a funky name for whatever he is pitching in his next books or training sessions.

Hmm... but this one is old school, from 20 years ago. And it was how we designed software back in the early 1980's. Sounds like how the Linux kernel is built, core in the middle, all manner of drivers (adapters) around the outside.

From the link "This approach is an alternative to the traditional layered architecture.". Ignoring the fact that it is the traditional "layered architecture" just drawn around a hexagon rather than horizontal lines.

On the other hand it seemed to be an early example of pushing back against OOP. Can't be all bad :slight_smile: