Feb 212014
 

Dear John,

thanks for the great show (ATP), I look forward to every episode the three of you do. In the episode I listened to today (#53) you guys talked about ObjC moving forward, and you mentioned Erlang a few times.

Two small disclaimers first, (1) I’m very new in the world of Erlang, and (2) the company I work for has subsidiaries that only focus on Erlang, and shares in companies whose products are built on top of Erlang. I like to believe I’m not influenced by this, but I am influenced, amongst others, by my CTOs passion for the ecosystem.

Erlang is two things: a VM called BEAM, and a language. The language is not to my taste, but I really like the VM. Lucky for me, there is a new language called Elixir that runs on the Erlang VM as a first class citizen.

What I really like with writing for this ecosystem is that it launches a ton of green threads instead of GCD threads, and these processes do true (shared nothing) message sending between them. The actor model is back!

Elixir has other fun stuff too, such as piping function calls as if they were commands in the terminal. So far, I find myself writing a bunch of pattern matching for the work I want it to do, in a more terse yet easy-to-read way than I’m used to coming from ObjC and the usual suspects of languages before that.

I think you’d find it interesting diving into the Elixir and Erlang VM combination. The take-away I’ve got that I’d love to bring back to ObjC would to be (1) even tighter on making everything immutable, (2) introduce green threads where for instance singletons can live, and (3) make a objc_msgSend that sends messages between threads not containing pointers to data, but an actual message, and having the sending process being able to continue with its logic until it needs the answer back where it can block and wait if there is no reply yet.

This was a bit longer than a 140 character tweet, but there you go. Oh, and to tie this together with the news, I only noticed Whatsapp because they sponsor conferences and give talks on how they built their backend in Erlang.

Nov 192012
 

Last week I made sure I have good backups of my iMac. I usually do, but I wanted to make doubly sure, as this weekend, I would nuke my disks to make a fusion drive on my iMac from 2011.

When the iMac was released in 2011 with the Z68 chipset, a SSD and a magnetic disc, I was excited, as I was sure Apple would exploit the caching part of the chipset, using 64GB of the SSD for caching. Alas, they didn’t. So I had to move files to “strategic places” and try to get my computer to act as quick as it could, trying to have it rely more on the SSD than the spinning disc.

The announcement of the fusion drive made me very happy, as it seemed that Apple would 1-up the Z68. The fusion drive would keep what was used a lot on my SSD, and use both drives as one combined drive, so no more moving files around manually and symlinking in between. Yay! But, alas, this would only be for the iMac 2012 and the Mac Mini 2012. Luckily, within long, Patrick Stein had shown us all how to use Core Storage to make our own fusion drive.

Creating the fusion drive was easy: boot from a USB stick with Mountain Lion 10.8.2, switch to Terminal and do

diskutil cs create Fusion disk0 disk1
diskutil cs list
diskutil cs createVolume <UUID> jhfs+ Drive 2288g

The hard part was finding out what would be the best amount of disk space to set up for the drive, but luckily it was equally easy to delete the fusion drive, so after a few iterations I had made my setup as close to 100% as I thought was good. (26.5MB left)

After completing that, I wanted to restore from Time Machine, but alas, that did not work. So I did a fresh install of Mac OS X instead, and then restored from Time Machine. Much better, that worked without a hitch. The only thing to think about there was that while I had backed up two drives, I now only had one drive, so it restored one drive, and I had to move over the data from the second one. No problem, but worth noting.

At this point, I had my iMac from 2011, a 3.4Ghz i7 with 16GB RAM, booting from a fusion drive built of the 256GB SSD and 2TB drives it was shipped with. This is an awesome setup! The sound from my 2TB drive has always been quite noticeable, and it has been quite silent this weekend. I’ve been running “iostat -w 1 disk0 disk1″ all the time, and the 2TB drive has roughly 1/80th the amount of disk access that the SSD has!!! That is amazing, and a whole lot better than what I achieved with my manual setup! :-)

