But it is probably NOT your fault.

I was recently asked by a client to review TDD and Refactoring CBT (Computer-Based Training) on popular online training sites, before rolling it out to the client’s developers. This was an interesting ask, since Industrial Logic has over 25 years of experience doing and teaching Test-Driven Development (TDD) and Refactoring, and offers hands-on, in-depth eLearning and in-person training on those skills. Nevertheless, since the client already had a contract with a large CBT vendor, I agreed to do the work.

I sampled several CBT TDD and Refactoring courses, and it quickly became apparent that the so-called “experts” teaching these classes knew very little about TDD or Refactoring.

Here are a few of the OMG moments I experienced:

  • Making changes to, or adding brand-new production code that was not driven by a test
  • Skipping the refactor step
    • in prod code
    • in test code
  • Writing more code than necessary to make the test green
  • Manually refactoring code when the IDE can do it automatically
  • Failure to leverage the IDE’s ability to generate classes, extract methods, change method signatures, add variables and constants, etc.
  • Skipping what are viewed as “trivial” steps (e.g. Not test-driving all of the production code because one “knows” what will be needed.)

Refactoring is an important practice and a key part of TDD. It enables you to clean up the code, make it more concise, remove duplication, make the design simpler and more elegant, which makes it easier to understand and modify.

In one CBT class on Refactoring, the instructor was using the IntelliJ IDE by JetBrains1. IntelliJ is packed with automated refactorings that greatly reduce human error when modifying code. Examples include extracting methods, inlining variables, and creating constants. I found it very hard to believe that this “instructor” was teaching me how to refactor manually. Instead of using cmd+option+m to extract a method, he was manually copying and pasting code. But the worst part about this refactoring course was that he never once mentioned “tests.” He never ran automated tests after his manual refactorings. In fact, I am not even sure he had tests to run!

Automated tests provide a safety net when refactoring code. At Industrial Logic, we rarely refactor code without automated tests. Even if the best we can do is write characterization tests (or my preference, approval tests) because tests are nowhere to be found. We create these tests first, in order to make the code safe to refactor.

I once worked with a client to teach them TDD using React back when React was fairly new. I had virtually no experience writing production code with React back then, so I took one of these online classes to “ramp myself up.” Fortunately, I had at this point enough experience with TDD to understand that what I was being taught was wrong. Even though I did find the course useful in learning React syntax, I had to disregard most of what was taught about using TDD for web development. In the very first demo in this class, the first thing the instructor does is modify the “production code” without writing a test. Additionally, most of the tests were used to “drive out” the markup language, not the functionality. This is very common in most “expert” TDD tutorials. But it isn’t TDD, not by a long shot.

Here are a some of the other things that I have found wrong in online TDD or Refactoring CBTs:

  • The instructor says they are going to use TDD but all the tests are written already. This is not remotely close to what TDD is or how it’s performed. Honestly, I wonder about the mental gymnastics one has to go through to arrive at this conclusion.
  • The instructor talks frequently about the testers writing automated unit tests first and then handing them off to the dev team. Again, this isn’t TDD. Also, it doesn’t help at all with design as the tests in TDD are written in a cycle, not all at once. One of the most important pieces of TDD is the refactor phase which increases quality and reduces technical debt. If a QE is writing this instead of the dev, you lose that benefit.
  • The instructor is talking about batching the unit tests, development, and refactoring instead of doing them continuously in an extremely short feedback cycle.
  • The instructor demonstrates copy and paste coding. This is a terrible practice.
  • The example code is built incorrectly. The instructor has a Case/Switch in the controller that does business logic. No dev should ever build a controller this way.
  • The instructor says it is an error to work without a Definition of Ready (DoR). DoR is an anti-pattern: a stage-gate approach that is often used to get people creating a Big Up Front Design. This contradicts the concepts of evolutionary design and the last responsible moment.

Some other common poor practices that I have run across while evaluating TDD CBTs:

  • The instructor explicitly states that Integration is not part of TDD. This is simply not true. People often choose to test drive an API starting with a failing integration test. This is a test that will not pass until all the microtests have passed and the corresponding production code is written. This is called the “outside-in” approach in TDD.
  • Creating production code before writing a test. If you don’t start with a test that fails for the right reason, you are not doing TDD.
  • The instructor uses fail() to get a failing test. That is just wrong. The test should fail for the right reason. fail() is not one. It should fail because you haven’t implemented the code required to make the test pass.
  • Waiting FAR TOO LONG to refactor. Should be refactoring continuously.
  • Not running tests after each refactoring.
  • With the exception of Emily Bache, no one I evaluated mentions mutation testing or running code coverage with tracing and tracking enabled to determine that all conditions have been properly tested.
  • Failure to use the IDE for renaming or changing method signatures; prone to human error
  • Waiting far too long to refactor tests
  • Failure to treat tests like production code

There are rules that we follow in TDD, when TDD is done right. It is simple, but it requires discipline. Typically, most programmers feel they are smart enough to skip a few steps ahead. I know. I was one of them. Until it came back to bite me. Then I started holding myself to these simple rules:

  • Write new code only if an automated test has failed.2

  • Eliminate duplication.3

  • You are not allowed to write any more of a unit test that is sufficient to fail, and compilation failures are failures.4

  • You are not allowed to write any more production code that is sufficient to pass the one failing the unit test.5

  • Never modify production code without a failing test unless you are in the refactoring step.
  • Treat your tests like you treat production code. They should live with the code in the same project and be committed to the same VCS repository.
  • Your tests, like your code, should be small and have one responsibility. Avoid multiple asserts that test multiple conditions in a test. Instead, write another test.
  • Run your tests often. After every change and/or refactoring.

A Better Way

There’s a far better way to learn TDD and Refactoring than CBT courses created by non-experts.

Many years ago, Industrial Logic recognized the need for scaling genuine TDD and Refactoring skills. Back then, we worked hard to produce a set of skill-building eLearning courses on TDD and Refactoring. Since then, we’ve never stopped refining those eLearning courses, and expanding the original Java, CSharp and C++ editions to include languages like Python, Kotlin, Swift, Javascript and more.

These courses are far superior to CBT courses because they are created by veteran practitioners. You learn why TDD and Refactoring are so valuable and how to actually perform these practices so you can leverage that value

Our eLearning can visualize your TDD and Refactoring performances and give you expert feedback:

alt_text

And unlike most CBTs, our eLearning allows you to ask questions and receive feedback from our veteran practitioners. We even created our Guided eLearning offering, so you can have a human instructor help you as you experience our TDD and Refactoring training.

Of course, the best way to learn is by applying these concepts to your production codebase. This is where so many people struggle and Industrial Logic shines. How do you apply what you learned to real enterprise code? Our player-coaches work with development teams to teach, mentor, and guide them through the process every step of the way.

Notes

  1. IntelliJ is a Java Development Environment byJetBrains that is known for its robust refactoring capabilities and code completion. 

  2. Kent Beck, “Test Driven Development: By Example”, preface. 

  3. Kent Beck, “Test Driven Development: By Example”, preface. 

  4. The Three Rules of TDD, Robert C. Martin 

  5. The Three Rules of TDD, Robert C. Martin