A pleasant walk through computing

Comment for me? Send an email. I might even update the post!

My Mixed Relationship with TDD

OK, not completely "created by," but You won't believe how old TDD is

Intro

I have a mixed relationship with Test-Driven Development (TDD). It's a valuable method that I've enjoyed--when I've used it. What matters more to me than test-first is creating automated tests early rather than late.

Despite my on-again, off-again history with TDD, I've written about it in tutorial form. This series also includes examples of mocking and dependency injection. What to mock is, I think, especially difficult to get right.

History

In 2001, at the beginning of the third millenium, I first learned about some eXtreme Programming (XP) practices, among them TDD. I wanted to try this out, but ran into a snag: Visual Basic 6 didn't have a good unit testing framework. 1 So, I wrote my own. I also wrote it to test private methods, because that's where the action was, and I hadn't yet wrapped my head around why testing public methods was key to keeping tests separate from code.

Even then, I got the TDDers thrill from seeing all green after running tests. However, my organization wasn't invested in TDD, so I set it aside. This was the story for the next couple of decades. The places I worked didn't care about more agile methods, and my efforts to introduce and use TDD didn't go far. Over time, I realized something else. My background in creative writing and music composition led me intuitively write code in a particular way:

  1. Draft the code, getting some things working quickly.
  2. Significantly rewrite as the better structure reveals itself.

TDD didn't fit into this way of coding new projects, because my code would often change a lot as I settled on the most effective patterns. In business parlance, this is a "fail early, fail often" approach. Writing tests first at this stage worked against me because the methods I was testing were in flux. Heck, the whole approach was in flux. I could delete them at any moment. It took me a long time to reconcile how to integrate unit testing and TDD into my personal, fluid--and effective--style of coding.

One developer I talked with said his team didn't practice "test first," but instead "test eventually." I stored this tidbit away, though something nagged at me. How often was "test eventually" turning into "test never?"

Database Testing

Another obstacle on my road to successful unit testing was how to deal with databases. This wasn't just my obstacle, of course. It hung up loads of developers. The Repository Pattern was known, but not well-understood or encouraged in the Microsoft world. Abstracting the database seemed--and often was--tedious, time-consuming, and prohibitively maintenance-heavy. What kind of software was I writing all the time? Yep, database-centric.

Things didn't because easier with the adoption of Entity Framework (or Linq2Sql). When it came to testing, Microsoft's own documentation often recommended Repository Pattern, and sometimes Unit of Work.2 This was frankly a mess. Why? Because EF was itself built using Repository (DbSet) and Unit of Work (DbContext) patterns.3 So, developers were writing an abstraction on top of an abstraction.

Again, I was hampered by a couple of things:

  1. When a regular employee, I wasn't working in an agile environment.
  2. When a contractor, I was often constrained by client expectations.

Today

Over the years, I've returned to TDD several times and have come to some tentative conclusions.

  1. For me, on a greenfield project, test-first shouldn't be introduced immediately, but only after going through my drafting/iterating process to help clarify how "the code wants to be written" (I agree, a squishy, woo-woo statement.)
  2. After that, TDD is a big help, primarily because it forces tests to be written in parallel to coding and forces useful abstractions and separation of concerns.
  3. Sometimes, though, TDD needs to be set aside while a coding solution is explored via a deep dive. Avoid premature testing. In these cases, the developer's mind needs to flow.
  4. Testing reveals architecture problems. This is another top value. In order for code to be testable, it needs to be well-architected using dependency injection and coding to interfaces.

I'm insisting on unit tests in my code, and forcing myself to use TDD in my workflow. This will require reading about modern TDD, and being confronted with terrific articles such as TDD Harms Architecture by "Uncle Bob" Martin.

Other Thoughts

Not "Design"

TDD is not design. Some people want the acronym to be Test Driven Design. But TDD isn't designing anything, except in the very loosest sense that programmers are always designing a method before coding it. We at least imagine how it's going to work, and that's--again, loosely--design. Robert Martin says it emphatically:

The idea that the high level design and architecture of a system emerge from TDD is, frankly, absurd. Before you begin to code any software project, you need to have some architectural vision in place. TDD will not, and can not, provide this vision. That is not TDD’s role.

And goes on to say

However, this does not mean that designs do not emerge from TDD – they do; just not at the highest levels. The designs that emerge from TDD are one or two steps above the code;...

Favorite Framework

