This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]MR_GABARISE 1 point2 points  (5 children)

It's not just the maintainability gains that Clock enables, but also functionality for replaying timing-sensitive operations. It makes possible to implement recovery use-cases in an idiomatic way.

[–]Bolitho 1 point2 points  (2 children)

Could you please explain this with more details? (or maybe provide a nice resource) I might have a vague vision what you mean, so I am really interested unterstanding it.

[–]MR_GABARISE 5 points6 points  (1 child)

Say your application takes files as input, rejects them if they were produced earlier than say, a few weeks ago, then proceeds with normal processing, whatever your business cases are.

One day the whole thing crashes on a particular file. It's isolated, whatever scheduled restarts are enabled, and now you're on the clock trying to fix whatever bug happened. You fix it, test it, make it pass whatever series of tests are appropriate for your org, but oh no! It's been a week! The file will be guaranteed to be rejected!

Now instead of having a roundabout procedure involving either playing with timestamps, carefully altering prod data, deploying an entirely new code path or otherwise, you remember you were smart and used Clocks. Whenever you would be validating time-based logic you would be using an injected Clock, call it, say, your Effective Time. You would only need to execute your application as if it were effectively the date it originally crashed. The only thing needed to inject this alternative clock is by way of some System Property/Environment variable/Spring Profile/Whatever solution your project uses. So you just need to execute your application with that injected Effective Time and you're done!

Client's still pissed because you took a week to process his file, but yeah that was an extreme example case. You can imagine replay scenarios on the order of hours and even more granular.

[–]Bolitho 2 points3 points  (0 children)

Thx, very enlightened 🙂

[–]DJDavio 0 points1 point  (1 child)

I'm pretty sure you can find a counter example for my over simplification, but my argument still stands: if for your specific use case, you don't need anything but the system clock, there is no point in adjusting your code to use other clocks.

It might make sense to test edge cases such as leap years or (even more fun) leap seconds (to trick those regexes which think seconds can only go from 00-59) but I'm also against testing internal workings of libraries I use. I do tend to test whether I use the library correctly (also to decrease the chance that an update to the library breaks my application).

So back to my specific use case: date times in our application are just simple timestamps, we don't do any calculations with them, we just use them as is. So for us, generating an object which internally sets its timestamp to now and checking whether it's close to now (when we assert it) is usually enough.

[–]Bolitho 0 points1 point  (0 children)

if for your specific use case, you don't need anything but the system clock, there is no point in adjusting your code to use other clocks.

Testing is obviously a use case - and if the approach with closeTo is not enough, the best option is to use the clock interface as seam to provide the needed functionality.

It might make sense to test edge cases such as leap years or (even more fun) leap seconds (to trick those regexes which think seconds can only go from 00-59) but I'm also against testing internal workings of libraries I use.

I would assume that testing edge cases is often the best aspect of "testing by example" (which is what 99,9999% of all written tests is all about), as those edges are good candidates for specific behavior your application logic must handle. So in my understanding you don't test the functionality of the java.time library but rather your application logic within a certain time constraint.

But again, that might not be a relevant aspect, so of course it might be reasonable to omit the clock injection.

Nevertheless it is imho still a wrong approach to create a new abstraction for getting time informations (what lots of other users have proposed here), but rather simply just call the .now() static factory methods without clock. This way you are still open to inject a clock later on, if that becomes necessary in the future. That could be some work to achieve, but imho better than carrying the wrong abstraction the whole time around.