Design Principles
Summarized using AI

TDD in Tatters

by Scott Bellware

In the presentation titled "TDD in Tatters," Scott Bellware addresses the evolution and degradation of Test-Driven Development (TDD) from its original design-focused intent to a tool-centric approach. With automation and various testing tools taking precedence, Bellware prompts the audience to reconsider the foundational principles of TDD grounded in good design practices.

The key points discussed throughout the video include:

  • Misunderstanding of TDD: Bellware asserts that TDD is often poorly implemented and understood, becoming more focused on automation rather than on mastering design.
  • Subtle vs. Crude: He distinguishes between 'subtle' aspects of design—reflecting deeper analysis—and 'crude' elements like tools and frameworks that often distract from these subtler principles.
  • The Journey to Mastery: Mastery is presented as a process rather than a destination, with continual growth in skill requiring attention to the subtle shifts in understanding design.
  • Impact of Automation: Automation can hamper understanding and productivity, creating a disconnect between developers and the code they write, leading to reliance on tools instead of fostering intimate knowledge of the codebase.
  • Design Principles: Good design is emphasized as paramount, requiring practices such as encapsulation, coupling, and abstraction. Poor design leads to complications and increased reliance on testing to cover up flaws.
  • Thought-Driven Development: Bellware promotes the need for reflection and thought in software design. Recognizing design flaws early allows developers to maintain clarity and intention in their coding practices.
  • Minimal Automation Approach: He introduces a simple string reversal application as a demonstration of TDD, using minimal automation to underscore direct engagement with the code.
  • Cultivating Effective Practices: Bellware concludes by encouraging a conversation around effective TDD practices, suggesting that a refined understanding of design can cultivate better productivity and outcomes in software development.

Ultimately, Bellware's talk serves as a call to return to the heart of TDD: focusing on design and craftsmanship over merely using tools, reminding developers that true productivity stems from a strong grasp of design principles rather than automated processes.