Also, I’ve had two kernel panics during the weekend. I cannot confirm that this is because of the fusion drive, but in the interest of full disclosure, I think I should bring it up. Patrick was very clear to say he would not recommend using this in a production system. I use it now on my home system, and I probably will for a while, but I have great backups, other machines to work on if this one fails, and a habit of living on the cutting edge. ;-)

My conclusion is that you should read Patrick’s writings and make up your mind if this is something you want to do. For my part, I have an iMac now that works exactly the way I want it to work, especially if I don’t get any more kernel panics. Of course, Apple doesn’t support this one bit, so if they make an update next month that kills of support for older macs, I’m out of luck. Don’t use this if you don’t have great backups, and don’t use this if you can’t afford your computer to be offline while you reinstall it and restore from backup. I have great backups and fall-back, so I’ll be using this setup, and report back on my dealing with it.

A last resource to mention is Andres Petalli’s write-up, there are a couple of good comments there as well.

 Posted by at 12:51 am
Sep 142012
 

The past month or so I’ve reviewed a lot of code, and one issue is cropping up all the time: too much use of @property

Suppose we have the class AlbumViewController that extends UIViewController, and is used to display information about a music album. In the view, we want to display a title, and some artwork. So we make our storyboard, and drop a UILabel and UIImageView into a view controller of the class AlbumViewController. Now, how do we hook them up? We’ve got really four alternatives:

1. Instance variables in the interface declaration

2. Properties in the interface declaration

3. Hidden properties

4. Instance variables in the implementation

Objective C, in Apple’s incarnation, doesn’t have any sense of private, protected and public variables and methods: everything is public.

Instance variables are accessible only to the class, and its subclasses.

Properties are accessible from any object that has a reference to the object that exposes these properties. This is the main reason for having properties. The second reason is if you want to have the getting or setting of a property to have some side-effects.

So, in the example above, if we choose properties, hidden or explicitly public, we invite other objects to manipulate these properties directly. Thus we need to inspect our interface: does it make sense to expose the UILabel and UIImageView directly? Can the class AlbumViewController handle that other objects will manipulate these views? Probably not.

Properties that would make sense, from a class interface perspective, would be setting the album title and artwork. Then you can keep the presentation of these as an implementation detail:


This way you have nice encapsulation, and thus make your class easier to use for the next person coming in to your project, or your self next week.

My issue with alternative #2 and #3 is that they are really the same: they expose the properties to the world, even though alternative #3 tries to obscure it a bit. If you write any kind of dynamic code using just the tiniest bit of class introspection, the methods will offer their service straight away. So unless your interface is to expose these properties, don’t use that. The only thing you’ve gotten extra out of this is having to ask people not to use your properties, and a slightly added cost to accessing your instance variables.

Alternative #1 is good if you want the instance variables to be available to subclasses, and make it clear that these should be considered. Again, there’s not all that much difference between this and alternative #4, but #1 is more explicit and readable, so it’s a great place if you expect it to be useful for subclasses.

Alternative #4 is my preference for everything that is just something I need to get my implementation of this class done. And I really think it should be yours as well, and is what should be taught in basic iOS training. Unfortunately, surprisingly many go for alternative #3, cluttering the interface with lots and lots of “hidden” properties, that aren’t hidden at all, especially not at runtime.

So to sum up: think about your interface and what you want to expose to the world. Expose only this, keep everything else as an implementation detail, unless you expect the class to be subclassed. Then you can expose some of the instance variables in your interface as well.

As a final PS, we’re not doing the compiler any favour going into these details, it will get its work done anyhow. But this is so that we can keep a clear interface when communicating with other developers coming into the project, using the project, and to your future self that is working on the project.

Now that I’ve posted my view, I would love to hear your opinions, especially because I would love to hear some good arguments in favour of alternative #3.

 Posted by at 11:43 pm
Aug 112012
 

Dear Friends, Followers, and random people of the internet,

Christina and I are expecting, and we just found out yesterday: it’s going to be a boy! :-) The doctors think he’ll arrive December 27th, we expect him to be a bit early.

We’ve been through all the usual tests, and everything looks good. He’s alive an kicking! ;-) So we couldn’t be happier, and it’s going to be an amazing change of life.

