分類
tool

JetBrains – IdeaVim插件的搜尋模式輸入中文會顯示打叉方塊

Situation
使用IdeaVim時按下 / 鍵,會進入搜尋模式。預設在此模式下輸入中文會顯示打叉方塊,無法正常顯示中文內容。

Action
File -> Settings -> Editor -> Font -> 點擊 Typography Settings -> 在 Fallback font選擇可支援中文字型的字體,如 Microsoft JhengHei UI -> 點擊 Save或其他確認的按鈕

Result
IdeaVim 搜尋模式已可正常顯示中文

分類
architecture tool

JetBrains – Rider 如何自定義Quick List項目並加入對應的熱鍵

說明

Rider提供大量好用的操作熱鍵來提升開發效率,但有些熱鍵預設的群組或位置不同,有時候你必須跳轉多次才能使用你想要的熱鍵。

Quick List提供一個組合常用熱鍵的方式,讓你把常用的熱鍵組織成Quick List。你可以透過熱鍵叫出Quick List,並在Quick List中再選擇你的操作。

A.建立Quick List項目

1.File -> Settings -> Appearance & Behavior -> Quick Lists

預設已經存在一個Deployment項目,這不是我們的目標先忽略它

2.點擊中央區塊的加號,填寫Display name / Description,主要使用來識別你新建立的Quick List項目

3.點擊Description下方的加號,出現Add Actions to Quick List視窗,在視窗把各個項目點開,選擇你想加到Quick List的操作(可以使用Shift多選),完成後點擊ok離開Add Actions to Quick List視窗。

4.點擊Save離開Quick Lists視窗

B.對Quick List設定對應的熱鍵

(這裡跟一般的熱鍵設定方式是一樣的)

1.File -> Settings -> Keymap-> 選擇Quick Lists中你想設定的Quick List項目

2.左鍵雙擊Quick List項目會出現Edit Shortcut視窗,在該視窗中設定你想要的熱鍵

3.設定完熱鍵之後,點擊Apply -> 完成

C.使用Quick List項目

跟設定熱鍵相同方式,你可以為你的Quick List項目設定熱鍵,透過熱鍵可以輕鬆叫出你的Quick List項目,最後再選擇你想要的操作。

分類
architecture

標準答案不是唯一解

在軟體開發的世界裡,我們常常追求「標準答案」,一種最佳、最高效的解決方案,這種解決方案的重要性無庸置疑。然而隨著時間和經驗的累積,除了尋找標準答案之外,對於多樣性和創新的「包容」是否也相同重要?

當我們面對複雜的項目時,如何在追求最佳解決方案的同時也給予團隊成員發揮創意的空間?這是一個值得深思的問題。我們必須認識到,有時候「標準答案」並非唯一答案,而是一個起點,一個讓我們基於實際情況進行調整和創新的基礎。

儘管在軟體領域中有許多成熟的開發模式和最佳實踐,但我們仍然鼓勵團隊成員提出新的想法。這種包容性不僅提高了團隊的創新能力,也促進了成員間的溝通與合作。這種創新和包容創造出不同的技術選擇和解決方案,能夠幫助我們更好地適應變化快速的技術環境。

最終,我們要學會的是在追求標準答案的同時,也要培養一顆開放的心。這種平衡不僅有助於我們的專業成長,也是領導和管理軟體開發團隊的關鍵。當我們願意聆聽不同的聲音,尊重多元的觀點,我們的項目和產品就能夠更加完善和創新。

在這個快速變化的時代,讓我們一起追求那些標準答案,同時也擁抱那些出乎意料的創意和多元化的解決方案。畢竟,在包容中,我們尋找的不僅是答案,更是一種成長和創新的動力。

分類
architecture frame

[架構][框架] 微服務架構:一個多維度的基本探討

微服務的基本概念

近年來,「微服務架構」已成為在軟體工程領域中的熱門話題。這個概念代表一種全新的系統設計和開發方法,它不再是將整個系統視為一個單一,巨大的複雜實體,而是分解成多個小而專注的部分。每個部分都關注於一個特定的功能或業務邏輯,並且可以獨立其他部分進行開發、測試和部署。

在多數的技術文獻和討論中,微服務架構被描述為一種將傳統的單體應用拆分成多個獨立運行的小型服務。這些小型服務各自有自己的數據庫、API 和業務邏輯。服務之間通常通過輕量級的通信協議,如HTTP RESTful API,消息隊列來進行交互。這種方法的主要優勢是允許開發團隊專注單一的業務功能,提高開發效率和質量。

