book covers

Indie macOS Dev Bundle, Swift 3 Ed..

Design solid applications and own your distribution process. Learn software architecture principles to make your Swift apps easier to maintain and extend. Set up your app for sale, with a trial mode and license generation all set. Including fully functional sample projects and code templates for your app.

Month 13 Is Out Of Bounds

Month 13 is out of bounds” appeared in my Xcode console logs today. But I don’t do date arithmetics.

When you create an empty macOS Cocoa app from the template, the message shows, too. It’s emitted before applicationWillFinishLaunching(_:) is called.

Looking at the Console.app output of other processes, I saw this was all over the place. TextMate, loginwindow, User Event Agent – every app is triggering this message.

Rdar or GTFO, right? – rdar://35792221

Let’s hope this does not indicate any important framework part is broken.

This is both humbling and worrying. Humbling, because Apple engineers make just the same silly mistakes as us app developers. Worrying, because having a working macOS is rather important to a lot of people around the globe, and while this message does not prevent me from using my Mac or any apps so far, bugs like these could have people killed in other contexts (think aerospace or autonomous cars).

Getting Worse

Update 2017-11-06: (Yes, I’m back on Nov. 6th! :) Seriously, it’s now Monday, Dec 4th.) Like some other people I was suddenly suffering from 100% CPU usage by the process UserEventAgent which also consumed RAM at a rate of about 4GB/ every 3 minutes. Disk swapping galore, my Mac turned unusable quickly. Only way I found to get rid of this:

  1. Deactivate automatic date and time setting
  2. Reset the date back to something in November
  3. Force quit the UserEventAgent process

Note that this only happened after rebooting. So if you can, do not shut down your Mac for a while just to make sure.

Why the Selection Changes When You Do Syntax Highlighting in a NSTextView and What You Can Do About It

On iOS, this does maybe not happen at all, but when you want to write syntax highlighting code for macOS apps, copying together stuff from around the web, you’ll end up with broken application behavior. In short: when you type and the attributes of the line change, the insertion point is moved to the end of the line. That sucks.

TL;DR: Do not perform style changes inside of NSTextStorage.processEditing() or NSTextStorageDelegate methods but subscribe to NSText.didChangeNotification or NSTextDelegate or NSTextViewDelegate.textDidChange(_:).

Description of the Problem

Illustrated in steps, it looks like this when you edit a line at the beginning and change the color of the whole line in accordance to the syntax:

The user types #, followed by a space character, to change the text line to a heading in Markdown and ends up with the caret at the end of the line

A lot of examples on the web are based off of NSTextStorage subclasses. Others use the NSTextStorageDelegate.textStorage(_:willProcessEditing:range:changeInLength:) callback with similar results. To simplify the explanation, let’s assume you subclass NSTextStorage and override processEditing() to apply syntax highlighting as advertised on objc.io:

class CustomTextStorage: NSTextStorage {
    // ... rest of the text storage methods ...

    override func processEditing() {
        processSyntaxHighlighting()

        // Apply highlighting before super so that attribute changes are combined
        super.processEditing()
    }

    func processSyntaxHighlighting() {
        // Parse text based on `self.editedRange` and apply styles, e.g.:
        let paragraphRange = self.string.paragraphRange(for: self.editedRange)
        if paragraphRange.hasPrefix("# ") {
            self.addAttributes([.foregroundColor : NSColor.red], 
                range: paragraphRange)
        }
    }
}

This wireframe applies highlighting to any edited line starting with # and then moves the selection to the end of the line. That means the position of the text caret – or “insertion point”, as the text view calls it – is not where the last user change happened anymore.

This is a widespread problem and the question is often asked on the web; people offer different work-arounds and quick fixes but no-one addressed the source of the problem so far, thus resulting in only 90% correct behavior.

Fixing the Editing Process to not Move the Selection (Warning: All Dead End)

To make sure you see which approaches will not be fruitful (and why), let’s go through a couple of work-arounds.

You can skip these approaches if you want to see the non-failing attempt.

Overriding Private NSLayoutManager API

In a talk from 2012, Max Seelemann of The Soulmen (the creators of Ulysses) showed the audience how to react to this odd phenomenon by applying a post-edit fix, overriding private API in NSLayoutManage._fixSelectionAfterChange(inCharacterRange:changeInLength:). (A video recording of the talk is only available in German.) That does indeed help with the insertion point, but if experiment further, you’ll bump into new display glitches and scrolling issues.

Keep in mind that 2012 was before Ulysses 3 shipped, and it’s 5 macOS versions ago. Maybe this was the only way to fix this behavior of the Cocoa text system back then. Compiling against the latest 10.13 SDK and deploying an application for macOS 10.11 and above, I can safely say that modern apps have no need to resort to this.

