Leonardo Borges

the not so usual geeky stuff

Build Automation With XCode 4.3, KIF and Jenkins

After coming back from my holidays in China - which were awesome - I had no downtime at ThoughtWorks and started at a brand new client/project - a much needed change from what I had been working on lately.

It’s an iOS project, more specifically an iPad app and that’s pretty much all I can tell you about it. I will however tell you how my first few days in the project have been so far.

Being a brand new project I wanted to get our CI environment up and running as fast as possible - after all the project has only a couple of tests now. For context, here’s our setup:

  • XCode 4.3
  • GHUnit (I’m not gonna talk too much about it since this was the easy part - their docs are pretty decent)
  • KIF (for UI tests)
  • Jenkins
  • WaxSim (Hack to get the iPhone Simulator to run on the command line)

In most environments I had worked so far - Java, Ruby, Clojure etc.. - running acceptance tests from the command line is a given and so is integrating that into your build system.

Well, that’s just not the case with iOS projects. These tasks can be a real pain and take a while to complete. Here’s what I had to do:

On your development Mac

I’m assuming here you have an XCode project with at least one KIF test and that it builds successfully from the GUI, when you hit play. Now we can move on to run the tests from the command line.

This is the script I’m using to run my KIF tests. I call it RunKIF.sh and will walk you through 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
#!/bin/bash

killall "iPhone Simulator"
rm /tmp/KIF-*

echo "Build the "UI Tests" target to run in the simulator"
xcodebuild -target "UI Tests" -configuration Release -sdk iphonesimulator clean build

OUT_FILE=/tmp/KIF-$$.out
# Run the app we just built in the simulator and send its output to a file
# /path/to/MyApp.app should be the relative or absolute path to the application bundle that was built in the previous step
echo "Running KIF tests"
/tmp/waxsim -f "ipad" "build/Release-iphonesimulator/MyApp.app" > $OUT_FILE 2>&1

# WaxSim hides the return value from the app, so to determine success we search for a "no failures" line
grep -q "TESTING FINISHED: 0 failures" $OUT_FILE

success=`exec grep -c "TESTING FINISHED: 0 failures" $OUT_FILE`


# if there was a failure, show what waxsim was hiding and crucially return with a non-zero exit code
if [ "$success" = '0' ]
then 
    cat $OUT_FILE
    echo "==========================================="
    echo "GUI Tests failed"
    echo "==========================================="
    exit 1
else
    echo "==========================================="
    echo "GUI Tests passed"
    echo "==========================================="
fi

You’ll notice there are mainly two things happening in this script:

  • It runs xcodebuild to build the target against which your tests will run
  • uses WaxSim to finally run your tests

To get the building step to work, despite what KIF’s documentation DOESN’T tell you, you need to add KIF as a target dependency to your KIF Tests target. This SO thread can walk you through it.

Now on to the fun stuff! For some reason I didn’t have the time to dig into, WaxSim seems to expect XCode to be under /Developer/ on your Mac.

The problem is that since Apple started distributing Xcode through the AppStore, it now lives under /Applications/Xcode.app/Contents/Developer/. Bam! This can cause all sorts of issues when building both WaxSim and your project. So if you see weird error messages complaining about not being able to find DevToolsFoundation.framework and the like, these sym links will probably fix things for you:

1
2
3
4
5
6
7
8
sudo ln -s /Applications/Xcode.app/Contents/Developer/ /Developer
sudo ln -s /Applications/Xcode.app/Contents/OtherFrameworks/DevToolsCore.framework /Developer/Library/PrivateFrameworks/
sudo ln -s /Applications/Xcode.app/Contents/OtherFrameworks/DevToolsCParsing.framework /Developer/Library/PrivateFrameworks/
sudo ln -s /Applications/Xcode.app/Contents/OtherFrameworks/DevToolsFoundation.framework /Developer/Library/PrivateFrameworks/
sudo ln -s /Applications/Xcode.app/Contents/OtherFrameworks/DevToolsInterface.framework /Developer/Library/PrivateFrameworks/
sudo ln -s /Applications/Xcode.app/Contents/OtherFrameworks/DevToolsKit.framework /Developer/Library/PrivateFrameworks/
sudo ln -s /Applications/Xcode.app/Contents/OtherFrameworks/DevToolsRemoteClient.framework /Developer/Library/PrivateFrameworks/
sudo ln -s /Applications/Xcode.app/Contents/OtherFrameworks/DevToolsSupport.framework /Developer/Library/PrivateFrameworks/