Cheers

   Christina & Niklas

 Posted by at 7:47 pm
Jul 252012
 

My camera marks HDR images quite clearly: They are a sequence of images, where the first second one and third one are equally many stops removed from the first one, and they’re usually within a couple of seconds from one-another, with all other settings the same. That sounds like something that should be easy to stack in the import-process, right? Preferably followed up by a rendering to a 32-bit pr channel image straight afterward that is set as the stack top image.

Unfortunately, I don’t know Lua, so I won’t write it myself any time soon. But such a trivial plugin should exist after all these iterations. Heck, it should be a core functionality!

As for grouping, possibly even a quick pre-rendering, I’d argue there should be a similar Panorama function.

Can anyone recommend any plugins?

 Posted by at 8:00 am
Apr 282012
 

Today I needed to work with an alertview, so here are two steps for pressing them:

Given /^I press alert button (\d+)$/ do |index|
touch("view:'UIAlertButton'")[index]
end

Given /^I press alert button named "([^"]*)"$/ do |text|
touch("view:'UIAlertButton' label text:'#{text}'")
end

 Posted by at 5:19 pm
Mar 242012
 

As promised, here are my reusable Calabash steps. Now, some of these are probably more inspirational than reusable (or ignorable, if you like ;-) ), but this is ALL the steps I use SO FAR apart from the standard steps. Like I said before, there are so many great steps already defined, so check them out. Anyway, here they are, all 134 lines:

Given /^I press the "([^\"]*)" tableviewcell button$/ do |cell|
touch("tableViewCell button marked:'" + cell + "'")
end

Given /^I press the "([^"]*)" label$/ do |label|
touch("view label text:'#{label}'")
end

Then /^I enter "([^\"]*)" in the "([^\"]*)" (?:text|input) field$/ do |text_to_type, field_name|
set_text("textField placeholder:'#{field_name}'", text_to_type)
sleep(STEP_PAUSE)
end

Given /^I press the "([^"]*)" segment$/ do |label|
touch("segmentedControl segment marked:'#{label}'")
end

