Rapture In Venice, LLC

:: Freelance iOS Development & Team Augmentation

What Can RIV Do For You?

 

  • Print
  • Facebook
  • Twitter

It’s Been Real, Android: Why I’m Retiring From Android

Update 10/13 – Due to the overwhelming response, some updates were made to clarify my positions on things. Also, take note, there’s plenty to like about Android development, too! (No provisioning profiles, amirite?) I only focus on the warts because I’m explaining why I left Android.

This week marks my final week of working on Android. I’ve had my ups and downs with it, but I’m excited to retire from Google’s mobile platform.

Very excited.

OK, story time…

How I Got Started With Android

I began dabbling with Android about a year after boarding the iPhone train. Prior to that, I’d spent a couple years writing Blackberry and Java ME apps. (What are thoooooossseee?) Having become comfortable with iPhoneOS (that’s what it was called back then, look it up…), Android was starting to take off and I was curious to learn it. I taught myself for a while and then took a course from my then co-worker, and now world renowned author, Tony Hillerson.

Around that time, I got tasked to work on an Android bank project with a platform superfan, Josh Jamison. It was my first chance to do daily Android work and…it…went…poorly. The tools were in their infancy and Eclipse was downright awful compared to Xcode. Everything was slower. Compiling, Running. The emulator was freaking useless and Genymotion didn’t exist yet. I didn’t have an Android device of my own to test with, either. I’d been so comfortable with iPhone’s environment and Android just felt so raw.

It was a miserable experience. No matter how hard I tried, I just couldn’t get in a groove. I was an awful Android developer until mercilessly I was moved to another team. (I don’t recall being fired from it, but I wouldn’t be surprised if I was.)

Over the next couple of years, I dipped back in and finally acquired my own hardware. (A Nexus S.) The tooling was improving and re-learning the platform gave me new insights and I started to grok things a lot better. After moving on to Double Encore, I started working on more Android projects and even led one. (Whoa.) Android developers were still a rare breed, but the community was drastically improved.

Soon after, I embarked on my own and turned Rapture In Venice into a full-time consulting studio. To my surprise, I was getting contacted for Android work a little more than I expected! Of course, I took it on.

In the 5 years Rapture In Venice has existed, I’d estimate I’ve spent half that dedicated to Android. I’ve done co-location work for it, built Android apps alongside iOS implementations, ported apps to Android from iOS, and even found time to create my very own app for the Google Play Store.

Even more shocking, I switched to a Samsung S6 edge+ as my personal carry for about 6 months!

That leads me to today…

My Retirement From Android

My decision to officially abandon the platform didn’t happen overnight. In fact, it’s taken two years of consideration and false starts.

For a long while, the “hybrid” mobile developer (knowing iOS and Android) was a rare sight. I took pride that I could do both. As a consultant, I could sell myself on someone who could write both versions of an app for a client. My fluency in both made me an asset for porting jobs. I relished it.

As time wore on, more developers were trying out both sides of the aisle. True hybrids are still rare, but there are many developers who have familiarity with both platforms now. Still, why would I leave one behind? I’ll tell you why.

Over the last couple of years, the unsettling feeling that I’m becoming a mediocre developer for each platform has crept over me. While it’s not true, and I have confidence in both, that feeling comes from the fact that I can only be half-engaged in each community. With each major conference, I can only watch a subset of the talks. With each new feature added to the platforms, it’s 50% harder to remember it all. I miss out on some new concepts while learning others. Even the basics have become unsteady.

Take, as an example, the simple concept of shared user preferences. iOS and Android both support this with NSUserDefaults and…SharedPreferences I believe? It’s funny, I always forget the name of it and have to try a couple autocompletions to recall it. Which one can store arrays? (It’s iOS.) Which one can store data in different buckets? (It’s Android.) Is it setBoolean or putBoolean? Do I call synchronize or commit. (Or apply now?) It’s hard to enough to remember an API clearly, let alone when you’re using two very similar API’s for two very similar platforms.