This points into the right direction, though: the NSLayoutManager is responsible for changing the position of the caret by altering the selection during processEditing().

Not triggering the NSLayoutManager

You can avoid moving the selection if you do not notify the text system of changes to attributes. That means you do not call NSTextStorage.edited(_:range:changeInLength:) with .editedAttributes in your CustomTextStorage.addAttributes(_:range:) implementation:

class CustomTextStorage: NSTextStorage {

    /// Switch used to prevent style changes in `processEditing` from
    /// triggering callbacks.
    fileprivate var isBusyProcessing = false

    override func processEditing() {
        self.isBusyProcessing = true
        defer { self.isBusyProcessing = false }

        processSyntaxHighlighting() // same as above

        super.processEditing()
    }

    /// The real implementation to delegate changes to.
    let content = NSTextStorage()

    override func setAttributes(_ attrs: [NSAttributedStringKey : Any]?, range: NSRange) {

       // When we are processing, `edited` callbacks will
       // result in the caret jumping to the end of the document, so
       // do not send them!
       guard !isBusyProcessing else {
           content.setAttributes(attrs, range: range)
           return
       }

       beginEditing()
       content.setAttributes(attrs, range: range)
       self.edited(.editedAttributes, range: range, changeInLength: 0)
       endEditing()
   }

   // ... rest of NSTextStorage implementation ...
}

This implementation will apply color changes but not move the insertion point.

It’s a 70% winning solution.

The remaining 30% are non-functional block changes. When you change the style of a block of text that exceeds the line of the insertion point (like a block comment, or something else that spans multiple laid-out lines in the text view), only the current line will be updated. The other lines will have new style information, but the layout manager will not schedule actually drawing them – until you select them with the mouse or move the caret inside with the arrow keys, say.

Invalidate the glyphs in NSLayoutManager to support block changes

So multi-line blocks of text do not redraw with the last approach. When I was so close to success a few weeks ago, I struggled to find anything to force-redraw the rest of the text as needed.

I tried two things:

  1. Notify NSLayoutManager about the edited attribute range after processEditing() had finished; and
  2. Invalidate a laid-out block of text on screen.

Sending the edited message as usual would, among other things I do not know about, call NSLayoutManager.processEditing(for:edited:range:changeInLength:invalidatedRange:). This is where I tried to hook in, first:

    func processEditing() {
        // Obtain the highlighted text ranges for post-processing:
        let rangesNeedingLayoutFixes: [NSRange] =
            processSyntaxHighlighting()

        super.processEditing()

        // Do the post-processing!!11
        for range in rangesNeedingLayoutFixes {
            for manager in self.layoutManagers {
                manager.processEditing(
                    for: self, 
                    edited: .editedAttributes, 
                    range: range, 
                    changeInLength: 0, 
                    invalidatedRange: range)
            }
        }
    }

This does indeed show attribute changes on screen, which means the layout manager generates new glyphs for the whole block as expected.

But when you hit spacebar or delete backwards, in lots of circumstances the scroll view jiggles or bounces up and down.

Another thing I applied to some limited success was to mark a larger range as invalid before changing the attributes:

func processEditing() {
    // Call super first this time
    super.processEditing()

    // Determine the to-be-highlighted ranges before
    let invalidatedRange: NSRange = ...
    self.layoutManagers.forEach { (layoutManager) in
        layoutManager.invalidateDisplay(forCharacterRange: invalidatedRange)
    }

    processSyntaxHighlighting()
}

That works way better but crashes in some cases, i.e. when the user scrolls the text view and you replace the contents during the scroll operation. Yeah, what a weird one. Imagine how long it took to figure out the source of seemingly unrelated, occasional crashes …

Interfere with Attribute Fixing

A suggestion I found on StackOverflow suggested to override NSTextStorage.fixAttributes(in:) and perform highlighting there.

override func fixAttributes(in range: NSRange) {
    processSyntaxHighlighting()
    super.fixAttributes(in: range)
}

This works because attribute fixing seems to be part of the call chain before the NSLayoutManager is notified. If you highlight inside processEditing, the attribute fixing will encompass the highlighted range; if you override fixAttributes, though, you get the user edited range and make sure to only pass that on to super.

Attribute fixing is important to remove inconsistencies in attribute assignments. Overriding the method means that the NSTextStorage now does not fix attributes for the whole range you applied highlighting to, possibly resulting in an invalid representation of attributes. That does not sound good; breaking attribute fixing by itself is bad in principle but might still not hurt much in practice. See “Using Text Kit to Draw and Manage Text” from the docs for more on attribute fixing.