在實際操作中,微服務架構不僅僅是關於將一個大型應用拆分成多個小服務。它還涉及到如何管理這些服務之間的交互,包括數據一致性、事務處理和錯誤恢復等。這些挑戰讓微服務的影響從技術層面涵蓋到組織和文化。

微服務的重要性

微服務架構的重要性在於提供一種能夠更快速、更靈活地反應業務變化的開發方法。在今天的競爭激烈的商業環境中,能夠迅速適應市場和客戶需求的企業往往更有競爭優勢。此外微服務還提供了更好的故障隔離,這意味著當一個服務出現問題時不會影響到其他服務,提高整體系統的可用性。

從業務角度看,微服務架構的意義不僅僅在於技術層面。它允許組織更加靈活地創建和維護應用程序,更好地滿足客戶的需求。由於每個微服務都可以獨立部署,這使得持續集成和持續部署成為可能,從而加速了軟體交付的速度。

微服務的使用概念

正確使用微服務架構,首先需要有一個清晰的業務需求和目標。接著確定哪些功能或業務邏輯應該被拆分成獨立的服務。一旦做出這些決策就需要確保每個服務都有清晰的接口定義,並且有適當的測試和監控機制。最後使用容器化技術和自動化工具來簡化部署和維運。

錯誤使用微服務架構可能會導致系統變得過於複雜和難以管理。如果沒有妥善管理服務之間的通信或依賴關係,可能會導致數據不一致或事務失敗。此外過度拆分服務可能會增加網路通信的開銷,從而影響性能。沒有適當監控和日誌記錄來輔助定位和診斷問題,除錯可能會變得非常困難。

微服務架構與多個軟體領域的重要概念也有密切關聯,你無法獨立看待微服務而忽略這些領域,例如DevOps文化和實踐有助於管理微服務的生命週期;容器化技術(如Docker和K8s)提供了簡單而一致的方式來部署和運維服務;持續集成和持續部署(CI/CD)確保軟體可以快速、可靠地交付給用戶。

微服務的原則

最後,根據以下的原則來實現微服務,可以幫助你保持在正確的方向
1.請關注微服務的本質(服務的分解)而不是技術層面
2.請確保服務之間鬆散耦合(可以獨立開發,測試,部署),避免成為分佈式的大型單體架構
3.最終目標不是實現微服務架構,而是提升開發或維護大型複雜系統的速度

分類
architecture skill

[架構][技巧] AI UnitTest:讓ChatGPT幫助你編寫更好的測試代碼

在軟體開發領域,AI工具的演進提供新方法來編寫和測試代碼。利用AI來輔助撰寫單元測試已經成為一種新的測試策略。

透過提示AI來撰寫測試代碼,可以更快速地生成測試用例,找出潛在的缺陷並解決問題,從而提高軟體開發的效率和品質。


流程

首先對ChatGPT描述使用的技術架構和想進行的步驟,接著在步驟中和ChatGPT互動並請它提供合適的單元測試代碼。(詳細內容請參考下方的”完整流程”)


優點

採用AI輔助撰寫單元測試的效果比預計還好,特別是測試範圍和效率

前者你可以明確指定AI提供測試的範圍,也可以要求AI提供容易遺漏的測試用例,擴大合理的涵蓋範圍。

後者比起手動輸入測試代碼,透過AI產生測試代碼的速度也會有顯著的提升。

提升速度這一點相當重要,許多排斥撰寫單元測試的開發者,主要原因為在開發時程中很難再排入撰寫單元測試的時間,更不用說當業務邏輯變動之後,與其對應的單元測試也必須重構修改,因此拒絕學習或撰寫單元測試。

若透過AI產生或重構測試代碼,就能大幅降低花費撰寫單元測試的時間,也能順便開啟通往TDD的大道。


缺點

不洩漏敏感訊息的情況下,將想測試的邏輯完整表達給ChatGPT是一個可能的問題,因為我測試的邏輯很簡單,ChatGPT很清楚溫度轉換公式,提供測試代碼相當容易,但若你想測試的演算法或情境特別複雜,要完整的表達清楚就沒這麼簡單了。


總結

