Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Quy tắc thực hiện TDD trong dự án cũ

Bài báo “Trách nhiệm trượt của mô hình kho lưu trữ” đã nêu ra một số câu hỏi, rất khó trả lời. Chúng ta có cần một kho lưu trữ không nếu việc bỏ qua hoàn toàn các chi tiết kỹ thuật là không thể? Kho lưu trữ phải phức tạp đến mức nào để việc bổ sung của nó có thể được coi là đáng giá? Câu trả lời cho những câu hỏi này khác nhau tùy thuộc vào sự nhấn mạnh được đặt trong sự phát triển của các hệ thống. Có lẽ câu hỏi khó nhất là:bạn có cần một kho lưu trữ không? Vấn đề "trừu tượng trôi chảy" và sự phức tạp ngày càng tăng của mã hóa với sự gia tăng mức độ trừu tượng không cho phép tìm ra giải pháp có thể thỏa mãn cả hai phía của hàng rào. Ví dụ:trong báo cáo, thiết kế có chủ đích dẫn đến việc tạo ra một số lượng lớn các phương pháp cho mỗi bộ lọc và sắp xếp, và một giải pháp chung tạo ra một chi phí mã hóa lớn.

Để có một bức tranh đầy đủ, tôi đã xem xét vấn đề trừu tượng về ứng dụng của chúng trong một mã kế thừa. Trong trường hợp này, kho lưu trữ chỉ được chúng tôi quan tâm như một công cụ để lấy mã chất lượng và không có lỗi. Tất nhiên, mô hình này không phải là điều duy nhất cần thiết cho việc áp dụng các thực hành TDD. Sau khi ăn một đống muối trong quá trình phát triển một số dự án lớn và xem những gì hiệu quả và những gì không, tôi đã phát triển một vài quy tắc cho bản thân để giúp tôi tuân thủ các hoạt động TDD. Tôi sẵn sàng nhận một lời phê bình mang tính xây dựng và các phương pháp triển khai TDD khác.

Lời nói đầu

Một số có thể nhận thấy rằng không thể áp dụng TDD trong một dự án cũ. Có ý kiến ​​cho rằng các loại kiểm thử tích hợp (UI-tests, end-to-end) phù hợp với họ hơn vì nó quá khó để hiểu mã cũ. Ngoài ra, bạn có thể nghe rằng việc viết các bài kiểm tra trước khi viết mã thực tế chỉ dẫn đến việc mất thời gian, bởi vì chúng tôi có thể không biết mã sẽ hoạt động như thế nào. Tôi đã phải làm việc trên một số dự án, nơi tôi chỉ giới hạn trong các bài kiểm tra tích hợp, tin rằng các bài kiểm tra đơn vị không phải là dấu hiệu. Đồng thời, rất nhiều bài kiểm tra đã được viết, chúng chạy rất nhiều dịch vụ, v.v. Kết quả là, chỉ một người có thể hiểu chúng, thực tế là người đã viết chúng.

Trong quá trình thực tập của mình, tôi đã xoay sở để làm việc trên một số dự án rất lớn, nơi có rất nhiều mã kế thừa. Một số trong số đó có các thử nghiệm, và những người khác thì không (chỉ có ý định thực hiện chúng). Tôi đã tham gia vào hai dự án lớn, trong đó bằng cách nào đó tôi đã thử áp dụng phương pháp TDD. Ở giai đoạn đầu, TDD được coi là sự phát triển Thử nghiệm Đầu tiên. Cuối cùng, sự khác biệt giữa cách hiểu đơn giản này và nhận thức hiện tại, được gọi ngắn gọn là BDD, trở nên rõ ràng hơn. Bất kể ngôn ngữ nào được sử dụng, những điểm chính, tôi gọi là quy tắc, vẫn tương tự. Ai đó có thể tìm thấy điểm tương đồng giữa các quy tắc và các nguyên tắc khác để viết mã tốt.

Quy tắc 1:Sử dụng Từ dưới lên (Từ trong ra ngoài)

