the expenditure of significant extra effort in an attempt to ease the accommodation of possible future requirements is nothing more than gambling.
That's why several people have noted that they aren't talking about "significant extra effort".
I've found that my predictions for possible future requirements have been significantly accurate (that's part of my job, ya know?). But, even if I'm almost certain that feature X will be required in the near future, if supporting feature X introduces even moderate extra effort or extra complexity, then I (usually) put aside supporting that feature, mentioning "you're not going to need it".
Just because you've been seriously burned by somebody who was bad at predicting future directions and even worse at recognizing costs doesn't mean we all have to be pathologically opposed to venturing even a little bit toward that side of the scale.
I am pretty quick to resort to "you're not going to need it", when the predicted need seems other than very likely, when the support for that need is starting to add even moderate additional complexity or looks to require even moderate additional effort, when the understanding of what the predicted future need likely really means seems even a little fuzzy, or even when the discussion of the need or how to support it has gone on too long or even just doesn't appear to be progressing particularly fast.
But I don't immediately shut down considerations of potential future changes with Draconian proclamations to strictly only consider present business requirements.
And it isn't just predicting specific future needs. It is giving the design the benefit of becoming clearer and cleaner so that it is more resilient to be modified even when how it might be modified has not been predicted in any specific way.
Bouncing potential future needs off an emerging design in order to gauge how easily it might accommodate them can be quite useful in discovering more natural boundaries between components, producing more modular pieces with more logically cohesive functionality such that each piece is less likely to require changes in future.
When solving a complex programming problem, my most common first step is to identify some subset of the problem that makes sense to separate out as an isolated module. When that process produces something with an obvious and clear name and logically tightly cohesive functionality where the subroutine names are obvious and clear, then I'm unlikely to spend much time futzing with that design and I can just factor that part out of the larger problem and continue working on what is left.
More often, the first choice of what to separate out isn't such an obvious "win". So I'll bat around different names trying to find the clear logical entity. But I'll also throw potential alternate uses other than the current requirements and this usually quickly leads to selecting different subsets of features and aids in figuring out a subset that isn't overly driven by the current specific mandated approach to the larger problem.
If given a business requirement to bill customers for "minutes used", specifically rounding up to the next nearest whole minute for each call, it can certainly be far from a waste of time to consider the possibility that the currently mandated rounding method might change. If your initial approach to meeting the given requirement can't handle that, then you might have come up with a rather fragile implementation. For example, you might opt to just store the pre-rounded number of minutes and nothing more. It might be worth considering an alternative like storing the call start time and the call end time.
If you start dreaming up the business wanting to bill in milliseconds, realize the database only stores date-times accurate to one second, and start designing how you can use proprietary high-resolution timer features to get more accurate start/end times and then debating exactly how you should store these high-res times in the DB... then somebody needs to smack you with "you're not going to need it".
There are tons of not-very-specific uses that are easy to predict as "likely to be wanted in future" of having fairly accurate start and end times of phone calls recorded. Since you demand examples: You might want to provide Operations with a graph of how many calls came in over the last 5 minutes so that they can monitor system activity, even though that wasn't handed to you as a specific business feature requirement for this work. I have actually previously predicted that need and seen it come true. I have almost never been given a business requirement to store accurate call start/end times. Stand in utter amazement at my astounding psychic abilities. ;)
It might also be worth considering that the business might want to charge per call (not just per minute), per phone number allocation, and/or per phone number assignment per month, even though the business has not even mentioned those possibilities to you. You certainly shouldn't start building a separate system for handling billing per call just in case the business will eventually want that. But you might decide to build the system for billing per minute in a different way such that it will likely be significantly easier to add support for billing per call to it. The mere effort of considering these alternate billing scenarios (that are easy to predict the business wanting in future because they are all quite common requirements for other businesses in the industry!) might lead to insights that actually simplify the design of the billing system, breaking it into more modular pieces that are easy to test and actually reduces the time required to build the initial version.
A recent project required the addition of a "maximum pool size" option to each customer's account. Most similar options were just database columns directly in the "customer account" table in the database. Some other options were columns in a "customer options" table in the database. We considered those two approaches to solving this new business requirement.
We also had the foolhardiness to consider predicting future business needs. We predicted that this would not be the last time that the business required a new option be added to customers' accounts! This led us to consider creating a table of option names and another table with a primary key of customer account_number + option_name and an additional text field to store the option value. Creating the two extra tables certainly added some minor extra complexity / effort. But, and I know this is just very hard to believe, we actually ended up needing three new account options before we had even finished that specific, small project! Our prediction came true again!
On another project, we were working on cleaning up some designs around how we make changes to data in our database. We have a lot of custom bulk database manipulations that we end up writing for customers and these custom modifications need to honor the existing business rules. The existing business rules were mostly implemented rather simply and quite directly in the specific places where the rules mattered for the current implemented features. In predicting future business needs, we figured that new features would be required that still needed to obey existing business rules and so it might be a good idea to try to factor out the data-related business rules into modules that could then be used by the ad-hoc customer bulk operations that get implemented and also by the existing standard interface features.
We ended up with several classes whose objects represent things like "a campaign" each of which is mostly a record from the database along with zero or more closely related other records from the database (similar to part of what an ORM provides but not using anything that would qualify as a general-purpose ORM).
We agreed that we wanted the handle to the database not stored in such an object. That way only the few methods that actually interacted with the database would be clear because those methods would require that a handle to the database be passed in to them.
Then we considered the possible future use case of copying something like "a campaign" from one database instance to another database instance. This presented an interesting challenge to the design as each object had knowledge of what parts of the in-memory object state were already in the database so that the changes could be "flushed" to the database either as an "insert" or an "update" or neither (because the item already matched what was in the DB) yet you could, in theory, pass a different DB handle in and the save would then be done "all wrong".
This led one team member to propose a minor feature that attempted to address this theoretical problem in a small way. I ended up strongly rejecting that feature idea because 1) we had never yet written code to copy such a logical entity from one DB instance to another, 2) wanting to do such in the near future seemed only moderately likely, 3) the feature added a moderate amount of complexity and effort to be implemented, 4) the feature didn't seem to really solve the proposed problem fully, 5) figuring out how to address the problem well seemed like it would require significant contemplation and complexity.
I am actually capable of realizing when a prediction of the future is problematic in lots of ways and in teaching others how to do so. I don't need any dogmatic rules about never trying to predict the future.
So I rejected that particular feature idea. But I am still allowing at least my subconscious to contemplate whether the fragility of our class design in the face of such a theoretical need represents a real problem in the abstraction chosen. The abstraction seemed quite clear and simple. But in just writing this up and thus indirectly contemplating that problem, I feel a better abstraction already half-way formed that I suspect will actually simplify the design even further while also making it much more robust in the face of multiple database instances.
It doesn't appear that that (hoped for) design improvement would ever have occurred to any of us had we not contemplated predicting future feature needs that had never been asked for and that even seemed rather far-fetched. We weren't even able to come up with a likely use-case for the feature until many days after it was proposed.
Now that the design is starting to come together in the back of my mind, I'm also already seeing a lot of potential uses for things that it seems likely to enable that had not been asked for before but that will have real benefits in the face of likely future scenarios similar to past scenarios we've run into many times and had to solve in much more difficult ways.
Trying to predict the future has been very beneficial to me over the years. Yes, I've seen people who really sucked at it and tended to get sucked into it and wasted lots of time as a result. I avoid wasting much time on it but not by refusing to ever do it. On the contrary, I consider it an important step when designing and almost always spend small amounts of time on it and have repeatedly found significant benefits from it.