<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>RCFans</title>
    <description>Logic will get you from A to B, imagination will take you everywhere.</description>
    <link>http://rcfans.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>基于规则的业务流程分析</title>
        <author>RCFans</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rcfans.javaeye.com">RCFans</a>&nbsp;
          链接：<a href="http://rcfans.javaeye.com/blog/211943" style="color:red;">http://rcfans.javaeye.com/blog/211943</a>&nbsp;
          发表时间: 2008年07月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          “思考得少，瞎干得多”，就是目前企业开发的现状。瞎干了两个月后，回头来分析一下一个有趣的流程，是我们目前项目中最复杂的一个流程（因为要完成它而不能动脑，所以复杂）。 <br /><br />首先把UML书上的案例扔到一边，那个是齐全的菜谱、佐料、原料而真实项目是荒地。想想走到荒地上给自己整一顿满汉全席，不容易啊…… <br /><br />现在已经忘了最初听到这个流程的描述是怎么样的了。大概就是“一个待办项会发送和接收很多次，也可以发送接收一次，发送完后就不能再次发送了，最后一个接收结束后才能结束整个流程”——够昏的吧^O^遇到这种事千万不能听客户、需求人员甚至项目经理的，架构师才是设计这个系统的人，不能自己分析、定义业务对象，下课去吧。 <br /><br />第一反应就是发送和接收必须是两个不同的待办项，随后是必须定义两个不同的动作：完全发送和部分发送。概念一定要区分准确。 <br /><br />随后关于如何叫完全发送和部分发送有几次需求上的变化，但不影响流程的执行规则。这个就形成了我在业务流程配置一文中写的ResponseTask类，当时的需求就是请求-接收，所以只写了两个Task；随后扩展成了每接收之后还有一个任务叫填写意见书，所有的意见书完成之后再开始一个新的任务。所以就改成了：请求-接收-响应三个操作，修改ResponseTask，增加了ResponseType这一枚举值属性，修改了结束的算法。目前的流程执行规则是相当死板的，完全硬编码在引擎内部，无法改变。以下是ResponseTask类和执行代码： <br /><br /><pre name="code" class="c#">
using System;
using System.Collections.Generic;
using System.Xml.Serialization; 

namespace Microsoft.Applications.ChinaMobilePMS.FlowEngine
{
    public class ResponseTask : TaskBase, IComparable&lt;ResponseTask>
    {
        private int requestNumber = 0;
        private ResponseType responseMode = ResponseType.Request; 

        [XmlAttribute("RequestNumber")]
        public int RequestNumber
        {
            get { return requestNumber; }
            set { requestNumber = value; }
        } 

        [XmlAttribute("Mode")]
        public ResponseType ResponseMode
        {
            get { return responseMode; }
            set { responseMode = value; }
        } 

        #region IComparable&lt;ResponseTask> Members 

        public int CompareTo(ResponseTask other)
        {
            if (this.responseMode &lt; other.responseMode) { return -1; }
            else if (this.responseMode == other.responseMode) { return 0; }
            else { return 1; }
        } 

        #endregion
    }
} </pre><br /><br /><pre name="code" class="c#">using System;
using System.Collections.Generic;
using System.Xml.Serialization; 