在現階段透過AI來輔助撰寫單元測試是一種可以探索的方式,事實上整個過程就是簡單的TDD開發流程,而ChatGPT就是我的結對編程同伴,而且這個同伴很有耐心,有求必應,沒有偏見(?)。

在測試範圍和效率都是AI的優勢,能夠大幅度縮短撰寫測試代碼的時間,但在不洩漏敏感資訊的情況下,如何表達複雜的測試邏輯會是一個可能的問題。


完整流程

以下是透過提示ChatGPT來產生測試代碼,再讓開發者來撰寫產品代碼的過程。

首先告訴ChatGPT系統簡述和技術架構和需求,包含測試庫的要求(MSTest)。

目前的系統是一個溫度轉換程式。
技術架構:C#,Winform,用於模型的測試庫(MSTest)。
所有的程式碼都應該使用上述的技術架構來撰寫。
需求:程式應該提供華氏和攝氏的溫度轉換並以測試驅動開發來撰寫。
請你只提供單元測試,我再回答是否通過你的單元測試,以這種循環方式來完成整個過程

好的,以下是使用 MSTest 撰寫的兩個單元測試。一個用於驗證華氏到攝氏的溫度轉換,另一個用於驗證攝氏到華氏的溫度轉換。

using Microsoft.VisualStudio.TestTools.UnitTesting;
using YourTemperatureConversionNamespace; // 請將此替換為您的溫度轉換類別的命名空間

namespace TemperatureConversionTests
{
    [TestClass]
    public class TemperatureConversionTest
    {
        [TestMethod]
        public void TestFahrenheitToCelsius()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputFahrenheit = 32.0;
            double expectedCelsius = 0.0;

            // Act
            double actualCelsius = converter.FahrenheitToCelsius(inputFahrenheit);

            // Assert
            Assert.AreEqual(expectedCelsius, actualCelsius, 0.01);
        }

        [TestMethod]
        public void TestCelsiusToFahrenheit()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputCelsius = 0.0;
            double expectedFahrenheit = 32.0;

            // Act
            double actualFahrenheit = converter.CelsiusToFahrenheit(inputCelsius);

            // Assert
            Assert.AreEqual(expectedFahrenheit, actualFahrenheit, 0.01);
        }
    }
}

這裡假設你有一個 TemperatureConverter 類別,並且該類別有兩個方法:FahrenheitToCelsiusCelsiusToFahrenheit。這些方法都接受一個雙精度浮點數(double)並返回一個雙精度浮點數。這些方法應該進行溫度轉換。

請注意,這些測試中的精確度為 0.01,這意味著如果實際結果與預期結果之間的差異小於或等於 0.01,則該測試將被認為是通過的。

請將此單元測試代碼添加到你的測試項目中,並運行這兩個測試。如果你的溫度轉換代碼正確,則這兩個測試都應該通過。

接著就可以建立Winform專案,並在該專案中新增一個TemperatureConversionTest測試類別並直接貼上ChatGPT提供的完整代碼。

當然,執行測試一定會失敗,因為根本還沒有TemperatureConverter類別。

(如果對測試驅動開發有點了解,應該可以發現這也是驅動測試開發的流程,甚至也可以把ChatGPT當作結對編程的對象)

最後再根據ChatGPT提供的單元測試,實作被測代碼。為了避免洩漏敏感訊息,被測代碼不會提供給ChatGPT。

被測代碼如下

    public class TemperatureConverter
    {
        public double FahrenheitToCelsius(double fahrenheit)
        {
            if (fahrenheit < -459.67)
            {
                throw new ArgumentOutOfRangeException("The Fahrenheit temperature cannot be less than -459.67");
            }
            return (fahrenheit - 32) * 5 / 9;
        }

        public double CelsiusToFahrenheit(double celsius)
        {
            if (celsius < -273.15)
            {
                throw new ArgumentOutOfRangeException("The Celsius temperature cannot be less than -273.15");
            }
            return (celsius * 9 / 5) + 32;
        }
    }

接著回答ChatGPT,已可通過單元測試,請再提供更多的單元測試。而且在這裡明確指定測試範圍為極限值


我已可通過你提供的單元測試,請再提供更多的單元測試,主要測試範圍為極限值
---
using Microsoft.VisualStudio.TestTools.UnitTesting;
using YourTemperatureConversionNamespace; // 請將此替換為您的溫度轉換類別的命名空間

