Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intended implementation of business logic in UseCases #295

Closed
DasBen opened this issue Dec 2, 2022 · 2 comments
Closed

Intended implementation of business logic in UseCases #295

DasBen opened this issue Dec 2, 2022 · 2 comments

Comments

@DasBen
Copy link

DasBen commented Dec 2, 2022

Hello!

first of all I would like to thank you for your scaffold-clean-architecture Blog Article on Medium and the GitHub Repository. It really did help me to structure my code and in regards to Clean Architecture. So good job on that 👍.

I'm currently having a discussion about this. The discussion is about the Implementation of UseCases.
My understanding is that the UseCase needs to be very abstract. So in case of process like this

CreateUser:

-> Validate Age
-> Validate Address
-> Encrypt Password
-> Save User
-> Return User

I would argue that all of these would be a Repository and no Info about the "How to validate" or "How to encrypt" or "How to save" would be implemented in the UseCases. Even if they are part of the business logic. Let's say I would like to not allow anyone under 21 years or over 60 years. The "How to" is an essential part of the logic.

How is it now expected to be implement as Business Logic:

  • Within Domain->UseCase->CreateUser->AgeValidator with Implementation of the AgeValidator right beside the UseCase?
  • Or would you write a Helper for that?

I thought the UseCase is flying on such a high level, where the age logic is not part of the implementation. But if its essential to the UseCase / Business Logic on "how it is done", where would that go?

The Original "Clean Architecture" by Robert C. Martin would argue that a helper would be wrong for this. But it feels so much nicer and cleaner. Also I would be able to replace that easily like making it into a Lib or a Rest Server or whatever.

If I wanted to make this without a Helper with minAge and maxAge configurable, I would have to:

  • Create a ConfigurationHelper which can read the Spring Config, because no Spring allowed within Domain
  • Read the application.yaml with @value("minAge") and @value("maxAge")
  • Pass that over to the AgeValidator to an Implementation right beside the UseCase File
  • Then that AgeValidator would Implement the Logic
  • The UseCase would then need to do new AgeValidator(configurationRepository) to use this with ageValidator->validate(user.getAge)
  • But this whole lot would mean extra work and since your tool is so good, I would have expected to have a "Configuration" Generator. But that does not exist. So I'm confused if this is intendet.

With a Helper that would be:

  • Create the AgeValidatorHelper which implements the Interface "validateAgeRepository"
  • Read the values with @value
  • Implement the Logik here
  • Just go for the Repository in the UseCase like validateAgeRepository->validate
  • But this would put Business Logic outside of the UseCases (Domain Model)

I'm so confused... Can you or anyone here inspire me about the intended use?

@gabheadz
Copy link
Contributor

gabheadz commented Dec 6, 2022

Hello Benjamin, we are glad to hear that the plug-in has helped you achieving cleaner code.

About your case, it is for sure a situation that keeps on emerging in every team and project. The reasoning we would apply is that, instead of abstract try to think in terms of what is pure to the domain and what’s a detail that the domain should be agnostic of.

With your own example, maybe trying to choose and apply a single approach asking the “How to’s” is what’s proving difficult. Maybe you should ask the What IS.

I would argue that the age validation must BE a pure function that it's intrinsic to your domain and that must be used in your createUser case. Age ranges can be defined by Application, and configuration should provide an instance of the use case with the data necessary to perform its intrinsic operations. By the way, the app-service module is the one in charge or wiring all things up, so that’s why no “configuration” tasks exist in the plug-in.

Some times there’s arguments pointing out that some functions can be used outside the domain layer and shall not be repeated (the DRY principle). And if that’s your case, and if those validations are implemented as pure functions, then there is no reason other layers cannot use them by declaring dependency on the domain, instead of creating additional modules in your application.

The same logic would apply to the validateEmail case, unless the validation processes depends on some sort of external service/data, which leads me to the encrypt password part of the “problem”.

The encryption process IS an implementation detail, that the use case should be agnostic of, meaning handling keys, key types, algorithms, seeds, salts, lengths, certificates, connection with key vaults, etc. should be handled by a helper and/or it’s infrastructure dependencies (repositories).

Hope this helps you a little bit into making your decisions accordingly.

Gabriel.

@DasBen
Copy link
Author

DasBen commented Dec 14, 2022

Thanks you for explaining!

@DasBen DasBen closed this as completed Dec 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants