Nick Harris

Learning Swift – The First Weekend

leave a comment »

This is part of my Learning Swift series of posts. Please see Super Euchre Swift to understand what I’m building while learning Swift.

I’ve been reading and learning about Swift since I was sitting in Moscone for WWDC 2014 and had the same “No F__king Way!” collective moment with the rest of the Apple Developer World. Ideas like let vs var, generics and even optionals and unwrapping were never hard for me to grasp. That means I think I’ve been OK at reading Swift over the last year but haven’t taken any opportunity to write some myself.

A big part of the reason I held off is Apple’s own statement that the language was going to be changing in big ways over that year. Way back when I first graduated college, there was a new language called C# along with the .Net Framework coming out of Microsoft. Though the first C# book I bought was in 2001, I didn’t ship real C# code until I was at NewsGator in 2005. The differences between the language and the compiler between .Net 1.0 and .Net 2.0 was huge. Microsoft was a fantastic partner in the transition but it was still eye opening to be sitting with a compiler engineer in Redmond trying to figure out why our code was broken.

So I waited. And what I’ve seen both from Apple at WWDC this year and the general buzz in the community has me convinced that now is the time to really jump in.

EuchreCard – Struct or Class

I started this weekend the same way I start every re-write of Euchre… the EuchreCard object. Euchre itself uses common playing cards. Luckily for me, Apple used playing cards in its Swift documentation about nested types.

The first thing that struck me about that sample code was that the BlackjackCard was a struct and not a class. This seems to be one of the fundamental decisions in Swift a developer needs to think through when adding objects to the code base.

I decided to go with struct for EuchreCard. For one, Apple used a struct for BlackjackCard. That’s usually a dead give away. The other was Greg Heo’s (@gregheo) Switching Your Brain To Swift talk at this year’s 360iDev. He had a slide (which unfortunately I don’t see in that post) about Swift foundation and what things are represented by struct vs. class. From what I recall the difference was quite stark in that there were minimal classes and many structs. That leaned me even closer to struct.

The ultimate conclusion I drew was deciding if an object should be passed by reference or by value. In Swift, structs are very much on par with classes. They can have properties, initialization functions, even their own functions. Obviously that’s very different then ObjC. Classes, however, are passed by reference, while structs are passed by value. That boils down to understanding when an object should be mutable and who can change it.

Mutability and type safety are some of the fundamental ideas that Swift is being built on. Pass by value is safer in the aspect that you can pass a value into a sub function without the caller worrying about what its value may have changed to when the sub function returns. That’s not to say mutable objects don’t have their place. They absolutely do. The approach I’ve decided to take with all things Swift is to use the safest option first then move to something thats a little more unsafe once I know WHY I need it to be. So for me that means struct first till I know I need it to be a class.

This is counter to what the Apple docs say, but I was also in the room for the very popular Protocol Oriented Programming in Swift session at this years WWDC. I need to watch that another dozen or so times to really understand it all but in the mean time I like this Stack Overflow answer on Swift Structs vs. Classes.

Suits and Associated Values

The next big decision I came across was how to represent a cards suit and rank. I’ve always used enums for these in the past and Swift didn’t change that decision. It did make it a little more interesting though.

With swift, an enum case can have an associated value. Enums in ObjeC, at least how I have always used them, are always ints. The BlackjackCard however uses a char for the suit. Not only is it a char, but its the unicode character for the typical card suits of hearts, spades, diamonds and clubs. Super clever!

But does clever mean better?

For me it doesn’t. In Euchre, the trump value of a Jack is tied not only to its suit but to the color of that suit. For instance, if trump is Clubs then the Jack of Clubs is the best card in the deck while the Jack of Spade is second. Its because both suits are black, the same way that both hearts and diamonds are red.

In my past code for Euchre I’ve relied on how I setup enums to help test if a card has the same color suit as another by using mod. This means I can do if statements that look like this:

