Patterns of Effective Teams

Again, Dan North, again great talk!

The talk was going around the following map:

Patterns

Dreyfus Squared

  • Different levels of people, do the pairing!, share the love and knowledge within the team

Shallow Silos

  • Rotate team/pairs

Seize of Day

  • Energize standups, discuss the status, not just report!, we don’t care about the brief status: I did XYZ, I will do ABC, I have no issues. Do the real scrum as it was inspired from american footbal to decide what the team will do now, today and how it’s going to solve the current problems.

Near and far

  • Cross-funcational teams vs. single specialized teams
    • solution in the middle, keep having very specialized teams but ask them to teach cross-functional teams

Warm welcome

  • already covered in his previous talk

Code Critique aka code reviews

  • Learning from others
  • Socializing

Team Hack Days

  • “TODO” days
  • “SMELLS” days – fix the smells in the code, I know, you don’t have smell in the code, just in case 😉
  • “RESEARCH” days
  • go and play with non-project tasks
  • => getting people together, great ideas can evolve

Walk a mile:

  • What’s the benefit of person (dev, manager)
    • Walk in his/her shoes
    • Take him off and let’s see

TDD

  • Can slow down in case I don’t know where you are heading to, i.e. prototyping, proposing different solutions,
  • Find a balance where it’s needed, some simple code could be verified by explanatory tester and it’s wasting of dev time

From https://blogs.msdn.microsoft.com/fkaduk/2013/06/12/ndc-oslo-2013-day-1/

TDD, where did it all go wrong

General

There are different kinds/levels of testing:

  • Unit testing:
    • testing class/method:
      • Helps us to get good design, but coupled to the implementation details
      • Implementation details is going to be changed so that we need to change also our class/method tests => which is expensive and we are lazy to do it => we skip it and the tests are dead
    • Testing behaviour:
      • HERE should be the focus
      • When implementation details have changed but behaviour stayed same, these tests are untouched and we should be free to refactor them
  • Integration testing
    • Testing componentization
      • Should be small amount of them
  • UX testing

ATDD

  • hard to maintain
  • Written by business analysts, customers, maintained by devs => nightmare,
  • Results in RED state
  • What’s the value  having them? They are veeery expensive

 Where did all go wrong?

  • Writing UT against classes, methods

Read the book written by Kent Beck: Test driven development by example to understand more, should be like a bible for devs who takes testing seriously

Zen of testing

  • Don’t write tests against UX
  • UX is going to be changed so your tests have to be changed
  • Let UX devs write them

Write tests against surface of module , avoid testing against implementation, don’t couple to implementation, couple to the behavior

Testing should be done using simple steps:

  • Get solution to the problem fast
  • Don’t solve the problem and engineer together, split them! Then unit testing becomes a part of problem solving task
  • Result:
    • Write hacky code just to make test working but DON’T STOP THERE!!! please
  • Engineeirng comes later => in form of refactoring!!!!, please, keep it in mind!

Result

DON’T COUPLE TESTS TO IMPLEMENTATION DETAILS!!!!!!

=> you write less tests

Common issue

Ice cream problem:

  • Manual testing is too expensive
  • Automated GUI tests – we need to rewrite them as soon as UI changes, they are never done, stays RED
  • Most useful and the cheapest are UT

Unit Tests – focused on business logic, behavior,

Integration testing: cooperation between components

UI – testing:

  • UI widgets testing
  • Keep them manual

It should be like this:

Hexagonal architecture

  • In the center there is a Domain Model
  • Around it there are so called ports – application program interfaces – which makes surface of the system
  • Around them we have port adapters (MVC adapter, DB adapter, Notification adapter …) <= this we need to fake in order to
  • We test around ports! – public API

TDD/BDD

  • Don’t test the things you don’t own
  • UT  coupled to the implementation helps us with a design but don’t be afraid to delete them. Tests on higher level should be kept long-term only.

 ATDD

  • Can help to clean-up the communication developer vs. business
  • Very expensive, business people don’t want to do it

Summary

  • BDD is unit testing on the higher level ..
  • DON’T mock internals
  • MOCK port to adapter

From https://blogs.msdn.microsoft.com/fkaduk/2013/06/14/ndc-oslo-2013-day-3/

Domain Drive Development (DDD) – First thought – Part 5

phần mở đầu, mình đã đề cập đến anh em họ hàng trong dòng họ xDD (Driven Design / Development). Và chủ đề chính của loạt bài này là focus vào Domain Driven Development. Trong phần cuối, bằng những kiến thức giới hạn của bản thân, mình sẽ trình bày mối quan hệ của các chú xDD này trong thế giới Software development. Liệu chúng phải loại trừ nhau để kiếm đất sống hoặc có thể cộng sinh để tạo nên một thế giới hòa bình và tốt đẹp hơn.

Thật may là thế giới ngày nay đề cao sự đối thoại hơn là đối đầu.

ndc-2011-specflow-pragmatic-bdd-for-net-6-728

Nguồn hình ảnh: https://www.slideshare.net/jbandi/ndc-2011-specflow-pragmatic-bdd-for-net

Nếu bạn đã từng apply TDD hoặc đơn giản là apply các bộ unit-test và từng xem như là cách để document về hành vi và yêu cầu người dùng mong muốn thì ắt hẳn là gặp không ít khó khăn. Việc viết test trước là cách rất tốt để thiết lập việc suy nghĩ về các vấn đề cần giải quyết trước khi bắt tay vào xử lý chúng. Tuy nhiên, đối với hầu hết các developer, hay nói rộng ra theo một cách khác, khi quá tập trung vào chi tiết – theo hướng emergent design thay vì up-front design – sẽ làm mất tầm nhìn cho các vấn đề lớn hơn, then chốt hơn như tính đúng đắn của requirement. Hay nói một cách khác, sẽ là rất khó để nói rằng TDD sẽ phản ánh được đầy đủ hình hài của user requirement, không thể phản ánh được các use-case mà khách hàng mong muốn.

Dan North đã đẻ ra một hướng tiếp cận khác gọi là Behavior Driven Development với 2 mục đích. Thứ nhất, các bộ test casse BDD được phát triển dựa trên ngôn ngữ tự nhiên sẽ giúp mô tả được cụ thể các use-case mà khách hàng mong muốn, ngôn ngữ tự nhiên này sẽ được “chuẩn hóa” một chút sao cho có cú pháp và có thể dùng các công cụ (như Cucumber) để verify chúng một cách tự động. Thứ hai, BDD sẽ giống như một roadmap giúp cho các developer có thể chèo lái công cuộc TDD của mình một cách có hệ thống, và đúng đắn (TDD Done Right).

Còn DDD, như đã đề cập trong các phần trước, nó chủ yếu focus vào việc develop Business Domain. Trong khi BDD chèo lái hành vi của system thì DDD sẽ mô tả chính xác những gì system cần có. TDD, khi đó sẽ là công cụ để bảo đảm Behavior và Domain sẽ được hiện thực đúng đắn.

Điểm khác biệt rõ ràng giữa chúng chính là chiều hướng của việc thiết kế. DDD theo chiều hướng middle-out. Nghĩa là sẽ bắt đầu với Domain Model, sau đó sẽ làm những phần xung quanh như GUI, DB, integration… Còn BDD, rõ ràng là theo hướng outside-in. Bắt đầu với use-case từ phía người dùng sẽ quyết định những thành phần cần có như Model, DB, UI…

Kết hợp tất cả lại

Thế giới ngày càng ưa chuộng Agile, nếu bạn muốn sử dụng TDD/BDD cùng với việc build một model mạnh với DDD, thì vẫn có cách để làm chuyện đó:

– [DDD] Đầu tiên sẽ tổ chức các buổi domain modelling workshop với domain experts hoặc/và với user để hiểu rõ về domain. Điều này giúp cho team có một cái nhìn tương đối, những hiểu biết ban đầu và các common vocabulary về hệ thống sắp được xây dựng.

– [BDD/ATDD] Với mỗi user story, chúng ta sẽ develop bộ acceptance test scenario. Acceptance Test Driven Development cũng giống như BDD là nó được viết dưới dạng ngôn ngữ tự nhiên để khách hàng có thể hiểu được.