namespace TemperatureConversionTests
{
    [TestClass]
    public class TemperatureConversionTest
    {
        [TestMethod]
        public void TestFahrenheitToCelsiusAbsoluteZero()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputFahrenheit = -459.67;
            double expectedCelsius = -273.15;
            
            // Act
            double actualCelsius = converter.FahrenheitToCelsius(inputFahrenheit);

            // Assert
            Assert.AreEqual(expectedCelsius, actualCelsius, 0.01);
        }

        [TestMethod]
        public void TestCelsiusToFahrenheitAbsoluteZero()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputCelsius = -273.15;
            double expectedFahrenheit = -459.67;
            
            // Act
            double actualFahrenheit = converter.CelsiusToFahrenheit(inputCelsius);

            // Assert
            Assert.AreEqual(expectedFahrenheit, actualFahrenheit, 0.01);
        }
        
        [TestMethod]
        public void TestFahrenheitToCelsiusHighTemperature()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputFahrenheit = 212.0;
            double expectedCelsius = 100.0;
            
            // Act
            double actualCelsius = converter.FahrenheitToCelsius(inputFahrenheit);

            // Assert
            Assert.AreEqual(expectedCelsius, actualCelsius, 0.01);
        }

        [TestMethod]
        public void TestCelsiusToFahrenheitHighTemperature()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputCelsius = 100.0;
            double expectedFahrenheit = 212.0;
            
            // Act
            double actualFahrenheit = converter.CelsiusToFahrenheit(inputCelsius);

            // Assert
            Assert.AreEqual(expectedFahrenheit, actualFahrenheit, 0.01);
        }
    }
}

把上述的單元測試新增到TemperatureConversionTest類別,並執行所有的單元測試,被測代碼可以成功通過單元測試!

接下來想對輸入的不合法數值做一些處理,所以要求ChatGPT對溫度低於絕對零度撰寫測試代碼

我已經可以通過你提供的單元測試,但如果輸入的溫度低於絕對零度,我想丟出一個異常,你可以寫出這種測試嗎?

當然可以。在這裡,我將為溫度低於絕對零度的情況寫出兩個測試。我們期望方法在這種情況下拋出一個異常。

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using YourTemperatureConversionNamespace; // 請將此替換為您的溫度轉換類別的命名空間

namespace TemperatureConversionTests
{
    [TestClass]
    public class TemperatureConversionTest
    {
        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void TestFahrenheitToCelsiusBelowAbsoluteZero()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputFahrenheit = -500.0; // Less than absolute zero

            // Act
            converter.FahrenheitToCelsius(inputFahrenheit);

            // Assert is handled by the ExpectedException attribute
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void TestCelsiusToFahrenheitBelowAbsoluteZero()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputCelsius = -300.0; // Less than absolute zero

            // Act
            converter.CelsiusToFahrenheit(inputCelsius);

            // Assert is handled by the ExpectedException attribute
        }
    }
}

在這兩個測試中,我們使用了 ExpectedException 屬性來指定我們期望方法在給定的情況下拋出的異常類型。在這種情況下,我們期望方法在溫度低於絕對零度時拋出 ArgumentOutOfRangeException。如果你的溫度轉換方法正確地處理了這種情況,那麼這些測試應該會通過。

把ChatGPT新增的測試代碼貼到測試類別之後,執行單元測試應該會失敗。因為在TemperatureConverter沒有根據輸入的不合法數據丟出異常。

回頭修改TemperatureConverter,主要針對華氏低於-459.67和攝氏低於-243.15,丟出異常

public class TemperatureConverter
{
    public double FahrenheitToCelsius(double fahrenheit)
    {
        if (fahrenheit < -459.67)
        {
            throw new ArgumentOutOfRangeException("The Fahrenheit temperature cannot be less than -459.67");
        }
        return (fahrenheit - 32) * 5 / 9;
    }

    public double CelsiusToFahrenheit(double celsius)
    {
        if (celsius < -273.15)
        {
            throw new ArgumentOutOfRangeException("The Celsius temperature cannot be less than -273.15");
        }
        return (celsius * 9 / 5) + 32;
    }
}

完成後順利通過單元測試!

最後想請ChatGPT提供它覺得缺乏的單元測試。

我已經可以通過單元測試了,最後我想請提供你覺得缺乏的單元測試

