I’m getting around to some of my New Year’s resolutions recently, and I’m afraid this weblog didn’t make the cut.
So this will be my last post on Helpful Tiger.
Don’t worry, I’m not disappearing from the Web. I’m sure I’ll see most of you around.
I’ve enjoyed writing it. I hope you’ve enjoyed reading it.
I’ve been writing code for a command-line input buffer.
Seems a bit odd in this day and age, eh? OS X already has a command line implementation – several, in fact.
But this one’s for my home project, which is a curious combination of Web browser and command line tool.
Per the Windows port, this command line acts a little odd. You can move up and move down in the command history using the up and down arrow keys, but if you modify any of the previous commands, those changes don’t “take”. Only changes to the last command are remembered if you move up and down the history.
Oh, and the current command – the one you’re looking at on the screen at any particular moment – needs to be held in an external buffer controlled by the cross-platform engine.
I have an NSArray of all the previous commands, and logic to copy the proper entry in that array to the buffer if the user moves up and down through the command history, but that last command line makes things a bit more fiddly. If you move up, I have to remember the contents of it, even though I have to fill the external buffer with new contents. But I don’t want to add it to the history, because you haven’t pressed return yet.
I said “fiddly,” not hard. My particular solution was to add it to the history array anyway, for the benefits I get from reusing the code that copies from the array to the buffer. As soon as you move up, we enter this special “extra entry added” mode, which we leave again if you move all the way back down again, or hit return.
So I knew that whenever the current command index didn’t point to the very end, I was in my mode, but I found myself getting a little confused, not able to nail everything down, even though the code itself wasn’t very complex. I knew what I wanted, but the code didn’t look like what I wanted.
The solution (and the point of this long-winded entry) was all about naming. Instead of the logic looking like this:
if(mCurrentCommandIndex < [mCommands count])
I made it look like this:
and exiting the mode, instead of looking like this:
I changed to look like this:
Not rocket science, but it allowed me to see where the code was doing its job, and where it wasn’t, and make the appropriate corrections.
Oh, that, and unit tests.
P.S. Yes, I use PowerPlant-style variable prefixes in my Cocoa code. So sue me.
As I’ve said before, for my small home project, where the most interesting work lies at the intersection of AppKit and a cross-platform C++ engine, I can’t write code the “unit test” way – writing the tests first – because those intersections are precisely what can’t be isolated from the entire application.
But I have changed some habits.
Now, I move the little snippets of logic I’ve written from their organically-grown locations to separate stand-alone functions.
These functions are grouped by purpose in their own files, such as
UTF8 Functions.c or
Geometry Translation Functions.m.
Because they aren’t classes, they need all their context passed in as parameters. This can be a pain in the ass, but it also prevents me from grouping too much functionality together; it would be too tedious to add all the necessary parameters.
It also means that I can access the logic directly from unit tests. I can try out in isolation all the little variations I need to really ensure the code is sound.
This works well for a small, home project. Splitting functionality out into lots of additional files may work less well in large-scale endeavors, where there are already hundreds of files in a project.
Then again, in such huge projects, the data model may be elaborate enough that there are more classes that, without modification, can be tested in isolation from AppKit (or each other).
Writing bugs often makes me more productive.
That, or writing requests for help.
For instance, I have a custom NSView, whose contents, mostly text, are completely laid out by a cross-platform engine, i.e. not by Cocoa. So I can’t use NSTextView.
But I want it to act like an NSTextView. For instance, I want to be able to select text just like an NSTextView, and I want a blinking cursor just like an NSTextView.
So I started writing up a query to the Cocoa-dev mailing list about this. But you don’t get much respect, or much help, if you aren’t as specific about what you need as you can be.
So first, I had to determine what I didn’t know. Which meant trying to implement it, and documenting where I got stuck.
Turns out, I didn’t get stuck, at least for the first part.
How do I get started learning about something new? Well, if I can guess an API name, I’ll start with the documentation, but usually I can’t. So I search http://search.lists.apple.com based on the words I do know, like “selected text color”. If there are a lot of false matches from other frameworks, I’ll restrict the search to Cocoa-dev, but sometimes the answer is, say, a Carbon API, so I’m inclusive at first.
I find that the spare, high-level style of Apple’s developer documentation sometimes leaves me scratching my head. Is this really what I need? The mailing lists are great for this sort of clarification.
So I find out the API I need for the selected text background is the appropriately-named:
And the post that gave me that also pointed me to the “Accessing System Colors” documentation topic, which helpfully mentioned the notification:
which allows me to change the color in my application immediately if the user chooses a different highlight color from System Preferences.
But I wasn’t done because, when an application window is no longer foremost, the selection color changes from the user-choosable highlight color to a gray color.
I was unable to find a specific question about that, but I found another post that talked about matching API colors via the Developer color palette in the color panel. (Cmd-Shift-C in TextEdit.) There isn’t a
nonForemostSelectedTextBackgroundColor system color, but there is a
secondarySelectedControlColor that matches the non-foremost selected text color in TextEdit, and has a name that at least could apply to my situation.
So I have something that works, and gets its information as much from the system as possible, so it’s as future-proof as possible while still being custom. And I didn’t need to ask any questions! Except…
The same routine didn’t get me an answer as to the best, most system-friendly way to show a blinking caret. I could do the whole thing myself, but that might look weird in the radically overhauled UI in Mac OS X 10.9 “Puddy Tat,” eh? And I’d rather not have an NSTextView whose sole function is to show that caret – seems like a fragile, hacky solution.
So I have a question after all.
I was getting a strange smearing effect when I tried to scroll in the main view of my application’s window.
I knew my content-drawing routines were being invoked correctly. I knew that the effect seemed to be happening somewhere in the depths of Cocoa, not in my code. But that’s all I knew.
Turns out, it’s because I was setting my view frames to fractional values (they’re floats, after all), but my content engine was still drawing things per integer coordinates.
This is the kind of thing that unit testing won’t help.
My goal was “make resizing the window and then scrolling through the main view work.” Can’t write a test for that because “work” means “look right,” and you can’t test for that when you don’t know how to make it look right yet.
It’s one part experimenting and one part perseverance and one part lightbulb going off after things go wrong.
And I find myself working through these kinds of issues a lot.
Anyone who says “Always write your tests first” can stick that in their pipe and smoke it.
Doctor: So don’t laugh.
“Legacy” in this case means “anything without unit tests,” which means just about all code out there. Including, I’m ashamed to admit, most of the codebase of the Neutrino project I’m currently working on.
Why, after all that effort I put into adding unit test capabilities to my project, have I mostly failed to follow through? Feathers’ book describes it well. Currently, neither programming languages nor external libraries and frameworks make it easy to separate the unique logic of your code from all the dependencies that it requires to actually get its work done.
My codebase, for example, does a lot of custom drawing to a view, and does that drawing in response to calls from the cross-platform engine that actually drives the process. So I’ve got two huge dependencies: the engine, and the Cocoa framework. How do you get around that?
But it’s not just Neutrino. I prefer to work on code that’s in the middle of complicated systems, doing interesting and complicated things.
The classes in Kent Beck’s Test Driven Development: by Example were small data model classes that dealt only with each other. Well, sure, that would be easy! Real world code is rarely so straightforward. Beck describes a world so far removed from mine it might as well be in another galaxy.
Feathers, on the other hand, gets dirty in the trenches. But he doesn’t reveal any magic formulas. Instead, over and over again, he says: stop laughing. Change the code.
Does the class you want to test rely on a well-protected singleton? Change the singleton so it isn’t, even though that allows others to use it incorrectly.
Does the class you want to test have some private methods? Make them public.
Does the class you want to test rely on other classes from a library or framework? Change your code not to refer to such classes directly, even at the cost of added complexity and overhead, so you can break the dependency and use dummy objects instead for your tests.
All these are ugly solutions, design-wise. And Feathers knows it; he makes multiple apologies for his techniques. But he stresses that they work.
Well-designed code, code that only allows itself to be used in the way it needs to be for production scenarios, turns out to be anathema to unit testing.
When I programmed primarily in C++, I looked askance at the typeless nature of Objective-C. How will the compiler check that you’re doing the right thing? What I’ve found since is that very few errors result from this extra freedom from type that you have in Objective-C. Maybe all those safeguards and extra complexity in C++ weren’t necessary after all?
Similarly, I wonder if the next major programming language might be optimized for unit tests. It will have even fewer compile-time restraints, even fewer security restraints, but many mechanisms to make it easier to test what you’ve just written – maybe even require such tests, or auto-generate such tests.
Until then, I’m going to see what the results are when I make my Neutrino code a lot less jolly.
I have a couple of music files in Ogg Vorbis format, a format that iTunes does not support by default.
Before, I used the Ogg Vorbis QuickTime 6.2 component written by Jordan Mendelson. Notice, however, the “6” in that title. Mac OS X 10.4 “Tiger” uses QuickTime 7. If you come to a Ogg Vorbis song file in your iTunes playlist on 10.4 when you have Jordan’s component installed, iTunes crashes.
Even cooler than that, the above page is really a bit of a developer Weblog, describing some of the steps he’s taken to make the component. If he got himself an RSS feed, I’d subscribe. He even has a teaser: “Watch this space.” Guess Apple isn’t the only one keeping secrets, eh?