00:00:06.359
Video equipment rental costs paid for by PeepCode.
00:00:20.039
Screencasts. Hi, I’m Glenn Vanderburg, and I’m here to talk about tactical design. This really isn't much of a Ruby talk; it's informed by my experiences with Ruby and my work with projects recently over the past two or three years. I presented it and it got accepted, and I hope you'll find it interesting. Before I really get into it, I want to address an omission. I really enjoyed Evan's keynote last night, but my friend Chris Morris and I were standing at the back of the room talking, and we realized—Chris in particular noticed—that Evan had kind of missed a very important Ruby community meme.
00:00:46.320
In some ways, it's a signature Ruby community meme. Evan alluded to it but did not actually mention it: it was an extension of Evan’s keynote, here, about cussing on slides. That said, we’ll see if that topic keeps going strong or fades away. Tactical design: Raise your hand if you design software. I gave a trial version of this talk on Tuesday night at the Dallas Ruby Brigade and asked that question. A couple of people didn't raise their hands, so I said, "Raise your hand if you're a programmer." Then they raised their hands because if you're a programmer, you design software. Now, raise your hand if you are ever in a position of teaching design to other programmers via mentoring. Okay, pretty much everybody. So, I'm targeting the right audience. Design is hard, and in my experience, teaching design is even harder.
00:01:39.000
Part of that comes from the fact that there are aspects of good design that we don't understand. We might know it in our gut when we see it. My boss, Stu Holloway, actually shows a picture of the Supreme Court judge who said, "I can’t define obscenity, but I know it when I see it." Sometimes, that's what good design is. When you can’t really articulate what it is, it becomes hard to teach. However, over the past few decades, we've learned a lot about what constitutes good design, and we have learned how to articulate it. Still, it's challenging to teach it to younger or less experienced programmers.
00:02:43.920
One of my favorite books in the software field is The Mythical Man-Month by Fred Brooks. He published it a long time ago, and 22 years ago, he wrote an essay called "No Silver Bullet." In that essay, he wrote, "We can get good designs by following good practices instead of poor ones. Good practices can be taught." I read that recently and thought, "In my experience, that's just not true." He went on to clarify that the difference between poor conceptual designs and good ones may lie in the soundness of design methods. However, the difference between good designs and great ones surely does not; great designs come from great designers.
00:03:37.959
Brooks goes on to despair about teaching design, suggesting that we should cultivate great designers. While I agree with that, we need more merely good designers and more merely good designs. If 10% of software systems in the industry were elevated from their current state to simply good design—not great—we would be a lot better off. Here’s the obligatory programmer productivity graph. I have been talking about design skill, and while this graph addresses productivity, I posit that it applies to design skill as well. If that’s the situation, and if there are few programmers with great design skills and many with very weak ones, what do we do to improve our field?
00:04:52.520
We can cater to the average programmer, but that approach hasn't worked well in the last decade. Building tools and platforms that cater to the average doesn't yield good results. We could adopt the Rails approach of catering to natural designers, which I appreciate and believe is better, but it’s not optimal by itself. There aren’t enough natural great software designers to handle everything that needs to be done, leading to those designers getting stuck cleaning up the messes left by others. That's lucrative for them, ensuring that they won’t be out of a job anytime soon, but it’s not satisfying work.
00:06:41.639
Another option is to scare off the really bad ones, which is fine with me, but it still doesn't solve the problem. We can identify and cultivate good designers, but we need more great designers along with more merely good designers. I’ve been thinking a lot about how to effectively teach, mentor, uplift, and enhance others' skills with regards to design. Let's revisit that graph to provide clarity on what I’m discussing.
00:07:22.960
I think we can divide this graph into three parts. On the left are natural designers—those who care and likely possess some innate aptitude. They will figure out how to do it right. In contrast, on the far right, we have a large number of individuals who are essentially hopeless in learning design skills. However, I believe that at the knee of the curve is a group that could learn it if taught effectively. They may not become great designers, but they can at least improve.
00:08:38.880
I've grown frustrated with traditional teaching methods aimed at these individuals, and that's the focus of this talk. How can we help potentially good software developers learn to think about design qualities in their code? I appreciated Matthew's talk on teaching through pairing, as I believe that's the only method that holds any promise. Mentoring people side by side has been my most successful approach. However, I've often struggled to teach design principles effectively, so I began experimenting with different techniques.
00:09:44.760
Let’s take a brief look at how we've come to understand design principles over the years. The first significant work was 1979's Structured Design by Yourdon and Constantine. In a recent keynote address, Kent Beck referred to it as the laws of physics in software development. This book introduced concepts like coupling, cohesion, code factoring, and encapsulation, which I agree represent fundamental laws of software design. However, simply introducing these terms doesn't seem to have produced much effect. In 1988, Bertrand Meyer introduced the concept of design by contract and a stronger notion of encapsulation, including responsibility and the open-closed principle—still prominently taught today.
00:11:38.200
In 1990, Wirfs-Brock introduced responsibility-driven design based on Meyer's concepts and established a whole design method around it. Then, in 1994, design patterns emerged, which provide solutions embodying design principles for specific situations—effectively design by example. I think this book arose from a similar frustration over the ineffectiveness of teaching principles through large-scale theoretical methodologies. Recent literature, such as Bob Martin’s Principles of OO Design, attempts to compile principles defined by multiple authors over the years. Eric Evans’ domain-driven design emphasizes the importance of focusing on a domain model to translate into a common language for communication between stakeholders.
00:13:07.639
Most of these books offer valuable insights, but I’ve struggled to help those who aren’t natural designers understand the mechanics of design. For context, Bob Martin espouses five principles of OO design in his book: the Single Responsibility Principle, which states that every class should perform a single clear task; the Open/Closed Principle, emphasizing that classes should be open to extension but closed to modification; the Liskov Substitution Principle, which concerns acceptable types of extensions when creating subclasses; the Dependency Inversion Principle, which addresses layers' dependencies through interfaces; and the Interface Segregation Principle, focusing on how responsibilities and methods are allocated to interfaces.
00:14:49.560
The challenge with these principles, as with others I’ve described, is that they are often abstract and high-level, creating an abundance of cognitive load for programmers. They focus primarily on class division and their relationships, including how inheritance versus composition functions, and how aggregation and association interact. I’ve noticed that many average programmers, and even many above-average ones, struggle to think about code at the class level. They often become too narrowly focused on individual methods or loops, missing the larger picture.
00:15:52.760
Years ago, Ralph Johnson wrote something on Ward Cunningham’s Wiki that has stayed with me: "With the right value system, making good short-term decisions leads to good long-term results." This highlights the need for a value system to guide actions during development. Just as values inform how we react to neighbors in disputes, a well-formed value system helps developers make the right decisions in code.
00:16:43.680
When I refer to tactical design, I mean defining the right value system that aids decision-making in programming rather than relying on unyielding laws of software development. We need rules of thumb or simplified formulas that, while they might not be perfect fit for high-pressure scenarios, yield suitable results in daily practice. My focus is at the level of methods and lines of code. The goal isn't necessarily to achieve great designs, but rather to equip those without existing design skills to produce decent designs that surpass their current capabilities.
00:17:28.400
The question then becomes: what values should we adopt? We could debate this, and I hope we do. I propose starting with two coding standards—short methods and few methods per class. Teams or pair partners could agree on a seldom-to-be-broken limit for these standards. I also suggest adding three principles: the first being the Single Responsibility Principle, which is more practical when phrased as 'Do One Thing.' The second, 'DRY', which stands for 'Don't Repeat Yourself', encourages minimizing redundancy in systems. Lastly, I propose the Uniform Level of Abstraction principle.
00:18:55.239
The 'Do One Thing' principle, articulated by Tom DeMarco, suggests that every object should have a singular responsibility, and all its interactions must align with that responsibility. In my view, this extends to methods as well; each should execute one specific task while avoiding needless complexity. I trust that this audience is familiar with DRY, acknowledging that every piece of system knowledge should have a single authoritative representation. The goal in tactical design is to simply simplify code by adhering to the principle of avoiding duplication.
00:20:22.800
The Uniform Level of Abstraction principle, identified largely in Smalltalk best practices, argues that methods performing identifiable tasks should maintain a consistent level of abstraction. By ensuring that the operations in a method have a matching abstraction level, a method becomes easier to read and comprehend. It's also far easier to refactor a method when all operations are at the same level; this promotes better naming and exposes potential DRY violations. I've seen how this principle can lead to valuable improvements, even when applied by programmers working independently.
00:21:39.079
I believe adhering to these principles results in decent, though not great, designs that yield impactful and lasting consequences. Firstly, they compel developers to discover simple design patterns. Secondly, they cultivate an appreciation for design principles through the practice of these small-scale tactical principles, preparing individuals for a deeper understanding of higher-level principles, as they begin to see the practical applications of cohesion, coupling, and overall responsibility in designs.
00:23:14.760
This journey fosters what I call ‘the awakening of the sense of smell’—the ability to recognize design quality in code. Knowing how to fix design problems is only part of the battle; the harder challenge lies in initially identifying the design problems amidst the chaos of coding. Smaller-scale principles are more comprehensible during the rapid pace of programming, particularly for less experienced programmers.
00:24:21.640
Having worked with many programmers in large organizations plagued with complex codebases, I’ve observed a concerning trend: many developers have never encountered clean, simple code in practice. They may have seen exemplary clean code in textbooks or programming courses, but they often face jargon-laden, complicated code in their working environment. Consequently, they may not understand they should strive toward simplicity and cleanliness in their code, which calls for a fresh approach to introducing principles and ideas.
00:26:30.639
Instead of fixating on lofty design principles that are comparatively complex to digest, teaching design in terms of basic, small-scale decisions can foster change. I'm slightly over time now, but I hope this introduction sparks discussion and questions.
00:28:08.160
Questions or observations?
00:28:31.000
David: How do you motivate good design and get people to want to do it? Well, I have two answers. First, I find the hopeless folks on the far right side of that graph likely will not care, and I can’t do much about that. However, I do know many programmers want to care if they can see the value and understand it. The second answer is that I believe the right approach is through pair programming or close collaboration. I've witnessed how motivation builds through small triumphs. Once developers see the positive outcomes of refactoring, such as uncovering hidden bugs, motivation often grows from there.
00:30:23.360
There's a process of setting programmers up for small successes instead of presenting an unreachable goal. Joe: From my three decades of experience, I’ve noted that in many cases, developers not only don't care, but they actively reject suggestions of improvement. David: Yes, I've seen that too. But I wouldn't categorize all developers as disinterested. In situations where I’ve encountered poorly written code, if I assert the whole system is flawed, it breeds resistance. Conversely, when I engage with developers on specific bugs using a collaborative mindset, I often find cooperation is much more readily available. This approach creates space for small changes ultimately leading into larger improvements.
00:31:59.360
Developer: While I agree that there are resistant programmers out there, we shouldn't overlook the potential in nurturing those who could develop that sense of care for their craft. I believe that learning essential skills and observing more proficient methods can awaken valuable realizations and transformations.
00:33:09.440
David: I completely agree, and that’s essential to avoid losing those individuals in the middle who could flourish when they are shown the way. My transition to an independent consultancy came from the desire to work more closely with motivated programmers; however, we cannot neglect those in between who are willing to learn.
00:34:07.760
David: Indeed, establishing a culture centered around collaboration can drive significant progress within teams, even when gradual.
00:35:14.560
Audience member: Management should create incentives aimed at promoting the cultivation of good programming habits, which can counteract the difficulties programmers face.
00:36:09.880
David: Very true. We need to address various aspects to elevate our profession as a whole.
00:36:34.080
Audience member: I observed that veteran programmers might be more averse to new strategies than younger developers; I feel that the Ruby community has many eager newbies who have adopted these good practices from the outset.
00:36:51.400
David: Yes, while this holds true, I'm worried that progress may sometimes yield slower results until established minds gradually shift. Your comments ring with my sentiment that change takes time.
00:37:09.440
Audience member: In the past, I worked with Java and attempted to refactor a troublesome class but encountered resistance. It was a 500-line method. However, after three hours of refactoring, the bugs became glaringly obvious.
00:37:28.560
David: Such challenges are typical; however, through a professional lens, it is now a fundamental aspect of my responsibility as a software developer to refactor and improve code without asking for permission. It's crucial that we carry that mindset.
00:38:02.880
Audience member: Indeed! The transition from a mere coding job to one of craftsmanship speaks volumes. While there are those who do not aspire for this path, I see potential in guiding many whose appreciation for best practices and quality can be sparked.
00:39:36.640
David: Correct. The joy of programming, collaboration, and crafting code should permeate our industry, so it’s important we engage with and uplift those who show potential.
00:40:28.960
Audience member: Thank you, Glenn.]