很好,你已經涵蓋了一些重要的測試案例。除了我們已經討論過的測試案例,我們還可以添加一些邊界測試和特殊值測試。以下是一些我們可以添加的額外測試:

  1. 輸入為零的情況:零度華氏對應的攝氏溫度為 -17.78°C,零度攝氏對應的華氏溫度為 32°F。
  2. 一些隨機值的測試:選擇一些隨機的華氏和攝氏溫度值,檢查轉換是否正確。

以下是相應的單元測試:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using YourTemperatureConversionNamespace; // 請將此替換為您的溫度轉換類別的命名空間

namespace TemperatureConversionTests
{
    [TestClass]
    public class TemperatureConversionTest
    {
        [TestMethod]
        public void TestFahrenheitToCelsiusZero()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputFahrenheit = 0.0;
            double expectedCelsius = -17.78;

            // Act
            double actualCelsius = converter.FahrenheitToCelsius(inputFahrenheit);

            // Assert
            Assert.AreEqual(expectedCelsius, actualCelsius, 0.01);
        }

        [TestMethod]
        public void TestCelsiusToFahrenheitZero()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputCelsius = 0.0;
            double expectedFahrenheit = 32.0;

            // Act
            double actualFahrenheit = converter.CelsiusToFahrenheit(inputCelsius);

            // Assert
            Assert.AreEqual(expectedFahrenheit, actualFahrenheit, 0.01);
        }

        [TestMethod]
        public void TestFahrenheitToCelsiusRandom()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputFahrenheit = 45.0; // A random Fahrenheit value
            double expectedCelsius = 7.22; // Corresponding Celsius value

            // Act
            double actualCelsius = converter.FahrenheitToCelsius(inputFahrenheit);

            // Assert
            Assert.AreEqual(expectedCelsius, actualCelsius, 0.01);
        }

        [TestMethod]
        public void TestCelsiusToFahrenheitRandom()
        {
            // Arrange
            TemperatureConverter converter = new TemperatureConverter();
            double inputCelsius = 20.0; // A random Celsius value
            double expectedFahrenheit = 68.0; // Corresponding Fahrenheit value

            // Act
            double actualFahrenheit = converter.CelsiusToFahrenheit(inputCelsius);

            // Assert
            Assert.AreEqual(expectedFahrenheit, actualFahrenheit, 0.01);
        }
    }
}

這些測試將增加對你的溫度轉換程式碼的信心。如果所有這些測試都通過了,那麼你的溫度轉換程式碼在這些測試覆蓋的範圍內應該是正確的。請注意,單元測試能幫助我們提高對程式碼的信心,但並不能保證程式碼百分之百的正確。例如,有可能存在我們尚未考慮到的邊界情況或特殊情況。因此,雖然這些測試是一個很好的起點,但可能仍需要進一步的測試和審查來確保程式碼的健壯性。

分類
architecture skill

[架構][技巧]軟體估算系列 – 基本估算技術 – 先計數再計算

在軟體估算中有一些原則可以優先考慮,其中一項就是先計數再計算。以下分別說明如何進行先計數再計算


先計數

具體做法為蒐集對目前專案進行估算最有幫助或最相關的資訊

舉個簡單例子,對於網站開發可以蒐集網站包含的網頁數量,若該網站包含10個頁面,10個頁面就是計數的結果。

另一個例子為釐清需求後,發現系統有10個特性(或功能)需要完成,這也可以當作計數的結果。

先計數的重點是盡量挑選對估算專案最有幫助或最相關的資訊,以下列出幾個優先考慮的方向

1.      和專案規模(時間,成本,人力)最相關的目標

2.      挑選在統計學具有代表性的數量,如計數的數量包含或超過20個

3.      了解計數的相關資訊,資訊代表甚麼意思? 適合目前的專案嗎?

4.      容易取得的計數資訊,在相同的條件下以容易計數的資訊為優先


再計算

接著再對計數的結果進行計算,若計數的結果有長久穩定的歷史紀錄或具體數據,效果會越好

繼續以上述的範例來說明,假設計數出網站包含10個網頁並根據已存在的歷史紀錄評估出1個網頁大約2.5天,那麼10個網頁大約就是25天。

再計算的重點為計算過程盡量透過歷史紀錄和具體數據來評估,特別要避免憑空推測或單憑經驗來計算,原因之一就是個人單體經驗未必適用於所有情況

這點對於經驗老練但不謹慎的開發者反而容易犯錯。

以下列出可用來計數的目標和後續計算所需的歷史資料