Please note I haven’t tested how bad this approach really is in practice. I found this and dismissed it for good reasons, no need to benchmark anything: Since attributes are not fixed properly, the layout manager will not be notified about the real range of invalid glyphs resulting from the highlighting. The layout manager probably redraw the current line only, and thus have the same issues with long blocks of text like the last failing approach.

Understanding the Source of the Problem

Highlighting inside processEditing() will move the caret of the text view. Looking at stack traces (“Why and when does the text view scroll after editing? By how much?”) and comparing parameters passed around in private methods of NSLayoutManager and NSTextView, I came up with the following explanation:

NSLayoutManager receives a combined “edited” messages during NSTextStorage.processEditing() that covers all affected ranges.

It goes like this:

  • The user types in the text view. Her change affects only the typed-in character range, resulting in an editMask of [.editedCharacters, .editedAttributes] for the limited range of the edit. In the heading example from above, it would be for an affected character range of NSRange(1..<2) for typing the space character after the hash with a changeInLength of 1. This is just the expected notification.
  • The syntax highlighting during processEditing() now interferes. It affects a much broader range, for example the whole paragraph, sending .editedAttributes with a range of, say NSRange(0..<17) in the case of the example line.
  • The text storage combines alls calls to self.edited(...), forming a union of the ranges and a union of the editedMasks. The NSLayoutManager receives only a single callback, via .processEditing(for:edited:range:changeInLength:invalidatedRange:) for the larger range of NSRange(0..<17) with [.editedCharacters, .editedAttributes]. Again: the syntax attribute changes are not received separately.
  • The layout manager triggers a selection change whenever .editedCharacters is received, calling _fixSelectionAfterChange(inCharacterRange:changeInLength:) which Max had introduced above. The edited character range is meant to be much smaller than the changed attribute range, but we got a combined version only, so that’s why _fixSelectionAfterChange receives the larger range.
  • It also triggers NSLayoutManager._resizeTextView(for:) with the whole range instead of the original, much more limited user-edited range. That triggers the bouncing scroll behavior. It’s like selecting and then paste-overwriting the whole block every time you hit a key inside.

Following the process description, you have to avoid expanding the range for the .editedCharacters event when you apply syntax highlighting.

Applying a Real Solution

Once you separate the user-originating text change from the syntax highlighting and end up with 2 layout passes, _fixSelectionAfterChange is only called for the user edit (because it contains .editedCharacters), but not for the attribute change during highlighting. Similarly, _resizeTextView will not be triggered because of style changes.

To end up with two separate layout passes, you have to apply syntax highlighting outside processEditing(). This includes NSTextStorageDelegate callbacks.

The first layout pass is finished when you receive a NSText.didChangeNotification. You can subscribe to it only, or use textDidChange(_:) which is part of NSTextDelegate (and its descendant, NSTextViewDelegate).

Heads up: when you apply attribute changes from outside, make sure to wrap all the highlighting changes in a beginEditing()/endEditing() block or the glyph generation will be triggered immediately for every change, wasting performance.

Here is an approach I find suitable. I don’t use NSTextViewDelegate but the notification mechanism instead because then you can make someone else the delegate if you need one at all. Also, this way the SyntaxHighlighter service is self-contained; if it was the delegate, you could unintentionally disable syntax highlighting by changing the text view’s delegate to another object. Which would leave you with a monster delegate that does everything. Nobody likes that, so here you are:

class ViewController: NSViewController {

    var textView: NSTextView!
    var syntaxHighlighter: SyntaxHighlighter!

    override func viewDidLoad() {
        super.viewDidLoad()
        // ...
        self.textView = // ... or use IBOutlet
        self.syntaxHighlighter = SyntaxHighlighter(textView: self.textView)
    }
}

class SyntaxHighlighter {
    let textView: NSTextView

    private var subscription: NSObjectProtocol

    /// - param textView: The text view which should be observed and highlighted.
    /// - param notificationCenter: The notification center to subscribe in.
    ///   A testing seam. Defaults to `NotificationCenter.default`.
    init(textView: NSTextView, 
        notificationCenter: NotificationCenter = .default) 
    {
        self.textView = textView
        self.subscription = notificationCenter.addObserver(
            forName: NSText.didChangeNotification, 
            object: textView, 
            queue: nil) { [unowned self] notification in
                self.textViewDidChange(notification)
        }
    }

    func textViewDidChange(_ notification: Notification) {

        // This implicit type expectation is not Good Code.
        // Prefer to use a NSTextView subclass that codifies this 
        // dependency (and offers a `processSyntaxHighlighting` method itself).
        guard let customTextStorage = self.textView.textStorage as? CustomTextStorage 
            else { return }

        customTextStorage.beginEditing()
        customTextStorage.processSyntaxHighlighting()
        customTextStorage.endEditing()
    }
}

