I’ll get back to writing about what I learned with my Adaptive UI demo soon.
I have a little mini-vacation to Seattle coming up in a few weeks that I’m really looking forward to. The last time I was in Seattle was 10 years ago to the day. Its definitely a trip I will never forget.
I was 26 at the time and had just started at NewsGator in April. I had taken over the Outlook plugin (aka NewsGator Outlook) and was working closely with my co-worker Gordon who was building NewsGator’s RSS sync services. Both my client and the backend were built in C# using .Net 1.1. The Outlook plugin was the first to fully embrace the new sync services (which were all in SOAP cause that’s what you did with .Net at the time), so Gordon and I were in Redmond at Microsoft to migrate everything to .Net 2.0.
If you’re wondering about FeedDemon and NetNewsWire – NewsGator had signed the deal with Nick Bradbury for FeedDemon so he was an employee at that point. Things with Brent Simmons were still in flux and so NetNewsWire was not part of this release.
Now why we decided that releasing NewsGator 2.5 the week Gordon and I were both in Redmond is beyond me. Honestly I have no clue. But we did.
To say it was a disaster is mild. We crashed our FogBugz server that day. My friends (friends still today) that worked support recall their entire monitors being inundated with email notifications as support email after support email streamed in.
Gordon and I didn’t have much access to help. We spent our day at Microsoft answering emails from support the best we could and not making any headway with .Net 2.0. At the end of the day, and after a quick “happy” hour with a few people Gordon knew at Microsoft, we did what some overwhelmed, helpless engineers would do after a disastrous release… we got blitzed at some bar in Kirkland.
After we got back to Denver though I learned what really puts companies in a good spot even when they mess up.
Greg Reinacker had announced the new release on his blog and quickly followed it up with some advice for all those having issues. Everyone at NewsGator was full hands on deck that entire weekend doing whatever we could to make our customers happy.
Personally I love reading this first blog post and the followup after Greg, Gordon, Ronnie and I were involved. We busted our butts to do the right thing by our customers. Those blog posts are just the ones I can find 10 years later. There were many others at the time.
So that’s what I was doing 10 years ago today. Failing. We all do. Just make sure you learn from your failures and don’t let them stop you from failing again :-)
A little over a year ago, at WWDC 2014, Apple announced a suite of tools and UIKit changes to support what it calls Adaptive User Interface. The idea behind Adaptive UI is to easily allow app makers to support a wide variety of devices and orientations without having to write specific code for each device. Personally for me the announcement of Swift took up most of the sessions I attended so I didn’t give Adaptive UI much thought until last fall when the iPhone 6 and 6+ were introduced. With the announcement of iOS 9 and the ability to run side by side apps on iPad I figured I needed to take yet another look at Adaptive UI and what it really means to support all devices and orientations.
This series of posts will use a sample workspace I created. Its very simple and I’m sure there are many nuances, tips and tricks that I’ll miss. But there are a number of other tutorials and articles. I’d recommend Rene Ritchie’s summary on iMore from last September as well as Sam Davies tutorial on raywenderlich.com.
Demo App Idea
The demo app is called One Eyed Royals. The idea is to show the three royal cards in a standard playing card deck and the wikipedia explanation of their nickname. The UI should fill as much of the screen real-estate as possible by scaling the images for the cards and adjusting the font for the description. It should also look slightly different in landscape mode on iPhone to keep the font size readable and not require the user to scroll the content.
There are three main tools you use to build an Adaptive UI – Auto Layout, Storyboards and Size Classes. Notice I didn’t mention anything about Swift or Objective-C. My demo is done completely in Interface Builder without needing a single line of code. I think that’s important to know. I see many developers use macros to determine devices and screen sizes then use hard coded values for view sizes and placements. Break yourself of that habit. Instead use the tools Apple recommends.
Adaptive UI means thinking about UI elements in terms of how they orient themselves with other UI elements. Desktop developers have had this mindset for a very long time. Users expect to resize windows on a desktop to whatever size they like. iOS developers (as well as Mac and Windows Desktop devs) have long had the idea of “Springs and Struts” to do this. Adaptive UI however means using Auto Layout.
Auto layout is a constraint based approach to UI design. I’m not going to try and give a good description of what that means. The best way to understand Auto Layout is to start using it and fight through the learning curve. There have been plenty of times when I’ve thrown up my hands in frustration and walked away for a bit before coming back to an Auto Layout issue. But I can say that the more you work with it the easier it becomes and you’ll start to understand the power behind it.
The demo workspace has an incredibly simple demo app that shows how to anchor labels at top right, center and bottom left of a “view”.
The battle over Storyboards versus xib files is still going strong. You can use Auto Layout and Size Classes with both so I’ll leave that choice up to you. I prefer Storyboards for their grouping of related UI. The project I work on is BIG. If each view had its own xib we would be struggling to figure out how they relate to each other. Storyboards do a lot of that for us. There’s also the misconception that you use only one Storyboard. You can use as many as you want and Xcode 7’s Storyboard References make it even easier.
Size Classes are odd but awesome. Instead of needing to define all of your constraints for all devices in a single place, you can instead break them down into subsets that inherent from a parent and allow you to disable, remove or add new constraints for a particular set of devices. Currently there are only “regular” and “compact” size classes for various devices and orientations. Apple docs are the best place to read about which devices use which Size Classes.
For my own understanding I included a simple app in the demo workspace that updates a label with the Size Class information. There are UIViewController delegate methods and properties that give you this information in code.
(iPhone 6, 5, 4S)
This looks like a good place to break. The next post (or possibly posts) will go into how I built the One Eyed Royals demo app. I’m thinking I’ll have a wrap up post which reflects on what I’ve learned and how I plan to move the project I work on to Adaptive UI. As always though, life and work may get in the way so no promise on timeline. But at least the demo app is available now for everyone to take a look at!
Finally took the opportunity to watch Advanced NSOperations (Session 226) from this years WWDC. I’m happy to see so many talking about it over the last week. NSOperation and NSOperationQueue along with NSURLConnection and NSURLConnectionDelegate have been the basis of almost all the iOS apps I’ve ever worked on going back to 2009. They were first introduced with Mac OS X v10.5 (Leopard) in 2007. They’re solid, proven and incredibly powerful. It was nice to see a WWDC session re-introduce them to the newer crop of developers, with some inventive uses, since I think many didn’t know they existed or understood how to use them.
My First Introduction
I was first introduced to them through Brent Simmons. Brent had written what I can only imagine was the most powerful and performant RSS downloading engine in Objective-C at the time (who knows, it may still be the best). It was being used in NetNewsWire as well as TapLynx. I was starting on my first iOS app for NewsGator Social Sites and needed much of the same networking and XML parsing so I began to incorporate it through a shared repository Brent setup for us to use.
It worked by creating separate NSOperations for each RSS subscription and throwing them all onto an NSOperationQueue which performed the download and parsing on a background thread then used NSNotificationCenter to tell other parts of the app when a feed was successfully downloaded, parsed and stored.
Social Sites wasn’t just RSS driven but most of the API’s were still XML based so the only changes I had to make were in XML parsing classes and not in the networking logic. Brent had solved that for me. My other change was to write the data to Core Data instead of straight to SQLite which is another story. (I did have a “doh!” moment when watching the session and seeing a separate save context operation dependent on all the other ones completing. That’s a great idea).
As Social Sites grew I needed more networking capability. I had to download not only messages being shared on the system but also users profile pictures and other meta data that was associated with a message but not as important to the user as the message its self. NSOperation already had priority setup so it was dead simple to throw user image download operations onto the queue but allow content downloading to execute first.
The same engine also powered networking for Glassboard iOS but with a new JSON parser instead of XML. That was the only change that I can recall being needed to reuse the entire background networking engine. Everything else was already done.
My Current Affiliation
After leaving NewsGator I started to see projects that used AFNetworking. This was before NSURLSession was introduced. AFNetworking at its heart is the same as what Brent had written. I had much appreciation for both once I realized that.
When I started on the current project that I work on I saw that it used AFNetworking but used a block approach to networking calls as they finished as opposed to NSNotification. To be honest I was a bit torn. I liked the block approach since it wasn’t as disjointed as NSNotifications. You could see who executed the network call and how it handled the result. But it was also very messy and added tons of code to the view controllers needing the data. It didn’t feel right but with so much code in place, an existing large team of developers and features outpacing refactoring it had to stay.
As the project moved on though we started seeing places where we had the same business logic being duplicated on different view controllers. Duplicated code is duplicated bugs so we started looking into ways to fix it.
What was introduced was a CommandBase class based off of Command Pattern popular in other languages. Of course my first reaction was “This is an NSOperation”. I was then pointed to a GitHub project by Magical Panda called MGPCommandBus which I pointed out was just an NSOperationQueue. (It may be more, I don’t know, I didn’t explore it any further then the description).
Unfortunately I was overruled with the thought that this simple CommandBase was better then the “overkill” of NSOperation. Don’t ask.
What I found more intriguing though is after introducing the pattern to the team how aptly they applied it in some very interesting ways. We started using commands not only to do networking but also doing things like deep linking, checking permissions for device hardware, even supporting a multistep upload and checkout process. It was great to see the size of our VC’s shrinking while making business logic independent, reusable and testable. I think iOS developers understand NSOperation they just don’t know how to successfully use it.
When I wrote my sample app for my talk at iOS Dev Camp Colorado Springs on PassKit I decided to try my hand at NSOperation again to do the networking with NSURLSession and data parsing with NSJSONSerialization. You can see some samples of what I did with my SignInViewController and my FetchAccountOperation.
Watching the WWDC Session tonight has me thinking that this pattern is finally validated in my head.
My Future Affiliation
I’m guessing some will say that this type of architecture is not necessary in Swift. I can’t say one way or the other if they’re right. I can read some Swift but to say I could architect an app solely in Swift at this point would be a lie.
What I can say is that I tend to learn languages by seeing them used to solve problems that I already understand. The demo app from the Advanced NSOperations session is all in Swift. I plan on using it to teach myself more of the language while knowing what its trying to accomplish.
I’d like to thank Dave DeLong and all the others that contributed for the great session. I gave it a standing ovation from home when it completed :-)
Also questions, comments telling me I’m wrong are always welcome. As someone I respect told me last week at WWDC – “It’s the internet. Everyones allowed to be wrong”.
Hopefully you’ve heard of App Camp for Girls by now. If not…
App Camp For Girls is a place where girls can put their creative powers to work, designing and building apps, while learning more about the business of software and being inspired by women mentors in the field.
Its a fantastic organization. Last year I had the privilege of sponsoring team imusicats at the Seattle camp. I’m incredibly proud of having that opportunity. When Jean MacDonald emailed me last week asking if I wanted to sponsor a team this year I didn’t hesitate at all. I’m excited to say that I will again be a project team sponsor for the Seattle camp!
The amazing part has been watching our community get involved through volunteering, donating and sponsoring. The App Camp Quiz Compendium, an app with 15 short quizzes developed by last years campers, reached #1 for Paid Apps in Entertainment. Not many developers can say they’ve reached that level of success, but now each of those campers can and that’s just plain awesome.
Of course with success comes even loftier goals and that’s what App Camp for Girls 3.0 is all about. In order to add more camps and enroll more campers, App Camp for Girls has started an Indiegogo crowd funding campaign. There are different levels and perks. I went for the Grace Hopper Portrait Art since I’m a both a computer scientist and a military brat.
Please take some time and read about their goals and hopefully make your own donation. At the very least buy the App Camp Quiz Compendium, it’s only $0.99. And if you’re going to be at WWDC, make sure to get a ticket to the fundraising happy hour hosted by WWDCGirls. Last year was a blast and I can only imagine this year will be even bigger and better!
I did a quick talk and demo at iOS Dev Camp Colorado this past weekend in Colorado Springs about PassKit and how to update a pass using Apple Push Notification Service (APNs).
Tom Harrington (amazing organizer of the event) and a few others asked me after how hard it was to send push notifications to APNs using NodeJS. It was one of the most intimidating parts I had to figure out for my demo but it turned out to be incredibly simple.
I used node-apn.
npm install node-apn
That’s the first NodeJS code I’ve shared here. Be gentle. I didn’t really ask or search how others prefer to do NodeJS, I just wrote it in a style I like.
I try to always own up to my mistakes. We all make them. If we don’t own them we don’t learn from them.
This evening I got caught up in a “Twitter Outrage Frenzy” around HBO Now and Comcast. I saw some posts about Comcast subscribers not being able to get to order.hbonow.com. Being a Comcast subscriber I tried loading the page myself and it did indeed fail to find the server. I then tried on my iPhone over T-Mobile LTE and low and behold there was the page.
Then I made my mistake. I took to Twitter to pile on with my own story of how terrible Comcast is:
— Nick Harris (@nick_harris) March 10, 2015
I couldn’t believe a company would do such an thing, and that was also my mistake. I should have looked at the situation through Occam’s razor before the tweet instead of after – which I immediately did. Situations like this are almost *always* DNS related. I’ve spent enough time trouble shooting my own DNS issues to know. This smelled like DNS from the start.
While I was starting to look at different ways that DNS could cause this, Jason Livingood (@jlivingood) VP of Internet Services at Comcast, replied to my tweet explaining it was a DNS error on HBO’s end:
— Jason Livingood (@jlivingood) March 10, 2015
I quickly posted my own apology:
— Nick Harris (@nick_harris) March 10, 2015
Marcus Zarra’s post The Dangers of Misinformation has changed my perspective on how I use my digital voice. After my initial post I had a handful of friends try the same thing and jump to the same conclusion as I did. That is completely my fault. I used my digital voice to disparage the wrong party for an issue I was having. My “shouting” on twitter then had reverberations to people who follow me. That troubles me deeply.
I made a costly mistake on Facebook a few years ago that burned bridges that did not deserve to be burned. The way I perceived the situation correctly made me angry but it was only after hearing the other side that I realized my perception was out of focus. Since then I’ve been very cautious about what information I put out into the world.
Tonight I discovered that I still have more work to do. I own that mistake, along with its lesson.
Supporting multiple languages in an app is hard. One of the hardest things is finding spot on translations.
NewsGator Inbox, at one point of its life, supported a handful on languages. NewsGator outsourced the translation. We gave them our English string files and they gave us back translated versions. We would test them for UI layout but nothing else.
The nomenclature of RSS at the time was to refer to blog enteries as “posts”. When our partner got one of our translated builds they were not happy to see all blog enteries referred to as “fence posts” – the translation of the word our service used in all of our apps strings.
When writing my book I also noticed this. Wiley had multiple levels of copy editing and I realized as they went on that the purpose was to have copy that was easy to translate. It was a fascinating process.
I guess the moral of the story is that if you invest in translation, pay for a company that will know dialect and apply it wisely. Having a plan to verify the translations independently sounds like a good idea too.