pdevito3 / wrapt.dev

wrapt-dev-git-master.pdevito3.vercel.app
6 stars 3 forks source link

This is a question about the relation ship between the domain, application and infrastructure.persistence layer. #3

Closed koimad closed 3 years ago

koimad commented 3 years ago

In your examples and documents you cover simple validation with the fluent validation API. My question is more about the non trivial validation when the validation rules need to obtain data from the persistence / database layer. With no dependency between the application and persistence layer, how do you see the validation rules accessing data previously stored. To replace a iqueryable repository or selector do you just see the use of IQueryable dependency which relates back C# dependencies rather than the applications dependencies.

Looking forward to discussing further.

Brian Wilkinson.

pdevito3 commented 3 years ago

Hey Brian,

Do you have an example of what one of these rules might look like just so I can lay it out a bit better and make sure we're on the same page?

koimad commented 3 years ago

Hi Paul,

         The simplest rule would possible be Name is Unique. Whist a constraint in the database may enforce the rule, a better approach is to perform validation and create a Rule Name Is Unique. This rule would need to be able to get a IQueryable so that it can query data that has been stored already.

            Another example might be a rule on Verifying an Object / Reports Status. The business rule in this case would be based on the following.

            A User many not change and reports status to verified if they have created or maintained any data contained within the report. This would depend on audit entries for one or more entities depending on how the audit information is recorded.

            One possible way to achieve the required low coupling could be to define Service or Selector/Query interfaces within the domain layer that are implement in one of the Infrastructure Layers. Thus the implementation in the infrastructure layer is decoupled from the interface.  And the interface can be used anywhere with no coupling to the implantation.  Is this the way you would see solving the problem.
          I know that this would require the validation rules to be added through dependency injection to get the interfaces correctly passed in.

            If so It might be nice to update the documentation and code generation to include some basic Selectors based on Id, Name etc. And then Include the implementation of the Selector and a simple rule to use it, The unique Name I think is the Ideal candidate to demonstrate the implementation through the different layers.

Hope my explanation helps

Brian.

From: Paul DeVito notifications@github.com Sent: 28 January 2021 19:28 To: pdevito3/wrapt.dev wrapt.dev@noreply.github.com Cc: koimad koimad@blueyonder.co.uk; Author author@noreply.github.com Subject: Re: [pdevito3/wrapt.dev] This is a question about the relation ship between the domain, application and infrastructure.persistence layer. (#3)

Hey Brian,

Do you have an example of what one of these rules might look like just so I can lay it out a bit better and make sure we're on the same page?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/pdevito3/wrapt.dev/issues/3#issuecomment-769319299, or unsubscribehttps://github.com/notifications/unsubscribe-auth/ABLS4SU7CF2KDC5PLE2KV3DS4G3FJANCNFSM4WXS2J3A.

pdevito3 commented 3 years ago

Agreed. You wouldn't want to start mixing business logic in your db if you can avoid it. Let's say were looking at a patients object. One option would be to 1) DI your patient repository into the patient manipulation validator 2) create a new isUnique validation rule that calls a repo method (existing or new) to get a list of patients that match that name 3) if the count is > 1 return false.

Maybe something like this? Might need to be ironed out a little bit.

        private readonly IPatientRepository _patientRepository;
        public PatientForManipulationDtoValidator(IPatientRepository patientRepository)
        {
            _patientRepository = patientRepository ??
                throw new ArgumentNullException(nameof(patientRepository));

            RuleFor(patient=> patient.FirstName)
                .Must(IsNameUnique)
                .WithMessage("First Name must be unique");
        }

        public bool IsNameUnique(PatientForManipulationDto patient, string newValue)
        {
            var patientsFromRepo = _patientRepository.GetPatients(new PatientParametersDto()
            {
                Filters = $"FirstName == {newValue}"
            });

            return patientsFromRepo.Count == 0;
        }

Another option would be to add the validation check to your repository methods directly. Ideally you're calling a single method in your add and update calls.

Hopefully that helps! I want to compile a list of examples of working in a clean architecture features eventually, so I'll keep this in mind as something to put in there.

As far as adding validation scaffolding into craftsman directly, I may do this eventually, but it won't be soon as this would need an incredibly complex API and much of it would just be a layer on top of fluent validation anyway. Not really possible to account for everything regardless, and this is just meant want to scaffold out the boilerplate not all of the business logic.

You're absolutely right that this would be a good feature to have an example for working in a clean architecture. Thanks for the note and please feel free to let me know if you think of anything else or have any issues as you're building!

pdevito3 commented 3 years ago

looks like this article could be helpful as a base. not 'clean,' but gives you an idea of how you could create the rule. Very similar to the above

koimad commented 3 years ago

Hi Peter, your solution is exactly what I was thinking of. The repository is a big question I prefer the idea from NGRX using the Selector pattern to try to encourage more reuse. I included the IPatientRepository in the Domain Layer so it's common, and the implementation in the ifrastructure.persistence layer. It keeps everything nice and simple. Thankyou for your time Brian.

pdevito3 commented 3 years ago

just realized it didn't link on my last comment: https://www.damirscorner.com/blog/posts/20140519-EnsuringUniquePropertyValueUsingFluentValidation.html

glad it was helpful, though I would be cautious about adding your repo to the domain layer as it generally shouldn't depend on any other project. regardless, good luck!