It’s just gotten too much and it’s hard to keep steady as an expert in both. On top of that, the value of knowing two platforms isn’t as helpful as it used to be. Sure, if I’m lacking work, I have two avenues to find more, but it’s not feasible for me to do both platforms for one client. They can simply use two resources at once nowadays. Apps aren’t as small as they used to be either, so there’s no value in my doing both.

The day-to-day of switching between platforms is also difficult. I’m currently finishing up a project where I’m doing maintenance on both apps for a client at the same time. I’ll switch from iOS to Android multiple times a day. Two different IDE’s, two different languages, and two different concepts of what the UI should behave like. It’s not easy to context-switch in this way. Every feature is implemented two different ways between them, too, so I have to solve every problem twice.

Finally, the biggest hurdle trying to work for both platforms at once is keeping up with new libraries. I spent the first 3 months of 2016 on an Android project with a team using newer programming paradigms I’d not yet experienced such as RxJava. When you’re switching between platforms as a developer you’re trying to get your frame of mind right and it depresses your willingness to check out a new way of doing things. Retrofit? Hang on, I barely remember how to use Volley, so I’ll try just maybe that on the next project…k?

Wait, what is picasso? Oh wow, I hadn’t heard of that one…I was busy learning Swift.

Goodbye, Cruel Android

Once I decided I had to pick one platform and stick to it, the only question left was which one.

As it turns out, that decision was an easy one.

In my opinion, over the last couple years, the Android development environment has broken down. Here’s what I’ve seen:

  • Google’s adoption of gradle has been a disaster and proved to me to be a terrible decision. It did help out with some previous deficiencies, namely multiple app targets, but it’s slowed down compilation severely. It also makes for masochistic configuration files with major redundancy and fragmented dependency hosts. Getting an app to compile shouldn’t be a challenge.
  • Multidex. My god, Multidex. It’s incomprehensible that Android can’t handle something as simple as keeping track of a few thousand methods, a limit easy to get to as it counts the SDK and your libraries. Multidex kills build times, has led to strange compilation problems, and even needs to be configured differently based on the version of Android you’re running on.
  • Fragments are another Android concept that has made life unnecessarily complex for the Android developer. Introduced when tablets came into being, they were better than the classic Activity but have always felt hacked in. This is when Android developers began living off the support libraries. It took years before I used a native Fragment and, even today, I’m not sure that’s even a good idea. I almost wish Android would’ve just redone the concept of Activity/Fragment and started from scratch. Today, some developers stick to using Activities as much as possible while some always use Fragments. You’ll never meet an iOS developer that doesn’t use a view controller, but the most basic of UI concepts in Android make for holy wars.
  • Interoperability is another source of unnecessary agony for developers. From the earliest days, the expectation was your application should run activities from other bundles and was expected to share its own with others. As it turns out, very few apps are designed to be used by others…but the architecture still has to handle it. This has led to a difficult environment to pass data between Fragments (using bundles) and special code to handle the simple act of rotating your phone. Passing data around can feel dirty and it takes a lot of effort and care to be sure your activity can be rebuilt from scratch while preserving its state.
  • AsyncTask. Years ago Google added this class to the API to “help” developers with background processing. Since then, endless blog posts and discussions have gone into how to use it properly. Google themselves didn’t account for phone rotations, finishing activities, lifecycle changes, and so on. Today, there are endless alternatives to this terribly thought-out helper and it began a trend of many Android tools that were poorly contrived and have led to tons of confusion. (Just look at how many different ways there have been to have a tabbed interface.)

Lastly, the development lifecycle is just so slow. In the beginning, the emulator was nearly unusable. Running an app sometimes didn’t work and you had to spend 2 minutes restarting the thing. Copying the APK takes a while, too. The best way to develop is directly on the hardware, but come on. Genymotion came along and made emulation better for a while, but recently even that became unusable with newer gradle versions and Instant Run.

And, by the way, did they ever get Instant Run to work right?

Maddening.

So there we go…my days of writing Android code are done. I’m still left with an understanding of how it works and I’ll be able to understand Android code for a long time, but I’m truly excited to go back to being laser focused on the latest and greatest iOS has to offer.

Sorry, Nouget. I never knew ya.

Goodbye.

  • Print
  • Facebook
  • Twitter

, ,

Time for Apple to Retire the 16GB iPhone?

