You're taking a dependency on Diesel - an infrastructure-level library - in your domain layer. That defeats the point of separating domain and infrastructure.
Excellent, I am currently using DDD with Rust, but I have a question at minute 6:45, you call in the Queryable and Serializable domain. In that case wouldn't you be contaminating the domain with the infrastructure?
Thanks for the feedback, Actually, there is no definitive right or wrong way when it comes to models in Domain-Driven Design (DDD). My approach is as follows: Use domain objects directly for GET requests when they match your data needs, as this simplifies your design and maintains consistency across your application. This approach is particularly effective for read-heavy operations, where performance benefits from avoiding unnecessary transformations and keeping the codebase straightforward.
I wonder if it is okay on 12:30 to rigidly define dependency on UserService in `fn new()` of a UseCase. How would you mock it in tests? EDIT: also, how would you architecturally approach changing something in user, or implementing some user-related logic? Like, editing an email with confirmation, which makes user's email take two separate states: - Confirmed(emailAddress: String); - and Unconfirmed(perviouslyConfirmedAddress: Option, newUnconfirmedAddress: String, confirmationToken: String). And then sending a message to the users's confirmed email.
If you need to mock user service just turn it into a trait or use some lib for it, not a big deal. You don't need to overly complicate things for the sake of "I can need it".
Why didn't you create a trait for Service and just create an implementation for that? "#[async_trait] pub trait UserService { async fn register(&self, new_user: &NewUser) -> Result; async fn find_by_email(&self, email: String) -> Option; }"
Surely, I will create a video on the job market. As far as frameworks go, Axum, Actix, and Rocket are all easy and straightforward to use. Each has its strengths that i will discuss in an upcoming video.
Thanks for the video! It turns out that the trait of the UserRepository, which is located at the domain layer, depends on the newUser structure, which is declared at the presentation layer? Doesn't this violate the order of dependencies in a clean architecture? 🤔
Thanks for the feedback! Yes, by definition, you're correct. However, when following patterns, there isn't always a one-size-fits-all approach. The best method is whatever works best for your specific situation. While introducing mappers and DTOs adheres to clean architecture principles, it also comes with additional maintenance costs. For straightforward use cases like this one, where the models are simple and relational fetching is minimal, it might be more practical to use domain objects directly.
Great job. A detail that he has forgotten. You use diesel and not diesel async for this reason it is recommended to wrap the database operations in a web::block. Example in the Actix documentation. web::block(move || { Obtaining a connection from the pool is also a potentially blocking operation. So, it should be called within the 'web::block' closure, as well. let mut conn = pool.get().expect("couldn't get db connection from pool"); insert_new_user(&mut conn, name) }) .wait? But this can mess up your repository. So we can use tokio::task::spawn_blocking. Good job.
Do you have a GitHub link to the source code for this?
2 หลายเดือนก่อน +1
This is not pure architecture at all. So many code smells. No workspaces are used, no isolation, primitive obsession, domain infested with infrastructure stuff, etc. Yes, there are some parts of DDD, but you can't call it "Clean Architecture" if there's almost none of it. Content quality can also be discussed. You only say what you write, but we see it. Let's read that. There are no explanations as to why this or that. Almost useless. And hey, take it as constructive criticism. We all need to learn.
Thank you for your feedback, Also you cannot judge someones content on a single video. This is one of the first on my channel. Try check all of the latest videos. Architectures, Designs are for us we are not for it. So try use per ur case! Peace
2 หลายเดือนก่อน
@@Semicolon10 That's fair. I will definitely check out more videos.
You're taking a dependency on Diesel - an infrastructure-level library - in your domain layer. That defeats the point of separating domain and infrastructure.
Domain should be clean and the innermost layer free from all dependencies.
You don't need to be an extreme purist to make things.
that was great, would love to see you do a second with testing and/or error handling.
+1 for testing and domain-level errors (use enums for that to make it bulletproof?)
Excellent, I am currently using DDD with Rust, but I have a question at minute 6:45, you call in the Queryable and Serializable domain. In that case wouldn't you be contaminating the domain with the infrastructure?
Thanks for the feedback, Actually, there is no definitive right or wrong way when it comes to models in Domain-Driven Design (DDD). My approach is as follows:
Use domain objects directly for GET requests when they match your data needs, as this simplifies your design and maintains consistency across your application. This approach is particularly effective for read-heavy operations, where performance benefits from avoiding unnecessary transformations and keeping the codebase straightforward.
@@Semicolon10 of course, thank you
I wonder if it is okay on 12:30 to rigidly define dependency on UserService in `fn new()` of a UseCase. How would you mock it in tests?
EDIT: also, how would you architecturally approach changing something in user, or implementing some user-related logic? Like, editing an email with confirmation, which makes user's email take two separate states:
- Confirmed(emailAddress: String);
- and Unconfirmed(perviouslyConfirmedAddress: Option, newUnconfirmedAddress: String, confirmationToken: String).
And then sending a message to the users's confirmed email.
If you need to mock user service just turn it into a trait or use some lib for it, not a big deal. You don't need to overly complicate things for the sake of "I can need it".
Great Video, could you continue with next videos on this content, jwt authen for example?
@@letoan285 Thats the plan.
Why didn't you create a trait for Service and just create an implementation for that?
"#[async_trait]
pub trait UserService {
async fn register(&self, new_user: &NewUser) -> Result;
async fn find_by_email(&self, email: String) -> Option;
}"
Hi can you please talk about rust job market as backend developer. Which framework is mostly in used is it axum,actix or rocket?
Surely, I will create a video on the job market. As far as frameworks go, Axum, Actix, and Rocket are all easy and straightforward to use. Each has its strengths that i will discuss in an upcoming video.
Thanks for the video! It turns out that the trait of the UserRepository, which is located at the domain layer, depends on the newUser structure, which is declared at the presentation layer? Doesn't this violate the order of dependencies in a clean architecture? 🤔
Thanks for the feedback! Yes, by definition, you're correct. However, when following patterns, there isn't always a one-size-fits-all approach. The best method is whatever works best for your specific situation. While introducing mappers and DTOs adheres to clean architecture principles, it also comes with additional maintenance costs. For straightforward use cases like this one, where the models are simple and relational fetching is minimal, it might be more practical to use domain objects directly.
Great Video
Great job. A detail that he has forgotten. You use diesel and not diesel async for this reason it is recommended to wrap the database operations in a web::block. Example in the Actix documentation.
web::block(move || {
Obtaining a connection from the pool is also a potentially blocking operation.
So, it should be called within the 'web::block' closure, as well.
let mut conn = pool.get().expect("couldn't get db connection from pool");
insert_new_user(&mut conn, name)
})
.wait?
But this can mess up your repository. So we can use tokio::task::spawn_blocking.
Good job.
Do you have a GitHub link to the source code for this?
This is not pure architecture at all. So many code smells. No workspaces are used, no isolation, primitive obsession, domain infested with infrastructure stuff, etc. Yes, there are some parts of DDD, but you can't call it "Clean Architecture" if there's almost none of it. Content quality can also be discussed. You only say what you write, but we see it. Let's read that. There are no explanations as to why this or that. Almost useless. And hey, take it as constructive criticism. We all need to learn.
Thank you for your feedback, Also you cannot judge someones content on a single video. This is one of the first on my channel. Try check all of the latest videos. Architectures, Designs are for us we are not for it. So try use per ur case! Peace
@@Semicolon10 That's fair. I will definitely check out more videos.
Omg so much boilerplate and repetition.