-
How to work around problems with Xcode SCM and svn+ssh
I use source control religiously, even for my own stupid projects at home. To this end, I run a SVN server on an old Quicksilver G4 tower that I use as my file server. Now that I am getting proficient enough with Xcode to do some damage, I decided to set up my SVN repo so I can manage my source while I work. Xcode’s SCM support is missing a few features and can thus be characterized as “modest” when compared with similar tools like Subversive in Eclipse, but it’s still a welcome addition to what I have come to regard as a generally-excellent IDE.
I run connectivity with my home SVN server over svn+ssh using transparent authentication. Unfortunately, Xcode doesn’t seem to handle svn+ssh connections the way you might expect them to. Worst of all, if you don’t set things up the way Xcode wants, it half-works, which is really f***ing confusing. Fear not, however – by operating somewhat abnormally, you can get it to work.
The default svn+ssh case
I have a server called zaphod that acts as my SVN host. My SVN repo on zaphod is stored in the path /Users/porgesm/Documents/code/svn-repos. My user account on this machine is porgesm, and my user account on my local machine is mporges. To enable transparent authentication, I have a SSH config file that looks like this.Host zaphod Hostname zaphod.local Compression yes User porgesm
zaphod.local uses networking magic to find the IP of the machine named zaphod in my network when I am at home. With this config, I can use SVN from the command line as follows. Note that all I need to enter for the server info is “zaphod”, and my ssh config file expands this appropriately to use any and all config settings I have defined for the host aliased zaphod in the config file.
maxbookpro:~ mporges$ svn list svn+ssh://zaphod/Users/porgesm/Documents/code/svn-repos CommonLib/ FacePlant/ HibernateMavenProject/ MavenReleasePlugin/ Pudding/ SampleMavenProject/ SomeAPI/ StrikeTracker2.0/ SvnCpp/ cxf/
This all works beautifully… unless you are in Xcode.
Xcode brings the FUBAR
So in Xcode (v3.1.4 – I don’t have another version to test with), my first (and incorrect) attempt to set up my SVN repo was as follows. Note the grayed-out label at the bottom where it says “Host Offline” – this is a very important detail that I missed at first.
Basically, the configuration pictured will let you browse and modify the repository from the Repositories window without issue, but if you try to compare, commit, update, or anything else from your project, all those options are grayed out in the menus and changed files don’t appear in the “SCM Results” tab of your workspace. This is the “half-works” situation I was talking about, which was confusing as hell.
At first, I thought Xcode was just broken. Since I also run a generic SVN service on zaphod, I tried setting up a repository using svn://zaphod.local as the URL, and it worked fine. So I figured there had to be something about the way I was defining my svn+ssh URL that Xcode doesn’t like, even though that URL works perfectly from the command line.
Xcode un-FUBAR’d
The solution is to expand the details of your SSH configuration in to the svn+ssh URL that you enter in to Xcode, and to enter your SSH account password for Xcode to use. Stupid, I know, but this is the only solution I could find that works. You would think that Xcode would hand off to the native SVN client the same way that Subclipse does for things like this, but that would be wishful thinking.
Once you enter all your details, you will get an “Authenticated” message at the bottom of the screen, and all the options that you expect to be able to use in Xcode will magically start working as expected.
And now, the caveat
Of course, there is a caveat to this workaround. Using my SSH config file, I can use the alias zaphod to access my server from anywhere on the Internet by changing the server address in my config file from zaphod.local to my dynamic DNS server and configuring the obfuscated SSH port number that I use. This is useful for when I am not at home, since I like to use SSH to log in to zaphod remotely from coffee shops and hotels to tunnel various services that the server runs (such as iTunes sharing, AFP for mounting remote directories, VNC, etc.).By explicitly specifying the server address in Xcode as in the solution above, I now have to keep the Xcode SCM repository details up to date with my SSH config file. This defeats the purpose of the SSH config file, which is to store all your SSH settings in one place for SSH to find and use. Suckage.
The best solution I can think of for this stupidity is to set up an SSH tunnel on a local port, and configure Xcode to point to that port on localhost. The downside of this is that I can’t use SCM with Xcode at home without having my tunnel lit up; but at least I’ll know that my SSH settings are all maintained in one place instead of scattered around various files.
To set up what I am describing, I would configure my SSH entry for zaphod as follows. The LocalForward entry causes SSH to tunnel port 3690 on my local machine to port 3690 on zaphod.local, which is where the standard SVN service runs. Note that the LocalForward is always set up from the perspective of the SSH host; in this case, my G4 tower in my local network. It’s basically just looping back to itself in the config file shown below.
Host zaphod Hostname servername.dynamic-dns-server-provider.com Port [obfuscated port number] Compression yes User porgesm #svn loopback for Xcode SVN LocalForward 3690 zaphod.local:3690I can then light up this tunnel with the command ssh zaphod in Terminal; the tunnel stays lit up as long as I have network connectivity and my Terminal session stays open. I would then use the SVN URL svn://localhost:3690 in Xcode to ride the tunnel securely across the Internet and access the SVN service on zaphod as if I was at home, as shown in the picture below. Note that when you go this route, there’s no need to provide authentication details since the SSH tunnel has already authorized me and I haven’t set up my svn:// service to require authentication. If I had set up the svn:// service to require authentication, I could enter my credentials in the fields provided in Xcode.