The notification is, as usual, sent synchronously. So your highlighting code will be executed right after the user hits a key (and after the change itself has been processed) without delay in the same run loop iteration. That means you won’t have a visible delay.

You can take chances and write asynchronous highlighting code, but that quickly looks weird. In complex situations, edited characters will now not appear after a delay; they will appear immediately. But the style changes are delayed, which in some ways feels even weirder.

I found it favorable to tolerate delays in synchronous highlighting that is noticeable (probably above the 100ms response threshold) which indicates: something is working hard here. Having immediate textual feedback but delayed style changes felt like the highlighter was too lazy to do its job properly. Especially so when you abort pending highlighting requests when the user types too quickly.

So that’s it, the most comprehensive explanation of the problem of syntax highlighting in NSTextViews affecting the caret location – and the only working solution that’s not just a half-assed work-around that looks good in demos but fails tests for production-level quality.

Feel free to share other half-baked solutions that kind of worked but eventually let you down in the comments and I’ll expand the list!

Blogs Merged Back Into One

I have migrated blog posts I published at cleancocoa.com over the past months back to this place. It was nice hosting the project on GitHub Pages, but in the end I never really wanted to post articles elsewhere.

The original problem of my web imperium still persists: on this personal page, both my coding stuff and my software need a hub. A proper next step is to create a better website index to direct casual visitors, I guess, and improve the website navigation.

It was fairly easy to separate the Zettelkasten Method project a couple of years ago because the two topics didn’t work well in one blog. But since then, the blog part was exclusively about programming. Tearing that out, too, just didn’t feel right after a while. Gut reactions aside, with the years I’m growing more worried when I do experiments like that because these personal decisions are also business decisions. I’m slowly becoming more professional in my concerns, I guess!

Dependency Injection via the Recent “Cake Pattern in Swift” Pattern is Useless in Practice

Dependency Injection means you do not create objects where you use them but “inject” objects a function/method/object depends on from outside. This is a useful trick to make code testable, for example. Once you adopt the mindset, it becomes second nature.

From the Java world stems the imperative to program against interfaces, not implementations. In Swift, this means to define injected dependencies not as concrete types but as protocols.

In an ongoing object collaboration, you will want to store the dependency as a property. The storage of the dependency is up to the component itself. Now the, let’s say, “injectability” can be lifted into a protocol, too. Then you can provide a protocol extension with a default implementation. That’s what Peter-John did in “Dependency Injection with the Cake Pattern” value.

The problem with this approach is that it has 0 real world value and is totally misleading because with that code you will not be able to actually inject anything; you’ll be hiding object creation in a protocol extension only.

Dependency injection is a useful pattern because it allows you to change the concrete object passed in. As I mentioned, apart from the final object in your production code, tests will benefit from injections a lot. When you do not write tests and never pass in another object in production code, you do not need dependency injection. “But it makes my code cleaner!”, people arguing based on principles will say. Yeah sure, it reads like cleaner code, but it’s useless code written like useful code in a “clean” manner. Getting rid of that code is more important than sticking the dependency injection label on it.

Look at the sample code from Peter-John. Here is the dependency as a protocol and some default implementation:

protocol ProductsRepository {
    func fetchProducts() -> [Product]
}

struct ProductsRepositoryImplementation: ProductsRepository {
    func fetchProducts() -> [Product] { return [] }
}

And here is the “having a dependency”-protocol, which is the result of what I called “lifting injectability into a protocol”:

protocol ProductsRepositoryInjectable {
    var products : ProductsRepository {get}
}

extension ProductsRepositoryInjectable {
    var products : ProductsRepository {
        return ProductsRepositoryImplementation()
    }
}

This protocol with its extension will help you get rid of writing client code like this:

class ClientLong {
    let products: ProductsRepository

    // Inject dependency in initializer:
    init(products: ProductsRepository) {
        self.products = products
    }

    func printPrices() {
        self.products.fetchProducts().forEach {
            print("This \($0.name) costs R\($0.price)")
        }
    }
}

Instead you can start with a shorter implementation of ProductsRepositoryInjectable:

class ClientShort: ProductsRepositoryInjectable {
    func printPrices() {
        self.products.fetchProducts().forEach {
            print("This \($0.name) costs R\($0.price)")
        }
    }
}

ClientShort().printPrices()

/*
 This Adidas Sneakers costs R2030.0
 This Nike Sneakers costs R1000.0
 */

There you have it: less code, using cleverly conceived protocols.

