OMG, Apple rejected my App!

After releasing my first RubyMotion app (FC St.Pauli chants), I’m currently working on another one for Freifunk Hamburg.

I am using Testflight with a group of 10+ beta testers, to verify that my app is working properly and has no issues whatsoever.

The Review Process

When I think that an app is close to be feature complete, I create a version that can be pushed to the AppStore. This process involves setting up a distribution certificate and other stuff in iTunes connect. It’s a little time consuming and the review-process usually takes some weeks, especially for new apps.

I was not totally surprised that the first revision got rejected by Apple, eventhough they stated, that the app crashed on startup, which none of my beta testers had experienced. I thought that this might be due to some iOS 7 related changes.

So I just submitted an updated version to the review process. Unfortunately that version also got rejected…

The Crash Report

The latest reject was also due to a crash on startup. In case of a crash, Apple provides a Crash Report in the Resolution Center (it’s super easy to find… NOT: iTunes Connect>Manage Your Apps>[The App Icon]>View Details>Links>Resolution Center).

There is a lot of info in such a crash report. It starts with some basic infos about the device and app environment:

Incident Identifier: 7B2A05A2-E9C3-47F8-90DC-3C37BA634D69
CrashReporter Key:   edb549cbc4b5919b7c8a04beb0db00da1ada7c41
Hardware Model:      xxx
Process:             freifunk [6726]
Path:                /var/mobile/Applications/44317BE9-04A0-4B3E-A3D8-24134AE1B06C/freifunk.app/freifunk
Identifier:          de.nofail.freifunk
Version:             0.0.1 (0.0.1)
Code Type:           ARM (Native)
Parent Process:      launchd [1]
 
Date/Time:           2013-09-13 08:06:36.406 -0700
OS Version:          iOS 7.0 (11A465)
Report Version:      104

then comes the root cause:

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Triggered by Thread:  0

followed by the backtrace when the crash occured:

Last Exception Backtrace:
(0x2fe08f4e 0x3a6156aa 0x2f85ac 0x2f86d8 0x2608f4 0x25df9c 0x2c78f8 0x2e887c 0x2e003a 0x2c81c4 0x232d50 0x2e8854 0x2e003a 0x22f9e8 0x22fc60 0x2302f0 0x325eacb2 0x325ea702 0x325e4d0e 0x3257f6a2 0x3257e9a4 0x325e44f8 0x34a38708 0x34a382f2 0x2fdd39e2 0x2fdd397e 0x2fdd2152 0x2fd3cce2 0x2fd3cac6 0x325e3794 0x325dea3c 0x42d9c 0x42860)

infos about the threads that were active during the crash:

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
[...]
9   CoreFoundation                	0x2fd3cd58 CFRunLoopRunSpecific + 636
10  CoreFoundation                	0x2fd3cac6 CFRunLoopRunInMode + 102
11  UIKit                         	0x325e3794 -[UIApplication _run] + 756
12  UIKit                         	0x325dea3c UIApplicationMain + 1132
13  freifunk                      	0x00042d9c 0x32000 + 69020
14  freifunk                      	0x00042860 0x32000 + 67680
 
Thread 1 name:  Dispatch queue: com.apple.libdispatch-manager
Thread 1:
0   libsystem_kernel.dylib        	0x3abc183c kevent64 + 24
1   libdispatch.dylib             	0x3ab02220 _dispatch_mgr_invoke + 228
2   libdispatch.dylib             	0x3ab01fa6 _dispatch_mgr_thread$VARIANT$mp + 34
 
Thread 2:
0   libsystem_kernel.dylib        	0x3abd4c7c __workq_kernreturn + 8
1   libsystem_pthread.dylib       	0x3ac3adc6 _pthread_wqthread + 306
2   libsystem_pthread.dylib       	0x3ac3ac80 start_wqthread + 4
 
Thread 3 name:  WebThread
Thread 3:
[...]
6   WebCore                       	0x37ebebae RunWebThread(void*) + 414
7   libsystem_pthread.dylib       	0x3ac3cc1a _pthread_body + 138
8   libsystem_pthread.dylib       	0x3ac3cb8a _pthread_start + 98
9   libsystem_pthread.dylib       	0x3ac3ac8c thread_start + 4