Stock checks around Colorado suggest there’s far less market for a 16GB model iPhone. Considering the size of apps, photos, videos, expansion of the OS itself, and how difficult it was to upgrade to iOS 8, seems many people are leery.

Time to retire it, Apple?  How about a base 32GB model next year?

Screen Shot 2015-09-26 at 9.36.54 AM

The day after the 6S release, stores across the country are left only with 16GB models…and gold. :-)

  • Print
  • Facebook
  • Twitter

Apple Quality is Down the Shitter

In 2007, I got a job with EffectiveUI here in Denver as a Flex Developer.  I’ll never forget my first day there: I was sitting alone at my desk for almost the entire day with nothing to do because nobody there had thought to have a computer ready for me when I started…

(I actually spent my first few weeks with nothing to do, but that’s a whole different nightmare of a story.)

So, it’s the afternoon and the lady who was tasked with coordinating with the guy who was lazy about going to the Apple Store in the first place comes over and I think she has my laptop!  It’s going to be a Mac Book Pro and I’m both nervous and excited because I’d never used Mac up to that point.  First, she pulls out a skinny notepad from a sheath and is handing it to me and now I bet she’s going to grab my new lap–hang on…

That’s…my laptop?  What the hell?  That’s the laptop?  Holy hell it’s skinny…!

So began my love affair with Apple.  The beauty of the machine. The ease at which I picked up on OS X. (I lept in on Tiger.) Soon, the iPhone would come out and what gloriousness it was!  Then later the iPad.  For me, Apple was miles better than PC’s and had the hardware you just lust for!

I thought it was a marriage that would last.

Maybe not.

A Series of Unfortunate Events (2013-15)

The past few years have been a nightmare as an Apple user.  Quality has gone way downhill as Apple insists to get in a macho arms race for technologies nobody’s asking for and fewer people needed.

First, I had to replace my iPhone 5 not once but twice.  Each due to problems with the hardware buttons.  I mean, seriously, we’re talking about the buttons.  While Apple is building a fucking spaceship in California right now, they can’t make sure something as simple as a button can be stable?

Alright, chalk it up to bad luck.  Yet next, Mavericks comes out, and that’s when I learn that Finder has taken a nose dive.  Since its release, followed by Yosemite, Finder has consistently had problems simply copying files.  It can hang.  You have to know how to relaunch Finder.  Any time I need to replace one I cross my fingers.  Something so simple…yet my faith wavers.  To this day.

Then comes Continuity, the ability to move between your Mac and iPhone or iPad “seamlessly.” I was puzzled as to why Apple would invest so much time and effort into allowing someone to edit a Numbers file on their iPad and then magically continue it on their iMac.  I can’t see how simply hitting save and then opening on the iMac is that big a deal.  However, I’ll be the first to admit how useful I found it to send SMS messages from my desktop.  It kept me focused on my work while I communicated with friends and family (and Craigslist sellers from whom I was buying games, games, games!)

Yeah, sending SMS messages was great for the few months it worked.  It’s been a year since it stopped, though.  I’ve googled, re-configured devices, pretty much everything and can’t get my phone to talk to my desktop anymore.  Nor my laptop!  It’s ridiculous.  One tiny little feature in a whole set that I liked, and it no longer works. Fantastic.

Let’s talk about my saga with Time Capsule.  Tired of my sketchy Linksys and in need of a local backup solution to replace unreliable online services such as Carbonite (sucky client) and Backblaze (the backups said they were happening, but they weren’t), I plunked down $400 for a Time Capsule.

This wireless-router-and-backup-system-in-one would be freaking great if it actually worked. To be fair, the wifi part has been excellent.  Yes, I still have to reboot it from time to time because it’s 2015 and we still can’t have reliable wifi routers, yet it’s the backup system which has been a nightmare.

The first one I got would have this problem where, every so often, the backups would start failing.  I’d reboot it and, presto, they’re working again!  Cool.  Then a few days later, nope, it’s down. Eventually, it never worked anymore  Finally, I brought it in to the Apple Store and the (figurative) genius replaced it for me.  Alright, it was just a bad one, let’s bring this puppy home and enjoy stress-free backups now!