That's easy. xUnit.net. I've loved it since its early days. Now, I've often used MSTest because it's A) built-in, and/or B) it's what the development shop was already using. But I prefer xUnit.net and its features such as Theories.

Using one of the "Should"4 libraries makes unit testing even more readable.

Wrap-Up

Testing is hard. Unit testing is hard. But early, automated testing builds confidence in the system, and TDD provides a valuable feedback loop that stacks nicely on other methods such as continuous integration.


  1. This isn't quite true. There was a framework, but my misunderstanding of why only public methods should be tested interfered with me using it.

  2. Such as this untestable craziness: Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application (9 of 10) | Microsoft Docs

  3. But not until EF 4.1, and mocking wasn't easy-ish until 6.0.

  4. shouldly and Fluent Assertions

Don't Be a Lazy Programmer Like Matthew Jones Isn't

Matthew Jones recently wrote a blog article titled Be The Laziest Programmer You Can Be. I like Matthew's articles, and I like this one in a way, but I'm going to make a case that Matthew's completely wrong in his definition of lazy. This is one of those subjects that rankles me, kind of like computer people routinely misusing the word "deprecate."

The traditional statemnent of Matthew's gist is:

If you want to find the most efficient way to do a job, give it to a lazy person.

Matthew states his thesis as:

lazy programmers want to do as little work as possible right now. But they also want to do as little future work as possible,...

He's absolutely right about the first part, doing as little work as possible right now. But he's absolutely wrong about the second, that lazy programmers are concerned about the future. They aren't, that's the problem. And, they're not efficient, they just get by.

Examination

Let's hit the dictionary first.

adjective, la·zi·er, la·zi·est.

  1. averse or disinclined to work, activity, or exertion; indolent.
  2. causing idleness or indolence:
    a hot, lazy afternoon.
  3. slow-moving; sluggish:
    a lazy stream.
  4. (of a livestock brand) placed on its side instead of upright.

verb (used without object), la·zied, la·zy·ing.
5. to laze.

"Averse or disinclined to work." This isn't decisive, because one could argue--as Matthew does--that a disincilation to work could extend toward future work. What does science have to say? [Emphases mine]

A person is being lazy if he is able to carry out some activity that he ought to carry out, but is disinclined to do so because of the effort involved. Instead, he carries out the activity perfunctorily; or engages in some other, less strenuous or less boring activity; or remains idle. In short, he is being lazy if his motivation to spare himself effort trumps his motivation to do the right or expected thing.

The Psychology of Laziness | Psychology Today

Other aspects of laziness that are discussed in a brief review of the psychology:

  • Procrastination "Laziness and procrastination are similar in that they both involve a lack of motivation. But, unlike a lazy person, a procrastinator aspires and intends to complete the task and, moreover, does eventually complete it, albeit at a higher cost to himself."
  • Evolution Our nomadic ancestors had to conserve energy to compete for scarce resources and to fight or flee enemies and predators. Expending effort on anything other than short-term advantage could jeopardize their very survival.... it made little sense to think long term.
  • Effort and Reward "In most cases, it is deemed painful to expend effort on long-term goals that do not provide immediate gratification. For a person to embark on a project, he has to value the return on his labour more than his loss of comfort. The problem is that he is disinclined to trust in a return that is both distant and uncertain. Because self-confident people are more apt to trust in the success and pay-off of their undertakings (and may even overestimate their likely returns), they are much more likely to overcome their natural laziness."

And, from 7 Reasons Why Laziness Is a Myth | Psychology Today:

  1. Fear of failure. "Many people get in their own way by postponing the pursuit of goals,""
  2. Fear of success. "This cousin of the fear of failure is very real: Many people are unconsciously worried that they’ll succeed in ways potentially threatening to others. So they avoid conflict by not moving forward."
  3. Desire for nuture. "some of us don’t know how to ask for what we want directly—so we act useless as a way of getting others to do things for us."
  4. Fear of expectations. "One of my patients rarely made plans and established herself as “lazy” so that other people would plan for her."
  5. Passive-aggresive communication. "People who avoid conflict often bury their dissatisfied feelings. They may communicate them indirectly through “laziness,” slacking in a way that will upset another person."
  6. Need for relaxation. "Many people erroneously assume that they should always be going full steam, and chastise themselves for being “lazy” when their body and mind shut down in protest."
  7. Depression. "In criticizing himself for “laziness,” a man may miss signs that he is depressed and needs treatment."

