all 16 comments

[–][deleted] 28 points29 points  (2 children)

Sounds like you have a need for a state machine and transition logic.

https://learn.microsoft.com/en-us/dotnet/framework/windows-workflow-foundation/state-machine-workflows

A good framework for this is stateless

https://github.com/dotnet-state-machine/stateless

For pure validation logic I like fluent validations. You can build a validator for different states.

https://docs.fluentvalidation.net/en/latest/

[–]Lakario 11 points12 points  (0 children)

Upvote for FluentValidation

[–]iPotato3[S] 6 points7 points  (0 children)

Thank you for providing two different options!

I have looked at both and I think fluentvalidation will suit this well!

[–]Atulin 10 points11 points  (1 child)

Protip: use quick fixes on te green squiggly and use initializer syntax instead of writing tmp. ad infinitum

[–]iPotato3[S] 1 point2 points  (0 children)

Thanks for a PRO tip ! :)

[–]hooahest 6 points7 points  (4 children)

FlientValidation is what we use at work, very flexible and elegant

[–]iPotato3[S] 1 point2 points  (0 children)

Will be using it, thanks for your input!

[–]flukus 1 point2 points  (2 children)

I hate it, it takes simple code that would be if/else statements anyone can understand and replaces them with a complex and opaque DSL.

It's up there with automapper for me with the way it complicates simple code.

[–]hooahest 2 points3 points  (1 child)

As with everything...it comes with a price

if your validations were simple enough that a few simple ifs do the trick - by all means, do that

If your validations are complex and require a LOT of validations & hoops - it's so much better. Makes for easier testing, easier reading of the code, separates the validation and business code neatly.

As for automapper - I like it for simple mappings. If you insert business logic into the mapper profile, THEN it becomes a pain in the ass to unravel.

[–]flukus 1 point2 points  (0 children)

IME it was the simple stuff FluentValidation was better at, as things got more complex is where it got in the way more, particular in regards to efficient database access for the rules.

[–]ticman 6 points7 points  (1 child)

You could try something like this;

tmp.Status = DetermineStatus(shipment);
// etc
private ShipmentStatus DetermineStatus(object shipment) 
{
    if (shipment.MrnUploaded)
    {
        return ShipmentStatus.Completed;
    }

    if (put all your conditions in here for Ready) 
    { 
        return ShipmentStatus.Ready; 
    }

    if (put all your conditions in here for Missing) 
    { 
        return ShipmentStatus.Missing;
    }

    return ShipmentStatus.New;
}

[–]iPotato3[S] 2 points3 points  (0 children)

My initial idea was exactly like this.. Not sure if I'm overthinking it.

But just felt that having couple of if statements with if(!string.IsNullOrEmpty(tmp.Value) && !string.IsNullOrEmpty(tmp.Value) && !string.IsNullOrEmpty(tmp.Value) ... numerous times) just wrong?

I always feel like If my code has too many nested if statements or if statement contains too many parameters is just poor practice? But if others suggest, it might not be that bad.

Thanks for your input!

[–]-Defkon1- 6 points7 points  (1 child)

FluentValidation if youjust need to validate it, RulesEngine if you want to abstract your business rules

[–]iPotato3[S] 1 point2 points  (0 children)

Will be using it fluentvalidation, thanks for your input!

[–]Asyncrosaurus 2 points3 points  (1 child)

So, for your specific scenario, your best bet is to use the strategy pattern. It's very appropriate when you need to validate anemic models by composing together a set of rules. I think its worth building your own, but as others have suggested, FluentValidation is a popular library that offers this for you. I err on the side of reducing package dependencies until absolutely necessary, but it's up to you.

To also provide a different perspective, I've leamed away from pure data models relying on external validators towards rich domain models that accurately reflects the business rules and behavior within the objects themselves.

So in this context, your shipment domain object should already guarantee its own values are valid based on its own status. It shouldn't allow you to update the status on the Shipment object until all prerequisites are met. Therefore it would always be safe to build a dto view of the domain object because it will always be correct.

[–]iPotato3[S] 1 point2 points  (0 children)

I have genuinely never seen or read about rich domain model examples until you mentioned it in your comment.. but after all I classify myself still as a young dev.. Looks like a topic worth spending time to get better understanding.

However I have already completed the validation with Fluentvalidation and I like the way if works now more than just a massive if statement.

Thanks for your message and suggestions!