I have a list of objects that will need to go through an approval process.

I am curious if it would be best to simply add some properties to my object, like ApprovedBy, and ApprovedOn.

Another option is to create an ObjectApproval class that contains this information as well as other information that needs to be stored.

If I wanted a list of objects that still needed approval, I could simply query for a null ApprovedBy in the first scenario. In the second scenario, I would have to maintain an accurate list of ObjectApproval items.

The next thing is, what if I need a multi-step approval process? In this case, I think it would be better to create an ObjectApproval type to track all the intricate details, and I could simply query for the ObjectApproval.Step (or something similar) to find out the items a specific user needs to approve based on their role

Any thoughts on this? Or perhaps design patterns to recommend?

  • 5
    Much like weeds, approval processes tend to grow with time. You may wish to plan accordingly. – Dan Pichelman Jul 29 '13 at 14:52
  • I immediately think of countless ways to do this; key being the fuller scenario I was working in that would help me decide. Can you give greater detail about the semantic meaning of these objects and their approval(s) and what all it relates to? – Jimmy Hoffa Jul 29 '13 at 16:03
  • I can give names to the objects, but it won't really help much since there are 3-4 different places I want to implement this, and all of the workflow steps are specific to what I'm working on and aren't really known to most others. (Secret secret! ;)) – Origin Jul 29 '13 at 17:30

If the approval is an integral part of the object (clearly a part of its design), then make it part of the object. In essence, the object can approve itself (via an Approve() method). But it's more likely that there are other objects that go through a similar (if not identical) approval process, and it becomes a cross-cutting concern.

In practice, some state will have to be stored with the object, even if that is merely an identifier for each object instance so that the approval object knows which objects have been approved. Typically this happens because your application talks to a database, and an Object-Relational Mapper provides you with domain objects that contain their own identifiers. The approval information would thus be contained in a different table.

Approval should not simply involve a bare boolean field or property on the object. Any object can change that field, and there is no accountability because a record of the approval is not kept. That's why an Approve() method is needed; it does the necessary work of archiving a record of the approval.

  • Smalltalk style delegation- almost, until you put the data in a different table. I like this approach but can't +1 without more info on the problem domain. Maybe a smart object is more fitting, or a simple state enum on the Obj (multistep approval favors this, and is an audit log necessary for each step?) just need more from the asker. – Jimmy Hoffa Jul 29 '13 at 16:36
  • Agreed that more information is needed. A generalized solution would have objects that implement IApprovable. – Robert Harvey Jul 29 '13 at 16:38
  • The one thing we can agree about based on the info given though hopefully is that (ApprovedBy == null||empty) == !Approved is semantic abuse of an ApprovedBy field, abusing fields in this way decays poorly with future work and is a totally unnecessary optimization. An Approved field should exist as well as the ApprovedBy. If you agree say something to the nature in here and I'll give you the +1 without the asker adding more info (who knows if he'll ever even come back) – Jimmy Hoffa Jul 29 '13 at 16:52
  • @JimmyHoffa: Updated my answer. – Robert Harvey Jul 29 '13 at 16:56
  • Funny to say "if he'll ever come back" given your nickname ;). I agree that if I were to store the status of the approval on the object, it should have a boolean field of "Approved" that can be checked instead of relying on some other piece of information (the approver for example) I also agree it should be part of the object, but isn't MyObject.Approval technically part of the object? I could do MyObject.Approval.WorkflowStep, right? – Origin Jul 29 '13 at 17:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.