This picture of laziness is much clearer. According to established social and science understandings, a lazy person:

  • Avoids doing hard work now, and so does the easiest thing he can get away with.
  • Isn't influenced by (or concerned with) future consequences.

Here are some attributes of a lazy developer1:

  • Doesn't write thorough unit tests. Tests, if written, allow him to fit the requirement, but don't catch enough problems.
  • Doesn't use consistent naming conventions. He uses whatever occurs to him at the moment.
  • Only updates Scrum/project estimates and completions if pushed to do so, and probably days after the fact.
  • Makes no or cursory source control comments upon commit.
  • Source code only works on his machine, unless he's been forced otherwise through continuous integration.

Refutation

Is Matthew a "lazy" programmer? No, of course, not, but now I'm in for a pound so let's go through his article point-by-point.

"why don't I hear you typing?"
Matthew got in trouble for being lazy for not typing enough. This was a management failure, pure and simple. And it's proven by the company having an overtime-oriented culture. I'll bet they were lazy because they weren't planning ahead, as Matthew was. That guy was wrong and a jerk.

Lazy programmers are good programmers. They don't do more work than absolutely necessary.

No. The confusion here is in the word "necessary." For Matthew, "necessary" means "do it right so we reduce doing it again." Lazy programmers define "necessary" as "required by something external." Let me call this one out.

Refactoring doesn't exist for the lazy programmer. It's not in his vocabulary.

Lazy programmers abhor redundancy

Just the opposite. A lazy programmer will copy/paste code all day, because he's a) finishing more work right now, and b) doesn't expect to have to fix the code later.

Lazy programmers explain their decisions. They write thorough comments

Nope. Lazy programmers, concerned only with the present, see explanations as a waste of time. "Working" code should be good enough, they reason.

A lazy programmer is not attached to his future self.

Lazy programmers automate everything that can possibly be automated

That would take foresight. I've seen this repeatedly, programmers who are too lazy to encapsulate a method, or write a utility to automate. They'll instead do it the long, hard way every time. Their justification? "Writing that utility will take too long!" (This thinking is further exacerbated by deadline-oriented management.)

Lazy programmers teach people more junior than them, partially so those junior people can do the work instead.

Half of this is right. Lazy programmers want to get other people doing their work. But the way they do it is to claim they're too busy to fix their own code, and too busy to explain clearly, so just figure it out.

Lazy programmers expect to be replaced.

Well, they should expect this, but are not only surprised when it happens, but also angry, because they think they're doing what was expected.

Be lazy. It's OK.

No, it isn't, because you're not. Programmers!, don't conflate laziness with other problems. And don't beat yourselves up, either! Get help with beliefs and root causes. Learn to value strategic thinking, to give yourself a positive boost about creating that automation utility. To see your future self grinning like mad and saying "This used to take the other guy four hours. I automated it and it's done in four minutes."

It [laziness] takes practice,

It should be pretty clear by now, but lazy people don't practice. I play violin. I'm prety good. But one reason I don't play violin really, really well is because I only practiced enough to get by. (I also didn't know about deliberate practice, but that's another story.) A lazy person, by definition, avoids effort.

Excellence requires continual effort

Is Laziness Bad?

No. Well, maybe. The behavior's not helpful, and often harmful. The thing is, lazy people aren't bad. It's not a disease, and it's not a character or moral defect. As noted above, there are people who get huge amounts done, but if they rest they demean themselves as lazy. That's unhealthy.

Laziness is a habit. And habits can be broken.

Then What is Matthew Jones?

That's pretty easy. Matthew is an effective developer. All of the positive traits he ascribes to laziness are in fact hallmarks of high-performing software engineers. Matthew:

  • Is concerned with how his current actions impact his future self.
  • Is likewise concerned with making his code easier for other developers.
  • Plans. Then executes. Then reviews and improves. He practices kaizen. He refactors mercilessly.
  • Coaches others and, I hope, is always willing to be confronted with opposition, otherwise I probably wouldn't have taken the time to write all this down. Because, Matthew...
  • Is wrong about what it means to be a lazy programmer, and I hope he revises his pitch. It's great to help programmers not be lazy, but I don't think redefining a word to mean its opposite is a good idea.

Matthew, I have a feeling I'd like you if we sat down for a beer. If you're ever in Denver, let's find out. You take your craft seriously, and have a light-hearted writing voice. It's from that mindset that I'm telling you, firmly, kindly: Matthew, buddy, you are not a lazy programmer!


  1. Sorry that these are all in the masculine. Unfortunately, 90% of programmers are guys, so I'm writing to the majority audience.