There are two very obvious problems:

  • Computed properties don’t work well for non-trivial object creation, for example if setting up the dependency in turn depends on some other dependency; you will want to store the objects. So a *Injectable protocol with a default extension might not always work.
  • No injection, but lots of hand-waving: it doesn’t help a bit when you actually want to reap any benefits of dependency injection, like, injecting a dependency. The code as cited does not allow injection of dependencies. It only hides object creation. To change the dependency in tests, you will need to define a property and override it somehow, via initializer injection or by making the property mutable internally. In any case, you will end up with code similar to ClientLong.

That’s when I concluded that this approach is not going to help you improve your code at all. There has to be more to make it useful in practice. All it does now is shorten the code of a contrived example to impress the reader.

A comment on the original post asked how to use this to inject mocks in tests, and Peter-Johns answer was along the lines of: use a dependency container singleton to create a testing seam. The protocol extension would then return DependencyContainer.instance.productRepository instead of creating a new instance. Actually providing a testing seam is an improvement. It has nothing to do with the pattern, though.

What you will want is code similar to ClientLong to keep the mechanism of injecting dependencies local. Then you use the initializer directly to inject your mock repository: ClientLong(products: mockRepository). You can do this a million times and it will Just Work. But forget to reset a dependency container singleton once and a lot of other tests that use the container will suffer and may even break. It’s also a lot less straightforward to read and understand than the initializer, thus increasing maintenance cost. If you think that accidentally breaking unit tests is a sign of bad tests, you’re right, and writing atomic unit tests for very cohesive objects is an obvious antidote – and now we’ve done a full circle, looking at unit tests for ClientShort which suffer from the very same problem.

A verdict from the author himself in the comment section on Medium is: this is only part 1 to show the basic technique. But, as I argued, it does not show actual dependency injection. It hides object creation in a protocol extension only.

If you take away anything from my post here, it should be that nice-looking samples do not always convey meaningful information, and that slapping “Pattern” onto something does not make it awesome. Or even useful.

Is the Mac mini (Mid 2011) a good developer device in 2017?

Short answer: No.


My trusty Mac mini served me well for years thanks to its 8 GB RAM and the 256 GB SSD. An SSD really helped make it faster back in the day. But with Xcode 9 and macOS 10.13 “High Sierra”, the machine begins to stutter.

I think it’s the CPU not really liking what I demand from it. Xcode 9 builds take a ton longer and the UI is less responsive. Sure, Xcode 9 sports a UI overhaul and might not be as performant as it could be, yet. That doesn’t help with the compile times which, for my current project, now take up to 5mins; that’s not even a fresh build.

So if you want to develop apps with Swift 4 and on the latest macOS, better get a more recent device. I don’t know which to recommend; the MacBook Pro is traditionally a good fit, but an iMac (or upcoming iMac Pro with its uncountable amount of CPUs and endless RAM) might be a good fit, too. Listen to Under the Radar ep. 89 for a more in-depth discussion by Marco Arment and David Smith.

I’d prefer a faster Mac mini because I have a nice-looking screen already and work at my desk 99.99% of the time anyway.

Inject ReSwift Middlewares from Different Project Targets During Runtime

Say you extract the ReSwift-based state module with all your app’s state types, reducers, and middleware into its own framework target. Until you add middlewares to the mix, it’s easy to keep this coherent.

Injecting side-effects through middleware is not easy to do, though, as long as you provide the Store instance from your state module. The store takes an array of Middleware upon initialization. They cannot be changed later. The state module would then depend on your app module with all its network request services and whatnot. That’s the wrong way around, also resulting in a circular dependency. Instead, you have two options to add side-effects that are inherently part of your app’s module, not of the state module:

  1. Create the store inside the app module, not in the state module;
  2. Add a general-purpose side-effect middleware that exposes mutation functions to the outside world.

The latter can look like this:

SideEffectRegistry.instance
    .addBeforeReducers { (bananaAction: BananaAction) in 
        Swift.print("Banana action passing through: \(bananaAction)") }

As a bonus (and risk!), this approach allows you to change which middleware are active during runtime. Keep in mind that ReSwift is designed not to allow this, so proceed with caution.

The closure is of type SideEffect. I found it beneficial to not have SideEffect take just any ReSwift.Action by default, because I usually conditionally check for one specific type, not multiple. So I lift the action type filtering to a generic constraint:

public typealias SideEffect<A : Action> = (_ action: A, _ dispatch: DispatchFunction) -> Void

Now you cannot create an array from these function bodies anymore; also, though the Action subtype is now reified as a generic constraint, the actual cast from Action to A has to go somewhere. I put it into a AnySideEffect box:

struct AnySideEffect {
    let boxedSideEffect: (Action, DispatchFunction) -> Void

    init<A: Action>(_ base: @escaping SideEffect<A>) {
        self.boxedSideEffect = { action, dispatch in
            guard let castAction = action as? A else { return }
            base(castAction, dispatch)
        }
    }
}

