程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Rational >> 在Rational Software Architect或……中使用JET2實現模型驅動架構

在Rational Software Architect或……中使用JET2實現模型驅動架構

編輯:Rational

在Rational Software Architect或Rational Software Modeler中使用JET2實現模型驅動架構

簡介:本文向讀者簡短地介紹了模型驅動架構(MDA),以及能將 UML 建模帶到更高層次的 JET2 技 術,也就是基於 Eclipse 的 Java Emitter Template 技術。您可以使用這個模板來將模型轉換成有用的 工件。

引言

讓我們來探討一下,這種改進會帶來什麼好處嗎?
               —Beach Boys

如果您就要得到一個項目的初始需求文件,或者能夠精確地估計並 設計進而開發,會帶來什麼好處呢?本文告訴您怎樣將一個在 IBM®Rational®Software Architect 中創建的統一建模語言(UML),轉化成一個動態估計和回饋的引擎。感謝在模型驅動架構 (MDA)、設計、靜態非描述性圖形、模型及圖表方面的巨大進步,現在是該執行它們的時候了。 Rational Software Architect 和 IBM®Rational®Software Modeler 是 Java Emitter Templates (JET)及 UML 建模的主要推動者。本文試著超越傳統的代碼生成技術以產生更加有用的系統 ,例如估計系統。

本文中的 JET 項目描述了以下的任務:

在需求與分析階段進行估計

在設計階段將模型 當做成熟的形式估計

生成對模型的回饋

模型提供了一個深刻老到的觀點,以了解怎樣通過 注釋性的 UML 表達業務問題。一個典型的需求收集包含了以下這些構件:

需求與業務行為通過用 例及交流來表達

活動圖顯示的進程及目標建模

通過結構化的模型表達的信息,例如 Class 和 Component 模型

模型隨著時間的增長而不斷地發展和成熟。一個從需求開始的典型模型可能還 會包括結構化的表達交流的分類模型。一個用例模型就是啟動估計過程的完美場。

關於 JET

Eclipse Modeling Framework(EMF),是 Rational Software Architect 的一個完整部分, Rational Software Modeler 包含了生成源代碼與文件的強大工具。其中有一款工具就是 JET (Java Emitter Templates)。有了 JET,您就可以使用像 JavaServer™Pages (JSP)這樣的語法來書寫 模板並運行它們。

前提條件

本文面向的讀者是那些對 Rational Software Architect 有 著詳細了解的人群。作者所做的一個假設是讀者能夠理解 XML、Java™技術,以及 XPATH 腳本語法 以及語義。

首個轉換:來自用例的項目估計

本文的一部分基於 Capers Jones 在其著作中 所描述的發現,這本書就是《估計軟件成本:將成本估計帶入現實主義》,第二版。您可以查看這本書的 第 7 章,“來自敏捷項目及新環境的手動估計方法”。他論述一個用例代表了大約 35 個功 能點的平均值,35 只是一個大概值,通常會在 15 及 75 個功能點之間進行變動。1500 個功能點的典型 使用(大約 75000 個 Java 聲明),大約需要 42 個用例圖 。單個用例基本上定義了大約 1785 個 Java 聲明的使用模式。

用例估計是 1998-2001 中的基線。大多數的思想領導權來自 1998 年 Schneider 和 Winters 以及 2001 Alistair Cockburn 。本文假設有一個項目團隊想要使用用例點來估計,這些用例點書寫了目標層 次上的用例。因此每一個用例都有一個目標。用戶目標層次上用例的目標,與業務價值的一個單元相類似 。

用例點是角色總體數量、關系以及用例方法學其他方面的集合體,該用例方法學指示了估計的 項目的值,因此組成了 JET2 估計引擎的基礎。在決定用例點的規模以後,就可以投入精力與日程安排的 規則了。

角色與用例的復雜性

每一個用例都代表 35 個功能點的平均值。圖 1 顯示了一 個在 Rational Software Architect 中創建和概述的簡單項目。

圖 1. 用例的范例

您可以使用表 1 來決定用例與角色未經調整的權重值。

表 1. 計算未經調整的用例點 (角色)

角色類型 描述 權衡因素 角色的數量 總體 簡單的 定義良好 API 的外部系統 1   WF * Number 平均的 使用基於協議界面的外部系統:HTTP 或者 TCP/IP 或者數據庫 2   WF * Number 復雜的 人 3   WF * Number   未經調整的角色權衡     總體

表 2. 計算未經調整的用例點(用 例)

用例類型 描述 權衡因素 用例的數量 總體 簡單的 1-3 交易 5   WF * Number 平均的 4-7 交易 10   WF * Number 復雜的 最少 7 個交易 15   WF * Number   未經調整的用例權重     總體

