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.

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/Planned_obsolescence#Programmed_obsolescence

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!

Sorting Markdown Tables by Column from the Shell

TableFlip doesn’t sort tables by column as of yet. So we all have to resort to other solutions – like shell or Terminal commands.

Let’s say your (Multi)Markdown table starts with a header (=2 rows) and has leading pipes like this:

| a | b | c | d |
| - | - | - | - |
| 1 | 2 | 3 | 4 |
| 9 | 1 | 2 | 3 |
| 3 | 4 | 5 | 6 |

You can sort the table by the 3rd column (column “c”) like so:

tail -n +3 table.md | sort --field-separator=\| --key=4

Explanation:

  • tail reads a file from the end; tail -n +3 reads a file from the end until the 3rd row, leaving out the first 2 rows, aka the header.
  • sort sorts the textual input; --field-separator=\| configures the sort command to not use tab stops but pipes as column separators; and --key=4 sets the 4th field (3rd column if your table starts with a pipe, which is counted by sort, too) as the input.

The output will be:

| 9 | 1 | 2 | 3 |
| 1 | 2 | 3 | 4 |
| 3 | 4 | 5 | 6 |

You can add the header back by combining tail with head, where head outputs the topmost 2 lines:

head -n 2 table.md && tail -n +3 table.md | sort --field-separator=\| --key=4

Et voilà:

| a | b | c | d |
| - | - | - | - |
| 9 | 1 | 2 | 3 |
| 1 | 2 | 3 | 4 |
| 3 | 4 | 5 | 6 |

Ready to be saved as a new file by routing the output to a new file name with ` > sorted_file.md`:

(head -n 2 table.md && tail -n +3 table.md | sort --field-separator=\| --key=4) > sorted_table.md

Week #18 of 2017 in Review

App News

  • Been working all week on the upcoming The Archive Beta. (You can still sign up!) First batch of testers will be equipped next week. I’m excited to see if nobody’s computer explodes.

Writing

Coding

Other Stuff

  • Accessibility is important in architecture as it is in technology. I found a tongue-in-cheek video with a Super Mario theme that probably resonates with geeks to raise awareness.
  • Last Sunday was sunny, so I went out and gathered the kids of our neighborhood to sculpt stuff from soap stone. I ended up being busy with taking care of the little ones but still finished a small snail.

Week #17 of 2017 in Review

Since I’m going to spread my writing thin on this blog in the upcoming weeks, I thought it might be nice if I highlighted some things that were happening. So here goes.

Update 2017-04-29: Forgot the coding stuff. Is now added!

App News

Blog Posts

Code

Other Stuff

  • Went out to paint a picture with acrylics last Sunday. Kind of happy, but I see where I can improve my strokes and technique. I’m rusty, and I never was that good in the first place, so way to go this year!

The Archive – Mac App Beta

The Archive screenshot
Early development preview of The Archive

My latest project is about to be ready: it’s a strictly plain text note-taking application. If you know our writing over at the Zettelkasten Method blog, you will know the method I’m incorporating in this app. Everything revolves about flexibility and your ownership of the notes. Plus the amazingly productive method itself is baked right into the app to guide your workflow.

Sign up here for a beta invitation in early May:

http://zettelkasten.de/beta/

Website Changes Imminent

The past couple of weeks have been unusually quiet around here. There are a couple of reasons:

  1. I was undergoing an operation (for a nearly-but-not-really abdominal hernia that I got from squats with bad form and tons of weight a couple years back and which showed symptoms in March) and being able to sit in front of a computer again took a while. I now permanently carry a 6x11cm plastic mesh in between the fasciae of my belly. Apart from most strength training still being too painful to do, everything’s fine in my day-to-day activities.
  2. When I could, I spent all my computer time on my current soon-to-be-announced project. It’s an important milestone in my Mac application empire and there are a lot of edge cases I have to cover to prevent data loss and the like. It’s pretty huge in terms of lines of code already, surpassing both the Word Counter and TableFlip.
  3. I am planning to move the programming blog from here to someplace else. Because I don’t have an outlet for all of my stuff at the moment. Programmers will be able to read my posts and notice my books on this site at the moment, but app customers will have a harder time finding their way around. As I grow my empire, I want to take better care of everything. I migrated most stuff to a GitHub Pages hosted Jekyll website. My secondary domain http://cleancocoa.com/ now points there if you want to have a look. Which means the schism is already real, it only doesn’t show on this website, yet.

Then there’s a lot of preparation happening for side-projects and my stuff at the Zettelkasten Method blog where we will run a live video stream today, by the way.

So the delay here is due to managerial problems and some re-structuring. I hope to clean up everything, soon, and then move forward with higher velocity. There’s a ton of unedited posts in my backlog waiting to be published.

FatSidebar View Component for macOS Released

One important user interface part of my latest top-secret project involves a sidebar of buttons. Like a regular toolbar, but taking up less space for chrome, looking more flat, and the user should be able to create toolbar buttons herself.

So while I was mostly sick at home for the last couple weeks, I spent my time cobbling this together. With drag and drop reordering and all.

logo

Find FatSadebar on GitHub!