if ((rank == .Jack) && (suit.rawValue % 2) == (trumpSuit.rawValue % 2))

If you’re not familiar with Swift, “rawValue” probably sticks out to you. When you assign an associated value to an enum case you can get its actual value by using rawValue. This allows me to treat a suit’s enum value as an Int in order to call % on it.

So though I could use a clever unicode character for a cards suit enum, I opted to stay with Int.

Calculated Properties

In my UI layer I have assets for each card that are named by using an abbreviation for the cards rank and suit. For instance, the Ace of Spades has an asset name of AS. The King of Clubs is KC while the Ten of Hearts is 10H.

My old ObjC code used calculated properties to return these to callers dealing with a EuchreCard. A calculated property is one that looks and acts like a property from the callers perspective but uses an internal method to calculate its value whenever its accessed.

Many old school ObjC programmers will tell you that calculated properties are evil and you should always use a function. They have very good arguments why that I typically agree with. Though for me, things like this asset name for a card were a perfect candidate for a calculated property since they made reading the code higher upstream easier on me though I took a small calculation hit on each access of the property.

Lazy Stored Properties

Swift solves this for me though in a very nice way with the introduction of lazy stored properties. Obviously my EuchreCard doesn’t know the name of its asset until it has its suit and rank set. I also don’t need this value right away when creating a deck of cards. I only need it when the UI first needs to display a card.

So instead of declaring a property that needs to be set on init…

(oh did I mention that Swift makes you set a value for all your properties during init? It does and its pretty awesome since it leaves nothing ambiguous up to the compiler/runtime)

…you can declare it lazy and set its value to a function that will be invoked the first time the derived value is needed. This way I can calculate its value once when its needed and have it stored for any point after. Very nice! I did the same with longName which I’ve used in past Euchre versions.

There’s nothing ground shaking or particularly valuable about my EuchreCard so why not share.

Here’s a gist of my EuchreCard struct.

First Weekend Conclusions

I wrote this down in my running Swift notes about 1 am Saturday but I like it:

“ObjC is hard to learn and really hard to learn the “right” way to use it. Swift feels different. The way it overlaps with other languages has made it very easy for me to pick up so far. I thought I would be fighting it more but instead I’m seeing much better ways to implement Euchre’s AI layer. I can see ways I could have done this in ObjC but the look of the code feels much more natural with Swift”

It was a fun weekend! Looking forward to diving in more!

Written by Nick Harris

August 24, 2015 at 3:40 am

Posted in Learning Swift

Super Euchre Swift

with one comment

Back when the first iPhoneOS SDK was announced I decided I wanted to learn how to build apps. I had been playing a shareware Euchre game on my Windows PC since college and thought it would be a fun exercise to learn Objective C while writing my own Euchre game for iPhone.

For those who don’t know, Euchre is the card game of choice for all bored lifeguards, wait staff, high school and college students in the Great Lakes region. Its the regional pass time. Its also very popular in Canada and Australia.

Pocket Euchre 1.0 went live in the app store in January of 2009. It was never a big money maker but for the first few years it averaged almost $1000/month. Since then its name has changed to Super Euchre, it’s become completely Apple Ad supported and its earnings have dwindled down to just over $100/month. Its no longer the best app I’ve ever shipped, but it still serves as a way for me to learn and use changes in iOS along with showing off just how bad of a UX/Designer I am – all while making a little beer money for the effort.

Being that Euchre has been my little side project and learning tool, I’ve decided to take another stab at a re-write of it, this time completely in Swift 2.0. My plan is to eventually ship another version of Super Euchre that has Game Center game play as well as a Mac version. Will I ever get there? I really hope so, but knowing what the real return on investment would be at this point I don’t know if my grand scheme will ever come true. But I can still use it as a way to learn Swift by applying it to problems I solved previously in ObjC so I can hopefully see the strengths of Swift instead of just re-writing the same logic with a new syntax.

Learning Swift