Now you can have an [AnySideEffect] array and pass any Action through. Only matching actions will be passed to interested middleware.

Heads up: This closure-based approach can allow removing all registered SideEffect, but not specific instances. For that, instead of a typealias‘d closure I’d use a reference type and check for reference equality (===) to remove/deactivate them.

Update 2017-09-29: I renamed the types a bit, from ApplicationMiddleware to SideEffect, etc.

The Full Implementation

/// - parameter action: The expected action to perform a side effect on.
/// - parameter dispatch: Default dispatch function into the current store.
public typealias SideEffect<A : Action> = (_ action: A, _ dispatch: DispatchFunction) -> Void

struct AnySideEffect {
    let boxedSideEffect: (Action, DispatchFunction) -> Void

    init<A: Action>(_ base: @escaping SideEffect<A>) {
        self.boxedSideEffect = { action, dispatch in
            guard let castAction = action as? A else { return }
            base(castAction, dispatch)
        }
    }

    func process(action: Action, dispatch: DispatchFunction) {
        boxedSideEffect(action, dispatch)
    }
}

public class SideEffectRegistry {
    public static var instance = SideEffectRegistry()
    private init() { }

    internal fileprivate(set) var sideEffects: [AnySideEffect] = []

    public func addBeforeReducers<A: Action>(sideEffect: @escaping SideEffect<A>) {
        sideEffects.append(AnySideEffect(sideEffect))
    }

    internal func process(action: Action, dispatch: DispatchFunction) {
        sideEffects.forEach { $0.process(action: action, dispatch: dispatch) }
    }
}

let sideEffectsMiddleware: Middleware<AppState> = { dispatch, getState in
    return { next in
        return { action in
            SideEffectRegistry.instance
                .process(action: action, dispatch: dispatch)

            next(action)
        }
    }
}

To Subscribe or not to Subscribe? Not!

The following is a guest post by my pal Sascha Fast, with whom I also work on the Zettelkasten Method project. Because of recent events in the Apple app ecosystem, he figured it’s time for uncovering the truth behind popular arguments for subscription-based pricing. So, please warmly welcome Sascha! 👏


Why do developers switch to a subscription model? There are many explanation out there to cover up the simple truth: Subscriptions promise more money.

It is a simple truth that is easy to say. Unless you have to sell this idea to people who ought to pay this money to you. How do you sell it? Perhaps, arousing compassion?

Developers have to eat… Kobe beef or canned beens?

What does it mean that developers have to eat? Basically, this is a disguise for the following statement: I don’t make as much money as I’d like.

But what does that really mean? Do you want some financial security and a can of beans a day? This sounds reasonable. But perhaps you want two vacations a year, send your kids to a private school and drive a big car to a restaurant to eat Kobe beef steak?

The statement “developers have to eat” is not only cheap and misleading. It is implying that I as a customer ought to be happy to give you money for your sense of entitlement to a certain lifestyle. I am a customer and give you money for the value you deliver. If you really want to hold on to that argument: Tell me how much income you think you are entitled to. If you tell me that’s none of my business, I’m fine with that, but then ditch the nonsensical claim that you don’t earn enough to fend off starvation.

Pull out your skin in the game

Another argument goes like this:

I am a creative person and cannot deal with the ongoing pressure of being forced to implement features to make money. Subscriptions give us more freedom to be creative.

Well, if you can’t stand the heat, stay out of the kitchen, snowflake. This uncovers another ugly truth: You don’t want any pressure to actually make your app better. Now you demand the money from me just for using the app. I repeat: You are sticking your hands out for money for the mere permission usage of your app.

As Nassim Taleb would ask: Where do you put your skin in the game? With subscriptions, you pull it out of the app development. Untrustworthy.

So, Don’t piss on my leg and tell me it is raining. I am asking you directly: What value are you offering me with your subscription to make me pay? Formerly, you gave me an app. A digital executable thing that serves as a tool for me. Now, you are selling me the mere permission to use your app for a short while. I cannot own anything anymore. No ownership. No control for me anymore. If you stop providing service for any reasons, I am fucked.

To sum this up: You decided to give me less value.

Don’t seduce me

Perhaps you are a developer, grinding your’s teeth as you read this. Perhaps you want to tell me why this is so good for me as a customer. The simple truth is: If it was so good for me as a customer, why do you need to explain it to me with lengthy rhetoric? It should be self-evident, shouldn’t it? If you offer something that is really good for me, you shouldn’t have to seduce me, should you?

Messed up finances

Additionally, you mess up my finances. If you read any good book on managing your finances, you will read something like the following: Quit your magazine subscriptions, don’t buy your coffee to go every morning at the corner store etc. Small expenses add up quickly.