Given /^I see the text "([^"]*)" to the right of the text "([^"]*)"$/ do |right, left|
leftRect = query("label {text LIKE '#{left}*'} parent view:'PdfThumbnailView'", :frame)[0]
screenshot_and_raise "Text \"#{left}\" could not be found" if(leftRect == nil)
leftX = Integer(leftRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
leftY = Integer(leftRect[/{(.*), (.*)}, {(.*), (.*)}/,2])

rightRect = query("label {text LIKE '#{right}*'} parent view:'PdfThumbnailView'", :frame)[0]
screenshot_and_raise "Text \"#{right}\" could not be found" if(rightRect == nil)
rightX = Integer(rightRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
rightY = Integer(rightRect[/{(.*), (.*)}, {(.*), (.*)}/,2])

screenshot_and_raise "The following texts should be on the same horizontal line: \"#{left}\" \"#{right}\"" if(leftY != rightY)
screenshot_and_raise "The text \"#{right}\" is not to the right of the text \"#{left}\"" if(leftX >= rightX)
end

Given /^I see the text "([^"]*)" beneath the text "([^"]*)"$/ do |bottom, top|
bottomRect = query("label {text LIKE '#{bottom}*'} parent view:'PdfThumbnailView'", :frame)[0]
screenshot_and_raise "Text \"#{bottom}\" could not be found" if(bottomRect == nil)
bottomX = Integer(bottomRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
bottomY = Integer(bottomRect[/{(.*), (.*)}, {(.*), (.*)}/,2])

topRect = query("label {text LIKE '#{top}*'} parent view:'PdfThumbnailView'", :frame)[0]
screenshot_and_raise "Text \"#{top}\" could not be found" if(topRect == nil)
topX = Integer(topRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
topY = Integer(topRect[/{(.*), (.*)}, {(.*), (.*)}/,2])

screenshot_and_raise "The following texts should be on the same vertical line: \"#{top}\" \"#{bottom}\"" if(topX != bottomX)
screenshot_and_raise "The text \"#{bottom}\" is not beneath the text \"#{top}\"" if(topY >= bottomY)
end

Given /^I don't see the "([^"]*)" button$/ do |expected_mark|
res = query "button", :accessibilityLabel
index = res.find_index {|s| s == expected_mark}
screenshot_and_raise "Index should be nil (was: #{index})" if (index != nil)
end

Given /^I scroll to "([^"]*)"$/ do |searchText|
res = query "TableView index:1 TableViewCell label", :text
row = res.find_index {|s| s == searchText}
scroll_to_row :tableView, row
sleep(STEP_PAUSE)
end

Given /^given I import "([^"]*)", "([^"]*)", "([^"]*)", "([^"]*)"$/ do |datasource, maindir, subdir, file|
touch("tableViewCell label text:'All files'")
sleep(STEP_PAUSE)
touch("tableViewCell label text:'#{datasource}'")
macro %Q|I wait until I don't see "Loading..."|
touch("tableViewCell label text:'#{maindir}'")
macro %Q|I wait until I don't see "Loading..."|
touch("tableViewCell label text:'#{subdir}'")
macro %Q|I wait until I don't see "Loading..."|
touch("tableViewCell label text:'#{file}'")
sleep(STEP_PAUSE)
touch("tableViewCell label text:'All files'")
sleep(STEP_PAUSE)
end

Given /^given I import "([^"]*)", "([^"]*)", "([^"]*)"$/ do |datasource, maindir, file|
touch("tableViewCell label text:'All files'")
sleep(STEP_PAUSE)
touch("tableViewCell label text:'#{datasource}'")
macro %Q|I wait until I don't see "Loading..."|
touch("tableViewCell label text:'#{maindir}'")
macro %Q|I wait until I don't see "Loading..."|
touch("tableViewCell label text:'#{file}'")
sleep(STEP_PAUSE)
touch("tableViewCell label text:'All files'")
sleep(STEP_PAUSE)
end

Given /^I remove all my documents$/ do
docs = query("view:'PdfThumbnailView'")
docs.each do |pdfView|
touch("button marked:'EditCards'")
sleep(STEP_PAUSE)
touch("view:'PdfThumbnailView' index:0 button marked:'card function delete'")
sleep(STEP_PAUSE)
touch("button marked:'Delete file'")
sleep(STEP_PAUSE)
touch("button marked:'EditCards'")
sleep(STEP_PAUSE)
end
end

Given /^I remove all my folders$/ do
if(query("label marked:'My folders'").count > 0)
titleRect = query("label marked:'My folders' parent view", :frame)[0]
titleX = Integer(titleRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
titleY = Integer(titleRect[/{(.*), (.*)}, {(.*), (.*)}/,2])

count = query("tableViewCell").count
i = 0
while i < count do
cellRect = query("view:'FolderTableViewCell' index:#{i} view", :frame)[0]
cellX = Integer(cellRect[/{(.*), (.*)}, {(.*), (.*)}/,1].split("{")[1])
cellY = Integer(cellRect[/{(.*), (.*)}, {(.*), (.*)}/,2])
if(cellX == titleX && cellY > titleY)
touch("view:'FolderTableViewCell' index:#{i} view")
sleep(STEP_PAUSE)
touch("view:'FolderTableViewCell' index:#{i} button")
sleep(STEP_PAUSE)
touch("segmentedControl segment marked:'Delete folder'")
sleep(STEP_PAUSE)

break
end
i = i + 1
end
end

macro %Q|I remove all my folders| if(query("label marked:'My folders'").count > 0)
end

Given /^I playback recording "([^"]*)" at label "([^"]*)"$/ do |movie, label|
playback movie, {:query => "label text:'#{label}'"}
end

 Posted by at 11:28 pm
Mar 042012
 

Everyone else is doing it, so I figured I could play “bingo” as well. :-)

My predictions begin with “one more thing” on the iPad event: iOS 6 and AppleTV are tightly linked. Developers will get access to iOS 6 betas within two weeks from the announcement, with another event where they go through all the cool stuff. But the AppleTV will be updated with an A5X processor and third party applications installed via the AppStore, and will sport Siri and iCloud integration in a way that makes it easier to use than ever.

The iPad 3 will be announced with an A6 processor, which has enough RAM to power the retina display. The A6 will be more or less identical to the Tegra 3. The iPad will ship with iOS 5.1, and will, together with the iPhone, get iOS 6.1 support this summer, iOS 6.0 will be AppleTV only. The iPad will of course get Siri support.

The main newcomer on the software platform will be Microsoft, shipping a full Office line (excluding MS Access) for iOS, multiplatform for iPhone and iPad, and with a tight AppleTV integration for presentation. The presentation will also focus on Microsoft and Apple having a great relation through iCloud.

iCloud will begin acting like more Dropbox in that it will let you share documents better between iOS apps and Mac apps, bringing iWork and iLife on the mac better integration with their iOS counterparts. This increases need for space, but the iCloud free space will rise. The iLife and iWork updates won’t be mentioned, but will come as a software update quietly a day or two after the show.

 Posted by at 11:27 pm
Feb 052012
 

For a project I’m doing at work, that I hope will eventually be open source, I needed to have protobuf compiled for iOS. A colleague of mine showed me how it had been compiled on iOS 4, using these scripts, but with iOS 5 I ended up with binaries compiled for the arm architecture instead of the armv7 architecture.

Be aware that the iOS 5 SDK actually ships with a version of protobuf, but it’s a bit old, being version 2003001. And it only ships the binary, not the headers.

To compile protobuf, grab the latest source (which is 2.4.1 at the time of writing this) and run the following script (download script):

After running this, you should have a directory called /tmp/protobuf/arm that is compiled for your iPhone or iPad with the armv7 architecture. Copy that into your project and start using protobuf :-)

 Posted by at 1:01 pm
Dec 182011
 

Kære alle

Kalenderen viser tydeligt, at julen atter nærmer sig med raske skridt. Vi skriver i dag den 4. søndag i advent og der er nu mindre end en uge til juleaften. Julegaverne er da også indkøbt og juletræet er købt, sat på fod og pyntet, hvorefter Silver har pillet de kugler og julehjerter ned fra træet, som han kunne nå. Som et af billederne viser, er vores juletræ således mest pyntet fra toppen og ned til midt på træt. Men det ser nu også meget sjovt ud med en kat, som kommer rendende med et julehjerte i munden eller bruger en julekugle som bold ;)

