Writing code without following certain professional practices often reminds me of a story I heard in Steven R Covey's book, The 7 Habits of Highly Effective People. The story was told to illustrate the difference between a leader and a manager. Here is roughly how it goes:
A group of people are cutting trees in the forest. One of them is a leader and another is a manager. The leader decides to climb a high tree at one point to see if they're making progress in the right direction. To his surprise, he finds out that they're actually cutting the wrong forest, so he yells at the top of his lungs "Wrong forest!!!" What does the manager say in response? "Shut up! We're making progress!"
This is pretty much what happens whenever a professional developer tries to remind a colleague of writing tests before writing code, pair-programming, or doing paper-prototyping on user-interfaces before implementing them.
When the colleague resists the suggestion, reasoning that it is more important to deliver than follow one of the suggested practices, would the resulting delivery be real progress? Or would it just be an illusion?
Let's look at test-driven development for an example. If a developer is delivering code without writing tests first, he may be delivering features "now," but if they have bugs that need to be fixed later with double the time at least that would have been spent writing the tests in the first place, was that real delivery or was it just an illusion?
What about skipping pair-programming and working solo? After having a few years of experience in pair-programming, I am completely aware now of how slower I am at delivering complex features whenever I work on them on my own. Often, such features are scrapped completely and redone after a review with someone. Was that real delivery or just an illusion?
How about delivering user-interfaces without doing any sort of conceptual design or paper-prototyping, let alone user testing? I've seen quite a number of user-interface screens developed and done only to be completely overhauled afterwards because they reflected the developer's mental model as opposed to the user's. Was that real delivery or just an illusion?
Writing tests first guides developers towards better code design, provides a safety harness that enables future refactoring of the code and maintenance by other developers without unexpected bugs popping up in other areas of the application, and keeps progress real and linear as opposed to illusory and unpredictable.
Pair-programming saves quite a bit of time by having developers sell each other on the benefits of certain designs before diving to implement them, results in transfer of knowledge between team members that makes them much stronger, and gets the benefit of unexpected synergistic solutions that often save hours of work. That's often much better delivery than having two programmers working independently all the time.
Finally, a little bit of time spent on designing user-interface paper-prototypes (10 minutes) and a bit more time spent testing the prototypes with real (or model) users (10 more minutes,) saves developers from so much time in rewriting bad user-interfaces or figuring out a reasonably usable user-interfaces for the actual users.
So, the next time you think about skipping one of the recommended professional practices, ask yourself: "Will I be delivering to the customer the most value in the long run if I skip this practice, or will I just be kidding myself into thinking that I'm delivering now when I'm hindering delivery in the long run and keeping myself in an illusion?"
One yardstick I use to evaluate whether my resistance to a suggested practice is legitimate or is just plain human resistance to change is to also ask myself "Am I only resisting it because I don't see how it can help the customer or is there a little bit of feeling of inconvenience to adopt it?" If there is even a nugget of feeling that I do not want to be inconvenienced by change, I give the practice another chance, keeping in mind that often it takes getting good at a certain practice before I can reap benefits from it.
Final Note: there are of course situations where some of the practices mentioned above may not be appropriate. For example, in a situation where a legacy app requires one extra feature and the team is not trained in TDD, it wouldn't make sense to apply it, but it does make sense to think about implementing that practice strategically in the future.