可計數的量化目標後續計算所需的歷史資料
特性每個特性用於開發和測試的平均時間
使用案例每個使用案例的平均工作時間
使用者故事每個使用者故事的平均工作時間
功能點每個功能點的平均工作量
頁面數每個頁面平均工作時間
資料層每個資料表的平均工作時間
類別每個類別的平均工作時間
可計數量化目標及後續計算歷史資料


總結

先計數再計算為軟體估算的原則之一,先計數的做法是對於估算目前專案最有幫助的資訊進行計數。請注意幾個優先考慮的方向

再計算的做法為對於計數結果進行計算,當計數的結果有長遠的歷史紀錄或數據,效果會最好。特別注意避免憑空或只憑經驗進行計算

分類
architecture skill

[架構][技巧]軟體估算系列 – 軟體估算的基礎 – 估算技術介紹

不同的估算技術適用於不同的估算環境,以下為選擇估算技術的主要因素


估算的目標

估算的目標分為兩種情況,第一種情況是你已經知道有哪些特性並可針對這些特性來估算時間和工作量,稱為”專案規模“。

第二種情況為你已被限制在固定的預算或工作時間內,必須在這個條件範圍內估算可以交付那些特性,稱為“估算特性”


專案規模

專案規模分為小型,中型,大型專案。

小型專案:

包含5個或5個以下的人員,因為個體生產力的可變性會明顯的影響其他因素,所以一些適用大型專案的估算技術不適用於小型專案。

對於小型專案來說比較好的估算技術為根據實際執行該專案的人員所做的估算(也稱為從下而上)。

中型專案:

中型專案一般為5到25人組成,專案週期為3到12個月。中型專案的優點為幾乎適用於所有大型專案和一些小型專案的估算技術。

大型專案:

大型專案為25人以上,專案週期為6到12個月或更長的時間。在大型項目中根據不同階段選擇不同的估算技術是最準確的。

大型項目的前期階段適用於根據統計或演算法延伸的估算技術(也稱為從上而下),較不適用根據個人提出的估算技術(從下而上)。

大型項目的中期階段可以根據已經產生的專案數據結合從下而上或從上而下的方法來評估,可以到較準確的結果。

大型項目的後期階段適用從下而上的估算技術。


開發風格

開發風格指的是專案的進行方式為直線或迭代,但對於估算技術而言直線和迭代差別在於前者在專案前期需求定義的佔比大,後者為軟體建構之後再進行的需求定義佔比大。

無論是直線或迭代都傾向於從上而下或根據統計的估算技巧開始,最後轉移為從下而上的方式結束,但因為迭代的進行方式會參考自身所產生的數值來改進,所以相比之下更能強化估算準確度。


開發階段

開發階段也可分為三種,各為前期,中期,後期。

前期:

直線式開發風格的前期通常為從問題定義開始到需求完成階段。迭代式開發風格的前期指的是專案初始規劃階段。

中期:

直線式開發風格的前期通常為從需求到初期架構完成階段。迭代式開發風格的中期指的是專案前2~4個迭代。中期的重點是已可取得一些關於專案生產率的數值。

後期:

無論是直線式或迭代式,後期都是指軟體建構中期到最終發布的範圍。


可能的準確度

估算技術的準確度會受3個因素影響,首先是技術本身提供的功能,第二為技術是否應用在合適的情境,第三是技術適用的專案階段。

當然,通常會期望使用最準確的估算技術,但準確度和成本為正比,高準確度的估算勢必付出較高的代價。另一個要注意的準確度會受不確定錐形的影響,考量成本的情況下在可變性低的範圍使用低成本的估算技術也是可以接受的。


總結

選擇估算技術的考慮因素有3個,分別為專案規模,開發階段,開發風格。

最好根據規模,階段,風格選擇不同的估算技術。若有成本的顧慮,就必須考慮可能的準確度和所付出的成本是否合適。

分類
architecture skill

[架構][技巧]軟體估算系列 – 軟體估算的基礎 – 影響估算的因素

影響估算的因素從高到低分別為專案規模,專案類型,人員因素


1.專案規模

專案規模為影響估算的第一要素,主要原因為專案規模的影響最大,在規模差距過大的情況下用歷史紀錄來評估新的專案最好謹慎一些。

一個簡單的例子就是十萬行(Lines of Code)和一百萬行專案的工作量比例並不等比於十倍(總行數)一樣簡單。