Quy tắc này đề cập đến phương pháp phân tích và thiết kế phần mềm khi nhúng các đoạn mã mới vào một dự án đang hoạt động.

Khi bạn đang thiết kế một dự án mới, việc hình dung toàn bộ hệ thống là điều hoàn toàn tự nhiên. Ở giai đoạn này, bạn kiểm soát cả tập hợp các thành phần và tính linh hoạt trong tương lai của kiến ​​trúc. Do đó, bạn có thể viết các mô-đun có thể được tích hợp với nhau một cách dễ dàng và trực quan. Cách tiếp cận Top-Down như vậy cho phép bạn thực hiện một thiết kế từ trước tốt về kiến ​​trúc tương lai, mô tả các đường hướng dẫn cần thiết và có một bức tranh hoàn chỉnh về những gì, cuối cùng, bạn muốn. Sau một thời gian, dự án chuyển thành cái được gọi là mã kế thừa. Và sau đó niềm vui bắt đầu.

Ở giai đoạn cần nhúng một chức năng mới vào một dự án hiện có với một loạt các mô-đun và sự phụ thuộc giữa chúng, có thể rất khó để đưa tất cả chúng vào đầu bạn để đưa ra thiết kế phù hợp. Mặt khác của vấn đề này là số lượng công việc cần thiết để hoàn thành nhiệm vụ này. Do đó, cách tiếp cận từ dưới lên sẽ hiệu quả hơn trong trường hợp này. Nói cách khác, trước tiên bạn tạo một mô-đun hoàn chỉnh giải quyết nhiệm vụ cần thiết, sau đó bạn xây dựng nó vào hệ thống hiện có, chỉ thực hiện những thay đổi cần thiết. Trong trường hợp này, bạn có thể đảm bảo chất lượng của mô-đun này, vì nó là một đơn vị hoàn chỉnh của chức năng.

Cần lưu ý rằng tất cả không đơn giản với các phương pháp. Ví dụ, khi thiết kế một chức năng mới trong một hệ thống cũ, dù muốn hay không, bạn sẽ sử dụng cả hai cách tiếp cận. Trong quá trình phân tích ban đầu, bạn vẫn cần đánh giá hệ thống, sau đó hạ nó xuống cấp độ mô-đun, thực hiện nó và sau đó quay trở lại cấp độ của toàn bộ hệ thống. Theo tôi, điều chính ở đây là đừng quên rằng mô-đun mới phải là một chức năng hoàn chỉnh và độc lập, như một công cụ riêng biệt. Bạn càng tuân thủ nghiêm ngặt cách tiếp cận này, thì mã cũ sẽ càng ít thay đổi.

Quy tắc 2:Chỉ kiểm tra mã đã sửa đổi

Khi làm việc với một dự án cũ, hoàn toàn không cần phải viết các bài kiểm tra cho tất cả các kịch bản có thể có của phương thức / lớp. Hơn nữa, bạn có thể không nhận thức được một số tình huống, vì có thể có rất nhiều tình huống trong số đó. Dự án đã đi vào sản xuất, khách hàng hài lòng nên anh em cứ yên tâm. Nói chung, chỉ những thay đổi của bạn mới gây ra sự cố trong hệ thống này. Do đó, chỉ chúng nên được kiểm tra.

Ví dụ

Có một mô-đun cửa hàng trực tuyến, tạo một giỏ hàng gồm các mặt hàng đã chọn và lưu trữ trong cơ sở dữ liệu. Chúng tôi không quan tâm đến việc thực hiện cụ thể. Xong là xong - đây là mã kế thừa. Bây giờ chúng ta cần giới thiệu một hành vi mới ở đây:gửi thông báo cho bộ phận kế toán trong trường hợp chi phí giỏ hàng vượt quá $ 1000. Đây là mã chúng ta thấy. Làm thế nào để giới thiệu sự thay đổi?

