2013年3月20日 星期三

節略HTML文字(文字內容包含連結等Tag)

有幾種可能的處理方式,分述如下:

  1. 前端<Div>的方式
<div style="width:450px; height: 18px;
         overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
         <asp:Label ID="Notice" runat="server" class="txt" />
</div>

    2.  Div配合綁定


<div title='<%# Eval("Notice") %>' style="cursor: hand; width: 153px; height: 20px;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
<asp:LinkButton ID="ClassTitle" runat="server" Text='<%# Eval("Notice") %>' />

    3.  Div配合綁定與程式


<div id="GroupNameDiv" runat="server" style="cursor: hand; width: 153px; height: 20px;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
<asp:Label ID="GroupName" runat="server" Text='' CssClass="txt"></asp:Label>&nbsp;
</div>                            
HtmlGenericControl GroupNameDiv = e.Item.FindControl("GroupNameDiv") as HtmlGenericControl;
GroupNameDiv.Attributes["title"] = GroupName.Text;

    4.  程式方式


int length = Regex.Replace(eItem.Content, "(?is)<.+?>", "").Length;
if (length < 40)
{
    Notice.Text = HtmlSubstring(eItem.Content, length);
}
else
{
    Notice.Text = HtmlSubstring(eItem.Content, 40) + "...";
}
public static string HtmlSubstring(string html, int maxlength)
{
    //initialize regular expressions
    string htmltag = "</?\\w+((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)/?>";
    string emptytags = "<(\\w+)((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)/?></\\1>";
    //match all html start and end tags, otherwise get each character one by one..
    var expression = new Regex(string.Format("({0})|(.?)", htmltag));
    MatchCollection matches = expression.Matches(html);
    int i = 0;
    StringBuilder content = new StringBuilder();
    foreach (Match match in matches)
    {
        if (match.Value.Length == 1
            && i < maxlength)
        {
            content.Append(match.Value);
            i++;
        }
        //the match contains a tag
        else if (match.Value.Length > 1)
            content.Append(match.Value);
    }
    return Regex.Replace(content.ToString(), emptytags, string.Empty);
}

2013年3月16日 星期六

集合介面的擴充關係

 

System.Collections

參考資料:

[書摘]《領導者,該想甚麼?》11 激勵他人的第二大障礙

 

我擔任團隊領導者,負責完成某項任務。當任務看似要失敗時,我將:

a. 任務擺第一,屬下次要。
b. 屬下擺第一,任務次要。
c. 平衡屬下與任務。
d. 逃離這個艱困情勢。
e. 以上皆非。

教戰守則1:
性命攸關的事,人務必擺在第一,毫無選擇的餘地。

教戰守則2:
如果工作的技術性不高,領導者無須具備技術能力,只需以恐懼進行領導。

教戰守則3:
有高超技術背景的人,可以將任何工作轉化成技術性工作,以逃避自己不願意的工作。

教戰守則4:
不關心下午的領導者,無法領導任何人,除非被領導者沒有其他選擇。

教戰守則5:
胸中無物卻假裝才高八斗,即便你非常關心他人,也不會有追隨者。

以下列原則衡量成敗:
當我完成的時候,他們是否對於討論的主題較不關心?
如果答案是肯定的,表示我失敗。如果答案是否定的,表示我相當成功。這就是所謂的溫伯格目標(Winberg Target)

教戰守則6:
工作取向的領導者常高估自己的成就。

教戰守則7:

我們從事的工作,很少值得我們犧牲對於未來的可能性。

如果你重視人甚於工作,或許你將失去完成任務的機會。但長久之後,這項任務已被遺忘,這些人卻仍然在你身邊,繼續共事,繼續影響更多人。


進一步而言,把人擺在第一位不一定減少任務成功的機率。大多數領導研究都是針對例行性工作,譬如如何在生產線上擔任主管,但複雜的技術性工作則是另一回事。當計劃發生問題的時候,只有適任的人有能力出面解決問題。

教戰守則8:
面對複雜的工作,沒有哪個領導者能保證,計畫不會「誤入歧途」。