Personal Reflections on Removing Distractions for Improved Productivity

I've done a couple of experiments with reducing distractions (here and here). Since then, I've taken the weed-whacker to Facebook, only check the news a couple of times a day, and (try to) restrict my Netflix.

What does this mean for me professionally and personally?

Facebook

First of all, I don't miss Facebook one bit. The research is pretty clear that social media makes us unhappy. What alarms me in retrospect is that Facebook use seems like an addiction: something bad for you, but you can't stop doing. Consider these stats from a recent NBC News/Wall Street Journal poll on social media usage:

  • 69% of adults in the US said "they use such services at least once a day."
  • And yet, "82% of Americans believe social media is a waste of time."
  • 57% said social media "does more to divide us."
  • 55% said "social media does more to spread lies and falsehoods."

I've been pretty careful for a long time about what services I sign up for. I can't deny the influence of Twitter, but I never understood the appeal of reading people's mundane, off-the-cuff thoughts, or publishing my own. I never signed up. Likewise, no SnapChat.

In short, I only had Facebook to deal with. I was a little worried about losing contact with my FB friends, but realized a) I only had about thirty FB friends, and b) that worry was a symptom of the FB disease. The solution was easy, I asked all my FB friends via instant messenger if they'd give me their email addresses so I could stay in touch. Many did. Anxiety-crisis averted. I backed up and deleted my account.

What now? That's easy, too. How about I make more real, in-person friends? You know, the kind that research shows actually increase well-being?

News

The news is inherently depressing, and apparently we love it. Even as a kid (back in the three-network days), I hated watching or listening to the TV news because it sounded ugly. This doesn't mean news isn't important. But there's only so much reporting of the current socio-political awfulness a person should read.

I used a browser blocker to keep me from reading the news during the day for several weeks. I'm pretty good now at only dipping into Google News and NPR a couple of times a day. I know from past experience I can go weeks at a time without checking the news because if something really, really important happens I'm sure I'll hear about it. Here's the way I now see being a news junkie:

The news is like Facebook. Emotionally, it's more like gossip, and is addictive in the same way.

The fact is, I can't do much, if anything, about what's in the news. So why obsess and clamor and complain over what I can't change, when I can fill my life with plenty that I can?

Netflix, et al

This is my bane. Netflix, Amazon Prime Video, CWTV, IMDb FreeDive, YouTube...I'm still addicted to streaming media. It's not wrong for me to enjoy a little TV and movies, but it's too often a go-to break from work or other activities. Is this bad? Yep, for the same reasons as above. It keeps me away from real, live social interactions. There's also evidence that watching TV has negative mental effects, while reading has positive effects. (Sorry, I don't have a link to this right now.)

My current solution to this is strict time-blocking. I try to only watch Netflix during certain times of the day.

I know when I'm watching too much TV. I can feel it, and that's compounded by my profession as a software engineer. My job is at the computer, so all together I can end up spending sixteen hours a day on the thing.

Meditation, WOOP, Time-Boxing, Habits: Whew!

Removing distractions has helped my productivity and well-being. But it's not enough. To create a healthier work balance, I needed to retrain my brain. Fortunately, we live in a great time for research into well-being.

Meditation
Proper meditation, where the wandering mind (the Default Mental Network) is stilled, helps not only with mental/emotional health but also distraction. After all, the wandering mind is distraction.

WOOP
This is a great technique for establishing new behaviors and habits. It can be done daily in a few minutes. I've used this to manage overwhelm when facing a large task list.

  1. Identify what you Wish for (the goal)
  2. Imagine and emotionally invest in the Outcome(s). It's valuable to imagine the affect on the future self.
  3. Imagine and emotionally invest in the Obstacle(s). Again, what's the affect on the future self?
  4. Create a simple If-Then Plan. "When this happens, I will do this."

Note: Do not "flip the Os". Imagine outcomes first, then obstacles.

Time-Boxing
I've adopted a 50-10 time box. Read my blog article.

Habits
There are great books on how to break and make habits, based on science. For those who love podcasts, here's an interview with the author of Atomic Habits.

Final Reflections

I've had to overcome some challenges in the past couple of years. Thankfully, I have a wife who loves me, and my clients have been happy with my work. I enjoy reading about science and well-being, and enjoy even more applying what I learn.

All in all, my experiments have been a success.