We’re hiring a new Java developer and decided to start by asking them to write code instead of the usual Q&A.
Recently we needed to add an hourly scheduler to our sliding window data aggregator and decided this would be a good test to see how people think and code.
We gave our candidates the following class skeleton to complete. As you can see, it has two parts. A constructor that takes in a variable number of minutes-past-the-hour arguments. And a method that returns the next occurrence given a fixed point in time.
We asked our candidates to compete the code and make all the tests in the main method pass.
Here’s the full listing. How would you implement it?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
import java.util.Date; /** * This class represents a fixed hourly schedule. * * It can tell you the next start time for an event after a given point in * time. * * You first define the minutes past each hour that an event can * occur (for example HH:00, HH:15, HH:30, and HH:45). Then you call * {@link #getNextTime(long)} to find the next occurrence from any point * in time. In the above scenario, passing in 4:23 PM today should return * 4:30 PM today. * */ public class HourlySchedulerTest { /** * Accepts the minutes past each hour that an event can start * (for example 0, 15, 30, and 45). * */ public HourlySchedulerTest(int ... minutesPastHour) { } /** * Returns the next start time from the given point in time. */ public long getNextTime(long fromMillis) { return ; } public static void main(String[] args) { HourlySchedulerTest test = new HourlySchedulerTest(0, 15, 30, 45); final long now = 1426708139391L; // Wed Mar 18 15:48:59 2015 expect(test, now, 1426708800000L); expect(test, now + 900000L, 1426709700000L); expect(test, now + 1800000, 1426710600000L); expect(test, now + 2700000L, 1426711500000L); expect(test, now + 3600000L, 1426712400000L); } private static void expect(HourlySchedulerTest test, long fromMillis, long expectedNextTime) { long actualNextTime = test.getNextTime(fromMillis); if (actualNextTime != expectedNextTime) { System.out.println("Test failed. Expected: " + new Date(expectedNextTime) + " (" + expectedNextTime + "), but found " + new Date(actualNextTime) + " (" + actualNextTime + ")"); } else { System.out.println("Test passed. " + new Date(actualNextTime)); } } } |
Happy coding!
Very close to our implementation 🙂 You can reduce several lines of code by replacing the break statement with a return.
I would implement it as follow:
Nice approach Philippe and your line count is almost on par with ours.
If I had included a real set of unit tests you would have caught an assumption in your code — that all schedules start on the hour. You can see what I mean by changing the input to be 15 and 45 minutes past the hour.
Thanks for being a good sport and sharing your quick answer.
You’re right: i missed it! … Shame on me 🙂
This time, it shoul be ok….
+1 for showing recursion instead of iteration.
I probably wouldn’t do this in prod code because of the overhead in calling methods. I’d also suggest making
minutesList
a field and moving its initialization to the constructor to save time and memory.Just found your site. Here is my first ever entry.
OK, so I don’t know how to post code and there are not any obvious instructions.
No worries. I surrounded your code with the PRE tag and one of the WordPress plugins figured it out.
Thanks for sharing the fewest lines of code so far Tomm 🙂
Just for fun: less lines of code. But I agree, it’s not really readable 🙂
nice 😉
A couple minor tweaks, removed extraneous objects, etc. It doesn’t perform well due to Calendar class calls though.
Okay, no Calendar. This one performs < 300MS for 1M.
Blake – you get points for testing against the 15 and 45 minute cases 🙂
You get more points for removing the Calendar class, our implementation doesn’t use it (or Date) either. That may make our implementations vulnerable to daylight savings time and leap year cases, but I haven’t tested them yet.
BTW, your test takes about 170 milliseconds for 1 million calls on my i7, but I know for a fact you can cut it in half 😉 Hint: do you need to call
Arrays.sort(startTargetsMillisArr);
insidegetNextTime
?Thanks for the feedback, Dele. Here I do a basic sort during the insert. Results in twice the (relative) speed. My metrics are from an i5. The metric is actually like 8 million calls, since each “run” tests the algorithm 8 times, and each algorithm searching either shorter (2) or longer (4) array.
Blake – it looks like you’re modifying one of the member arrays inside
getNextTime
. If you can move this to the constructor, you’d have an thread-safe implementation.I used to ask developers to give advantages of immutable types like String and BigDecimal. Thread-safety was always a good answer 🙂
What about a bit of Java 8 APIs?
Thanks for sharing. I’m a big fan of fluent interfaces, but this one seems hard to read…
Razvan – this is a very sweet use of fluent APIs 🙂 You’d get points for the most readable so far — including against our own — code is for people after all.
BTW, your
minutesToMillis
method should probably return a long instead of int. I’d probably also typecast intValue() to a long instead of creating a java.lang.Long instance, but it’d be very hard to measure the slight performance difference.Thanks for sharing. Cheers.
I’m not sure what happened, but some lines are missing :-P. Here is the complete implementation:
Very tight implementation 🙂
The main difference from ours is we used a loop instead of a binary search.
Thanks for sharing.