public class EuropeShop : Shop
{
    public override void CreateSale()
    {
        var items = LoadSelectedItemsFromDb();
        var taxes = new EuropeTaxes();
        var saleItems = items.Select(item => taxes.ApplyTaxes(item)).ToList();
        var cart = new Cart();
        cart.Add(saleItems);
        taxes.ApplyTaxes(cart);
        SaveToDb(cart);
    }
}

Theo quy tắc đầu tiên, các thay đổi phải là tối thiểu và nguyên tử. Chúng tôi không quan tâm đến việc tải dữ liệu, chúng tôi không quan tâm đến việc tính thuế và lưu vào cơ sở dữ liệu. Nhưng chúng tôi quan tâm đến giỏ hàng được tính toán. Nếu có một mô-đun thực hiện những gì được yêu cầu, thì nó sẽ thực hiện nhiệm vụ cần thiết. Đó là lý do tại sao chúng tôi làm điều này.

public class EuropeShop : Shop
{
    public override void CreateSale()
    {
        var items = LoadSelectedItemsFromDb();
        var taxes = new EuropeTaxes();
        var saleItems = items.Select(item => taxes.ApplyTaxes(item)).ToList();
        var cart = new Cart();
        cart.Add(saleItems);
        taxes.ApplyTaxes(cart);

        // NEW FEATURE
        new EuropeShopNotifier().Send(cart);

        SaveToDb(cart);
    }
}

Trình thông báo như vậy tự hoạt động, có thể được kiểm tra và các thay đổi được thực hiện đối với mã cũ là rất ít. Đây chính xác là những gì quy tắc thứ hai nói.

Quy tắc 3:Chúng tôi chỉ kiểm tra các yêu cầu

Để giảm bớt số lượng các tình huống yêu cầu thử nghiệm với các bài kiểm tra đơn vị, hãy nghĩ về những gì bạn thực sự cần từ một mô-đun. Trước tiên, hãy viết tập hợp các điều kiện tối thiểu mà bạn có thể hình dung như các yêu cầu cho mô-đun. Tập hợp tối thiểu là tập hợp mà khi được bổ sung bằng một cái mới, hành vi của mô-đun không thay đổi nhiều, và khi loại bỏ, mô-đun đó không hoạt động. Phương pháp BDD giúp ích rất nhiều trong trường hợp này.

Ngoài ra, hãy tưởng tượng các lớp khác là khách hàng của mô-đun của bạn sẽ tương tác với nó như thế nào. Bạn có cần viết 10 dòng mã để cấu hình mô-đun của mình không? Giao tiếp giữa các bộ phận của hệ thống càng đơn giản càng tốt. Do đó, tốt hơn là chọn các mô-đun chịu trách nhiệm cho một cái gì đó cụ thể từ mã cũ. SOLID sẽ hỗ trợ trong trường hợp này.

Ví dụ

Bây giờ, hãy xem mọi thứ được mô tả ở trên sẽ giúp chúng ta mã như thế nào. Đầu tiên, hãy chọn tất cả các mô-đun chỉ liên quan gián tiếp đến việc tạo giỏ hàng. Đây là cách phân bổ trách nhiệm cho các mô-đun.

public class EuropeShop : Shop
{
    public override void CreateSale()
    {
        // 1) load from DB
        var items = LoadSelectedItemsFromDb();

        // 2) Tax-object creates SaleItem and
        // 4) goes through items and apply taxes
        var taxes = new EuropeTaxes();
        var saleItems = items.Select(item => taxes.ApplyTaxes(item)).ToList();

        // 3) creates a cart and 4) applies taxes
        var cart = new Cart();
        cart.Add(saleItems);
        taxes.ApplyTaxes(cart);

        new EuropeShopNotifier().Send(cart);

        // 4) store to DB
        SaveToDb(cart);
    }
}

