Often I’m being asked why do I choose a particular technology, technique or a way when it comes to the iOS development. Instead of going through it over and over again, I figured out it would be nice to collect these thoughts in one place and then additionaly discuss them if needed.
While I don’t have religious beliefs when it comes down to development, things mentioned below are result of my sizeable experience with iOS, working alone and in a team and many, many hits and misses. What works for me won’t necessarily work for the others, nor are the other approaches wrong. It’s simply my point of view.
With that being said, working for a client is much more than just the development or a technology. Without going too far right now, let’s just say that many external factors play a significant role here. In my opinion, honest and open communication as well as ability to adapt are some of the most important. So I try to stay open and ready to adapt to client (or team) needs and wishes but if I’m asked how the project would look like in my best opinion, it would be something like below.
I usually don’t use Storyboards but write all of my UI in code. Yes, it can feel scary when starting a project from scratch and sometimes a little bit slower at first. But these are minor drawbacks for me comparing to what Storyboards usually bring.
And some of them are:
Complex revision control - sometimes just opening a Storyboard file will change a few lines in the underlying XML. Will you discard them every time? Commit them, bloating your Git history and potentially confusing your team members with no actual change? To this day I’m still not sure what’s the best approach. Additionally, merging this kind of files is a really time consuming task with cryptic ViewController IDs and other references.
Difficult changes - if you try placing your views inside a new parent (just to group them for example), Interface Builder will remove all parent relating constraints and you’ll have to start over. Hopefully you’ll have your constraint constants somewhere jotted down because everything get’s lost. While this doesn’t seem like a big deal for small stuff, it can quickly add up and lead to frustrations and it’s also time consuming. If you’re doing something like this in code, it should be a breeze.
Incredibly hard dynamic layouts - some would argue that majority of today’s apps are just shiny JSON printers. If that’s the case, you should definitely try to have the best one. In other words, most of the apps are backend based, and they’re not just pulling the data from there but also a UI layout descriptions. To achieve this kind of behaviour, Storyboards need to be backed by additional code, being it a simple referencing outlets or layout logic, which is kind of in contrast with their original idea - not having do the layout in code.
Black magic stuff - although one might say there’s no black magic because everything is transparent in the underlying XML representation if you are willing to dig. But the thing is, you actually have no idea what’s going on when deserialization happens at a runtime. There’s was a lot of Storyboard UI breaking cases when new Xcode would be released (remember device screen canvas, then switching to abstract quadratic one, then switching back?) so traditionally Septembers were usually reserved for Storyboard files fixing. By the way, I still remember the case when one UILabel’s property value was not properly serialized in XML.
Hardware requirement - although MacBooks feature probably the best trackpads on the market, they are still just a trackpads; using them with Interface Builder more than 5 minutes becomes a real pain. Although this is not a big issue most of the time, imagine yourself working remotely at a coffee shop. Also, a larger screen would be nice to have.
Several major drawbacks pushed me to do layout only in code. But as we know, writing entire UI was tedious job to do ever since AutoLayout first appeared so it’s not surprising we have so many layout libraries out there. As I’ll explain later, I’m not a big fan of pulling dozens of libraries into the project, even more so if they introduce another language (DSL), as many layout libraries do. Therefor I’m creating constraints using Apple’s Anchor API and to reduce a number of needed lines and remove the need to manually activate constraints every time, I use one small library called TinyConstraints. It’s basically just the added sugar so I don’t worry about it being obsolete or if I manually need to fix a bug.
Hopefully, you won’t get me wrong. I don’t hate Storyboards and actually use them for smaller hobby apps and prototyping (although a lot less since the SwiftUI appeared). They are very good for understanding application’s flow and if you will, act as some kind of documentation for navigation. Also, I find them very suitable for beginners in iOS development where they instantly can see how constraints work together. I think this is the main reason why Apple was pushing them so hard. But I just cannot recommend them for anything a bit more complex.
Sticking to “out of the box” solutions i.e. Apple’s frameworks is my strategy. Because of their commercial nature they are generally better tested and have first class support. Knowing there’s someone who got your back is really encouraging to try out new things and the fact that majority of other developers are using them mean you won’t be left alone to deal with the problems. Of course, there’s nothing wrong with using 3rd party libraries and frameworks but I like to keep them at minimum.
Dependencies are the topic for their own and deserve separate post so I’ll just mention a few things to back up my decision. If you are looking for a team member, chances are you’re going to find one more easily by sticking to Cocoa frameworks than if you use, for example, some obscure Reactive library. Also, you have better chances of reducing the technical debt this way because for example, it’s very unlikely Apple will discontinue Combine just like that. Even the SwiftUI which is meant to replace UIKit will slowly roll out and UIKit will still be here in upcoming years. Apple bets on the frameworks that are sure to last. They usually have more complete documentation (although Apple docs are often the subject of complaints), aforementioned support and are better tested.
I really enjoy myself in experimenting with new technologies from Apple although I start introducing them very late in a serious projects. As with any new technology, early problems are always there and you may be better off waiting for things to be polished.
Although I started playing with Swift very early, my first commercial project with Swift was based on Swift 4. I still think this was the best time to fully adopt it and I’m very glad that I missed Swift 2 to Swift 3 and Swift 3 to Swift 4 refactors. A huge time sink for nothing.
Of course I was bitten in the past and I’m glad for it because it was an important lesson. As game developer, I early adopted SpriteKit since back then it was the best documented OpenGL sprite library and I really liked it’s API style. Everything was working nicely until Metal was introduced and it had some serious performance issues. SpriteKit did automatically choose Metal on supported devices (newer ones) as underlying engine while older ones still used OpenGL. As a result, newer ones were struggling with any kind of a scene, giving in approx 5 FPS (think of a fast slideshow) and I couldn’t do anything about it. In fact, nobody could, a vast majority of games were affected.
Supporting iOS versions
It’s great having your app on as many devices as possible. But everything comes at a cost.
Android platform has a nice way of falling back to older OS versions when working with specific APIs but iOS doesn’t and probably never will. Apple’s policy is to make as many users as possible update since updates bring, except new and shiny features, a critical security patches. So in reality you have to do a lot of manual checking and adjustments, although to be fair, it improved a little bit from the Objective-C days. On the bright side, while Android still struggles with huge fragmentation, iOS fortunately doesn’t. A vast majority of users update and they do it pretty quickly. Every year when a new iOS public Beta becomes available, some of them rush to update so it’s probably better to look to the future than being stuck in the past. Current iOS versions are available on pretty old devices. For example, iOS 13 is supported on iPhone 6S device family which was released in September 2015., what is 4 and a half years ago. Even iOS itself does pretty good effort in smoothing the update process by automatic downloading and offering the overnight update.
So there’s really no reason not to update from user perspective. But still, some small amount of them don’t, not because they can’t, but because they simply don’t care. And chances are, they probably won’t care for your app either.
Is it worth to support a few years old iOS versions? In my experience, usually not. Just supporting older versions can be really resource consuming, and when it comes to the testing, a real burden for moving forward quickly, which is probably the most important thing in today’s world. And if you are developing specific kind of software, like modern games or Bluetooth connectivity software, having a real testing devices is a must. Since Apple doesn’t really support downgrading the iOS, number of required devices at your disposal can grow pretty quickly. Even if the money is not an issue, modern nomad lifestyle can be if you are in constant need of having those devices around you.
It’s a sure thing that Apple itself has a larger user base than any of my apps or the companies I worked for and more development resources, but their apps reveal a similar stance regarding the older version support. For example, at the time of writing, Pages, Numbers and Keyote requires iOS 12, Apple Developer 12.4, Garage Band 13.0, iMovie and Clips 13.4 (pretty recent). Only iTunes U had an older support for iOS 11.0.
With all that being said, I would choose to support one major version back from the current one. If the current iOS is 13.4.1 for example, I think supporting iOS 12.0 is reasonable enough. If there are some critical fixes, I wouldn’t mind raising the minimal required version to 12.4.
I think style guides are an absolute necessity in a team. They can help onboard new team members more quickly and avoid confusions and arguments since they provide a single source of the truth. Even if it’s just you, they are a great way to keep your sanity and avoid having to do some decisions over and over again. Also if you are developing in a consistent way, chances are many things will become automatic and speed up your process while reducing cognitive load.
Swift is still relatively young language and there isn’t any official style guide yet. Looking at how Apple guys do it can be a good direction but it ultimately comes down to your and your’s team preference. There are a lot of different public style guides (e.g. Google, LinkedIn, Airbnb) but one of my favorites is Ray Wenderlich Swift style guide. Preferably, with a couple of tiny modifications.
Also I like the idea of using Swift protocols solely for the alignment on the naming and where are particular things done - e.g. where are the constraints created, how we are adding and referencing subviews etc.