On top, Subscriptions are difficult to handle. The default with subscriptions is: If you don’t do anything about them, you pay for them. So the developer turned the tables again. The customer has to actively stop paying. Without subscriptions, developers have to reach out to their customers to hustle for money. Subscriptions are nice for developers, but bad for customers. Again.

It gets worse:

Version 1.0 will be even more crappy

The earlier you can make money with worse of an app, the better it is for you, financially. The subscription model will encourage that. You can sell it with a promise. Developers will offer even crappier so-called versions 1.0.

The race to the bottoms begins and you are part of the problem

At this moment it seems very obvious that app subscriptions will increase the cost per app. This is only natural, because as of today, users don’t have to rent that many apps: They are willing to pay more at this point of time for their selected (few) favorites. On the Mac, there are only a couple of apps you have to rent. Therefore, the cost of renting one or two apps is no big deal. But as more and more developers switch to this model, and as the monthly cost increases for customers, many users will themselves switch – to different apps.

The market will create opportunities for developers who are willing to work for less money: The race to the bottom will accelerate. This is basic economics in the open market.

Max Seelemann of The Soulmen, developers of Ulysses, wrote the following:

Also, dear fellow developers: Only together can we end the cheap pricing spiral & estimations on the App Stores. Don’t undervalue your work! https://twitter.com/macguru17/status/897050754497884160

Max, I love your app to the death. For two years, I wrote thousands of words with it and considered it the best app for writers to this date. But imagine a developer could put himself in a better position by lowering his price to gain market advantage. What if he is willing to work for a cheaper price and is totally fine with it? Why shouldn’t he do it? There are tons of people who are happy with a humble income.

There is no inherent value to any product. There is only the market, governed by the invisible hand. Everybody can pick any price and see where this is leading his business. Someone could charge $100 per month for an app that’s worse than Ulysses for example. Someone could charge $10 once up-front for a better app, just because he doesn’t need more money, or because he lives in India and is happy about every extra dime. That’s not an ethical issue. It just means somebody is charging less than you, and will attract people who want to pay less. He’s not a bad, bad person; he’s targeting a specific audience. Just because you make less afterwards doesn’t mean that you are entitled to the potential sales you lost. Max is trying to make a ethical argument in a non-ethical space. For example: I could make a point from the consumers perspective.

The cheaper the price the more people you can help. Go as low as you can afford to.

Both view points are valuable depending on the perspective. But one thing is for sure: The race to the bottom has begun and will turn high speed. Meanwhile, Apple is guiding it with pretty impressive tactics.

Apple is incentivizing the developers to change to a subscription-based model. After a year for each subscriber, Apple’s cut decreases from 30% to 15%. Paid-up-front apps always suffer the 30% cut. They have a clear interest that the developers change to the subscription model.

Why? We don’t know. I personally believe it is about controlling the developers and outsourcing work while still having a big piece of the pie. Christian and I talked about the rationale behind the App Store: Great Developers make Apple’s iOS and Mac platforms more attractive because of the variety of available apps. But if you are a truly independent developer, Apple doesn’t see a dime from your efforts. Like in the days before the App Store, where people sold their software independently. And like quite few of developers do again, ditching the Mac App Store. Therefore, they trick you into slavery via the attractiveness of the App Store. The caveat: 30% of your revenue is taken away. This kills two birds with one stone. Apple gets control over developers through their guidelines and gets a buttload of money for which they have to do virtually no work.

Today, the App Store is the way to go to distribute your apps. With the incentive to change to a subscription model they are streamlining their revenue. They also guide the race to bottom. With the expectation of getting 15% more revenue if you can hold your subscribers for longer than a year, you can calculate more tightly. iOS and Mac get better and cheaper apps for their platform. If you don’t race along and keep your prices up, Apple will be just fine since they will still get their share of your money.

If you see the amount of users that are really angry about every developer who switches to a subscription model you can deduce that there will be a huge demand that is unfulfilled. This is an opportunity to fill the gap.

Quo vadis?

There are very few voices that are pro subscription. Some are okay with this model in spite of the increased costs for users. They know that this will entail more money for the developer. They want to support the developers. That’s the only reason they come up with: It is good for developers.

Where do these voices come from? They come mainly from pro users who make a living off of those apps, and other developers and journalists who clearly have an incentive to promote this idea.

I am not saying that developers who switch to subscription-based pricing are cutthroats. Not at all. I am saying that it is clearly the case that everybody knows what a subscription model means: More money for the developers. Nothing more, nothing less. There is no problem with that. But just say so.