Thread 4:
0   libsystem_kernel.dylib        	0x3abd4c7c __workq_kernreturn + 8
1   libsystem_pthread.dylib       	0x3ac3adc6 _pthread_wqthread + 306
2   libsystem_pthread.dylib       	0x3ac3ac80 start_wqthread + 4
 
Thread 0 crashed with ARM Thread State (32-bit):
    r0: 0x00000000    r1: 0x00000000      r2: 0x00000000      r3: 0x00002060
    r4: 0x00000006    r5: 0x3ca9318c      r6: 0x00000000      r7: 0x27dce594
    r8: 0x1450efa0    r9: 0x00000001     r10: 0x14569fb0     r11: 0x00000000
    ip: 0x00000148    sp: 0x27dce588      lr: 0x3ac3da33      pc: 0x3abd41fc
  cpsr: 0x00000010 

and the address space:

Binary Images:
0x32000 - 0x334ffb freifunk armv7  <3ae0aadc89773fe8a07f885fdaff2237> /var/mobile/Applications/44317BE9-04A0-4B3E-A3D8-24134AE1B06C/freifunk.app/freifunk
0x2bee8000 - 0x2bf0878a dyld armv7  <b37cba000c7d3f8ea414f060d45ce144> /usr/lib/dyld
0x2edd9000 - 0x2edd9fff Accelerate armv7  <8e17835efc9234da89e3080c47fad906> /System/Library/Frameworks/Accelerate.framework/Accelerate
[...]

Analyzing the Report

It’s not obvious what to do with such a report so Apple gives a Technical Note on this topic. You can also find some information in the Debugging Guide of the RubyMotion docs.

The big problem with the crash report are the missing identifiers. There is no hint for what might stand behind any of the memory addresses noted in the backtrace or whatever. That’s were Symbolication comes into play.

Symbolicating your RubyMotion Crash Report

Symbolication is the the process of converting the numeric addresses in the stacktrace to matching parts of the codebase. In order to get this working, you will have to keep the *.dSYM files that were generated with your release build. They are in the same folder as your .ipa file, that you are uploading to the AppStore (ie build/iPhoneOS-5.1-Release/freifunk.dSYM/).

It’s a good idea to backup those files! Otherwise you won’t have the possibility to ever know why a crash happened.

Symbolication is pretty easy once you know what to do. You can use the atos command line utility to “convert numeric addresses to symbols of binary images or processes”. Go to the release folder of your app and run the command with the exception backtrace, use the first address of the binary image as your base address and point to the executable binary:

cd build/iPhoneOS-5.1-Release
atos -o freifunk -l 0x32000 -arch armv7 0x2fe08f4e 0x3a6156aa 0x2f85ac 0x2f86d8 0x2608f4 0x25df9c 0x2c78f8 0x2e887c 0x2e003a 0x2c81c4 0x232d50 0x2e8854 0x2e003a 0x22f9e8 0x22fc60 0x2302f0 0x325eacb2 0x325ea702 0x325e4d0e 0x3257f6a2 0x3257e9a4 0x325e44f8 0x34a38708 0x34a382f2 0x2fdd39e2 0x2fdd397e 0x2fdd2152 0x2fd3cce2 0x2fd3cac6 0x325e3794 0x325dea3c 0x42d9c 0x42860

This produces a somewhat readable output:

0x2fe08f4e
0x3a6156aa
__vm_raise() (in freifunk) + 468
rb_vm_raise (in freifunk) + 280
rb_exc_raise (in freifunk) + 4
rb_name_error (in freifunk) + 92
rb_mod_const_missing (in freifunk) + 116
dispatch_rimp_caller(objc_object* (*)(objc_object*, objc_selector*, ...), unsigned long, objc_selector, int, unsigned long const*) (in freifunk) + 272
rb_vm_dispatch (in freifunk) + 4502
rb_const_get_0 (in freifunk) + 684
rb_scope__init_testflight__ (in freifunk) (app_delegate.rb:45)
dispatch_rimp_caller(objc_object* (*)(objc_object*, objc_selector*, ...), unsigned long, objc_selector, int, unsigned long const*) (in freifunk) + 232
rb_vm_dispatch (in freifunk) + 4502
vm_dispatch (in freifunk) + 504
rb_scope__application:didFinishLaunchingWithOptions:__ (in freifunk) (app_delegate.rb:3)
__unnamed_2 (in freifunk) + 316
0x325eacb2
0x325ea702
0x325e4d0e
0x3257f6a2
0x3257e9a4
0x325e44f8
0x34a38708
0x34a382f2
0x2fdd39e2
0x2fdd397e
0x2fdd2152
0x2fd3cce2
0x2fd3cac6
0x325e3794
0x325dea3c
main (in freifunk) (main.mm:15)
start (in freifunk) + 36

