Make Money Outside the Mac App Store book cover

My book is out: Make Money Outside the Mac App Store.

Own your products and know your customers: sell outside the Mac App Store. In a few hours, you’ll have in-app purchases, a trial mode, and piracy protection all set. The book includes fully functional sample projects and code ready to be copied into your app.

Custom Enumerated Sequences in Just 1 Line of Code

In “Creating a Cheap Protocol-Oriented Copy of SequenceType (with a Twist!)” I created my own indexedEnumerate() to return a special kind of enumeration: instead of a tuple of (Int, Element), I wanted to have a tuple of (Index, Element), where Index was a UInt starting at 1. A custom CollectionType can have a different type of index than Int, so I was quite disappointed that the default enumerate() simply returns a sequence with a counter for the elements at first.

Thinking about the meaning of “to enumerate” a bit more, I understand why that is so. Still I need something different that an enumerated sequence.

Now Rob Napier kindly got in touch via email and told me about some cons of my approach I wasn’t quite aware of. Thanks for that!

On top of that, he showed me a version which was only 1 line of lazily evaluated code that could replace my IndexedSequence type:

let indexedValues = zip(collection.indices, collection)

A CollectionType exposes a property called indices which is a range over (startIndex...endIndex). Zipping that range with the collection itself produces a sequence of tuples of type (Index, Element). Just what I needed. 1 line of code. This was so concise that I now have found a couple more places where zipping did the job better than my naive approach.

Thanks a ton, Rob.

Evaluate and Launch Your Idea With Small Steps

As you may know, I’m totally immersed in getting TableFlip ready to ship. By some random circumstance, I recently stumbled upon Paul Jarvis’s getting started post about online businesses.

I already read the hip books about startups: Startup Owner’s Manual (meh), Lean Startup (ok), $100 Startup (inspiring), Lean Entrepreneur (meh), Running Lean (good one) – you name it. I still found Paul’s action-oriented collection valuable to get started. It’s the little first steps that matter which I tend to forget sometimes.

With TableFlip, I wanted to know if a visual Markdown table editor would be something people liked. So I put together a landing page for it and asked around. By sheer luck I managed to get 300 subscribers in about a month. I’m excited to show them the first test build. – Sadly, I cannot say that I have any fancy techniques to share. Being connected to other people that love to re-tweet your announcements or post links to their blogs helps a lot. Nothing else has had any effect for me, like, ever.

I posted a link to Joa Allen’s recommendation to get in touch with truly loyal people with a free app MVP that solves 80% of their problems already.

The bottom line of all this is: Just. Do. It. You need feedback, so get something out as quickly as possible. Then you may be able to fend off starvation in the long run.

Swift Depends on Objective-C

Brent Simmons brings up valid concerns about the current state of Swift: you cannot write any software using Cocoa (AppKit for Mac or UIKit for iOS) with Swift without somehow interfacing with the Objective-C runtime. That’s kind of weird , don’t you think?

When I write apps with Swift, I always feel most comfortable in the model layer. And everything else thats just a struct or class Foo without inheriting from a framework. It’s 100% mine. I love that about using Swift.

I guess that’s part of why Russ Bishop wrote a few types to encode Float32 without any external dependencies: it’s possible, but it’s foundational work, so to speak. The exercise is interesting, but usually you’d just use NSData, for example.

So when you want to display something on screen, there’s Apple’s frameworks waiting for you to be imported. Depending on NSObject and the dynamic dispatched stuff Objective-C borrowed from Smalltalk – things you find in scripting languages like Ruby, too. But which are completely absent in pure Swift.

The 20 years of design that went into Carbon, Cocoa and Objective-C, as Daniel Jalkut points out, adhere to a different philosophy than Swift. But Daniel and Brent’s point isn’t that Swift will do away with all that and we should be afraid. It’s that Swift promises more than it can keep at the moment. It’s not independent. At least not if you’re using it outside its limited Open Source’d scope. When you write apps for Apple devices, Swift is bragging to do all the things while behind the scenes good ol’ Objective-C is pulling most of the strings related to actual user interactions.