教戰守則9:
成功的問題解決型領導者,必將人擺在第一位。

下列段落是薩提爾(Virginia Satir)對於領導者人性的觀點。
這篇文章是為醫生寫的,讀者可以將「醫生」改為「領導者」:


懸壺濟世是相當崇高的工作。為了負擔這項工作,醫生必須持續在人性和成熟度方面成長。我們面對的是人的生命。我認為,學習當一名醫生和學習當水電工迥然不同。水電工只需技術純熟即可,醫生則不止於此。水電工無須愛一根水管才修理它。醫生不屬於任何一種學派,任何一種技術派別,都必須以人性為立場,使對待自己一樣對待他人。


我教學的時候,非常重視醫療的人性面。我們是人,我們的醫療對象也是人。我們必須了解自己、愛自己,才能看見、聽見、觸見並了解我們的病人。我們營造的醫療氛圍,必須讓病人可以看見、聽見、觸見病了解我們。

教戰守則10:
領導者的工作對象就是人。除了人以外,領導者並無其他工作。

2013年3月14日 星期四

NeatUpload 進度列使用方式詳細說明

 

有鑑於網路上的的資訊大部分都是不完整的,部分是錯誤的,在花了不少時間的測試與問題排除後,終於找到可以正確運作的方法。

    1. 實際操作介面可參考http://www.brettle.com/Demo.aspx

    2. 先到http://neatupload.codeplex.com/下載NeatUpload壓縮檔案。

    3. 壓縮檔內的NeatUploadBinaries\bin\Brettle.Web.NeatUpload.dll是這次要使用的核心參考檔案。

    請注意檔案版本(請看檔案內容的詳細資料):

    l 1.3.4034.20191為確定可以運作的版本

    l 1.3.3034.31897為確定”不能”正常顯示進度列的版本。測試時可發現URL QueryString的prevStatus始終都為Unknown。

    1.3.4034.20191之相關訊息如下:

    MD5校驗值:33464845920CE706DA6A1C69FFDF5253

    image

    4. 拷貝NeatUploadBinaries\NeatUpload目錄到網站”根”目錄。

    請確定為根目錄,其他目錄將無法讀取NeatUpload必須使用到的檔案(像是NeatUpload.js、Progress.js),如果你碰到Javascrip錯誤,請務必檢查這一項。

    5. 新增UploadHttpModule到web.config中

    <httpModules>
    	<add name="UploadHttpModule" type="Brettle.Web.NeatUpload.UploadHttpModule, Brettle.Web.NeatUpload" />
    </httpModules> 
    6. 新增web.config的sectionGroup
    <sectionGroup name="system.web">
        <section name="neatUpload" requirePermission="false" type="Brettle.Web.NeatUpload.ConfigSectionHandler, Brettle.Web.NeatUpload" allowLocation="true" />
    </sectionGroup>


注意:allowLocation=”true” 允許下面區段可以對個別的網頁來做設定

7. 修改web.config以變更 ASP.NET 針對實作所支援的檔案上傳大小上限,並同時設定neatUpload區段

<httpRuntime maxRequestLength="100000" />
    <neatUpload useHttpModule="false" maxRequestLength="2048" efaultProvider="FilesystemUploadStorageProvider">
        <providers>
            <add name="FilesystemUploadStorageProvider" type="Brettle.Web.NeatUpload.FilesystemUploadStorageProvider" tempDirectory="D:\WebSites\TEMP\" />
	</providers>
    </neatUpload>

注意:neatUpload的maxRequestLength必須要小於或等於httpRuntime的maxRequestLength。maxRequestLength單位為KB,最大值2097151。

如果allowLocation="false",useHttpModule必須要設定為true。

useHttpModule=”true” && AutoStartCondition="true" 即可在網頁中見到進度條。

8. 新增web.config的location區段。

<location path="Modules/Processing.aspx">
    <system.web>
      <neatUpload useHttpModule="true" maxRequestLength="2097151" />
      <httpRuntime maxRequestLength="2097151" executionTimeout="3600" useFullyQualifiedRedirectUrl="true" />
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
</location>

