In my line of work, either I'm building a new component, or I'm dealing with requirements change. So dealing with the shifting sands of what the system should do is a major concern.
Requirements come and go for me. And losing requirements can be just as disruptive as getting them. Worried about how component X will handle users? Well, we don't ship component X anymore, so any refactoring work you've done is wasted.
I might be the odd one out with requirements changing all the time, but I don't get the choice between good design and fast design. I have to creep forward in my architecture, like I'm fumbling around in the dark, because what my system should do today may not hold until tomorrow.
"In my line of work, either I'm building a new component, or I'm dealing with requirements change. So dealing with the shifting sands of what the system should do is a major concern."
And that is simply the case with certain lines of work.
To help me determine which requirements changes are simply a failure in the requirements process I ask myself:
"If I had shipped feature X a month ago would it have had business value?"
If the answer is no then I'm likely dealing with a legitimate requirements change.
For example:
If I worked in the tax industry and the government changes tax laws then shipping these changes months before would not deliver any business value.
Or if I have to make a requirements change because of an external dependency changing. No extra value.
Sounds like you have a good idea of what I'm on about. Still leaves me searching for a way to deal with my system.
Take your tax-software example. You need to start work before the law is written, but there could be changes in the law that require a rework of business logic. What do you work on? How do you prioritize? And how do you deal with that subsystem that no longer has a reason to exist?
In my domain, technical debt is not really a choice I make. It is something that happens as the system ages. I wish I could get someone to speak to that.
In the case of the tax software there's a big question I have:
Do you have a rules engine already or not?
If you're hodge-podging it all together and all the rules are implicitly defined by the code as it exists you're in a bad spot. Knowing that the rules will change every year your goal isn't to grind out this year's changes really hard for six months (and then even harder for another moth to change the final changes) and then slack off for five months.
Instead you should implement a system such that the specifics of the changes are captured in the rules. Once the new drafts come out you need to look for what all the possible new rule categories are, what additional data needs to be captured, etc. But then once things are finalized it's a matter of tweaking the rules slightly to capture the final wording of the bill.
This may not be something that applies to you, though. What area do you work in? How does the debt pile up without choices being made?
I work in government contracts, so your example of complying with the tax code was oddly relevant.
There are plenty of places that follow along your example: I can build a general solution that will withstand a wide range of changes. This doesn't change the fact that a change could come along that I didn't anticipate. What I would call "debt" is more the result of changes in requirements than choices the team made.
You can still frame dealing with change as classic "technical debt", except the full cost/benefit of each design can't be well known. Instead it looks more like "technical investment"; you try make a design that will pay off, but you don't have a guarantee that it will.
I find myself hedging a lot of my designs, and rarely am I able to justify spending a lot of time up front on any architecture.
Requirements come and go for me. And losing requirements can be just as disruptive as getting them. Worried about how component X will handle users? Well, we don't ship component X anymore, so any refactoring work you've done is wasted.
I might be the odd one out with requirements changing all the time, but I don't get the choice between good design and fast design. I have to creep forward in my architecture, like I'm fumbling around in the dark, because what my system should do today may not hold until tomorrow.