Silver er også en flittig gæst på klaveret, når vi spiler julesalmer, ligesom han elsker at sidde i sofaen sammen med os og se julekalender på tv. ”Ludvig og julemanden” har faktisk vist sig at være en overraskende god julekalender, og et par enkelte nostalgiske kig på Nissebanden på Grønland er det da også blevet til…

Den første weekend i december stod også i julehyggens tegn, da Niklas og jeg var på en weekendtur til Lübeck, hvor vi selvfølgelig fik både smagt og købt en del hjem af det berømte Lübecker marcipan. Desuden erfarede vi, at tyskerne er rigtig glade for juledrikke med en del spiritus i, hvilket medførte, at vi måtte vente et par timer ekstra med at køre hjem fra Lübeck om søndagen, da stort set alle de drikkevarer vi fik fat i på julemarkedet om eftermiddagen havde en del alkoholprocenter…

Sidste weekend bød på julefrokost, tangoworkshop, juletræspyntning, familiebesøg og den næsten obligatoriske gåtur til dyreskoven for at fodre dådyrene og kronhjortene med æbler, gulerødder og rugbrød. Desuden gjorde Niklas en god gerning med julehjælp i JCI regi; det er altid godt at kunne hjælpe de familier, som har det hårdt med lidt julevarer her i december.

I denne weekend har vi for alvor påbegyndt julefejringen, da Christinas mor og far, Hanne og Kjeld, havde inviteret os til ”førjul” i deres hyggelige sommerhus på Sjælland sammen med Christinas storebror Rasmus, svigerinde Anne og niecerne Freja og Emma samt vores tilsammen 2 katte og 1 hund. Dejligt at være samlet igen, og fint at kunne sprede julefejringen over flere dage.