注意:useHttpModule必須要設定為true,否則就算ProgressBar的AutoStartCondition=”true”還是不會顯示進度條。

9. 設定web.cong以變更 IIS7 在要求中所支援的內容最大長度。maxAllowedContentLength單位為bytes,最大值4294967295。

<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="209715100" />
      </requestFiltering>
    </security>
</system.webServer>

注意:maxAllowedContentLength優先權高於maxRequestLength。maxAllowedContentLength預設值約為28.6MB。

也可以透IIS管理員的要求篩選來做設定:

image

10. 確認web.config中的trace設定,必須要為false,否則進度列不會顯示

<system.web>
    <trace enabled="false" pageOutput="true" localOnly="false" requestLimit="500" />
</system.web>
11. 在.aspx中放入


  • 描述詞屬性設定:<%@ Page EnableSessionState="false" Trace="false" %>

  • 註冊Tag:<%@ Register TagPrefix="Upload" Namespace="Brettle.Web.NeatUpload" Assembly="Brettle.Web.NeatUpload" %>

  • 上傳控制項:<Upload:InputFile id="inputFile" runat="server" />

  • 觸發用按鈕:<asp:Button ID="submitButton" runat="server" Text="Submit" />

  • 進度條:<Upload:ProgressBar id="inlineProgressBar" runat="server" inline="true" Triggers="submitButton" AutoStartCondition="true" Url="/NeatUpload/progress.aspx" />

12. 在.aspx.cs中加入Page_Load()

private void Page_Load(object sender, EventArgs e)
{
	if (!IsPostBack && Request.Params["processing"] == "true")
	{
		DoProcessing();
	}
}


13. 在.aspx.cs中加入DoProcessing()

private void DoProcessing()
{
	ProgressInfo progress = inlineProgressBar.ProcessingProgress = new ProgressInfo(5000, "Units");
	//for (int i = 1; i <= 5000; i++)	{
	//	System.Threading.Thread.Sleep(1);
	//	progress.Value = i;
	//}
	progress.Text = "Processing Complete";
}

14. 在.aspx.cs中的觸發事件中的適當位置加入DoProcessing()

private void submitButton _Clicked(object sender, EventArgs e)
{
	DoProcessing();
        
        //解除System.IO.IOException Message="由於已有另一個處理序正在使用該檔案,所以無法存取該檔案。"
	inputFile.FileContent.Close();
        inputFile.MoveTo(tmpFile, MoveToOptions.Overwrite); //存檔
}

15. 進度條的實際顯示是藉由嵌入在IFrame中的/NeatUpload/progress.aspx來顯示。



  • 各個Upload:DetailsSpan分別代表上傳的不同階段。可以由URL參數prevStatus看出是在哪個階段。

  • <Upload:DetailsSpan id="processing" 區段為一般上傳所使用。

  • <%# ProcessingHtml %>可以移除,否則會代入程式中所指定的值。這一段會在處理完畢後才使用。

  • 可修改標題、顯示的文字、CSS、取消上傳的圖示等。

