The subtle difference between process and practice in Software Engineering
From learning the ropes to fighting the ropes - a cautionary tale of how a best practice can become the worst process
Early in my career as software engineer I was lucky enough to discover the power of unit testing. My organization at the time relied heavily on QA. Having enough trust from the leadership, I advocated for making unit tests mandatory and it was accepted. What a glorious mistake it was!
This was my first of many encounters with practice vs process that made me realize their differences. They are both important, but it is paramount you use them in the right context.
I will start with a bit of definition to establish a mental model and then jump right into advice.
What is a process?
A process is a series or set of activities that interact to produce a result; it may occur once-only or be recurrent or periodic.
Wikipedia
Going back to my story of caution, developers writing unit tests is a process, and management has the authority to enforce it.
The result was that many people from the team started sharing standup updates like “I’m done, just writing the unit tests” or “it’s fixed, but tests are breaking”.
Work was not getting done faster as I have promised, but slower.
What is a practice?
a job or business that involves a lot of skill or training
Cambridge Dictionary
Practice in this context is a way of doing things - a how rather than a what.
What I particularly like in the definition above is that it involves skill. And skill, in contrast to a process, is not something you can enforce. It is something you have to teach or hire.
What is a best practice?
More often than not, a best practice is a process in disguise. If you read a cool blog post from a big tech company and decided to adopted it in your 5 people startup, it is very likely you are focusing on what (the process) and missing out the why and how.
Don’t be tricked by wording. Remember that a practice is a how and a process is a what.
Is a process always a bad thing?
No.
Processes are a useful way of putting constraints and limit local optimization. People are very good at avoiding short-term friction.
Imagine there is a bug in production and customers are complaining about it. It is not the end of the world, but it is generating customer support requests and the team is embarrassed. They are working around the clock to fix it.
Should they write unit tests? Can they skip the integration testing step and directly push a build to production? What if the automated tests take an hour to complete?
A deployment process is there to make sure the team is not optimizing out of embarrassment in the moment. Instead of resolving this specific situation faster, a proper constraint motivates the team to write better code and tests, preventing similar issues, or make integration tests run faster.
If there is no process, if the team is free to drop the practice whenever “the situation demands it”, you will miss out a lot of opportunities for long-term gains, not to mention the outages your “fixes” will undoubtedly cause at some point.
In the worst case, a team under a lot of pressure can neglect the practice so often that it is no longer “a practice”.
When to use which?
Imagine you start to encourage pair programming practice in the team. This will certainly have a positive overall effect as people will optimize for cases when it is obvious it will help, e.g. complex features or some stretch assignments for a junior developer.
The danger is that you will miss opportunities to leverage it. A complex feature will be developed by a lone wolf who is well over their head. The team will “forget” about the practice when feeling overwhelmed with parallel work.
Enforcing a pair programming process will eliminate that risk. However, it will also mean mundane features are developed by two bored engineers, decreasing the overall team throughput and creating friction as people feel “stupid” doing it.
The bottom line is to put a process when you cannot tolerate mistakes and prefer practice when you cannot tolerate friction.
Conclusion
Process and practice work best together. Without process, a practice might be neglected, and without practice, a process might be misinterpreted.
Teach practices (like unit tests) to ensure people understand the how and sometimes put a processes (like measuring coverage) as reminder when you cannot afford to forget.
And absolutely always start with why1.
How did my story end? I did a lot of pair programming to teach unit testing.
A reference to Start with Why: How Great Leaders Inspire Everyone to Take Action, a must read in my opinion.