使用該表來分析一個用例,角色與用例根據主鍵值來進行定型:簡單的,平 均的,或者復雜的。

必須創建一個單獨的 JET 項目以運行 JET 轉換。從 New Project 向導開始 :

從主菜單中,選擇 File > New > Project。

在 JET Transformations 向導中, 選擇 JET Transformation Project。

輸入一個項目名。例如,使用 Estimation。

點擊 Finish。

創建的 JET 含有包含兩個文件的一個模板:

main.jet

dump.jet

因為項目將會處理不同類型的估計,創建兩個單獨的 JET 模板:一個為用例 點分析創建,另一個為類點分析創建。

不同類型的角色與用例的統計包含在 Java 腳本集部分中 :<% %>

代碼會掃描搜索模型中的用例與角色。當代碼在模型中找到它們時,它會檢查構造 型鍵值,並增加相應的遭遇次數,如代碼行 1 所示。

代碼 1. 用例點分析

   
<%--
 // Initialize Variables. 
--%>
<%
int  countUCComplex = 0;
int countUCAverage = 0;
int countUCSimple = 0;
int countActorComplex = 0;
int countActorAverage = 0;
int  countActorSimple = 0;
%>

<%--
 // Get the name of the  model 
--%>
<c:setVariable var="model" select="/Model" />
Project Estimates for Model: <c:get select="$model/@name" />

<% --
 // iterate through all packages
--%>
<c:iterate  select="//Package" var="package" >
 <c:if test = "//Package[self::Package]"  >
Packages: <c:get select="$package/@name" />
 <c:setVariable  select="$package" var="source"/>
 <%--
 // iterate through all use  cases in the package
 --%>
 <c:iterate  select="$package/packagedElement[self::UseCase]" var="useCase" >
 Use Case:  <c:get select = "$useCase/@name" />
 <%-- get the stereotypes --% >
  <c:iterate select="$useCase/eAnnotations" var="stype" >
   <c:iterate select="$stype/details" var="details" >
  <c:setVariable  select="$details/@key" var="key"/>
 Type: <c:get select = "$key" />
  <c:choose>
   <c:when test = "$key = 'complex'">
    <% ++countUCComplex; %>
   </c:when>
   <c:when test =  "$key = 'average'">
   <% ++countUCAverage; %>
    </c:when>
   <c:otherwise>
   <% ++countUCSimple; %>
   </c:otherwise>
  </c:choose>
  </c:iterate>
   </c:iterate>
 </c:iterate>
 <%--
 // Iterate through  all use case actors in the package
 --%>
 <c:iterate  select="$package/packagedElement[self::Actor]" var="actor" >
 Actor: <c:get  select = "$actor/@name" />
 <%-- get the stereotypes --%>
   <c:iterate select="$actor/eAnnotations" var="stype" >
  <c:iterate  select="$stype/details" var="details" >
  <c:setVariable  select="$details/@key" var="key"/>
 Type: <c:get select = "$key" />
  <c:choose>
   <c:when test = "$key = 'complex'">
    <% ++countActorComplex; %>
   </c:when>
   <c:when test =  "$key = 'average'">
   <% ++countActorAverage; %>
    </c:when>
   <c:otherwise>
   <% ++countActorSimple; % >
   </c:otherwise>
  </c:choose>
   </c:iterate>
  </c:iterate>
 </c:iterate>
  </c:if>
</c:iterate>
**Totals** 

Simple Use Cases:  <%= countUCSimple %>, UC Weight: <%= countUCSimple*5 %>
Average Use  Cases: <%= countUCAverage %>, UC Weight: <%= countUCAverage*10 %>
Complex Use Cases: <%= countUCComplex %>, UC Weight: <%=  countUCComplex*15 %>
Simple Actors: <%= countActorSimple %>, Actor  Weight: <%= countActorSimple*1 %>
Average Actors: <%= countActorAverage  %>, Actor Weight: <%= countActorAverage*2 %>
Complex Actors: <%=  countActorComplex %>, Actor Weight: <%= countActorComplex*3 %>

計算全部未經調整點及個人時間

全部未經調整點是所有個人部分的總結:

未經調整的用例 點(UUCP) = 未經調整的角色權重(UAW) + 未經調整的用例權重(UUCW),因此:

UUCP = UAW + UUCW

為了計算個人時間,您必須計算技術方面的復雜性及環境,如代碼行 2 所示。

清 單 2. 計算未經調整的用例點

