方法: 找到 jstudio.jar 包中, 反編譯包中 com.m7.wide.A.G, com.m7.wide.A.N, com.m7.wide.eclipse.license.ui.LicenseUIManager 三個主要文件,再反編譯 com.m7.wide.A.A.B 替換成 com.m7.wide.A.BB(在 com.m7.wide.A.G.java中的 B換成BB這樣就可以編譯了),上面三個主要文件中, G中public static H A(String s1,String s2,String s3) 和public static H B(String s, String s1, String s2)很重要,G用來據判斷創建N,N為LICENSE的實現,在N中的P變量為限制日期, N中變量參考: L = "qcfqBUugu2D79g1ZJBDDqA==0000";
A="0000";
I="02";
T="21";
K="trial";
N="S-1-5-21-1078081533-436374069-1343024091";
H= new Date();
P=new Date(System.currentTimeMillis()+10*24*3600*1000l);
C="__anonymoustrial__32847@m7.com";
J=true;
這是trial版本,對應G.A中來創建,如果不是G.B中創建(同時注意public static boolean G(Properties properties)為false), 在LicenseUIManager中verifyLicense直接修改成return true 這樣啟動時就不會檢測,但要以用它前18行進行自己破解的檢驗. 祝大家好運.
NitroX for jsf ide 一個可做為Eclipse的插件,包括上下文敏感的源碼編輯、支持即拖即放的所見即所得的設計、錯誤檢測、debugging工具、以及一些其他的JSF開發的Eclipse視圖,使用起來感覺還不錯。
下載地址
http://www.m7.com/m7secure/secure/ExpressNitroXStrutsJsfTrialInstall-463.zip?m7key5=458575972227127_747927165746785
關于如何破解,另見說明。
實現圖形JSF組件--很簡單地構建一個純HTML無法輕松實現的圖形Web應用程序組件
開發人員認為,如果有合適的工具來創建交互式Web界面,他們就能將時間集中在核心需求和定制上,并在規定時間內及時得交付應用程序。與其他技術如JavaServer Pages或Apache Struts 相比,JavaServer Faces (JSF)技術為創建交互式Web應用程序帶來了很多便利。JSF在程序邏輯和GUI表示之間劃出一條清晰的界限,提高了對Web程序的維護能力,并為Web用戶界面組件的開發和重用提供了一個框架。
如今,許多Web應用程序開發人員都在轉而使用JSF,但是他們發現,預先定制的JSF UI組件受到基本DHTML窗口部件的限制。監管或業務流程監控之類的高級應用程序需要能與JSF框架兼容的高級可視化組件。JSF框架的標準化使它易于開發能夠重用的自定義Web GUI組件。另外,Web組件開發商現在能提供更復雜的組件,并承諾Web應用程序開發人員能夠輕松地使用這些組件。此類JSF用戶界面組件必須集成并部署到JSF運行時框架中去,并在其中完全展開,還必須在設計時很好地集成到提供JSF支持的IDE中去。
盡管JSF帶來了標準用戶界面框架,但對于開發第一個自定義JSF組件而言,還是存在幾個缺陷和漏洞。讓我們看看怎樣創建一個純HTML無法輕松創建的圖形JSF組件。圖形JSF組件的特點不僅要求生成DHTML,而且還需要對圖像生成和客戶端交互提供補充支持。我們將以一個圖形組件的例子來闡述這些特點。該圖形組件能夠提供曲線圖,并為各種客戶端導航和交互提供便利。我們還會了解到將該圖形組件集成到JSF-enabled IDE中所需要的步驟。通過理解圖形組件的設計方法,您將會更好地理解如何實現JSF組件,而這應該能使您開發出定制的JSF圖形組件。
什么是JSF?
JSF是一種能夠簡化Web應用程序表示層結構的標準服務器端框架。定義JSF框架的JSR 127(參見參考資料)帶有一個能提供基本UI組件(如輸入欄和按紐)的參考實現。您可以將可重用用戶界面組件集中起來創建Web頁,將這些組件綁定到應用數據源上,并用服務器端事件控制程序處理客戶端事件。根據說明書介紹,組件供應商能編寫與JSF運行時框架集成的組件,并將其集成到在設計時與JSF兼容的IDE中去。
從很大程度上講,JSF組件同在HTML 2.0技術要求下可用的HTML組件和標簽直接相符合。對許多Web應用程序而言,這套相對簡單的組件是夠用的。然而,許多應用程序如監管或監控程序需要更復雜的數據顯示與交互,比如制表、制圖和映射。由于JSF組件在HTML中直接提交復雜圖形小部件的能力有限,所以設計這些高級組件的能力并不突出。解決方案要求服務器端組件向客戶傳輸圖像,卻會給自身帶來問題,因為在基本HTML圖像上進行交互要受到限制。最后,使用JavaScript時,必須能調用客戶端交互來使用戶能對數據進行導航和交互。
讓我們看看開發一個簡單的、將CSS輸入HTML頁面的JSF組件需要哪些步驟。當開發高級JSF圖形組件時,這一簡單組件的描述和代碼樣本會作為背景。圖1顯示了如何使用即將開發的組件,并顯示將要得到的結果。使用這種組件的好處是能夠通過改變某個JSF動作的組件值,來改變整個頁面的外觀。
圖1:顯示了我們如何使用一個非常簡單的JSF組件將CSS輸入某個HTML頁面并得出結果。
開發組件
JSF組件包含若干個Java類和配置文件。為創建一個自定義JSF組件,您需要開發一個擴展JSF基本組件類的Java類;為默認呈現軟件包開發呈現程序;開發一個將在JSP頁面中用于描述標簽的Java類;編寫一個標簽庫定義(TLD)文件;編寫JSF配置文件。讓我們更深入地了解這5個步驟。
開發組件Java類。組件類負責管理代表組件狀態的屬性。因此,我們必須根據組件的行為(如輸入組件或輸出組件),給組件選擇適當的基類(參見清單1)。這里描述的組件可進行擴展javax.faces.component.UIOutput,以顯示指向某個樣式表文件的URL,或內聯式樣式表的內容。該組件可用于在JSF動作中將某個樣式表轉換成另一個樣式表。關聯屬性規定著值的類型:要么是一個URL,要么是內聯樣式。該組件還必須能夠在向服務器發送請求期間,使用經過JSF框架處理的對象,來存儲并修復自己的狀態。組件的狀態由重建對象所需的重要屬性值組成。JSF框架自動調用saveState()和restoreState()方法,我們可以在組件中實現這兩種方法來達到這一目標。
清單1. 組件類管理顯示組件狀態的屬性。可依據組件的行為,為其選擇一個適當的基類。在本例中,該組件擴展javax.faces.component.UIOutput,以顯示指向某個樣式表文件的URL,或者某個內聯式樣式表的內容。
import javax.faces.component.*;
public class CSSComponent extends UIOutput {
private Boolean link;
public String getFamily() {
return "faces.CSSFamily";
}
public boolean isLink() {
if (link != null)
return link.booleanValue();
ValueBinding vb = getValueBinding("link");
if (vb != null) {
Boolean bvb = (Boolean) vb.getValue(
FacesContext.getCurrentInstance());
if (bvb != null)
return bvb.booleanValue();
}
return false;
}
public void setLink(boolean link) {
this.link = new Boolean(link);
}
public Object saveState(FacesContext context) {
return new Object[] { super.saveState(context),
link };
}
public void restoreState(FacesContext context,
Object stateObj) {
Object[] state = (Object[]) stateObj;
super.restoreState(context, state[0]);
link = (Boolean) state[1];
}
}
開發呈現程序。呈現程序有兩個作用。第一,呈現程序負責發送適當的HTML程序段,該程序段能在客戶端中呈現組件。通常情況下,這個HTML程序段由一些適于呈現整個Web瀏覽器的HTML標簽組成。此JSF生存周期稱作編碼階段或呈現—響應階段。該響應階段還能發送增強客戶端交互性的JavaScript代碼。
呈現程序的第二個作用是解析來自客戶端的數據,從而對服務器端的組件狀態進行更新(如用戶在文本字段輸入的文本)。標準呈現程序軟件包具有強制性,但也可以提供其他呈現程序軟件包,用于提供可替換的客戶端表示法或SVG之類的語言(參見參考資料)。通過檢驗組件的連接屬性,您實現的呈現程序(參見清單2)將選擇在HTML頁面中發送的CSS樣式。
清單2. 標準呈現程序軟件包具有強制性,但是,您可以使用其他呈現程序軟件包,來提供可替換的客戶端表示法或語言。通過檢驗組件的連接屬性,您實現的呈現程序將選擇在HTML頁面中發出的CSS樣式。
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;
public class CSSRenderer extends Renderer {
public void encodeEnd(FacesContext context,
UIComponent component)
throws IOException {
super.encodeEnd(context, component);
if (component instanceof CSSComponent) {
CSSComponent cssComponent =
(CSSComponent) component;
String css = (String)cssComponent.getValue();
boolean isLink = cssComponent.isLink();
if (css != null)
if (isLink)
context.getResponseWriter().write(
"<link type='text/css' rel='stylesheet'
href='" + css + "'/>");
else
context.getResponseWriter().write(
"<style>;\n" + css + "\n<style/>\n");
}
}
}
開發標簽類。同樣,JSF框架提供了用于擴展的基類,來編寫與組件相關的標簽。該標簽類負責定義并呈現將在faces-config.xml文件中應用的組件樣式(這種樣式的描述很簡短)。它還負責創建JSF組件(由JSF框架來處理),傳遞JSF標簽中所包含的屬性,該屬性用于初始化組件(參見清單3)。
清單3. 該標簽類定義了將在faces-config.xml文件中應用的組件的樣式和組件呈現方式。
import javax.faces.webapp.UIComponentTag;
public class CSSTag
extends UIComponentTag {
private String value;
private String link;
public String getComponentType() {
return "faces.CSSComponent";
}
public String getRendererType() {
return “HTML.LinkOrInlineRenderer";
}
protected void setProperties(UIComponent component) {
super.setProperties(component);
Application app =
getFacesContext().getApplication();
if (value != null)
if (isValueReference(value))
component.setValueBinding("value",
app.createValueBinding(value));
else
component.getAttributes().put("value", value);
if (link != null)
if (isValueReference(link))
component.setValueBinding("link",
app.createValueBinding(link));
else
component.getAttributes().put("link",
new Boolean(link));
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
該標簽提供setter和getter來管理鏈接和值屬性。組件一旦創建,便會調用setProperties()方法,對標簽屬性進行初始化。每個標簽屬性都無外乎兩種:要么是文字值,要么是bean屬性的一個綁定。
編寫標簽庫定義(TLD)。TLD是一個XML文件,它通過將標簽名與相應的Java類相關聯來描述標簽。TLD還描述了標簽所允許的屬性(參見清單4)。這個TLD定義了一個名為css的標簽,該標簽綁定到CSSTag類。它還聲明了鏈接和值標簽屬性。
清單4. TLD是一個通過將標簽名與相應的Java類相關聯來描述標簽的XML文件。TLD定義了名為css的標簽,使其與CSSTag類綁定。它還聲明了鏈接和值標簽屬性。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC
"-//Sun Microsystems, Inc.//
DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>custom</short-name>
<uri>http://www.ilog.com/jviews/tlds/css.tld</uri>
<description>This tag library contains a tag for a
sample custom JSF Component.</description>
<tag>
<name>css</name>
<tag-class>path.to.CSSTag</tag-class>
<description>A component that displays the style
inline or a link a to a css file</description>
<attribute>
<name>id</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<type>java.lang.String</type>
<description>The id of this component.
</description>
</attribute>
<attribute>
<name>binding</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<type>java.lang.String</type>
<description>The value binding expression
linking this component to a property in a
backing bean. If this attribute is set, the
tag does not create the component itself but
retrieves it from the bean property. This
attribute must be a value binding.
</description>
</attribute>
<attribute>
<name>value</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
<type>java.lang.String</type>
<description>The inline css text or the url to
the css file to link.</description>
</attribute>
<attribute>
<name>link</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<type>java.lang.String</type>
<description>Whether the value is a link or
the inline style.</description>
</attribute>
</tag>
</taglib>
編寫JSF配置文件。為了將某個JSF組件集成到框架中,您必須提供一個名為faces-config.xml的配置文件。該文件將組件類型和呈現程序類型(用于JSP定制標簽處理程序)與對應的Java類關聯起來。它還能描述與每個組件一同使用的呈現程序(參見清單5)。該文件定義了faces.CSSFamily組件家族。在本例中,該家族由faces.CSSComponent這一個組件類型(該類型與CSSComponent類綁定)組成。最后,HTML.LinkOrInlineRenderer類型的呈現程序(由CSSComponent類實現)要與faces.CSSFamily家族相關聯。
清單5. 該文件將組件類型和呈現程序類型與對應的Java類聯系起來,并描述與每個組件一同使用的呈現程序。它還定義了faces.CSSFamily組件家族。
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//
DTD JavaServer Faces Config 1.0//EN"
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<faces-config>
<component>
<component-type>faces.CSSComponent
</component-type>
<component-class>path.to.CSSComponent
</component-class>
<component-extension>
<component-family>faces.CSSFamily
</component-family>
<renderer-type>HTML.LinkOrInlineRenderer
</renderer-type>
</component-extension>
</component>
<render-kit>
<renderer>
<component-family>faces.CSSFamily
</component-family>
<renderer-type> HTML.LinkOrInlineRenderer
</renderer-type>
<renderer-class>path.to.CSSRenderer
</renderer-class>
</renderer>
/render-kit>
</faces-config>
開始制圖
如果您希望將自己的組件集成到JSF-enabled IDE中,您還可以提供補充說明。比如說,除提供其他的設計時信息外,還可以提供一個名為sun-faces-config.xml的XML配置文件,用于描述應在IDE中公開的組件屬性。
既然已經看到如何創建一個簡單的JSF組件,不妨再來看看怎樣創建一個圖形JSF組件。我們將遵循同樣的基本步驟來設計一個高級JSF圖形組件。讓我們以一個圖形組件(如ILOG JSF圖形組件)為例,通過一組分類,該組件為數據值分布提供了可視化表示。該圖形能夠以條型統計圖、圓形分格統計圖和氣泡式統計圖等各種顯示方法來顯示數據集合。該JSF圖形組件有兩個初始設計限制:
我們已經擁有Java圖形bean組件,它具備所有圖形顯示能力。該組件可以顯示很多圖形,而且可定制性很高。在理想情況下,我們希望利用bean組件,使用它的功能來構成我們的JSF組件的基礎。
普通JSF應用程序需要重新載入整個頁面以更新視圖。這種方法適合基于表單的應用程序,但在很多情況下卻不適用于高度圖形化的用戶界面。因此,我們的JSF圖形組件必須能在不更新整個頁面的前提下處理某些簡單的導航,以提供更好的用戶體驗。
以下是滿足這些需求的解決方案:該JSF圖形組件將管理圖形bean組件,包括創建圖形bean、定制該bean以及使該bean可用于服務器端操作。呈現JSF組件將分為兩個階段完成。JSF呈現程序會產生一個<img>標簽和一套JavaScript對象(參見圖2)。客戶端將請求服務器發回一張圖像。這一請求由某個servlet完成,該servlet獲得圖形bean,并利用圖形提供的方法生成一幅圖像(參見圖3)。任何只改變該圖形外觀的進一步用戶交互(放大、掃視、更改樣式表等)都會引起圖形的一次增量更新。如果客戶端不只是要求對圖形圖像進行更新,那么將提交該頁面(參見圖4)。
圖2JSF圖形組件管理圖形bean組件,包括創建圖形bean、對其進行定制,并使其可用于服務器端動作。JSF呈現程序生成一個<img>標簽和一套JavaScript對象。
圖3 客戶機通過servlet要求服務器獲得一張圖像。該servlet獲得圖形bean,并通過由圖形提供的方法生成一幅圖像。
圖4如果客戶端不只是要求對圖形外觀的進行更新,那么頁面將被提交。
JSF圖形組件還配有一套附加的JSF組件。overview可顯示該圖形整體視圖,顯示一個代表圖形視圖的長方形,還應允許用戶掃描可視區域。legend組件可顯示數據集合的相關信息,還能自行在圖形中顯示,依被顯示數據的樣式而定。也能提供客戶端的interactors如掃描和放大,這些功能可看成是客戶端交互,表示與圖形的交互不會像一次正常的JSF交互那樣重新載入整個頁面。
要想呈現圖形組件,只需使用chartView標簽:
<jvcf:chartView id="c" style="width:500px;height:300px" … />
該數據在HTML頁面中作為圖像顯示。該圖像由servlet創建,旨在響應一次HTTP請求(該請求包括指定結果圖像、生成圖像映射以及生成內聯式圖例等各種參數)。結果圖像隨之被嵌入客戶端DOM,頁面中只有圖像自身這一部分被更新。
應用程序核心部件
讓我們看看簡單的定制JSF組件和高級圖形組件之間的一些區別。JSF圖形組件類很像一個標準組件,不過是多了一個可訪問圖形bean(該圖形bean負責生成在HTML頁面中顯示的圖像)的圖形屬性。JSF組件可以通過某個綁定值或在當前會話中對這個圖形bean進行局部檢索。當JSF圖形組件成為某個應用程序的核心部件時,可選的JSF組件(如概覽或圖例)便與主圖形相關聯,來顯示附加信息(見清單6)。
清單6. 當JSF圖形組件成為某個應用程序的核心部件時,可選的JSF組件便與主圖形相關聯,來顯示附加信息。
<jvcf:chartZoomInteractor id="chartZoomInteractor"
XZoomAllowed="true"
YZoomAllowed="true" />
<jvcf:chartView id="chartView"
chart="#{myBean.chart}"
servlet="demo.ImageMapServlet"
interactorId="chartZoomInteractor"
width="500"
height="300"
styleSheets="/data/line.css"
waitingImage="data/images/wait.gif"
imageFormat="PNG" />
<jvcf:chartOverview id="chartOverview"
style="height:100;width:150px"
viewId="chartView"
lineWidth="3"
lineColor="red" />
<jvcf:chartLegend id="legendView"
viewId="chartView"
width="400"
height="180"
layout="vertical"
waitingImage="data/images/wait.gif" />
呈現程序是實現這個JSF的一大難點。如前所述,呈現程序并不生成簡單的HTML,而是生成由HTML(<IMG> tag)和JavaScript proxy(代理程序)組成的動態HTML(DHTML)。
Proxy是一個負責管理客戶機組件圖像顯示的JavaScript類實例。該對象是服務器端Java組件類在客戶端顯示;它與組件類具有相同屬性。頁面上的每個組件、圖形及其配件都有一個proxy實例。呈現JavaScript時,在每個可視的JavaScript變量上使用facesContext.getExternalContext().encodeNamespace(name)方法是個很好的實踐。這樣做在今后方便地將組件集成到到JSR 168-compliant端口環境中。
為舉例說明客戶機上的proxy,必須在頁面上導入JavaScript支持庫。為保持客戶端盡量瘦,需要基于JavaScript庫支持的proxy類,對JavaScript庫進行模塊化。因此,需要給每個proxy類輸入一套不同的、有可能重疊的庫。圖形呈現的困難部分,出現在發送這些script庫的階段。每個組件的呈現程序都要聲明自己需要哪個庫,以及什么時候發送引用的庫,必須認清已發送的庫,以避免重復。僅在頁面呈現期間的存在script管理器負責這項篩選工作。每當呈現程序想要發送整套庫輸入時,它都會向篩選出已發送庫的script管理器提供列表。
客戶端proxy的目的在于允許編寫腳本,并避免不必要的頁面更新。一旦呈現了圖形,在客戶端便可使用proxy,以便動態安裝interactor,并顯示或隱藏圖像映射。Proxy對象也可供支持JavaScript鼠標事件處理的常規JSF組件使用。
<jvcf:chartView id=
"chartView" .. />
<h:selectBooleanCheckbox id=
"genImageMap" onclick=
"chartView.setGenerateImageMap(
this.checked ? true : false,
true);" />
對組件客戶端proxy進行局部修改的問題在于,其狀態不再與服務器上的Java組件的狀態同步。為解決這個問題,proxy使用一個隱藏的輸入標簽(<INPUT TYPE="HIDDEN">)來保存客戶機上的新狀態。當執行某個標準JSF動作并提交頁面時,呈現程序將解析該隱藏狀態,使客戶機與服務器同步。這種行為需要呈現程序類中有專門的破解行為。標準破解方法得以改進,以便解析來自客戶機的狀態,并更新服務器端組件的狀態。
測試實例
圖形及其相關組件之間的關聯由標記引用與綁定來完成。為使頁面設計具有靈活性,一個組件可以在呈現之前被引用。因此,在呈現時間內,如果某個組件屬性引用另一個尚未呈現的組件,那么,將延遲發送依賴于客戶機進行解決的JavaScript代碼,直到呈現已引用的組件。此工作可由依賴性管理器完成。
為證實這一點,不妨看一個典型實例,該實例涉及某個概覽,該概覽引用一張圖形。
<jvcf:overview viewId=
"chart" [...] />
<jvcf:chartView id=
"chart" [....] />
存在兩種情況。被引用圖形組件已經呈現,因此不存在任何問題
JSP:
<jvcf:chartView id=
"chart" [....] />
<jvcf:overview viewId=
"chart" id="overview" [...] />
render:
[...]
var chart =
new IlvChartViewProxy ( .. );
[...]
var overview=
new IlvFacesOverviewProxy (
.. );
overview.setView(chart);
[...]
已引用圖形的組件在依賴的概覽組件之前不會呈現。既然如此,可在依賴性管理器上注冊一個組件創建監視器。已引用圖形組件最終呈現時,其呈現程序會通知自己創建的依賴性管理器。此時,將發送解決依賴性所需的代碼:
JSP:
<jvf:overview viewId=
"chart" id="overview" [...] />
<jvdf:chartView id=
"chart" [....] />
render:
[...]
var overview =
new IlvFacesOverviewProxy (
.. );
[...]
var chart =
new IlvChartViewProxy ( .. );
overview.setView(chart);
[...]
開發JSF組件的目的之一,是能夠將它們應用于任何與JSF兼容的IDE。盡管如此,JSF兼容性并不足以保證這種設計時集成將會有效。下面是在開發JSF組件過程中,為了便于在今后與IDE集成需要注意的一些簡單思想:
首先,定制JSF組件應該提供一個基本HTML呈現程序。在設計時,JSF IDE不能呈現請求有效數據或app服務器連接的動態圖形組件。因此,帶有復雜的或非傳統的(比如不是HTML)呈現程序的組件,應該使用Beans.isDesignTime()來確定是提供一個基本HTML表示法,還是提供真正的組件呈現程序。
另一個設計時問題是組件的位置和大小。不同IDE使用不同的標志和屬性。能夠調整大小的組件(如一幅圖像)應能處理定義大小的不同方式。
最后,為了與IDE集成,組件必須提供尚未被JSF說明定義的補充信息。遺憾的是,當前每個IDE都需要特殊處理程序來集成組件,即:在一種情況就需要XML文件,而在另一種情況下需要eclipse插件,如此等等。下一個JSF JSR(2.0版)的主要目的之一,將是指定附加的元數據格式。
如您所見,編寫一個簡單的JSF組件并不難,因為框架已經完成了大部分工作。JSF框架管理著組件狀態、呈現程序等等。在本文中,我們已經擴展了這些基本概念,來設計一個能夠顯示復雜元數據、提供增量更新、支持大量客戶端交互并與配套組件協作的高級圖形JSF組件。支持這些特點需要對基本JSF組件的結構進行許多改進。當然,增量更新的概念今后對JSF框架將是一個很好的完善,因為它只允許呈現頁面已改變的部分,避免了更新整個頁面。按照JSF說明書工作往往不足以確保組件完全集成到JSF IDE中;一個新JSR應能及時解決這些難題。盡管存在缺陷,JSF框架仍能極大地加快Web組件開發速度、方便的融合來自各種資源的組件,以創建完整的、復雜的Web應用程序。
參考資料
作者簡介
Marc Durocher是ILOG的一名軟件架構師,ILOG是企業級軟件組件和服務的主要提供商。Marc Durocher在ILOG負責開發ILOG JViews生產線上的JSF組件。可以通過mdurocher@ilog.fr聯系Marc。
原文出處
http://www.ftponline.com/weblogicpro/2005_03/magazine/features/mdurocher/
Java技術自問世時光已經過去了9個年頭。作為一名一直關注其成長的記者,曾經一段時間有過這樣的想法:“Java技術已經成熟,是不是發展速度該放慢一些了呢”。然而,這種想法錯了。近來Java技術的進化相當顯著。Java技術正在迎來“又一次革命”的風暴。這就是本文的結論。
“又一次”指的是什么?“革命”指的又是什么?光看結論的話肯定是一頭霧水。其實,筆者要講的并不是變化這樣一個事實,而是“促進變化的原動力”。是什么讓Java技術發生變化?讓我們從這一角度出發,先看一下Java的變化歷程。
Java正處于轉變期
回顧Java技術的發展歷程,人們一定會感慨:2004年到2005年發生的變化如此之大,可以說“現在”正是Java技術的轉換期。Java技術由編程語言(Java語言)、運行環境(JVM:Java虛擬機)、框架(Java API群)組成,目前在每一個層面上都發生著巨大的變化。
(1)編程語言的變化
Java語言標準出現明顯變化。在2004年9月發布的正式版本J2SE5.0(J2SE:Java2 Standard, Standard Edition,Java技術的核心運行環境)中,對Java語言標準中的Generics與元數據進行了大幅擴展。出現了被認為是“自Java問世以來的最大一次語言標準變化”(美國Sun Microsystems)。這次語言標準的變化給許多Java API帶來了影響。許多企業API的新版本都引入了基于元數據的注解(程序中記錄的附加信息),以較短的編碼記述更多的信息。
(2)Java運行環境的變化
在J2SE5.0中,大幅度強化了JVM的管理功能與實用性,換句話說就是具備了Java執行OS(操作系統)的特征。例如,原來在J2EE(Java2 Platform, Enterprise Edition,構筑企業系統的Java技術)領域,標準配備有作為管理功能的應用軟件管理框架JMX。不僅如此,還配備有JVM自身監控功能((JSR 174: Monitoring and Management Specification for the Java Virtual Machine)。在標準功能架構中可以實時監視JVM運行時的狀態,也就是內存使用量、線程狀態等。
J2SE5.0中新追加的功能中包括并行處理實用程序(JSR 166),其基礎是紐約州立大學Doug Lea提供的程序庫。也就是說,標準規格中采用了來自民間的程序庫。
(3)框架的變化
服務器端的Java框架也發生了巨大變化。企業級Java技術--J2EE的“使用方法”說明文件“J2EE Blueprint”中,提出了將應用軟件分為Web層、EJB層(Enterprise JavaBeans,將包括事務處理在內的業務進程模塊化的框架)來構筑的思路。這兩種層次都迎來了架構更替時期。Web層的新框架為JSF(JavaServer Faces,將模塊組合起來構筑Web應用程序的框架),EJB層為標準方案中剛剛公布的下一代EJB規格“EJB3.0”。
值得注意的是,促成框架發生變化的正是來自民間的源碼開放軟件。
對JSF產生影響的是作為源碼開放的Web層框架得到普及的Apache Struts。JSF是對Struts的思路進行改進的產物,JSF的Spec Lead(規格制定領袖)之一Craig R. McClanahan就是Struts的作者。
對EJB3.0造成影響的也是民間源碼開放軟件。EJB3.0引入了DI(Dependency Injection,依賴注入)容器類(Container)與POJO(Plain Old Java Object)持久類這些新功能,大大減輕了編程的復雜性。這些概念因PicoContainer、Spring等源碼開放軟件的導入而引人注目。
其背景在于用戶對“目前的EJB過于復雜”的批評。原本由EJB反對派提出的設計思想與源碼開放軟件,卻變成了EJB3.0的中心概念,顯出了巨大的影響力。
(4)腳本語言
在Java技術標準中新增加了編程語言Groovy(JSR 241)。這是一種可與Java語言無縫連接的腳本語言,有望以極短的程序完成相關處理。“在Java技術中添加Java以外的語言”,這聽起來也許有些別扭,其實以前就有這樣的呼聲,希望將可以充分利用Java技術資源的腳本作為語言使用。Groovy本來是源碼開放軟件,最終得到認可,被采納為標準規格。
由上述可以看出,Java技術的構成要素正在發生巨大變化。就在不久以前,一提起服務器Java,“Servlet、JSP、EJB是重要的API”這樣的說明還占主流,但現在基于JSF和EJB3.0的應用程序已經變成了“面目全非”的程序。而在運行短程序或測試時,甚至還出現了不僅是Java語言,連腳本語言都開始調用Java框架的情況。
這些變化從大的方面來看的話,可以說是進一步發揮了Java面向對象的優勢。當然,也包括提高開發效率、提高運行穩定性、簡化運行管理等業務上的優勢。
開發者團體是真正的“變革推動者”
那么,這些變化的原動力來自哪里呢?為什么說“目前”正面臨著“又一次變革”呢?理由如下:
在Java技術的發展過程中,1999年到2000年是一個大的轉折點。J2EE概念于1999年出現。日本國內的J2EE也在隨后2~3年內得到正式普及,但這一技術體系早在5年前就已經確立。在我們眼前,新一代Java技術的輪廓正逐漸顯現出來。
JCP(Java Community Process)2.0于2000年問世。以會員制的組織形式推進Java技術的規格制訂、總體發展方向則以委員會的方式決定。從而形成了不依賴特定企業的規格制訂流程。這一組織形式歷經近5年的時間,逐漸發展成“變革的推動者”。
J2EE此前一直飽受批評,認為“Web層與EJB層的差距太大”、“EJB過于復雜”,但這也是因為這是一項實際使用的技術。JCP同樣也遇到很多批評,稱其“沒有完全公開”、“制定的技術標準卻不可思議地讓Sun擁有知識產權”,但JCP卻作為一個團體不斷發展壯大。
直接推動Java技術變化的當事者為5年前形成的基于團體的標準制訂流程--JCP,但真正將討論與技術納入JCP的卻是包括Java技術批評者在內的眾多Java開發者團體。他們也是早期開展Java技術變革的先行者。由此誕生的下一代技術將會在2~3年后逐漸波及主流企業用戶。
Java技術的“變革推動者”為開發者團體。不受制于特定企業,通過眾多需要Java的開發者的建議,Java技術正在不斷發展進步。(
實現的主要功能是:自動從cvs中check out模塊,然后編譯,把編譯后的class打成jar,再commit到cvs服務器的指定位置。
build.xml
|
<?xml version="1.0"?> <project name="gnt Auto build" basedir="." default="build">
<!-- The CVSROOT value --> <property name="cvsroot" value=":pserver:dhf:@192.168.0.200:D:/cvs_repository_z"/> <property name="cvs.password" value=""/> <property name="ywzcpt.dir" value="${basedir}/ywzcpt"/> <property name="ywzcpt.module.name" value="ywzcpt"/> <property name="zfyw.dir" value="${basedir}/zfyw"/> <property name="zfyw.module.name" value="zfyw"/>
<property name="external.dir" value="${basedir}/external"/> <property name="external.module.name" value="external"/> <property name="cvs-op" value="co " /> <!-- Initializing --> <target name="init"> <tstamp> <format property="today" pattern="yyyy-MM-dd hh:mm:ss"/> </tstamp> <echo message="${today}" /> </target> <target name="prepare" depends="init" > <cvspass cvsroot="${cvsroot}" password="${cvs.password}" passfile="ant-cvs.cvspass"/> </target> <target name="external-check-out" depends="prepare"> <cvs cvsRoot="${cvsroot}" package="${external.module.name}" passfile="ant-cvs.cvspass"/> </target> <!-- Retrieve the ywzcpt module --> <target name="ywzcpt-check-out" depends="external-check-out"> <delete dir="${ywzcpt.module.name}"/> <cvs cvsRoot="${cvsroot}" package="${ywzcpt.module.name}" passfile="ant-cvs.cvspass"/> </target>
<target name="zfyw-check-out" depends="external-check-out"> <delete dir="${zfyw.module.name}"/> <cvs cvsRoot="${cvsroot}" package="${zfyw.module.name}" passfile="ant-cvs.cvspass"/> </target>
<!-- cvs checkout --> <target name="check-out"> <antcall target="external-check-out" /> <antcall target="ywzcpt-check-out" /> <antcall target="zfyw-check-out" /> </target> <!-- build XSP framework --> <target name="build"> <echo message="+=============================================+" /> <echo message="| Start Building GNT for compilation |" /> <echo message="+=============================================+" /> <antcall target="ywzcpt-build" /> <echo message="+=============================================+" /> <echo message="| End Building GNT for compilation |" /> <echo message="+=============================================+" /> </target> <target name="ywzcpt-build" depends="ywzcpt-check-out"> <echo message="+---------------------------------------------+" /> <echo message="| Start Building ywzcpt for compilation |" /> <echo message="+---------------------------------------------+" />
<ant antfile="build.xml" dir="${ywzcpt.module.name}" output="ywzcpt.log" />
<property name="ywzcpt.add" value="add ./build/log/*.log ./build/*.jar ./build/*.war"/> <property name="ywzcpt.commit" value="commit -m '${today}' ./build/log/*.log ./build/*.jar
./build/*.war"/> <ant antfile="build.xml" dir="${ywzcpt.module.name}" target="commit-build" /> <echo message="+---------------------------------------------+" /> <echo message="+ End Building ywzcpt for compilation |" /> <echo message="+---------------------------------------------+" /> </target> <target name="zfyw-build" depends="zfyw-check-out, ywzcpt-build"> <echo message="+---------------------------------------------+" /> <echo message="| Start Building ywzcpt for compilation |" /> <echo message="+---------------------------------------------+" />
<ant antfile="build.xml" dir="${zfyw.module.name}" output="zfyw.log" />
<property name="zfyw.add" value="add ./build/log/*.log ./build/*.jar ./build/*.war"/> <property name="zfyw.commit" value="commit -m '${today}' ./build/log/*.log ./build/*.jar
./build/*.war"/> <ant antfile="build.xml" dir="${zfyw.module.name}" target="commit-build" /> <echo message="+---------------------------------------------+" /> <echo message="+ End Building ywzcpt for compilation |" /> <echo message="+---------------------------------------------+" /> </target>
<target name="clean" > <delete dir="${ywzcpt.module.name}"/> </target> </project>
|
ywzcpt/build.xml片斷:
|
主要實現commit功能 <target name="commit-build"> <cvs cvsRoot="${cvsroot}" passfile="${root.dir}/ant-cvs.cvspass" command="${ywzcpt.add}"/> <cvs cvsRoot="${cvsroot}" passfile="${root.dir}/ant-cvs.cvspass" command="${ywzcpt.commit}"/> </target>
|
最后,在win2k中制定一個計劃任務,就可以了。
作者: 周思博 (Joel Spolsky)
譯: Chen Bin
2005年1月2日
雖然大概一兩年前我還在夸夸其談桌面應用程序是將來的潮流,大學生們現在還是偶爾向我請教職業發展的問題。所以我把我的建議寫下來。以供學生們閱讀,嘲笑,忽略。
大多數銳氣十足的學生從來不向前輩征求意見。在計算機科學領域,這樣做是正確的。因為前輩們很可能說些“在2010年前,市場對于那些只會敲擊鍵盤的代碼工人的需求將會超過一億(因此前景是樂觀的)”,或者諸如“Lisp語言現在真的很熱門”。
我和那些前輩也差不多,當我給別人建議時,實際上我不知道自己在說些什么。我是如此的落后于時尚,以至于連AIM也搞不明白,而不得不使用 email(恐龍時代的產品,在那個時代,音樂是刻在扁扁的的圓圓的盒子上,噢,那種盒子叫cd)。(譯者按:我認為祖兒這里在說反話,后文很多地方作者都在說反話,讀者盡量理解這種美國式幽默吧。)
所以你最好不要理睬我將要說的,你應該立刻去制作某種在線交友軟件。
然而,
如果你喜歡編程,那就感謝上帝吧:你屬于幸運的少數人,這些人喜歡工作,他們的工作可以保證他們能過上舒適的生活。大多數人沒有這么幸運。對大多數人來說,工作是不愉快的,忍受工作的目的攢錢,是為了在年滿65歲退休后能過上自己想過的生活。如果他們想過的生活不需要靈活的膝蓋,明亮的眼鏡,輕盈的腳步的話。
現在讓我回到主題,我將提供一些建議。
好了,不羅嗦了,下面就是Joel給計算機系學生們七條免費的建議:
- 畢業前學會寫作
- 畢業前學會C語言
- 畢業前學習微觀經濟學(microeconomics)
- 不要因為某些非計算機課程枯燥無趣就敬而遠之
- 學習有大量編程實踐的課程
- 不要擔心工作都跑到印度去了
- 好好做夏季畢業實習
讓我逐條解釋這些建議。但解釋之前我要說明一下,如果因為這些建議是Joel的建議你就打算無條件地接受,以至于連我的理由都想跳過,那么你就太單純,太容易被別人騙了。如果你是那種單純的人,我還要給你第八條建議,找心理醫生咨詢一下如何培養自信(self-esteem)。
畢業前學會寫作
如果Linus Torvalds不懂如何布道的話,Linux會成功嗎? 正象每一個黑客,Linus精通寫作,他知道如何準確地在email和郵件討論組中使用書面英語表達自己的思想,所以他能夠從全世界召集大量志愿者為Linux工作。
你聽說過最近風靡全世界的極限編程(Extreme Programming)嗎? 即使你不懂什么是極限編程,你至少聽說過這個詞。為什么?因為宣傳極限編程的人都是天才的作者和演說家。
就看看你身邊的那些小型的軟件開發組織吧,最有權力和影響力的人是那些可以用自信,準確,舒適的英語交流的人。好吧,我承認這些人也許言過其實,但是你無可奈何。
一個合格的程序員和一個偉大的程序員的區別不在于知道多少種編程語言,不在于他們是喜歡Python或者Java,而是在于他們是否擅長表達。他們能夠說服,所以他們獲得權力。他們能夠寫清楚明白的評論和接口文檔,所以他們使得別人不用重寫,而可以重用他們的代碼,否則他們的代碼就是毫無用處的。他們也能夠寫出清晰的用戶手冊,于是最終用戶可以理解他們的代碼是做什么用的,明白了他們的工作的價值。sourceforge埋葬著許多精美的代碼,這些已死的代碼無人使用,因為代碼的作者很少寫(或者根本不寫)用戶手冊。
我不會雇傭一個不懂寫作的程序員。如果你擅長寫,你就很容易找到工作,緊接著你就會被要求寫技術規格文檔,這意味著你已經被管理層注意到了。
大學里有一些課程,要求你做很多的寫作練習,不要猶豫,趕快參加這些課程。不要錯過任何要求你每周或者每天練習寫作的課程。
給自己建立一個網絡日志(weblog)。在上面寫的越多,你會寫地越容易。寫地越容易,你就寫地越多,這是一個正向地循環激勵。
畢業前學會C語言
我可沒有說是C++。雖然現在用C的工作不多,但是掌握各種編程語言的程序員事實上用C來交流(lingua franca);更重要的是,C比某些“現代”語言更接近機器語言。我不管現在大學里在教什么流行的垃圾語言(trendy junk),你至少得花一個學期接近機器。否則,你不可能使用高級語言寫出高效的代碼。這意味這你不會有機會寫編譯器或者操作系統,也許這是更好的編程工作;別人不會相信你能夠為大項目設計架構。無論你知道多少高級的控制結構,知道如何進行錯誤處理,如果你不能解釋為什么while (*s++ = *t++);的意思是進行字符串拷貝(而且對你而言這是世界上最自然,最易懂的代碼),那么你就是在對編程一竅不通的狀態下編程(programming based on superstition)。打個比方,就好比一個醫生不懂基本的解剖學就給你開處方,如果你問這個醫生為什么開這種藥而不是那種藥,他會說因為醫藥銷售代表說這種藥有用。
畢業前學習微觀經濟學(microeconomics)
我個人對經濟學的一些理解:在經濟學剛誕生的時候,它只是局限于有限的領域,在這些領域中人們發展和發現了很多有用的理論和很有趣的事實,這些理論和事實是從邏輯上是可以證明的。然后, 經濟學開始走下坡路了。 “有限的領域”就是微觀經濟學,它對于商業可以進行有意義的指導。然后,事情就開始變糟了(以下部分你可以跳過),你接下來碰到的是討論諸如失業率和銀行利率之間關系之類東東的宏觀經濟學,很多時候宏觀經濟學討論的理論都是無法證明正確或者錯誤的。接下來事態更加惡化了,經濟學中的一些領域開始和物理學搭界,嗯,學習物理經濟學也許你幫你在華爾街找到好工作。言歸正傳,無論如何請學習微觀經濟學,因為你需要知道什么是“供給和需求”,什么是競爭優勢,什么是凈現值(NPVs,Net Present Value,指項目經濟壽命期內現金流入總和與現金流出總和之差額),什么是折扣和邊際效用(discounting and marginal utility),如果你真想了解商業是如何運作的話。
為什么計算機系的學生要學習經濟學?因為理解商業基本規律的程序員對商業界來說是寶貴的程序員。我記得無數個程序員使我非常沮喪,因為他們在代碼中堅持某些瘋狂的設計,這些設計從技術上來說,完美;從資本主義的角度來看,發瘋。如果你是一個理解商業的程序員,商業會給你回報。這就是你要學習經濟學的原因。
不要因為某些非計算機課程枯燥無趣就敬而遠之
首先,你需要讓你的學分平均分(GPA)看起來漂亮點。
不要低估學分平均分的威力。很多雇主和人事經理(包括我)閱讀簡歷時首先看成績,為什么?因為這代表了大部分的教授在很長的時期內對你的學業的一個平均的看法。托福成績(美國的托福大致相對于我國的高考中的語文考試)?哈,幾個小時的測驗而已。當然學分不一定說明了一切,如果你修的是很難的課程,學分就有可能低一點。即使你的學分平均分很高,我還是要看各科分數是否一致。如果你應聘的是軟件工程師職位,我為什么要關心你在大學里學的歐洲歷史課程分數的高低呢?畢竟,歷史很枯燥。那么要是你要編程的部分也是很枯燥的,你是不是要放棄了?事實上,有時候編程是枯燥的,如果你不能忍受編程中的枯燥部分的話,你就不能完成整個工作,雇主不愿意雇傭你這樣的員工。
我在大學里修過一門叫做“文化人類學”的課程,因為那時候我也搞不懂我到底要學什么,聽起來這么課程可能還蠻有意思的。
出乎我的意料。我不得不閱讀大量講述巴西熱帶雨林中的印第安人如何如何的書,讓人真昏昏欲睡。聽老師講解也好不到哪去,我發覺看教室外的草如何長更有趣點。土著人如何烤蕃薯藤和我有什么關系?我為什么要去討論如何烤蕃薯藤?但是期中考試馬上就要到了,我暗暗下定決心,如果我能跨越“文化人類學”這個障礙,以后也許沒有什么能難倒我了。我決心得A并且得到了A。以后當我不得不坐在林肯中心,連看18個小時的瓦格納的《尼伯龍根的指環》時,我終于明白我為什么要學習“文化人類學”了,相比之下,我也能忍受這種歌劇了。
學習有大量編程實踐的課程
我還記得決定不去讀研究生的那一刻。
就是在學習《動態邏輯》(Dynamic Logic)這門課的時候,我記得是耶魯的Lenore Zuck(一個天才的教師)教的。
修這門課的時候,我已經不再是雄心勃勃了。我可不指望在這么課程中得個A,我夢想的是混個及格。邏輯本質上是很簡單的:如果結論正確,前提必須正確。例如,如果“所有讀書好的人都能找到工作”并且“張三的讀書好”,那么“張三能夠找到好工作”。就這么簡單。
但是我要學的是動態邏輯, 動態邏輯和一般邏輯差不多,但是要考慮時間因素。例如,“在你開燈之后,你可以看見你的鞋子”加上“過去燈被打開了”意味著“你現在可以看到你的鞋子”
動態邏輯學對于象Zuck教授這樣的天才理論家來說非常誘人,因為這門學科的知識也許可以用來證明計算機程序是否正確。我記得在第一堂課上,為了證明“如果你有一盞關著的燈”并且“你按了一下開關”,那么“現在燈亮了”,Zuck教授就使用了兩黑板加上邊上的墻壁。
證明過程難以置信的復雜。我覺得如此復雜的證明過程很可能會有小錯誤,但是我沒辦法證明證明過程本身是正確的。事實上,寫在黑板上的證明跳過了很多中間步驟,許多步的證明使用了演繹法,使用了歸納法,以及一些研究生才懂的證明方法。
作為課后作業,我們需要證明以下命題:如果燈過去是關著的,并且現在它是開著的,請證明有人按了開關
我真的試著證明它了。
我花了許多小時,試圖證明這個命題。
在無數個小時的努力后,我發覺Zuck博士的原始的證明有一個邏輯上的錯誤,也許這個錯誤是我的筆記抄錯了,我不知道。于是我終于認識到,如果為了證明一個簡單的問題需要花三個小時寫下幾黑板的證明步驟,再考慮到這個漫長的證明過程中可能會引入種種錯誤,那么這種機制是不可能用來證明任何有趣的東西的。
對動態邏輯學家來說,有用是無關緊要的。
于是我退出了那門課程,發誓永遠不會去讀計算機系的研究生。
這個故事的主題是,計算機科學和軟件開發不一樣。如果你非常非常幸運,你的學校會開軟件開發的課程。然而,他們也可能不開這樣的課程,因為名牌大學認為教授實用技巧的事情應該留給那些二三流的技術學院或者某些釋放犯人再安置計劃。你可以在任何地方學習編程,我們是耶魯大學,我們培養未來的世界領導人。你付給耶魯16萬美元的學費就是為了學習如何寫循環語句嗎?你把耶魯當成什么地方了?Java速成班嗎?哼。
問題在于,我們沒有一個專業的學校教授軟件開發。所以如果你想成為一個程序員,你可以進計算機系讀書(當然計算機科學也值得學習),但是你學的不是軟件開發。
如果走運的話,你可以在計算機系發掘出很多有大量編程實踐的課程,就象你能在歷史系找到很多提供寫作水平的課程一樣。這些課程絕對值得學習。如果你喜歡編程,不要為你不能上教授諸如lambda算子或者線性代數的課程沮喪,在那里你連摸一下計算機的機會都沒有。找找看有沒有名字中帶有“實習(Practicum)”字樣的課程,不要在乎Practicum是個拉丁語。有用的(無奈狀)課程就是需要在課程名中塞一些拉丁語,才能從那些裝模作樣(Liberal Artsy Fartsy)管理層的眼前蒙混過關。
不要擔心工作都跑到印度去了
啊哈,如果你人在印度,你就無所謂了。愿你享受外包帶來的工作機會并順祝身體健康。
但是我聽說現在愿意讀計算機系的學生越來越少了。據說原因之一是工作機會都跑到印度去了。我認為這種觀點是大錯特錯。首先,根據眼前的商業時尚選擇事業是非常愚蠢的。其次,即使工作真的都跑到印度和中國去了,編程對于其他有趣的工作來說都是極好的訓練,例如業務流程工程(business process engineering)。第三,無論是在美國還是印度,好程序員仍然是非常短缺的,請相信我。當然,現在有許多所謂搞IT的人吵吵嚷嚷地說就業形勢不好,工作太難找。但是事實如何?恕我直言,好程序員找工作還是很容易。第四,你還有更好的主意嗎?歷史系的畢業生找工作更容易嗎?去法學院如何?據我所知,99%的律師恨他們的工作,每分鐘都恨。而且律師一周工作90小時。正象我以前說過的,如果你喜歡計算機,那么感謝上帝,你將屬于全世界人中的極少數的幸運兒,這些幸運兒熱愛他們的工作,而且工作也可以提供體面的收入。
實際上,我也不認為報考計算機系的人越來越少有多大的意義。相對于internet泡沫時期大家都瘋狂的往計算機系擠,現在的人數回落只是回歸正常水平而已。在泡沫時期,我們這個行業涌入了許多對計算機毫無興趣的南郭先生,他們夢想的是拿著高的嚇人的薪水加誘人的期權,然后年輕退休。謝天謝地,現在這些人都跑了。
好好做夏季畢業實習
明智的招聘者知道熱愛編程的人初中就為當地的牙醫寫數據庫程序,高中就在計算機夏令營教課,為校報規劃網站,在某個軟件公司做實習。他們找的就是這樣的人。
如果你喜歡編程,你最容易犯的最大的錯誤就是“有活就接”。我知道,其他專業的學生假期打工可顧不了這些條條框框。但是你不一樣,你擁有一種特殊技能,不要浪費它。當你畢業時,你的簡歷上應該已經羅列一堆的編程工作實習。讓其他人去“為大家提供租車服務”(Tom Welling是個例外,他業余時間去演超人)。
最后,為了讓你的生活更容易一點,也為了說明我這篇文章是能夠自圓其說的,我將給我自己的公司的做做廣告。我的公司Fog Creek軟件公司,可以為大學生提供軟件開發方面的實習機會。在我們公司,你可以學習“編碼,開發,商業”。去年在我們公司實習的Ben就是這么說的,可不是因為我給他什么好處他才這么說。二月一號截至,抓緊機會吧。
如果你聽了我的建議,你就會太早地賣掉Microsoft公司的股票,拒絕Google提供的職位,原因是因為你已經擁有自己的公司了。到時候可別后悔,更別怪我,呵呵。
有沒有聽說過SEMA?這可是衡量一個軟件開發組好壞的很深奧的系統。別介,等一下!別按那個聯接! 給你六年你也搞不清這玩意。所以我自己隨便攢了一套衡量系統,信不信由你,這系統,三分鐘就可掌握。你可以把省下的時間去讀醫學院了(譯注:美國的醫學院可是要讀死人的!)。
Joel 衡量法則
- 你們用不用源文件管理系統?
- 你們可以把整個系統從源碼到CD映像文件一步建成嗎?
- 你們每天白天都把從系統源碼到CD映像做一遍嗎?
- 你們有軟件蟲管理系統嗎?
- 你們在寫新程序之前總是把現有程序里已知的蟲解決嗎?
- 你們的產品開發日程安排是否反映最新的開發進展情況?
- 你們有沒有軟件開發的詳細說明書?
- 你們的程序員是否工作在安靜的環境里?
- 你們是否使用現有市場上能買到的最好的工具?
- 你們有沒有專職的軟件測試人員?
- 你們招人面試時是否讓寫一段程序?
- 你們是否隨便抓一些人來試用你們的軟件?
|
“Joel 衡量法則”好就好在你只需照著逐條回答以上問題,然后把所答為“是”的問題算成一分,再加起來就可以了,而不需要去算什么每天寫的程序行數或程序蟲的平均數等等。但咱丑話說在前面,可別用“Joel 衡量法則”去推算你的核電站管理程序是否可靠。
如果你們得了12分,那是最好,得了11分還過得去,但如果只得了10分或低于10分,你們可能就有很嚴重的問題了。嚴酷的現實是:大多數的軟件開發公司只能得到2到3分。這些公司如果得不到急救可就玄了,因為像微軟這樣的公司從來就沒有低過12分。
當然,一個公司成功與否不僅僅只取決于以上標準。比如,讓一個管理絕佳的軟件公司去開發一個沒有人要的軟件,那開發出來的軟件也只能是沒有人要。或反過來,一幫軟件痞子以上標準一條也達不到,沒準照樣也能搞出一個改變世界的偉大軟件。但我告訴你,如果不考慮別的因素,你只要能達到以上12條準則,你的團隊就是一個可以準時交活的紀律嚴明的好團隊。
1. 你們用不用源文件管理系統?
我用過商業化的源文件管理系統,我也用過免費的系統,比如CVS,告訴你吧,CVS挺好用。但如果你根本就沒有用源文件管理系統,那你就是累死了也沒法讓你的程序員出活:他們沒法知道別人在改動什么源文件,寫錯了的源文件也沒法恢復。
使用源文件管理系統還有一大好處是,由于每一位程序員都把源文件從源文件管理系統里提出來放到自己的硬盤里,幾乎不會發生丟失源文件的事,最起碼我還沒聽說過。
2. 你們可以把整個系統從源碼到CD映像文件一步建成嗎?
這句話問的問題是:從你們最新的源碼開始到建立起能夠交出去的最后文件,你們有多少步驟要做? 一個好的團隊應該有一個批處理程序一步便可將所有的工作做完,像把源文件提取出來,跟據不同的語言版本要求(英文版,中文版),和各種編譯開關(#ifdef)進行編譯,聯接成可執行文件,標上版本號,打包成CD映像文件或直接送到網站上去,等等等等。
如果這些步驟不是一步做完,就有可能出人為差錯。而且當你很接近產品開發尾聲的時侯,你可能很急于把最后幾個蟲解決,然后盡快地交活。如果這時候你需要做20步才能把最終文件制出來,你肯定會急得要命,然后犯一些很不該犯的錯誤。
正因為這個原因,我工作的前一個公司從用WISE改用InstallShield:我們必需要讓我們的批處理程序完全自動化地,在夜里,被NT scheduler起動把最終文件制成,WISE不能被NT scheduler啟動而InstallShield可以,我們只能把WISE扔掉。(WISE的那幫家伙向我保證他們的下一代產品一定支持在夜里自動運行.)
3. 你們每天白天都把從系統源碼到CD映像做一遍嗎?
你們有沒有遇到過這樣的事情:一個程序員不小心把有毛病的源碼放進源文件管理系統,結果造成最終文件沒法制成。比如,他建立了一個新源文件但忘了把它放進源文件管理系統,然后他高高興興鎖機回家了,因為在他的機器上整個編譯得很好。可是別人卻因為這沒法工作下去了,也只好悶悶地回家了。
這種造成最終文件沒法制成的情況很糟糕,但卻很常見。如果每天在白天就把最終文件制一遍的話,就可以讓這種事不造成太大危害。在一個大的團隊里,要想保證有毛病的源碼及時得到糾正,最好每天下午(比如午餐時)制一下最終文件。午餐前,每個人都盡可能地把改動的源文件放到源文件管理系統里,午餐后,大家回來,如果最終文件已經制成了,好!這時大家再從源文件管理系統里取出最新的源文件接著干活。如果最終文件制作出錯,出錯者馬上修正,而別人還可接著用原有的沒問題的源程序干活。
在我以前曾干過的微軟Excel開發組里,我們有一條規定:誰造成最終文件制作出錯,誰就得被罰去負責監視以后的最終文件制作過程,直到下一位造成最終文件制作出錯的人來接任他。這樣做不僅可以督促大家少造成最終文件制作出錯,而且可以讓每個人都有機會去了解最終文件制作過程。
如果想更多了解這個話題,可以讀我的另一篇文章 Daily Builds are Your Friend.
4. 你們有軟件蟲管理系統嗎?
不論你有任何借口,只要你寫程序,哪怕只是一個人的小組,如果你沒有一個系統化的管理軟件蟲的工具,你寫的程序的質量一定高不了。許多程序員覺得自己可以記得自己的軟件蟲。沒門!我從來記不住超過2到3個軟件蟲。而且第二天早上起床后忙著去買這買那,好不容易記住的軟件蟲早忘掉了。你絕對需要一個系統來管住你的那些蟲。
軟件蟲管理系統功能有多有少。但最少要管理以下幾種信息:
- 如何重復軟件蟲的詳細步驟
- 正常情況(無蟲)應是怎樣
- 現在情況(有蟲)又是怎樣
- 誰來負責殺蟲
- 問題有沒有解決
如果你覺得用軟件蟲管理系統太麻煩,可以簡化一下,建立一個有以上5列的表來用就行了。
如果想更多了解這個話題,可以讀我的另一篇文章Painless Bug Tracking.
5. 你們在寫新程序之前總是把現有程序里已知的蟲解決嗎?
微軟Windows Word的第一版的開發項目曾被認為是“死亡之旅”項目。好象永遠也做不完,永遠超時。所有人瘋狂地工作,可怎么也完成不了任務。整個項目一拖再拖,大家都覺得壓力大得受不了。最后終于做完了這個鬼項目,微軟把全組送到墨西哥的Cancun去度假,讓大家坐下來好好想想。
大家意識到由于項目經理過于強求程序員們按時交活,結果大家只能匆匆地趕活,寫出的程序毛病百出。由于項目經理的開發計劃并沒有考慮殺蟲的時間,大家只能把殺蟲的任務往后推,結果蟲越積越多。有一個程序員負責寫計算字體高度的程序,為了圖快,居然寫一行“return 12;”了事。他指望以后的質檢人員發現這段程序有毛病后報告他再改正。項目經理的開發計劃事實上已變成一個列寫程序功能的清單,而上面列的所謂程序功能遲早都會成為軟件蟲。在項目總結會上,我們稱這種工作方法為“絕對劣質之路”。
為了避免再犯這個錯誤,微軟制定了“零缺陷策略”。許多程序員嘲笑這個策略,覺得經理們似乎在指望靠行政命令來提高產品質量。而事實上“零缺陷策略”的真正含義是:在任何時候,都要把解決現有程序里的問題作為首要問題來抓,然后再去寫新程序。
為什么要這樣做呢?
一般說來,你越不及時地殺蟲,殺蟲的代價(時間和金錢)就會越高。比如,你寫程序時打錯了一個字,編譯器馬上告訴你,你很容易就把它改正。你剛寫好的程序在第一次運行時發現了一個問題,你也很快就能解決它,因為你對你剛寫的程序還記憶猶新。如果你運行你的程序時發現了一個問題,可這個程序是幾天以前寫的,你可能就需要折騰一會兒,還好,你還大致記得,所以不會花太長時間。但如果你在你幾個月以前寫的程序里發現了問題,就比較難解決了,因為你已經忘了許多細節。這時候,你還沒準兒正忙著殺別人程序里的蟲吶,因為這家伙到加勒比海阿魯巴島度假去了。這時候,解決這一堆問題的難度不亞于從事尖端科學研究。你一定得小心翼翼地,非常系統化地從事,而且你很難知道多長時間你才能把問題解決。還有更糟糕的,你的程序已交到用戶手里了,才發現問題,那你就等著套腰包吧。
總結起來,就一條:越早解決問題,越容易解決。
另外還有一個原因,剛寫的程序里發現問題,你能夠比較容易地估算解決它的時間。舉個例子,如果我問你寫一段程序去把一個列表排序需要花多長時間,你可以給我一個比較確切的估計。如果你的程序,在Internet Explorer 5.5安裝以后,工作不正常。我問你要多長時間把這個問題解決,你恐怕都估計不出來,因為你根本就不知道是什么原因造成了這個問題。你可能要花三天時間才能解決,也有可能只花兩分鐘。
這個例子告訴我們,如果你的開發過程中有許多蟲沒有及時解決,那你的開發計劃肯定不可靠。反過來,如果你們已經把已知的蟲全部解決了,要做的事只是寫新的程序,那你的開發計劃就會比較準確。
把已知的蟲全部解決,這樣做還有一個好處:你可以對競爭對手快速反擊。有些人把這叫著“讓開發中的產品隨時處在可以交給用戶的狀態”。如果你的競爭對手推出一個新的功能想把你的客戶搶走,你可以馬上在你的產品里加上這個功能,立刻將新產品交付用戶,因為你沒有一大堆積累下來的問題要解決。
6. 你們的產品開發日程安排是否反映最新的開發進展情況?
為什么我們需要開發日程安排?如果你的程序對公司的業務很重要,那公司就必須知道你的程序何時能寫完。滿世界的程序員都有一個通病,那就是他們都搞不清自己何時才能寫完要寫的程序。他們都只會對管理人員嚷嚷:“等我做好了就做好了!”
不幸的是,程序寫完了,事遠遠沒完。作為一個公司,在發行產品之前,還有許許多多的事情要做:何時做產品演示?何時參加展覽會?何時發廣告?等等。所有的這一且都依賴于產品的開發日程安排。
定下產品開發日程安排,還有一個很關鍵的好處:它逼著你只做叫你做的功能,甩掉那些可要可不要的功能,否則這些可要可不要的東西有可能把你纏住。請看featuritis 。
定下產品開發日程安排,按照它開發,這并不難做,請看我的另一篇文章 Painless Software Schedules ,這篇文章告訴你一種制訂產品開發日程的好方法。
7. 你們有沒有軟件開發的詳細說明書?
寫軟件開發的詳細說明書就像是繡花:人人皆知是好東西,可沒誰愿意去做。
我不知道這是為什么,也許是因為多數程序員天生就不喜歡寫文章。其結果是,一個開發組里的程序員們,寧可用程序來溝通,也不愿寫文章來表達自己。他們喜歡上來就寫程序,而不是寫什么詳細說明書。
在產品的前期設計過程中,如果你發現了一些問題,你可以輕易地在說明書里該幾行字就行了。一旦進入了寫程序的階段,解決問題的代價就要高得多了,不僅僅是時間上的代價,而且也有感情上的代價,因為沒人愿意將自己做成的東西扔掉。所以這時候解決問題總有一些阻力。
沒有產品開發詳細說明書就開始寫程序,往往會導致程序寫的亂七八糟,而且左拖右拖不能交付使用。我覺得這就是Netscape遇到的問題。前四個版本的程序越寫越亂,以至管理人員作出一個愚蠢的決定:把以前的程序統統扔掉,重新寫。后來他們在開發Mozilla時又犯了同樣的錯誤。產品越做越亂,完全失控,花了幾年的時間才進入內部測試階段。
我最得意的理論是:如果讓程序員們接受一些寫文章的訓練如an intensive course in writing,他們就可能會改變一下不寫說明書的壞習慣,而以上所說的糟糕的例子就有可能少發生。
另一個解決問題的辦法是:雇一些能干的項目主任,專職寫產品開發詳細說明書。
不論采用以上哪種方法,道理只有一個:在沒有產品開發詳細說明書之前,決不可寫程序。
如果想更多了解這個話題,可以讀我的四篇文章。
8. 你們的程序員是否工作在安靜的環境里?
當你讓你的智囊們工作在安靜,寬敞,不受人打擾的環境里,他們往往能更快地出活,這已是不爭的事實。有一本經典的講軟件開發管理的書Peopleware 把這個問題闡述得很清楚。
問題在于,我們都知道最好不要打斷這些智囊們的思路,讓他們一直處于他們的最佳狀態中,這樣他們就能全神貫注,廢寢忘食地工作,充分發揮他們的作用。作家,程序員,科學家,甚至籃球運動員都有他們的最佳狀態。
問題還在于,進入這個最佳狀態不容易。我覺得平均起來,需要15分鐘才能進入最佳狀態,達到最高工作效率。有時侯,當你疲勞了或已經高效率地干了許多工作了,你就很難再進入這個狀態,只好干點雜事打發時間,或上網,玩游戲等。
問題更在于,你很容易就被各種各樣的事打擾,被拽出你的最佳狀態:噪音啦,電話啦,吃午飯啦,喝杯咖啡啦,被同事打擾啦,等等。如果一個同事問你一個問題,只花你一分鐘,可你卻被拽出你的最佳工作狀態,重新回到這個狀態需要花半小時。你的工作效率因此而受到很大影響。如果讓你在一個嘈雜的大房間里工作(那幫搞網站的家伙還就喜歡這樣),邊上的推銷員在電話里大叫大嚷,你就很難出活,因為你進入不了你的最佳工作狀態。
作為程序員,進入最佳工作狀態更難。你先要把方方面面的細節裝在腦子里, 任何一種干擾都可能讓你忘掉其中某些東西。你重新回來工作時,發現好些東西記不起來了(如你剛用的局部變量名,或你剛才的搜索程序寫到哪里了等)你只好看看剛寫的程序,回憶一下,慢慢地回到你剛才的最佳工作狀態。
我們來做一個簡單的算數。假設一個程序員被打擾一下,哪怕只有一分鐘,他卻需要花15分鐘才能回到最佳工作狀態(統計資料顯示如此)。我們有兩個程序員:杰夫和愚夫, 坐在一個大辦公區里工作。愚夫想不起來用什么函數去進行Unicode 字符串復制。他可以花30秒查一下,或者花15秒問杰夫。由于他坐在杰夫的旁邊,他就選擇去問杰夫。杰夫被打擾了一下,耽誤了他15分鐘,節省了愚夫15秒鐘。
現在,我們把他們倆用墻和門隔開,讓他們倆分坐在不同的辦公室里,愚夫又想不起來什么涵數名,自己查一下要花30秒;問杰夫,要花45秒,因為他要站起來走過去問(對這幫程序員來說,這可不是件簡單的事,看看他們的體質就知道為什么了)。所以他選擇自己去查。愚夫損失了30秒鐘,可是杰夫少損失了15分鐘。哈哈!
9. 你們是否使用現有市場上能買到的最好的工具?
用可編譯語言寫程序恐怕是這世界上為數不多的還不能隨便抓一個破計算機就可以做的事。如果你用于編譯的時間超過幾秒鐘,你就應該換一臺最新最快的計算機了。因為如果編譯時間超過15秒,程序員們就會不耐煩,轉而去上網看一些無關的東西比如The Onion,弄不好一看就是好幾個小時。
調試圖形界面軟件時,用只有一個顯示器的計算機不僅不方便,有時甚至是不可能。用有兩個顯示器的計算機,要方便許多。
程序員們經常不可避免地要去畫一些圖標或工具欄圖。多數程序員沒有一個好的圖形編輯器可用。用微軟的“畫筆”軟件去畫圖標簡直是笑話,可事實上大家還就在這樣做。
在我的前一個工作,系統管理員成天給我發來自動警告,說我在服務器上使用了超過220兆的空間。我告訴他,按現在硬盤的價錢,超出這點空間的價錢遠低于我用的廁紙的價錢。讓我花10分鐘去清理我的文件絕對是我工作效率的莫大浪費。
一流的開發組絕不折騰它的程序員。工具落后會讓人用起來覺得難受,一點點積累起來,會讓程序員們成天叫苦,而一個成天叫苦的程序員絕對不會是一個高消率的程序員。
再添一句,要想使你的程序員高興,最好的辦法就是給他們買一些最新最棒的工具軟件。用這種方法可以讓他們乖乖地為你工作,這可比用高薪吸引他們來得便宜得多。
10. 你們有沒有專職的軟件測試人員?
如果你的開發組里沒有專職的測試人員,或沒有足夠的測試人員(兩到三個程序員就應該配一個測試員),那你的產品就一定是毛病百出,或者你在花100美元一小時的代價去雇你的程序員去做30美元一小時就可以雇到的測試員的工作。想在測試員身上省錢,絕對是打錯了算盤。我真不明白為什么這么多人算不過來這筆帳。
我有另一篇文章專門講這個,請看Top Five (Wrong) Reasons You Don't Have Testers。
11. 你們招人面試時是否讓寫一段程序?
我問你,讓你去招一個魔術師,你是否連看都不看一眼他的魔術玩得怎樣就要他?當然不會!
你舉辦婚宴,要請一個廚師,你是不是連嚐也不嚐他做的菜好吃不好吃就要他?我想也不會。
奇怪的是,幾乎每天都有這樣的事發生:在面試一個程序員時,簡歷寫得漂亮,談得熱火朝天,問幾個簡單的問題(如CreateDialog()和DialogBox()有什么區別?這種問題,查一下幫助文件就知道了),人就招進來了。你真正應該關心的不是這人記不記得這些寫程序的邊邊角角的東西,而是他能否出產品!更糟糕的是,許多問題是知道就知道,不知道,想死也不知道的問題。
不能這樣下去了!在面試時,請一定要讓寫一段程序。在我的這篇文章里Guerrilla Guide to Interviewing,我有許多好建議。
12. 你們是否隨便抓一些人來試用你們的軟件?
這句話的意思是,讓你從走道里走過的人中,隨便抓幾個人來,讓他們試用你的軟件。如果你抓五個人來用你的軟件,那你就可能把你的程序中95%的不方便使用的地方找出來。
要想讓用戶去買你的軟件,你必須要設計好你的用戶界面。這其實并不難。你可以讀我的free online book on UI design打打基礎。
用戶界面設計的關鍵是,如果你讓幾個人去用你的軟件(五六人可能就夠了),你可能很快就找出最大的問題。想知道為什么嗎,請讀Jakob Nielsen's article。只要你堅持隨便抓一些人來試用你的軟件,你就能將你的用戶界面設計得越來越好。
The Joel Test 軟件開發成功12法則的四個實用領域
- 用該法則來衡量你的軟件開發組,告訴我你得的分數,讓我來品頭論足。
- 如果你是開發組的經理,用該法則來使你的組提高效率。如果你們一上來就能得12分,你就 別再打擾你的程序員了, 專心致志別讓公司的管理人員來煩你的程序員吧。
- 如果你在找一份程序員工作,問問你未來的老板他能得幾分,如果分數很低,你一定要確信你進去后有足夠的權力來改變這一切,否則,最好躲遠點,不然,你在那兒會很難受的。
- 如果你是投資者,正在決定是否向一個軟件公司投資,或者你的軟件公司正在決定是否兼并另一個軟件公司,該法則可以幫你做決定。
Java有基本數據類型,在這些基本數據類型周圍又有包裝類。通常,編程人員需要將一種類型轉換成另一種。看看Listing C.中的代碼片斷。
Listing C
public class Employee {
private static final Integer CHILD = new Integer(0);
public static void main(String args[]) {
//code for adding n to an Integer
int n=10;
Integer age= new Integer(30);
Integer ageAfterTenYear= new Integer(age.intValue +10);
}
}
請注意,用于計算ageAfterTenYear的內循環代碼看上去是多么雜亂。現在,在Listing D.中看看相同的程序使用autoboxing重寫后的樣子。
Listing D
public class Employee {
public static void main(String args[]) {
int n=10;
Integer age= new Integer(30);
Integer ageAfterTenYear= age +10;
}
}
有一件事值得注意的:在先前,如果你取出(unbox)Null值,它將變為0。在次代碼中,編譯器將自動地轉換Integer為int然后加上10,接著將其轉換回Integer.。
MyEclipse GA 4.0 的破解方法:
1、修改com.genuitec.eclipse.core.LicenseWarningDialog類,增加public int open() { return 0;}函數
2、修改com.genuitec.eclipse.core.A類,修改boolean _mth0102(PluginVersionIdentifier pluginversionidentifier)函數,使其返回true;
3、修改com.genuitec.eclipse.core.C類,修改public boolean _mth0102(boolean flag, boolean flag1)函數,使其返回true。
如果你不愿自己破解可以用這個文件:
下載文件 哦,對了這個破解文件的允許環境為jdk1.5