namespace Microsoft.Applications.ChinaMobilePMS.FlowEngine
{
    public class Activity : IActivity
    {
        //...
        public void StartActivity(string actionValue)
        {
            switch (mode)
            {
                case TaskMode.Response:
                {
                    responseTasks.Sort();
                    ResponseTask requestTask = responseTasks[0];
                    ResponseTask receiveTask = responseTasks[1];
                    ResponseTask responseTask = responseTasks[2];
                    if (status == StatusType.Scheduled)
                    {
                        status = StatusType.InProgress;
                        requestTask = responseTasks[0];
                        requestTask.CreateTask();
                    }
                    else if (status == StatusType.InProgress)
                    {
                        switch (actionValue)
                        {
                            case "CompleteSubmit":
                                requestTask.Approve += new ApproveHandler(receiveTask.CreateTask);
                                requestTask.ApproveTask();
                                receiveTask.RequestNumber++;
                                break;
                            case "Submit":
                                receiveTask.CreateTask();
                                receiveTask.RequestNumber++;
                                break;
                            case "Receive":
                                receiveTask.Approve += new ApproveHandler(responseTask.CreateTask);
                                receiveTask.ApproveTask();
                                receiveTask.RequestNumber--;
                                responseTask.RequestNumber++;
                                break;
                            case "Reject":
                                receiveTask.Reject += new RejectHandler(requestTask.CreateTask);
                                receiveTask.RejectTask();
                                receiveTask.RequestNumber--;
                                break;
                            case "Response":
                                responseTask.ApproveTask();
                                responseTask.RequestNumber--; 
                                if (((requestTask.Status == StatusType.Completed) && (receiveTask.RequestNumber &lt;= 0) && (responseTask.RequestNumber &lt;= 0)))
                                {
                                    CompleteActivity();
                                }
                                else
                                {
                                    responseTask.Status = StatusType.InProgress;
                                }
                                break;
                            default:
                                break;
                       }
                    }
                }
               break;
            }
        }
    }
} </pre><br /><br />昨天参考了Workflow Pattern，其实这个被我表达为Request-Receive-Response的流程的标准描述是以下两个的综合： <br /><br /><u><strong>Parallel split pattern</strong></u><br /><img src="http://www.workflowpatterns.com/patterns/control/images/fig2.png" /><br /><br /><u><strong>Synchronization pattern</strong></u><br /><img src="http://www.workflowpatterns.com/patterns/control/images/fig3.png" /><br /><br />于是我拿出纸和笔，画下了这幅图：<br /><img src="http://byfiles.storage.msn.com/y1pYaKuZFHNqghlnFGBbOTxQybyxFGnnmIzUsyMvwaiRpa8jecXCislz7q89ztKKPpG?PARTNER=WRITER" /><br /><br />想了想，这副图没有把完全发送与部分发送的分支表达出来，于是改成了这幅：<br /><img src="http://byfiles.storage.msn.com/y1ptzqXXQRceTSdRHfGIdUplDDAKNjJC4oVUeIs7D6bWLy0T8xsDf8syh9Fxxcxvpbw?PARTNER=WRITER" /><br /><br />现在呢，有了选择。如果用户选择部分发送，它将走图一的流程，否则就一个简单的2-3-4走完。但是，这时依然缺少了东西，缺少了4开始的条件。并且，部分提交和完全提交唯一的区别就是是否结束1，所以不用专门配分支，再把选择和任务2视为并发任务，因为他们没有先后关系，虽然界面上操作有先有后，但这个选择不能决定任务2是否产生。又改：<br /><img src="http://byfiles.storage.msn.com/y1p7fDA7DKWWUofK3I9RFS8ot8OeqM6OiQC4c8aBDG7V-ZvkhQ0xM7rcriNTnuHiO0W?PARTNER=WRITER" /><br /><br />这一个算是比较满意的分析模型。根据这个模型，先前硬编码的执行算法将被抽象为ControlRule，它将继承自RuleBase，代表了上图的流程线。而这个分支是用户在执行时选择的，暂定名为Choice：<br /><pre name="code" class="xml">&lt;ControlRule Mode="Choice">
    &lt;Choice Result="Complete">
        &lt;Then />
    &lt;/Choice>
    &lt;Choice Result="Partial">
        &lt;Then />
    &lt;/Choice>
&lt;/ControlRule> </pre><br /><br />规则引擎将解释这个配置并执行。而在Task的执行上，也会定义在配置中，而不是现在这样硬编码。例，选择完全提交之后结束任务一：<br /><pre name="code" class="xml">&lt;ControlRule Mode="Choice">
    &lt;Choice Result="Complete">
        &lt;Then>
            &lt;Task ID="1" Action="End" Mode="auto" />
        &lt;/Then>
    &lt;/Choice>
&lt;/ControlRule></pre> <br /><br />这里Mode="auto"意为系统自动处理，不需要产生待办项。接下来是关于任务2的产生，它与Choice并行关系的，而且是任务一提交后必然无条件产生的，故命名为Unconditional：<br /><pre name="code" class="xml">&lt;ControlRule Mode="Choice" />
&lt;ControlRule Mode="Unconditional">
    &lt;Task ID="2" Action="Start" Mode="manual" />
