October 16, 2009, 1:57 pm
I’m doing something in Java at work. This is perhaps a greater surprise to me than to anyone else, as up until now I didn’t think I knew Java. It turns out to be much easier for me to understand now than last time I peeked at it, perhaps from what I’ve been doing in Objective-C.
In any case, I was asking a friend of mine whether Java can do multi-line string literals รก la Perl/Ruby/Bash/etc:
string = <<END
This is the first line.
This is the second line
END
The answer, apparently, is no. So, there I was about to go accept this syntax:
private static String string = "This is the first line.\n" +
"This is the second line.";
when my friend mentioned that StringBuilder is much more memory efficient than String. This was counter-intuitive to me, particularly as I would expect a non-mutable string to be more memory compact than a mutable string. Don’t know why, that’s just what I assume.
Then he pointed out that each “something” instantiates a new String class. So, my “thing” + “thing” turns out be something more like this at the compiler:
string = new String(new String("This is the first line.\n") + new String("This is the second line."));
That’s not exactly true, as after more investigation it turns out that the compiler would probably see those as string literals and inject them as constants into my class file. This is what I’d expect, really, coming from an Objective-C world. That’s still less memory efficient than I want, though.
My work project is tiny, so the impact of this is negligible. I really want to start out on the right foot, though, memory management-wise. I’ve been in the situation of inheriting projects that started simply, then became bloated and stupid as they passed from hand to hand. So, I want to start this the right way.
My bigger question is how Objective-C really handles strings at the compiler. Does this have implications for how NSStrings should be concatenated or built with formats? If that’s the case, then I should look at every for loop in my code.
October 13, 2009, 8:27 am
Well, I’m stuck at BART waiting 40 minutes for the next shuttle bus (barely missed the last one), huddling under a concrete overhang to hide from the rain. This is where my commute is awesome!
Anyways, I discovered some neat aspects of search the other day… Let’s say that you have a search query and you want to refine the results by tags or filters.
If you have multiple options for one type of tag, then those form an OR relationship. Different types of tags form an AND. So:
WHERE search LIKE "%x%" AND
(type_1 = xx OR type_2 = yy) AND
(category_1 = xy OR category_2 = xxyy)
Makes sense.
The problem starts when you try to generate counts for each tag, particularly if you want those counts to update on the fly. At that point, your relationships change. For each tag, you need a separate query that pulls its section out and compares it to the combination of the items in the other section. So:
WHERE search LIKE "%x%" AND type_1 = xx AND (category_1 = xy OR category_2 = xxyy)
...
WHERE search LIKE "%x%" AND type_2 = yy AND (category_1 = xy OR category_2 = xxyy)
...
WHERE search LIKE "%x%" AND category_1 = xx AND (type_1 = xx OR type_2 = yy)
...
WHERE search LIKE "%x%" AND category_2 = xxyy AND (type_1 = xx OR type_2 = yy)
This of course gets really expensive really fast, as you have to run a separate query for each tag. At this point you would have to optimize the hell out of everything you could possibly optimize, cache as much as you can cache, work on your indexes and beef up your server. Even then you’d probably want to performance test this as heavily as you can to see where the weak points are in your deployment. This is a scaling nightmare waiting to happen.
BUT it works. And it’s kind of cool.
It’s also cool that I can blog from my phone in the rain at a BART station. Cool. Yeah, that’s the word for it.
October 2, 2009, 2:13 pm
I have not been testing my controllers. It’s terrible. Part of this has been because I only managed to get OCUnit to work in my project about a month and a half ago, and in the intervening span of time I was fighting to get it to work with a CoreData dependency. The other part of it is that I really haven’t known how to test my controllers.
[This is where I really should have started TDD four months ago and not done any coding without it.]
So my problem is that I have a main controller that does a lot. I mean a LOT. It’s in charge of knowing when location services are enabled. It downloads records from my server and inserts them into my database. It keeps track of which records are in memory (being an NSFetchedResultsController delegate). And I don’t have any tests written against it. It’s really starting to get scary, as I look at the features I still need to implement.
The issue I’ve been facing has been that the code that I want to start writing tests around is dependent upon NSURLConnection: when it gets word from its location manager that locations are enabled, it fires off a GET to my server. It all works in theory, but already I’m realizing that I would have found problems earlier and isolated my bugs when coding them if I’d been writing tests to prove the desired behavior. It’s completely dependent upon a foreign class in order to function, however.
This is where dependency injection comes in. I was searching for a way to hijack the NSURLConnection framework with OCMock, but kept coming back to the fact that I was creating my connection deep in the middle of code that had other external dependencies. So I was getting really confused. Thankfully I stumbled upon this Wikipedia link.
If I rewrote my code so that I could pass in the connection object only when it was required, I could then test the subsequent code with a mock object and not have to worry about testing my external dependencies.
So this:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
// do stuff
[self downloadCoordinate:newLocation];
}
- (void)downloadCoordinate:(CLLocation *)location {
// context context init and observation to process records
NSURLRequest *request = // setup request
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:request delegate:self];
if (connection) {
// set up NSMutableData for received data
}
}
Becomes this:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
// do stuff
NSURLRequest *request = // setup request
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:request delegate:self startImmediately:NO];
[self downloadCoordinate:newLocation];
}
- (void)downloadCoordinate:(CLLocation *)location
connection:(NSURLConnection *)connection {
// context context init and observation to process records
if (connection) {
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[connection start];
// set up NSMutableData for received data
}
}
Now I can write a test that calls the download method directly, and I can pass in a mocked object to fake the request. That’s dependency injection: you write your code so that you can inject foreign dependencies from outside, so that your code doesn’t become internally dependent upon an external resource.
Note that I had to add the connection to the run loop schedule. This was because it was throwing an exception if I just called start without it. I’m not exactly sure what’s going on behind the scenes, but apparently if you initialize the connection with startImmediately:NO it doesn’t add it to the current run loop?
Now I just need to figure out how to mock up an NSURLConnection so that I can run the tests. Sigh.