Get the source code for this video for FREE → the-dotnet-weekly.ck.page/domain-validation Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@Milan, how to check validation rule with dependencies? For example I need to check an email is unique of user in DB. User is aggregate model. Do I need to check this validation rule in the handler?
Great video! Your content is excellent and well structured. I usually use the result approach because it enforces explicit error handling and thus addresses the double-edged nature of exceptions in .NET - they are easy to ignore or overseen and can lead to unexpected problems later. In my experience, result types are great for domain rules and exceptions are great for problems beyond my control, such as network errors, authentication errors, external libraries, etc.
Thank you for the great videos on these important topics! I really appreciate your clear and concise style. I tend to agree that the Result method makes the code more readable and performant. Could you not use the [CallerLineNumber] and [CallerMemberName] attributes from System.Runtime.CompilerServices in the base Result class to capture the method name and line number where the error is thrown?
Wow, this is brilliant! I wasn't aware this even existed. I'm definitely making a video about this. I'm going to give you full credits for the idea, is that alright? 😁
I have recently found this series and it has been helping immensely with a new learning project im undertaking. One thing i would like to add (and hopefully get a response) is this: With the exceptions approach, code flows naturally better because you dont have to check at every turn if you got bad results or not. The handler in this video would only have to deal with the happy path, making it smaller and improve readability. Since we also typically centralize the exception handling via filters/etc we dont have to keep bubbling errors (im the video Milan is logging the error, but one could want to pass that info up, or create another error result and pass that up so that the controller up top can show it to the user) Maybe im too set in my ways, but i havent seen an example that centralizes error handling as cleanly as its possible with exceptions, but using results. Here is a wish @MilanJovanovicTech would revisit this because youre the one guy i trust to teach me the ways of DDD
I really like this Reault pattern approach Milan, it is more readable and easy to understand. I will use this approach in my future project. Thanks for this!
Commented separately. IMO almost NO added value, with a risk of having unhandled results and side-effects and almost no visible performance gain! At least if you consider the problem as a whole, and not just a partial part of it (back-end only).
Excellent video, thanks. For those concerned about stack trace, I think it doesn't make sense if they are domain validations and not unhandled exceptions. For the latter, there are still exceptions where there is a context of the unexpected error
You channel it's the best that I'm find in 2022 about programming. Tks for a lot of Golden Tips. I know this 2 aproachs and I really preffer throw exception. I do believe when used with small domains and tiny projects, the performance its not big deal. A lot of hugs from Brazil ;)
I like the Result pattern and creating an Error class was a nice touch. And I really like the Static DomainError class. I’ll be thinking about using these techniques in future projects.
I got a suggestion for how to improve logging with the Result class in case of failures, so I will cover it in a future video. Turns out it can be pretty close to exceptions in terms of stack trace and debuggability.
Have you done that "I got a suggestion for how to improve logging with the Result class in case of failures, so I will cover it in a future video. Turns out it can be pretty close to exceptions in terms of stack trace and debuggability." If so, in which video?
Hi Milan, thank you for the content. Well i would like to know where and how did you defined the « Create () » method in ResultT class. The last line of code of that class uses it to return a value from a Result. Thank you for your help
Great series of videos, keep up the good work. Small suggestion it will be fair to mention the authors and their blogs and github repositories from where the concepts and code is borought (Vladimir Khorikov enterpisecraftsnamnship and CSharpFunctionalExtensions for Error, Result and Failure classes and also Jason Taylor and his Clean architecture template).
It's kind of a combinatio of using the idea, and evolving it into your own. But I understand what you're saying, I will see to introduce something from the next video!
I have been throwing exceptions, at domain level and at the application level which I plug in to the middleware for nice formatted errors (400, 403, 404, 500, etc.). Thanks for this awesome content, might have to consider the Result object or the ErrorOr library. Still waiting for a video on how to handle domain events
Nice video, most of the time i use nugets like "throw" and "error-or" (Amichai Mantinband) or "result" and "gauard clauses"(steve smith/ardalis ). But the benefit of your documented domain errors is good to know. For your first solution, i highly recommend, that your domain (custom)exceptions should be serializable.
For these small little classes like these, I usually prefer rolling my own implementation. I find that the added flexibility is well worth it. Making the exceptions serializable is a great suggestion!
Thank you for amazing videos, just found your channel really excited. Would be glad if you name the series videos by order as well like 1, 2, 3 as part of the names.
The core idea of exceptions is that you are FORCED to handle the error OR that the error will automatically propagate up the whole call stack until some code can handle it in meaningful way. With the return Result that can become an issue. Depending on how that ResultT class is implemented one could ignore the result status and access the Value (haven't seen that code - but that should be secured by an exception if the result is a Failure). That Result wrapper is definitely much better as returning a boolean or some magic value (like -1). An alternative is to follow the Try... pattern like bool int.TryParse(string s, out int result). Here it is obvious that the result can signal failure and should be evaluated. I'll give that ResultT approach a try...
Yeah, accessing Value on a failure result throws an exception. I agree it's a different paradigm entirely, and that there are ways to go around checking the Result. But I like that it's more explicit than exceptions. You know that the method returns a Result which can either be a success or failure. With exceptions, you need to be aware of the implementation details of the method you are calling, to know what to expect and handle it appropriately.
A really pure implementation of this pattern only exposes the inner value in a single method called "Match", where you pass in two funcs, one that handles the "Value" case, and one that handles the Error case. With this design, the caller has no choice but to handle both cases. So something like this: return Result.From("myString", failIf: s => s is null) .Map(NextOperation) .Map(NextOperation) .Match(val => val, err => "Error");
You could attach the Stack Trace if you want. But I don't think that is what result types are for. They are for rules and validation. Thus predictable through business logic. An exception occur as an exception at code or system-level: like null references, stack overflow, or IO exceptions. You need to handle them both though.
Handling of errors/exceptions - I completely agree with you on this, Marina. But do we need to raise exceptions for what is essentially expected behavior? I feel like people misuse exceptions sometimes.
@@MilanJovanovicTech Yes. And perhaps that should be the point: Developers should not throw their own exceptions. Just return result objects instead. Thank you for this video! This got me thinking. In fact, this is related to a problem that I’m tackling know at work. Returning error messages. So I did pretty much what you did. Created a Result class. Standardized the errors. Btw. I have already experimented with a Result class that act like a discriminated union. More like Rust. But lack of language support makes the syntax a bit more cumbersome. It is on my GitHub.
Fully agree. The happy trade-off, IMO, is definitely to use the result types cleanly, like presented - but to log stack traces. It is the best of both worlds, and allows for that level of detail for debugging purposes, but can be disabled in a non-development environment, too, if desired.
I like your approach more than using 3rd party to do this, ie fluent assertions, etc, because respect POCO. Also, throwing exceptions it's not too bad, if you handle it 👍
@@elpe21 Fluent Validation is great at validating an entire object. It might not work so well to validate individual parameters passed into a method on an aggregate. Also, I'd caution against adding too many dependencies to your domain layer. This should be kept as simple as possible.
That's a greath video! thanks for you teaching us. I have a question. In the Result class, where the Create(value) method came from? Line 15 Result(TValue? value) => Create(value);
Another great video Milan. This one really piqued my interest. I can see the benefits of using a Results object (especially if you can automatically capture the stack trace as suggested by others). However, I prefer using guard clauses to throw exceptions. They allow me to very quickly add validation to a method in a minimal way. For example: DomainException.ThrowIfEmpty(email); DomainException.ThrowIfEmpty(firstName); DomainException.ThrowIfEmpty(lastName); Using a Results object, requires you to sprinkle error handling throughout your application. Using exceptions on the other hand, allows centralized capturing of errors which is great for applications that expose APIs.
Of course, it's a tradeoff. Most people are very familiar with throwing exceptions. Using Result objects is outside of the comfort zone. That being said, I like how with result objects writing tests is super easy. Also, it's explicit that the method can fail and you should handle the failure case.
@@MilanJovanovicTechits also important to note that exceptions are for when something is unexpected. If you guard against a certain condition but you expect it to be able to occur then its not exceptional and an exception should not be used.
I believe the result-based approach could fully replace exceptions if only there was a language-level syntax which allowed result objects to be passed up to the caller, similar to how exceptions bubble up. That way, you can have a clean syntax like when using exceptions, and leave the error handling to some global handler, or handle the result object directly. Rust does this with the ? operator, but I wouldn't use rust even if my life depends on it so I hope we get better language support for result objects lol
I prefer the result template approach. usually I add a middleware to convert exceptions to a result template to enhance the api behavior. I would suggest defining the Result as a struct to avoid returning a null result, sometimes beginners do that which doesn't make sense.
1- Returning result from aggregate, value object or component needs failure check for each single invoker. It could be N times, so it is very sad. Most of my domain methods are using builder pattern, it is hard to use with that. It is sufficient to check once in any layer when throwing an exception. I think it is the most definitive option you need to decide with that. 2- Stack trace is a big deal when tracing an error. 3- There is not much performance loss for a single entity process. But, when you do batch operations or processing array typed nested value objects in aggregate it may hurt a bit. For that, we can process them concurrently. Of course, this creates some complexity. Finally; of course it is a tradeoff. I am bit closer with throwing an exception, I think it is more manageable.
Exceptions are also problematic if you have many API requests. What about explicitness with Result return value? You know what to expect. With exceptions this is implicit.
Thank you for your great job. I'm learning a lot of new things and concepts. I would like to know if throw exceptions in validation domain is really a good practice ?
@@MilanJovanovicTech in your video, Error is class inheriting from IEquatable but the link above contains record. Which one you use as standard for your projects?
Great videos, learned a lot. Would be nice to also have a link to code, as for the Error class example, we never get to see the complete code.. same with other implementations in this series
Hi there, I'm enjoying another great video! I have a question about FluentValidation usage in a DDD + Clean Architecture approach. In our projects, we've been using FluentValidation extensively for data validation. However, under the Clean Architecture principle, the domain should not have external dependencies. This raises the question of where to place our AbstractValidator implementations? Should we create a dependency to the FluentValidation library? In out case, All Repositories and Domain Services interfaces are within the domain project and Some of our validation rules are quite complex and rely on database checks! Could you provide some guidance about these questions?
@@MilanJovanovicTech Hi, it's ok I made the subscription thank you. can you make a video on Entity Validation by implementing the specification model and the notification model. Thanks very much
Awesome video reminds me on ErrorOr library, looks like your friend (don't remember his name) was inspired by this approach. Performance all the way, I like that self documenting part. Testing it's still easy. Awesome video thanks!
We may or may not have chatted about it at some point :) My favorite part is when writing tests result.Error.Should().Be(DomainErrors.Gathering.AlreadyPassed); Easy to write, easy to read also.
Hi Milan. Thanks for the video. Should we use here FluentValidation? if yes, then how? sometimes I need to inject an external source to provide validation.
Hello Milan First I would like to thank you for your great efforts, second I would ask you to make this solution a public repo on github, please? Thanks 😄
Mlian thanks for the video. I prefer to use functional programing approach to handle validation in particular using either monad with methods match/bind/map, please share your opinion on that approach?
I love that approach, Boris! I also use it on some projects, where I write everything in functional fashion (Map/Bind/Tap/Match, etc.). I definitely want to cover this in some of the future videos.
Like the series! Great ONE! But, didn't like the way when the exception vs result objects were compared in code, as in the case of exceptions the strings were not extracted and were done in a different style. IMO all the benefits of a result (except the performance) can be achieved with custom exceptions, they can be self-documenting as well + they have stack-trace, which is better than logs. Reg. logs even Udi Dahan has his own view, which he uses to promote message-based systems (really easier to spot errors based on failed message counts). The costs of exceptions are something we should not care much, as in most cases, every external input should be validated on the client side as well (at least to a possible level) and thus exceptions inside the back end should be fairly rare. I have an extended extension (interface and static methods) to set ErrorCode, ErrorMessage and have a Result-like object with the exception. But if we want to have that self-documenting part, it's custom exceptions stored on one place, with pre-set messages is the way to go!
Great video Milan! I am little confused while trying to figure out which status code to return and how to know this. For example result can be a Success or Failure this is ok but how do you know it is a 401, 404 or 500 error? Or if it is a success it can be a 200 or 204 etc. Am I supposed to check that in Controller level or just add a StatusCode property to the Result object?
@@MilanJovanovicTech Thanks for the answer. I know what the status codes are. I think I couldn't explain pretty well. I was talking about what is the point of seperating Success and Failure? You mentioned that you can match the ErrorTypes with 404, 400 and so on. But what if there is no error? A service can return Success but controller needs to know either if it is a 200 or 204. But there is no such a information in the Result object. How do you handle that?
Great Video Milan :) ... Well, if you are using Domain Events with Eventual Consistency, the Exception Approach is need to rollback any changes of the transaction, right? Or do you have a different approach for this kind of situation with the Result workflow too? :)
@@MilanJovanovicTech thanks very much for your response :) ... I currently had a transaction opened per request and did a rollback if an exception occured (was implemented in middleware or ActionFilterAttribute)... thats why I was wondering how to do this with the Result Approach :)
Doubt. I saw in some part of ur code, return Unit.Value when the result fails. How do u know that fails outside to return it for cliente-side for example, because u are awalys returning "void"? I usually used throw new SpecificExpcetion and take it on controller returning the right status code.
I would add that you can clean it up a bit more too by adding a second generic to your result type for errors. Then have your errors derive from gathering errors and have your gathering errors derive from error. Then in your function declaration you use Result as the return type. You add an implicit conversion in result for the second generic and then you directly return the error. Instead of returning Result(error type). I also tend to just return exceptions instead of creating a new error type as it saves a bit of time and the caller can throw it if they want and to do so you can add a ThrowIfErrant method to result and chain it on the call. I.e GetInvitation().ThrowIfErrant().
How is a second generic helpful? I think it's constraining, if anything. And I don't like the idea of having inheritance with Errors. I much prefer composition of some sort.
@@MilanJovanovicTech the second generic let’s you specify the type errors in the declaration. When calling the method an IDE will show you the return type on hover or as you’re typing which includes the errors as the second generic. Then the caller can easily see what type of errors need to be handled. Similarly if you’re calling through an interface you can still see the types of errors whereas otherwise you just have to hope the comments are accurate. (Even the exceptions listed in the core libraries comments are not super helpful as they only apply to older versions sometimes A great example is anything in Path or Directory classes. None of those throw exceptions in .NET 7 but their doc tags state they do. If you read the online docs they say are restricted to older versions). As far as inheritance goes, it’s not strictly necessary if you’re really against it, but personally I find it makes sense here similar to way all exceptions derive from exception. It lets you group your errors by type. So you can use GatheringErrors as a superclass. This is in the direction of how newer languages like rust do error handling. They force you to declare all of your errors and the force the caller to handle all of them. While this doesn’t go that far it does give increased visibility which can allow you to do it a bit closer to that model. Rust actually uses a Result with a generic for the return type and error type:
Have you seen/What are your opinions of the ErrorOr package by Amichai? It seems to implement your Result Object pretty cleanly, including enumeration of errors, and some handy matching methods. Great video, love the pacing and objective pros/cons of each solution
Thanks for creating this series of videos. One question about structuring the solution: In your Gatherly solution you have a few entities, and your project structure seems to be fine. What's your suggestion on structuring large solutions (using Clean Architecture) with something like 50 entities. I can think of having sub-folders or having multiple domain projects for each boundary? I like to hear your opinion.
I would say grouping by feature would be the go-to approach. Identify which entities go together, and then group them inside a feature folder. I'm actually releasing a video about that (well, sort of about that) on Tuesday next week.
Is it possible to find somewhere code that you have written? You explained those conceps really clear in opposite to the all "mentors" that tried to do it :)
Hey Mateusz, I'm sharing the code with my Patreons. However, you should be able to find something similar on GitHub profile in the projects that are public
Milan, what do you think of the following alternative: creating a Manager class for each entity, where this class would be located within the domain layer and handle the corresponding validations (instead of having validations inside the entity). The entity would have internal access methods (for example, "internal void ChangeText(string text)"). This way, the business layer would be required to use the manager class to make changes to the entity, and the manager class would be able to access the entity's internal methods. This way, the Aggregate Roots, Entities, and Value Objects would remain clean, with minimal code, internal methods, and properties with private setters. Additionally, this method has the advantage that you can use the Manager with dependency injection and use IStringLocalizer to translate messages, or invoke encapsulated business rules with dependency injection as well.
Thanks for the great video. I'm using ErrorOr library created by Amichai. May be you can publish your Result code as nuget package and we can explore in our projects.
There is already a great package from Vladimir Khorikov - CSharpFunctionalExtensions. This is where I got the idea from. But I will consider if I have something unique enough to make it my own package.
I prefer to save stack trace everywhere because it's more common behavior which doesn't depends on languages, frameworks etc as I think. It's simple to debug. And it's more natural for understanding behavior of app by other developers. But maybe it's because I'm the old school engineer) Some languages using the result pattern as a box decision. To my mind, using the Result object is better when you have some complexitive logic depends on exception. You can't see it so often and It's not a good practice. For example If you have an external closed provider and you have to separate the logic depends on exception It's the better way to do it without throwing an exception in your app in source point.
I been using exception case, people are to afraid of throwing exception for some reason (if performance is really critical why use c# in the first place?). Just have exception with a global exception middleware to deal with them as you wish, for me is must clear than passing Result upper the call and deal with it in the controller/handler level.
Although I agree the performance impact most likely isn't going to be detrimental. I can't agree that throwing exceptions is clearer. With Result, you know through the entire call chain to expect a success/failure. With exceptions this is implicit.
@@MilanJovanovicTech What you meant? I mean for example in Person entity you have to check identity number by country when somebody try to create Person instance. Also you have IIdentityNumberValidator interface to check that.
Hey Milan, let's say I have Connection class, with m2m relationship to Employee class. I want to have this kind of logic: If Connection is "direct message", then it can't have more than 2 employees. I wanted to implement this logic in domain, and throw an exception. But I realized that if I dont load employees eagerly each time, the exception wont be thrown. I'm new to these topics, would it be true to say that this is not a domain level condition?
Thank you for your great videos. I have a question please, how do the Application and Presentation layers know about the Domain Validation? for example, in the Gathering validation Result object case, you logged the error in the domain layer, and you didn't return any clear message to the upper layer. Therefore, the upper layers, will not have a meaningful message to show to the end-user.
You are correct! I'm trying to build out this applicatiom very slowly and methodically, soon enough we will be connecting everything with the API and Database. And then it will all make sense, I promise!
@@MilanJovanovicTech That would be great. I will be waiting for upcoming videos. I am really excited about this series, thank you for your limitless efforts.
Dear @MilanJovanovicTech, I kindly request that you consider creating a well-organized playlist for beginners. This playlist would arrange code step by step, making it easier for newcomers to follow the sequence and find specific topics such as structure, MediatR, and Serilog within your videos. Your assistance in this matter would be greatly appreciated.
Do you really create separate exception classes for each error which might occur in your projects? I think this only makes sense if you later want to catch the different exception and handle those differently otherwise if all exceptions are handled in the same way, I don't see much benefit in having different exception types. Context information about this error can still be transported via the exception message or the "Data" property or you create one DomainException type which has custom properties.
Yes, I've head cases where there is a custom exception for every possible error. Nothing wrong with that approach. Another option, is as you said nicely, to have one custom exception and pass in different values when throwing it.
I've been watching you for 1 year, great videos you have! But as I'm seeing using result's pattern really making my code messy, for example I need +4 lines for everything because it returns result object and I need to check if it's succes and etc. On the other hand using exceptions really making code small and easy to read. I really like the result pattern so could you give us more info or tip&tricks how to not end up with long code?
Thank you so much. But if I have the same error result at different files, so any way to know where it happened? Just using log to trace the problem right?
Why would you have the same error in multiple files? Ideally these errors should be tightly coupled to a certain use case, and the more specific the better.
What approach do you use most in your projects? Exceptions or Results? Another question is, in your project do you make double validations (both in command/request object and domain objects) or just in domain models?
I usually use Results these days, since I find it more explicit. I rarely do double validation. But I make a difference between "Input validation" and "Domain validation"
Hi @@MilanJovanovicTech , I really like this approach but now I am confuse between Domain Validation and Request Command behaviour pipeline validation. Can you please explain both , please.
@Milan Jovanović You will have every possible exception for DDD in one place? Same as your second solution? Also, you can return a list of failures. For example, for Send Invitation, you can have two separate errors for one call (Send Invitation to Creator and Event in the Past). Btw what are you going to return for Value objects? You will get the result from the value object, and if that is not an error, you will continue? I am finding both approaches troublesome :| Have you tried to integrate Fluent Validation with DDD?
I always struggle to do domain validation because in theory de domain layer should have no dependencies whick means I cannot use validation frameworks or libraries like fluent validation. I saw some colegues doing domain validation in DTOs which I don't agree. What do you think about this?
I use FluentValidation for input validation, before I reach the Domain layer. i think what I'm showing in this video is more appropriate for the Domain layer.
I prefer the Result approach, BUT! ON AVERAGE, throwing exceptions might actually be more performant. Especially if you are the client of your own API. If the consumers of your service are not malicious, the happy path should be expected to happen A LOT more often than the exceptional path, in which case, the extra allocations of the Result objects will result in worse performance.
Hi! Milan. I'm just a junior dev trying to understand this advance topics. I have a cuestion. There are application validations and domain validations if I'm right?. But if i want to send all the domain errors in ones, how could I do that?. For example if i have a class with a lot of value objects. How could I send all the errors in ones instead of sending one by one? Like when you use the validation attributes from the .net library. To validate your porpeties And finally. It is a good practrice?send all the errors in ones? I hope you may help me and understand me. Thanks! An have a good day.
Technically, the input validation should already prevent you from sending bad data to the domain. The domain validation is there as a fail safe - and for guarding the business rules. You could do the validations in the domain, collect the errors in a list and return those. But how will you handle that on the client?
Another drawback of object results is that if your project has a multi-layer, you should wrap the error up to the API layer to show the proper error message to the user. Instead of using Unit.Value.
@@MilanJovanovicTech It's not a drawback, and it just needs more effort and writes more code if I want to be more precise, especially when using results for handling errors in other cases like HTTP calls and other things. Your logic section sees a lot of checking but throwing an exception cost performance but less code in some cases.
For me it depends on the logic. If there's a lot of logic and you are really deep, than it's much easier to throw the exception and handle it in ExceptionHandler. With Result pattern, in this case, you should handle this error in each method, before final one. And that's kind of messy.
You can use Railway Pattern to create concatenated methods that return the Result class. I can assure you that the code will look much simpler and easier to read. You can use libraries like ErrorOr that already come with this functionality
Nice video, but I think you skipped some downsides regarding the Result pattern. First of all it creates a huge overhead in your method interfaces, and even though you stated that it increases the expressiveness, I kinda think it's the opposite. The whole code becomes a convulted mess of "Result" objects being returned everywhere, just like what you'd get using a library like Vavr in the Java world. I don't think it add to the readability of the code at all. The other issue I see is that for the callee, it really makes no difference whether you need to try-catch a Checked Exception or check whether the Result object contains a result or an error. In most systems, this forces you to pass the consequence of "indesired path" (Exception or Result.Error) down the whole calling chain. That's why I often prefer using the Unchecked Exception with a global handler; for some apps it might make sense, but when you design an API, a global Exception Handler does the trick just fine and avoids the use to handle the errors/exceptions throughout all the layers.
And in addition performance isn't too bad with throwing exception. Nick Champsas did some performance tests recently and It's nearly 40% slower than with Result pattern in casses where you are throwing exceptions thousands times a second which is not regular situation. Usually your domain throws exceptions much rarely so in reality impact is much lower than 40%
What are the complete steps to create a computer program to mine 50,000 bitcoins every second and the withdrawal method is via paypal only There is no waiting for withdrawal and no minimum withdrawal
Not a huge fan of the first solution. Even though you have your stacktrace, the code flow can be really messy resulting in a bad debugging experience. But it's the easiest and most common so.. The second solution is great, however I don't find it very scalable and it's a pain to maintain. The static classes will grow endlessly and you would have to manage and divide them over and over again. Also, the errors are not very explicit, you have to follow the references bubble to see where each Error is triggered and why. That's what I found at least for my projects and worked with alternatives to counter that
@@MilanJovanovicTech I ended up with 2 alternatives depending on the project: - Integrating FluentValidations in my Domain project forcing my entities and events to link to a validator. The domain project should not be dependent from any library but i found that a good tradeoff compared to the benefits of doing this. Easy validation rules, fast debugging, scalable structure (you just add a validator with your new entity). You also have the control if you want to throw an exception on SOME scenarios. I would choose to validate and throw on rules that should never happen... - For other projects, I actually borrowed a concepts from F# and JS: Adding a delegate onError that forces the caller of each function to handle the unlikely scenarios. I think it's the same as your second solution with one single benefit, you can group these handles in a single reusable delegate which if you're not using MediatR or any Pipeline behavior is cumbersome. I wasn't using MediatR so that was it I assume you can do that with some reflection magic but laziness stopped me from exploring that ;)
Sorry Milan. From my point of view, you're not addressing Domain Validation directly in this video. It seems more focused on error management within domain layers. Another thing will be if you manage de condicionals "If" with fluent validation to create validation rules for this entity.
Get the source code for this video for FREE → the-dotnet-weekly.ck.page/domain-validation
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@Milan, how to check validation rule with dependencies? For example I need to check an email is unique of user in DB. User is aggregate model. Do I need to check this validation rule in the handler?
where is the repo?
Díky!
Děkuji mnohokrát (if google translate didn't butcher it 😅)
Great video! Your content is excellent and well structured. I usually use the result approach because it enforces explicit error handling and thus addresses the double-edged nature of exceptions in .NET - they are easy to ignore or overseen and can lead to unexpected problems later.
In my experience, result types are great for domain rules and exceptions are great for problems beyond my control, such as network errors, authentication errors, external libraries, etc.
Glad it was helpful!
Thank you for the great videos on these important topics! I really appreciate your clear and concise style. I tend to agree that the Result method makes the code more readable and performant. Could you not use the [CallerLineNumber] and [CallerMemberName] attributes from System.Runtime.CompilerServices in the base Result class to capture the method name and line number where the error is thrown?
Wow, this is brilliant! I wasn't aware this even existed. I'm definitely making a video about this. I'm going to give you full credits for the idea, is that alright? 😁
Yes, I would be honored. Thank you for the kind words.
Amazing comment ! Thank you.
This is awesome.. amazing idea @jkode!
@@MilanJovanovicTech Has this video already come out?
I have recently found this series and it has been helping immensely with a new learning project im undertaking. One thing i would like to add (and hopefully get a response) is this:
With the exceptions approach, code flows naturally better because you dont have to check at every turn if you got bad results or not. The handler in this video would only have to deal with the happy path, making it smaller and improve readability. Since we also typically centralize the exception handling via filters/etc we dont have to keep bubbling errors (im the video Milan is logging the error, but one could want to pass that info up, or create another error result and pass that up so that the controller up top can show it to the user)
Maybe im too set in my ways, but i havent seen an example that centralizes error handling as cleanly as its possible with exceptions, but using results. Here is a wish @MilanJovanovicTech would revisit this because youre the one guy i trust to teach me the ways of DDD
I'm working on a video about that today 😁
And one more is coming out this week to also address that
I really like this Reault pattern approach Milan, it is more readable and easy to understand. I will use this approach in my future project. Thanks for this!
Glad you liked it :)
Commented separately. IMO almost NO added value, with a risk of having unhandled results and side-effects and almost no visible performance gain! At least if you consider the problem as a whole, and not just a partial part of it (back-end only).
Excellent video, thanks. For those concerned about stack trace, I think it doesn't make sense if they are domain validations and not unhandled exceptions. For the latter, there are still exceptions where there is a context of the unexpected error
And worst case, you can include a stack trace yourself with Environment.StackTrace
You channel it's the best that I'm find in 2022 about programming.
Tks for a lot of Golden Tips.
I know this 2 aproachs and I really preffer throw exception. I do believe when used with small domains and tiny projects, the performance its not big deal.
A lot of hugs from Brazil ;)
Thank you very much! I have a lot of great content planned for 2023
I like the Result pattern and creating an Error class was a nice touch. And I really like the Static DomainError class. I’ll be thinking about using these techniques in future projects.
I got a suggestion for how to improve logging with the Result class in case of failures, so I will cover it in a future video.
Turns out it can be pretty close to exceptions in terms of stack trace and debuggability.
@@MilanJovanovicTech I am looking forward to checking that video out!
Have you done that "I got a suggestion for how to improve logging with the Result class in case of failures, so I will cover it in a future video. Turns out it can be pretty close to exceptions in terms of stack trace and debuggability."
If so, in which video?
Hi @@MilanJovanovicTech , is this your own created Result class or its from the Result package?
Hi Milan, thank you for the content. Well i would like to know where and how did you defined the « Create () » method in ResultT class. The last line of code of that class uses it to return a value from a Result.
Thank you for your help
gist.github.com/m-jovanovic/aa25b1ae424c985ff8ae696a79b6fe6e
Thanks a lot !
Great series of videos, keep up the good work. Small suggestion it will be fair to mention the authors and their blogs and github repositories from where the concepts and code is borought (Vladimir Khorikov enterpisecraftsnamnship and CSharpFunctionalExtensions for Error, Result and Failure classes and also Jason Taylor and his Clean architecture template).
It's kind of a combinatio of using the idea, and evolving it into your own. But I understand what you're saying, I will see to introduce something from the next video!
Totally agree. It would be great to keep all these examples in a public repository.
Thank you for letting me know Vladimir Khorikov 😄😊
I have been throwing exceptions, at domain level and at the application level which I plug in to the middleware for nice formatted errors (400, 403, 404, 500, etc.). Thanks for this awesome content, might have to consider the Result object or the ErrorOr library. Still waiting for a video on how to handle domain events
That's a great approach also. I'm using that on one of my projects.
I recorded the domain events video. It's dropping next week on Thursday 😁
Great video ! I personally use the ErrorOr library
It's a great alternative also.
Result objects. what a life saver.
Pretty clean code you end up with
Great approaches and like seeing the high level comparisons. We do a similar Results object in a few applications. Keep making great videos!
Thanks a lot Mike! I'm happy to hear of more people using Result object 😁
Nice video, most of the time i use nugets like "throw" and "error-or" (Amichai Mantinband) or "result" and "gauard clauses"(steve smith/ardalis ). But the benefit of your documented domain errors is good to know. For your first solution, i highly recommend, that your domain (custom)exceptions should be serializable.
For these small little classes like these, I usually prefer rolling my own implementation. I find that the added flexibility is well worth it.
Making the exceptions serializable is a great suggestion!
how can serialize an Exception?
Thank you for amazing videos, just found your channel really excited. Would be glad if you name the series videos by order as well like 1, 2, 3 as part of the names.
I add them to playlists, since most of these can be watched as standalone videos.
@@MilanJovanovicTech Maybe l am missing something but the playlist does not have this, it starts on the domain validation video.
@@100kshooter5 I re-ordered it now
But I didn't change the names
@@MilanJovanovicTech Thank you, amazing work.
Thanks for another excellent video Milan. You are the best!
Thanks a lot, buddy!
Great video Milan. I prefer Result Object approach.
Good choice!
The core idea of exceptions is that you are FORCED to handle the error OR that the error will automatically propagate up the whole call stack until some code can handle it in meaningful way. With the return Result that can become an issue. Depending on how that ResultT class is implemented one could ignore the result status and access the Value (haven't seen that code - but that should be secured by an exception if the result is a Failure). That Result wrapper is definitely much better as returning a boolean or some magic value (like -1). An alternative is to follow the Try... pattern like bool int.TryParse(string s, out int result). Here it is obvious that the result can signal failure and should be evaluated. I'll give that ResultT approach a try...
Yeah, accessing Value on a failure result throws an exception. I agree it's a different paradigm entirely, and that there are ways to go around checking the Result. But I like that it's more explicit than exceptions. You know that the method returns a Result which can either be a success or failure. With exceptions, you need to be aware of the implementation details of the method you are calling, to know what to expect and handle it appropriately.
A really pure implementation of this pattern only exposes the inner value in a single method called "Match", where you pass in two funcs, one that handles the "Value" case, and one that handles the Error case. With this design, the caller has no choice but to handle both cases. So something like this:
return Result.From("myString", failIf: s => s is null)
.Map(NextOperation)
.Map(NextOperation)
.Match(val => val, err => "Error");
Great job Milan 👍
Thanks a lot!
You could attach the Stack Trace if you want. But I don't think that is what result types are for. They are for rules and validation. Thus predictable through business logic. An exception occur as an exception at code or system-level: like null references, stack overflow, or IO exceptions. You need to handle them both though.
Handling of errors/exceptions - I completely agree with you on this, Marina.
But do we need to raise exceptions for what is essentially expected behavior?
I feel like people misuse exceptions sometimes.
@@MilanJovanovicTech Yes. And perhaps that should be the point: Developers should not throw their own exceptions. Just return result objects instead.
Thank you for this video! This got me thinking.
In fact, this is related to a problem that I’m tackling know at work. Returning error messages. So I did pretty much what you did. Created a Result class. Standardized the errors.
Btw. I have already experimented with a Result class that act like a discriminated union. More like Rust. But lack of language support makes the syntax a bit more cumbersome. It is on my GitHub.
Fully agree. The happy trade-off, IMO, is definitely to use the result types cleanly, like presented - but to log stack traces. It is the best of both worlds, and allows for that level of detail for debugging purposes, but can be disabled in a non-development environment, too, if desired.
Great work! I have been using the exception path.
If it works, don't fix it. Right?
I like your approach more than using 3rd party to do this, ie fluent assertions, etc, because respect POCO. Also, throwing exceptions it's not too bad, if you handle it 👍
I still use FluentValidation for input validation at the Application layer.
@@MilanJovanovicTech What are pros of using FV vs manually written validation class? Lots of inputs I have to manually validate anyway.
@@elpe21 Fluent Validation is great at validating an entire object. It might not work so well to validate individual parameters passed into a method on an aggregate. Also, I'd caution against adding too many dependencies to your domain layer. This should be kept as simple as possible.
That's a greath video! thanks for you teaching us. I have a question. In the Result class, where the Create(value) method came from? Line 15 Result(TValue? value) => Create(value);
gist.github.com/m-jovanovic/aa25b1ae424c985ff8ae696a79b6fe6e
thanks a lot! @@MilanJovanovicTech
Another great video Milan. This one really piqued my interest. I can see the benefits of using a Results object (especially if you can automatically capture the stack trace as suggested by others). However, I prefer using guard clauses to throw exceptions.
They allow me to very quickly add validation to a method in a minimal way.
For example:
DomainException.ThrowIfEmpty(email);
DomainException.ThrowIfEmpty(firstName);
DomainException.ThrowIfEmpty(lastName);
Using a Results object, requires you to sprinkle error handling throughout your application. Using exceptions on the other hand, allows centralized capturing of errors which is great for applications that expose APIs.
Of course, it's a tradeoff. Most people are very familiar with throwing exceptions. Using Result objects is outside of the comfort zone. That being said, I like how with result objects writing tests is super easy. Also, it's explicit that the method can fail and you should handle the failure case.
@@MilanJovanovicTechits also important to note that exceptions are for when something is unexpected. If you guard against a certain condition but you expect it to be able to occur then its not exceptional and an exception should not be used.
I believe the result-based approach could fully replace exceptions if only there was a language-level syntax which allowed result objects to be passed up to the caller, similar to how exceptions bubble up. That way, you can have a clean syntax like when using exceptions, and leave the error handling to some global handler, or handle the result object directly. Rust does this with the ? operator, but I wouldn't use rust even if my life depends on it so I hope we get better language support for result objects lol
It's coming with discriminated unions in C# :)
I prefer the result template approach.
usually I add a middleware to convert exceptions to a result template to enhance the api behavior.
I would suggest defining the Result as a struct to avoid returning a null result, sometimes beginners do that which doesn't make sense.
That's an interesting point about using structs
Thank you for the great videos!
I'm glad you liked it :)
1- Returning result from aggregate, value object or component needs failure check for each single invoker. It could be N times, so it is very sad. Most of my domain methods are using builder pattern, it is hard to use with that. It is sufficient to check once in any layer when throwing an exception. I think it is the most definitive option you need to decide with that.
2- Stack trace is a big deal when tracing an error.
3- There is not much performance loss for a single entity process. But, when you do batch operations or processing array typed nested value objects in aggregate it may hurt a bit. For that, we can process them concurrently. Of course, this creates some complexity.
Finally; of course it is a tradeoff. I am bit closer with throwing an exception, I think it is more manageable.
Exceptions are also problematic if you have many API requests.
What about explicitness with Result return value?
You know what to expect.
With exceptions this is implicit.
Thank you for your great job. I'm learning a lot of new things and concepts. I would like to know if throw exceptions in validation domain is really a good practice ?
I don't think there's a *best* way to do thing, so just choose what works for you and stick with it. My personal favorite is using Result objects.
brat moji ima sve tri bitne wow igre.
I igrao retail do skoro. Smucio mi se Ulduar pa batalio 🤣
Thanks for the videos, really I learn a lot from you. One question. This Gathering entity is also used to create the database thgrough ef core?
In a way
08:57 Good idea. Makes the possible errors more discoverable.
Yup, makes it much more readable and easier to group errors.
Hello, can you showcase the result and resultT classes which you are using in the video along with line number and caller method name implementations?
Here: gist.github.com/m-jovanovic/aa25b1ae424c985ff8ae696a79b6fe6e
Don't have line number/caller method, but can be added easily
@@MilanJovanovicTech great, thanks Milan for the information and support 👍
@@MilanJovanovicTech in your video, Error is class inheriting from IEquatable but the link above contains record. Which one you use as standard for your projects?
Also, you can implicitly cast the domain error into a result
Nice suggestion. Working on a similar video now, and I'll see if it makes sense to include that
Excellent, I think we have similar functionality in NuGet packages such as ErrorOr etc.
I plan to expand on the Result/Error concept to show you something much more powerful in some of the future videos
Can we create partial class for domain class, where one part contains only properties; and another with constructors & methods ie behaviors???
Partial classes are a terrible idea. They were initially designed for source generators.
@@MilanJovanovicTech Ok, is there any otherways to separate propertties and behaviors?
@@ravindranaths513 Why do you want to separate them?
The standard way is anemic domain model and a service class with behavior.
Great video, thanks for sharing :)
Thank you too!
Can you please share Error Class also. Thank you much for the prompt response.
Just a record with two properties :)
Great videos, learned a lot.
Would be nice to also have a link to code, as for the Error class example, we never get to see the complete code.. same with other implementations in this series
I share the code on Patreon :)
@@MilanJovanovicTech Thank you, already subscribed wit yearly plan on Patreon in the meantime :)
Hi there, I'm enjoying another great video! I have a question about FluentValidation usage in a DDD + Clean Architecture approach. In our projects, we've been using FluentValidation extensively for data validation. However, under the Clean Architecture principle, the domain should not have external dependencies. This raises the question of where to place our AbstractValidator implementations? Should we create a dependency to the FluentValidation library? In out case, All Repositories and Domain Services interfaces are within the domain project and Some of our validation rules are quite complex and rely on database checks! Could you provide some guidance about these questions?
I place them next to commands
In production do you handtype the Result object, or do you use libs, like e.g. language-ext?
I've used my own implementation, but you can also use a library
Hi Milan, as always very instructive video always, is it possible to have the complete implementation.
I share it on Patreon
@@MilanJovanovicTech Hi, it's ok I made the subscription thank you.
can you make a video on Entity Validation by implementing the specification model and the notification model. Thanks very much
Awesome video reminds me on ErrorOr library, looks like your friend (don't remember his name) was inspired by this approach. Performance all the way, I like that self documenting part. Testing it's still easy. Awesome video thanks!
We may or may not have chatted about it at some point :)
My favorite part is when writing tests
result.Error.Should().Be(DomainErrors.Gathering.AlreadyPassed);
Easy to write, easy to read also.
@@MilanJovanovicTech Absolutely, extremely readable
Awesome content
Thank you very much!
Hi Milan. Thanks for the video. Should we use here FluentValidation? if yes, then how? sometimes I need to inject an external source to provide validation.
I wouldn't introduce FluentValidation to the domain
great video!
Glad you enjoyed it
Hello Milan First I would like to thank you for your great efforts, second I would ask you to make this solution a public repo on github, please?
Thanks 😄
At the moment I only share the code on my Patreon
Mlian thanks for the video. I prefer to use functional programing approach to handle validation in particular using either monad with methods match/bind/map, please share your opinion on that approach?
I love that approach, Boris! I also use it on some projects, where I write everything in functional fashion (Map/Bind/Tap/Match, etc.).
I definitely want to cover this in some of the future videos.
Big fan of result objects
Did you also try Railway Oriented Programming?
@@MilanJovanovicTech looks very interesting. Never heard of it
Like the series! Great ONE!
But, didn't like the way when the exception vs result objects were compared in code, as in the case of exceptions the strings were not extracted and were done in a different style.
IMO all the benefits of a result (except the performance) can be achieved with custom exceptions, they can be self-documenting as well + they have stack-trace, which is better than logs. Reg. logs even Udi Dahan has his own view, which he uses to promote message-based systems (really easier to spot errors based on failed message counts).
The costs of exceptions are something we should not care much, as in most cases, every external input should be validated on the client side as well (at least to a possible level) and thus exceptions inside the back end should be fairly rare.
I have an extended extension (interface and static methods) to set ErrorCode, ErrorMessage and have a Result-like object with the exception. But if we want to have that self-documenting part, it's custom exceptions stored on one place, with pre-set messages is the way to go!
Awesome writeup. Could you explain a bit more about your last paragraph?
Great video Milan! I am little confused while trying to figure out which status code to return and how to know this. For example result can be a Success or Failure this is ok but how do you know it is a 401, 404 or 500 error? Or if it is a success it can be a 200 or 204 etc. Am I supposed to check that in Controller level or just add a StatusCode property to the Result object?
It's all about adding semantic meaning with the response, study the HTTP status codes developer.mozilla.org/en-US/docs/Web/HTTP/Status
@@MilanJovanovicTech Thanks for the answer. I know what the status codes are. I think I couldn't explain pretty well. I was talking about what is the point of seperating Success and Failure? You mentioned that you can match the ErrorTypes with 404, 400 and so on. But what if there is no error? A service can return Success but controller needs to know either if it is a 200 or 204. But there is no such a information in the Result object. How do you handle that?
Great Video Milan :) ... Well, if you are using Domain Events with Eventual Consistency, the Exception Approach is need to rollback any changes of the transaction, right? Or do you have a different approach for this kind of situation with the Result workflow too? :)
if failure - rollback transaction (or better yet, don't even commit it)
@@MilanJovanovicTech thanks very much for your response :) ...
I currently had a transaction opened per request and did a rollback if an exception occured (was implemented in middleware or ActionFilterAttribute)... thats why I was wondering how to do this with the Result Approach :)
Thanks for always sharing great knowledge. Please drop a link to the tutorial code repo. It's very helpful
There isn't a repo, I share the code on Patreon
Is it always common to use cleqn architecture and DDD or is there an alternative approach to DDD?
These videos specifically focus on CA and DDD
Doubt. I saw in some part of ur code, return Unit.Value when the result fails. How do u know that fails outside to return it for cliente-side for example, because u are awalys returning "void"? I usually used throw new SpecificExpcetion and take it on controller returning the right status code.
That's an old approach with MediatR to return nothing - you can always update it to return a Result
I would add that you can clean it up a bit more too by adding a second generic to your result type for errors. Then have your errors derive from gathering errors and have your gathering errors derive from error. Then in your function declaration you use Result as the return type. You add an implicit conversion in result for the second generic and then you directly return the error. Instead of returning Result(error type). I also tend to just return exceptions instead of creating a new error type as it saves a bit of time and the caller can throw it if they want and to do so you can add a ThrowIfErrant method to result and chain it on the call. I.e GetInvitation().ThrowIfErrant().
How is a second generic helpful? I think it's constraining, if anything. And I don't like the idea of having inheritance with Errors. I much prefer composition of some sort.
@@MilanJovanovicTech the second generic let’s you specify the type errors in the declaration.
When calling the method an IDE will show you the return type on hover or as you’re typing which includes the errors as the second generic. Then the caller can easily see what type of errors need to be handled. Similarly if you’re calling through an interface you can still see the types of errors whereas otherwise you just have to hope the comments are accurate. (Even the exceptions listed in the core libraries comments are not super helpful as they only apply to older versions sometimes A great example is anything in Path or Directory classes. None of those throw exceptions in .NET 7 but their doc tags state they do. If you read the online docs they say are restricted to older versions).
As far as inheritance goes, it’s not strictly necessary if you’re really against it, but personally I find it makes sense here similar to way all exceptions derive from exception. It lets you group your errors by type. So you can use GatheringErrors as a superclass.
This is in the direction of how newer languages like rust do error handling. They force you to declare all of your errors and the force the caller to handle all of them. While this doesn’t go that far it does give increased visibility which can allow you to do it a bit closer to that model. Rust actually uses a Result with a generic for the return type and error type:
Have you seen/What are your opinions of the ErrorOr package by Amichai? It seems to implement your Result Object pretty cleanly, including enumeration of errors, and some handy matching methods.
Great video, love the pacing and objective pros/cons of each solution
Yes, I actually introduced Amichai to the concepts. And he came up with the ErrorOr library. I guess he should owe me royalties 😂
Hi Milan, thanks for you awesome video I like it 👍
Did you finish your Validation Library?
I had no time to commit to that, I think it's going to happen soon enough though
Thanks for creating this series of videos. One question about structuring the solution: In your Gatherly solution you have a few entities, and your project structure seems to be fine. What's your suggestion on structuring large solutions (using Clean Architecture) with something like 50 entities. I can think of having sub-folders or having multiple domain projects for each boundary? I like to hear your opinion.
I would say grouping by feature would be the go-to approach. Identify which entities go together, and then group them inside a feature folder. I'm actually releasing a video about that (well, sort of about that) on Tuesday next week.
Is it possible to find somewhere code that you have written? You explained those conceps really clear in opposite to the all "mentors" that tried to do it :)
Hey Mateusz, I'm sharing the code with my Patreons. However, you should be able to find something similar on GitHub profile in the projects that are public
Milan, what do you think of the following alternative: creating a Manager class for each entity, where this class would be located within the domain layer and handle the corresponding validations (instead of having validations inside the entity). The entity would have internal access methods (for example, "internal void ChangeText(string text)"). This way, the business layer would be required to use the manager class to make changes to the entity, and the manager class would be able to access the entity's internal methods.
This way, the Aggregate Roots, Entities, and Value Objects would remain clean, with minimal code, internal methods, and properties with private setters.
Additionally, this method has the advantage that you can use the Manager with dependency injection and use IStringLocalizer to translate messages, or invoke encapsulated business rules with dependency injection as well.
Too many classes.
@@MilanJovanovicTech Ok, like everything it has its pros and cons. Thanks for responding Milan, I really appreciate your videos.
Great videos, keep it up. Just wondering, what is the VS theme you are using?
Thanks Mathew! It's ReSharper dark theme.
Thanks for the great video. I'm using ErrorOr library created by Amichai. May be you can publish your Result code as nuget package and we can explore in our projects.
There is already a great package from Vladimir Khorikov - CSharpFunctionalExtensions. This is where I got the idea from.
But I will consider if I have something unique enough to make it my own package.
I prefer to save stack trace everywhere because it's more common behavior which doesn't depends on languages, frameworks etc as I think. It's simple to debug. And it's more natural for understanding behavior of app by other developers. But maybe it's because I'm the old school engineer) Some languages using the result pattern as a box decision. To my mind, using the Result object is better when you have some complexitive logic depends on exception. You can't see it so often and It's not a good practice. For example If you have an external closed provider and you have to separate the logic depends on exception It's the better way to do it without throwing an exception in your app in source point.
You can always include the StrackTrace on the Result, I tried it one one project and it worked nicely
@@MilanJovanovicTech Thanks ) It will be interesting to try that way.
Can you please tell me where you have created result classes Thank you!
I mean in whihc video ?
gist.github.com/m-jovanovic/aa25b1ae424c985ff8ae696a79b6fe6e
I been using exception case, people are to afraid of throwing exception for some reason (if performance is really critical why use c# in the first place?). Just have exception with a global exception middleware to deal with them as you wish, for me is must clear than passing Result upper the call and deal with it in the controller/handler level.
Although I agree the performance impact most likely isn't going to be detrimental.
I can't agree that throwing exceptions is clearer. With Result, you know through the entire call chain to expect a success/failure. With exceptions this is implicit.
What about if you need to use interface(di) in entity for validation?
Double dispatch?
@@MilanJovanovicTech What you meant? I mean for example in Person entity you have to check identity number by country when somebody try to create Person instance. Also you have IIdentityNumberValidator interface to check that.
Hey Milan, let's say I have Connection class, with m2m relationship to Employee class. I want to have this kind of logic: If Connection is "direct message", then it can't have more than 2 employees. I wanted to implement this logic in domain, and throw an exception. But I realized that if I dont load employees eagerly each time, the exception wont be thrown. I'm new to these topics, would it be true to say that this is not a domain level condition?
I think you can implement this in the Domain, eagerly loading 1-2 entities won't be problematic for performance.
Thank you for your great videos.
I have a question please, how do the Application and Presentation layers know about the Domain Validation? for example, in the Gathering validation Result object case, you logged the error in the domain layer, and you didn't return any clear message to the upper layer.
Therefore, the upper layers, will not have a meaningful message to show to the end-user.
You are correct! I'm trying to build out this applicatiom very slowly and methodically, soon enough we will be connecting everything with the API and Database. And then it will all make sense, I promise!
@@MilanJovanovicTech
That would be great.
I will be waiting for upcoming videos.
I am really excited about this series, thank you for your limitless efforts.
Both solutions have the same problem. What if I have and API, and I want to know all the errors that occured?
Extend the Result to have an Error[]
Please shared code also a result class can you give all source code or video where you create all these 3 files?
gist.github.com/m-jovanovic/aa25b1ae424c985ff8ae696a79b6fe6e
@@MilanJovanovicTech thankyew so much bro.very helping bro
Dear @MilanJovanovicTech, I kindly request that you consider creating a well-organized playlist for beginners. This playlist would arrange code step by step, making it easier for newcomers to follow the sequence and find specific topics such as structure, MediatR, and Serilog within your videos. Your assistance in this matter would be greatly appreciated.
Do you really create separate exception classes for each error which might occur in your projects?
I think this only makes sense if you later want to catch the different exception and handle those differently otherwise if all exceptions are handled in the same way, I don't see much benefit in having different exception types.
Context information about this error can still be transported via the exception message or the "Data" property or you create one DomainException type which has custom properties.
Yes, I've head cases where there is a custom exception for every possible error. Nothing wrong with that approach.
Another option, is as you said nicely, to have one custom exception and pass in different values when throwing it.
Great Video Can you share error class in shared folder please
Check out my GitHub
Is Result object basically a Monad ?
Something like Maybe, or Either/Neither
I've been watching you for 1 year, great videos you have! But as I'm seeing using result's pattern really making my code messy, for example I need +4 lines for everything because it returns result object and I need to check if it's succes and etc. On the other hand using exceptions really making code small and easy to read. I really like the result pattern so could you give us more info or tip&tricks how to not end up with long code?
That's simply the price you pay for using Results. You have to check for success/failure at some point.
@@MilanJovanovicTech Then what about clean code, where methods should be short, doesn't it violate it?
Thanks
You're welcome!
Thank you so much. But if I have the same error result at different files, so any way to know where it happened? Just using log to trace the problem right?
Why would you have the same error in multiple files? Ideally these errors should be tightly coupled to a certain use case, and the more specific the better.
What approach do you use most in your projects? Exceptions or Results?
Another question is, in your project do you make double validations (both in command/request object and domain objects) or just in domain models?
I usually use Results these days, since I find it more explicit.
I rarely do double validation. But I make a difference between "Input validation" and "Domain validation"
Hi @@MilanJovanovicTech , I really like this approach but now I am confuse between Domain Validation and Request Command behaviour pipeline validation. Can you please explain both , please.
Can you add static class for throwing exceptions? You will have all errors in one place, as you have in second solution?
Static class for throwing exceptions? Interesting. What do you think we gain from that?
@Milan Jovanović You will have every possible exception for DDD in one place? Same as your second solution?
Also, you can return a list of failures. For example, for Send Invitation, you can have two separate errors for one call (Send Invitation to Creator and Event in the Past).
Btw what are you going to return for Value objects? You will get the result from the value object, and if that is not an error, you will continue?
I am finding both approaches troublesome :|
Have you tried to integrate Fluent Validation with DDD?
@@coolY2k Handling a list of Results can be a little problematic.
@@coolY2k I use FluentValidation in the Application layer, only for input validation.
I always struggle to do domain validation because in theory de domain layer should have no dependencies whick means I cannot use validation frameworks or libraries like fluent validation. I saw some colegues doing domain validation in DTOs which I don't agree. What do you think about this?
I use FluentValidation for input validation, before I reach the Domain layer. i think what I'm showing in this video is more appropriate for the Domain layer.
I prefer the Result approach, BUT! ON AVERAGE, throwing exceptions might actually be more performant. Especially if you are the client of your own API. If the consumers of your service are not malicious, the happy path should be expected to happen A LOT more often than the exceptional path, in which case, the extra allocations of the Result objects will result in worse performance.
Agreed, if the consumers aren't malicious there won't be many issues
Hi! Milan. I'm just a junior dev trying to understand this advance topics. I have a cuestion. There are application validations and domain validations if I'm right?. But if i want to send all the domain errors in ones, how could I do that?. For example if i have a class with a lot of value objects. How could I send all the errors in ones instead of sending one by one? Like when you use the validation attributes from the .net library. To validate your porpeties And finally. It is a good practrice?send all the errors in ones? I hope you may help me and understand me. Thanks! An have a good day.
Technically, the input validation should already prevent you from sending bad data to the domain. The domain validation is there as a fail safe - and for guarding the business rules. You could do the validations in the domain, collect the errors in a list and return those. But how will you handle that on the client?
Another drawback of object results is that if your project has a multi-layer, you should wrap the error up to the API layer to show the proper error message to the user. Instead of using Unit.Value.
Why is that a drawback then?
@@MilanJovanovicTech It's not a drawback, and it just needs more effort and writes more code if I want to be more precise, especially when using results for handling errors in other cases like HTTP calls and other things. Your logic section sees a lot of checking but throwing an exception cost performance but less code in some cases.
Awesome!
Glad you liked it 😁
Mlian thanks for the video. I am wondering which extension you are using for coloring your code in visual studio
It's Resharper
Wait, separate exception for everything? Isn’t that a bit much
Also, how does one turn them into codes? Like 400 or something like that
Some people actually do this. YES - it is too much
Great @Milan Thank you for share!
Did you upload code somewhere?
I want to take a look at code!
I'm making it available for my Patreon supporters only. However, take a look at my Github account. I'm sure you will find something similar
Hi,
your explanations are great.
Can you please share the code?
Reach out on LinkedIn or Twitter
Thank you for great your work!
How would you return such errors as results in a WebAPI responses?
At the controller level just check the result, and based on IsSuccess return whatever you think fits.
Whats wrong with model errors, maybe using fluent validation.
Different purpose
Great, thanks! Btw, what's your VS Theme name?
Dark theme + R# syntax highlighting
For me it depends on the logic.
If there's a lot of logic and you are really deep, than it's much easier to throw the exception and handle it in ExceptionHandler.
With Result pattern, in this case, you should handle this error in each method, before final one. And that's kind of messy.
That's why I try to keep the call stack "shallow"
You can use Railway Pattern to create concatenated methods that return the Result class. I can assure you that the code will look much simpler and easier to read. You can use libraries like ErrorOr that already come with this functionality
Nice video, but I think you skipped some downsides regarding the Result pattern.
First of all it creates a huge overhead in your method interfaces, and even though you stated that it increases the expressiveness, I kinda think it's the opposite. The whole code becomes a convulted mess of "Result" objects being returned everywhere, just like what you'd get using a library like Vavr in the Java world. I don't think it add to the readability of the code at all.
The other issue I see is that for the callee, it really makes no difference whether you need to try-catch a Checked Exception or check whether the Result object contains a result or an error. In most systems, this forces you to pass the consequence of "indesired path" (Exception or Result.Error) down the whole calling chain. That's why I often prefer using the Unchecked Exception with a global handler; for some apps it might make sense, but when you design an API, a global Exception Handler does the trick just fine and avoids the use to handle the errors/exceptions throughout all the layers.
It's when people overuse exceptions for flow control that things become problematic, and performance tends to degrade
And in addition performance isn't too bad with throwing exception. Nick Champsas did some performance tests recently and It's nearly 40% slower than with Result pattern in casses where you are throwing exceptions thousands times a second which is not regular situation. Usually your domain throws exceptions much rarely so in reality impact is much lower than 40%
What are the complete steps to create a computer program to mine 50,000 bitcoins every second and the withdrawal method is via paypal only There is no waiting for withdrawal and no minimum withdrawal
42
Not a huge fan of the first solution. Even though you have your stacktrace, the code flow can be really messy resulting in a bad debugging experience. But it's the easiest and most common so..
The second solution is great, however I don't find it very scalable and it's a pain to maintain. The static classes will grow endlessly and you would have to manage and divide them over and over again. Also, the errors are not very explicit, you have to follow the references bubble to see where each Error is triggered and why.
That's what I found at least for my projects and worked with alternatives to counter that
I'm curious what did you end up using the end? Since you weighed in with the pros/cons for each approach.
@@MilanJovanovicTech
I ended up with 2 alternatives depending on the project:
- Integrating FluentValidations in my Domain project forcing my entities and events to link to a validator. The domain project should not be dependent from any library but i found that a good tradeoff compared to the benefits of doing this. Easy validation rules, fast debugging, scalable structure (you just add a validator with your new entity).
You also have the control if you want to throw an exception on SOME scenarios. I would choose to validate and throw on rules that should never happen...
- For other projects, I actually borrowed a concepts from F# and JS: Adding a delegate onError that forces the caller of each function to handle the unlikely scenarios. I think it's the same as your second solution with one single benefit, you can group these handles in a single reusable delegate which if you're not using MediatR or any Pipeline behavior is cumbersome. I wasn't using MediatR so that was it
I assume you can do that with some reflection magic but laziness stopped me from exploring that ;)
How can I get code for this video?
It's available on my Patreon
Where can i get this code? @milan
I share it on my Patreon: www.patreon.com/milanjovanovic
Sorry Milan. From my point of view, you're not addressing Domain Validation directly in this video. It seems more focused on error management within domain layers. Another thing will be if you manage de condicionals "If" with fluent validation to create validation rules for this entity.
That's ok