&lt;/ControlRule> </pre><br /><br />这里的Mode="manual"表示会生成一条待办项，到达指定办理人处。对于最后任务4启动的验证：<br /><pre name="code" class="xml">&lt;ControlRule Mode="Conditional">
    &lt;Condition>
        &lt;Task ID="1" Status="Completed" />
        &lt;Task ID="2" Status="Completed" />
        &lt;Task ID="3" Status="Completed" />
    &lt;/Condition>
    &lt;Then>
        &lt;Task ID="4" Action="Start" Mode="manual" />
    &lt;/Then>
&lt;/ControlRule> </pre><br /><br />至此，已经基于规则实现了这个流程，其中的三条规则是：选择型、条件型、无条件型；进一步了解之后再进行补充。下一次，将围绕任务进行面向行为的分析，核心问题还是办理人的持久化目的地。
          <br/>
          <span style="color:red;">
            <a href="http://rcfans.javaeye.com/blog/211943#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 05 Jul 2008 22:49:03 +0800</pubDate>
        <link>http://rcfans.javaeye.com/blog/211943</link>
        <guid>http://rcfans.javaeye.com/blog/211943</guid>
      </item>
      <item>
        <title>面向变化的业务流程控制</title>
        <author>RCFans</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rcfans.javaeye.com">RCFans</a>&nbsp;
          链接：<a href="http://rcfans.javaeye.com/blog/211941" style="color:red;">http://rcfans.javaeye.com/blog/211941</a>&nbsp;
          发表时间: 2008年07月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          新的需求是客户希望能够“提前启动一些工程阶段”——以前是客户定好了整个流程，全部按照既定的规则运行。 <br /><br />这个也能够理解，跟我们开发一样，真正进入开发阶段，并不完全是按照详细设计进行，也未必按照开发计划走，需求有变化的东西都要搁置，先开发已确定的东西，只管按里程碑交付就行了。 <br /><br />加入这个功能的目的是为了让“计划跟得上变化”，还好目前的流程引擎是基于有限状态机的，功能的扩展不会引起整个引擎的逻辑改变。 <br /><br />随着这个项目的深入，感觉客户是在不断的成长=_+前些天他们提出了可能的需求：为两个并行的下一步待办任务指定不同的待办人。 <br /><br />连同上一个需求，昨天想到一个比较可怕的问题：如果客户提出在每一个执行步骤都能够自定义一步或多步下一系列步骤怎么办？ <br /><br />PM同志说：那是不可能的，岂不是意味着我们的流程引擎失去了作用？ <br /><br />哈哈，对于现在有流程引擎，可能是失去了作用，但是“死流程引擎”上线后可能会马上失去对客户的作用才是真的。 <br /><br />流程引擎的一个重要功能是解释流程规则，目前大多数Workflow、BPM提供的建模工具和我设计的配置工具就是建立这样一个流程规则，然后布署，运行，对每一次运行进行一个规则持久化，以保证新规则不影响旧数据。如果需要更改，就得重新建流程规则，再布署。 <br /><br />纵观软件工程的发展，从面向对象、面向行为、面向方面、面向事件等编程思维，逐渐上升到面向服务、面向领域、面向流程的业务思维，其根本目的就是实现更灵活的业务改变，统一的口号都是“拥抱变化”。基于事件编程的好处是，把具体执行什么步骤，推迟到运行时刻。 <br /><br />流程引擎也需要做到在执行时刻能够重定义流程，如果权限和规则允许的话。这也就满足了在发生变化的时刻跟踪并进行改变。再变态一点是实现跨流程任务，由用户决定把哪一些自己的待办任务合并（Workflow Pattern中的Merge）到一起处理，举个形象的例子是去洗手间的同时把喝咖啡的杯子拿去洗了^O^而不是跑两趟~ <br /><br />本来这两天的任务是解决多任务不同处理人的问题，直接需要解决的是把处理人当作流程数据好，还是业务数据好？号称最灵活的OSWorkflow也没有解决这个问题……到现在都还没个定论，却噼哩叭啦引出这么多。
          <br/>
          <span style="color:red;">
            <a href="http://rcfans.javaeye.com/blog/211941#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 05 Jul 2008 22:41:36 +0800</pubDate>
        <link>http://rcfans.javaeye.com/blog/211941</link>
        <guid>http://rcfans.javaeye.com/blog/211941</guid>
      </item>
  </channel>
</rss>