ndc-2011-specflow-pragmatic-bdd-for-net-13-728

Nguồn hình ảnh: https://www.slideshare.net/jbandi/ndc-2011-specflow-pragmatic-bdd-for-net

– [BDD/ATDD] Sau khi đã có bộ acceptance test case, chúng ta sẽ tiến hành việc generate hoặc implement những bộ executable test dựa trên các test case đó. Sau đó sẽ tiến hành develope theo hướng outside-in. Có thể pass các test case bằng cách sử dụng test-double để giả lập những phần chưa hoàn chỉnh trong system nhằm hoàn thành scenario.

– [BDD/TDD] Lúc này kết hợp giữa BDD và TDD để implement những chi tiết còn lại. TDD lúc này là vô cùng quan trọng trong việc hiệu chỉnh (refactor) lại mã nguồn sau này.

– [BDD/TDD/DDD] Sau khi hoàn thành scenario, ta có thể refactor lại code cho đẹp và dễ maintenance. Có thể sử dụng Domain Model patterns (building blocks) để xây dựng phần Model.

– [DDD] Trong quá trình develop, chắc chắn Domain Model sẽ có nhiều thay đổi so với ban đầu, do đó cần phải liên tục update (làm mịn) model vào những thời điểm cần thiết.

Lời kết

Theo phong trào, mình sẽ để lời kết ở đây và không nói gì.

Xem lại các phần khác ở đây:

Và mình sẽ viết riêng 1 bài kết ở đây nữa:

edwardthienhoang

Book Review: xUnit Test Patterns: Refactoring Test Code: Gerard Meszaros

Khi đối diện với những điều không (chưa) biết, kẻ bi quan sẽ tỏ ra lo sợ và trốn chạy, người lạc quan thì không như vậy, họ luôn biết cách đối mặt với nó.

Vào những năm cuối thập niên 90, khi phong trào eXtreme Programming mới bắt đầu được khai nén, đã có những nhóm, những nhà tiên phong đi đầu trong việc áp dụng các kỹ thuật của nó như pair programming, collective ownership và test driven development. Tuy nhiên, họ đã gặp phải rất nhiều vấn đề trong đó, ví dụ như là làm thế nào để apply TDD, viết và quản lý test code cho real-world project. Khi production code lẫn test code bắt đầu phình ra cũng là lúc họ nhận ra rằng ngày càng tốn nhiều effort chỉ để làm những công việc lặp đi lặp lại. Đã có lúc, đến 90% effort bỏ ra chỉ cho việc maintenance những unit test cases đã có chỉ để đáp ứng một thay đổi cực kỳ minor. Một con số thật sự làm nản lòng và gây hoang mang dù là những người lạc quan nhất. Và họ biết, họ cần phải làm gì đó để thay đổi điều đó.

3394674118_28fd307467

TDD, kẻ thì khen, người thì chê. Kẻ khen thì trầm trồ về sự ưu việt của nó, kẻ chê thì nói TDD thực sự chỉ là 1 thứ rối rắm, tốn nhiều công lắm của mà không thực sự giải quyết được bài toán mà họ gặp phải. Nhưng có mấy kẻ hiểu được làm TDD như thế nào cho effective. Khi đối diện với một dự án phức tạp, vấn đề gây đau đầu nhất trong mỗi lần thay đổi source code chính là degradation, làm sao để analyze và thực hiện regression test để bảo đảm code change là “vô hại” đến những phần khác. Những lúc như vậy, ai cũng mong có một bộ automated test để phòng thân, nhưng cái giá của nó không phải là free, hoặc có thể là vô giá.

Prorgramming is hard, hay nói cách khác, tạo ra những đoạn code trong sáng, dễ maintain và extend là không dễ. Trừ khi ta nắm được các bí quyết để làm chuyện đó. Bằng cách nhận biết đâu là những đoạn code tệ (code smell), hay mở rộng ra là project smell, architecture smell, environment smell, ta sẽ biết cách để sửa chữa chúng. Refactoring những chỗ không tốt thành tốt hơn đòi hỏi những kỹ thuật cao hơn như nắm vững các coding, design principle, patterns. Khi đó, code sẽ trở nên sáng sủa và vững vàng hơn nhiều, programming is now easy and much more exciting, like a joy!! ^^

Testing is extremely hard, vì trường học không (kịp) dạy ta các kỹ năng về kiểm thử. Programmer thích lập trình, sợ bugs, ghét tester… nên đâm ra ghét testing. Đặc biệt không có anh nào code dở mà có thể test (unit, at least) giỏi, mấy người như vậy qua làm tester hết rồi. Còn lại những anh code dở và test cũng dở, và những anh code vốn giỏi mà test dở. (Chỗ này hại não =)) Với những anh code giỏi thì khả năng để improve kỹ thuật testing là tương đối dễ dàng, những anh khác, vui lòng quay lên phần “Programming is hard”.

Để make (Unit) Testing more fun and do-able, việc đầu tiên chính là phải code giỏi cái đã. “Code that hard to test is the bad code”. Vậy làm sao để nhận diện đâu là code tệ? Đa phần đã nghe đến code smell, vậy còn test smell. Sử dụng test smell để nhận diện các vấn đề gây khó khăn cho việc viết test là bước đầu tiên. Test smell có thể bao hàm rất nhiều thứ kể cả code smell. Bên cạnh đó, cũng giống như programming, testing cũng có principle và pattern của nó. Nói chung, mọi thứ đều có nguyên tắc, tuân thủ theo luật lệ sẽ cho ra các sản phẩm unit-test chất lượng.

Nếu ai đủ kiên nhẫn đọc đến đây thì sẽ thắc mắc, viết dông dài vậy làm gì. Ah, tất nhiên là mình giới thiệu sách rồi (thực ra là khoe cuốn sách mới mua, mới đọc được có cái (hard)cover và cái preface đã bay lên chém gió như thần).

Tên cuốn sách
xUnit Test Patterns: Refactoring Test Code: Gerard Meszaros

Mục đích cuốn sách:
– Giải tỏa nỗi sợ về (automated) (unit) testing. Là nguồn cảm hứng và chỗ dựa (kỹ thuật) vô cùng bổ ích cho những ai đã, đang và sẽ có dự định improve productivity throuhg testing. Cuốn sách đề cập đến các kỹ thuật develop automated unit test case, các test smell để giúp programmer tránh các lỗi thường gặp lúc viết production code và test code + các cách refactoring chúng. Test principle là kim chỉ nam cho việc viết test, test design patterns là các practices áp dụng cho từng trường hợp cụ thể.
– Nếu xem GoF là kinh thánh cho dân Production Code thì xUnit Test Patterns này là dành cho Test Code.

For fun:
– (Khoe) Sách gốc hardcover $79.99. Dày 900 trang, nặng gãy tay :)))
– Người review trên tinh thần chém gió là chính chứ mới đọc được cái cover thôi =))
– Chỉ có cuốn sách trong hình là thật
– Link ebook cho dân không đủ điều kiện: google nhé 😉

Domain Drive Development (DDD) – First thought – Part 1

Nhan nhản trên Google có các câu hỏi đại loại như: so sánh giữa TDD (Test Driven Development) và DDD (Domain Driven Development), phương pháp nào tốt hơn? Rồi lại có BDD (Behavior Driven Development), CBD (Component-based Development) làm mình không khỏi confuse, tuy nhiên trong 1 phút suy nghĩ và cũng có được câu trả lời cho riêng mình. CDD mới là số 1. Cafein Driven Development. Người Việt ta thường có thói quen uống cafe, rảnh rỗi uống cafe, muốn thức khuya, uống cafe, vò đầu bứt tóc thì càng cần 1 tách cafe, vậy nên nó là tốt nhất.