I’ve been enjoying Brent’s Swift Diary posts, though to be honest they were mostly over my head as I had not really gotten my hands dirty with Swift. I’m a week out from taking a break from contracting work for September and besides getting some long overdue house work done, I plan to spend a lot of time learning Swift 2.0. I started this weekend. So I think I’ll give the Learning Swift blog series a shot as well.

There’s a couple reasons to do this. First I want to think through the decisions I’ve been making. For me the best way to reflect on decisions is to write out what reasoning I had at the time. Secondly it gives anyone who reads this a chance to tell me their ideas on what they would have done instead.

I’ve added a category to my blog called Learning Swift. We’ll see how it works out.

Written by Nick Harris

August 24, 2015 at 1:35 am

Posted in Learning Swift

360iDev 2015 Retrospective

leave a comment »

Another 360iDev is in the books. I had the honor of being a speaker this year for the third time since I started attending back in 2009. This year, just like every other year, was an absolute blast. The best part about 360iDev is not the sessions, though they are amazing, but instead its the attendees and speakers. Everyone is there to learn from each other and help each other in not only our professional careers but also in our Apple developer community and even this year (thanks to Mike Lee) the world.

360iDev Speaker Dinner
(photo by Fuad Kamal, @flexRonin)

My Session – Git it Together

For the last year and a half I’ve been immersed in GitFlow. I find it to be a very effective way to manage a large project with many developers. But a 45 minute talk about source control would be dull so I decided to submit a talk where I would do a short history and overview of source control systems out there and to assemble a panel of other speakers to get their perspectives. I was happy when it was chosen!

My favorite part about putting it together was finding the panelist. Out of the five, one was a good friend, one was a person I met last year at 360iDev and three I met via the Slack team 360iDev had set up for speakers who I then met in person as we were getting ready to start the session. How cool is that! Perfect strangers willing to pitch in and share their experiences.

I haven’t seen any comments yet but my feeling after was that it went very well. I learned a lot from the panel, which I’ll admit was my selfish reason for submitting the idea. My entire slide deck is here, though I only used a small fraction of those slides.

I’d also like to thank my panelist again:

Kyle Richter (@kylerichter)
Janene Pappas (@AphroditeSW)
Ben Lachman (@blach)
Daniel Pfeiffer (@mediabounds)
Brett Jones (Possible Mobile)

Other Highlights

My favorite session from this year is probably Mike Lee’s (@bmf) talk about the possibilities for the downfall of human society and what we can do to change it. I’ve always enjoyed Mikes talks as well as just hanging out and talking. The conversations are often very thought provoking. This talk was no different.

Next was Jay Freeman’s (@saurik) Bug or Feature talk. If you’ve never met Jay or have never listened to one of his talks, do yourself a favor and go find one. Jay is a genius. He’s probably one of the smartest people I have ever met. His talks are 100 miles per hour and always mind blowing as well as hilarious. I’m so glad he speaks every year at 360iDev!

Joe Cieplinski (@jcieplinski) and Marin Todorov (@icanzilb) talks on ways to make money while still being indie were both fantastic and paired well with Ben Lachman’s (@blach) panel on failure. Greg Heo (@gregheo) and Jay Thrash’s (@jaythrash) talks were probably my favorite code oriented sessions, but Jay Graves (@skabber) talk about using Go for cross-compiled business logic is right up there.

Being front row for my very good friend Jenny Blumberg’s (@jennyblumberg) first ever conference session was pretty awesome too.

When the video’s come out I encourage you to watch them all. So much knowledge shared!

Wrapping Up

A big thank you to John and Nicole Wilker (@jwilker, @nwilker) for another great 360iDev! As usual I made new friends that I hope to see back each year and if not I hope to keep in touch with in one form or another. For now though, I’m going to get some sleep…

Written by Nick Harris

August 20, 2015 at 3:10 am

Posted in Uncategorized

The Quick Fix

with one comment