I filed this as a bug with Apple (#7646524), so hopefully they will fix it in a future release.
-
Adding Headers and External Libraries to Xcode Projects
I come from the Java world. In the Java world, when you want to add a library to a project you just add a JAR to the classpath and you are good to go. With a little extra work, you can whip up an Ant script with Ivy or a Maven build, and suddenly anybody can download your project and build it and, like magic, that whole library dependency thing is taken care of as your project’s dependent libraries fly in across the wonderful intarwebs and expose their soft nougat innards to the compiler and runtime for linking.
After a week of messing with Xcode and C++ libraries, I’ve come to one conclusion: managing dependencies in platform-dependent environments is a big pain in the ass. I guess that’s the trade-off for blazing speed. But I digress; this post is about adding said libraries to projects in Xcode, not complaining about dependency management.
Before reading this post, please note that I literally have a week of experience with Xcode; I am by no means an expert. However, I didn’t find much material on the web for including external libraries, so I’m sharing what I have gathered so far and seen working for the benefit of other newbies. If you are an experienced Mac/Xcode developer, please correct me on any incorrect statements/assumptions in the comments.
Compiling In External Library Support with Header Files
When it comes to using external libraries in your project, Xcode actually does a fine job in helping you – but the documentation isn’t particularly up-front about how to set this up. If you Get Info on your project, there’s a build setting called Header Search Paths that lets you set search paths for headers, allowing the compiler to find them. Note that you can set separate paths for the Debug and Release builds, so if you want to put the same settings in all your builds, make sure you select All Configurations in the drop-down at the top of the build window before you enter any header paths.On the project I am working on, I have copied in the source and headers for the SvnCpp library that is part of the RapidSVN project since I don’t want other people that download my project to have to deal with doing this. I put these under the project folder along with the Apache Portable Runtime (apr) and Subversion (svn) headers that SvnCpp depends on using a project structure like this.
/MyProject /apr ...headers for apr... /svn ...headers for svn... /svncpp ...source for svncpp... /svncpp ...headers for svncpp...Since these directories are nestled under my project root, I can now set the Header Search Paths as follows:
${SOURCE_ROOT}/apr ${SOURCE_ROOT}/svncpp
SOURCE_ROOT is a variable that Xcode exposes to its build environment, referencing the root of the project wherever it may be. This is expanded for you at compile time by Xcode under the hood. For a complete list of build variables, check out Apple’s documentation in the Xcode Build Settings Reference.
Note that I have two folders called svncpp with one nested in the other. This is becuase all the source in SvnCpp references header file includes using the statement #include “svncpp/header_file_name.h”. By setting the top-level svncpp folder as a header search path with the recursive option turned on, Xcode uses this path as the root of the search and can reference the relative path to the headers in a way that agrees with these #include statements.
Finally, what about the svn path? Well, the Subversion headers are referenced in the SvnCpp source using statements like #include “svn_client.h”. To get this to work, I simply made a group in the Xcode project containing references to all the headers in the svn directory. I set the Path Type to these header files to Relative to Enclosing Group so the file names appear in the compiler path as just their file names, which matches the expectations in the source code.
Including Libraries for Linking
So, that covers the headers; what about the libraries containing the object code that these headers reference?As it turns out, the dylibs for SVN and APR are in the Mac SDKs under /Developer/SDKs/MacOSX[version].sdk/usr/lib/, such as libapr-1.0.2.7.dylib. To include these in my project and allow Xcode to find them for linking, I simply located these dylibs on the file system and dragged them in to the Link Binary With Libraries step under my target. Xcode pulls them in to the project automatically under the Path Type Relative to Current SDK, which I like because it means that I should be able to distribute my build and anybody with the Mac SDK on their system should be able to use it. The SDK provides symbolic link abstractions, presumably so that you can link to a general version of a library (such as libsvn_client-1.dylib) instead of a specific version (such as libsvn_client-1.0.0.0.dylib). Honestly, I haven’t had enough experience with OS X development to comment on best practices in this area, but it seems to follow the “wildcard” conventions available in Maven to link to a major version of a library’s API without specifying the exact point release, which lends more flexibility so long as the developers of the library have adhered to a standard for API compatibility within major version numbers.
Anecdotally, the SVN and APR libraries that I have linked to in my SDK are accompanied by matching header files under /Developer/SDKs/MacOSX[version].sdk/usr/include, so it really would have made more sense for me to link to these SDK headers than to copy the header files in to my project. However, I was experimenting with adding headers to my projects, so I wanted to see how to do it the brute-force way first. I don’t think the compiler is going to complain so long as the headers you compile against match the binaries you link against.
-
iPad, You Pad, We All Pad For iPad
The name’s pretty awful. But besides that, I kind of like this new device.
Kicking about the house, I like to go on the Internet to read RSS feeds, watch YouTube, play a game, etc. while cooking or half-watching a TV show. A laptop is too clumsy and fragile for these tasks (I’m always scared to spill liquids on the keyboard when reading recipes off the web). So, I’ve been doing these things a lot recently on my iPhone. But the iPhone’s a bit small and the battery dies pretty fast under intense use. So the iPad’s a perfect replacement for around-the-house computing.
When we travel, there’s a few things for which I like to bring a laptop along: music, movies, occasional Internet use (to find a hotel, restaurant, attraction, or map to somewhere), and to offload photos and video from the digital camera/camcorder. But taking a laptop on a trip along with its case and charger is a pain in the ass, and then you have to either have an air card for Internet access, find a wireless hotspot, or pay for in-hotel service. Sure, the iPhone can get the job done for most of these needs – but it’s not ideal. So if you gave me a big iPhone and threw in a nice e-reader, a mobile bookstore, and a reasonable data plan, then I’d say the travel computer problem is solved. And compared to my 7-lb laptop, it’s a lot less to carry if I want to take it with me.
I spend a fair amount of time presenting stuff at work to execs/peers/users, running to meetings to take notes, and checking email/surfing the web between these activities. Unplugging my laptop from my workstation and running around with it is painful; especially between office suites since I don’t want to shut the lid and put it to sleep, but I can’t sling it under my arm if the lid’s open. So once again, the iPhone has been doing double-duty as a note taker and email browser. But again, it’s a bit small – especially for taking notes and presenting diagrams and Keynote presentations. So there’s another fit for the iPad: a secondary device on my work desktop, acting as a digital picture frame and music player until I’m ready to whip it up of its dock to take around the office for some brief mobile chore.
There’s a few things I don’t like about the iPad. It doesn’t appear to have the ability to annotate documents (at least not yet). Like the iPhone, it seems to be similarly crippled in to having no arbitrary local storage. A camera on the front would have been nice for video conferencing or sending video postcards. A smart media card slot would make a lot of sense. Charging $130 extra for 3G seems like a bit much.
But then I have to put things in perspective. Most of the things I’d store on the iPad have apps that do the storage for me. I almost never video-conference on the other three computers that I own, all of which have video cameras. And is it really that pricey in the big scheme of things? The entry-level iPad with 3G service is $629, which is about $30 more than an out-of-contract iPhone 3GS – and you get a lot more computer for $30 than you do with an iPhone.
So pretty much the only thing it’s lacking is document annotation, which is a software thing. I’d really like to see Apple add this, and if not, there’s an app that does it for me. And if Apple fulfills some rumors out there to store my iTunes library in the cloud for me, then the small amount of flash storage in the entry-level model becomes no problem at all.
So while I won’t be rushing out to buy an iPad, I can definitely see one somewhere in my future.
-
Using AppleScript to Position iChat Windows
We use instant messaging quite a bit at Highwinds. I bounce back and forth between using my laptop by itself, and using it with a secondary 22″ display. Regardless of how I’m using my laptop, I like my iChat windows to fill the laptop screen with about a 3-pixel gap between each of them. This means that when I’m on my laptop alone, its screen gets filled when I Apple-Tab to iChat, and when I’m on a two-monitor setup, the larger attached monitor display is free of chat windows and they are all present on my laptop screen so I can work while watching for chats.
My AIM and GMail buddy lists are about the same length, so I like to stack them on top of each other with half of the screen height given to each. My Highwinds buddy list is the longest, so that gets a full column to itself to the right of my AIM/GMail lists. Finally, I have my chat window occupying the rest of the right-hand side of the display. You can see this in the image below (some screen names have been obscured to protect the innocent).
Unfortunately, Apple hasn’t programmed OS X to remember the position of windows between laptop-only and display-attached configurations, which means I always have to manually move my chat windows back to the second display after I reconnect it to my laptop. This is a pain in the ass. I finally got a few minutes to write an AppleScript to do this for me automatically, presented below.
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
-- Get display area tell application "Finder" set displayAreaDimensions to bounds of window of desktop set widthOfDisplayArea to item 3 of displayAreaDimensions set heightOfDisplayArea to item 4 of displayAreaDimensions end tell tell application "System Events" to tell process "Dock" set dockDimensions to size in list 1 set heightOfDock to item 2 of dockDimensions end tell -- Set up desired coordinates when running iChat on the laptop monitor at 1440x900 set maximumChatWindowHeight to (heightOfDisplayArea - heightOfDock) set chatWindowWidth to 275 set padding to 3 set heightOfMenuBar to 22 set laptopPhysicalDisplayWidth to 1440 set aimCoordinates to [0, 0, chatWindowWidth, (maximumChatWindowHeight / 2) - heightOfMenuBar] set gmailCoordinates to [0, (item 4 of aimCoordinates) + (heightOfMenuBar + padding), chatWindowWidth, maximumChatWindowHeight] set highwindsCoordinates to [chatWindowWidth + padding, 0, (chatWindowWidth * 2) + padding, maximumChatWindowHeight] set chatWindowCoordinates to [(chatWindowWidth * 2) + (padding * 2), 0, laptopPhysicalDisplayWidth, maximumChatWindowHeight] -- Shift everything over by laptop display width if using a second monitor if widthOfDisplayArea is greater than laptopPhysicalDisplayWidth then set widthOfSecondaryDisplay to (widthOfDisplayArea - laptopPhysicalDisplayWidth) repeat with currentDimensions in [aimCoordinates, gmailCoordinates, highwindsCoordinates, chatWindowCoordinates] repeat with itemPosition in [1, 3] set item itemPosition of currentDimensions to ((item itemPosition of currentDimensions) + widthOfSecondaryDisplay) end repeat end repeat end if -- Position chat windows tell application "iChat" set bounds of window "AIM Buddy List" to aimCoordinates set bounds of window "myGoogleTalkAddress@gmail.com" to gmailCoordinates set bounds of window "myWorkEmailAddress@highwinds.com" to highwindsCoordinates set bounds of windows whose name contains "Chats" to chatWindowCoordinates end tell
The script is pretty simple. It grabs the screen and dock dimensions, and sets up some global variables. Then, for each of my buddy lists (AIM, GMail, and Highwinds) it sets up 4-coordinate position arrays describing the [top left x, top left y, bottom right x, bottom right y] coordinates that I want each window to end up in. Next, it checks the total display area: if the area is greater than the width of my physical laptop display, it bumps all the X coordinates over by the width of the secondary display so that the windows end up on my laptop display (since I position my laptop to the right of my secondary display). Finally, it tells iChat to position the windows, referencing each by their title bar. I group all my chats in to a single window, so the title of this window is something like “18 Chats”; as a result, I use a query-like expression to reference this window’s title.
Rather than dynamically setting the position of your chat windows, if you would prefer to move your chat windows to the positions that you want them in and have your Mac tell you what the coordinates are, you can use the script below. You can then hard-code these coordinates in to the coordinate arrays in the script above.
1 2 3 4 5 6 7 8 9 10 11 12
tell application "iChat" activate set allChatWindows to every window repeat with currentWindow in allChatWindows set windowBounds to the bounds of currentWindow set allBounds to "" repeat with bound in windowBounds set allBounds to (allBounds & bound & ",") end repeat display dialog (name of currentWindow & ": " & allBounds) end repeat end tell
-
An Objective-C Tutorial for Enterprise Java Programmers
As a programmer, the lingua franca for computers and I is mainly Java. And although I have no real work-related purpose for it, I’ve always had a hankering to learn Objective-C and OS X development.
And so, over the years, I’ve acquired a handful of really nice books on Objective-C and OS X programming that generous relatives have bought for me as gifts from my Amazon wish list, including Aaron Hillegass’s Cocoa Programming for Mac OS X and Beginning Mac OS X Programming from Wiley. But after a handful of evening coding sessions, I’ve never been able to stick with it long enough to learn it, and every time I return to an old project I find that I’ve forgotten most of what I learned and have to start over at the early chapters again.
Last night, I finally figured out why this is the case when I decided to give OS X development another try. All the books I have dive in and say: “Let’s build a program with a GUI!” And then I’m bouncing around between Xcode and Interface Builder, and I’m doing drag-and-drop UI building, and I’m hooking up selectors to class methods, and it’s totally alien from anything I’ve ever done before.
The reason this is so alien to me is that I’m an enterprise Java programmer with years of experience writing web and desktop apps through code, with the IDE as a participant rather than the full-blown means. The last time I used a drag-and-drop editor to build a GUI was when I was forced to take a VB6 class in college; even in my programming salad days, I thought that a “program that builds a program” was way too far from the metal. I’ve got a solid foundation in ground-up MVC principles, and I never, ever start building an application GUI-first nor use drag-and-drop GUI builders.
When building something in Java, what I do is code the core business logic of the app, write unit tests, and then hook the GUI in to it last once I know everything at the core is working perfectly. If I could just apply this pattern to development of an Objective-C project, I knew I would have a chance of actually retaining what I had learned. I know that the way things are done with OS X is to use Interface Builder and hook up the GUI to the classes visually (and that this is one of the things that makes it a rapid development environment), but for me it was just the wrong place to start.
So, I decided to try building a test-only GUI-less app last night, and I had some success. I’d like to share what I did with other Java developers in case it can help them too. This won’t be a tutorial as much as a post with a bunch of links to other tutorials that helped me accomplish my goal along with notes about using Objective-C and Xcode that were helpful to somebody familiar with Eclipse. If you like, you can download the project that I put together for reference.
Getting Started
I’ll assume that if you are reading this, you (a) have a Mac and (b) have installed Xcode. If not, go and do these things now. Go ahead, I’ll wait.
As I usually advise programmers learning JUnit to build the world’s simplest calculator application, I decided to apply this same principle to what I was doing. So that’s what I’ll be telling you about; riveting, I know…
Making Xcode Livable
Having worked in Eclipse so long, I’m used to having code completion on by default, all my editing happening in a single window, strong support for custom code formatting, and many other things that just seem like good plain common sense.
Xcode in its default state appears to have none of this, and is really frustrating to use when you first dive in if you are familiar with Eclipse. Have no fear, though – these features are mostly there and just need to be turned on. before you do anything with Xcode, I suggest that you open the preference pane and set up the following options. Note that I am using Xcode 3.0 on Leopard so you may see the options under different headings depending on the version you are using.
General Tab
- “Layout”: set this to “All-In-One” to prevent tons of new windows from opening whenever you do anything at all.
- Check “Open counterparts in same editor” to prevent Apple-Option-Up (used to switch between header and implementation files) from causing the files to open in a new window.
- Check “Automatically open/close attached editor” to cause the in-window editor to be used when you select code files.
- Check “Automatically clear log” to clear out the log between runs, a la Eclipse.
Code Sense Tab
For some reason, code sense is not on by default from what I could see, which just seems plain silly to me. The options for turning it on in this tab are self-explanatory .Debugging Tab
Launching an app in debug mode doesn’t show the debug “perspective” in Xcode by default. I changed the “On Start” option to “Show Console & Debugger” to make this happen, since I am used to switching to debug mode in Eclipse when I launch an app to see what it’s doing. Press Apple-0 in Xcode to switch back to the project “perspective” after running your app.SCM
Setting up a source control repo is totally painless, and Xcode has a built-in SCM browser that’s as nice as anything I’ve used elsewhere. I got it hooked up to my SVN repo running on my old G4 tower in about ten seconds using svn+ssh.Unit Testing in Objective-C
In Java, I always use JUnit and its associated set of libraries (such as JMock). There’s a framework for Objective-C called OCUnit which is basically identical to JUnit in purpose and operation, and an associated mocking framework called OCMock. Apparently OCUnit is such a standard that Apple decided to include it in Xcode 3.x, so unless you are developing in Xcode 2.x or lower you don’t need to download and compile OCUnit yourself.
To get a basic Xcode project set up with unit testing, I found this tutorial on the ADC site to be the easiest to follow. There are a few gotchas.
- If you are using an older version of Xcode 3.x like I am and the ADC site is being retarded and not letting you download a newer non-Snow Leopard version of Xcode, then the panels are not as nicely broken down as the screenshots in the tutorial. It’s very easy to accidentally pick the C++ Unit Test Bundle instead of the Cocoa Unit Test Bundle. If your project compiles fine but you get linking errors during your build, you picked the wrong framework. You’ll also be able to tell this by looking in the Info window for the Unit Tests target (select the target, right click, and select Get Info). Under the Build tab, if the Linking => Other Linker Flags section shows “-framework Carbon -framework SenTestingKit” instead of “-framework Cocoa -framework SenTestingKit”, you selected the wrong thing – you need the Cocoa version for a Cocoa app.
- The way that OCUnit works, it links in to your main application as a dependency during building. So, you’ll create a regular GUI app, create a unit testing target with a dependency on this app, and then when you build the unit testing target it fires up a unit test wrapper during the build and exercises your code; the build will simply fail if any tests fail. The nice thing about this is that your test errors appear as build errors in Xcode, which lets you see build error bubbles adjacent to the broken assertions (in other words, no custom OCUnit runner plugin is needed in Xcode like the JUnit plugin is needed in Eclipse). The key takeaway here is that you want to make sure that your Cocoa GUI app fires up in main.m (i.e. the default “return NSApplicationMain(argc, (const char **) argv);” code is present); if not, then the OCUnit hooks can’t work their magic.
- Each class implementation file (i.e. .m file) in an Xcode project can be built for one or more targets. You choose the target for your classes as you create them using the “New File…” wizard, but you can verify and/or change your build targets by right-clicking the .m file and selecting “Get Info” and looking in the “targets” tab. Like with JUnit, you don’t want your tests ending up in your main application, so make sure your app code is aimed at the main application target in your project, and your test code is pointed to your unit testing target.
Besides this, OCUnit is very similar to JUnit with the convention for test method names to begin with “test…”, setUp() and tearDown() methods, and automatic introspection of the unit test class to determine the tests to run. Assertions are implemented as macros (which are kind of like Java’s static imports from what I can see).
Writing Some Objective-C
I’m told Objective-C is like SmallTalk, but having never learned SmallTalk I can’t tell you if this is true or not. In any event, it’s a piece of cake to learn for anybody who has a basic understanding of object-oriented development and C/C++. I’ve forgotten a lot of the C/C++ I learned in college, and haven’t refreshed on method overloading or language specifics yet since my primary goal last night was to get a unit testable project up and running, so forgive the basic-ness of the code presented below, but I wanted to share what I wrote so that people familiar with Java and JUnit can get the idea.
I found a few useful tutorials on the language to get me going, in addition to referring to my books for sample code. Tristan O’Tierney has a nice language overview on his blog.
Here’s the awful Objective-C code for my calculator app.
Calculator.h
1 2 3 4 5 6 7 8 9 10 11
#import <Cocoa/Cocoa.h> @interface Calculator : NSObject { } - (int) addTwoNumbers: (int) first secondNumber:(int) second; - (float) addTwoDecimals: (float) first plus:(float) second; @end
Calculator.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#import "Calculator.h" @implementation Calculator - (int) addTwoNumbers: (int) first secondNumber:(int) second { return (first + second); } - (float) addTwoDecimals: (float) first plus:(float) second { return (first + second); } @end
CalculatorTest.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#import <SenTestingKit/SenTestingKit.h> #import "Calculator.h" @interface CalculatorTest : SenTestCase { // it's standard in Objective-C to declare class // members in the header file; this will be our fixture Calculator *calculator; } - (void) testAddTwoNumbers; - (void) testAddTwoDecimals; @end
Calculator.m
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
#import "CalculatorTest.h" @implementation CalculatorTest - (void) setUp { // I'm using Objective-C 2.0 which has built-in garbage collection // so I didn't use [[Calculator alloc] init] or use autorelease pools; // not sure if this is the right way to do this yet but I saw it in a // tutorial calculator = [Calculator new]; } - (void) tearDown { // This resets the fixture reference for each test. Again, this // was recommended so I'm just towing the line calculator = nil; } - (void) testAddTwoNumbers { // I wanted to see where log output for tests goes; more on this later NSLog(@"Something in my test..."); int result = [calculator addTwoNumbers:3 secondNumber:6]; // This is how SenTest rolls for assertions... ugh. See my update // at the end of this blog post for a way to get JUnit-style // assertions with Hamcrest if you prefer them STAssertEquals(9, 9, @"Expected 9, got %d", result); } - (void) testAddTwoDecimals { float result = [calculator addTwoDecimals:10.1 plus:1.2]; STAssertEquals(11.3f, result, @"Expected 11.3, got %f", result); } @end
Getting Output
Any output from print statements in your main app code will show up in the console in Xcode, but output in the test classes themselves does not. However, everything you NSLog shows up in the OS X Console, so if you really need to print something in your unit test and see it come out as output, open up the Console application. There is a little lag since Console polls its logs. There might be a way to get the output of the unit test inside Xcode but I couldn’t find it.
Next Steps
Now that I have all that working, for my next trick I want to do something else that is familiar to me: talk to a web service. Apple has a few tutorials on their web service APIs as well as their tree-based XML parsing. I haven’t gone through these yet, but they look pretty thorough and have tutorials. They also provide a sample Java web service app (linked to in the web service document) which will echo back whatever is sent to it, so you can use this to test out your Cocoa calls to SOAP.
I hope you find this useful. I’m looking forward to corrections/tips from anybody who really knows what they are doing with this stuff, so please add them in the comments.
UPDATE 2010.02.06:The “STAssertEquals”-style syntax for assertions in SenTest is really annoying if you are used to JUnit-style assertXXX()-style assertions. I just found a blog post by the guys at CarbonFive where they describe how to set up Hamcrest matches for Obj-C. Check it out! The source for the Obj-C implementation of the Hamcrest project has an Xcode build that works flawlessly.
-
Performing SQL Validation (a.k.a. “Data Dips”) with RIATest
We started using RIATest at Highwinds to automate our Flex functional testing. For those of you who are unfamiliar, RIATest is a great Flex-only alternative to products like HP’s QuickTest Pro, allowing you to fully automate your Flex functional testing either from the RIATest IDE itself, or via the command line. While QuickTest Pro can be used to automate a wide variety of GUI-based apps, it costs about five times as much as RIATest, so if you are only testing Flex apps RIATest is a great low-cost alternative.
Something else that QuickTest Pro lets you do that RIATest does not is perform “data dips” or, to put it in layman’s terms, query a database during functional testing. This can be useful for validating non-visual system state.
For example, let’s say that you have an application that allows you to change user information, and that the requirements dictate that whenever the user information is changed, a last modified date on the user’s record should be updated. If the last modified date is not visible as a label within the Flex app, RIATest can’t validate that the last modified date has changed, since it can only validate the state of Flex components. In this scenario, you’d typically want to
(a) execute a functional test to change a user’s info,
(b) validate the changes to the UI after the user’s information is saved and loaded again for viewing, and
(c) check the state of the database to validate that the last modified date has indeed been updated.However, since RIATest doesn’t offer data dip functionality, step (c) would be impossible without manual intervention from a QA tester. This is where riatest-integrator comes in.
Thankfully, the RIATest developers put a special object in RIATest called Process. Process allows you to execute an external process, and interact with its input, output, and error streams. Once I discovered this, I decided to write a little Java library that would make it easy for me to fire up a Java process from the command line, hook RIATest to its input and output streams, and write input from RIATest to it. The process would then pass the input to some kind of integration inside of the Java process, and return output from the integration for inspection by RIATest. This turned out to be pretty easy as expected, and I published the library to Google Code under the name riatest-integrator.
Currently, there is a download available on the Google Code site that lets you query MySQL databases right out of the box. There is a sample RIATest script on the home page of the project showing how you can call it from RIATest and validate output coming back from the database. It’s a really simple implementation, but if people are interested in it, I’ll add more features and functions. The API is also really straightforward, so any Java developer with even the most modest skills should be able to customize it to their needs.
The API in the library is not limited to SQL; anything that Java can talk to can be hooked in to. We have some proprietary back-end servers at Highwinds that speak NNTP, so we could easily write an NNTP integration that allows us to have RIATest query the state of our NNTP message groups after actions are taken in our Flex apps.
If you are a RIATest user, please take a look at the project, and share your feedback either here on my blog, or as feature/bug requests in the project’s issue tracker.
-
Debt To America
I just finished watching the documentary Maxed Out on NetFlix Streaming this evening. Considering that I spent most of the morning reconciling a year’s worth of monthly statements for my 401k and brokerage accounts, I’ve had money matters on the brain all day, and this blog post is the result.
Maxed Out
Maxed Out looks at the credit industry from a number of different angles, interviewing debt collectors, consumers from various walks of life, and a few Harvard professors. They also throw in a smattering of clips from congressional hearings, and sound bites of president G.W. Bush making an ass out of himself and signing in laws that only help big businesses. The whole point of the film is to expose our debt culture, and how the poor stay poorer by being saddled with debt they can never pay off while the government gives legislative hand-outs to big lenders.In my opinion, the movie tried a little too hard to present a damning perspective of the creditors and our government officials. Far be it from me to defend the credit vampires or the influential lapdogs in public office, but credit takes two to tango. When things go south with an irresponsible consumer that drank too much from the credit firehose, they are as much to blame as the credit card company who gave them the credit they should never have had.
Well, that’s not very satisfying; this is America, so somebody must be to blame for all this debt… but who?
Is it the government’s fault?
It’s hard to discuss our government without sounding jaded, but please know that I’m not. I’ve come to understand that our capitalist society, like most things in life, is a two-sided coin with a number of cons that I must be willing to accept in order to enjoy the pros.Because of the way this country operates, I can live a lifestyle that would be considered fabulous in some parts of the world, but in order to do so I have to accept that our government is largely controlled by the flow of money. Along with this, I have to accept that (regardless of any utopian ideals) the people in our government have a primary purpose to protect the interests of the businesses who will keep their campaigns well-funded; my personal interests and protection are mostly secondary concerns. So long as our government acts favorably to business, businesses can be successful, and I’ll be able to earn a decent wage as an employee and continue to enjoy the life I left England for.
This is simply the way of the USA. There’s not much any of us can, ever will, or necessarily should do to change that.
So, is it the credit card company’s fault?
If government protects the interest of businesses first, we can’t expect the government to protect us as consumers. We also shouldn’t be surprised that lending companies, like all companies, want to make as much money as they can. We should be equally unsurprised at the choice of people creditors want to lend to, i.e. those who are most likely to make minimum payments from the day they make their first credit card purchase until the day they die (leaving the creditors with massive profits).Personally, I think it’s somewhat hypocritical for us as a nation to criticize these companies for doing what they do. I may not find it ethical, but I understand the motivation for a business to make as much money as it can from the best possible consumer of their product.
It’s our fault.
We’re the ones that sign the credit card agreements. We’re the ones who charge all the crap that we can’t afford. We’re the ones who don’t educate our children about how to save money and live within their means. We have nobody to blame but ourselves. There isn’t a credit card company on the planet that can force any of us in to debt without us playing our part.If there is anything to be angry about, it’s our collective apathy.
I took a life skills class in high school. They taught me about baking and condoms, but they never touched on how to balance a checkbook or what compound interest looks like. Nobody showed me a sample of monthly expenses for running a household, paying a mortgage, or owning a car. My guidance counselors showed me a big binder full of careers and the starting salaries for each, but I had no idea what kind of lifestyle I could lead with a $20,000 starting salary versus a $40,000 one. There was no mention of how to save money, let alone of how I should invest it for the future.
And so, the only good financial habit I picked up as a teenager was a stoic motivation to pay my credit card off every month – the result of being given a credit card at age 16 by my parents along with a white lie that my account couldn’t carry a balance beyond the grace period. If you’re wondering, I intend to play the same trick on my kids.
While I left high school with a solid education in all things academic, I lacked the life skills to be effective as a financially responsible human being. I spent six post-graduation months working a single job and constantly owing money. Finally, my step-mom sat me down for about an hour and worked me through my budget. Looking back, that one hour has had more impact on my life than almost anything I learned in all my years of school.
The result was that I couldn’t afford to support myself on a single job; I either needed to make more money or work two jobs. I ended up doing the latter. I took the foundation that my step-mom gave me and put together a two-year plan to save up enough money to pay off my car loan and go to college. The plan involved the abandonment of every luxury (no matter how small), and left me with about $20 a month in discretionary spending money. It was a hard two years of brown-bag lunches and lackluster Friday nights, but in turn, I learned both the crushing financial constraints that a loan could put on me and the discipline to save money to meet a future goal. Barring interest-free promos and necessities like auto and housing loans, I’ve been debt-free ever since – all because somebody who knew the potential perils cared enough to take responsibility for me.
Let’s Take Ownership.
And thus, we arrive at the point of my rant: as a country, we need to take ownership of our finances. We need to make sure that our kids understand the money minefields awaiting them in life. No kid should leave high school without knowing what kind of lifestyle the salary associated with their chosen career will let them lead, or just how important it is for them to pay themselves in savings before they pay their bills. Every school should cover this stuff in home economics; it’s maybe two class’s worth of material along with some basic reading as homework. And since that’s unlikely to happen, I urge you to talk to your kids (or nieces and nephews) and set them straight.If you yourself are confused, don’t be embarrassed; seek some help. There’s loads of it in the library and on the web. I recommend The Millionaire Next Door as a starting point, along with a saying whose origin I have long since forgotten: “The secret to happiness is to live beneath your means.”
In closing
I think it’s likely that the reason our government is racking up trillions in debt is because many of the people running our country grew up in a debt culture. I also think our collective apathy toward our government’s financial irresponsibility stems from how many of our citizens owe money and can’t imagine a debt-free existence.Perhaps if we can raise a generation of fiscally responsible kids, they’ll form the next generation of fiscally responsible adults, and we’ll see an end to irresponsible borrowing in both our government offices and our personal lives. It’s worth a try.
-
Lamenting the Loss of 100% Mortgage Financing
While I totally get that 100% financing is seen as a big contributor to the Great Mortgage Meltdown of 2008, I don’t believe this is entirely true, and I’m pretty surprised that they have gone away for good. Allow me to explain.
As a young professional, gainfully employed on a decent salary, I decided in 2003 that I wanted to buy a home. I started saving up for a down payment. However, the housing market was starting to pick up its pace, and I quickly realized that the values were going up faster than I could afford to save a down payment that would make any difference at all to the price of the kind of house I wanted. This being the case, I went out and found a property that I liked, and my step mom (who was brokering mortgages at the time) found me 100% financing with no down payment, a decent interest rate, and no PMI. In this manner, I ended up buying my first (and current) house in June of 2004.
Since then, I’ve never missed a payment, my mortgage was (and still is) affordable within my means, and my credit has always been excellent. Thanks to a solid financial education from my parents, I’ve been debt free (barring an occasional car payment and a mortgage) for as long as I can remember. I’ve also steadily amassed a tidy sum in a money market account over the last decade with the purpose of covering me in case I should lose my job or fall on similar hardship. My wife and I have also routinely tucked away savings for retirement in our 401Ks and IRAs. So, when Jessica and I started looking around recently for a bigger house, I expected that people of our credit standing, financial stability, and obvious fiscal responsibility would still be able to get a 100% mortgage.
As it turns out, this is not the case. 100% loans are gone for good, and the system is back to requiring at least a 5% down payment (unless you go FHA at 3.5% and subject yourself to the loan limits for your locale). Also, PMI is standard once again on loans until the house reaches an 80% debt-to-value ratio, where the “value” portion is equal to the sale price and not the appraised price. And no matter how good your credit is or how much cash you have on hand, those are the rules.
So, let’s explore why these rules are stupid.
It goes without saying that 100% financing (or, indeed, any financing) should only be offered to people who qualify for the loan, and not to people who can’t afford a mortgage in the first place. I’d like to think I fall in to the “qualified” category. Currently, my wife and I have access to enough assets in liquid and retirement savings that if we both lost our jobs, we’d have funds to draw on so that we can keep paying the mortgage and other bills for quite some time. So, with 100% financing and no cash out of pocket, we’re in great shape in even the worst-case scenario.
Now let’s look at the 80% loan scenario. If we take some of the cash we have as our safety net and put it in to the house as a 20% down payment, the safety net is diminished. Even though our mortgage payment is smaller in this scenario due to the lower value of the mortgage loan, we’ve got less access to cash to cover us if one (or both) of us loses our jobs. Thus, the likelihood of us defaulting on the loan becomes higher than it was before. In other words, we become riskier people to lend money to. How this can make any sense to the lending institution boggles my mind.
To boot, if we were to default, we’d lose the cash from our down payment when we lost the house leaving us in an even worse financial position than the default alone. In this way, it just makes no sense to put any cash in to a property: the only cash I’d ever want to invest would be earned equity from the sale of our existing house, but with the market the way it is we’ll probably only earn about 10% profit of our house’s original value if we sold it tomorrow, which is hardly 20% of a more expensive house.
Let’s say we put in 5%. Now we’re paying PMI, which would be somewhere between $200 and $350 extra each month, giving us a larger monthly payment to make. Again, should we lose our jobs, this means that we’ll run out of savings faster paying for something that’s supposed to protect the lender. Once again, we’re in a worse position than we would be with cash in hand and a 100% loan. The same is true for “creative” financing with two mortgages (such as one at a low interest rate for 80% of the house, another at 10% at a higher interest rate, and a 10% cash down payment).
With that all said and done, let’s look at the impact on the housing market. Here you have my wife and I looking to invest in a slightly more expensive house that we can readily afford. But due to the down payment requirement, we’re probably going to avoid it altogether. That means no home sale. Assuming that we’re not the only ones following this thought process, the likelihood for the housing market to stabilize and for qualified people to start investing in it again is slim – other than the investors who summed up fat stacks of cash from the boom and are coming back in to pick over the spoils, of course.
It just doesn’t make any sense. I say bring back the 100% loans – only this time, actually qualify the people looking to secure them instead of just handing them out to anybody who can fog up a mirror.
-
Maybe I Don’t Want a Nook
I took a look at the Nook today in our local B&N store. Don’t get me wrong – it’s a nice e-reader, it’s just not exactly what I was expecting.
What I was hoping for was a device that I could use to carry all my books, notes, and PDFs, which I could then review and/or annotate on the road. Pretty much the only thing that the Nook wouldn’t be able to do for me is the annotation use case, but that’s a big deal to me, unfortunately. The problem is that while the Nook can annotate documents, the process for highlighting the bit you want to annotate (and then adding the annotation itself) is really slow due to the fact that the e-ink display takes so long to redraw with each movement of the cursor. While it would be possible to annotate documents, it would take so long that I would go out of my mind.
The bottom line is, I think I’ve been spoiled by having an iPhone with a full touchscreen interface and snappy performance; I may need to wait for that Apple tablet after all.
Besides the annotation situation, the Nook is a neat little device. If you are in the market for an e-reader, I highly recommend that you check it out. The weight is right, the build quality is decent, the screen is clear and easy to read, the color touchscreen is a nice addition that works well with the main screen, and the online browse and purchase process is fast and easy enough considering the scope of the device’s capabilities.
-
I Want a Nook
With my birthday and Christmas approaching, my wife always asks the inevitable question of what I’d like to receive as a gift. Due to the fact that I’m either totally spoiled or have meagre requirements for self-actualization, I’ve got pretty much everything that I could ever want, and it isn’t often that a material possession of any kind should take my fancy. However, with all these eBook readers coming out, now is one of those rare times.
There’s been something of an electronic reading revolution going on for a while, which has continued to gather steam as more mobile devices appeared and laptops dropped in price. For a long time, I couldn’t get used to reading on a computer; there was just something about holding a book and learning to “know” where to open it for a piece of reference material (being a programmer, most of my books are technical and reference is my primary use case). However, in the last few years I’ve really come to love being able to search and annotate electronic documents, and the fact that my Macs print everything to PDF natively has facilitated this to the point where I’m completely paperless. Having an iPhone has allowed me to experience electronic reading on a small screen, which works, but has highlighted for me why a bigger screen would be better and a different device is needed.
My boss got a Kindle shortly after they came out, and I definitely liked it, but it seemed limited in implementation. Now that B&N has come out with the Nook, the whole concept of a viable eBook reader seems to be getting off the ground.
Nook vs. Kindle
There are a few things I like better about the Nook when compared to the Kindle. Firstly, Nook has the Android OS. I can see B&N opening the device up to third party developers at some point, which would be pretty cool. Even if they don’t, I expect that future software revisions will have all sorts of cool stuff in them. Secondly, the Nook has WiFi access. Third, it has a memory expansion slot for a microSD card, and I intend to start using such a card to hold all my technical notes and reference materials as well as my eBooks. Fourth, it supports the EPUB format, which O’Reilly (the premier technical publisher) is embracing as one of their electronic book formats, which means I don’t need to wait for B&N to offer certain titles (and their programming reference library for eBooks is surprisingly poor considering the geek factor associated with eBooks). Finally, it has a replaceable battery.On the con side, the Nook doesn’t read .txt or .doc files, but these features seem well in the range of paltry software updates in future revisions. Also, there doesn’t appear to be a way to wirelessly get my self-generated content (such as files from work) on to the Nook, although you obviously can transfer documents via microSD or USB. I’d be willing to pay a small fee to get documents on to the device wirelessly, or to maintain my own online library of images and eBook content. Again, since the phone runs on Android, these are use cases that I see coming to fruition in the future – and if they don’t, it won’t be the end of the world.
Use cases
Almost immediately after getting a Nook, I can see myself writing a few handy AppleScripts to convert web pages, software design discussions in emails, technical documents from work and the web, and other stuff to PDF to be saved in a “pending transfer” directory on my computer, which I’ll copy over to my microSD card before powering down at the end of the day. I can then refer to this library of reference materials wherever I may be. Ideally, if the Nook offered a basic web browser one day, I could set the script up to FTP content to a location on my personal web site where I could retrieve it wirelessly on-demand; that would be the bomb.Why not wait?
Of course, there are some other really interesting things happening in this space. The Plastic Logic QUE is not going to be released (or maybe just the details of it) until January 7th, 2010 (although there is a video of its prototype on YouTube). But since the QUE is aimed at business users, will probably be more expensive, is bigger than I would really like my eReader to be, and won’t run Android AFAIK, I’m not sure this is the device for me.And then there’s always the possibility that the ubiquitously non-existent Apple tablet should show up some time when we least expect it. We all know that the iPhone rumors took several years to come to fruition, but they finally did – and look at the impact that device has had on its market. Again, an Apple tablet is likely to cost a fortune; $200.00 to $300.00 all-in for a Nook with accessories seems like a good deal to me.
Now, if only my wife read my blog… :)
Tagged Yelling
Most Popular Yelling
- Scrolling Large Data Sets in Flex Charts (35)
- How To Become A Software Engineer/Programmer (15)
- On A Personal Note (10)
- Abandoning ColdFusion? (9)
- Adobe Says: "Thousands of Developers are using CF 8" (9)
- What to do about Healthcare? (8)
- CFUNITED Day 2 (7)
- Build Tools: Maven Flex Plugins (7)
- Why People Hate Vista (and Other Microsoft Products) (7)
- Opinions on JDeveloper, Oracle's J2EE Strategy (6)
Stuff I Like
More Yelling
- July 2010
- June 2010
- May 2010
- April 2010
- March 2010
- February 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- May 2009
- April 2009
- March 2009
- February 2009
- January 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- January 2007
- December 2006
- August 2006
- July 2006
- June 2006
- April 2006
- February 2006
- December 2005
- November 2005
- October 2005
- August 2005
- July 2005
- June 2005
