Category Archives: iOS

Mobile app development full lifecycle – part 1

Brainstorming

This is a really exciting stage. An idea hits you while travelling on the bus. What is missing from this world? A facebook for dogs of course! A million dollar idea.

In case you are a visual thinker, you quickly draw up screens in your head. You envision experiences, key moments in using the app. You quickly realize that this would be a very silly app, but that’s okay. It’s okay to throw out most of the ideas at this stage. Let the right side of the brain do it’s thing.

How about a pixel graphics creator app for iPad? Let’s work with this from now on.

Feature list

Let’s break up the app into a set of features. Put them on a list to be able to manage them.

Obviously a pixel graphics creator app needs a canvas.
Creating lines easily might be useful, put this also on the list.
The canvas will be zoomed in most of the time, yet it’s important to see the full picture in original size. This can be solved by a secondary non-interactive view with bird’s eye view.
Predefined color palettes! It’s hard to use color pickers, entering codes for colors are also not user friendly on mobile. Palettes solve this problem.
Animation support!
And so on.

When the list is done, let’s mark those features that are essential for the first working version of the app. These will be our MVP. We mark the canvas, secondary view, exporting, simple version of color palette as MVP. The rest are nice to haves for now.

Closing remarks

We should do a minimal market research at this stage. Check if there is a very similar app in the app store already. Even if there is, this doesn’t mean there isn’t room for a better one. But the app store is a very competitive place, with an awful search engine. It’s better to face the oncoming troubles of marketing early.

Mockups

Interface builder is great, but it’s not good for mockups. I personally use Balsamiq Mockups and pen and paper.

When I designed a side-scroller platform game for iOS and Android, I cut out from cardboard all the screen sizes I wanted to support and started to play with them. I wanted to provide pixel perfect graphics on key devices, I also wanted to minimize the amount of art work as I was really slow at that then. By playing with the cardboard I found the solution. The background was created for the biggest height, but also made sure that the middle section – where all the interaction happens – also fits on the smallest height device. The rest of the background is just for visual enjoyment, so it was not a big deal when the top and bottom was cut on small devices. This also enabled a nice feature of imitating an earthquake cheaply at a key point in the game. As the screen scrolled horizontally, I didn’t have a problem with the width.

All I wanted to say is to use whatever works for you. But if you are not working alone and have to share the mockups, using a digital tool like Balsamiq can be much simpler than, e.g. scanning your hand drawings.

The mockups helps in concretizing the product. It often turns out that many features simply don’t fit on the screen. You have to iterate on them a lot and sometimes have to make painful decisions. Like when a critical feature needs to be cut out.

When the main screens are finished, the main interactions, the application flow should be designed. Be vigilant to think about possible error paths at every step. You could spend most of your time implementing the error paths, not the happy paths. In case you can simplify handling errors on the UI side (like dedicated UI element to indicate errors asynchronously) at this stage, it will save you tremendous amount of time later.

When all the screens, and application flow is done. The last step in this stage is to show it all to someone. Get some early input. They could point out major weaknesses in the design. It’s cheaper to make changes now, than later during implementation.

I’ll continue with coding the first prototype in the following post.

Swift Set vs NSMutableSet

As of Swift 1.2 there is a native Set<> type in the standard library, see Swift 1.2 and Xcode 6.3 beta.

New native Set data structure — An unordered collection of unique elements that bridges with NSSet and provides value semantics like Array and Dictionary.

It sounded great. Another thing added to the done list.

Beware though, Swift’s Set and Objective-C’s NSSet and NSMutableSet have fundamental differences.

Just to not keep you waiting for the punchline. Set’s insert is actually an upsert (insert or update) operation. Other methods, like union and unionInPlace are also updating the existing elements if they were already in the set.

Different function names are not an issue, e.g. NSMutableSet has -addObject:, Set has insert(_:). So far so good.

Let’s check out the documentation.

NSMutableSet
- addObject:
Adds a given object to the set, if it is not already a member.

Set
insert(_:)
Insert a member into the set.

Is there even a difference? It’s not apparent at first, but there is a huge discrepancy. Let’s check it out with a small code.