<% int totalWeight = countUCSimple*5 +
  countUCAverage*10 +
  countUCComplex*15 +
  countActorSimple*1 +
  countActorAverage*2 +
  countActorComplex*3;
%>
Unadjusted Use  Case Points = <%= totalWeight %>

假設您安裝了 Technical Complexity Factor 1.075 版本、Experience Factor 0.545 版本及 Experience / Stability Index 7 版本,那麼 現在您就可以按照代碼行 3 中所示的那樣計算個人時間。

清單 3. 未調整的個人時間

<% double personHours = (20 * totalWeight) * 1.075 * 0.545; % >
Unadjusted Person Hours = <%= personHours %>

您可以將 Person Hours 分配給不同的 IBM®Rational Unified Process®(RUP®)階段,如代碼行 4 中的范例所示。

清單 4. 分配給不同的階段

Project Life Cycle
Inception (5%) = <%= personHours*0.05 %> Hours
Elaboration (20%) =  <%= personHours*0.2 %> Hours
Construction (65%) = <%= personHours*0.65  %> Hours
Transition (10%) = <%= personHours*0.1 %>  Hours

擴展的轉換:類點分析

類點方法提供了系統層次的估計。Class Point 方法 的基本想法最初是由 Costagliola、Ferrucci, Tortora 和 G. Vitiello 提出的。提出這種方法的目的 是,提供一種方法我們可以用來在開發的階段不斷地精化估計,並利用新的信息直到它們可用為止。

因為功能點需要不斷地處理包含用例的規格,所以還可以從中得到一些初步的數據。

用戶 類的識別與歸類

在類點統計的第一步期間,會分析設計規格以識別類並為它們歸類。

決定 類的復雜性

External Methods 告訴您了類界面的規模。這個規模由本地定義公共方法的數量決定 。服務請求提供了不同系統工件聯系的評價方法。它同樣適用於單個類,並由其他類請求的不同服務的數 量決定。

計算總的未調整類點

Class 模型及 Interaction 圖回溯至前面描述的用例,如 圖 2 和圖 3 所示。

圖 2. Class 模型

圖 3. Interaction 圖

表 3. 所請求外部方 法及服務的復雜性及權衡

權衡 復雜性 最多 8 個外 部方法及單個服務請求 簡單的 最少 8 個的單個服務請求 平均的 最多 4 個服務請求上最多 4 個的外部方法 簡單的 最 多 4個服務請求上 5 個到 8 個的外部方法 平均的 最多 4 個服務請求上最 少 8 個外部 方法 高的 4 個或者更多服務請求上最少 4 個外部方法 平均的 所有其他的 高的

接下來的一 步涉及到了從以上描述的各種模型(用例、類模型及顯示信息流的交流圖)中進行的計算。JET 模板中的 代碼行 5 負責進行這項工作。它實現了一個 Java 扇區以存儲需要的數據。文中還描述了在模板和 Java 代碼之間共享數據的一些非常有意思的方法。如代碼行 5 所示,代碼首先通過了 Class 模型,然後通過 了 Interaction 模型,隨後又計算外部方法和服務請求 。

清單 5. 類點分析

<%@jet imports="java.util.*" %>
<%
class Additions {
 public String className;
 public int nem;
 public int nsr;
  public String lifeLine;
}

java.util.Vector modelClass = new  java.util.Vector();
java.util.Vector l = new java.util.Vector();