Not.

My new Time Capsule worked for a month or so without problems, but since then, I’d say every month, the dreaded, “It’s been 10 days since your last backup” message will pop up on my three machines.  The Time Capsule is still doing wifi, but the backup system is stuck.  Nothing fixes it except a power cycle.  Oh, joy.  That might sounds like not a huge deal but realize that this is the backup system, not the wifi.  When wifi starts failing, rebooting it works and it’s really no big deal.  For backups, I only know something had gone bad a week and a half after the problem starts!  There’s no option I can see that will warn me when just a day goes by without a backup.  I just have to manually check each day I guess.

I put up with it, but it’s bullshit.  Two broken Time Capsules?  Hardly likely.

How about iCloud?  Once again, this was a technology I didn’t think I really needed, but it has proven useful.  For one, it’s an easier way to backup my devices.  For a progressively smaller amount of money each month, I can back up all my photos to the Internet. Sweet! Better yet, those photos sync to all my devices so when I take a picture with my phone it will immediately sync with my desktop!

Well, almost immediately. Pretty quickly.

Uh, maybe after a few minutes.

OK, hours sometimes…?

Alright, honestly, I have no fucking clue when the photos will sync.  Sometimes it’s pretty quickly and sometimes it takes days.  The general rule of thumb is that when it would be really handy to sync quickly, it never happens. I never have a problem with Dropbox…but iCloud?  Oh, man.  Problems all the time.

Along to the rescue is…Photos for Mac! This handy app replaced iPhoto because…well…I don’t know why it replaced iPhoto.  It has less features, looks ugly as shit, and best yet…it does not support the ability to drag and drop from the app itself into, say, a file selection dialog.  That used to be really useful, but Apple says Photos is better for me. And, after using it for many months, I still can’t really tell you if the iCloud synchronization happens when it’s open or in the background.  I don’t know because the syncing has gotten worse.  Won’t somebody tell me?

(Oh, hey, I just ran the app and it looks like the two photos I took this morning finally synchronized over to my desktop. Too bad I emailed myself the files 10 hours ago.)

h6UmLjR

Moving to my iPhone, let’s see, I’ve had a whole slew of problems: spontaneous reboots, apps like eBay breaking under iOS 9, many graphical glitches in apps ever since iOS 7 drastically altered UIKit for no real reason, hooking it up to a charger may or may not actually initiate charging, they moved the power button to the side (directly across from the volume buttons) so I take lots of accidental screenshots of my phone now, and the best part has been when Apple decided that being the only phone that knew how to handle portrait/landscape photos correctly was not enough and opted to fuck it all up instead. (How am I supposed to laugh at Android users posting sideways pics on social media when I can’t tell who’s who anymore?!)

And we can’t forget the Apple Maps launch, can we?

What the Hell Happened?

I’ll tell you what happened and it’s simple: Apple has gone away from iterating on tight, well-tested systems and shifted to pumping out huge, complex technologies that the PR department can make hype commercials with.  We’ve seen Continuity, iMessage, iCloud, Game Center, Apple Pay, Flat Design, Siri, Apple Maps, PassBook, Touch ID, Facetime, iBooks and the list goes on and on.  Some of these are really great, too!  But, look at all the technology and integration that goes into each one.  It all has to be re-tested for every update.

Digging a little deeper, there’s a lot of blame to place on the changes to the Developer API.  In the early days of iPhone, the API was clean and easy to work with.  Then, Apple started introducing an endless chain of expansions that do nothing but lead to buggy code:

  • A Core Data persistence system that makes thread-based data access trickier than achieving alchemy.
  • iCloud integration with Documents that’s extremely hard to code correctly and even harder to test.
  • The complete UI redesign in iOS 7 is so incredibly, unnecessarily complex that apps today still have bugs related to it.
  • Pulling autorotation responsibilities out of UINavigationController.  That one change caused so much pain for so many people.
  • Swift, the language Apple hopes to replace Objective-C some day, is designed by the Antichrist and? only! gets! { worse? }.with! each? iteration!
  • Speaking of Swift, using the debugger has been a much buggier, slower experience ever since the new language showed up.  Anyone else notice this?
  • Provisioning profiles are actually harder to deal with in 2015 than they were in 2009. (Do you want to fix this?  NO!  NO, XCODE!)
  • Storyboards are incredibly powerful except that they’re so incredibly frustrating to work with in the editor. (It also causes Xcode to crash more than anything else.)
  • More devices per generation, with more variety, requires many more releases per iteration.  The list of beta builds when a new release is out makes even Android blush.
  • Custom keyboards seemed like a great idea until every single iPhone user complained how broken they were.  And still are.
  • You now need to provide no less than 149 app icons to ship your app.
  • Even launch images are over-complicated these days!
  • Autolayout.  Need I say more?