I know, right? Moving on.

By now you should be able to successfully run RunKIF.sh and get meaningful results from your test. Let’s configure our CI server now, shall we?

On your CI Mac

Depending on which state your build box is, you might need to create the same sym links I created in the previous section. So ssh into your build box and try to build your project from the command line:

1
xcodebuild -target "UI Tests" -configuration Release -sdk iphonesimulator clean build

This time I’ll assume you already have Jenkins installed and running.

Your Jenkins server is probably running as the jenkins user. You need to change that. Jenkins has to be running within a Desktop session - that’s a requirement from WaxSim. It needs an active desktop session in order to launch the simulator - and thus needs to run as a user who can login to your CI Mac.

If you installed Jenkins using Homebrew, here’s a plist you can use to specify which user jenkins should run as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>Jenkins</string>
    <key>ProgramArguments</key>
    <array>
    <string>/usr/bin/java</string>
    <string>-jar</string>
    <string>/usr/local/Cellar/jenkins/1.439/lib/jenkins.war</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>UserName</key>
    <string>UserWhoCanLogintoThisMac</string>
</dict>
</plist>

Then load the new plist:

1
launchctl load -w  /Users/UserWhoCanLogintoThisMac/Library/LaunchAgents/org.jenkins-ci.plist

Don’t forget to enable automatic login on the CI Mac for the user Jenkins is using. Check this article to learn how to do it.

Now we’re mostly done. Just go ahead and configure your project.

Add a build step of the type Execute Shell and provide sh RunKIF.sh as the command string. Trigger your build and everything should work as expected.

Final thoughts

Once I actually got these steps together to write this post, it didn’t look like much. But the amount of time I wasted finding out what had to be done to actually make this work is just insane.

I’m shocked at how much behind iOS development tools seem to be. It just shouldn’t take this much effort and time only to get some UI tests automated. So far I’m disappointed with the tooling around the Apple ecosystem and I really hope this improves sooner rather than later.

Clj-syd Report #0

Last night we held the first ever meetup for the Sydney Clojure User Group!

When I decided to start running the meetups I had no idea we’d end up with 37 people on the first night! What a great turn out!

As for the content, here’s what you missed:

  • Running Clojure apps on Heroku - Lincoln Stoll (@lstoll)

Linc works for Heroku but ended up not spending a whole lot of time talking about that - instead he showed us how to build a simple web application using Compojure, a small Clojure web framework.

He then evolved the example by implementing it using Noir - yet another web framework that builds on top of Compojure, adding some helpful macros.

To top it off, the UI was implemented in ClojureScript - so that was all Clojure from end to end!

  • Paredit (in Eclipse) for the IDE junkie - Matt Quail (@spudbean)

If you’re into lisps and use emacs - if not you should anyway - you learned to love paredit.

However, not everyone gets to write Clojure for a living and a lot of us end up in some sort of IDE. If you’re in Java land, a popular choice is Eclipse and Matt showed us how you can get the paredit goodness right there using the Eclipse plugin counterclockwise.

Frustrated with the Clojure REPL? Wish you had more useful shortcuts? Decent line editing? Saving that nice function you’ve been working on right from the REPL? Then make sure you check out both the presentation and IClojure, Cosmin’s project.

Definetly worth a try.

Bayan was in one of our internal meetups. Some people raised the fact that we don’t see a lot of the design patterns made popular by the GoF book in languages such as Ruby, Python or Clojure and the overall opinion is that in those languages, some of the problems these patterns solve in, say, Java, simply don’t exist.

Bayan decided to dig up a few and show what’s the alternative in Clojure. Interesting perspective.

Want more?

Join us on Google Groups, submit a talk proposal on the wiki and RSVP to the next meetup!

See you next time!

Project Euler: Problem 4 in Clojure

I solved a few of the problems on Project Euler in the past, both in Java and Ruby, and thought it would be useful to redo them in Clojure, thus improving my skills on the language’s core functions and libraries. Today I’ll share problem 4.

Go ahead and read it but here’s the meat of it:

“Find the largest palindrome made from the product of two 3-digit numbers.”

From this statement we can tell two things: (1) we’ll need a function that can tell whether a number is a palindrome or not and (2) that the largest palindrome is given by the product of two numbers between 100 and 999, inclusive.

Let’s tackle number one first:

1
2
3
(defn palindrome? [n]
  (= (->> n str reverse (apply str))
     (str n)))

With our utility function in hand, one possible solution might be as follows:

1
2
3
4
5
6
7
8
(defn largest-palindrome []
  (apply max (filter #(palindrome? %)
                     (for [x (range 100 (inc 999))
                           y (range 100 (inc 999))]
                       (* x y)))))
(time
 (largest-palindrome))
;;"Elapsed time: 1405.358 msecs

While this works, I wasn’t happy with a couple of things in this solution. First, I thought I could do without using filter. Second, we have unnecessary multiplications going on, leading to poor performance - it takes ~1.4secs to finish.

You see, when we begin multiplying the numbers, we’ll see multiplications such as 100 * 100, 100 * 101, 100 * 102 … and then again, after the first loop is exhausted, 102 * 100, 102 * 101, 102 * 102 …

That led me to take a closer look at for, Clojure’s list comprehension macro. It’s a very powerful construct, providing 3 useful modifiers: let, while and when.

With that in mind, I refactored my first solution to look like this:

1
2
3
4
5
6
7
8
9
10
11
(defn largest-palindrome-1 []
  (apply max (for [x (range 100 1000)
                   y (range 100 1000)
                   :while (>= x y)
                   :let [z (* x y)]
                   :when (palindrome? z)]
               z)))

(time
 (largest-palindrome-1))
;;"Elapsed time: 689.262 msecs"

Here, the while modifier makes sure we aren’t wasting any time with unnecessary multiplications. The when modifier lets us get rid of the outer filter call. And as you can see, the solution is about twice as fast as its first version.

On top of that, it’s still pretty concise. Not bad.

Backlog: Ola Bini on Clojure/conj

As I promised in my previous post, here are the highlights of what Ola Bini had to say about Clojure/conj.

Clojure/conj is the largest gathering of clojure programmers, hackers and enthusiasts, with a single track of talks spanning three days. Ola selected his favorite talks and summarised each one of them.

The actual slides for each one of the talks can be found on github.

You can find Ola’s slides here.

Fun Data Structures

This is certainly a very interesting topic. The highlight here is the approach Clojure takes to handling immutable data structures efficiently: persistent data structures through structural sharing - maybe a good short talk for the next meetup?

However, even though efficient, there are cases where the space complexity of known algorithms gets compromised. More specifically, algorithms that rely on the ability of changing data structures in-place - such as the QuickSort - will suffer from this approach.

I asked Ola about it and the short answer is that you should use a different algorithm that takes advantages of trees instead, since they often don’t rely on in-place changing.

The long answer is a book called Purely Functional Data Structures - another one added to my wish list.

Logic/constraint programming

This is a topic that’s completely new to me and it sounds fascinating at first. It also ended up being the topic of the rest of the tech night, with Ola, Sarah and Jo - also ThoughtWorkers - giving us a Logic Programming 101 crash course using Prolog. Lots to read up on.

In the Clojure world, logic programming can be achieved via core.logic.

The book The Reasoned Schemer was also mentioned as a good read on the subject.

Cascalog (github repo)

Haven’t had the time to play with it yet but it seems extremely useful. It’s a Clojure-based DSL for processing “Big Data” on top of Hadoop.

There you have it. Come join us for our next meeting!

Announcing the Sydney Clojure User Group

Update: We now have a Meetup.com page. Head over there to learn about our next meetups as well as to RSVP to them. We’ll discontinue usage of the wiki for registering attendees, in favor of the new site. Everything else on this post however still holds.

If you’ve been following my blog, you’ll have noticed I started running internal Clojure meetups/hack nights at ThoughtWorks here in Sydney a while ago. While being closed, we’ve already had one international speaker - Ola Bini - come and share his experience as an attendee at Clojure/conj. I promise I’ll blog about it soon.

We’re a small but active group, eager to learn and as a natural result we couldn’t stay closed for any longer! :)

That’s why last Tuesday, the first time we had external guests, we decided to make the group public so anyone could join.

It was great having people from outside ThoughtWorks sharing their real world experience with Clojure. One of them, Harry Binnendijk from Whoto, even gave a presentation about how and why they’re using Clojure [1].

There was another talk, by yours truly, on Continuation Passing Style and Macros in Clojure. It was a great night.

Interested? Read on.

Our meetings will be held on the 3rd Tuesday of every month - at least to start with.

To help organize things we have a Google group where we’ll announce the next meetings, do the traditional “call for papers”, share ideas on how to improve our group, job posts and anything related to Clojure/FP.

We also have a wiki where you can see when and where the meetings are happening, sign up to talk/attend etc…

