Hi Milan, glad you posted this. Have added something new to my knowledge base. Will ensure I follow through the series. Hope it's going to be in its own playlist 😊 Thanks a million.
Thank you. Milan I've been using C# for a long time, but I've rarely utilized unit testing, so it's something I'm still pretty low on, but after taking the course, I've gained a lot of confidence in it.
@@MilanJovanovicTech But when would you do this? In this case you call it on example.Create(), but you do not necessarirly have a domain entity in delete. Would you call it in a service layer?
Thank you for once again a very good and pedagogic video. I like them all. I have a different situation. We have an old, quite large, database. And I want to refactor the systems around it. My approach is to add a database model (classes reflecting the database who are created by scaffolding), in the infrastructure project together with mappings to and from the new domain model I want to build. I know that it's not optimal adding another DTO layer which also adds complexity. But I don't know what else I could do. A mapping from the database (with Fluent API) to the domain model will be quite complicated (because the db model and the domain model will be so different) and I'm not sure if it's possible to do. Do you have an opinion how to implement a (DDD) domain model for an existing database or another approach to my problem? I must also mention that the primary keys are not GUIDs, they are integers and many times identity columns.
Your approach is fine. The cost is added complexity and more code to maintain. But as long as you have a clear mapping from DB model to Domain model (and vice-versa) - you're on the right track.
@@MilanJovanovicTech 👍Thank you Milan. That was good to hear from an external person 😊 I'm trying to use Mapperly for the mapping part. But it's hard to use with value objects. I can't get it to work... I haven't seen any video or found any webpage explaining how that is done. I'll continue checking your great videos and get good ideas from you. Thanks again for the job your doing!
I am new to DDD, modular monoliths, and designing microservices. Are the modules in your monolith the same as what should be it's own microservice? IE, we have an excercise and a workout module, so would we have an excercise and workout microservice if we were to use microservices?
can domain modeling to do something like this in clean architecture? data class DevByteVideo(val title: String, val description: String, val url: String, val updated: String, val thumbnail: String) { val shortDescription: String get() = description.smartTruncate(200) }
Nice video. Thank you! I have a question: is ok to send that domain event just for instantiating the User entity? What should be the case when User entity is creating a object just because a query from UserRepository? You're not creating a User itself, just instantiating the entity. Thanks!
@@MilanJovanovicTech But every time? Imagine that you need to send a welcome email to the user when is created in the system. In that case is perfect. But, imagine that you query that user from database to make login, for example, that domain event will be raised too and the welcome email will be sent. In this case is not so good.
The point of ddd is in the effort to align software development (technical) with your users' business cases (domain). You are building a bridge between the developers and the users, creating better communication and collaboration. The first step to achieve this is to identify the "domain" of your user business. What is the entities that will be in the business? What can you do with them? It's necessary to use the proper term, according to your users, of your entity classes. Because keeping the domain knowledge is important in DDD, we have to build a whole structure of projects that builds around those entities. DDD shines if you have expert users and many developers with knowledge gap between them.
@@dputra interesting, thanks for that reply. So I'm guessing it's really good for when a company outsources it's development and helps the developers understand what they're trying to do better?
@@phennexion It's even impossible for the internal IT team to know exactly the business needs. Softwaremill wrote a good article about DDD. Just google it! 😁
It is not true when you say "Name cannot be null" for the static factory method on User just because the parameter type is not marked as nullable. The consumer can explicitly call User.Create(null), ignoring any warnings and the intent of the method. This is exactly the scenario where you *do* want a guard clause. Conversely, the nullability of the value parameter of the Name record should *not* be nullable since you have a guard that will throw if the consumer does pass null.
@@MilanJovanovicTech Sorry Milan, I didn't understand your reply. Trying to clarify my own comment: In your video, you have a nullable reference type, and guard against it being null. You also have a non-nullable reference type but don't guard against that being null. You state that the Name value passed to the factory method cannot be null - it can. It's not a struct.
@@petewarner1077 Conceptually, yes - it can be null. But in any normal execution flow it will never be null. And I'm saying you can guard against this with nullable reference types + code analyzers. You can turn "treat warnings as errors" and the build will never pass if you're trying to pass null for a non-nullable value. Does that make sense?
4:11 I don't get it. You've created a public ctor in which you're accepting a nullable string argument BUT you're immediately throwing an exception if a 'null' is passed. Why did you make the argument nullable then? You need to do it ONLY if 'null' IS a valid value for the parameter. Otherwise you should explicitly declare that you expect non-null value and to throw an exception if you get 'null'.
Why in Name record we are use nullable type in constructor? If I want to create an instance of the Name record then i'll expect that i can pass NULL to Name record, because it accept a nullable type and VS studio don't show me, that i wrong, because constructor accept nullable string but in runtime i get exception
@@MilanJovanovicTech do I understand correctly that in this way we lose the possibility of hints from the IDE and get an error (warning) not at the compilation stage, but in runtime? What is the advantage of this approach?
Great video, Milan, does You consider making video about how to deploy app into production? This would be great supplementation of your Clean Architecture course. Without any doubt, i would like to see how You deploy your built on docker app into production using for ex. Azure.
That's an awesome suggestion! I have a CI video coming out soon, but I'll work on a deployment one afterwards. In the meantime, there's this: ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-QP0pi7xe24s.html
I love the strongly-typed properties like the user's name in this video. But I have difficulty setting up the persistence of entities for such properties. I know I've seen it done in one of your videos but it requires a full control on the context, which is something I didn't have in one project where it was database-first and the scaffolding was configuring the context. I think the persistence of strongly-typed ids/properties would deserve a video of its own, considering the different ORMs or approaches.
What are your thoughts on passing primitive types in the static factory methods instead of Value Object types? I find that I'm cluttering and needing to check lots of results in my use cases before I can actually create the entity / aggregate root. Instead I move the logic of creating value objects to the entity and can combine the results using your railway oriented implementation.
I like to assume that everything has been checked by the time I hit my domain entities. But I'm totally not against your approach. I can see how it simplifies the use cases, and moves more of the responsibility to the domain.
@@MilanJovanovicTech After using this for a while and testing with a profiler I noticed that for my usecases I recreate the strongly type id value objects a lot by using this approach. Which caused some performance hits. I refactored to use your approach instead.
Hi Milan, I really like this video. Can you also do a video when an aggregate user owns an entity and in the infrastructure layer identityuser is used to handle authentication/authorization?