From time to time, I get my fix of beautifully relaxing and flexible programming with Ruby. Because I cannot make use of pure Smalltalk. Swift doesn’t speak the same language. When Ruby is the charismatic bard in your role-playing party, Swift is the elven strategist. One charms the ladies while the other lays out the plans. One is cool while the other strict.

Outperforming the Competition

[U]nless your talent and skills absolutely dwarf those of your competition, the deep workers among them will outproduce you.
—Cal Newport, Deep Work

(via Shawn Blanc)

This is super relevant if you’re on your own or even starting to pursue a career in programming. It doesn’t matter how much time you spend. The intensity of focus counts. Call it myelin or what else you will: only deliberate practice will make you better. “Deliberate” means it’s challenging. And that you pay attention to the challenge. That you elaborate why you failed. All of this takes a bit of extra time, but the result is so much better than simply dashing through and hoping for the best.

It’s easy to leave the StackOverflow copy & paste “”coders”” behind.

That’s why I find Khuong’s 100 Swift projects or Patrick Bellot’s experiments in Swift so impressive. Everyone can do that.

I know for sure that I need to pick up a book on Core Image and Core Animation sometime, soon, because I have no clue how to use these frameworks. It’s not a blind spot. It’s a known weakness. Doing a challenging project in these areas will catapult my skill further towards mastering the craft.

Here’s my invitation to you: take a minute to evaluate where you stand. What does make you uncomfortable? Take note of that. Make these things projects. Then do or plan some research for each to find out how to tackle these known unknowns. Then execute.

Better Sliding Menus

In a recent usability post of Raluca Budiu, the common mobile app pattern of sliding menus is criticized: when the menu button is at the left edge and the content slides away to the right, then hiding the menu again requires the user to move her hand, and reading the menu items requires her to move her finger out of the way. With fat fingers, this is even more of a problem.

Here’s two conceptual images with an overlaid fat finger silhouette so we’re on the same page:

screenshot of sliding menus
When the user reveals the hidden menu, the menu toggle moves away so she has to reach with her thumb. Or, worse, use the opposite hand to tap the button.

I wonder why people favor this fancy pattern where the content slides to the right and reveals a menu to a menu that slides out like the good old pull-down menu or your well-known web site hover menu.

screenshot of overlaying menu
The menu expands below the user’s finger

Menu items should be aligned to the right of the toggle so the finger doesn’t obstruct scanning of the menu.

It’s like a generic UISplitViewController on an iPad in portrait behaves. There, the master view controller overlays the detail view controller by default. The only but significant difference is that the toggle stays in place.

As a first step towards this goal, using a UISplitViewController plus adding a separate toggle to the master view controller can do the trick already.

How to Abort a Chain of Rake Tasks on Error

I use nanoc as my static site creator for this blog. It’s written in Ruby, my favorite scripting language. And so I use a Rakefile to automate most things, like generating a fresh copy of the site and deploying it to my server.

Only last week did I find out how to make Rake not continue when a part of its tasks failed. Most of the stuff I use is wrappers around shell commands with a few system notifications sprinkled in. $? does capture the latest shell call’s return value (kudos dnsimple.com):

task :generate do
  out = system "nanoc co" # compile site
  
  # abort on error
  if $?.to_i == 0
    puts  "Compilation succeeded"
  else
    abort "Compilation failed: #{$?.to_i}\n#{out}\n"
  end
end

In the past, when I changed something and was to lazy to preview changes, the task chain of cleaning + compilation + deployment sometimes resulted in compilation errors; then a lot of files would be missing in the compilation result’s folder; and then the folder would still get rsynced to my server, deleting most of the stuff there. Oh my. I’m glad these times are gone. Astonishingly, total data loss on the server never bugged me enough to look this simple thing up.

How to Get Started with Swift: Write New Tests in Swift