換句話說以兩百人月可完成十萬行的專案,不等於以兩千人月可完成一百萬行的專案。

主要原因就是溝通和連續性問題,而且規模越大的專案其問題會越嚴重。這引起了軟體開發領域領域的有趣現象,”規模不經濟效應”(Diseconomies of scale)。

一般來說生產製造提到的”規模經濟效應(Scale Economies Effect)”,指的是在某個規模中工廠越大,生產線越多,生產成本就會越下降。

軟體開發的”規模不經濟效應(Diseconomies of scale)”卻正好相反,專案規模越大,生產成本反而會越上升。

規模不經濟效應通常只會發生在規模差距過大的專案上,在規模相似(一到五倍之間)的專案上使用平均值來推算工作量,基本上是可以接受的。

假設十萬行的工作量為兩百人月,則平均人月為五百行(十萬除以兩百)。若新專案規模預估為二十萬行(五倍之內),則可以估計大約是落在390~410人月。

最後要注意當規模差距在合理的範圍(一到五倍之間),可以使用平均值做為參考基準來推算工作量。但若規模差距過大(五倍以外),則最好拉大並謹慎評估。


2.專案類型

專案類型為影響估算的第二要素。

類型通常和安全性,可靠性,軟體生命週期等等相關特性有密切的關係。

高度要求安全性和可靠性的軟體(如飛航系統,心臟調節器,公共運輸)比對公司內部的員工網頁,開源軟體等等。對系統各種面向的要求截然不同,其人月平均產出代碼量的差距從十倍到二十倍都有。

還好,通常在同一間軟體公司或同個部門,其開發專案類型的變化不會太大。

原則上也是別把看起來規模相似,但不同類型的歷史紀錄當作參考的唯一基準。換句話說不同類型的專案最好不要混為一談。


3.人員因素

人員因素為影響估算的第三要素。

人員因素包含以下幾種特性表現,需求分析能力,開發者能力(通用),人員流動頻率,業務領域經驗,開發語言和工具經驗,開發平台經驗,團隊凝聚力。

下方是各項特性的比例圖(原本的比例圖不太好理解,我重新繪製了圖表)

橫軸為上述提到的各項特性種類,縱軸為平均工作量,以50為基準點,代表完成該項工作的期望值。分別以兩種不同顏色的直條代表最好和最差的情況。

先以單項能力來看,差距最大的為需求分析能力,以期望值50為基準點,最好的需求分析能力可以減少29%(79-50)的工作量,最差的需求分析能力必須增加42%(50-8)的工作量。

換句話說若需求分析預期完成的天數為50天,最好的情況只需要35.5天(50 – 14.5)。最差的情況需要71天(50 + 21)

差距最小的為團隊凝聚力,以期望值50為基準點,最好的團隊凝聚力可以減少14%(64-50)的工作量,最差的團隊凝聚力必須增加11%(50-39)的工作量。

換句話說若專案預期完成的天數為50天,最好的情況只需要43天(50 – 7)。最差的情況需要55.5天(50 + 5.5)

從各項數據得到一個結論,專案負責人最好能了解誰是某項工作的最佳人選,特別是在需求分析,開發能力,業務領域,這三項可以掌控的因素盡量挑選合適人選。

另外當專案不得已發生以上各項變動,特別是排名越前面的特性對專案評估的結果影響越大。最好重新評估專案,按照新的排程進行。


結論

影響估算的因素從高而低有3種,分別為規模,類型,人員。
在規模要注意的是差距不大(1~5倍之間)可以推算平均值來評估,反之,最好謹慎進行估算。
在類型要注意的是別把規模類似但類型不同的歷史紀錄做為唯一的參考點。
在人員要注意的是因各項特性變動所造成的影響,最好了解誰是這項工作的最佳人選並對排名前段的特性進行篩選,也要注意當特性發生變動後最好重新進行評估。

分類
architecture skill

[架構][技巧]軟體估算系列 – 軟體估算的基礎 – 準確估算的好處

有些開發人員或專案經理已經習慣失準的估算,高估或低估皆會對專案造成不同的影響。

在萬不得已的情況下是選擇高估好還是低估好?


低估帶來的問題

1.低估的影響有連貫性

通常專案早期階段的活動(釐清需求,規劃原型,設計架構)影響專案的程度較大。這些早期活動的時程被低估壓縮而產生的負面效應,也會影響中後期活動(實作功能,測試除錯)的時程。