% >
<c:setVariable select="/Model" var="modelName" />
Model Name:  <c:get select="$modelName/@name" />
<c:iterate select="//Package"  var="package">
 Package Name: <c:get select="$package/@name" />
  <%-- Iteration through all classes --%>
 <c:iterate  select="$package/packagedElement[self::Class]" var="class" >
 Class: <c:get  select="$class/@name" />
 <c:setVariable var="clName" select="$class/@name"  />
 <% int nems = 0; %>
 <c:iterate  select="$class/ownedOperation" var="oper" >
  Operation: <c:get  select="$oper/@name" />
  Visibility: <c:get select = "$oper/@visibility"  />
  <c:if test="$oper/@visibility='public'" >
  <% ++nems;  %>
  </c:if>
 </c:iterate>
 <c:if  test="$class/ownedOperation">
 <%
  Additions a = new Additions();
  a.className = org.eclipse.jet.xpath.XPathUtil.xpathString
  (context.getVariable("clName"));
  a.nem = nems;
  modelClass.addElement (a);
 %>
 </c:if>
 </c:iterate>
 <%-- Iteration  through all Interactions --%>
 <c:iterate select="$package/packagedElement [self::Collaboration]" var="collab" >
 Collaboration: <c:get  select="$collab/@name" />
 <c:iterate select="$collab/ownedBehavior [self::Interaction]" var="interact" >
  Interaction: <c:get  select="$interact/@name" />
  <c:iterate select="$interact/lifeline"  var="lline" >
  <c:setVariable var="llName" select="$lline/@name" />
  Lifeline: <c:get select="$lline/@name" />
   Represents: <c:get  select="$lline/represents/@name" />,
  <c:get  select="$lline/represents/type/@name" />
   <c:setVariable var="repClass"  select="$lline/represents/type/@name" />
  <%
   boolean notFound =  true;
   for (int i = 0; i < modelClass.size(); i++) {
    Additions a = (Additions) modelClass.elementAt(i);
   String repClassName =  org.eclipse.jet.xpath.XPathUtil.xpathString
  (context.getVariable("repClass"));
   if (repClassName.equals(a.className)) {
    a.lifeLine =  org.eclipse.jet.xpath.XPathUtil.xpathString
  (context.getVariable("llName"));
    modelClass.setElementAt(a, i);
    notFound = false;
   }
   }
   if (notFound) {
   Additions a = new Additions();
    a.className = org.eclipse.jet.xpath.XPathUtil.xpathString
 (context.getVariable ("repClass"));
   a.lifeLine = org.eclipse.jet.xpath.XPathUtil.xpathString
  (context.getVariable("llName"));
   modelClass.addElement(a);
   }
   %>
  </c:iterate>
  <c:iterate select="$interact/fragment"  var="frag" >
  Fragment (covered): <c:get  select="$frag/covered/@name" />
   <c:setVariable var="llname"  select="$frag/covered/@name" />
   <c:if test="$frag/message">
    Message: <c:get select="$frag/message/@name" />
   Type: <c:get  select="$frag/message/@messageSort" />
   <c:if  test="$frag/message/@messageSort='synchCall'">
    <%
    String  lifeLine = null;
    for (int i = 0; i < modelClass.size(); i++) {
     Additions a = (Additions) modelClass.elementAt(i);
     lifeLine  = org.eclipse.jet.xpath.XPathUtil.xpathString
  (context.getVariable("llname"));
     if (lifeLine.equals(a.lifeLine)) {
     ++a.nsr;
      modelClass.setElementAt(a, i);
     }
    }
    %>
    </c:if>
   </c:if>
   <c:if test="$frag/start">
    Start: <c:get select="$frag/start/message/@name" />
   </c:if>
   <c:if test="$frag/finish">
   Finish: <c:get  select="$frag/finish/message/@name" />
   </c:if>
   </c:iterate>
  <c:iterate select="$interact/message" var="msg" >
  Message: <c:get select="$msg/@name" />
   Receive Event: <c:get  select="$msg/receiveEvent/message/@name" />
   Send Event: <c:get  select="$msg/sendEvent/message/@name" />
  </c:iterate>
  </c:iterate>
 </c:iterate>
</c:iterate>

Totals:
<%
int countSimple = 0;
int countAverage = 0;
int countComplex =  0;
for (java.util.Enumeration e = modelClass.elements(); e.hasMoreElements();)  {
 Additions a = (Additions) e.nextElement();
%>
Class: <%=  a.className %>, NEMS <%= a.nem %>, Lifeline <%= a.lifeLine %>,
  NSR <%= a.nsr %>
<%
 if ((a.nem <= 8) && (a.nsr  <= 1)) ++countSimple;
 else if ((a.nem <= 4) && (a.nsr >=  2) && (a.nsr <= 3)) ++countSimple;
 else if ((a.nem <= 4)  && (a.nsr > 3)) ++countAverage;
 else if ((a.nem >= 5)  && (a.nem <= 8) && (a.nsr >= 2) && (a.nsr <= 3))  ++countAverage;
 else if ((a.nem > 8) && (a.nsr >= 2)  && (a.nsr <= 3)) ++countAverage;
 else ++countComplex;
}
% >

Counts:
Simple: <%= countSimple %>
Average: <%=  countAverage %>
Complex: <%= countComplex %>

<%
 int  tucp = (countSimple * 5) + (countAverage * 8) + (countComplex * 13);
% >
TUCP (Total Unadjusted Class Points) = <%= tucp %>
</c:log>

在您知道全部的未調整點之後,就很容易添加其他的因素以達到未經調 整的私人時間,就像您對用例點分析所做的那樣。

總結及其他的選項

本文帶著您浏覽了 UML 模型的一些關鍵區域,以及怎樣獲取、轉化以及創建添加至智能報告的工件。您可以使用 BIRT (業 務智能和報告)來做相似的獲取工作。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved