Sunday, August 7, 2011

Being honest vs Making excuses

The other day, I was involved in a conversation with a group of developers. Several of them work at a large company whose product is built on Ruby on Rails. We were talking about the development environment there, specifically the test suite. The codebase is quite a few years old and has a very slow test suite in part due to some design issues in the codebase. I asked what their test suite was currently running at, and I don't remember the exact figure, but it definitely had a lower bound at 30 minutes (I think it might have been an hour). I then asked about just the unit test suite, the one you should be running frequently while developing. The speed for that was on the order of many minutes. Someone else then asked how it was to run a single set of examples, the type that's focused on whatever part of the codebase you're actively working on, the type that should be run almost constantly while writing code. This was 'better,' being on the order of 30-45 seconds. I remarked that this was still horrible, especially when working on a piece of the system that didn't need specific features of Rails*. One person remarked that this was inevitable with a large codebase. I disagreed. That is, I disagreed with the statement that the size of the codebase was the cause. Slow unit test suites and the inability to quickly run focused subsets are an indication of a design problem with the codebase, not the size. As we talked more, I started to notice something that I've seen before but had a hard time placing: extreme rationalization of bad situations.

This got me thinking. Often times, we choose to be in certain situations and then, rather than admitting that the situation is bad and dysfunctional, then convince ourselves -- and justify to others -- that this is the only way it can be. While we are free to choose trade-offs for whatever situation we place ourselves in, it is important to be honest with ourselves about the causes of the situation. For example, the above company has interesting computer-science-types of problems which makes up for the bad situation regarding the actual development process.

If we are not honest about the causes of a bad situation, we pose a significant danger to those who are either less-experienced or uncertain about their own situation. Take a slow test suite, for example. Having a test suite that actively hinders a developer from running portions of it while developing is a deterent even to run the suite at all. As the run time climbs into minutes, the test suite becomes an antagonist, rather than the helper and guide that it should be. Instead of rationalizing, say you have some serious design flaws in your system. Or, say you have a large codebase and a huge team consisting of people with varying desires to write automated tests. When we mask the real causes of a problem, it has the potential to confuse less-experienced developers who look to us for guidance. For example, thinking a slow test suite is inevitable could stop someone from asking for help optimizing their own codebase while there is still time. If you are talking to a less-experienced developer and you mask the fundamental problems, what message are you conveying to them?

The point of this post is not to point out how people are wrong or that you have to fix, or are able to fix, a bad situation. I just want to raise a reminder that there is a difference between rationalization and being honest with the reasons for something. By rationalizing, we are fooling ourselves and those who learn from us into thinking that you can't do better and it isn't worth trying. By being honest with the reasons, we have the opportunity to both learn from our mistakes, and teach others what pitfalls might await given certain decisions.

So, the next time you find yourself talking with someone and describing a less-than-optimal situation, ask yourself whether you are being honest about the causes. It doesn't mean you have the power or inclination to fix the problem, but talking about the causes can lead to valuable conversations about how we can do things better in the future.

also... can we stop using the terms 'ivory tower' or 'real world' when rationalizing our situations? As DHH said, "The real world isn’t a place, it’s an excuse. It’s a justification for not trying." (other inspirational quotes)

*In fact, I will put forward you can't do an effective test-driven development cycle with a feedback loop that long.

As always, thoughtful comments are happily accepted.

11 comments:

  1. "...can't do effective TDD with a long feedback cycle" is a canard. Those, like me, who write a test first because it helps with thinking through the problem get a benefit before the cost of a long feedback cycle is imposed. Clearly, an immediate (or nearly so) feedback cycle is the optimal condition for writing software. Calling TDD ineffectual in anything but a quick feedback cycle is bogus.

    ReplyDelete
  2. Mario,

    Calling my statement a canard could be called a canard, itself. I've worked with both slow and long test suite runs. I've seen others work in both types of situations. The difference is effectiveness from a TDD-perspective is barely comparable. I hardly would consider that statement unfounded.

    In the TDD cycle, you write a test, write simple code to pass the test, refactor, repeat. This process allows you to collaboratively work with your tests on evolving a good design. When you have to wait 45 seconds between writing simple code to see the test pass, or wait 45 seconds between doing your refactoring and verifying your change, your effectiveness drops significantly.

    In general, slow tests are a smell of a design issue, especially in a language with no compile time, such as Ruby. If you are in a compiled language, you do incur a cost for that, but you can (and should) take steps to shrink the dependencies that need to be included in a compile. Effective dependency management for assemblies or packages can shrink the compile time dramatically. I've seen and worked with incredibly fast tests in compiled languages, too.

    ReplyDelete
  3. Expanding on Corey's reply, it's kind of a microcosm of the switch from requirements-driven waterfall development to TDD. Everything that tightens the iterative loop increases the velocity of design-informed-by-tests. Conversely, everything that widens the loop--even if it's a 30s test--pushes the developer further towards designing everything-at-once instead of one simple addition at a time.

    ReplyDelete
  4. When I do something objectively silly and insist on doing it, then someone asks me why, I usually notice that the reason has to do with something else that either I feel ashamed to acknowledge or feel unmotivated to address. In those situations, I find that putting attention on the problem behind the problem tends to solve the surface problem quite readily. Knowing this pattern, I find I empathise better with the person doing the objectively silly thing. Empathising better with that person, I find I can more successfully guide them past the problem behind the problem, even if that problem is quite serious. I even find that I do that better to and for myself.

    ReplyDelete
  5. Sometimes we aren’t consciously rationalizing problems. Sometimes we end up with a problem without realizing it, and we end up blaming processes, tools, or technologies not because we are trying to rationalize problems, but because we honestly believe they are the cause of the problem. This is especially the case when the problem manifests itself as an annoyance rather than a crisis. People have an amazing capacity to put up with uncomfortable situations.

    What I find the most useful of your post is that you are stating that these annoyances are an indicator that there is something wrong with the code. And that we should be aware of them, determine the real cause, and then address them. There is a problem, however, when people adapt to them: you just don’t notice them. It would be great if there was an indicator that would alert us to get us out of our frame of mind.

    The good thing is that humans come equipped with an excellent error detecting mechanism: pain. Pain tells our brain that something is wrong with our body, and we should fix it. The most amazing thing is that we feel pain also when we are working and there is something wrong going on. So, if doing a task on an app hurts, then it is likely that we created a coding or design problem. And it is most probably that we are the cause of it and not the process, tool, or technology, although there are some exceptions.

    ReplyDelete
  6. Hugo,

    Thanks for the comment.

    It is true that we are great adapters to difficult or painful situations. This is a good thing, as it allows us to still be happy when we find ourselves in situations that we either can't or won't change.

    Also, I want to emphasize that my point is not that it is not always the case that there is some root cause different than what we think, just that it is something we should consider.

    ReplyDelete
  7. Its true that sometimes we all feel that convincing others is much more easy and its better we keep silent for the time being. but this silence had made thosepoeple win their silly arguments. so if someone speaks boldly in such situations i just feel good.

    ReplyDelete
  8. Thanks for the comment, Andrea. It can be a good thing to speak up.

    ReplyDelete
  9. This comment has been removed by a blog administrator.

    ReplyDelete
  10. I am very happy to have stumbled upon this blog post as I have been having a very similar line of thought lately as demonstrated by these tweets:
    Reality
    The way it is

    One thing I like to do before responding with a statement like "... inevitable with a large codebase" is evaluate in my mind the benefit of saying that statement over the long term (including the attitude it fosters in others) VS getting curious about your feedback to see if we can learn something or brainstorm a solution that would improve the times.

    However, too many developers let their ego get in the way (and I'm guilty of it too), especially when they feel they have delivered to business successfully and helped make a lot of money despite a long running test-suite. Yet, that is a very limiting way of looking at it. A more useful way would be to think of how much more money the business would make when developers are not wasting time tinkering with a slow test-suite. How much better business solutions would emerge when code design is optimized to yield a faster test-suite.

    So, then the only conclusion I can deduce from a developer not thinking of "how much better things can be" VS "the way it is" is mental laziness and resignation to the status quo, under the guise of "working hard to get something out".

    And with that, I leave you with this tweet:
    Virtue of Work

    ReplyDelete
  11. Sometimes we aren’t consciously rationalizing problems. Sometimes we end up with a problem without realizing it, and we end up blaming processes, tools, or technologies not because we are trying to rationalize problems, but because we honestly believe they are the cause of the problem. This is especially the case when the problem manifests itself as an annoyance rather than a crisis. People have an amazing capacity to put up with uncomfortable situations.

    What I find the most useful of your post is that you are stating that these annoyances are an indicator that there is something wrong with the code. And that we should be aware of them, determine the real cause, and then address them. There is a problem, however, when people adapt to them: you just don’t notice them. It would be great if there was an indicator that would alert us to get us out of our frame of mind.

    ReplyDelete

Please don't post anonymously; I won't use your name/url for anything insidious.
Comments by Anonymous are not guaranteed to make it through moderation.
Constructive comments are always appreciated.