I have never written my own custom view component from scratch before. I helped improve KPCTabsControl for Swift 3 when I created TableFlip last year. And of course I participated in a lot of smaller open source projects, too. But I never started from scratch, and that was cool.

Also fun: creating the library’s own “logo”. Made it feel so much more official.

What’s cool about writing a new thing from nothingness is that I had no clue what to do and how to start. This component turned out as rather adventurous mental gymnastics because I had to leave the paths of application development I know so well. I still don’t know all the answers; what are best practices? Get something colorful on screen? Customize drawRect and draw boxes and placeholders? Partition the view into sub-components using Auto Layout from the get go? Is drawing text better handled by NSTextField labels than NSAttributedString.draw(in:) or is the overhead too much? (I still don’t know the best answer for this.)

Anyway! I ended up putting this together as a library with sample app. There are some unit tests for inserting items into the “fat sidebar”, but otherwise I find the drawing and layout related code to be absolutely hideous. Cannot come up with improvements on that front that go beyond cosmetics, though. Maybe later, with more experience.

Non-Obvious Swift: Defer

The following code works as expected:

class FooCollection {
    private var items = [Foo]()

    func removeAllItems() -> [Foo] {

        defer { items.removeAll() }
        return items
    }
}

But do you know what “expected” means in this case?

As a reader, you assume the author had an intention. You look for the mens auctoris and are an overall benevolent reader, I hope. Presupposing said intention, you may assume that it does something special if you put the call to items.removeAll() in a defer block.

The removeAllItems method returns an array of items. If the internal collection was empty when the return statement is reached, that’d be pointless, wouldn’t it? Since your benevolent, you assume that the author isn’t stupid and that it does indeed return a non-empty collection in some cases.

Say the author had added a documentation line:

/// - returns: Array of items that were removed.
func removeAllItems() -> [Foo] { // ... }

Now that should tip the scale! So the internal collection of items is returned and afterwards emptied. Aha! How clever!

Ze true connoisseur of Swift appreciates ze brevity of defer

As a critical reader, you should be able to solve the puzzle and call the author names. Because, why make it so non-obvious to the reader? Why the guessing that either requires manual (or unit-) testing or the Swift doc (and trust in its truth) to verify the assumptions?

I was curious about the outcome of this approach so I just tried it before writing this up. Then I deleted the “”“clever”“” code and replaced it with what I had before:

class FooCollection {
    private var items = [Foo]()

    func removeAllItems() -> [Foo] {
        let removedItems = items
        items.removeAll()
        return removedItems
    }
}

I prefer this any day. I hope you do, too.

Setting the Line Height of a NSTextView

NSTextView (and UITextView for that matter) have a defaultParagraphStyle attribute where you can set the text’s line height. That works swell – if you display text statically. Once the user can enter something, you can run into trouble:

  • If the user adds text in the middle of an already laid-out line of text, the paragraph style is retained.
  • If the user writes at the beginning of the line, the line height info gets lost.
GIF of the process
This is what happens when you type at the beginning of a line

It’s your usual RTF nightmare. I know this behavior from rich text editors; and I developed my own way to make sense of it in the process. It might not be what is really going on, but it’s a good heuristic: it’s just like the opposite of making a word bold, placing your cursor after that word, type, and get more bold text. There, the “bold text” information is carried on. The cursor inherits this info from the character left to it. But if you start at the beginning of a line, your cursor will not inherit what comes afterward. And since there is nothing before its position, it starts with empty info, and thus empty line height settings. Since the whole paragraph is affected by this, the latest change wins. Beginning to type at the beginning of a paragraph with empty paragraph settings removes them from what comes afterwards.

So this might not be The Truth, but it helps me deal with shitty software. I don’t want to write shitty software, though, so I look for ways out of this. I don’t intend the user to change paragraph settings; I want the text view to have a certain look and feel no matter what gets pasted or typed in it.

Hunting for Core Text/TextKit callbacks, NSTextStorageDelegate seems to provide a good customization point:

func textStorage(
    _ textStorage: NSTextStorage, 
    didProcessEditing editedMask: NSTextStorageEditActions, 
    range editedRange: NSRange, 
    changeInLength delta: Int
) {
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineHeightMultiple = 2.0
    textStorage.addAttributes([NSParagraphStyleAttributeName : paragraphStyle], range: editedRange)
}

Of course it makes sense to store the global paragraphStyle once and re-apply it here. I don’t know if this is the best place to put it, though. Re-applying all the NSAttributedString settings while typing might not perform best.

Also, this is affecting the “rich text representation” of the text. If you copy the result and paste it into TextEdit, say, the text will look the same, line height settings and all.

You can override the pasteboard representation to be “plain text” only in order to remove the style info and thus have it behave like the “Paste and Match Style” command from the “Edit” menu automatically.

Again, I don’t know if this is the best way to do this.

What I’d expect to create instead:

  • a text view with a “plain text” representation by default (the model)
  • typesetting customizations that only affect what is visible on screen (the view)

I imagine this to be like HTML code/browser rendering, not like WYSIWYG. What you type is not what you see. Just what you’d expect a source code editor to be like.

I’ll keep you posed as I dive deeper into TextKit and stuff.


→ Blog Archive