The market will react because there will be people who are willing to adhere to a simple model that puts the user first. I estimate that there will be a couple (or plenty?) of other apps that switch to the subscription model. Once a tipping point is reached, there will be developers who are going to take advantage of the gap between those expensive pricing models (that is, subscription) for professionals and the cheap non-functional crap software crapware out there. Simple apps which give regular users enough functionality they need for a reasonable fixed price.

Planned obsolescence arrived in the world of software

Wikipedia defines planned obsolescence as:

Planned obsolescence or built-in obsolescence in industrial design and economics is a policy of planning or designing a product with an artificially limited useful life, so it will become obsolete (that is, unfashionable or no longer functional) after a certain period of time.

Wow. Sounds like subscription to me. If you want to sell your app using a subscription model, you have to program the app so that it ceases to function properly after a certain period of time.

This is perhaps the biggest failure of the subscription model I can think of. It isn’t that the app ceases to work by itself. You have to design it that way. If the app doesn’t work after a year or two because the operating system changed, the blame is not on you. But with subscription based pricing, you decide to deliver software that destined to die every month, except when the user inserts another coin at a certain time. It’s as if someone came to your car with a tire lock every month and you had to give him money so he goes away.

In some cases, notification may be combined with the deliberate disabling of a product to prevent it from working, thus requiring the buyer to purchase a replacement. (Wikipedia again) https://en.wikipedia.org/wiki/Plannedobsolescence#Programmedobsolescence

Remember the good old days? You found your old computer in the basement and started it just for the sake of it? Played the old games, immersed yourself in nostalgia. With self-dying software, developers end this.

I repeat: I wish the best of luck to you. But you made yourself part of the problem.

Good for no one but Apple

This text is a bit more aggressively written than I intended to. To me, it is just sad that developers let themselves being screwed by Apple. Even sadder that they pass the screwage on to the user.


Christian here again. Thanks, Sascha! This is a really important topic because we’re at a turning point for both developers and customers of Mac software. You probably already know that I totally support the verdict that the Mac App Store is not a good venue for anybody except shoppers. That’s why I teach people how to ditch the App Store. If you’re interested, I wrote about my perspective on subscriptions last year.. Leave a comment below, and thanks for reading!

Show a fat iOS-Style Insertion Point in NSTextView

I have no clue why my previous attempts at customizing drawInsertionPoint(in:color:turnedOn:) always produced visual glitches. I really tried a lot of different ways. But it turns out you don’t have to do that much, really:

class MyTextView: NSTextView {
    var caretSize: CGFloat = 4

    open override func drawInsertionPoint(in rect: NSRect, color: NSColor, turnedOn flag: Bool) {
        var rect = rect
        rect.size.width = caretSize
        super.drawInsertionPoint(in: rect, color: color, turnedOn: flag)
    }

    open override func setNeedsDisplay(_ rect: NSRect, avoidAdditionalLayout flag: Bool) {
        var rect = rect
        rect.size.width += caretSize - 1
        super.setNeedsDisplay(rect, avoidAdditionalLayout: flag)
    }
}

Adapted to Swift from a Gist by koenbok.

That’s all it takes. Marvelous!

Update: So it turns out that the drawing works just fine in a test project, but I end up with 1px-wide insertion points/carets/I-beams when I click with the mouse or press up/down arrow keys. Left and right work fine. I wonder what’s wrong with this. Isn’t it supposed to be a rather simple customization?

How to Use NSGlyph in Swift

I couldn’t find a simple answer on the web at first, so here’s my take for Googlers.

When you need NSGlyph (which is a UInt32), you probably want to use NSATSTypesetter.insertGlyph(_:atGlyphIndex:characterIndex:) or NSGlyphStorage.insertGlyphs(_:length:forStartingGlyphAt:characterIndex:) which in turn is implemented by NSLayoutManager. But the useful glyph types to use like NSControlGlyph are Ints. How do you get a NSGlyph-pointer from these?

Thankfully, in Swift you can satisfy UnsafePointer<NSGlyph> in two useful ways:

  1. Pass a reference to a mutable variable with the & prefix, like:

    let glyphIndex = ...
    let charIndex = ...
    var glyph = NSGlyph(NSControlGlyph)
    layoutManager.insertGlyphs(&glyph, length: 1, forStartingGlyphAt: glyphIndex, characterIndex: charIndex)
  2. Pass an array of immutable values that is going to be kept alive for long enough, like:

    let glyphIndex = ...
    let charIndex = ...
    layoutManager.insertGlyphs([NSGlyph(NSControlGlyph)], length: 1, forStartingGlyphAt: glyphIndex, characterIndex: charIndex)

Since the exemplary insertGlyphs method call uses a plural-s, it’s pretty straightforward to use an array once you stop worrying about the question “where do I get a pointer from?”


→ Blog Archive