So if you’ve been thinking about learning Clojure but haven’t had the chance yet, come join us. Joining a group like this in its beginning is a perfect learning opportunity.

And if you’re a Clojure hacker already, we’d love to hear from you just as much!

We welcome all levels and encourage everyone to submit talks they’re passionate about.

I hope to see you in the next meet up. Feel free to shoot the group an email or to me directly at leonardoborges(dot)rj(at)gmail(dot)com

And don’t forget to add us to your calendar so you don’t miss out - next meetup will be on Feb 21st at ThoughtWorks Sydney!

0

[1] Link to the presentation will be available soon

So Long 2011: Year Highlights

It’s that time of the year to look back at what you’ve done and either be happy about it or… well not. :)

To me anyway 2011 was a great year but I won’t bore you with the details so I’ll just jump straight into a couple of highlights!

The biggest one of course was the project we developed to help the Queensland flood victims back in January - which brings me to the next topic:

Speaking

Said project gave me the chance to speak at a few events, sharing this and other great stories:

(1) - XConf is an internal technical conference here at ThoughtWorks

Content

Here in the blog, these are a few of the most popular articles for 2011:

Languages

I decided to learn Clojure and started an internal user group at ThoughtWorks Sydney - you can read a brief report on our first meetup here.

The group’s been a bit off lately since I was on leave in Brazil and then the whole holiday season happened but it’s definitely one of the things I want to make happen more often in the new year.

Clojure is a great language and I expect it to keep gaining a lot of traction in 2012.

And I guess that’s it…

A lot more happened in the last 12 months but these are definitely my favourite parts.

Happy new year everyone! I’m sure 2012 has a lot of new challenges and surprises for us :D

Help Keep RottingNames on the Appstore

A year ago I decided to try my hand on iPhone software development and created a very simple application to experience the whole lifecycle of putting a complete project on the Apple AppStore - I wrote about it a while back.

The result was RottingNames, a heavy metal band name generator.

Since then, I haven’t developed anything else for the iPhone - mostly because my interest lies elsewhere now - but I did notice a small yet steady amount of downloads for this cool little app.

You can download RottingNames for free from the App Store and I like keeping it that way.

However, to be able to put an application on the AppStore, Apple charges an annual fee of A$99 - even if the application itself is free.

I had decided not to renew my iOS Developer Program membership but it seems a pity to let RottingNames vanish like this. Es pecially knowing there are a few die-hard fans out there having a good laugh with it.

Here’s the deal: I’m asking for A$99 in order to renew the membership.

In return, RottingNames will stay on the AppStore for another year, for free.

So hit the button below and stay metal! \m/

Click here to lend your support to: Help keep RottingNames on the AppStore and make a donation at www.pledgie.com !

RubyConf Brazil 2011

I was in São Paulo last week - the 3rd and 4th of November - for RubyConf Brazil. For those who don’t know, RubyConf Brazil is the evolution of Rails Summit Latin America, where I had the privilege to speak in 2009.

This year though, all bets were off. Fabio Akita and Locaweb put together a great event, with over 700 attendees and about 30 speakers split in two streams and two awesome days.

Once more I had the chance to speak at the event and different from previous years, all talks were recorded and streamed live! You can check mine - in portuguese - here as well as my slides - in english - on slideshare.

All other talks can be watched from the eventials’ RubyConf Brazil page. Locaweb has also published the official Flickr album of the event.

It was great to meet up with great friends again as well as to meet amazing new people such as the guys from ThoughtWorks Brazil. I promise I’ll make the detour next time! :)

I hope to see you all again soon!

Report: Clojure Meetup #1

Last Tuesday we held ThoughtWorks’ Australia first Clojure meetup here in Sydney. It was a lot of fun so I thought I’d share a few words about it.

The format was rather simple. First, we had a brief introduction to the language syntax by breaking down a couple of snippets and understanding how each bit worked. For instance, this is one of those snippets:

1
2
3
4
5
6
;;word count
(reduce #(if (%1 %2)
              (assoc %1 %2 (inc (%1 %2)))
              (assoc %1 %2 1))
{}
(clojure.string/split "Clojure 101 - this is is gonna be be great great great" #"\s"))

The cool thing here is that a simple example like this can show quite a few things about Clojure’s syntax:

After this brief discussion about Clojure’s API, we split up in pairs to solve a simple problem from Project Euler:

Add all the natural numbers below one thousand that are multiples of 3 or 5.

It’s the easiest on the site so it allowed us to focus entirely on the language. My first thought was to implement it in an imperative way, but that wouldn’t really teach me anything new so Kurman - the colleague I was pairing with - and I came up with this solution, which I really like:

1
2
3
4
(reduce #(if (or (= (rem %2 3) 0) (= (rem %2 5) 0)) (+ %1 %2)
           %1)
      0
      (take 1000 (iterate inc 0)))