Selve juleaften og 1. juledag tilbringer vi sammen med Hanne og Kjeld i Hjerting sammen med vores to katte, Dumbo og Silver. Den 27. december kører vi om morgenen af sted til Norge for at fortsætte julefejringen med Niklas’ familie og venner, som vi også fejrer nytårsaften med inden vi atter sætter kurs mod Danmark den 2. januar.

Det bliver dejligt med en lang juleferie efter et travlt år, der har budt på mange spændende oplevelser både privat og arbejdsmæssigt. På hjemmefronten med huset og vores ferier til Nice, Sardinien, Korsika og Norge samt vores fritidsinteresser, hvor dans fylder meget. Arbejdsmæssigt har Niklas skriftet arbejde, og er nu i Århus et par gange om ugen, mens han i det nye år skal starte en Esbjerg afdeling op for IT-firmaet Trifork. For Christinas vedkommende har det i efteråret og i december stået på omorganisering i kulturafdelingen, og efter adskillige timers oprydning og flytning rundt på næsten alle personers arbejdspladser, bliver det spændende at se hvad det nye år bringer af nye samarbejdsrelationer og opgaver.

Ligeledes bliver det spændende om der kommer sne igen i år til jul eller om regnen og blæsten fortsætter? Om ikke andet kan vi vel håbe på en hvid nytårsfejren i Norge med gode skimuligheder :)

Uanset om vi får tilført julestemning via sne eller ej, ønsker vi jer alle sammen en rigtig glædelig jul samt et godt og lykkebringende nytår.

På gensyn i det nye år!

Kærlig hilsen

Niklas og Christina

Nov 222011
 

From time to time I get the same problem: the application switcher (command-tab) stops responding. It usually takes closing a lot of programs or restarting to get it working again. Today, I seem to have found the gangster: Screen Sharing. When I closed it, application switching started working again. It must have taken over the control over a couple of keys too many.

 Posted by at 6:56 pm
Nov 182011
 

ubd wanted to connect to windows.net, so I looked it up, and it belongs to Ubiquity.framework, that is a part of the iCloud integration. Hmm…

The man-page says this: “ubd is the ubiquity server process. It is primarily used for “Mobile Documents. There are no configuration options to ubd, and users should not run ubd manually.”

 Posted by at 9:00 pm
Nov 012011
 

Tomorrow I begin work at Trifork! :-) There I’ll be doing iOS development, so before I begin I thought I’d like to share a bit about how I do my development now.

First of all, I use GitHub and Beanstalk for source control, depending on what client the work is for (for my own projects, I use GitHub). Mercurial is nice, but git and svn just work with XCode, so I stick to that.

Since I have source control, I can have continuous delivery. For that I use Jenkins. Jenkins is not good enough. It’s not great. It’s not beautiful. It’s not intelligent, easy, friendly, intuitive, or all those other nice words. But it works! I use the Clang Scan-Build, Github OAuth, Github, Pre SCM BuildStep, Redmine, SICCI, SSH Slaves and Xcode integration plugins, even though I’d get most things done by just adding a shell script. That gives me a build per commit, which is nice and reliable and brings the pain forward. Jay pain! ;-)

Of course, having this infrastructure in place begs for tests. Now I think tests for iPhone applications suck. Bigtime! The reason is that I hate deployment cycles. It takes time, and that time I’d rather use writing code, thinking about the application, solving real problems for my customer, preferably before he knows about them. If not that, I’d rather drink coffee, do chores in my home, or clean my pipes, rather than waiting for build cycles. It’s just an enormous waste of time. And tests for iOS drain time, as there’s no such thing as a unit test for iOS. Everything is an integration test or a user acceptability test. You always fire up the entire application before running any test.

So now I have that rant done, it’s great that I can leave my tests to Jenkins. It will perform them, and the output will get converted to what looks like a JUnit test so that it can get picked up by Jenkins’ tooling and be presented nicely. Jay! :-)

