Have you ever needed to configure a system and come across a setting like this:
<ReloadInterval>72</ReloadInterval>
What do you think this means?
Does this mean reload every 72 milliseconds? Every 72 seconds? Perhaps minutes?
What about days? In 3 days there are 72 hours, so if the 72 is a significant value, perhaps this means every three days?
Perhaps it means reload every 7 minutes, with 2-second retries … and lest you discard this as completely improbable … this is what it would mean for at least one system I’ve had the misfortune to work with. Fortunately, I didn’t get much of it on me.
The crux of the problem here is that the meaning of this number can’t be known by inspection. Instead, it requires reference to information held elsewhere - perhaps in the documentation, perhaps in the source code of the system itself, perhaps in someone’s head.
Let’s look at another example:
Task.Delay(900);
What does the 900 mean here? Is it intended to delay for just under a second, or for 15 minutes?
Again we have a problem where the meaning of the number has to be understood by reference to another source.
The problem here is that a bare int value doesn’t carry enough information. It specifies just a count, nothing more. It doesn’t tell you what is being counted. The difference between a count of milliseconds and a count of hours is significant.
A better approach is to use a semantic type that matches the requirement for a specific duration.
In .NET, TimeSpan
In the .NET world, the type TimeSpan would solve this right out of the box. The required format is straightforward and completely unambiguous.
Revisiting the <ReloadInterval> example from above, 72 seconds is unambiguously specified as a 1 minute and 12 seconds:
<ReloadInterval>0:01:12</ReloadInterval>
Alternatively, we might see 0:00:00.072 for 72ms, or 1:12:00 for 72 minutes. Admittedly, one limitation of TimeSpan is that you can’t write 72 seconds directly, you have to put down 1 minute and 12 seconds instead.
For a 900ms delay in code, as seen in our second example, we could write:
Task.Delay(TimeSpan.FromMilliseconds(900));
Or, if we wanted a 15-minute delay, we could use TimeSpan.FromSeconds(900).
If this looks unwieldy, a couple of trivial extension methods on int would allow you to write 900.Milliseconds() or 900.Seconds() which is even easier to read.
In Go, time
The time package has a convenient time.ParseDuration() func to provide similar functionality for Go developers, with an even nicer text format.
Revisiting the <ReloadInterval> example from above, 72 seconds is unambiguously specified as:
<ReloadInterval>72s</ReloadInterval>
Alternatively, we might see 72ms, or 72m with the obvious meanings.
For a 900ms delay, we could write
Task.Delay(time.ParseDuration("900ms"));
Or, if we wanted a 15-minute delay, we could use time.ParseDuration("900s").
Both of these lack the finesse of the .NET solution, requiring a string parse and its associated overhead every time, but it would be easy to cache the duration somewhere easily accessible.
Conclusion
No matter the language, you can always do better than using a raw int to represent a duration. Either use something built-in or roll your own if you have to.
Long before I ever wrote any Go code and discovered the time package, I had written my own robust parsing library for C# that handled strings like "7s", "60m", and "8m15s" as easy to understand ways to specify a duration. I ported that library from Delphi, so I’ve been applying these ideas for a very long time.
Remember: an int is a poor duration.




Comments
blog comments powered by Disqus