2.低估的影響難以補救

低估專案時程通常也代表專案延期完成,若組織營收和專案時程有直接關係,除了導致獲利下降,也會連帶影響品牌形象。


高估帶來的問題

1.高估容易導致拖延

若專案實際需要2個月,但估算預計3個月。那麼專案在第1個月的實際完成率會遠低於預計完成率。(因為可以拖延到第2個月才開始動手)

2.高估造成資源浪費

無論高估人力或時間都是多餘的成本浪費,且高估程度越多,浪費也越多。

另一個需要謹慎觀察的情況是組織的高估風氣,在組織中通常高估專案獲得的評價會優於低估專案。因為至少專案是在”高估”的時程內完成,其造成的成本浪費比低估導致時程延期的負面影響來的輕微。

為了獲得較高評價或避免列入黑名單,大家就會傾向高估。特別是管理者不具有相關產業知識的情況下,只看結果而不看過程,高估風氣會更明顯。


了解高估和低估的不同影響之後,在不得已的情況下要怎麼選擇?

當然是看情況。

若低估導致專案延期是殺頭重罪,在無法準確估算的情況下只能選擇高估。(特別是有高估風氣組織)。

至於選擇低估的情況應該有兩個,首先是根本不知道是低估,如相關專案經驗不足,相關技術不熟悉,需求釐清沒有做到位,需求變化太大。

其次是被迫選擇低估,也就是說專案時程已經決定,沒辦法改變。但還是可以透過協商來調整是否能提供部分功能而不是整體功能,讓低估所造成的負面效應降到最小。


最後來看看準確估算可以帶來什麼好處?

1.減少專案風險

專案的風險其實就是專案的理想目標和實際估算的差距,差距越大,風險就越大。

能夠早期處理風險代表可以考慮更多的應變措施,如早期增加人手,縮減規模,改變時間交付功能等等。


2.強化進度評估

準確估算通常代表專案的預計進度,透過比較預計進度和實際進度就可以清楚了解專案進度的狀態是提前還是落後。


3.減少錯誤發生

大約40%的軟體錯誤來自於緊急的進度壓力,這些進度壓力其實可以透過準確的估算進度來避免。在急迫壓力下通常只能選擇盡快完成功能,趕上進度。沒辦法採用單元測試或TDD來驗證正確性,也導致錯誤的可能性大增。


4.提高協調合作

專案的估算不準確,也會連帶影響專案中其他相關活動的時程,這些其他相關活動包含製作文件,市場銷售,後續的預算或人力編制等等。準確的估算能提高專案相關活動之間的協調與合作。

分類
architecture skill

WinForm DataGridView 和 BindingSource 的簡單綁定

Situation

資料和介面的同步一向是實作技術的關鍵點。特別在有多個改變資料的位置,手動編寫兩者的同步不僅繁瑣且難以維護。

WinForm 提供的資料綁定 (Data Binding) 提供非常簡便的方式以自動同步控件屬性和資料屬性。其目的就是當資料或控件兩者其中之一改變時,另一者會同步變化。

資料綁定在使用方式上可以簡單也可以複雜,想要詳細了解的朋友可以參考 Windows Forms 2.0 數據綁定。

以下只說明如何綁定 DataGridView 和 BindingSource。

Action

3個步驟就能簡單綁定 BindingSource 和 DataGridView。

1.宣告並初始化 BindingSource

private BindingSource bindingSource = new BindingSource();


2.指定 BindingSource 的 DataSource 屬性所使用的資料型別

bindingSource.DataSource = typeof(MaintainData);//指定使用的自定義資料型別(MaintainData)


3.把 BindingSource 賦值給目標 DataGridView 的 DataSource 屬性

dataGridViewTest.DataSource = bindingSource;//綁定目標DataGridView(dataGridViewTest)


Result

完成以上綁定步驟之後,dataGridViewTest 會根據 bindingSource 的內容自動更新,不必手動同步。如下

bindingSource.Add(new Maintain()); //dataGridViewTest會自動更新
bindingSource.Clear(); //dataGridViewTest也會自動更新


而當你操作 dataGridViewTest 之後, bindingSource也會自動更新。

Extends

事實上資料綁定還可分為簡單資料綁定 / 複雜資料綁定 / 單項資料源 / 清單資料源。

在不同的情境中結合這些技巧,使用資料綁定會更加得心應手。