There’s no one thing that has brought us to this point.  In my mind, Apple is stretching itself thin in trying to maintain so many devices, technologies, and features at a stable level.  In getting the complicated things working, they fail to keep the fundamentals such as file copying stable. Fixing a bug requires a lot of cross-device testing, too, so updates come slower as well.

Whatever it is, it’s come to the point where I’m considering not only a switch to an Android device, but stopping iOS development completely, too.  I don’t want to, but right now keeping up with iOS SDK “advances” (I can’t air quote this enough) is a monstrous headache.  I’m still catching up with advanced UICollectionView stuffand that’s years old now.

*sigh*

Apple.  Fix this.

  • Print
  • Facebook
  • Twitter

, , , , ,

Developing a Local CocoaPod Alongside Your iOS App

Whether you’re an independent developer or a large team building apps for multiple clients, there’s no better way to improve your efficiency than by collecting your most useful code into one re-usable, unit-tested framework.

Today, I’m going to show you a great way to use CocoaPods so that you can simultaneously build your Swift apps while locating generalized solutions into their own standalone Pod.

Let’s Create Our Pod

The first thing we’ll do is create a Pod that will store all of our handiest classes, components, and extensions.  We start by creating a project for a Swift framework:

Choose "Cocoa Touch Framework"

Choose “Cocoa Touch Framework”

Name it however you like and make sure it uses the Swift language.  I’ll call mine Tilikum:

Call the framework whatever you like, but I'll dedicate mine for the poor, imprisoned Orca. :-(