class Foo: Hashable, CustomStringConvertible {
  let value: Int
  //Additional Information
  let addInf: Int
  init(value: Int, addInf: Int) {
    self.value = value
    self.addInf = addInf
  }
  var hashValue: Int {
    return value.hashValue
  }
  var description: String {
    return "{Foo, v:\(value), a:\(addInf)}"
  }
}

func ==(lhs: Foo, rhs: Foo) -> Bool {
  return lhs.value == rhs.value
}

I use Swift 2 here. You can copy the above code into a Playground.

To finish the experiment run the remaining code.


var s = Set()
// []
s.insert(Foo(value: 1, addInf: 100))
// {{value 1, addInf 100}} 
print(s)
// "[{Foo, v:1, a:100}]\n"
s.contains(Foo(value: 1, addInf: 100))
// true
s.contains(Foo(value: 1, addInf: 200))
// true
// Everything is okay so far.
s.insert(Foo(value: 1, addInf: 200))
// {{value 1, addInf 200}}
print(s)
// "[{Foo, v:1, a:200}]\n"
// Should have printed "[{Foo, v:1, a:100}]\n"!

These results shed light on the meaning of the short documentation.

Insert a member into the set.

It always inserts the element, even if it means it overwrites the existing element in the Set. It's not an insert it's an upsert (insert or update).

It's hard to pinpoint why this is a problem. Maybe it's not, I just got used to other kinds of APIs, like the C++ STL.
One fact is that it ruins a type of algorithm which I like to use. I now have to check for containment before every insert, which ruins the readability of the code. So I definitely got burned by this. (A simple solution to the latter is adding a checking insert function to the Set with an extension.)

I still got the feeling that this new API is wrong. I opened a bug report 24101520 about it. We will see whether this is a bug or a feature.

Just for the sake of completeness I included the NSMutableSet version too below.


@objc class Foo2: NSObject {
  let value: Int
  let addInf: Int
  init(value: Int, addInf: Int) {
    self.value = value
    self.addInf = addInf
  }
  override var hashValue: Int {
    return value.hashValue
  }
  override var hash: Int {
    return value.hashValue
  }
  override func isEqual(object: AnyObject?) -> Bool {
    if let object = object as? Foo2 {
      return value == object.value
    } else {
      return false
    }
  }
  override var description: String {
    return "{Foo, v:\(value), a:\(addInf)}"
  }
}

func ==(lhs: Foo2, rhs: Foo2) -> Bool {
    return lhs.value == rhs.value
}

And the evaluation.


var r = NSMutableSet()
// {()}
r.addObject(Foo2(value: 1, addInf: 100))
// {{NSObject, value 1, addInf 100}}
print(r)
// "{(\n    {Foo, v:1, a:100}\n)}\n"
r.containsObject(Foo2(value: 1, addInf: 100))
// true
r.containsObject(Foo2(value: 1, addInf: 200))
// true
r.addObject(Foo2(value: 1, addInf: 200))
// {{NSObject, value 1, addInf 100}}
print(r)
// "{(\n    {Foo, v:1, a:100}\n)}\n"
// Prints what one expects. No update here.

Don’t tie your engineers hands

This blog post is about how companies waste a lot of time and money by forcing a bad method of working on their mobile engineers.

It usually starts with the old and seemingly wise observation that writing code twice is bad. Now some managers stop right here and make this a mantra for the company. By which they hurt their own business. I’ll explain why and show that implementing the “same” feature twice is sometimes the best thing one could do.

I’ll walk through some common scenarios that comes up at companies, like they have an iOS app and they want to port it to Android ASAP. At the same time I’ll probably rant about my previous bad experiences.:)

At first a little about me. I started working on Android in 2009, and on iOS in 2010. I use mostly C++, Objective-C and Java on mobile. I worked both on apps and mobile games.

1. Don’t use the same UI on all platforms

This isn’t that common nowadays, but almost every company made this mistake when they started working on Android. Usually they had an already successful iOS app and they wanted to release an Android version. Android was nowhere near as important for them as iOS, so they wanted to cut corners wherever they could. They started by reusing the design of the iPhone app. A phone is a phone, what harm could it do if they look the same? Well, as it turns out plenty.

