David Scott Bernstein's Blog, page 9
September 4, 2019
Let Go of Perfectionism
It was Voltaire who said, “Don’t let the perfect be the enemy of the good.” By that what I believe he meant was that while it might be good to strive for perfection we have to realize that we won’t always achieve it and if we are going to insist on everything being perfect we might end up not getting anything done. In the fast-paced world of business today good means good enough.
Any investment follows the laws of diminishing returns. We want our features to be good enough but not too good because if they’re too good it means that we’ve essentially wasted some of our customer’s money overbuilding some features.
Some of this is unavoidable because we can’t predict the future but I find that having good acceptance tests and a clear definition of our acceptance criteria can help us get really clear on how much of a feature to build before we consider it done. This may not seem like a big deal but to software developers, this is really big.
Nearly half of all features built across the software industry are never, ever, ever used. This means that there is a lot of waste in what we build so knowing what really is needed versus what we think might be needed is important. Just think of how much more effective you would be with half of your time back.
One of the key differences that I noticed between junior developers and seasoned senior developers is their notions around a perfect design and implementation of their designs. What I find is that the more senior a developer becomes less attached they are to making a perfect piece of code because we recognize that there are always trade-offs and our goal is not to write perfect code but to write code that is of sufficient quality that it gets the job done and is straightforward to extend in the future. Just doing that will get you ahead of 90% of the rest of the industry.
I used to believe that there was no such thing as a “perfect design” and so I shouldn’t strive for creating one. Instead, today I believe there is actually such a thing as a perfect design for a particular situation but the problem is it’s very costly to implement and so I find ways of mitigating that cost by making it cheap to go to a perfect design later in areas when and if it is needed.
The needs of software often change and as they do the requirements for the design changes but far too often we saddled ourselves with an existing design even though new requirements have significantly changed the problem and therefore we should be open to changing the design.
The thing that really helped me let go of perfectionism was reading Martin Fowler’s book, Refactoring: Changing the Design of Existing Software. When I realized that the process of going from a poor design to a better design is often safe, straightforward, and repeatable then I realized that it doesn’t matter where I start with the design, what really matters is where I end up!
One of my very favorite quotes from one of my favorite authors, Stephen King, is “murder your darlings.” Well, he is a bit of a violent and macabre sort, isn’t he? But his sentiment is quite valuable, I think. We tend to get attached to a design or a way of saying something or presenting something that may makes sense initially but given other factors and as we learn more, we may want to supersede the initial thought. I try not to get attached to anything but especially my own ideas and my own preconceived ideas of how things should be. This is one of the many things that magic, self-improvement, and software development have in common—focus on outcomes and let the details take care of themselves.
As software developers, our goal is to provide quality software that does what the customer wants at the most affordable price and we do this by building just enough of a feature in order for customers to derive value. This is why I believe that perfectionism and professionalism can sometimes be at odds with each other. How can this be resolved? Well, stay tuned because I’ll discuss that in my next blog post.
Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software
August 28, 2019
Share Common Quality Practices
In addition to sharing a common definition of what quality means in terms of CLEAN code, we also must share some common quality practices that can help us increase the quality of the code we create. These practices should be straightforward to apply so we can easily make them our habits.
Here are some of my favorite practices around creating CLEAN code:
Cohesive
Entities such as classes or methods that are cohesive how about one thing. My favorite practice for this is simply giving a behavior and name. If I can easily name something then it’s about that one thing but if I have trouble naming it because it does too many things then I know that I need to break it up into separate entities.
Loosely Coupled
Code that is loosely couple interacts with its dependencies indirectly through an interface or some other indirect method. One of the most important practices for doing this is using dependency injection either through a framework or just manually bypassing in dependencies two methods rather than having the methods instantiate them themselves.
Encapsulated
Encapsulated code is code that has hidden its details of implementation. This allows the developers to change the implementation later without other parts of the system being dependent upon them. We do this by keeping as much data and behavior scoped as tightly as possible so that only the entities that need to know about it do and the rest of the system can be blissfully unaware.
Assertive
Assertive code is code that’s in charge of itself so when we put state or data into a class the code that should manage that data should also be in that same class. Think of objects as little people that want to become self-reliant. They must have everything they need to do their jobs.
Nonredundant
Nonredundant code is code that is not repeated, not just in its form but also in its intention. If two different routines essentially do the same thing then that is considered redundant. Redundancy is not always obvious in code but we want to make sure that we follow the “one rule in one place” practice.
So these are some simple practices for improving the CLEAN code qualities. The more our industry begins to pay attention to code quality and common quality practices that we can share, the more our industry and our customers will benefit from more reliable and maintainable software.
Note: This blog post is based on a section of my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software.
August 21, 2019
Get Crisp on the Definition of Quality
When we talk about quality we may think of a fine piece of furniture or the quality service we receive at a fancy restaurant but what does quality mean in the context of software? I find that when we talk about the domain of ideas, and software is in the domain of ideas, that we often use metaphors which are based upon the physical world and are not always accurate.
In the physical world the notion of quality has to do with fine craftsmanship and longevity. We talk about quality workmanship and in the physical world quality always comes at a premium.
But quality in software is different. Think about it, we’re talking about things that don’t have any mass. The costs in most businesses are the cost of goods and the cost of production. If we build things, physical things instead of virtual things, then much of our costs would be involved in the acquisition of materials, the creation of our products, and their distribution.
We have none of this and software. Once we build the thing our production and distribution is essentially zero. Of course, that doesn’t mean that our cost of doing business is zero, far from it. The software industry has many other costs that are required of it, such as ongoing support. But in terms of production and distribution, which is often the largest cost in every other industry, in the software industry those costs are negligible.
So how does the notion of quality translate into the world of software? In my experience, true software quality is about achieving the same ends as physical quality, which is longevity, durability, and fitness of purpose. But these are squishy words and so we really have to understand what makes quality in software. In my experience, the ultimate goal in software development and the thing that we have largely ignored as an industry is to write software that is durable and has longevity. In other words, write software whose cost of ownership is as low as possible.
I say that the cost of ownership for the software we write is of paramount importance because this is where industry spends the most money. It’s been well documented that on average it costs five times more after software is released than it costs to create it in the first place. It costs half as much to fix defects after release and twice as much again to make minor enhancements. As an industry we write software that is expensive to fix and difficult to change.
The five CLEAN code qualities that I’ll discuss over the next seven blog posts reflect things that we can see and understand in our code. We can see when they are lacking or when they are present in code. I find this much more helpful than the so-called quality factors. I like to call them the “-ibles.” For example, reliable. If I tell you that your code needs to be reliable I haven’t helped you very much because I haven’t told you how to do what I’ve told you to do. The CLEAN code qualities our actionable. I call them qualities but they are actually quantitative because we can see them in our code and we can know what to do to improve them.
In my next blog post, I’ll discuss some quality practices that we can do to improve the CLEAN code qualities.
See you next time.
Note: This blog post is based on a section from my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software.
August 14, 2019
Why Practice 5: Create CLEAN Code
The fifth practice from my book Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software, is called Create CLEAN Code.
CLEAN is an acronym but it’s also a shout out to the books Clean Code and The Clean Coder by Robert C. Martin. and to the Clean Code talks, a series of Google Tech Talks, by Misko Hevery. Both of these resources hold outstanding value for software developers.
I’ve overloaded the term here myself to mean five specific things that we can look at in code to determine it’s understandability.
These five code qualities are actually quantifiable, we can see them in code and as we improve them our software becomes more straightforward to maintain and extend.
These same qualities go far beyond the realm of software development because they’re really reflections on the way we think and understand the world. The way we form concepts and communicate also has these qualities. They show up in the design of everyday things and how we organize our lives because they are indeed fundamental to the way we think and understand.
Interested to know more about these qualities? I take a deep dive into them in my book and also in several posts on my blog so I encourage you to check out some of my other posts on code qualities. Here I’ll just describe them briefly:
The C in CLEAN stands for cohesive. This means that a software entity, either a class or a method, for example, is about one thing and at a single level of abstraction. This is important because we want to make the behavior of our systems something that we can easily name and so behaviors must be well represented by the names that we give them.
L stands for loosely coupled, which means that when code has dependencies on external services then we want to connect to them indirectly. We want to create code that’s decoupled from its dependencies so that we can independently test and verify it.
E stands for encapsulated, which means that we hide internal implementation details and only present a defined interface to the outside world. Encapsulated code is more modular and has far fewer side effects.
A stands for assertive which means that in the object-oriented model all objects are in charge of themselves and of managing their state. This makes it more straightforward for objects to interact in the system and be far less entangled when systems are extended.
N stands for nonredundant which means that we do things only once. Redundancy can have subtle forms which look different but actually do the same thing and we want to rid our systems of those subtle forms of redundancy so that the design becomes clearer and the code becomes cleaner.
Each one of these code qualities affects the other. When one is poor then others tend to be poor as well. When we improve one it also tends to improve the others.
This means that you don’t have to focus on all of them, just pick one or two that make the most sense to you and focus on them. As you improve one of them you’ll notice that others improve as well and that’s because these code qualities are actually facets of the same thing–the same gem–which is the code. They are different lenses by which we see our code or evaluate our code and good code tends to have all of these qualities.
Having discussed each of these code qualities in detail in previous blog posts, which you can easily find on my website, I will now dive deeper over the next seven blog posts, into strategies for increasing code quality, which comes from my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software, in a section called Seven Strategies for Increasing Code Quality.
August 7, 2019
Track Progress
As the proverb says, “Data speaks louder than words.” Well, if it’s not a proverb then it should be.
The only way to know for sure if pair programming is right for your team is to track progress and see if the metrics that are important to you improve as your team starts to become more collaborative with pairing.
What are the metrics that are most important to you? When I look at pair programming, the most important indicator that I focus on is code quality. When I say code quality I mean several things.
The easy and quick way to interpret what I mean by code quality is to look at the testability of code. If developers are producing good, testable code that has automated unit tests and can independently verify each feature then I know I have a true measure of my progress and I have a good sense that high-quality code that’s straightforward to maintain and extend is being produced.
For me, the number one metric that I look at is testability in code but there are other metrics that you can look at such as code coverage and cyclomatic complexity, as well as many other indicators.
I also want to look at the amount of work that the team is doing but generally, I don’t like to track story points. Rather than assign tasks with different story points, I like to help teams get good at breaking tasks down into their smallest components so that every task is a small task and then instead of counting story points we simply count tasks.
The number of tasks the team can complete within an iteration is likely to be similar to the number of tasks the team completed in the last iteration or the one before that. Generally, if the team isn’t trying to do something very different than they were doing before then one could expect that the team’s throughput would be similar to their past performance.
How much more precise do we need to be and how much are we willing to pay for that precision? Historically, we’ve been very bad at estimating how much work needs to be done, especially as the time horizon increases. Estimation can help with planning but an estimate is not a deliverable. I find that often managers are willing to pay far more than they should for an inaccurate estimate that didn’t make any difference on the project.
I think that planning and estimation, especially the way it is practiced in Scrum, is largely a waste of time and can be inappropriately used by management as a way of forcing developers to get more done even at the expense of cutting corners and incurring technical debt.
Many of the ways that we track progress in software development actually de-incentivizes developers from doing the right things. If we are incentivized to make local optimizations but those local optimizations don’t affect the overall throughput, then the ultimate value of those optimizations is still very low.
If your team spends a lot of time in triage fixing bugs then finding ways to prevent bugs from being created in the first place could hold a great deal of value. Traditionally, this is one of the benefits of pair programming.
I find that for many tasks pair programming can be more efficient and effective but you can’t assume that two people will immediately get the work done together that they could have done by themselves in the short term because there is always a learning curve. It can take some time before two people get into enough of a groove to really get high productivity. But when it happens it can be magic.
I like to look at before and after data, a lot and generally I look at things like defect rates before and after a practice is introduced. I also look at code coverage and cyclomatic complexity but just as indicators on code quality because I don’t think we can programmatically determine whether a piece of code is good or not, we have to examine it ourselves.
Ultimately in my experience, I find exactly what the published studies find, which is that pair programming improves not only developer quality but also productivity. Fewer defects are being created, more requirements are being interpreted in ways that are of value to the customer and technical skills are being propagated throughout the team so that everyone’s collaborating more effectively and efficiently.
When I see teams who adopt Extreme Programming practices such as pair programming and the gains that they make over their competition I see how much of a competitive advantage high performing teams can be, especially in highly competitive and high-stakes markets.
Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software called Seven Strategies for Seven Strategies for Agile Infrastructure.
July 31, 2019
Let Teams Decide on the Details
As hard as it can be sometimes to convince managers to let their teams try pair programming and see if it improves their overall productivity and quality, sometimes I have the exact opposite problem and I have managers who want to force teams to do pair programming, even when the teams don’t feel it’s right for them. This can be a real issue.
I know many software developers who prefer not to pair and that should be just fine for everyone. Pair programming should not be a forced activity. There’s a lot of us who would just rather work in solitude and that’s not necessarily bad. We do need to collaborate and share ideas but there are many venues for doing that. Pair programming is not the only way to propagate knowledge across a team.
I find that in matters like these that the team should decide what works best for them. It’s good to have a guide or someone who can help the team try different practices but then leave it up to the team to decide how they want to implement them. Forcing developers to do pair programming against their will can be seen as an invasion of privacy and no one wants to go there. Instead, give people the space to discover what works for them. It’s natural that some people will want to engage in some practices more than others and so when we let the team find their own equilibrium then these things can often resolve themselves.
Teams probably shouldn’t be trying pair programming without also trying other new practices. Pairing works best when you’re learning a new set of skills because you have your pair partner to help reinforce those skills as you’re doing development. This is actually one of the quickest ways I know to go from the learning phase into the proficiency phase—do it with another person.
But when I say to let teams decide on the details of how they want to implement these practices they also need to have some level of guidance and support from management. They need to be aware of what resources they have available to them and I find that many teams aren’t aware of these things.
Scrum says to let teams self-organize and that’s a beautiful idea in principle but I rarely see teams have the skills and ability to self-organize around the right technical practices and that is because this is not common knowledge in our industry.
So we have to let teams decide on the details and also make sure that they have access to knowing what their options are and that comes from understanding the practices of software development by doing it or working with people who have done it. Books, blog posts, conferences, and training can also help. Software development is complex and we are constantly learning new and better ways of doing it. It’s a lot of effort to keep up but there are many rewards to be reaped if you can stay on the leading edge of developing software.
Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software called Seven Strategies for Seven Strategies for Agile Infrastructure.
July 24, 2019
Try All Configurations
Another key to discovering what works best for you when doing pair programming is to try all configurations. By that I mean mix it up as much as possible. On each project, you should try pairing with at least everyone once. Also try pairing for different periods of time before you switch pair partners, like an hour at a time or half a day at a time or two days at a time (with breaks), etc.
Mix things up as much as possible. This is the way that we stumble upon the things that work best for us. Just observe as you vary things. It also helps to write things down. Observe how long your attention span lasts to determine how often it makes sense for you to swap driver and navigator. Is it about the same for your pair partner? Or do they have significantly more or less stamina than you do?
These questions are worth exploring when determining who you pair best with. I often find that the best pair partners are not the ones who are the most senior or the most knowledgeable. I often find that complementary skills and personalities tend to work best for pair partners.
In other words, pair an introverted person with an extroverted one. Pair a practical person with a more abstract one. The benefits that we get from pairing come from the differences in perspectives that the other person brings and so we’re looking for people who are not like us, who are different from us and can bring that different perspective.
When I am introducing pair programming to developers who haven’t been exposed to it before I sometimes meet with resistance because they think that they’ll get criticized but they learn very quickly that we’re all human and we all make mistakes. Even the best of us can make silly mistakes.
I teach a software developer class that includes three afternoons of pair programming. At the beginning of my class, I sometimes spot a student who is clearly resistant to the notion of pairing with another developer. I love watching the process transpire because very often the person that was the most resistant to trying pair programming, in the beginning, becomes my very best advocate. I know one developer at a very large software development company who was definitely resistant to the notion of pair programming and later became one of the big proponents for pairing in his team and then across many other teams in his organization.
I keep saying throughout this series of posts on pair programming that you have to experience it to really understand it and it has to be done in the right way. When done well, pair programming can be one of the most powerful and valuable techniques for learning new skills and bringing the best of our skills and talents to our work.
Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software called Seven Strategies for Seven Strategies for Agile Infrastructure.
July 17, 2019
Put in an Honest Day
While I am a big believer in pair programming I don’t believe that we should do it all the time.
Pairing is exhausting!
After a pair programming session, I am usually wiped out because I am working hard the whole time. I have someone looking over my shoulder analyzing everything that I do. That’s great for learning new habits because if I slip up there someone there to remind me to do the right thing but it takes a lot of energy to be in that mode with someone.
When we work alone we can let our mind wander at times. We can check Twitter and the local news or whatever. But when we’re working with a pair partner we are focused and we stay focused the whole time we are working together. We’re also less likely to be interrupted by someone else when they see that we’re engaged in a conversation. The end result is that we spend much more focused attention on our work and we get a lot more done which, by the way, is why managers should support their developers in doing pair programming as much as they want.
It’s good to start slow and pair for maybe an hour or two at a time. I find that pairing for more than about four hours a day can be just too much when you’re first starting out. Don’t expect to put in a full day of pairing on an ongoing basis because I think that’s unrealistic, even for experienced developers. If you can do one to four hours of pairing in a day then I think that’s pretty good.
You’d be surprised at how much work you can get done in sessions like these. I always find that I get a lot of work done when I pair with another developer. I also learned an enormous amount about how they approach problems and build software.
I’ve worked with literally thousands of software developers as a consultant and as a trainer. I find that there are many valid ways of approaching software development but there are some eternal principles and practices that make the software we write more resilient to change in the future.
Not only do I find that I learned an enormous amount when I pair program from my pair partner but I also learned a tremendous amount from the process of putting my thoughts into words so that I can describe what I’m thinking to them. In the process of putting my thoughts into words, I tend to think through my ideas that come up and I find better solutions.
I can’t help but laugh to myself when managers tell me that pair programming is inefficient. It just tells me that they don’t understand where the real bottlenecks of software development are.
It turns out that two people working together can often produce higher quality code with fewer defects and these things significantly improve overall productivity. Coupled with the enormous benefit of propagating best practices throughout the team and giving team members the opportunity to discover best practices together, pair programming can be a hugely valuable practice for improving overall team productivity and consistency of results.
Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software called Seven Strategies for Seven Strategies for Agile Infrastructure.
July 10, 2019
Swap Roles Frequently
Another important technique for engaging developers in pair programming is to swap roles frequently.
For new pairs who are just starting to work together, I recommend swapping roles every 2 to 20 minutes. For more established pairs who’ve worked together well, I recommend swapping roles every 20 to 60 minutes, although that could become much more frequent as we’re learning new tasks or building unfamiliar skills.
We also want to do what Arlo Belshee refers to as promiscuous pairing. We want to engage in pair programming with everyone on our team. I didn’t really understand the importance of this until I began to practice it. What I discovered was that my very best pair partners were the ones I had least expected. I learned something unique and special from everyone on the team but it seemed like the people that I knew the least turned out to be some of the very best people to pair with and I would have never known that if I didn’t follow the practice of pairing with everyone at least once.
I always encourage everyone to pair with everyone. I also encourage people to experiment with different time lengths for their pairing sessions. Sometimes it’s valuable when learning new skills to rotate in and out of pairs frequently, I usually like to stay with a pair partner for the entire day or task or iteration. Generally, my preference is to swap pair partners on a task basis.
Aside from gaining new and fresh perspectives by pairing, it’s also an incredibly valuable way to propagate knowledge across the team. I find that this propagation of knowledge happens at many levels from the mundane to the abstract. I learned practical tips for how to use my tools more effectively and I’ve also learned new problem-solving techniques and approaches from pairing.
Sometimes, I’ll pair with a junior programmer and I do this specifically to be in the mentor role and help them improve their craft. I find though that doing this can often help me as a teacher more clearly articulate the things that make good development practices.
I think that software development has been in the dark for far too long and we put ourselves thereby isolating ourselves and thinking that writing code was a solitary activity. When we pair we learn from each other and when we do this promiscuously across the team we can propagate enormous amounts of information and knowledge very quickly. The end result is that we start to adopt common practices and the overall quality of the code improves.
As we begin to level-set our knowledge and skills the code we are working on starts to look more and more generic. This means that anyone on the team can work on any part of the code because everyone is cross-functional. This is a highly valuable thing to have on a team and it gets naturally achieved through pair programming. And this is just some of the many benefits of pairing.
Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software called Seven Strategies for Seven Strategies for Agile Infrastructure.
July 3, 2019
Engage Driver and Navigator
Pair programming is really a very simple concept. It’s about writing code in groups of two or more people. The person currently at the keyboard is called the driver. The person or people who are not at the keyboard are called the navigator or navigators.
The driver’s job is to deal with the minutia of entering code into the computer. This actually frees the navigator to think about the next few steps and keep a bigger picture in mind.
Nearly every team that I have met who is either having trouble with pair programming or didn’t like pair programming turned out to be doing it wrong. To them, pair programming was taking turns at the computer. They fight for the keyboard and the person who got the keyboard would hog it. Since the navigator really didn’t have anything to do they would take a nap until it was their turn.
That is not pair programming!
Pair programming is not about taking turns at the computer. Pair programming is about bringing two minds to bear on solving the same problem. So how do you encourage true collaboration, especially when we were taught to program in solitude?
One solution is to “past the keyboard.” I like to swap driver and navigator frequently and this helps to keep both engaged in the task at hand. How frequently? I say swap driver and navigator anywhere from every 2 to 20 minutes and I tend to prefer the short side, especially when I’m starting out with new teams. In other words, swap driver and navigator every 2 to 4 minutes to start with and that tends to keep people engaged.
We want to pair to bring software development to a true collaboration where two people are working together to discover the right solution. One of the best ways that I found to get developers into a truly collaborative mode when pairing is to have them start off in what Llewelyn Falco calls strong style pairing.
Llewellyn defines strong style pairing as follows: “In order for an idea to go from your head into the computer, it must go through someone else’s hands.”
In other words, the navigator is the one directing the driver to do the work. I like to think that the driver is in support of the navigator. While I’m the driver, my job is to make it easier for the navigator to do their job. I do this by dealing with the little details of typing in code so that the navigator doesn’t have to worry about it.
When I play the role of the navigator, I feel my job is to support the driver by helping them enter in code the most efficient and effective way possible. For example, if I’m aware of key bindings for actions that they are unaware of, then I may share that with them or I may help them learn a new procedure of steps by first giving them the instructions step-by-step and naming the procedure so that when we need to use it again I just refer to it by name instead of listing each step again.
The way I like to think of it is that the navigator’s job is to give information to the driver at the highest level of abstraction that they are currently able to receive. This is constantly changing for the driver at any given moment. That’s why it’s really important for the navigator to be very sensitive and make sure they’re not overwhelming the driver.
When driver and navigator are both engaged in pair programming then development can become a true collaboration and we can see really great things emerge. Not only will pairs produce code with fewer defects but they’ll also write cleaner code that cost less to maintain and extend.
Pair programming can be exhausting so I don’t recommend doing it for more than a few hours at a time. Pair programming can also be a lot of fun and very engaging when we do it well. That doesn’t mean that the magic happens every time or with every person. We have to find our best partners, that’s what will discuss in my next post so stay tuned.
Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software called Seven Strategies for Seven Strategies for Agile Infrastructure.