Bằng cách này, chúng có thể được phân biệt. Tất nhiên, những thay đổi như vậy không thể được thực hiện cùng một lúc trong một hệ thống lớn, nhưng chúng có thể được thực hiện dần dần. Ví dụ:khi các thay đổi liên quan đến mô-đun thuế, bạn có thể đơn giản hóa cách các phần khác của hệ thống phụ thuộc vào mô-đun đó. Điều này có thể giúp loại bỏ sự phụ thuộc cao và sử dụng nó trong tương lai như một công cụ độc lập.

public class EuropeShop : Shop
{
    public override void CreateSale()
    {
        // 1) extracted to a repository
        var itemsRepository = new ItemsRepository();
        var items = itemsRepository.LoadSelectedItems();
			
        // 2) extracted to a mapper
        var saleItems = items.ConvertToSaleItems();
			
        // 3) still creates a cart
        var cart = new Cart();
        cart.Add(saleItems);
			
        // 4) all routines to apply taxes are extracted to the Tax-object
        new EuropeTaxes().ApplyTaxes(cart);
			
        new EuropeShopNotifier().Send(cart);
			
        // 5) extracted to a repository
        itemsRepository.Save(cart);
    }
}

Đối với các bài kiểm tra, các kịch bản này sẽ là đủ. Cho đến nay, việc triển khai chúng không khiến chúng tôi quan tâm.

public class EuropeTaxesTests
{
    public void Should_not_fail_for_null() { }

    public void Should_apply_taxes_to_items() { }

    public void Should_apply_taxes_to_whole_cart() { }

    public void Should_apply_taxes_to_whole_cart_and_change_items() { }
}

public class EuropeShopNotifierTests
{
    public void Should_not_send_when_less_or_equals_to_1000() { }

    public void Should_send_when_greater_than_1000() { }

    public void Should_raise_exception_when_cannot_send() { }
}

Quy tắc 4:Chỉ thêm mã đã thử nghiệm

Như tôi đã viết trước đó, bạn nên giảm thiểu các thay đổi đối với mã cũ. Để làm điều này, mã cũ và mã mới / đã sửa đổi có thể được tách ra. Mã mới có thể được đặt trong các phương pháp có thể được kiểm tra bằng cách sử dụng các bài kiểm tra đơn vị. Cách tiếp cận này sẽ giúp giảm thiểu rủi ro liên quan. Có hai kỹ thuật đã được mô tả trong cuốn sách “Làm việc hiệu quả với mã kế thừa” (liên kết đến cuốn sách bên dưới).

Phương thức / lớp mầm - kỹ thuật này cho phép bạn nhúng một mã mới rất an toàn vào một mã cũ. Cách tôi thêm trình thông báo là một ví dụ về cách tiếp cận này.

Phương pháp quấn - phức tạp hơn một chút, nhưng bản chất là như nhau. Nó không phải lúc nào cũng hoạt động, nhưng chỉ trong trường hợp mã mới được gọi trước / sau mã cũ. Khi gán trách nhiệm, hai lệnh gọi của phương thức ApplyTaxes được thay thế bằng một lệnh gọi. Đối với điều này, cần phải thay đổi phương pháp thứ hai để logic không bị phá vỡ quá nhiều và nó có thể được kiểm tra. Đó là cách lớp học trông như thế nào trước khi thay đổi.

public class EuropeTaxes : Taxes
{
    internal override SaleItem ApplyTaxes(Item item)
    {
        var saleItem = new SaleItem(item)
        {
            SalePrice = item.Price*1.2m
        };
        return saleItem;
    }

    internal override void ApplyTaxes(Cart cart)
    {
        if (cart.TotalSalePrice <= 300m) return;
        var exclusion = 30m/cart.SaleItems.Count;
        foreach (var item in cart.SaleItems)
            if (item.SalePrice - exclusion > 100m)
                item.SalePrice -= exclusion;
    }
}

Và đây là cách nó trông như thế nào. Logic làm việc với các thành phần của giỏ hàng đã thay đổi một chút, nhưng nhìn chung, mọi thứ vẫn như cũ. Trong trường hợp này, phương thức cũ trước tiên gọi một ApplyToItems mới, sau đó là phiên bản trước của nó. Đây là bản chất của kỹ thuật này.