TDD thì nghe nhiều làm nhiều (ko nhiều nhưng nói cho nó có vần). Vậy thì mình có thể tóm gọn nó trong 1 2 từ không? OK, TDD là 1 quy trình. Quy trình trong việc viết mã mà trước đó phải có unit test (automated). Mình không bàn sau về TDD, chỉ muốn nhấn mạnh đế chữ quy trình. Quy trình là gì: – Quy trình (規程 – Procedure) là trình tự (thứ tự, cách thức) thực hiện một hoạt động (#) đã được quy định, mang tính chất bắt buộc, đáp ứng những mục tiêu cụ thể của hoạt động (Wikipeadia). Nghĩa là cứ vậy mà triển khai, muốn viết code, cộng trừ nhân chia gì đó, hãy viết cùng với bộ test case.

business-plan-3

DDD thì mới nghe cách đây vài năm, lúc đó còn trẻ, còn đam mê với kỹ thuật, công nghệ này nọ, công nghệ, framework nào mới ra cũng muốn học, làm thử và trầm trồ, khen chê. Đến dạo gần đây, sau 1 thời gian cảm thấy không còn hứng thú với mớ công nghệ đó nữa (già rồi chăng, phần này làm biếng mô tả), lại nghe người trên nhắc nhiều đến domain, architecture của hệ thống. Chỉ cần nắm được domain và kiến trúc của hệ thống thì coi như làm chủ được nó. Mình đặc biệt thích thú về mảng kiến trúc, tuy nhiên trong bài này cùng bàn luận về domain 1 chút.

Domain là gì?

Domain, là kiến thức về business, hoàn toàn không liên quan đến công nghệ (technology). Vậy thì có ý nghĩa gì về mặt lợi ích khi 1 dân công nghệ lại chỉ đi học về chứng khoán, ngân hàng, bán lẻ,..?

Các bạn – dân công nghệ, có khi nào tự hỏi rằng khi làm việc trong 1 dự án (đặc biệt là outsourcing), thì chỉ biết cắm đầu làm, focus vào công nghệ, khi gặp trouble thì không thể tự giải quyết, đưa ra đề xuất mà toàn phải Q&A để nhờ giúp đỡ từ khách hàng. Rồi khi dứt áo ra đi, cái mà mình để lại cho người sau, có chăng chỉ là những tips và tricks, class diagram, troubleshootings cái environment quái quỷ. Rồi họ cũng chật vật như bạn, cho dù mình đi đâu đi chăng nữa.

Các bạn – lại là dân công nghệ, lần này có nhiệm vụ phát triển các hệ thống inhouse, cây nhà lá vườn (bự bự chút nha). Có khi nào khi được đưa vào project, liền mở source code ra đọc xem nó xài MVC hay MVVM, Database config ra sao, rồi khi nhận 1 task thì grep, debug hoặc hỏi người kế bên coi code trong class nào, mà hoàn toàn không hiểu được ngữ cảnh của công việc, bug văng từa lưa, nhiều khi cũng chẳng hiểu nổi thằng quái nào để lại đoạn “mật mã” này, làm gì với nó bây giờ. Có khi nào 1 dự án fail vì khách hàng không chịu làm acceptance, cả 2 phía dường như không hiểu được nhau, thôi đành chia tay, khách hàng cho anh phần đặt cọc, còn anh mất 1 khách hàng, tiền đâu nuôi đám dev bây giờ? Đuổi việc, giải thể công ty cho khỏe.

Sau 1 hồi vẽ ra những ngữ cảnh ở trên, chắc sẽ có nhiều người giật mình, và bắt đầu lo lắng, vậy tôi phải làm sao đây, chẳng lẽ đời đến đây là hết sao, sắp bị đuổi việc thật sao. Nhưng không sao, hãy bình tĩnh các bạn à, cùng nhau đi đến hết bài viết rồi hãy quyết định làm gì tiếp theo.

Deep dive into Domain and bring Domain belong/in to Project

Có 2 vế, thứ nhất là hãy học tập về domain mà cả team đang phát triển. Nếu một project tầm nhỏ và vừa thì chỉ cần các bạn developer năng động lên 1 chút, trong quá trình làm, phải document lại những kiến thức và hiểu biết của mình về 1 nghiệp vụ nào đó và cùng share cho cả team, mỗi người đảm nhận 1 module, nghiệp vụ, sau này có thể hoán đổi vị trí cho nhau để hiểu sâu hơn về phần khác. Keyword ở đây chính là: Knowledge Base. Nghĩa là mọi thứ đừng nên để trong đầu mỗi người, mà phải được viết ra, hiện hữu trên giấy tờ, tài liệu, đem nó vào 1 chỗ shareable cho toàn team như wiki hoặc 1 shared folder nào đó. Đến một ngày, kho kiến thức của cả đội (về cả nghiệp vụ và kỹ thuật) sẽ ngày càng hoàn thiện, mọi người ai cũng happy vì khi đề cập đến 1 vấn đề nào đó thì có thể hình dung ra, giải quyết nó hoặc đưa ra giải pháp cho khách hàng. Ai cũng được tăng lương, ngày làm 8 tiếng.

Nếu một dự án quá bự, các bạn developer phần không có thời gian để tìm hiểu tường tận, phần phải vò đầu với các công việc về mặt technical và integration thì hãy chào đón các thành viên mới cho đội của mình, các BA (Business Analyst). BA là người có đầu óc phân tích về nghiệp vụ rất tốt, vì họ được đào tạo các kỹ năng để làm chuyện đó. Đứng giữa khách hàng và các developer chính là các vị BA. Họ luôn sẵn sàng lắng nghe và truyền tải thông điệp giữa 2 phía. (Lưu ý ở đây là cả 2 phía chứ không phải chỉ là người truyền tải requirement từ khách hàng đến các dev, các dev ở đó có la ó cũng mà trời cao cũng không thấu là không được, cần phải nghĩ đến chuyện hòa hợp giữa business aspect và technical aspect). Trách nhiệm chính của các ông/bà BA là phân tích requirement khách hàng nói bằng ngôn ngữ tự nhiên, distill (chắt lọc) và modeling (mô hình hóa) thành dạng requirement mà dev có thể hiểu và thực hiện được.

Đó là phần ý tưởng (idea), còn đây là phần hiện thực nó. Sẽ gộp chung cho cả 2 phía, Dev và BA. DDD chính là chìa khóa. Bất kể là Dev hay BA thì cũng nên biết đến phương pháp này để làm cho cuộc sống happier.

DDD là gì, nó sẽ làm được những gì, so sánh, kết hợp với các xDD khác như thế nào, mời các bạn đón xem ở phần 2.

edwardthienhoang.

TDD – From the Inside Out or the Outside In?

Often the hardest part of programming is knowing where to start. With test-driven development the right place to begin is with a test, but when faced with a blank page, it can be daunting.

Is it best to start with the detail of what you are building, and let the architecture form organically using an Inside Out approach? Or, do you start with the big picture and let the details reveal themselves using Outside In?

Inside Out TDD (Bottom Up/Chicago School/Classic Approach)

Although all developers should be mindful of the bigger picture, Inside Out TDD allows the developer to focus on one thing at a time. Each entity (i.e. an individual module or single class) is created until the whole application is built up. In one sense the individual entities could be deemed worthless until they are working together, and wiring the system together at a late stage may constitute higher risk. On the other hand, focussing on one entity at a time helps parallelise development work within a team.

Taking the game Tic-Tac-Toe as an example, one solution could include at least three entities-a Board, a Prompt, and a Game.

Using the Inside Out approach, the Board and the Prompt are easily identifiable as standalone, whereas the Game integrates the entities across the whole system.

Starting with the Board, the developer can think of the functionality required for this one entity, and implement those responsibilities one test at a time.

For example, the board will need to be updated with a player’s move, so a test similar to the below can be added, and the functionality implemented.

public class BoardTest {

    @Test
    public void updateBoardWithUsersMove() {
        Board board = new Board("- - - " +
                                "- - - " +
                                "- - -");

        Board updatedBoard = board.update(1, X);

        assertThat(updatedBoard.symbolAt(1), is(X));
    }
}

The board will need to identify winning combinations, so these tests could be added one at a time in order to drill out that functionality.

    @Test
    public void hasWinningRow() {
        Board board = new Board("X X X " +
                                "- - - " +
                                "- - -");

        boolean hasWinningLine = board.hasWinningLine();

        assertThat(hasWinningLine, is(true));
    }

    @Test
    public void hasWinningColumn() {
        Board board = new Board("X - - " +
                                "X - - " +
                                "X - -");

        boolean hasWinningLine = board.hasWinningLine();

        assertThat(hasWinningLine, is(true));
    }

    @Test
    public void hasWinningDiagonal() {
        Board board = new Board("X - -" +
                                "- X -" +
                                "- - X");

        boolean hasWinningLine = board.hasWinningLine();

        assertThat(hasWinningLine, is(true));
    }

Once the Board is deemed complete, the next entity can be considered. The Prompt, which is unrelated to the Board, can be started and the developer can test that the correct wording is displayed to the screen when asking for the player’s input.

public class PromptTest {

    @Test
    public void promptsForNextMove() {
        Writer writer = new StringWriter();
        Prompt prompt = new Prompt(writer);

        prompt.askForNextMove();

        assertThat(writer.toString(), is("Please enter move:"));
    }
}

The developer is thus tackling one isolated piece of functionality at a time.

When it comes to the Game, which is the top level, all the pieces must be put together, with the individual entities interacting with each other.

public class GameTest {

   @Test
   public void gameIsOverWhenWinningMoveMade() {
     Writer writer = new StringWriter();
     Reader reader = new StringReader("6\n");
     Prompt prompt = new Prompt(reader, writer);

     Game game = new Game(prompt, new Board("X - - " +
                                            "X O O " +
                                            "- - -"));

     Board updatedBoard = game.play();

     assertThat(writer.toString(), containsString("Please enter move:"));
     assertThat(writer.toString(), containsString("Player X won!"));
     assertThat(updatedBoard.symbolAt(6), is(X));
   }
}

Because Inside Out TDD focuses initially on the individual entities of the system, the risk of these entities not interacting correctly with each other is pushed to a later stage. If the entities do not communicate as expected, there will be re-work.

From the above test case, it has become clear that a winning message needs to be printed by the prompt, detailing whether player X or O won the game. As the winning symbol is not currently available from the Board, it would need to be implemented retrospectively by adding another test to the Board entity.

    @Test
    public void hasCorrectWinningSymbol() {
        Board board = new Board("X - - " +
                                "X - - " +
                                "X - -");

        PlayerSymbol winningSymbol = board.getWinningSymbol();

        assertThat(winningSymbol, is(PlayerSymbol.X));
    }

The prompt would then require updating to provide a method which takes this winning symbol, and announces the winner.

    @Test
    public void displaysCongratulatoryMessage() {
        Writer writer = new StringWriter();
        Reader reader = new StringReader("");
        Prompt prompt = new Prompt(reader, writer);

        prompt.displayWinningMessageForPlayer(X);

        assertThat(writer.toString(), is("Player X won!"));
    }

This example demonstrates that when using Inside Out TDD, full understanding of the system design is not required at the beginning. Only one entity needs to be identified to get started. The inner details of that entity emerge through the use of specific unit tests, leading to a design that adheres well to the Single Responsibility Principle (SRP). At the initial stage, it is not always clear what behaviour needs to be exposed on an entity. This could result in more, or less behaviour being exposed than is required.

With Inside Out, if there is a cluster of entities expressing a behaviour, such as the Game, unit tests can span more than one entity (as the Board and Prompt are also being used). This means that collaborating entities can be replaced without changing the test, providing a framework for safe refactoring.

For example, if a PrettyWriter was to be used in place of a StringWriter in the Game, apart from injecting the right instance into the Game on creation, the rest of the test remains untouched.

    @Test
    public void gameIsOverWhenWinningMoveMade() {
        Writer writer = new PrettyWriter();
        Reader reader = new StringReader("6\n");
        Prompt prompt = new Prompt(reader, writer);

        Game game = new Game(prompt, new Board("X - - " +
                                               "X O O " +
                                               "- - -"));

        game.play();

        assertThat(writer.toString(), containsString("Player X won!"));
    }

It is worth noting that bug finding can prove more difficult with Inside Out as several entities need to be considered when investigating issues.

Finally, when new to a programming language then Inside Out is a good starting point. The developer only needs to focus on one entity at a time, building knowledge of the language and test framework as they go. Inside Out generally has no requirement for test doubles because the entities are all identified up front so the real implementations are available for use.

Outside In TDD (Top Down/London School/Mockist Approach)

Outside In TDD lends itself well to having a definable route through the system from the very start, even if some parts are initially hardcoded.

The tests are based upon user-requested scenarios, and entities are wired together from the beginning. This allows a fluent API to emerge and integration is proved from the start of development.

By focussing on a complete flow through the system from the start, knowledge of how different parts of the system interact with each other is required. As entities emerge, they are mocked or stubbed out, which allows their detail to be deferred until later. This approach means the developer needs to know how to test interactions up front, either through a mocking framework or by writing their own test doubles. The developer will then loop back, providing the real implementation of the mocked or stubbed entities through new unit tests.

Using the same Tic-Tac-Toe example, the implementation starts with a failing high level acceptance test for the scenario “Given the winning move is taken, the game should display a winning message”.

public class GameTest {

    @Test
    public void gameShouldEndIfThereIsAWinningRowInTheGrid() {
        Board board = new Board("X X - " +
                                "O - O " +
                                "- - -");

        PromptSpy promptSpy = new PromptSpy("2");
        Game game = new Game(promptSpy, board);

        game.play();

        assertThat(promptSpy.hasAnnouncedWinner(), is(true));
    }

This test will result in many entities being created, although initially the result could be hardcoded with the expected outcome.

public class Game {

    private Prompt prompt;

    public Game(Prompt prompt, Board board) {
        this.prompt = prompt;
    }

    public void play() {
        prompt.displaysWinningMessageFor(X);
    }
}

A PromptSpy is used in order to defer the real implementation of the Prompt until later. The GameTest can verify that the Prompt is communicating correctly. Once the interface of Prompt is defined, the developer can switch to writing unit tests for the real Prompt implementation in isolation.

Often test frameworks offer mocking functionality out of the box, and some developers prefer to write their own. This is a surprisingly straightforward task for languages such as Java, where there is strict typing, but can prove more difficult in dynamic or functional orientated languages.

class PromptSpy implements Prompt {
    boolean hasDisplayedWinningMessage = false;

    public PromptSpy(String playersMove) {
    }

    public void displaysWinningMessage() {
        hasDisplayedWinningMessage = true;
    }

    public boolean hasAnnouncedWinner() {
        return hasDisplayedWinningMessage;
    }
}

The next test shows players making moves until the game is drawn. At this point, smarter logic needs to be implemented so that the game can read in the players’ moves.

  @Test
    public void playersTakeTurnsUntilTheGameIsDrawn() {
      String seriesOfMoves = "1\n2\n5\n3\n6\n4\n7\n9\n8\n";
      PromptSpy promptSpy = new PromptSpy(seriesOfMoves);

      Board board = new Board("- - - " +
                              "- - - " +
                              "- - -");
      Game game = new Game(promptSpy, board);

      game.play();

      assertThat(promptSpy.hasAnnouncedDraw(), is(true));
      assertThat(promptSpy.numberOfTimesPlayersPromptedForMove(), is(9));
    }

This means the PromptSpy needs updating to count the number of times the players are prompted to enter their move, as well as ensuring the draw message has been displayed.

class PromptSpy implements Prompt {
    private boolean hasDisplayedWinningMessage = false;
    private boolean hasDisplayedDrawMessage = false;
    private int numberOfTimesUsersPrompted = 0;
    private final BufferedReader reader;

    public PromptSpy(String playersMove) {
        reader = new BufferedReader(new StringReader(playersMove));
    }

    public int read() {
        try {
            return Integer.valueOf(reader.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void displaysWinningMessage() {
        hasDisplayedWinningMessage = true;
    }

    public void displaysDrawMessage() {
        hasDisplayedDrawMessage = true;
    }

    public void promptUserForMove() {
        numberOfTimesUsersPrompted++;
    }

    public boolean hasAnnouncedWinner() {
        return hasDisplayedWinningMessage;
    }

    public boolean hasAnnouncedDraw() {
        return hasDisplayedDrawMessage;
    }

    public int numberOfTimesPlayersPromptedForMove() {
        return numberOfTimesUsersPrompted;
    }
}

At this point, the Game class could look something like the following.

 public class Game {

    private final Board board;
    private Prompt prompt;

    public Game(Prompt prompt, Board board) {
      this.prompt = prompt;
      this.board = board;
    }

    public void play() {

      while (board.hasFreeSpaces() && !board.hasWinner()) {
        prompt.promptUserForMove();
        board.update(prompt.read(), nextSymbol());
      }

      if (board.hasWinner()) {
        prompt.displayWinningMessageForPlayer(board.getWinningSymbol());
      } else {
        prompt.displayDrawMessage();
      }
    }
}

It can be seen through this example that when using Outside In TDD the developer needs some prior knowledge of how the entities in the system will communicate. Focus is usually on how the entities interact rather than their internal details, hence the use of high level acceptance tests. Outside In solutions often apply the Law of Demeter-a new entity is never created without the primary entity asking what it wants from it. This adheres well to the “Tell Don’t Ask” principle, and results in state only being exposed if required by other entities.

With Outside In TDD the implementation details of the design are in the tests. A change of design usually results in the tests also being changed. This may add more risk, or take more confidence to implement.

Conclusion

Both approaches form part of a developer’s tool kit. If the programming language and the domain are well known, then either approach can be successful. Because both approaches advocate good testing, they provide a safe refactoring environment which helps lead to a robust design.

Inside Out TDD favours developers who like to build up functionality one piece at a time. It can be easier to get started, following a methodical approach of identifying an entity, and drilling out its internal behaviour. With Outside In TDD, the developer starts building a whole system, and breaks it down into smaller components when refactoring opportunities arise. The path can feel more exploratory, and is ideal for situations where there is a general idea of the goal, but the finer details of implementation are less clear.

Ultimately the decision comes down to the task at hand, individual preference, and the methodology of team collaboration. If the tests are very difficult to configure, it may be a sign that the design is too complicated. Entities must be continually reviewed to look for refactoring opportunities.

The goal of each approach is the same-to build a working, reliable system with a maintainable internal design.

https://8thlight.com/blog/georgina-mcfadyen/2016/06/27/inside-out-tdd-vs-outside-in.html

The Solution to Technical Debt

From http://blog.crisp.se/2013/07/12/henrikkniberg/the-solution-to-technical-debt

By Henrik Kniberg

(related article: Good and Bad Technical Debt – and how TDD helps)
(Translations: Russian)

Are you in a software development team, trying to be agile? Next time the team gets together, ask:

How do we feel about the quality of our code?

Everyone rates it on a scale of 1-5, where 5 means “It’s great, I’m proud of it!” and 1 means “Total crap”. Compare. If you see mostly 4s and 5s, and nothing under 3, then never mind the rest of this article.

If you see great variation, like some 5s and some 1s, then you need to explore this. Are the different ratings for different parts of the code? If so, why is the quality so different? Are the different ratings for the same code? If so, what do the different individuals actually mean by quality?

Most likely, however, you will see a bunch of 2s or worse, and very few 4s and 5s. The term for this isTechnical Debt, although for the purpose of this article I’ll simply call it Crappy Code.

Congratulations, you have just revealed a serious problem! You have even quantified it. And it took you only a minute. Anyone can do this, you don’t have to be Agile Coach or Scrum Master. Go ahead, make it crystal clear – graph the results on a whiteboard, put it up on the wall. Visualizing a problem is a big step towards solving it!

Don’t worry, you aren’t alone, this is a very common problem. <rant>However, it’s also a very stupid, unnecessary problem so I’m baffled by why it is so common.</rant>

Now you need to ask yourselves some tough questions.

Do we want to have it this way?

If not, what do we want the code quality to be? Most developers want a quality level of 4 or 5. Yes, the scale is arbitrary and subjective but it’s still useful.

If opinions vary strongly then you need to have a discussion about what you mean by quality, and where you want to be as a team. You can use Kent Beck’s 4 rules of Simple Code as a reference point. It’s hard to fix the problem if you can’t agree on where you want to be as a team.

What is the cause of this problem?

This is just a rhetorical question, because the answer is clear.

“Things are the way they are because they got that way!” -Jerry Weinberg

Crap gets into the code because programmers put it in! Let me make that crystal clear: Crappy Code is created by programmers. The programmer uses the actual keyboard to punch the actual code into the actual computer. Irregardless of other circumstances, it is the actions of the programmer that determine the quality of the code

The first step in solving technical debt, is to admit and accept this fact.

“but wait, we inherited a bunch of crappy legacy code. We did NOT write it!”

OK, fair enough. The relevant question in that case is: “is code quality improving or getting worse?” Rate that on a 5 point scale (where 1 is “getting worse fast”, 5 is “getting better fast”). Then reapply this article based on that question instead.

Why are we producing crappy code?

The answer will vary. However, I’ve asked it many times and I see some very strong trends.

It’s probably not because you WANT to write crappy code. I’ve never met a developer who likes writing crappy code.

It’s probably not because you don’t know HOW to write clean(ish) code. The skills will vary, but it’s enough that you have a few people in the team with good skills in writing clean code, and a willingness from everyone else to learn. Combine that with a habit of code review or pair programming, and most teams are perfectly capable of writing code that they would rate a 4 or a 5, if they take the time they need.

It may be because of broken window syndrome. Crappy code invites more crappy code, because people tend to adapt their new code to the quality of what’s already there (“when in Rome…”). Once you realize this, you can decide to simply Stop It, and introduce code review or pair programming to police yourselves.

However, the most probable reason for why you are writing crappy code is: Pressure.

I often hear comments like “we don’t have time to write clean code” (<rant>that statement is at worst a lie, at best a lame excuse</rant>). The truth is, you have 24 hours per day just like everyone else, and it’s up to you what you do with it. Face it. You do have time to write clean code, but you decided not to. Now let’s keep examining this concept of Pressure.

Where does pressure come from?

You might want to do a cause-effect analysis of this. Is the product owner pressuring you? Why? Who is pressuring the product owner? Who is pressuring the person who is pressuring the product owner? Draw the chain of pressure.

Then ask yourself. Is this pressure real? Do these people really want us to write crappy code? Do they know the consequence of crappy code (I bet you can list many), and do they really think it is worth it? Probably not. Go ahead, get on your feet and go ask.

Sometimes the cause of the pressure is the programmers themselves. Developing a feature almost always take longer than we think, and we really want to be a Good Programmer and make those stakeholders happy, so the pressure builds up from inside.

NOTE: sometimes there is business sense in writing crappy code.  Sometimes technical debt is Good. We may have a critically important short-term goal that we need to reach at all costs, or we may be building a throw-away prototype to quickly test the market. But that should be the exception, not the norm. If you clean up the mess you made as soon as the short-term goal is reached, or you actually throw away the throw-away prototype, then you won’t end up with a chronic case of Code Crapiness.

Shall we decide to stop this nonsense now?

This it the most important question.

If you are a programmer, the fact that you (as programmer) are responsible for the problem is actually Good News. Because that means you are perfectly capable of Solving the problem. And the solution is simple:

Stop Writing Crappy Code

(Just what the world needs – a new acronym: SWCC™)

“but but but but but…. we don’t have time… the PO bla bla bla, our release date bla bla”

No, spare me the excuses. Just Stop It.

Well OK, you might actually decide to continue writing crappy code. You might decide that this battle is not worth fighting. That’s your decision. If so, at least don’t call yourself an agile development team, and do challenge anyone else who thinks you are agile. One of the fundamental principles of Agile software development is Sustainable Pace. If you are consistently creating Crappy Code, development is going to get slower and slower over time. There is no business sense in this, and it is certainly not agile.

But assuming that you do want to stop, let’s explore what happens.

As a team of programmers, you can take a stand: “We Will Stop Writing Crappy Code”! Write it up on the wall. Shake hands on it. Add “no added technical debt” to your Definition of Done.

Tell the world, and the people who you believe are pressuring you into writing code: “We have been writing crappy code. Sorry about that. We’ll stop now.” Trying saying it loud. Feels good!

Stop Writing Crappy Code

Look at these two curves.

Yes, this is a simplification, but the difference is real. If you Keep Writing Crappy Code, you get slower and slower over time (as you spend more and more of your time wrestling the code). If you Stop Writing Crappy Code, you get a more sustainable pace. But there is velocity cost – you will slow down in the short term.

As team, you decide how much work to pull in – that pull-scheduling principle is fundamental to both Agile and Lean. It’s built into the agile methods. For example, in Scrum Sprint Planning the team chooses how many backlog items to pull into a sprint, same in XP Planning Game. In Kanban, the team has a work-in-progress limit and only pulls in the next item when the current one is Done. Basically, the team has full power and responsibility over quality. Use the power!

In concrete terms: If you are doing Scrum, and you’ve been delivering about 8-10 features per sprint, try reducing that. Only pull in 6 stories next sprint, despite any perceived pressure. Ask yourself at each sprint retrospective. “What is the quality of the code that we produced this sprint (scale 1-5)”. If it is less than 4-5, then pull in fewer stories next sprint. Keep doing that until you find your sustainable pace.

This has business implications of course. The product owner (or whatever you call the person who makes business priorities) will have to prioritize harder. She’s used to seeing 8-10 stories come out of each sprint. Now she will only see 6-7, so she needs to decide which stories NOT to build.

Yes, this will lead to arguments and tough discussions. The real source of pressure (if there was any) will reveal itself. Quality is invisible in the short term, and that needs to be explained. Take the battle! Stand by your decision. If programmers don’t take responsibility for the quality of their code, who will?

Code quality is not Product quality

Code isn’t everything. There’s more people involved in product development than just programmers. There’s business analysts, testers, managers, sysadmins, designers, operations, HR, janitors, and more.

Everyone involved is collectively responsible for the quality of the product being built. That includes not only the code, graphical design, database structure, and static artifacts like that. It includes the whole user experience as well as the business result of the product.

Code quality is a subset of product quality.  You can have great code, but still end up with a product that nobody wants to use because it solves the wrong problem.

What about vice versa – can you have a great product, but crappy code? I hate to admit it but, Yes, technically you can build a great product with crappy code. Somehow teams seem to get away with this sometimes. However, improving and maintaining the product is slow, costly, and painful, because the product is essentially rotten on the inside. It’s a lose-lose proposition and over time the best developers will leave.

What about the Old Crap (a.k.a Legacy Code)?

OK, so you’ve stopped writing crappy code. Congratulations! You’ve stopped accumulating technical debt. You’re still paying interest on your existing debt, but at least the debt has stopped growing.

Next step is to decide – can you live with the existing technical debt, or do you want to do something about it?  If you decide to reduce technical debt, the consequence is that you will slow down even further in the short term, but speed up over the long term. Like this:

Sometimes it’s worth it, sometimes not. The answer is not obvious, it’s a business decision, so make sure you involve the people who are paying for it.

If you decide to reduce your current technical debt, make that a clear decision: “We will Stop Writing Crappy Code, and Gradually Clean Up The Old Code”.

Once you agree on this (and that’s the hard part), there are plenty of techniques for how to do it. Here are two techniques that I’ve seen work particularly well:

  1. Add to your Definition of Done: “Technical debt reduced”. That means whenever you build a feature or touch the code, you leave the code in a better shape than you found it.  Maybe rename a method to make it more clear, or extract some duplicate code to a shared method. Small steps. But if the whole team (or even better, all teams) does this consistently, code quality will noticeably improve within a few months.
  2. For the larger cleanup areas, create a “tech backlog” & reserve time for it. For example, list the top 10 areas of improvement and commit to fixing one every week or sprint, before building any new features.

Just keep in mind that, however you do it, repaying technical debt means Fewer Features in the short term. Adapt your velocity forecasts and release plans accordingly. Just like any investment, there is a short-term cost. Make sure everyone is clear on that.

You need to Slow Down in order to Speed Up.

Final words

Bottom line: code quality is the responsibility of the people who actually write the code (otherwise known as Programmers).

As programmer, you own the problem, and you own the solution. There’s no need to fret or be ashamed of the past. Instead, stand proud and use your power to do something about it – make a loud decision toStop Writing Crappy Code. That will start a chain of events and Good Stuff will likely follow in the long term. It’s hard and it takes courage, but I don’t know any other way to solve technical debt.

Good luck!

/Henrik

FAQ

Is technical debt always bad?

No. Having some debt can be fine. See my other article Good and Bad Technical Debt (and how TDD helps).

The problem I’m talking about here is chronic, out-of-control, continuously growing debt. I’ve seen so many companies drowning in technical debt, moving painfully slow, losing key developers, and regretting bitterly that they didn’t take code quality seriously from the beginning because it’s so much more expensive to fix it afterwards. Cutting quality gives short term benefits, but the long term is longer than the short term, and most companies do want to survive in the long term.

What is technical debt anyway?

Anything about your code & development environment that slows you down. For example:

  • Unclear, unreadable code.
  • Lack of test automation, build automation, deployment automation, and anything else that could be automated that you do manually today.
  • Duplicate code.
  • Tangled architecture & unnecessarily complex dependencies.
  • Slow, ineffective tools.
  • Uncommitted code & long-lived branches (hides problems that will slow you down later).
  • Important technical documentation that is missing or out-of-date.
  • Unnecessary technical documentation that is being maintained and kept up-to-date.
  • Lack of test environments.
  • Long build-test cycle & lack of continuous integration.

Technical Debt và Legacy System

Technical debt – tạm dịch là “Khoản nợ kỹ thuật” được dùng nhiều trong Software Engineering. Theo Henrik Kniberg, những khoản nợ kỹ thuật là bất cứ thứ gì trong việc viết mã khiến bạn chậm lại về lâu dài. Ví dụ như là mã khó đọc, thiếu (hoặc không có) kiểm thử tự động, mã trùng lặp, hoặc sự liên kết lằng nhằng giữa lớp, mô-đun… (Think of technical debt as anything about your code that slows you down over the long term. Hard-to-read code, lack of test automation, duplication, tangled dependencies, etc. Henrik Kniberg).

cycle

Cũng giống như những khoản nợ về tài chính: có vay mới có nợ, có nợ ắt sẽ sinh lãi. Technical debt sinh ra vì nhiều lý do: áp lực kinh doanh, thiếu kỹ năng trong phân tích thiết kế cũng như kỹ năng lập trình, không có các bộ mã kiểm thử dẫn đến việc trì hoãn (hoặc không thể) tái cấu trúc lại mã nguồn… Nếu không được trả, theo thời gian, nợ sẽ đẻ lãi, dẫn đến việc chậm tiến độ, những đoạn mã mới được thêm vào sẽ mất nhiều thời gian và chi phí hơn, mà đa phần trong số đó là chi phí cho việc gỡ rối (debugging) và kiểm thử hồi quy (regression testing).

TechnicalDebt

Nếu bạn đang làm việc với 1 legacy system (có rất nhiều định nghĩa về legacy code, nhưng mình thích nhất định nghĩa của Robert C. Martin: legacy code = code without test) nghĩa là bạn đang mang trên mình món nợ về kỹ thuật. Một đoạn mã được viết cách đây 10 năm cũng gọi là legacy code, một đoạn mã được viết ngày hôm qua cũng gọi là legacy code nếu chúng đều không được “chống lưng” bằng mã kiểm thử. Và nếu bạn vẫn tiếp tục tạo ra những đoạn mã “without test”, cũng tức là bạn đang tự đẻ thêm nợ cho chính system của mình. Điều đó cũng giống như việc bạn thêm vào những đoạn mã khó đọc, mã trùng lặp, hoặc sự kiên kết lằng nhằng giữa lớp, mô-đun… (Có phải mình cũng vừa lặp lại những gì đã nói ở trên?).

Vậy bạn sẽ trả nợ bằng cách nào? Hay thõa hiệp trước món nợ + lãi đang ngày một tăng khi mã mới được thêm vào?
Có hàng tá lý do để biện minh cho việc thõa hiệp, có thể kể ra như: đừng phá vỡ những đoạn mã đã chạy ổn định, hệ thống chúng ta quá phức tạp, do đó cần thêm thời gian để (tìm hiểu) thêm mới hoặc sữa chữa một đoạn mã nào đó (và đảm bảo không phá vỡ những đoạn mã hiện tại). Có một câu ví von khá hay về vấn đề này. “The code may not be pretty, but damnit, it works!” dùng để nói về Duct Tap Programmer – người viết mã chỉ để “chạy được”.
Nếu chọn cách trả nợ, những việc bạn sẽ làm là đừng (hoặc hạn chế) để lại nợ nần cho những thế hệ (mã) phía sau. Và điều đầu tiên đó là Hãy ngừng việc tạo ra những đoạn mã xấu (Stop writing crappy code).

TechnicalDebt-StopWritingCrap-vs-KeepWritingCrap

TDD đã khó, TDD cho legacy system còn khó gấp bội. Bài viết dưới đây của Mark Levison bàn về việc những vấn đề gặp phải khi áp dụng TDD trong Legacy System, qua đó trích dẫn 1 số phương pháp của Keith Ray – XP Coach để làm việc với legacy code nhằm giảm (paying down) những khoản technical debt, dựa trên nền tảng cốt lõi là viết mã sạch, tái cấu trúc mã nguồn và bỏ túi SOLID principles.

Xin trích dẫn nguyên văn bài viết bởi Mark Levison từ http://www.infoq.com/news/2009/11/legacy-code

Allan Baljeu was trying to TDD with a legacy C++ code base, he was running into trouble because:

we end up with classes that don’t fully implement the functionality that’s eventually needed, and when others come around to use those classes, and eventually fuller implementations are required, then it turns out that the original design is not adequate, a new design is required, some expectations (tests) need to change and previous uses of the class need to be updated.

He wondered if Big Design Up Front would help solve the problem. George Dinwiddie, Agile Coach, suggested that Alan’s design was trying to tell him something. You have to pay attention to the fundamentals of clean code. You can look at basic coupling and cohesion (i.e. SOLID).

Mike “Geepaw” Hill, Agile Coach, says that in his years of coaching agile teams, one of the following has been at the root of these problems:

  • team is not yet up to speed on refactoring, so your classes aren’t really
    minimal
  • team is not yet skilled at simplicity, so ditto
  • team is not yet doing aggressive & rapid microtesting (aka unit testing), so changes break tests too often
  • team doesn’t know how to handle cross-team or company-to-public dependencies, e.g. shipping api’s
  • team neither pairing nor open workspacing, dramatically slowing team-wide understanding.
  • team likely has no jiggle-less build
  • team could be using tools from the ’40s

Keith Ray, XP Coach, suggests that with legacy code (i.e. systems with high technical debt) the cost of repaying technical debt dominates the cost of implementing a story. He goes on to offer an approach:

To make the code more well-factored (paying down the technical debt), whenever you need to integrate a new feature into it, you should pay close attention to code smells in both the new code and the old code and consider refactoring to deal with each smell as you recognize it.

You can do refactorings in small safe steps (even in C++) manually. Very closely follow the instructions in Fowler’s book on Refactoring until you learn them by heart. Eclipse with gcc has a few refactorings that actually work: Extract Method and Rename. Rename understands scope, so it is safer than search-and-replace. Extract Method and the other refactorings in Ecipse might be buggy, so be careful when you use them. For things like changing a function signature, “lean on the compiler” to show where changes have to be made.

You also need tests to make sure the refactorings are not damaging the existing features. Feather’s book on working with legacy code has lots of techniques for adding tests to legacy code. On a higher level, code smells are violations of good design principles. For example, the Single Responsibility Principle (SRP) says there should one purpose for every class / method / module. There are principles about coupling and cohesion and managing dependencies, etc. It’s often easier to detect a code smell than it is to apply these abstract principles. “Large Class” and “Large Method” are remedied by “Extract Class” and “Extract Method/Move Method”, though knowing SRP helps in deciding what parts of a class or method should be extracted.

Perhaps the most important design principle is “Tell, don’t ask”: keep functionality and data together…. bad code often has the functionality in one place, and gets the data it needs from other places, creating problems with dependencies and lack of locality — symptomized by “adding a new feature requires changing lots of code”. The code smells “Shotgun Surgery”, “Feature Envy”, “Long Parameter List” are applicable here.

Getting fast feedback will allow more refactoring, which will (eventually) allow faster development of new features. Try to get parallel builds happening (distributed compilation). Try to get smaller source files and smaller header files. Reduce the complexity of header files – use forward declarations, avoid inline code, try to keep only one class per header file / source file. Using the “pimpl” idiom widely can decrease compile time by 10%, but it can also disguise the “Large Class” and “Feature Envy” code smells.

The advantage of refactoring instead of rewriting, is that you always have working code. If your manual and automated tests are good, then you should be able to ship the code, even if it is a half-way state between a bad design and a good design.

Keith also wrote “Refactoring: Small Steps Guaranteed to Help You Clean Up Your Code” an article on refactoring C++ code in Better Software Magazine.

Previously on InfoQ: Dealing with Legacy Code, Uncle Bob On The Applicability Of TDD andMaking TDD Stick: Problems and Solutions for Adopters

What does TDD mean?

From http://blog.goyello.com/2011/08/29/what-does-tdd-mean/

Pawel Olesiejuk

 

Test Driven Development (TDD) is not about writing tests. Writing tests is writing tests, period. TDD is more than that, it’s a methodology.  It has started as a part of the agile methodology invented by Ken Beck called eXtreme Programming (we recommend Kent Beck’s book “Extreme Programming Explained”). The main idea of TDD is to write tests before code. It’s seems to be irrational but it’s not!

I try to do TDD every time when I’m writing code, but I won’t name myself a TDD expert. Experts like Robert C. Martin a.k.a. Uncle Bob, Kent Beck, Roy Osherove, Corey Haines and my teacher Kristoph Manuszewski, just to name a few, inspired me.

I’d like to share my knowledge about TDD and I’ll refer to articles/posts/books/screencast of people mentioned above.

It’s so f… simple

Most programmers can’t understand ‘Why the hell should I write a test for all code that I’m writing? It is so f… simple‘. Maybe it is, maybe it isn’t, but you can’t be sure that in the future the code remains the same. Edward V Berard says that ‘Walking on water and developing software from a specification are easy, if both are frozen’. Requirements are changing all the time, the environment is no longer stable. Perhaps someone else will extend/change your code. He is not you and he doesn’t know all the tricks you’ve used in your code. He can easily break your code without knowing it. This “he” could even be you after a couple of months.

Benefits of using TDD

It is proven that using TDD reduces the amount of bugs by at least 50% (The Cost of a Bug). I mean good TDD, not only automated tests. Consider this, how long does finding a bug take (and what about when an end-user finds it)? How long does tracing and fixing the bug take? How long do you need for integration tests to confirm you haven’t broken anything after fixing a bug?

Let’s assume the above will take 15 minutes to 3 hours per bug. How many bugs can there be in a single project? 100? 1000? So how much time do you spend on fixing them? This can easily grow up to 1,5h * 1000 = 1500h. Are you still there?

What would you say if you can save 750h in your project when using TDD? I think it is worth trying.

Tests are your safety net

Good tests (later on I’ll use “tests” for “good tests”) assure you that you haven’t broken anything in your previous functionality. This is the first (but not the only one) reason why you must (SIC!) write a test for every production code (production code is everything but tests) based functionality. If you have a code coverage of over 90% you will have certainty your code works. You won’t have to run the application to know that. This is your ‘safety net’, your parachute. Your tests should be as trustworthy as a net or a parachute.

Test driven code shows the user standpoint

When you write a test before writing production code you’ll understand how you (or somebody else) will use it, because the test is the first user of your code. And when you think from a user’s standpoint you will think about the interface first. This is a good design practice. Your code will be easy to use. It will become self explanatory.

Test Driven Design forces you to think upfront

Often after creating some class, you want to use it in another place and then you realize it cannot be reused in an easy way. It’s great and does lots of beautiful things at once. But it isn’t sufficiently useful. It isn’t flexible enough. It isn’t configurable, because you didn’t think of such things before.

If you’d written tests before you’d know about this stuff earlier and wrote this class in a different way. This is the greatest benefit of TDD!

Really, try it!

Usage specification better than documentation

Another advantage of tests is when someone reads them he’ll know how to use your code. Tests are like specification. Even better, they are usage specification, a tutorial ‘how to use the code’. Imagine that you are starting to use a new tool. With the tool you’ve got fat documentation with code samples on the back. What do you read first, API documentation or code samples? Furthermore, tests and code will always be in sync, so you don’t have to bother with synchronizing your documentation while the code is changing.

S.O.L.I.D. principles become natural

The next thing about writing tests before production code is that you won’t create big complex classes, because you really don’t want to write a complex test with lots of stubs. So, you will create small classes with only one responsibility. Your code will be decoupled, flexible and configurable. You don’t have to worry about S.O.L.I.D. principles. It will be so natural to follow them.

The proof of the pudding ….

In the end the proof of the pudding is in the eating. Therefor, to convince you probably the best example is a ‘real’ example. Robert C. Martin wrote series of articles about a young person (after school) who wants to become a programmer. But he didn’t want to write tests because he ‘can do this right without tests. It is so f… simple‘. I really recommend reading the whole story! You will find it here: http://www.objectmentor.com/resources/publishedArticles.html -> By Topic -> Craftsman

Test Driven Development gives you the opportunity to create well designed, flexible and easy to use code, good dependency decoupling and specification at once. Saying that writing tests before code costs you too much time is senseless. Redesigning, rewriting, debugging and creating specifications takes much more time. Furthermore, tests can assure you that your code (always) works, this is a priceless thing and nothing but automatic tests can give you such certainty. So… DO TDD!!

We Are Complicating Things a Bit too Much (TDD & DDD)

The other day, I saw something that really encompasses one of the biggest hurdles for younger developers to get through. That hurdle is terminology. These days, there is all sorts of “___ driven development”. In our team, we even joke about “assumption driven development”.

Naming things is one of the hardest things to deal with in programming. It gets worse when we are doing something that is uncomfortable. Make it worse, before we ever started programming there are tons of people who have already named things (and naming things was hard for them too).

And see, this is where we as a community come in and can help people understand things a lot easier. Of course it doesn’t hurt if we don’t muck up some serious patterns and terminology even more (no I’m not talking about Facades, the argument over that hurt the community more).

All The Driven Development

One of the big things that bothered me the other day was hearing someone say “you thought TDD was hard, wait until you change over to using DDD”. Maybe it was out of context, but I think that at heart, a lot of young developers (especially those that are freelancing or the most senior on a small young team) get confused. It used to be information on software patterns was a bit more limited: you hear something from a close coworker, that one message board you subscribe to, a professor, a senior dev, etc then you use it. Now, we face massively social communities where everyone spouts their ideas on Twitter, G+, SO, and more. A developer that would have been slowly introduced to design patterns, Extreme Programming/Agile Development, and best practices are instead bombarded with everything at once.

So I hope to clarify some confusion of thinking that TDD (Test Driven Development) and DDD (Domain Driven Development) are somehow in competition or mutually exclusive. They aren’t in fact! So I’ll dig in to what I’ve taken out of the two methods and where they fit together.

What Is TDD

TDD is the process of writing tests based on a particular desired pieced of functionality, letting them fail. Then you write the least amount of code possible to make the test pass, then write another test. Cycle this over and over until you have finished a feature and then go back and refactor. It’s a bit simplified, I know, but this is the heart of TDD. Don’t get stuck in the mud about it! Don’t worry about techniques, code structure, etc.

Don’t let people fool you!

TDD is just the process of testing code before writing it!

What Is DDD

DDD takes a bit more explaining. You see, a Domain is a set of functionality that you are attempting to mimic that lies outside of your application. Maybe this is a physical event like an election, maybe it’s something a bit more arbitrary such as a source code project initializer. You will want to assign a Domain Expert, this could be your project manager, yourself when you put on your spec writing hat for a new side project (that is really dangerous though), but most likely, your Domain Expert will be your client. The point is, to create something, you must first understand what it is you are trying to create! DDD describes the process of consulting and deciding on explicit definitions of each piece of the domain that you are trying to mimic. And you make sure that these definitions are written before ever writing code. Then these definitions and naming structures from your domain study are used to create a more informed code base. Then when you pick your head up for the next change, error, fix, whatever: you consult with the Domain Expert and turn programming talk back into the Domain terminology.

Don’t let people fool you!

DDD is the process of being informed about the Domain before each cycle of touching code!

Mixing the Two Together

Alright, so now lets see WILL IT BLEND!? That is the question. DDD lives mostly in how you research before coding, how you name things, and how you interact with the client. On the other hand, TDD is the process of actually writing your code. So, as you can see, there is no conflict of interest between the two strategies and they fit together quite well.

Ok, I Lied… A Bit…

If you read Eric Evan’s book on Domain Driven Development and Martin Fowler’s Blog, you will see that their process of Domain Driven Development goes beyond just getting an informed view of the domain and describing it with “ubiquitous language”. They include code coverage, continuous integration, a testing strategy, and code organization as part of the DDD life cycle. While these things do happen between getting domain information from a client before coding and then translating things back to the domain expert, I’m not so sure that these are really part of DDD. Let me explain.

If as good programmers (and good DDD programmers at that), we decide to break things down into their unique single role parts we’d see a few things when examining the formation of the DDD mindset. First, is that it borrows heavily from Extreme Programming. EP was a multi pronged approach to developing software in a more iterative and maintainable fashion. It included planning phases, writing tests, using continuous integration, and more. EP claimed that code was the most important thing in a software project, and developers should be prepared to code efficiently.

Evan’s came in and took a lot from the toolbelt in front of him and created his own method to attacking software problems and he put understanding the domain first. This meant that while code was still really important, the best code in the world is only as good as the understanding of the problem you are trying to solve. At the end of the day, what makes Evan’s process unique was the communication with a Domain Expert. It’s this communication that I would argue IS DDD. Everything else was slight modifications on existing techniques.

A Word On Code Structure

I made a point that TDD as a philosophy doesn’t care how you structure your code. There are those that would probably think that this transfers to DDD as well. Unfortunately it’s a bit stranger than that. While the simplified view of DDD makes me want to say that code structure isn’t part of DDD, I can’t really tell you that. With a deep understanding of the domain and wanting to mimic the domain within the code base, your code structure will and should be influenced. Also on the other side of things, it makes the translation of software output to the domain expert much easier for you: if you are stuck remembering how this SuperDuperSoftwarePatternThing relates back to your domain, you aren’t doing yourself any favors. Stick with efficiency and mimic the language you set up when talking with the client. If things are hard to structure, that’s a sign that you may not understand the specifications for the different actors in the domain.

A Word On BDD

BDD is an implementation of TDD which brings in some aspects of DDD. BDD focuses on how to name tests and instructs that tests should start from outside interaction in. For instance if you want to go to a page and see some blog posts you’d write the test for the route, say “hey I want to see some posts”, then you’ll say “I need to get some posts from somewhere”, then keep going until collide with unit tests at the low level.

BDD also goes to the effort of giving a more conversational way of writing tests. Since many tests start from the outside of a system and work their way in, BDD lends itself well to testing a pass or fail condition for a user story or feature. This means that you describe what actors are setting up a feature to be tested and then what result is to be expected. If you caught that, you may see that BDD lends itself as a TDD strategy for teams that have a solid domain definition from DDD. BDD is also often heralded because BDD testing tools can be arguably more human readable to non-developers such as Domain Experts.

http://ryantablada.com/post/we-are-complicating-things-a-bit-too-much-(tdd-and-ddd)