The interesting parts here in this stack are rb_scope__application:didFinishLaunchingWithOptions:__ (in freifunk) (app_delegate.rb:3) and rb_scope__init_testflight__ (in freifunk) (app_delegate.rb:45). They show that the app crashes during initialization in didFinishLaunchingWithOptions when calling the method init_testflight with the error const_missing. This is the matching code part:

  def init_testflight
    TestFlight.takeOff(NSBundle.mainBundle.objectForInfoDictionaryKey('testflight_apitoken'))
  end

So the problem seems to be that TestFlight was missing somehow. This was kind of weird, because I was using TestFlight for distributing my beta builds and all worked fine. Doing some grep in the compiled sources, I saw that the TestFlight SDK was not included in the distribution build. The underlying problem was, that the TestFlight source path was only set in an development block:

  app.development do
    app.testflight.sdk = 'vendor/TestFlightSDK'
    [...]
  end

Moving out of there fixed my crashing App version.

So the Freifunk App finally made it and you can get the in the AppStore!

So Coded – A Web Conference in Hamburg

On 19th & 20th September 2013 there will be the first So Coded Conference in Hamburg, Germany. I just recently joined the awesome team of organizers and as you can imagine, there is a lot of stuff to do…

The conference aims at Ruby, Python, JavaScript, PHP developers and their shared passion for the interwebs. At the conference, there will be space for up to 150 coders at a sweet location, the LOLA in Hamburg Bergedorf, to learn, teach, hack and have fun! The nice LOLA-Bar is open to relax and chill in between sessions or to hack on your projects.

The team of organizers did a great job already to get in touch with some awesome folks, but we are still reaching out to international speakers to present an incredible lineup for the attendees. Engine Yard, GitHub, 6wunderkinder, Travis CI just dropping some names…

If this sounds cool and interesting for you, grab one of the few early bird tickets left!

And if you think that your company should support So Coded, have a look at the sponsoring section.

“computering” – a different presentation style

Keynote is nice, but it’s not well suited for technical presentations. Live coding on the other hand is hard and often fails horribly because of some minor typos etc.

Some month ago I visited the Python Usergroup Montreal and I saw an awesome live coding session from Rory Geoghegan. He was typing incredibly fast and 100% correct! Watching him, at first I was baffled, then I was amazed and then I got suspicious…

Rorey used Keyboard Cat to replay his code!

The “computering” gem

If you are into Programming-Screencasts like me, you should definitively watch the PeepCode Play by Play episode with Aaron Patterson and Corey Haines. In that episode they have a pairing session on some Ruby code. At some point they drift off and start computering with dinosaur-hands:

(Find all animated GIFs at the PeepCode Blog)

Based on the Keyboard Cat and inspired by the dinosaur-hands i created computering. With the computering command line application you can pretend to type amazingly fast and 100% accurate even in dinosaur-hands-mode!

computering is just a couple of days old, but you can already build interactive command line presentations with it using a simple Ruby-DSL. I used it for our last Ruby Usergroup Meeting and held a talk called OMG Rails4!

Screen Shot 2013-07-11 at 20.20.08

just don’t do it – the art of being lazy

One thing that I find myself doing a lot is skipping a lot of required programming tasks. From what you can find on the Interwebs only a lazy programmer is a good programmer!

This does not mean that you should be doing nothing though… it’s all about getting things done instead of getting stuck in the details!

don’t test your code

I am a huge fan of BDD and Test First. It’s hard writing all those tests when you are lazy. That’s why people tend to write Happy Path tests only.

I think that there are also a lot of areas, where writing tests does not even make sense. IE when you are creating prototypes, learning new frameworks or whole languages and when you are trying to sketch out an object model in code. In those cases, I don’t skip tests altogether, but I defer it to the point where I am confident with what I am going to create.

