Hi Godefroid,

CCing zope3-users, where this post belongs to.

On Monday 12 March 2007 11:48, Godefroid Chapelle wrote:
> - about the existing workflows (DCWorkflow, Zope3.wfmc, AlphaFlow,
> OpenFlow...)

Kit asked the question about workflows on the SchoolTool list as well; I 
assume that you guys are working together.

I have personally found that workflow engines are ususally overkill. In fact, 
I think document/content publishing as it is done in Zope 2 CMSs is one of 
the exceptions.

In SchoolTool we decided early to use a workflow engine to enforce process. We 
have found there that it was overkill. (Everyone else can read Tom's comment 
on the SchoolTool-Dev list.)

That said, here is my experience from another customer. This customer asked us 
to rewrite a job application management software. You can easily see the 
common workflows there. However, her complaint about the old system was that 
the workflow was too stiff and she wanted to change the list of stati of a 
particular application at any time manually, effectively breaking the 
workflow.

With those requirements in mind we looked at our options, and she wanted to 
deliberately break the flow we decided against any workflow engine. Instead, 
we implemented stati as a special property of the application. Whenever the 
stati are changed, we fire events for each added status and another event for 
each removed status. We then created a module called "policy" that contains a 
multitude of event subscribers listening to the events and doing the work. 
Those tasks include writing logs, sending E-mails, triggering other status 
changes, security changes, and data verification. Here is some of the 
interesting code:

application:

class Application(Contained, Persistent):
    ...
    @apply
    def stati():
        """See IApplication"""
        def getStati(self):
            return self._stati
        def setStati(self, value):
            removed = set(self._stati) - set(value)
            added = set(value) - set(self._stati)
            self._stati = tuple(value)
            for item in removed:
                zope.event.notify(StatusRemovedEvent(self, item))
            for item in added:
                zope.event.notify(StatusAddedEvent(self, item))
        return property(getStati, setStati)

policy:

@zope.component.adapter(interfaces.IStatusRemovedEvent)
def historyApplicationStatusRemoved(event):
    log(
        event.object,
        _('Status Removed: $status', mapping={'status': event.status}))

# Not reacting to a status change, but nevertheless interesting to look at.
# Yes Martijn, I love hurry.query!

@zope.component.adapter(interfaces.IApplicationCompletedEvent)
def applicationCheckForDuplicate(event):
    # When upon completion of the application, another application with same
    # last name, first name and birth date is detected, then this application
    # is marked as duplicate
    app = event.object
    duplicateQuery = query.And(
        query.value.Eq(('app-catalog', 'firstName'), app.firstName),
        query.value.Eq(('app-catalog', 'lastName'), app.lastName),
        query.value.Eq(('app-catalog', 'birthDate'), app.birthDate),
        query.query.Not(
            query.set.AnyOf(('app-catalog', 'stati'), 
(interfaces.INCOMPLETE,))
            ),
        )

    result = tuple(query.query.Query().searchResults(duplicateQuery))
    # Only mark applications as duplicates, if the application is not itself
    if (len(result) == 1 and app not in result) or len(result) > 1:
        app.stati += (interfaces.DUPLICATE,)

So in fact, our workflow engine is the Zope 3 event framework. I like it for 
the following:

- There is no new framework overhead; use what you know.

- It is maximally flexible. I have control over the way I implement the 
business logic and the UI. 

- Having all policy in one place (this includes event subscribers to other 
events as well) provided great oversight. Whenever the customer asks 
me: "What are the rules for this behavior?" (even though she specified it, of 
course), I can just go to this one place and give her an answer within a few 
minutes.

- Easy to test. It is very simple to test each event subscriber in isolation 
and go through all the cases.

I guess I would not have to say it again, but I really like this pattern.

Regards,
Stephan
-- 
Stephan Richter
CBU Physics & Chemistry (B.S.) / Tufts Physics (Ph.D. student)
Web2k - Web Software Design, Development and Training
_______________________________________________
Zope3-dev mailing list
Zope3-dev@zope.org
Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com

Reply via email to