Then we get to deployment. My clients communicate with me. A lot! This should be different like so, I changed my mind about this, I’ve found a bug if you do like this and that. It’s great! I love my users for this! It creates such a momentum! So how awful wouldn’t it be if I said “I’ll collect everything and give you a beta in three weeks”? Continuous delivery isn’t just delivery to me, it is to the users as well. For this I use HockeyApp. They’re a great bunch and really responsive, and while they just don’t support iOS 5 well enough yet, there is so much good there. My app gets auto-deployed up there and my client sees the new release, hits install and boom! Now he’s running the latest build! :-) Crash reports get sorted by build numbers, and the guys at HockeyApp have told me they’re working at making the crash reports even more awesome! Jay! :-)

So how do I follow up on these things? I have to admit, I’m a cheapskate, so I use Redmine. I would use Basecamp, and I hope to be using it, it’s so awesome, but so far it’s not been worth the extra cost. The day it is, I’ll run and buy it quickly. My problem with Basecamp and Redmine? I just haven’t seen how I’d integrate it with my scrum sprints. Yet. I’m sure they both can, and I hope to learn from people that are wiser than me in this regard.

Finally, after a deployment to the appstore, I use Flurry to keep track of where my users are at, both in version of the app (why don’t they upgrade! This new version is awesome! I need to tell them more about it!) and the OS (really? They’re still on iOS 4?? iOS 5 has been out a month now! Oh well, not everyone is like me). Also, I’ve rolled my own crash reporting that, should I have failed horribly, the users can get in touch with me or the client, with a detailed log of what went wrong.

So, that’s my work setup this far, and I’m quite happy with it. It still needs better scrum integration. It’s still too many pieces that don’t talk sensibly together. But it’s getting better knit together, and I’m looking forward to seeing how Trifork does it, how I can improve based on what they have to teach, and how I can improve the way they’re doing it. It’s going to be great! Those guys are brilliant, and I love working with brilliant people.

Finally, if you’re in the Esbjerg area, working with iOS, get in touch with me. If you’d love to start working with iOS, get in touch with me! There’s an NSCoder Night coming up soon, biweekly I hope. :-)

 Posted by at 12:04 am
Oct 182011
 

Ok, everyone, let’s all calm down. There’s been so many blog posts and podcast debates all over the net about what’s wrong with Dart. The only problem with Dart, the way I see it, is that Google is too good at marketing: too much hype before we got to see the product.

The way I see Dart, it’s another language for doing client-side web application programming. Luckily, it’s not another Flash or Silverlight with its plethora of languages. It would like to be a part of the browser, but for now it contends itself to being a language that compiles down to JavaScript. That puts it together with CoffeeScript and Objective-J, to name but a few. See a long list here. As you can see from the list, this is nothing new.

The only problem with Dart is that everyone had their hopes up for the perfect language that would contain all their pet features. And of course, the set of preferred combinations is probably as big as the number of developers in the world.

What I find to be one of the strong points of Dart is that it uses the actor model as its concurrency model. I remember it well from my days at uni, thinking it was a model leading to waaay to much overhead. Surely, the Smalltalk guys must be mad! But as time has given us more power, I’ve come to believe that this is a great model, which has lead me to Scala and Akka. Although GCD is very powerful, I find myself looking into using actors in my language of choice, Objective-C, all the time.

So where does Dart go from here? Well, that depends on what kind of backing it has from Google. Google hasn’t been very clear on how well the Dart support is grounded in the organization. But if it gains a good community of libraries and evolves a good community, it could become the preferred way of writing Android apps, letting developers re-use code for their web-app and mobile app. If not, it could become shelved like Go.

Personally, on this front I’ll brush up my ancient JavaScript skills and look more at SproutCore the next couple of weeks, probably along with CoffeeScript. Then in a month or two, if there is any momentum going for Dart, I’ll probably write something where I can exploit Darts actor model and see if we become good friends. 2011 will be interesting still. :-)

 Posted by at 9:05 pm