public class EuropeTaxes : Taxes
{
    internal override void ApplyTaxes(Cart cart)
    {
        ApplyToItems(cart);
        ApplyToCart(cart);
    }

    private void ApplyToItems(Cart cart)
    {
        foreach (var item in cart.SaleItems)
            item.SalePrice = item.Price*1.2m;
    }

    private void ApplyToCart(Cart cart)
    {
        if (cart.TotalSalePrice <= 300m) return;
        var exclusion = 30m / cart.SaleItems.Count;
        foreach (var item in cart.SaleItems)
            if (item.SalePrice - exclusion > 100m)
                item.SalePrice -= exclusion;
    }
}

Quy tắc 5:"Phá vỡ" các phần phụ thuộc ẩn

Đây là quy tắc về điều xấu lớn nhất trong một mã cũ:việc sử dụng mới toán tử bên trong phương thức của một đối tượng để tạo các đối tượng, kho lưu trữ hoặc các đối tượng phức tạp khác. Tại sao lại tệ như vậy? Lời giải thích đơn giản nhất là điều này làm cho các bộ phận của hệ thống có tính kết nối cao và giúp giảm sự gắn kết của chúng. Thậm chí ngắn hơn:dẫn đến vi phạm nguyên tắc "kết hợp thấp, kết hợp cao". Nếu bạn nhìn ở khía cạnh khác, thì đoạn mã này quá khó để trích xuất thành một công cụ độc lập, riêng biệt. Việc loại bỏ những phụ thuộc ẩn như vậy cùng một lúc là rất tốn công sức. Nhưng điều này có thể được thực hiện dần dần.

Đầu tiên, bạn phải chuyển phần khởi tạo của tất cả các phụ thuộc sang phương thức khởi tạo. Đặc biệt, điều này áp dụng cho mới toán tử và việc tạo các lớp. Nếu bạn có ServiceLocator để lấy các phiên bản của các lớp, bạn cũng nên xóa nó khỏi phương thức khởi tạo, nơi bạn có thể lấy ra tất cả các giao diện cần thiết từ nó.

Thứ hai, các biến lưu trữ thể hiện của đối tượng / kho lưu trữ bên ngoài phải có kiểu trừu tượng và giao diện tốt hơn. Giao diện tốt hơn vì nó cung cấp nhiều khả năng hơn cho nhà phát triển. Kết quả là, điều này sẽ cho phép tạo ra một công cụ nguyên tử từ một mô-đun.

Thứ ba, không để các tờ phương pháp lớn. Điều này cho thấy rõ ràng rằng phương thức làm được nhiều hơn những gì nó được chỉ định trong tên của nó. Nó cũng là dấu hiệu của việc có thể vi phạm SOLID, Luật Demeter.

Ví dụ

Bây giờ, hãy xem mã tạo giỏ hàng đã được thay đổi như thế nào. Chỉ có khối mã tạo giỏ hàng là không thay đổi. Phần còn lại được đưa vào các lớp bên ngoài và có thể được thay thế bằng bất kỳ cách triển khai nào. Bây giờ lớp EuropeShop có dạng một công cụ nguyên tử cần một số thứ nhất định được biểu diễn rõ ràng trong hàm tạo. Mã trở nên dễ hiểu hơn.

public class EuropeShop : Shop
{
    private readonly IItemsRepository _itemsRepository;
    private readonly Taxes.Taxes _europeTaxes;
    private readonly INotifier _europeShopNotifier;

    public EuropeShop()
    {
        _itemsRepository = new ItemsRepository();
        _europeTaxes = new EuropeTaxes();
        _europeShopNotifier = new EuropeShopNotifier();
    }

    public override void CreateSale()
    {
        var items = _itemsRepository.LoadSelectedItems();
        var saleItems = items.ConvertToSaleItems();

        var cart = new Cart();
        cart.Add(saleItems);

        _europeTaxes.ApplyTaxes(cart);
        _europeShopNotifier.Send(cart);
        _itemsRepository.Save(cart);
    }
}SCRIPT