I’ll dedicate my new Pod to that poor, imprisoned Orca named Tilikum. :-(

Now, let’s write ourselves a useful little extension for the String class for this example. Obviously, a lot more work will go into this later, but for the purpose of this tutorial we’ll simply get things started with something small.  Here’s our code:

A little extension to get us started...

A little extension to get us started…

This extension adds a length property to the String class.  We’ll add more down the road, but this is enough to demonstrate our Pod setup.  If you’ve never written a framework before, be sure to mark the extension as public, too, or else the code can’t be accessed outside of it!

OK, the extension is done, but we’re not ready to move on to our application until we write some unit tests first!  Remember, the best part about centralizing all this code is that it allows us to properly unit test in an organized manner.  You’d never copy the unit tests around along with the code…go on, admit it.

Let’s add the tests:

By adding unit tests we not only keep the code in one place, we pledge to harden it with unit tests!

By adding unit tests we not only keep the code in one place, we pledge to harden it with unit tests!

Alright, the code is all done, so now we need to turn this project into a bonafide Pod. Assuming you have CocoaPods installed, let’s hit the command line with this to create a default Podspec

This will create a starter Podspec for us.

This will create a starter Podspec for us.

Make whatever changes you like to the default file, but do make sure you change the source_files value to something like this:

s.source_files  = “Classes”, “Tilikum/*.swift”

Build and voila! Congratulations, your Pod is ready to go!  Next, we’ll create an app that uses it.

Let’s Create Our App

With the Pod created, we can have as many apps as we want using it…but let’s start with just one.  Once again, we create a new project, this time a regular ole iOS Swift app:

This TilikumClientApp app will use the useful code we keep in the Tilikum Pod.

This TilikumClientApp app will use the Tilikum Pod.

Note that there’s no requirement that we share a workspace or working directory or anything with the Pod.  The Pod is completely independent of our app. The only requirement, obviously, is that our app uses Cocoapods so that it can access Tilikum. Let’s configure TilikumClientApp now.

First, we integrate Cocoapods and create our Podfile:

This created the default Podfile.

This command creates the default Podfile.

Now, the important part: we add our Tilikum Pod to the project.  Usually we’d do this by adding a pod specification found in the main Cocoapods repository, but this time we’re going to point it at a local path:

Point to your local Pod and don't forget to add the use_frameworks! method or your Swift framework won't be linked in properly.

Point to your local Pod and don’t forget to add the use_frameworks! method or your Swift framework won’t be linked in properly.

This syntax points to the Tilikum Pod that’s located in the same parent directory as the app.  If you want to store it elsewhere, you can, but if you’re working with multiple developers make sure you agree on a hierarchy that works for everybody.

There are many benefits to pointing at a local directory rather than an online repository:

  • You can freely add new code to the Pod while you’re working on the app.
  • You don’t have to commit or push any code and you certainly don’t need to cut a new version of your Pod for every single change you make.
  • This encourages centralizing your generalized code in the Pod due to a quick development cycle.

Right now you might be thinking that relying on a current snapshot of the code as it stands in a developer’s local workspace isn’t a good thing, and you’re right!  You’re also reading the wrong tutorial. ;-)  This is about developing your Pod and app at the same time, not using versioned Pods.  You’ll have to commit and version things while you code your app to do that and that’s not going to motivate you to maintain both at the same time. You’re have to rely on generalizing and exporting your code to a Pod after your development is done and…well…we all know that’s likely never going to happen.  You’ll be too busy celebrating your new app’s release to think about it.

This method works really well and, obviously, is ideal in single-developer environments.

Alright, where were we?  Ah yes!  Now, we just need to use the Tilikum Pod in our app. The code is simple, we merely need to import the framework where we need it and then just use our new extension however we wish:

We import Tilikum above and then we can simply use our new length method!

We import Tilikum above and then we have access to our new length method!

Done!  Now, as we develop our app more, whenever we want to add some useful code we think our other apps will want to leverage, we add it to Tilikum rather than the app. Instant re-usability! Cool!

There’s just one little wrinkle we need to talk about (you knew there would be), and that’s what we need to do to refresh the Pod once we’ve added something to it.

Let’s Update the Pod so the App Sees New Stuff

Let’s say we add a new method to our extension, or a new extension altogether. We build Tilikum, but when we try to build TilikumClientApp we’ll find that the new code can’t be used yet.

Why?

The answer is simple: the Pod has to be updated in the app. Remember, TilikumClientApp isn’t pointing directly at Tilikum, it’s simply installed the Pod into its workspace just as if it was in the main Cocoapods repository.  So, we need to re-install it.

Doing that isn’t so intuitive, however.  Running pod install again won’t work because Cocoapods won’t think that Tilikum is updated even if you committed the new code.  You can update the Podspec’s version number, but we don’t want to do that after every code change or we’ll quickly stop bothering with the Pod altogether.  Luckily, there’s an easy command line sequence that takes care of it for us:

Don't worry that the other Pod (iRate) appears to be getting re-downloaded, it's actually cached.

Don’t worry that the other Pod (iRate) appears to be getting re-downloaded. It’s actually cached.

Boom!  Keep in mind, with the command above, that this will re-install all the Pods we have specified in our Podfile. However, the other Pods are actually cached and aren’t really being downloaded at all. (On Mac, you can find the cached Pods in ~/Library/Caches/Cocoapods/Pods.)  This means we have very little overheard to this step and it’s therefore feasible to do.

Summary

Using this setup, you can easily locate your app-specific code in your app while locating your re-usable code in the Pod.  You can build quick and easy and won’t have to do any refactoring later.  As a bonus, keeping our most useful code in one place encourages us to build unit tests to make sure they’re correct!

Now, all our handy String extensions and enhanced UIButton classes are instantly available to our other apps without having to pull them out later.  It’s all done as we go!

When you’re done building a particular version of your app, you can go ahead and check in the Pod code and cut a new version of it if you like (if you’ve made it public).  Other users can then use your Pod the normal way.

Awesome?  Awesome!

 

  • Print
  • Facebook
  • Twitter

Previous Posts Next posts