TheProlog / prolog-use_cases

Use-case layer for Meldd/Prolog application.
0 stars 0 forks source link

Refactor existing use-case attribute management. #44

Open jdickey opened 8 years ago

jdickey commented 8 years ago

Use cases have generally used form objects to aggregate, validate, and decorate attributes and collaborators. This was a great improvement over earlier approaches, but it suffers from several problems that, in one way or another, have caused pain over the last several weeks of effort:

  1. They conflate collaborators (providers of services such as authorisation or persistent storage) with parameter attributes (the bits of specific, generally one-off, information needed to accomplish a particular use case);
  2. The future of the attribute-management library underlying our form-object implementations, Virtus, has been called into question by events including the departure of the original maintainer (who has since been working intensively on a replacement, refinement, and expansion of the concepts in Virtus); and
  3. As we encounter more issues involving ActiveModel and/or state, we've been further reminded that form objects' primary use case is in mutable, possibly iterative, state manipulation and validation. Further, to the best of our memory, ActiveModel::Validations is the last remaining use of ActiveModel in the current Gem, and its use is limited to form objects. Nuke form objects, and we can drop the dependency on the active_model Gem (and most of its dependents) altogether.

We have a proof-of-concept implementation (buried) in Commit 2921201 for the ProposeEditContribution use case (which Just Happens to be the most complex use case yet implemented). Despite its total complexity, a review of the code and its history should indicate that this new implementation strategy (or "architectural detail" if you prefer) eases understanding, and likely reliability, of the code.

This issue was opened to serve as a reminder of the intent to, and placeholder for PRs for, refactoring existing use cases following the ProposeEditContribution exemplar. We confidently expect that each such rework (if not the totality of all such) will be done in far less time than the ProposeEditContribution rework itself.

jdickey commented 8 years ago

Also important to keep in mind here is that a use case object's use of its collaborators must be idempotent; code outside the use case will implement functionality not core to the domain logic (persistence, authorisation, etc); that code must not be used within a use case in such a way that a transient failure risks leaving the system in an inconsistent state (e.g., an Accepted Contribution properly recorded in the Contribution Repository but the Article content not updated in the Article Repository or vice versa). The purpose of the Result objects is to give that outside code all the information it needs to figure out how to manage writing to persistent storage and other services on behalf of the use case. Most delivery mechanisms implement, for example, some form of atomic transactional logic in their persistence support; there is absolutely no reason to reinvent that wheel in our use cases.