Quy tắc 6:Càng ít thử nghiệm lớn càng tốt

Các bài kiểm tra lớn là các bài kiểm tra tích hợp khác nhau nhằm kiểm tra các tập lệnh của người dùng. Không nghi ngờ gì nữa, chúng rất quan trọng, nhưng để kiểm tra logic của một số IF trong độ sâu của mã là rất tốn kém. Việc viết bài kiểm tra này mất cùng một khoảng thời gian, nếu không muốn nói là nhiều hơn, giống như viết chính chức năng. Việc hỗ trợ chúng giống như một mã kế thừa khác, rất khó thay đổi. Nhưng đây chỉ là những thử nghiệm!

Cần phải hiểu những thử nghiệm nào là cần thiết và tuân thủ rõ ràng sự hiểu biết này. Nếu bạn cần kiểm tra tích hợp, hãy viết một bộ kiểm tra tối thiểu, bao gồm các kịch bản tương tác tích cực và tiêu cực. Nếu bạn cần kiểm tra thuật toán, hãy viết một bộ kiểm tra đơn vị tối thiểu.

Quy tắc 7:Không thử nghiệm các phương pháp riêng tư

Một phương thức private có thể quá phức tạp hoặc chứa mã không được gọi từ các phương thức public. Tôi chắc chắn rằng bất kỳ lý do nào khác mà bạn có thể nghĩ ra sẽ chứng tỏ đây là đặc điểm của mã hoặc thiết kế "xấu". Rất có thể, một phần của mã từ phương thức private nên được tạo thành một phương thức / lớp riêng biệt. Kiểm tra xem nguyên tắc đầu tiên của SOLID có bị vi phạm hay không. Đây là lý do đầu tiên tại sao nó không đáng làm như vậy. Thứ hai là theo cách này, bạn không kiểm tra hành vi của toàn bộ mô-đun mà là cách mô-đun thực hiện nó. Việc triển khai nội bộ có thể thay đổi bất kể hành vi của mô-đun. Do đó, trong trường hợp này, bạn nhận được các bài kiểm tra mong manh và cần nhiều thời gian hơn mức cần thiết để hỗ trợ chúng.

Để tránh phải kiểm tra các phương thức riêng tư, hãy trình bày các lớp của bạn dưới dạng một bộ công cụ nguyên tử và bạn không biết chúng được triển khai như thế nào. Bạn mong đợi một số hành vi mà bạn đang thử nghiệm. Thái độ này cũng áp dụng cho các lớp trong ngữ cảnh của hợp ngữ. Các lớp có sẵn cho khách hàng (từ các tập hợp khác) sẽ là công khai và những lớp thực hiện công việc nội bộ - riêng tư. Mặc dù, có một sự khác biệt từ các phương pháp. Các lớp bên trong có thể phức tạp, vì vậy chúng có thể được chuyển đổi thành các lớp bên trong và cũng được kiểm tra.

Ví dụ

Ví dụ:để kiểm tra một điều kiện trong phương thức riêng của lớp EuropeTaxes, tôi sẽ không viết một bài kiểm tra cho phương thức này. Tôi hy vọng rằng thuế sẽ được áp dụng theo một cách nhất định, vì vậy thử nghiệm sẽ phản ánh chính hành vi này. Trong bài kiểm tra, tôi đã đếm thủ công những gì nên là kết quả, lấy nó làm tiêu chuẩn và mong đợi kết quả tương tự từ lớp.

public class EuropeTaxes : Taxes
{
    // code skipped

    private void ApplyToCart(Cart cart)
    {
        if (cart.TotalSalePrice <= 300m) return; // <<< I WANT TO TEST THIS CONDIFTION
        var exclusion = 30m / cart.SaleItems.Count;
        foreach (var item in cart.SaleItems)
            if (item.SalePrice - exclusion > 100m)
                item.SalePrice -= exclusion;
    }
}

