Revenge against the Clock
Space-Time Singularity by Stefano Di Chiara
It’d be hard to actually give you a good example about this. Kind of what has always happened recently has been that, somewhere or the other, Time has kept eluding me as a function.
At first, as you know, I had these issues with comparing timestamps in this project because Objective-C’s NSDates are compared in the order of micro-seconds, not seconds. So, if you have two timestamps at 15:24:25 and 15:24:26 and asked the method [NSDate timeIntervalSinceDate:] for a value, you’d expect a return of -1, or at least -1, since the difference between them is that the first is older (smaller) than the latter by a second. Or what’s the same, NSOrderedDescending (I think I got that one right). Problem: at a micro-second level, maybe they’re only separated by -0.7 seconds, or -0.9999919 seconds, but not -1. My solution? Handle the special case where the difference between two NSDates drops below a second.
But how do you handle that special case? Oh, I see. It’s just a simple comparison! Hours need to be greater than the number of minutes, minutes need to be greater than the number of seconds. Not so fast, Coyote.
There’s a trap (pun not intended) here. It turns out, there’s a very common case, happens once in every minute, where actually, the largest date has a number of seconds smaller than the previous one (if we’re going second by second). That’s right, at the turn of every minute, we have a situation like 15:24:59 and 15:25:00 have, where the first is smaller than the second, even though the first’s number of seconds is much larger. Funny, right? Easy to catch, then? I thought so, too. Then it came to mind that this was actually a lot more complicated: what happens at the turn of every hour? Minute 59 is “bigger” than minute 00, but if the latter belongs to a bigger (newer) hour, the first is smaller (older). Right. I hope you’re getting the pattern here, because it also happens at the turn of every day, at the turn of every month, and at the turn of every year. And if you think this is a trivial thing to deal with, think again.
This has been the reason why my tests have not been stable, and the issue is a little bit more complicated to code than you’d think at first. For example, when making something akin to my [NSDate newerThan:] method, you’ll start writing the code, put up a Unit Test, run it, and get all tests to pass on your first try. Congratulations! Now I ask you: “have you tried asking the smaller number whether it’s newer than the newer one?” Think about it: if you’ve coded this pretty quickly, everything will suddenly break down in your mind, just like the sound of a plate mashing into pieces on your mom’s kitchen floor after your girlfriend decides to dump you over WhatsApp (I wish that doesn’t happen, by the way). The issue is, we’re always assuming we’re the bigger number, when of course, that’s not exactly how we want to use the function, since when we call it, we really don’t know which number is bigger than the other, A or B. So then it becomes a complex net of interleaving “if” statements. I actually went a bit around this one and synthesized it to a single working line, although I obviously broke it down to make the code it more readable. If you think about it, in the end, it’s a logic problem, nothing that should really make us lose our sleep to us programmers, but in practice some things turn out to be a lot trickier than what we’d expect.
So that was my main issue. I’ve worked on the project for about 3-4 days you could say. And only in the last two, if today is the fourth, you can really say I’ve put that diabolic succubus that’s been following me throughout 9 weeks of project to rest. What about the other two? Well, after I thought I’d fixed that very same Time bug and cleaned up some of the Standard Engine’s code, I decided I wanted to solve a couple of things regarding our UI. The first thing I did is to try out this app that’s in Beta version and totally free for now, Reveal app.
You will agree with me that it is a beautifully-looking piece of OS X software, and even if it only serves the purpose of allowing you to show-off how your UI is constructed, it helps to sell whatever you’re doing. From what I’ve seen thus far, it’s actually a bit more than just a pretty face: you can update the UI of your Nib in real-time through the app, and the changes will make themselves visible in the Simulator, too. So it’s a very interesting way of tweaking your UI, really. If not for layouts, maybe for tweaking colours, margins, and maybe even looking through your Nib’s hierarchy and making sure you’re not adding more layers than you need: this is something Android is very picky about, and which it will not forgive you for; Android doesn’t do Z-Buffer testing (software or hardware-rendering, no difference) so if you put a View directly above the other, it’ll overdraw. Go and ask Romain if you don’t believe me. He actually spoke about this a couple of weeks ago at Google I/O, too.
Back to our own business. I worked on a problem I didn’t want to have later, which was UITableViewCells capable of holding on their own all of the potential content a Ticket may carry, since until now I haven’t dipped my toes into that area. After all, it would be a heart-breaking moment to see how the Engine fetches content off Twitter and/or Facebook for the first time, to not be able to see that content with my own eyes just because I failed to do this first, right? (Yes, I know I’m kind-of building towards that moment as if it were the last push the Man needed to exit Plato’s Cave for the first time.)
I worked on it; actually days 2 and 3 were a week apart, since both the F-1 Canadian Grand Prix and my other arrangements required their due attention and did not allow me to get back. Apple’s APIs were clearly not made for this, since the same API using different parameters doesn’t yield the desired results. I thought maybe as iOS developers this issue could be solved at the platform level, because it’s clearly something we really need, and thus far I really don’t know if it’s been done or not in the latest release. I’ve seen some WWDC videos, and after I finish publishing this I’ll have to decide whether I watch some more or whether I get back to Lara Croft’s newest adventure, only this time enjoying Tressfx support.
So that works, and I even made my TestSupplier use attributes to write its name in bold, which is obviously work I’ve cut out ahead of when real Suppliers come into town. With this done, a completely different matter started filling my head.
Users. At the moment I’m actually thinking about the three things we need to do to finish work on the Engine: insulate it against Suppliers taking too long or a lost Internet Connection; Engine State-Saving; and one I haven’t mentioned much but that is important, making the Engine track which Tickets are removed and added after every Pool so I can animate those changes with UITableView, instead of bluntly reloading the table. But there’s a fourth: again, Users. Until now, “users” have been a fictionally-generated dictionary of 5 or 6 values, but IRL, with real Suppliers, users might not be part of the data itself, requiring a different download and network-wait time. But that’s not the real problem. The problem is, how to store those Users efficiently?
Ideally, the Supplier wouldn’t download too much of a surplus of Tickets, but even if it does, the issue is although we might need to download user’s information, we don’t know if we should keep it or not: the Engine, for all we know, could cut off all the Tickets where half of the users we just downloaded appear, and if the Supplier keeps all that unused data, we’re being inefficient in our use of memory. It’s true, you can argue that data might be of use on the next Pool, reducing the time required to fill it, and I agree with you, but what I don’t want is to burn too much system power on RAM memory. I can handle requesting the data for the same user again, but we’ve already put a lot of memory pressure with the Track, and it’s not our duty as good developers to increase that pressure: we must find a good balance, and I have chosen, for now, to pay the price with Users. How? Well, in a perfect world, Objective-C would allow me to have a weekly-referenced NSMutableDictionary, which it doesn’t. If it did, I could make the Tickets handle strong pointers to the Users, with a weakly-pointed cache of users in my Supplier, and Pool Cutting would take care of automatically clearing out of the Cache any users I don’t need after the Pool is finished: Pool Cutting would kill the last strong pointer to the Object, and if I make it the key in the Supplier’s NSMutableDictionary, it’d drop. Again, that’s not possible, and it also leaves the lingering question of: “but wait, what would happen in that case is that the key would be a null-pointer; the pair would still be an entry in the NSMutableDictionary”. And if you’ve been keeping the question of: “you’re going to end up burning a lot more power in repeated network-requests for Users you’ve already downloaded than if you keep them in memory”, my answer remains “I know”. It’s my design choice.
Problem in hand, the obvious solution seems to be to “bend” my own Engine-Supplier API so the Supplier is notified of when one of its Tickets has been cut off the Pool and perhaps even the Engine when State-Saving comes on board, but this is something I hoped to manage without modifying any of my APIs, just to prove they’re good as they are right now. So for now, I’ll let it rest, and tackle it on the beginning of next week when, hopefully, I’ll be cleared to resume work on the project.
As for the rest, one of the reasons I wanted to do something UI-wise is to have some interesting pictures to show you, just like I used to in weeks 1-6. Unfortunately, I updated pretty quickly to iOS 7 in my iPhone 4S and Xcode 4.6 wouldn’t detect it, so it’s Xcode 5 for me if I want to push forward, which I will starting next week. I simply wanted to finish this build on 4.6 instead of switching mid-build.
Lingering ideas about WWDC? I’m pretty happy with what Apple is up to with Mavericks, and I really fancy updating my late 2011 17" MBP to the early preview, but I just want to wait a bit before doing so. Those under-the-hood improvements give this release a very Snow-Leopard feel to it, which I absolutely adore, and I love that finally we can go full-screen on more than one screen: that’s something that should’ve happened back with Lion, and, AirPlay should’ve worked they way it will work since Mountain Lion.
As for iOS7, I have very few words. As I’ve said before, I’m not entirely sure this project will see the daylight. On a level, I’m very committed to it, but I don’t know much about what life is going to offer me any day soon. This remains a long-haul project, and as I’ve said many times before, the thing I’m looking most to is finishing pre-production: after that happens, I can unveil more details about what I really had in mind with all of this, and why did I really need to build such an Engine. As for iOS’ upcoming release, it seems pretty certain my project should target it because there isn’t anyway, unless I fully dedicate myself to it, and even then I doubt I’d make it, it’s going to make it before the Fall. Even if it does though, that wouldn’t be a good idea: what everyone has to do right now, is stretch out their arms and fingers, and start coding app revamps for iOS7’s launch, because it’s simply going to be the biggest goldmine-day software has ever seen since the days of the App Store’s debut. This is going to be even bigger: there’ll be a new iPhone next to this new iOS, and even if people don’t get the new iPhone, at least iPhone 5 users will want to update very quickly to the new OS, I can assure you of that (the performance of iOS7 in the 4S will probably not be buttery-smooth).
Please don’t be like me, focus, get your app done, and rake in the benefits.
As a concluding sidenote, I pretty much notice myself this has been a much more livelier post than what I’ve written recently. Coding does have that effect on me, pressuring my brain down to its lowest level at times, where I simply need a break, looking beyond logic and Xcode’s coloured letters, to breathe and think freshly again. Still, I keep writing and publishing even though I’m not feeling up to it because I know it’s important, even if very few people read me, but it does build it all up inside my head, and in someway, I need it.
Hope you’ve enjoyed this post, and I’ll be back next week. See you then!