A simple, concise solution that demanded a functional approach. It allowed us to explore Clojure’s APIs and concepts such as lazyness through the use of an infinite sequence. Fun :)

I created a github repository to host this and upcoming solutions from our group. Feel free to browse around.

Can’t wait for our next meetup, when we’ll hack on Overtone!

Hiring Good People Is Really Simple

It really is. There’s no magic involved.

Again and again I come across articles from people complaining about the current interview practices. They complain it doesn’t give you enough depth into the candidate’s ability, personality etc. That it measures the wrong qualities. Or that it just doesn’t work and bad people keep coming through the pipeline.

Well, instead of complaining how about you change it? I’m talking about hiring software engineers here so the first rule you should keep in mind is that you need to get them to write code.

Let me spell that out for you: get them to write code.

It’s as simple as that. If your hiring process doesn’t include this step, just give up and go do something else.

What kind of company are you hiring for?

This is important because it will let you know how to structure your interview process and where to place the “write some code” step. For instance, some companies such as Google, Facebook and ThoughtWorks can’t afford bringing in every candidate for on-site interviews. Not with that influx of applications anyway. Such companies put some sort of coding challenge as their first barrier to entry, before you’re ever invited into their offices. So keep that in mind.

What should I get them to code?

I’m glad you asked! But I’m afraid the answer is it depends.

Different companies - which in many cases means different projects, business models, cultures and what not - hire inherently different people. You need different skills.

Here is where I think ThoughtWorks gets things right most of the time. The coding challenge the candidate is given is, to a smaller extent, the exact kind of code he’s most likely to be writing once he joins. By no means does it mean he’s expected to write the same projects over and over. Far from it. It just gives us a fair go on their abilities in a close-to-real setting.

Google, on the other hand, will give a programming challenge over the phone. Pardon the pun but ‘google’ it and you’ll see it often involves puzzles which leads me to assume they solve puzzles everyday - don’t get me wrong, they helped solve many computing challenges of our time that I’m thankful for but they have a multitude of projects that need different skill sets and as such I’m not sure it’s the best process but, hey, they seem to have the best engineers in the world so it sure works wonders for them.

The bottom line is that this coding challenge should be geared towards finding what your company values, and what it considers to be good code. If puzzles work for you, do that. If you value well tested code, state so in the challenge and evaluate if you’re presented with a well written test suite. If you want someone who can learn anything fast, ask them to develop a simple app in a language they don’t know. You catch my drift.

What then?

The coding challenge is all well and good and it’s an extremely useful tool. However what happens next seems to vary a lot from company to company so I’ll share here, from personal experience, what I think really works: have candidates code whatever project you’re hiring them for.

Back when I moved from Brazil to Spain in 2008, this is exactly how I got hired.
I was interviewed over the phone by one of the company’s owner friends. He’s a genius. He had worked at this same company before but moved on to Google later on. That was my first barrier. Once past that, the company simply invited me, with all expenses paid, to spend a week in their offices, working on a real project together with my soon to be co-workers.

This was by far the most thorough interview process I’d ever been through. They actually got to see how I work. How I deal with other people. How I approach real problems. And on the other hand, I also had a great chance to evaluate what I was getting myself into.
After that week was up, the company’s CEO gathered the feedback from all my peers and to my delight made me an offer.

I still think this is the only way you can be sure to be hiring the right people. Is it time consuming? Yes. Is it expensive? Maybe. You can save a lot of money by only paying the wrong person to work for a week, than actually hiring them and having to pay for at least a month’s worth of work from them. Bad work at that!
I suppose such a process wouldn’t work for some companies, mainly Google and Facebook given that even after the first few barriers there are still a lot of applicants left but then again most companies out there aren’t like them.

But make no mistake - finding the right person is hard and it takes time. Knowing if someone is that right person, on the other hand, is simple, if you’re committed to it.

Conclusion

Obviously this isn’t the only way to hire good software engineers. But I do believe it’s the only one that is fair to both the company and the candidate and will definitely decrease, if not eliminate, your false positives.

Oh, and I apologize if I sound pedantic but getting them to write code, by whatever means, isn’t optional.