Let’s first look at it from the high level. The problem is that every mobile platform has different UI patterns. Users gets accustomed to their chosen device’s UI. If an app uses a different pattern they will get confused or even get angry. One good example is when there is an iOS Back button in an Android app, and to make it worse it does not respond to the hardware back button (which is present on every Android device). This often means an instant uninstall.

But this choice will affect the engineers work too. If a UI pattern is not present on one of the platforms, then they have to implement it from scratch. It means wasted time, and bugs. But even when they have a seemingly similar Widget on both platforms, subtle differences in them could cause a lot of problem. I’ll talk about an example in detail below, but before that I’ll mention an exception.

Exception to this rule

If the existing app already has a unique UI then it perfectly makes sense to use the same design on both platforms.

Personal experience

I started working at Ustream in 2009. I spent almost 4 years there. We made the same mistake as above. Our first Android app used iOS buttons. We didn’t make all the mistakes that can be made though, like not responding to Android buttons, but it still looked liked an iOS app. I actually loved that first version.:) Because the Android UI was super ugly back then compared to iOS.

Half a year later they split the Android team, and I became the lead of one of them. We worked on the core apps and the other team started to work on a new ambitious product. Their product manager wanted to use the same UI patterns on both iOS and Android. He knew and liked iOS, so naturally this meant tons of extra work for the Android devs.

Where this approach failed miserably was the TabBar (TabActivity) widget. Android had a TabBar just like iOS. Seemingly the only difference between them was that the buttons were at the top on Android. As it turned out the Android implementation was so horrible, it was unsuitable to be used in a real app. Google get rid of that view later. There is a better one on Android now.

When the engineers realised this they tried to convince the product manager to use a different pattern on Android for this particular feature. They didn’t succeed. So they ended up reimplementing an iOS like TabBar on Android. It turned out to be a huge task. What supposed to be a simple few days long task became a several month long job. In the end, for various reasons that product was cancelled, and the product manager has been let go.

Conclusion

Unless your app already has a very unique UI, use platform specific UI patterns. By the way, this is a prerequisite for the app to became featured in it’s app store.
It means more work for the designers, but it also means much less work for the engineers as they can use the best design patterns for the given platform.

An important fact of the mobile platforms is that they evolve very quickly. If you force to put extra layers on the APIs in any way, you’ll find that most of the time is spent on maintaining those layers. And you will cut yourself off from using the new best patterns, or the hottest new features. For these reasons I always recommend using the native APIs for app development and suggest to stay away from PhoneGap and similar offerings.

2. Feature parity should not mean source code parity (apps)

For many companies feature parity across all platforms have the highest priority. The problem is that – in my experience – most companies wants to achieve this by forcing source code parity. Like having the same classes in Java and Objective-C. Or generate code from one platform to the other. Maybe there is something wrong with me, but I never understood how and why one leads to another. :)

Personal experience

There were several mobile teams at Ustream. (Symbian, iOS, Android, Blackberry, Windows Mobile, Maemo …) Implementing Ustream on mobile was very challenging, as there was no public API on any platform for what we wanted to do. Sharing best practices and even code – when it made sense – came up constantly. There weren’t any arranged meetings to discuss these. But we were sitting close to each other and were always curious how the others solved a difficult problem on their own platform. I enjoyed working there a lot at that time.

We naturally knew that as the platforms are so alien to each other, there is little room for sharing codes between them. We had a C library that was shared between the iOS and Android teams for a few common tasks, but nothing else.
But this doesn’t mean that we didn’t port codes from one OS to the other. We did that several times, but on the other hand we found that making time to adjust the code for the given platform always worth it in the end.

Interestingly enough, it came up once that the BB team and the Android team should share the same code base, because you know … both use Java. ;) But thankfully the managers quickly rejected that idea.

BB had Java ME (based on Java 1.3), Android is based on Java 1.5, and our code base was a combination of C, C++, Java and ARM assembly. So comparing BB and Android is like comparing Java and Javascript. ;)

Conclusion