// test suite
public class EuropeTaxesTests
{
    // code skipped

    [Fact]
    public void Should_apply_taxes_to_cart_greater_300()
    {
        #region arrange
        // list of items which will create a cart greater 300
        var saleItems = new List<Item>(new[]{new Item {Price = 83.34m},
            new Item {Price = 83.34m},new Item {Price = 83.34m}})
            .ConvertToSaleItems();
        var cart = new Cart();
        cart.Add(saleItems);

        const decimal expected = 83.34m*3*1.2m;
        #endregion

        // act
        new EuropeTaxes().ApplyTaxes(cart);

        // assert
        Assert.Equal(expected, cart.TotalSalePrice);
    }
}

Quy tắc 8:Không kiểm tra thuật toán của các phương pháp

Một số người kiểm tra số lượng cuộc gọi của các phương thức nhất định, xác minh chính cuộc gọi, v.v., nói cách khác, kiểm tra hoạt động nội bộ của các phương thức. Nó cũng tệ như thử nghiệm những cái riêng tư. Sự khác biệt chỉ là ở lớp ứng dụng của việc kiểm tra như vậy. Cách tiếp cận này lại đưa ra nhiều bài kiểm tra mong manh, do đó một số người không thực hiện TDD đúng cách.

Đọc thêm…

Quy tắc 9:Không sửa đổi mã kế thừa mà không có kiểm tra

Đây là quy tắc quan trọng nhất vì nó phản ánh mong muốn của một đội đi theo con đường này. Nếu không có mong muốn di chuyển theo hướng này, mọi thứ đã nói ở trên không có ý nghĩa đặc biệt. Bởi vì nếu một nhà phát triển không muốn sử dụng TDD (không hiểu ý nghĩa của nó, không nhìn thấy lợi ích, v.v.), thì lợi ích thực sự của nó sẽ bị làm mờ đi bởi những cuộc thảo luận liên tục về mức độ khó và không hiệu quả của nó.

Nếu bạn định sử dụng TDD, hãy thảo luận vấn đề này với nhóm của bạn, thêm nó vào Định nghĩa Hoàn thành và áp dụng nó. Lúc đầu, nó sẽ được khó khăn, giống như với mọi thứ mới. Giống như bất kỳ môn nghệ thuật nào, TDD đòi hỏi sự luyện tập liên tục và niềm vui sẽ đến khi bạn học. Dần dần, sẽ có nhiều bài kiểm tra đơn vị được viết hơn, bạn sẽ bắt đầu cảm thấy “sức khỏe” của hệ thống của mình và bắt đầu đánh giá cao sự đơn giản của việc viết mã, mô tả các yêu cầu trong giai đoạn đầu tiên. Có các nghiên cứu TDD được thực hiện trên các dự án lớn thực sự của Microsoft và IBM, cho thấy việc giảm các lỗi trong hệ thống sản xuất từ ​​40% đến 80% (xem các liên kết bên dưới).

Đọc thêm

  1. Sách “Làm việc hiệu quả với Mã kế thừa” của Michael Feathers
  2. TDD khi đến tận cổ của bạn trong Mã kế thừa
  3. Phá vỡ sự phụ thuộc tiềm ẩn
  4. Vòng đời của mã kế thừa
  5. Đơn vị bạn có nên thử nghiệm các phương thức riêng tư trên một lớp không?
  6. Nội bộ kiểm tra đơn vị
  7. 5 Quan niệm Sai lầm Phổ biến về TDD &Kiểm tra Đơn vị
  8. Định luật Demeter

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Giảm thiểu tác động của việc mở rộng cột IDENTITY - phần 2

  2. Trận đấu gần nhất, Phần 3

  3. Làm thế nào để tính toán trung bình động trong Redshift

  4. Không phải bạn, mà là tôi (xử lý sự cố I / O)

  5. Công dụng của hàm DECODE trong SQL là gì?