Part II - What is The Right Timing for Tydings?
This is the second part of the article Summary and Impressions on the Book “Tidy First? A Personal Exercise in Empirical Software Design” by Kent Beck. Please, you’re invited to read Part I, if you haven’t yet 🙂
Ok, so what is The Right Timing for Tydings?
This is a very interesting question in so many ways. Perhaps, this is interesting because there’s no single answer that can be generalizable. Actually, there’s even a question on whether tidyings should be applied at all. So, assuming the pull request model, here’s the puzzle:
I create a PR with my behavior changes mixed up with my tidyings.
Reviewers complain that my PRs are too long or going out of scope.
I separate the tidyings into their own PRs, either before (more likely) or after the PR with behavior changes.
Reviewers complain that the tidying PRs are pointless (or time pressure prevents my PRs from being reviewed).
Go back to 1.
Of course, the problem above will depend on other factors too, such as the size of the PR, review latency, different moments in the release cycle, etc. But if you’re tidying the code, the changes do need to go somewhere. There’s no single solution that will guarantee steps 2 or 4 are not going to happen, but there are some practices that might help in reducing them or avoiding them to some extent.
From the book, the short version of the recommendation is: tydings go in their own PRs, with as few tydings per PR as possible – option 3 above, but this is easier said than done.
What to consider then?
The book breaks this down a bit more as a trade-off analysis that’ll, of course, depend on context and engineer’s intuition. Watch for:
-
Batch Size: amount of tidying per batch (or PR).
-
Collisions: the more tidyings per batch, the longer the delay before integrating, and the greater the chance that a tidying collides with work someone else is doing.
- This becomes even more critical when the codebase is super large with hundreds of contributors.
- Interactions: the chance of a tidying batch accidentally changing behavior rises with the number of tidyings in the batch. And likewise, merge costs rise dramatically when we have an interaction.
- Speculation: The more tidyings per batch, the more we are prone to tidying unnecessarily.
-
Collisions: the more tidyings per batch, the longer the delay before integrating, and the greater the chance that a tidying collides with work someone else is doing.
Time put into a tidying batch: a good rule of thumb to measure the batch size is to look at how long your tidying is taking. It’s supposed to take a few minutes up to an hour. If it takes longer than an hour then it might mean you’ve lost track of the minimum set of structure changes needed to enable your desired behavior change.
Unfortunately, in many organizations, the cost of getting a single change through review and deployment is high, which kind of forces engineers to work on fewer batches, which in turn forces the team to work on bigger batches – the anti-pattern of bigger and less frequent batches. That goes back to the basics of Continuous Integration (or why software integration became ‘continuous integration').
All in all, considering the code review PR-based model, if we want to make tidyings low cost, which thus decreases the cost of making behavior changes, the best approach is to work on reducing the cost of code reviews (or even eliminating the need for it, but that’s something for another article).
Also, adding another piece not mentioned in the book, orthogonal to all that is the presence of a good test suite. When changes are “guarded” by a good set of tests which developers can rely on, it is the most rewarding investment a team can make, in my opinion. Besides code review, the presence of tests will certainly contribute to increasing developers and reviewers confidence about the changes in question, thus reducing friction on tidying (whether they’re mixed up with behavior changes or in separate PRs). And if they’re batched in separate PRs, and passing all tests, the need for code review is reduced (unless engineers do code reviews for other purposes such as knowledge distribution for instance).
Ok, those were considerations about tidying batch size and how long they take. But, what about how tangled tidyings usually get in the code changing process?
Separating tidyings in practice
In practice, naturally, while you’re working on a PR, you tend to make a sequence of mixed changes that involve tydings and behavior changes. That results in three options:
1. Ship it as is. This is impolite to reviewers and prone to errors, but it’s quick.
2. Untangle the tidyings and changes into separate PRs, or a sequence of PRs, or a sequence of commits in a single PR. This is more polite, but it can be a lot of work.
3. Discard your work in progress and start over, tidying first. This is more work, but it leaves a coherent chain of commits.
In summary, these options stem from deciding between ‘untangling’ the tidyings and work on them in separate PRs or not (just shipping them mixed with behavior changes), thus assuming you should tidy.
However, there’s still an important question to answer: Should I tidy at all? And if yes, when? Way later? Or right after I make the behavior changes? Or right before?
Never, Later, After, First?
Never: that’s basically the idea of ‘if it ain’t broke, don’t fix it.’ or ‘yes, there is a mess, but we consciously choose not to do anything about it as we’re not changing the behavior significantly anyways’’
Later: the tidying batch is big, and there’s a payoff, but it is not immediate. So, break up the big batch into smaller ones. Work on small tidying batches in between future behavior changes.
After: when the tidying batch is not big, waiting for later will make the work ‘more expensive,’ and when you won’t feel a sense of work completion if you don’t tidy after your behavior changes.
First: when it’s clear what to tidy and how, and the tidyings pay off immediately in terms of code and design comprehension and less expensive behavior changes.
And what’s the economic reasoning behind all that?
The Economics Reasoning
Behind all the alternatives listed above, there’s the concept of “cost” (or money). Kent applies two economic metaphors to when to do the tidyings. The first one is A Dollar Today > A Dollar Tomorrow – This is based on the notion that the money earned today is worth more next day (and as time goes by) because that allows you to invest it in exchange for some benefit (i.e., more money or some other benefit). You can read it as materializing a software change sooner is better when you can collect the benefits/profits of such a change sooner than later. So, this ties back to what we saw earlier.
Tidy After (or Later): If we can implement behavior changes that make us money now and tidy after, let’s then make money sooner and spend later – this gives us the flexibility to exercise a profit soon and the ability to invest it to make our today-dollar > tomorrow-dollar (and part of that investment can be a batch of tidyings later or not). However…
Tidy First: If the cost of tidying first + cost of behavior changes is still less than the cost of the behavior changes without tidying, then let’s go for it! There’s no point in ‘paying’ more for a tidying after or later if it can be done at a lower cost now.
And what if the opposite is true? The cost(tidying) + cost(behavior changes after tidying) > cost(behavior changes without tidying). Hmm… if you answer is “No, don’t tidy first, in this case, or don’t tidy at all.” then maybe you’re right. But maybe you’re not. Still, no straight answer, unfortunately. That leads us to the second economic-related concept posed by Kent and that is the concept of Options.
Without going into the details about the concept of Options in the finance domain, here you can assume that, as a software engineer, you may want to exercise an Option by investing time on tidying first based on the speculation (or I should say based on your best judgment call as an engineer) that your tidyings will enable profits (i.e., benefits) in the future. As in the finance domain, an Option comes at high risk (the risk of being wrong in your speculation or judgment call). For instance, even though when cost(tidying) + cost(behavior changes after tidying) > cost(behavior changes without tidying), you may still think that you can amortize the cost of tidying first over a series of behavior changes in the near future that can benefit from the tidyings.
If I was able to summarize well the two economic concepts (today-dollar > tomorrow-dollar & Options) then you probably realized at this point that those two strategies conflict at times. This means:
Earning money now (today-dollar over tomorrow-dollar) can reduce future options. This relates to the decisions of “Tidy After” or “Tidy Later” or maybe don’t even tidy at all.
However, perhaps, if you don’t earn money now (if you spend, instead), you may get a chance to exercise those future options. “Options tell us to spend money now to make more money later“. This relates to “Tidy First” and to possibly combine it with “Tidy After” and “Tidy Later” too. If the value of the options created is greater than the value lost by spending money sooner and with certainty than this path makes sense.
Too complicated? Hmm… Yes (at least it sounded complicated to me at first). However, I have found this theory good to frame my mind around this software design topic. I think it can help the thought process as a conceptual framework while engineers evolve software.
From the book, “software design has to reconcile the imperatives of ‘earn sooner/spend later’ and ‘create options, not things’.” And that’s what makes this economic dimension discussed in the book such an interesting topic – and no wonder why software design is such a simple topic at first, and yet a complicated matter at the same time.
Finally, this book is the first of a series that is in the works. Kent promised two other books following this one. Let’s wait and see.
Top comments (0)