When you look at large Rails applications they usually have several layers of tests. Unit, Functional, Integration etc. Unfortunately, every layer of tests adds a layer of complexity. I have seen a lot of projects where people write Capybara Spec or Cucumber Features that try to cover the whole application logic! Those test-suites are often brittle and slow, maintenance is a huge PITA. I rather remove those tests and stick with Unit-Tests that might not cover all integration points, but are easy to maintain, understand and also fast.

Use full stack tests only for mission critical features. If you have a good monitoring and deployment process in place, fixing bugs can be cheap. What’s worse, slow and fragile tests, or no tests at all?

don’t refactor your code

I did a lot of refactoring, especially in large legacy systems, some times with no tests as a safety-net. Refactoring is not a value in itself. If a piece of software does it’s job, why would you even think about refactoring it?

Clean Code is something that you want to achieve in every software project. That is because clean code promises to be easier to change and maintain. So it’s not actually about clean, but changeable code. Refactoring code to make it beautiful is waste, always strive to make it more modular and in this regard, easier to change in the future.

I have set up some strickt rules for when I refactor a piece of code:

  • I am changing it anyways in order to add a feature or fix a bug.
  • I am totally pissed of the way it is implemented!
  • I am sitting on a plane and have nothing else to do…

don’t optimize your app

I don’t know how much time I wasted in discussions with other programmers, claiming that this or that part of an application needs some optimization. Most of the time it’s even worse, people implement optimized software right away… This thing, also known as Premature Optimization or how I call it Premature Ejaculation, is most often the source for the NR. 2 reason of why I refactor code (I’m pissed off).

Optimized code tends to be more complex or less readable and in 99% of all implementations, there is a simple, clean, readable and actual faster way to implement it anyways.

Especially code complexity or the complexity that frameworks introduce in order to be super fast comes with a big downside: decreased productivity! It feels like I spent a whole developer year just fixing bugs related to the Rails Asset Pipeline and I am not the only one.

don’t think out of the box

It’s a good thing when you are confident with your programming language, you know every shortcut of the IDE that you use, you run a database that you deeply understand and that you are able to tweak, your operating system is up for half a year and you know what buttons to push to keep it running!

There is no value in introducing new technologies to your application stack until you have a real need for it. Stability and Know-How are often underestimated! I think it makes absolute sense to squeeze the last drop of performance out of your existing stack, keep it as long as you can!

It’s a different thing for programmers though. Playing with new frameworks, databases, operating systems and coding in different types of IDEs is key for expanding your horizon. Learning a new programming language each year is one of those things, that keeps you up to date and lets you think about coding problems from different perspectives. But do you want to have all those languages, frameworks and databases in your application stack? Is it worth introducing heterogeneous systems to your company’s infrastructure?

don’t automate

There are tons of tasks in your daily workflow that could be automated. Automation is a key factor in terms of productivity. If you want to have fast and sound processes in your business, automation is probably the way to go.

On the opposite, I think that it’s fine to be doing manual tasks! It’s always a tradeoff between the value that the manual task provides, versus the cost that creating an automated tool, it’s maintenance and support costs.

Is it worth setting up a whole CI infrastructure, when all you have is just a single app to test? Well, it depends… As a lazy developer, I would look for services that do the heavy lifting for me.

Conclusion

Create something, put some sugar and cream on top, ship it!

OSS licensing

There are so many different license models out there in the open-source community. I don’t know what all the fuss is about… I hate legal stuff, just ship it and ask for permissions later!

Nevertheless I have a license for my open source projects on github as well and it’s just there to say FU to everyone that actually cares about licensing. It’s called THE BEER-WARE LICENSE:

/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp
 * ----------------------------------------------------------------------------
 */

THE (extended) BEER-WARE LICENSE

I modified it a little to come closer to my own needs (markdown + more beers!):

## License
"THE (extended) BEER-WARE LICENSE" (Revision 42.0815): [phoet](mailto:ps@nofail.de) contributed to this project.

As long as you retain this notice you can do whatever you want with this stuff.
If we meet some day, and you think this stuff is worth it, you can buy me some beers in return.

Cheers!