16. 可用參數與詳細的描述,請參考官方文件(http://neatupload.codeplex.com/documentation)。


17. 加入多國語的方式如下:



    甲、將Progress.aspx第一行換成

    <%@ Page Language="C#" AutoEventWireup="false" CodeFile="Progress.aspx.cs" Inherits="NeatUpload_Progress" %>
    乙、加入以下程式碼到Progress.aspx.cs:
    public partial class NeatUpload_Progress : Brettle.Web.NeatUpload.ProgressPage
    {
        protected override void OnPreInit(EventArgs e)
        {
            CultureInfo ci = GlobalizationLibrary.Instance.GetCultureMapping(HubUtil.GetCurrentLanguage());
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = ci;
        }
    }

線上學習-教材與學習紀錄之間的關聯

 

image

最簡單的CollectionEditor範例

Keyword: CollectionEditor、伺服器控制項、Server Control

程式碼部分如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing.Design;
using System.ComponentModel.Design;
[assembly: TagPrefix("LD.SC", "hyh")]
namespace LD.SC
{
    [Serializable]    
    public class Sample
    {
        public String Text { get; set; }
        public String Value { get; set; }
    }
    public class ExCollectionEditor : CollectionEditor
    {
        public ExCollectionEditor(Type type)
            :base(type)         
        {
            
        }
        protected override bool CanSelectMultipleInstances()
        {
            return false;
        }
        protected override Type[] CreateNewItemTypes()
        {
            Type[] ItemTypes = new Type[1]; //這邊需要給一個固定的大小
            ItemTypes[0] = typeof(Sample); //單一元素的型別
            return ItemTypes;
        }
    }
    [ToolboxData("<{0}:KVP runat=server></{0}:KVP>")]
    public class KVP : WebControl
    {
        List<Sample> _SampleList = null;
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [PersistenceMode(PersistenceMode.InnerProperty)]        
        [Editor(typeof(ExCollectionEditor), typeof(UITypeEditor))]
        public List<Sample> KeyValuePairs
        {
            get
            {
                if (_SampleList == null)
                {
                    _SampleList = new List<Sample>();
                }
                return _SampleList;
            }
        }
        protected override void RenderContents(HtmlTextWriter output)
        {
            output.Write("SAMPLE");
        }
    }    
}

收工,回家。不是啦,順便看一下使用的畫面唄。


image


原始檔顯示如下:

<hyh:KVP ID="KVP1" runat="server">
    <KeyValuePairs>
        <hyh:Sample Text="AA" Value="1" />
        <hyh:Sample Text="BB" Value="2" />
    </KeyValuePairs>
</hyh:KVP>


 


參考資料:


ASP 中斷點設定

 

image

 

image

 

中斷點設置:”debugger;”

(有設置中斷點時,不需要附加至處理緒)

2013年3月2日 星期六

[書摘]《用戶故事與敏捷方法》第10章 迭代計畫

 

小結

1. 迭代計畫是發佈計算的進一步計劃,但只在迭代即將開始才開始做迭代計算。

2. 迭代計畫中,團隊討論每個故事,然後從故事中分解出任務。

3. 任務的大小沒有強制的範圍(例如,3到5小時)。相反,從故事中分解出任務,用來幫助估算或鼓勵多個開發人員合作完成一個故事。

4. 每個任務都有開發人員承擔。

5. 開發人員通過估算他們承擔的任務,評估他們是否承擔過度。

開發人員職責

1. 負責參加迭代計畫會議。

2. 負責幫助把所有故事劃分為任務,而不是自己想做的事。

3. 負責為認領的任務承當責任。

4. 負責確保承擔適當工作量的工作。

5. 在整輪迭代中,負責監控自己剩餘的工作,同時也要監控隊友剩餘的工作。如果很快就能完成自己的工作,就有輒任幫助隊友承擔部分工作。

客戶職責

1. 負責對迭代中包含的故事排列優先級。

2. 負責指導開發人員交付他們能提供的最大商業價值,這意味著,從發布計畫設定之後,若有更高價值的故事,要負責調整優先級以交付最大的商業價值。

3. 負責參加迭代計畫會議。

[書摘]《用戶故事與敏捷方法》第9章 發布計畫

 

小結

1. 在計畫發布時,有必要知道客戶預期的大致發布日期和故事的相對優先級。

2. 故事應該以明確的順序排列(第一個、第二個、第三個,等等),而不是利用諸如”非常高”、”高”、”中等”模糊順序的分組。

3. 故事的優先級由客戶確定,但也要考慮開發人員的想法。

4. 使用速率將以理想日為單位的估算轉換成日曆日。

5. 估算團隊的初始速率是很有必要的。

開發人員職責

1. 負責提供信息(有時包括基本假設和可能的替代方法)給客戶,以幫助他排列故事優先級。

2. 負責在基礎性需求或架構性需求與其他客戶需求之間取得權衡,避免不切實際地提高基礎性需求或架構性需求的優先級。

3. 建立發布計畫時,負責在實際估算的基礎上,適當包括一定長短的時間用以項目緩衝。

客戶職責

1. 負責以自己對故事價值的估計來確切排列用戶故事的優先級。把故事排列為高、中、低這三個優先級是不夠的。

2. 負責誠實地表達發布期限。如果再7月15日需要,請不要為了保險起見而告訴開發人員6月15號就需要。

3. 負責理解理想日和日曆日的不同。

4. 在想對故事的不同組件排列不同的優先級時,負責分割故事。

5. 負責了解為何不應該譴責或批評一對個人速率為0.6的程序員,只因為他的速率小於1.0。

[書摘]《用戶故事與敏捷方法》第8章 估算用戶故事

 

小結

1. 用故事點估算故事,故事點是故事複雜度、工作量或工期的相對估算。

2. 應由團隊估算故事,估算屬於團隊而不是個人。

3. 通過和其他估算進行比較來進行三角測量。

4. 團隊是否使用結對編程對故事點估算沒有影響。結對編程影響的是團隊的速率,不是他們的估算。

開發人員職責

1. 負責用一個方式定義故事點,並且是對團隊可用和相關的。努力保證這個定義的一致性。

2. 負責給出誠實的估算。不屈服誘惑或壓力而給出低的估算。

3. 負責以團隊估算。

4. 負責估算應與其他估算一致。即所有2點的故事都應差不多。

客戶職責

1. 負責參加估算會議,但是你的任務是回答問題並澄清故事細節。你不必參與故事估算。

[書摘]《用戶故事與敏捷方法》第7章 優秀用戶故事準則

 

小結

1. 為了確定故事,從每個用戶角色使用系統的目標開始考慮。

2. 分割故事時,試著將他分割成貫穿應用程序所有層面的故事。

3. 試著讓故事的大小能夠在使用後讓用戶感到可以去喝杯咖啡休息一下。(在故事被採用後,能讓用戶有些成就感)

4. 如果有項目領域和環境的需要,可以用其他需求蒐集或文檔技術來補充故事。

5. 創建約束卡,將它們貼在公共的牆上,或者編寫測試來確保系統沒有違反約束。

6. 為團隊即將實現的功能編寫小的故事,針對未來實現的功能編寫寬泛的、高層次的故事。

7. 不要讓故事過早涉及用戶介面。

8. 實際編寫故事時,要包括用戶角色。

9. 用主動語態編寫故事。例如,要說"求職者可以發布簡歷",而不要說"簡歷可以被求職者發布"。

10. 為單個用戶編寫故事。不要寫"求職者可以刪除簡歷",而要寫"求職者可以刪除他自己的簡歷"。

11. 讓客戶,而不是開發人員編寫故事。

12. 用戶故事要簡短,別忘了,他們的目的是提醒開發人員和客戶進行對話。

13. 不要給故事卡編號。

[書摘]《用戶故事與敏捷方法》第5章 與用戶代理合作

 

小結

1. 在本章中,我們學習了不同類型的用戶代理,討論了編寫用戶故事時,為什麼用戶代理不如實際用戶理想。

2. 除非用戶的經理也是用戶,否則他就不是適合的用戶代理。

3. 開發經理會試圖擔任用戶代理,因為他們已經參與到項目每天的細節中。然而,開發經理大多不是正在開發的軟件用戶,所以他們不是理想的用戶代理。

4. 在產品公司裡,客戶經常來自於市場團隊。來自市場團隊的人,經常是不錯的用戶代理,但他們通常關注於軟件的功能數目,而不是其質量,這點必須要克服。

5. 與很多不同的用戶(而這些客戶同時也是用戶)聯繫的銷售人員可以是很好的開發項目客戶。銷售人員必須避免把重點放在那些可以重新贏得已失去訂單的故事上。在所有情況下,銷售人員是與用戶溝通的有效渠道。

6. 領域專家可以成為優秀的用戶代理,但必須避免一點:在為產品編寫故事時,將產品開發成只適合那些與他們有相同水平的人使用。

7. 客戶,那些做出購買決定的人,如果他們能與用戶密切地交流,那麼他們能成為非常好的用戶代理。顯然,如果客戶自己也是用戶,那就是完美的組合。

8. 為了成為好的用戶代理,培訓師和技術支持人員必須避免僅僅關注產品中那些他們每天關心的方面。

9. 本章也簡短地給出了一些與用戶代理一起工作的方法,包括用戶顧問團隊的使用,使用多個用戶代理,分析競爭產品,儘早發布軟件來獲取用戶反饋。

開發人員職責

1. 負責幫助組織機構為項目物色合適的用戶。


2. 負責了解不同類型的用戶代理怎麼考慮你們正在開發的系統,他們的背景如何影響交互。

客戶團隊職責

1. 如果你不是軟件的用戶,則要負責了解自己是屬於哪類的用戶代理。


2. 負責理解自己會將那些偏見帶入到項目中,如何克服這個問題,無論是依靠別人還是其他方法。

[書摘]《用戶故事與敏捷方法》第4章 蒐集故事

小結

1. 能夠引出及捕捉需求這一想法是錯誤的。他有兩個有問題的假設:用戶知道所有的需求;需求一旦被捕捉,就鎖定,不再改變。

2. 拖網捕魚的比喻是非常有用的:他說明了需求有不同的大小,需求會隨著時間的推移變化,需要一些技巧發現需求。

3. 即使敏捷流程支持需求的後期湧現,依然需要對預期的發布進行展望並開始寫下容易發現的故事。

4. 我們可以通過用戶訪談、觀察用戶、問卷調查和舉辦故事編寫工作坊來發現用戶故事。

5. 使用多種方法比過度使用一種方法更能獲得好的效果。

6. 通過開放式、與背景無關的提問更容易獲得有用的答案,例如,"告訴我你想怎麼搜索工作?"就勝於"你要通過職位名稱來搜索工作嗎?"

開發人員職責

1. 負責理解並使用多種技巧來捕撈用戶故事。

2. 負責知道怎麼使用開放式和背景無關的提問。

用戶職責

1. 負責理解並使用多種技巧來捕撈用戶故事。

2. 負責盡早寫更多的用戶故事。

3. 作為軟件用戶的主要代表,負責和他們多溝通。

4. 了解怎麼使用開放式和背景無關的提問。

5. 如果需要關於編寫故事的幫助,負責安排並舉辦一次或多次故事編寫工作坊。

6. 負責確保在捕撈故事過程中考慮所有用戶角色。

[書摘]《用戶故事與敏捷方法》第3章 用戶角色建模

 

小結

1. 大部分小組只考慮單一的用戶類型。這會導致軟件忽略原本需要的一些用戶類型。

2. 為了避免從單一用戶的角度編寫所有故事,要識別與軟件交互的不同用戶角色。

3. 通過對每個用戶定義相關特徵,可以更清楚地看到不同角色間的不同點。

4. 對於有些用戶角色而言,用代表人物來描述會很有幫助。虛構人物是假想出來的用戶代表。他們有名字、有照片,還有足夠的相關細節,因為對項目成員來說,很真實。

5. 對於有些應用程序,極端人物可能有助於蒐集原本被遺漏的故事。

開發人員職責


1. 負責參與確認用戶角色和虛構人物的過程。

2. 負責理解每個用戶角色或虛構人物,以及他們之間的異同。

3. 開發軟件時,負責考慮不同的用戶角色對於軟件如何運行的不同偏好。

4. 負責確保在識別和描述用戶角色時,他們只是這個過程中的工具,不應超越做為工具之外的任何用途。

客戶職責


1. 負責尋找用戶(多多益善),病逝別恰當的用戶角色。

2.負責參與識別用戶角色和虛擬人物的過程。

3. 負責確保軟件沒有關注不恰當的用戶。

4. 在編寫故事時,負責確保每個故事都能和至少一個用戶角色或虛構人物聯繫起來。

5. 開發軟件時,負責考慮不同的用戶角色對於軟件如何運行的不同偏好。

6. 負責確保在識別和描述用戶角色時,他們只是這個過程中的工具,不應超越為工具之外的任何用途。

[書摘]《用戶故事與敏捷方法》第2章 編寫故事

 

一個優秀的故事應該具備以下特點:
‧獨立的(Independect)
‧可討論的(Negotiable)
‧對用戶或客戶是有價值的(Valuable to Purchasers or Users)
‧可估計的(Estimatable)
‧小的(Small)
‧可測試的(Testable)

小結

1. 理想情況下,故事之間是獨立的。有時很難做到這一點,但我們要盡量來實現這一目標。故事之間的交付順序應該是無關的,可以任意拿一個故事來實現。

2. 故事細節由用戶和開發人員討論得出。

3. 故事應該很清晰地體現對用戶或客戶的價值。最好的做法是讓客戶編寫故事。

4. 故事可以注釋一些細節,但是過多的細節會使故事難以理解,也可能給人一種開發人員和客戶無須交談的錯覺。

5. 給故事加上注釋最好方法是給他編寫測試用例。

6. 如果故事太大,複合故事和複雜故事可以分成幾個小的故事。

7. 如果故事太小,幾個小故事可以合併成一個較大的故事。

8. 故事應該是可以測試的。

開發人員職責

1. 負責幫助客戶編寫故事,這些故事要能提醒你們同客戶交談,而不是紀錄詳細的需求定義,故事應該對用戶或客戶有價值,他們是獨立的、可測的、大小合適的。

2. 如果被運及實現故事所用的技術或基礎架構信息,應該使用對用戶或客戶有價值的術語來描述。

客戶團隊職責

1. 負責編寫故事,這些故事要能提醒你們同開發人員交談,而不是紀錄詳細的需求定義,他們對用戶或你們自己是有價值的,他們是獨立的、可測試的、大小合適的。

[書摘]《用戶故事與敏捷方法》第1章 概覽

 

小結


1. 故事卡包含對用戶或者客戶有價值的功能簡短描述。

2. 故事卡是故事的可見部分,但客戶團隊和開發人員關於故事的對話更重要。

3. 客戶團隊包括那些確保軟件符合潛在用戶需求的人,可以包括測試人員、產品經理、實際用戶和交互設計師。

4. 故事卡由客戶團隊編寫,因為他們最了解如何表達需要實現的需求,也因為他們會在後期與開發人員共同確定故事細節並安排故事的優先級順序。

5. 按照故事對客戶的價值安排故事的優先級順序。

6. 將各個故事放入迭代,進行發布與迭代規劃。

7. 速率是開發人員可以在一輪迭代中完成的工作量。

8. 放入一輪迭代的故事估計總合不能超過事先開發人員估計的速率。

9. 如果故事太大以致於無法在一輪迭代中完成,可以老慮把它分成兩個或更多的小故事。

10. 驗收測試用於驗證實現的故事是否開發成符合客戶團隊的設想。

11. 用戶故事是很有意義的,因為他們強調口頭交流,你和開發人員都可以理解,可以用於進行迭代計畫,在迭代開發過程中能很好地工作,而且因為他們鼓勵推遲細節。

[書摘]《用戶故事與敏捷方法》第6章 用戶故事與驗收測試

 

小結


1. 驗收測試可以用來記錄客戶和開發人員討論的很多細節。

2. 驗收測試紀錄了有關故事的一些假設,這些假設可能還沒有和開發人員討論過。

3. 驗收測試提供了檢查故事是否被完整實現的基本標準。

4. 驗收測試應由客戶來血而不是開發人員。

5. 驗收測試應在程序員寫代碼之前就寫好。

6. 如果新的測試對闡明故事的細節或意圖沒有任何幫助,就不用再寫。

7. FIT和FitNesse是寫驗收測試的優秀工具,他們用的是我們熟悉的表格或電子表格格式。

開發人員職責


1. 若團隊覺得有需要,則負責實現自動化驗收測試。

2. 開始開發一個新的故事時,負責考慮更多的驗收測試。

3. 負責為代碼做單元測試,使驗收測試就不必顧及故事的每個細節。

客戶職責


1. 負責編寫驗收測試

2. 負責執行驗收測試