Daniel Jalkut of MarsEdit fame is slowly getting up to speed with Swift. I have a few Swift-only projects already (Move!, TableFlip and secret in-progress ones). On top of that, every feature I add to the Word Counter is a Swift module, too. The main code of the Word Counter is still in Objective-C, though.

Integrating new types to the project using Swift is awkward. There’re things you can only use in one direction. Most if not all Objective-C code can be made available for Swift and works great. The other way around, not so much. Also, Objective-C imports from the -Swift.h file won’t be available in Swift-based test targets. So you’ll have to isolate these even further, create wrappers, or whatever. Porting a class to Swift can work, but the side effects on testing make it harder.

I like Daniel’s advice to write your unit tests in Swift if you’re still not certain if you should make the switch to this new and volative language. It’s a good idea to get your feet wet.

Considering the problems I ran into with the Word Counter, though, I wouldn’t know how, honestly.

App Pricing and How to Make More Money

Joe Allen posted on Reddit how selling Soundboard Studio for $29.99 helps him sustain a business. You’ll find more details on his indie business blog where the latest posts circle around similar topics.

The advice is sound. If you charge pennies, it’s hard to make a living. It’s also not new advice (compare freemium advice, what the market accepts). Still it’s uncommon to charge “a lot,” whereas “a lot” is either more than $2 or $9, depending on the target audience.

The problem Joe identifies is this: charging a high price in the iOS App Store will scare people off. There’re no trial versions. The best you can have is social proof: 5-star app store reviews and praise on the internet.

Joe’s approach is interesting, though. He doesn’t even try to convince people to pay the high price up front. Instead, he builds the app for an audience of already very committed people to which he sells the app just like Mac developers or web app marketers would.

In fact, he applies standard advice for web service marketing to iOS apps: gain trust and show how your product will appeal to users.

  1. Give away a lot for free to attract users. “Give them the fish.” This is your minimum viable product, if you will. It’s going to be a free app in this case.
  2. Collect e-mail addresses from within the app in exchange for a freebie. More “free”, did you notice? A PDF report, related bonus content, you name it. It’s important that the freebie is relevant to your users lest they won’t sign up for an e-mail newsletter.
  3. Stay in touch with subscribers. Ask them questions about how happy they are with the app. Collect feature requests.
  4. Create a pro version of your app with a super relevant feature and sell it with pro pricing in mind. Joe charges $9 for his pro teleprompter. He also charges $29 for his pro soundboard. I guess the target audience of his soundboard compares the price to $1000 equipment, so framing the price in terms of current alternatives and the extra value you offer is key.
  5. Sell to your list of subscribers. Prepare them for the release date. Give them the opportunity to get the app for a discount during the first 48 hours. Make them happy and give something back in return for their feedback.

That’s about it: collect e-mails in exchange for freebies and find out what users really wish for. Create that and sell it to them. They’ll be hooked in advance already or else they wouldn’t have signed up.

The overall situation is a bit easier for Mac developers. You can give away demos, for example. Invite people to closed beta tests and then make things right.

Joe’s approach to build a fully functional free app as MVP is a lot of work and increases the risk of producing waste: creating a product nobody wants. It’s still better than implementing ALL THE FEATURES first, releasing to the void, and still not making it.

The “Lean” crowd values learning. Giving away an app for free and gathering feedback is a costly but focused way to learn. It’s a live experiment. Another advice you’ll find on the web is to run free giveaways of your app to increase downloads and get into the top lists of the app store. Joe’s approach does that, too, only he’s not doing this sequentially but gives away a free version in parallel.

I don’t say this kind of building a list is the silver bullet. It may not work for games at all. But it’s probably more effective than releasing a free and a paid version to the app store while still not having anyone who knows about the app. Having prospects on a list is a tremendous help. Joe’s calculations give everything he said an air of plausibility, but you’ll still have to assemble the list of interested people to run any numbers on your own. Have 1 signup in 2 months? Then the price won’t matter much.

Subscribe to the Clean Cocoa Newsletter!

Write clean code effortlessly and become a happy programmer. Let me help you get the latest recommendations on time. No spam, guaranteed.

* indicates required