00:00:15.839 Thank you all for coming! I appreciate having such a crowd on such short notice.
00:00:21.600 We had a cancellation, so I jumped at the chance to get another opportunity to speak to you.
00:00:26.640 I'd like to say that I've only had a few hours to put this presentation together, but I've actually been working on this for a couple of years.
00:00:39.040 So if it's bad, it's because it’s bad!
00:00:48.079 This is one of those talks that suggests you're doing it wrong, and that can be problematic.
00:00:58.960 I realize that this is my mode of learning, so hopefully you won’t take anything personally. I’ll try not to be too preachy.
00:01:09.920 Unfortunately, I have a tendency to learn by convincing myself that what I'm doing is wrong just to see if I can find something wrong with it.
00:01:21.840 So when I do this, it's not meant to harm anyone except myself.
00:01:28.080 The thrust of this talk revolves around several points. One topic I discussed last year at the same time, in the same room, with some of the same people, is that TDD is still poorly understood and poorly done.
00:01:40.479 Automation, contrary to popular belief, can be ruinous to productivity. The productivity that you get from design is vastly superior to that which comes from automation.
00:01:55.119 TDD was supposed to be a path to greater mastery in design, but over the years since around 2000, it has become largely focused on tooling.
00:02:06.560 I want to talk about some fundamentals to get things going. These are the fundamentals about us, and by 'us', I mean me, as I project myself onto you.
00:02:24.560 This is my prejudice on how I think that you work, based on who I am. I want to talk about things that are subtle, and things that are crude.
00:02:40.959 Things that are subtle are things you might not yet be attuned to, things that you might dismiss as negligible because they are often mistaken for misunderstanding.
00:02:55.679 I'll state quite audaciously that the things that are subtle are what you want to pay attention to and leverage, but they're very easy to miss.
00:03:10.239 On the opposite end of the spectrum, there are crude things. Crude things are tangible and material. For the purposes of this talk, crude things are necessities and starting points.
00:03:22.959 They involve muscle memory, drills, and dogmas. Unfortunately, crude things are what we are hardwired to connect with.
00:03:38.560 This stems from the fact that we have spent more years as humans evading saber-toothed cats than we have evading software defects or design defects.
00:03:46.159 Crude things can be traps, as they may get in the way of realizing the subtler things. Crude things are also easy to transfer—it's easier to teach you how to use a testing framework than to teach you about design.
00:04:04.319 This is one reason why TDD ends up devolving into what one might call an 'intellectual materialism', where you know what you should be doing, but there's a cruder form of it that you might actually be doing.
00:04:18.160 Now, I don’t want anyone to be thrown off by the term 'mastery' here. In our Western industrial modern culture, we tend to view mastery with cynicism.
00:04:34.560 We often see everyday, tangible things as mystical, labeling them as 'zen' without truly understanding them.
00:04:49.280 The issue I want to raise about mastery is that it is more about the process than the destination, which reflects a more Eastern mindset.
00:05:02.240 Once you reframe it that way, you realize that mastery and the pursuit of perfection are not high concepts far removed from reality; they are everyday realities.
00:05:20.959 Recognizing mastery is about acknowledging the process of improvement and that pursuing mastery does not automatically give you the right to claim it.
00:05:42.720 The connection to subtlety here is that as you advance in a skill, the early steps you take yield noticeable changes. For example, if you’ve never written a line of code before, the moment you write one line is a significant change.
00:06:03.199 However, as you progress, the changes and refinements you make become less noticeable. A person with extensive experience in coding may overlook these subtle refinements, viewing them as negligible.
00:06:20.360 Yet, these finer adjustments accumulate and can cause an exponential increase in your capabilities and productivity.
00:06:37.680 This is crucial because design resides in the realm of the subtle. Test-driven development is also subtle, whereas test-first programming can be seen as crude.
00:06:52.760 You can find yourself doing test-first programming while thinking you're doing TDD, and it’s important to recognize that this isn’t necessarily the same.
00:07:05.760 Through my practice of TDD, it's possible to write code that meets the criteria of test-first programming but still ends up with design qualities that are less than desirable.
00:07:20.119 Test-first programming doesn't inherently lead to the desirable goals of test-driven development. We are hardwired to notice crude things, which often takes our focus away from subtler details.
00:07:44.320 You can have TDD in your mind, yet be doing test-first programming in practice without realizing the distinction—unless you stop occasionally to reflect on your code and consider if you are truly succeeding.
00:08:11.600 This reflection might involve adopting a pessimistic viewpoint as a thought experiment to examine the potential shortcomings of your work.
00:08:39.360 Let's now quickly discuss automation, which focuses on tooling—the material side of the spectrum.
00:08:51.200 Automation can distract your thinking from design principles and can often lead to further complications rather than reducing them.
00:09:08.000 I would like to reference a paper from an industrial psychologist discussing how automation can expand rather than eliminate human operator problems.
00:09:25.119 This has been evident with the rise of unit testing over the past decade and a half, where the assumption was that writing a lot of unit tests would document the code.
00:09:42.959 What tends to occur is that programmers stop engaging with the code directly and instead rely on automation, creating a growing separation from the systems they are building.
00:10:05.759 As human operators, we must maintain our intimacy with the codebase, while also acknowledging that automation can detract from our understanding of the systems we are working on.
00:10:20.399 This topic further reflects that we still exist in a craft state rather than a fully industrialized one; craftsmanship combined with industry is the optimal approach.
00:10:39.279 We must address the realization that not every process should be automated, and the predicament lies in the fact that we create automation as part of our product.
00:10:56.800 As pro-automation product developers, we are resistant to the idea that the core thrust of our work may not be as beneficial as we self-affirm.
00:11:12.960 It's often said that TDD is about design. If you observe people practicing test-first programming, you can see two similar actions that yield very different outcomes.
00:11:28.800 The key difference lies in the understanding of the software design characteristics and what qualifies as good design.
00:11:44.000 If you don’t begin with a clear notion of desirable design, it becomes difficult to achieve it. Conversely, you may also become hypersensitive to any friction.
00:12:00.960 Rather than viewing small frictions as negligible, consider them as signs of looming issues that may be subtle and masked by your current skill level.
00:12:15.200 Much like how cancer starts small but can grow pervasive, small benefits can have a significant impact on your productivity in the long run.
00:12:33.760 Good design encompasses principles such as encapsulation, coupling, and abstraction. These are higher-order principles that contrast with more tangible design principles.
00:12:53.000 Encapsulation refers to the idea of telling objects or systems what to do rather than asking them. Coupling refers to the entanglement between modules, which in Ruby could be a class.
00:13:08.320 With weaker encapsulation, there tends to be more coupling, which detracts from the clarity and function of your code.
00:13:22.799 The goal of design is not about getting a computer to execute instructions—rather, it's about how human beings can achieve clarity over the code they write.
00:13:39.100 Design is ultimately about enhancing human cognition. It predicts productivity, which is fundamentally more valuable than automation.
00:13:58.080 We tend to underestimate the impact of subtle design mistakes. Every sense of frustration or friction should be recognized as an indication that there is a deeper issue to address.
00:14:17.480 Design mistakes that appear minor can accumulate over time, leading to pervasive problems that significantly inhibit productivity.
00:14:42.720 Therefore, it is crucial to act on these signs rather than dismiss them as negligible, recognizing they can have a mass impact.
00:15:00.320 Good design principles are not just esoteric academics; they are practical guidelines that can enhance your productivity and efficiency.
00:15:16.800 This shift in perspective can significantly reduce your downtime spent resolving issues, allowing for smoother workflow.
00:15:30.120 It’s a tough realization that every test introduces additional coupling; however, the question is how to maintain productivity while assessing designs.
00:16:03.760 The truth is, poor design leads to excessive reliance on testing, which inadvertently creates a cycle of increasing coupling and complexity.
00:16:22.960 This vicious cycle drives your productivity down. Each testing framework available naturally encourages you to break productive design principles.
00:16:40.959 The syntaxes and grammars of testing frameworks often become obstructions in your creative flow of test-driven development.
00:16:54.720 The focus should thus be on designing workable software rather than just functional software. Working software is a necessity, but it's the bare minimum.
00:17:07.840 You can achieve better design without sacrificing usability; workable software is software that a human can engage with easily.
00:17:17.919 We often encounter the idea that it’s normal to be stumped when dealing with code, yet that signifies a lack of maturity in our industrial understanding.
00:17:35.600 It’s crucial to improve knowledge transfer and momentum in our development processes, avoiding the sawtooth patterns of momentum loss.
00:17:52.240 This requires reexamining what we consider 'services' in software design. Services should ideally only accept commands rather than return data.
00:18:06.560 For instance, a construct labeled 'service' in service-oriented architecture should not provide direct data on request. Instead, it should confirm commands.
00:18:24.960 It’s essential to distinguish between services and database structures. Many definitions blur the lines, hindering our understanding of design.
00:18:39.840 Many mechanisms mislabel data retrieval by services as valid, which indeed confuses the conceptual architecture.
00:18:59.920 With objects, proper design can become difficult when using certain frameworks like Active Record, which can violate sound design principles.
00:19:13.600 We often employ shortcuts in such frameworks that may yield immediate results, but they can obstruct better long-term practices of clarity and insight.
00:19:36.320 If you have never seen a better architecture or design, it might be time for exploration to see what's possible beyond what we typically encounter.
00:19:56.480 To illustrate my point, I want to share a quick sample application as a demonstration.
00:20:03.040 This is a simple example of string reversal, a trivial concept; however, it's a great way to explore TDD.
00:20:14.560 I'll be using a library called 'Proof', which is not a full-blown library but rather a proof of concept to discuss the design focus in TDD.
00:20:28.800 This approach emphasizes minimal automation to maintain a direct connection with the code.
00:20:46.080 Fielding questions about structure or semantics often disrupts the flow, so I prefer to simplify those considerations.
00:21:04.560 As I develop this example live, let’s analyze and collaborate on how to seamlessly integrate TDD into our code.
00:21:16.800 The idea is to write down thought processes as they occur, nurturing a coherent design even pre-implementation.
00:21:27.520 So far, I’m demonstrating the string reversal process as a fundamental example of TDD.
00:21:34.880 As I sketch out my code, it's crucial to emphasize the importance of clarity over complexity when structuring test cases.
00:21:55.680 Shaping my code is about exploring design principles without letting external frameworks constrain my creative results.
00:22:05.840 This approach leads to producing cleaner and more effective results in my coding process.
00:22:29.920 Ultimately, we want our environments to reflect best practices in a way that induces productivity rather than obstructs it.
00:22:47.920 By espousing these principles and sharing this framework, I hope to cultivate a positive conversation around effective TDD practices.
00:23:15.440 Thank you for your attention, and I'm looking forward to your thoughts and insights on this topic.
Explore all talks recorded at LoneStarRuby Conf 2013
+21