The most important thing is that the teams owned their own code. We could use the best design patterns, the best tools the platform provided to us. I can’t emphasize this enough.
Every team was as fast implementing a new feature as fast they could get. We were not hindered by adhering to anyone. But we shared our knowledge and ported code from each other when it made sense.

Exception to this rule

None.
Seriously, do yourself a favor and stay away from JS on mobile.:)

2. Feature parity should not mean source code parity (games)

Let me start with an exception here, because it’s more important.:)

Exception to this rule

If you start a game from scratch – as games usually don’t use OS specific features (or only a few) -, I think the best approach is to use a cross platform engine. I would prefer to use my own C++ engine. But Unity or the Unreal engine could be a good choice too.
LibGDX is very good for Android, and it’s cross-platform, but I personally wouldn’t use it for iOS.
I don’t recommend cocos2d-x. It’s one of the ugliest engine out there that you can find.

Porting from iOS to Android

The most common scenario is that you have a cocos2d game and you want to port it to Android.

I think there isn’t a good approach for this. There are only bad ones and super bad ones. I think the best thing you could do is to rewrite it from scratch in a good cross platform engine. That way at least the team could learn a more useful engine.

Having two separate teams, one for iOS and one for Android could work too, in that case they could use the best engine/methods on their chosen platform. Reaching feature parity can be reached easily by having the same product manager (or producer) for the teams. They would probably implement a given feature in a different time scale, but they would usually be a lot faster than if they would have been tied by shared code somehow.

And here comes a super bad choice.

Use cocos2d-x, just because it has a similar API to cocos2d.

Objective-C devs might like this at first, as cocos2d-x use similar design patterns as objective-c. But as they get to know C++, they would either start hating C++ for not having a dynamic runtime or would start hating cocos2d-x for being the ugliest C++ engine out there. Did I mention that it is also slow? :)

Reaching feature parity would be the least of your problems. Because you would encounter a scenario where one thing works in cocos2d, but it doesn’t work in cocos2d-x. Then you either have to hold back the cocos2d team, or you would have to release a lower quality game on iOS. I think no sane game dev wants to use cocos2d-x the second time.

Porting from flash to mobile

This is another common scenario.

I don’t know ActionScript well. But I think it’s common knowledge now that it’s not good for mobile. I think most companies doesn’t think to reuse ActionScript code on mobile. When this time comes in a company’s life it is best to hire engineers with mobile experience.

Personal experience (cocos2d-x)

I worked for a few months at a game dev company. I was hired to find the best approach porting their existing iOS (cocos2d) games to Android. They already worked with an external company who ported one of their games to Android. I think many things can be learned from their mistake. They choose cocos2d-x, because well, it looks like cocos2d. This seems a reasonable move if you don’t know already cocos2d-x. After that, their approach was that every other week they manually rewrote every objective-c line to c++. This is where I threw an exception. :)

My first reaction was that I was amazed that this method worked. I mean they reimplemented half of the Foundation framework, some of Cocoa Touch, they even found a way to mimic objective-c’s runtime. I think what they achieved there is commendable. On the other hand the end result was a much slower game, than the original. The code was super ugly. The engineers did not own the code. They were more like robots, who manually rewrote every line of code to cocos2d-x. They were game devs who were forced to never made a single creative decision during work.

They worked like this to reach feature parity on both platform. The funny thing is that as far as I know they never get there. The iOS app was always several steps ahead of them.

The entire rewrite took them more time than what the iOS team needed to release the original game on iOS. I think this alone would have been enough to abandon this method forever. But the end of the story is that I couldn’t convince a manager to try out a new approach instead of this completely broken one, so I didn’t stay there long.

Conclusion

I think it’s always a bad move to tie your engineers hands in any way. I’ve yet to see a good enough reason for that. The sad truth is that most of the time when I encountered this at different companies, they didn’t reach their original goal. Sometimes rewriting a code from scratch is not the worst choice you can make. Reaching feature parity does not require to bound two source code together. By doing that you would instantly put a serious burden on every engineer in your team, with little hope to achieve the original goal. Sharing knowledge between teams is much more important than putting artificial chains on them.