I had a situation recently. There was a crashing bug that was dominating our crash reporting. It was effecting just over 1% of a decent size install base, but with many customer support channels it was dominating attention from anything else.

I keep a close eye on our crash reporting with each release. I was the first to notice the problem and was deep into investigation by the time it caught others attention. This app goes through a rigorous QA process so when something like this comes up its very hard to figure out reproduction steps.

Obviously it was an issue, but it wasn’t until the iTunes App Store met its requirements to publish reviews for a new release that we got solid reproduction steps. There’s a good tangent here about the iTunes App Store and the Apple Wall between users and developers but I’ll leave that for another day. I’ll just say that it was the best 1 star review I had gotten in a long time.

With reproduction steps in hand I zeroed in on not only the problem but where we introduced it into the code. The code seemed innocuous but the nasty bugs usually are.

My plan was then to identify not only the root of the issue but anything that might be effected by any code change. This was not a quick process. This bug was part of a very sensitive portion of the user’s overall experience. Without knowing all the aspects of the issue there was a good chance that any fix would impact users in some other way. It was essential to understand the problem to its root.

Once I figured out the root of the problem I did what I would hope others devs would do with such a sensitive part of the users experience – I detailed it out, along with my plan for a fix, to a trusted colleague. As smart as you might think you are, you are wrong from time to time. Allowing someone else to review your thoughts and architecture shouldn’t be seen as a weakness but a strength. As devs we should always be humble about our code.

Implementing the plan meant some refactoring. To me it wasn’t dangerous refactoring, but some people see risk in lines of code changed versus moving away from code that could have more hidden issues. I wasn’t served well in that I missed an even deeper root issue that QA found with regression on my changes. It was a simple fix because I knew the root problem, but it was a blip in the regression testing for a new release.

As my changes were moving to final QA regression I was challenged that I did too much and was asked to look for a smaller impact code change/”fix” that would deal with the superficial problem. The root of the issue would be addressed in a later release.

I understand this way of thinking. Stop the crashes for now then fix later. What I don’t get is the allocation of resources.

I had figured out, documented and resolved the issue. Passing that fix down the line to reset and find a “quick fix” meant not only readjusting my mindset around the problem from a proper fix to a bad one, but also refocusing QA resources to test both. Instead of being done with testing over the course of a day, we would be adding another week of testing down the road to test both the “temp” fix and the real fix.

In the end my fix passed QA and went into production. We’re back to our next release without this hanging over our heads cause it was fixed right the first time.

What’s your point?

This all comes down to the idea that there are quick fixes in software development.

Software is complicated. As an apps life lives on its complexity grows faster then its utility. As software engineers its our duty to solve the root issues instead of “throwing code at the problem”.

When you don’t you’ll end up in the long run trying to put out fires and crashes instead of adding value to your app. Its much easier on yourself and your team and your customers to fix things right the first time.

I want “cool sailing with some waves”.
No fires.

Written by Nick Harris

August 10, 2015 at 3:45 am

Posted in Uncategorized

NewsGator 2.5 – 10 Years Later

leave a comment »

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 :-)

Written by Nick Harris

June 29, 2015 at 5:03 am

Posted in Uncategorized

Adaptive UI Part One – Introduction

leave a comment »

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.

screen_shot_1 screen_shot_2

(iPhone)

screen_shot_3 screen_shot_4

(iPad) 

Tools

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.

Auto Layout

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”.

Storyboards

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

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.

screen_shot_6 screen_shot_5

(iPhone 6, 5, 4S)

screen_shot_8 screen_shot_7

(iPhone 6+)

screen_shot_10 screen_shot_9

(iPad)

Up Next

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!

Written by Nick Harris

June 25, 2015 at 5:18 am

Posted in Uncategorized

NSOperation – My Story

leave a comment »

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.

Finally

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”.

Written by Nick Harris

June 22, 2015 at 2:39 am

Posted in Uncategorized

Follow

Get every new post delivered to your Inbox.