Dash 5 Documentation Browser for Mac is Available

Dash 5 has a new, slick, flat UI. Here you see how the “apple:” prefix turned into a documentation-relative search.

I use Dash every day. And while it seemed the last upgrade to v4 wasn’t that long ago, my 1Password-powered licence purchase history tells me it was in February 2017 that I last paid for a Dash license, almost 3 years ago. So it’s about time that a paid upgrade hits Kapeli’s online store!

What can I say: I enjoy using Dash. It works. I use it to browse the Swift language docs, UIKit and other Apple framework docs, the Ruby and PHP language documentation, and what not!

Dash borrows interaction patterns from web browsers. You go to the search bar via Cmd-L, which is usually bound to the “location bar” in web browsers, and also the Omnibar in my app The Archive, and nvALT, and similar apps. The usual “find” shortcuts won’t work: Cmd-F will search within the visible document, and Cmd-Opt-F, regularly used to global searches in Finder and apps like OmniFocus, is not bound to anything. Since the search bar is now displayed like a browser location bar anyway, I didn’t have trouble adjusting.

If you’re new to Dash and have e.g. the Ruby and Apple docs installed, here’s The 1 Weird Trick That Saves Hours Of Work – or whatever buzzfeed headline this could become.

How to Limit Your Search to a Particular Docset

By default, Dash searches withing all your installed docsets. I have more than a dozen installed: one for each language I regularly use and a couple of frameworks/libraries that I use time and again, for example: the Apple framework docs, Ruby, PHP, Python, also Git Flow, Ruby on Rails, the Gosu game framework, ncurses.

When I search for the “Iterator” protocol definition in Swift, I don’t need or want to see the Ruby equivalent. I want to focus on the Apple docset. Here’s what you can do:

  • Open a new empty tab in Dash with Cmd-T to start a new search context
  • Type apple: iterator and notice how the search now displays a “locked” Apple icon in the search bar + the term “iterator”. This now confines searches to the Apple framework/language docs.
  • Open another tab and type ruby: each_with_object and notice how the icon is now the Ruby language icon and the search limited to the Ruby docs.

Each docset has its own search prefix. You can inspect these in the app Preferences (Cmd-,) in the “Docsets” preference pane. The right column shows the prefixes.

Years ago, I had to double-click the documentation bundle icons to confine my searches; but since learning of the DOCNAME + : search prefix I can search way more efficiently.

I have never used search profiles, though I can see how this can help trim down search results in a useful way, too. You could create a search profile for “Web Development” that enables searching in HTML, CSS, SCSS, and some JavaScript libraries but does not include any of your other docsets. That’s like combining multiple docset search prefixes in a set union. Similarly, for a Rails app, to include the Ruby language docset, Ruby on Rails framework docset, jQuery and SCSS can be handy.

If you haven’t already, grab yourself a copy of Dash!

Native macOS Notifications for Emacs Org Tasks and Appointments

Emacs is a text editor, kind of. But I use its Org mode for “keeping notes, maintaining TODO lists, planning projects, and authoring documents with a fast and effective plain-text system” – its Agenda became my daily productivity hub. It’s a calendar view of all things scheduled for the day, plus some other info interspersed: thanks to the plain text nature of the whole interface, it’s simple (albeit not easy) to re-style everything you see there. Add sub-headings, spacing, links, text, what have you.

But I still use the macOS native Calendar and Reminders. Because they produce notifications on my Mac.

On iOS, thanks to the amazing beorg app, I get notifications for the parts beorg understands. And it seems to understand all of my task deadlines and appointments so far. I can highly recommend this app. It’s a native iOS app that parses the .org files and presents a graphical UI, though. Emacs is just text. And as long as I don’t run macOS from within Emacs, which I by this point bet you can do, Emacs-internal popups will go by unnoticed when I browse the web, message people, do email, or program in Xcode. So Emacs Org mode cannot be my sole trusted system whenever I need a push notification to e.g. get up and leave the house for an appointment.

Until this week, that is.

I figured out a crude way to produce macOS native notifications based on deadlines and appointment times in my Org task items. At the moment, I get a notification of everything with a time and date attached to it and cannot selectively enable or disable reminders-like notifications. But it’s a start.

Approach to a Solution

Emacs can run shell processes just fine. That means as long as I have access to a command-line program to produce notifications, I can make this work.

  • I know and use terminal-notifier by Julien Blanchard to produce Banner-style notifications for long-running tasks from the shell. You get a notification that faded away after a while. Good start, but I need sticky Reminders-like notifications for most appointments.
  • A fork of terminal-notifier by Valere Jeantet called alerter implements sticky notifications, with the ability to even send Message-like replies back to the process if configured thus. That’s what I’m using, albeit with the default “Close” and “View” actions.

Emacs comes with a package called appt for Appointment Mode. I don’t use the mode, but the package comes with background checks that one can hook into to produce notifications at the right time.

Code to Implement This

I didn’t figure this out on my own. My Emacs Lisp is just too bad for coming up with a working solution for most things.

I did modify a solution by Sarah Bagby that is itself a modification of other people’s code.

Sarah uses terminal-notifier, which runs the notification and exits immediately. alerter keeps running while the notification is visible to receive the reply event; so Sarah’s synchronous call to the shell-command function wasn’t viable as it blocks Emacs. The obvious alternative, async-shell-command, produces a new buffer to capture the output in a split window, which I don’t want to happen.

Luckily, I found the start-process function that runs an executable asynchronously, and you can also specify a buffer name to capture the output, and pass nil to simply discard all output.

This lead me to changes by Justin Heyes-Jones who’s also using terminal-notifier but with the start-process function, and the following nifty line of code:

(defvar terminal-notifier-command (executable-find "terminal-notifier") "The path to terminal-notifier.")

This produces a variable with the full path to the executable program, based on a lookup in your executable path directory list. I compiled and installed alerter locally in ~/bin, so I added this path to the lookup list, before the Homebrew binary folder:

(setq exec-path (append '("/Users/ctm/bin" "/usr/local/bin" "/usr/local/sbin") exec-path))

I’m so bad at Emacs Lisp that I couldn’t make this work with ~/bin using expand-file-name, so I hard-coded my path reference in there as /Users/ctm/bin. If you want to copy the code, I’m sorry you have to adjust this.

Now to the adjusted setting in my init.el:

(require 'appt)

(setq appt-time-msg-list nil)    ;; clear existing appt list
(setq appt-display-interval '5)  ;; warn every 5 minutes from t - appt-message-warning-time
(setq
  appt-message-warning-time '15  ;; send first warning 15 minutes before appointment
  appt-display-mode-line nil     ;; don't show in the modeline
  appt-display-format 'window)   ;; pass warnings to the designated window function
(setq appt-disp-window-function (function ct/appt-display-native))

(appt-activate 1)                ;; activate appointment notification
; (display-time) ;; Clock in modeline

(defun ct/send-notification (title msg)
  (let ((notifier-path (executable-find "alerter")))
       (start-process 
           "Appointment Alert" 
           "*Appointment Alert*" ; use `nil` to not capture output; this captures output in background
           notifier-path 
           "-message" msg 
           "-title" title 
           "-sender" "org.gnu.Emacs"
           "-activate" "org.gnu.Emacs")))
(defun ct/appt-display-native (min-to-app new-time msg)
  (ct/send-notification 
    (format "Appointment in %s minutes" min-to-app) ; Title
    (format "%s" msg)))                             ; Message/detail text


;; Agenda-to-appointent hooks
(org-agenda-to-appt)             ;; generate the appt list from org agenda files on emacs launch
(run-at-time "24:01" 3600 'org-agenda-to-appt)           ;; update appt list hourly
(add-hook 'org-finalize-agenda-hook 'org-agenda-to-appt) ;; update appt list on agenda view

You can see that I copied most of the setup code, removed the (display-time) function call (because I don’t want to have a visible clock in my editor), and created the ct/send-notification function so it finds the alerter binary for me (Sarah’s code had this hard-coded) and invokes the notification helper program. I added -sender and -activate arguments to the call so that I get the app icon in the notification based on the sender, and because terminal-notifier would use the -activate argument to open Emacs when clicking a notification (alerter currently doesn’t, but maybe someone will merge these two together again …).

The appointment database is refreshed hourly, plus every time my Org agenda is rebuilt. Sounds sufficient so far.

Now this Org mode sub-task:

** TODO Hello World, this is a task due soon!
SCHEDULED: <2019-12-04 Wed 10:53>

is transformed into a notification:

When you have multiple items due at about the same time, all their info is crammed into the same notification box. That’s not that useful on its own, but it still is a trigger for me to look at the agenda and see what’s going on.

For appointments that happen in the city, I usually add alerts in the native Calendar.app 45m to 60m before the appointment to pack my things and prepare to leave the desk. I had trouble at first, but it works out-of-the-box when I add :APPT_WARNTIME: 60 to the task property drawer:

** TODO Hello World, this is a task due in the far future!
DEADLINE: <2019-12-04 Wed 23:59>
:PROPERTIES:
:APPT_WARNTIME: 60
:END:

This will produce a notification 60 minutes before the event. And then repeat the notification ever 5 minutes, because that’s the appt-display-interval setting for me. This is not optimal, and I’d rather have a de-escalating display timer that happens 60m, 15m, 5m, and at the meeting itself.

I think I will disable the interval completely. I have to test all of this in practice, first, though.

Next Steps

  • alerter’s output is appended to a buffer in the background; I could process this output to e.g. show the Org agenda when the “Show” action button is clicked. That would be helpful to offer a “remind me again in X minutes” option, solving the problem of notifications popping up every 5 mins for an hour when I set :APPT_WARNTIME: 60.
  • alerter does not activate Emacs when I click the “Show” button at the moment, but terminal-notifier has built-in support for this. Should be fix-able.
  • The notification title is “Appointment in X minutes”. If you have 2 appointments, one due in 5, one in 10 minutes, the title will read “Appointment in (10 5) minutes”. That’s a string representation of an emacs list of minutes. Not that useful in practice.
  • terminal-notifier and alerter don’t need to be separate binaries, and I want to see why their re-combination failed in the past. Maybe I can help out there.
  • org-agenda-to-appt doesn’t clean up removed appointments. I don’t know if I want it so, because then it will be a destructive process. It’s not “stateless” insofar as it cleans and replaces appointment reminders; it’s not a pure function mapping all agenda tasks to the new list of appointments. If you add appointments to the list via any other means, they will be preserved at the moment. That’s good. But on the flip-side, after I added the test event with warnings 60 minutes before the due time, it wouldn’t ever go away. Call appt-delete interactively to go through all upcoming reminders and delete whichever gets on your nerves.

FourLayerArchitecture Is Still Under-Appreciated

I was recently following a link to The Wiki, the original c2.com wiki by Cunningham & Cunningham, Inc. It was a link to the FourLayerArchitecture page. At the very bottom, it currently says “Last edit August 25, 2006”. In the early 2000s, the wiki had to be closed for editing by the general public because of abuse, and this page seemingly lays dormant ever since.

If you never read the page, I recommend you take a look. The wiki in general is a great resource of programming wisdom and Agile methodology origin stories.

Now what I find striking is the fact that you’ve got the release date of the iPhone on one hand – 2007, with 12 years of technological advancements and the subsequent rise of the mobile development craze since –, and this wiki page’s edit date of late 2006 on the other. So the iPhone, overall, is a newer technology than whatever the page currently reads.

And it does read a very simple but interesting thing: it proposed a software architecture that is composed of 4 layers for better maintainability. I have read about these layers in countless books, as long as these books were targeted at Java Enterprise developers. But not a single one of the popular books for iOS development targets this. I began to write about the topic of “software architecture” precisely for this reason: because I found it to be a very interesting, rewarding, and utterly underappreciated topic.

All we’ve got in the iOS/macOS scene so far is MVVM, VIPER, and maybe some Reactive/declarative approaches.

I develop my own apps with some kind of a layered architecture ever since, and I still enjoy doing it. It helps me develop the apps in a way that reduces entanglement a fair bit. It’s great. I love it. 10/10, can recommend.

So give the wiki page a shot and think how you could benefit of a separation of your code into

  1. the UI layer,
  2. the Application or mediation layer that connects all the pieces,
  3. the Domain Model layer, where your dependency-less business-objects live, and
  4. the Infrastructure layer, where your networking and database connection code resides.

That Weird Obstable of Interface Builder When You Get Started With iOS Development

A very strange obstacle to overcome when you just get started with iOS or macOS programming is to use custom views or view controllers. How does this magic even work? And what do the steps mean that you have to perform?

When you use a Xcode template, you get a Storyboard or a Xib with the most important components for an initial, empty app to display something on screen. This is accompanied by an AppDelegate and a custom ViewController class. If you don’t know anything and just get started developing for iOS, say, then this is a good place to start hacking away: after all, the bare-bones infrastructure has been handled for you.

You will need to learn how to navigate around in an Xcode project, which takes time already, but apart from that, you can pretty much start copy & pasting stuff from the interwebs into a test project and see where this takes you.

But eventually you want to make a custom view. One that draws custom shapes, for example. If you have experience and know what you’re doing, it’s as simple as:

  1. Add a new file from a Cocoa class template to the project, CustomView, inheriting from NSView/UIView,
  2. override the draw(_:) method of the custom view with your drawing code,
  3. use CustomView as the type name in Xcode’s Interface Builder to instantiate the view from the Xib/Storyboard.

That’s “only” three steps, and they are instructional for me, and most iOS devs I can think of will know how to parse these instructions. But if you just get started, this is not helpful.

Then, you need a list like this:

  1. Create a new file for the custom view:
    1. Select “New” > “File…” in Xcode.
    2. In the template picker sheet that pops up, make sure your app’s platform is selected at the very top (iOS or macOS).
    3. Then select the “Cocoa Class” template. Double-click or hit “Next” to continue.
    4. In the “Class:” text field, enter “CustomView”. That’ll be the name of the type you are about to create.
    5. From “Subclass of:”, select “NSView” (or “UIView” on iOS). Leave the language to the default, probably “Swift”.
    6. Select a place to save the file. The default that Xcode suggests is fine for now, but you may want to pay closer attention to this in the future when you start to organize files in custom groups. Proceed.
    7. Xcode’s editor will open the file for you automatically.
      • You see a couple of lines of comment at the top that you can ignore.
      • The import statement makes sure that this file knows about the platform stuff provided by Apple.
      • The class CustomView: UIView { ... } (or class CustomView: NSView { ... }) block is the declaration of your class. Inside the curly braces, you can put method declarations that will be usable by instances of your view. We will implement the drawing routine there in a second.
  2. Write the custom drawing routine:
    1. Inside the curly braces that delimit all contents of your custom type, add a new line and then override the default drawing method by typing override draw(_ dirtyRect: NSRect) { }. If you type “draw”, Xcode will show a couple of suggestions, where you can pick the correct method and have the declaration be generated for you. The dirtyRect parameter is passed into the view so it knows where it can draw. This is useful for large, scrolling views so you can redraw only the visible portion on screen, or a part below the mouse cursor. That’s why it’s called “dirty”: it’s the portion that needs redrawing.
    2. Inside the curly braces of this method, you can add your own drawing code. For now, we will fill the whole region of the view with a single color. To do that, add a line inside this draw method body that reads: UIColor.blue.setFill() to change the current fill color to blue. Add another line afterwards that reads: dirtyRect.fill(). That will use the currently set color and the rectangle portion that needs redrawing, which by default will be the whole area.
    3. The result should look like this: swift class CustomView: UIView { override draw(_ dirtyRect: NSRect) { UIColor.blue.setFill() dirtyRect.fill() } }
  3. Hook your new view type to be used by Interface Builder:
    1. Open your MainMenu.xib/Main.storyboard/… in Xcode.
    2. In the leftmost sidebar of the editor portion of Xcode, select your ViewController scene. That should make it visible if it wasn’t already, which can sometimes happen if you open a file in Interface Builder after a long while. [Here, I’d add screenshots to highlight which sidebar I’m talking about, because Xcode’s default view has a sidebar to the left with the project navigator, a sidebar to the right with file info, and then the Interface Builder view has its own outline structure.]
    3. Expand your ViewController scene by ⌥-clicking the rightward-facing triangles. That should expand (and collapse) the whole sub-tree.
    4. From the expanded view hierarchy that this outline represents, select the innermost View. That’s the default content view of your ViewController, which is a feature-less UIView by default. We are going to change it to our custom view type.
    5. With the View selected, make sure the right inspector sidebar in Xcode is visible where you can inspect properties of whatever is currently selected inside Xcode. You can use the rightmost toolbar buttons of Xcode to toggle the sidebar. The inspector sidebar has a couple of icons at the top to change its currently visible tab. We want the “Identity Inspector”, which in current Xcode versions is the 3rd tab. (Hover over the icons to see the tab names.) You can also quickly jump to this inspector tab by hitting ⌘⌥3, which will also show the sidebar if it wasn’t visible before. I recommend you memorize this because you’ll need it a lot.
    6. In the “Identity Inspector” sidebar, with the View still selected, you will see at the very top that the “Custom Class” group of properties has a drowdown labeled “Class”. It’s set to a placeholder value of “UIView” by default. In that field, type “CustomView” to select your own view. This instructs Interface Builder to create an instance of your new type instead of an empty blank view when the app launches.

See how much explaining I did? I even erred on the side of brevity here, omitting a few explanations that I found to be instrumental to understanding what’s going on when I teach people Swift and using Xcode.

The last step, wiring things up in Interface Builder, is just the weirdest. And it’s very fragile: when Xcode changes, all screenshots will be outdated. This happened a couple of times in the past decade. It’s hard to explain what’s going on in words, too. Opposed to code, you cannot show the result in a single snapshot. You have to describe the process, and to describe the process, you have to describe the steps involved. Nobody enjoys reading or writing these kind of instructions. And you cannot give a reader instructions like you’d give a machine, e.g. in UI tests, where you’d say app.buttons["Identity Inspector"].tap() if you’re lucky, or moveMouse(1234, 300) to define absolute coordinates (which doesn’t work, of course, so you have to stick to “toolbar button in the top-right of the window”).

If you, the reader, do not have access to higher-level concepts like “create a file from template”, or “change the type of the view in IB”, then all of this gets very, very weird.

What does it mean to enter the “CustomView” type name in that particular sidebar that is only visible when you have an Interface Builder document open and select a view (or other object) inside it?

To help one of my pupils understand this, I eventually resorted to story mode:

The document that you edit in Interface Builder is essentially saving an instruction for your app to create your user interface for you. You could write it in code, but this is a bit simpler, and you have visual feedback in the editor, which is nice, especially when you just get started. When we have a look at the documentation of UIView, we can see that there’s an initializer called init(coder:) that you probably will not call for quite a while in your code: it is used by the part of your app that understands Interface Builder files to create a new object instance, though. During app launch, a “coder” is used to decode the declarations from the Interface Builder file and make an object of your custom type for you. If we rely on these instructions, we have to tell the decoder that your CustomView does exist, and that you want an instance of that instead of the default UIView here. The “Identity Inspector” is concerned with all things that pertain, well, the identity of the view, its type and some other fundamental settings. It’s visual properties, like size, or textual content in case of text labels, is grouped under different inspectors. So to tell the decoder which view object type you want, you have to change the “identity” instructions so that the “Class” that is used is known by the name “CustomView”. To do that, we have to expand the inspector sidebar first, then head to the third, the identity inspector, by clicking …

The story about decoding and what happens here apparently resolved some confusion. It’s good I do know this stuff and can produce a very shallow description of the goings-on here to help others learn and understand the steps involved. Because rote repetition will only get you so far. I still forget to change the class name in my Interface Builder files every other day, and I program for Apple platforms on a daily basis for 8 years now. It’s second-nature to double-check this place when things don’t look as expected. But the actual setup is still arcane when I try to take on the glasses of someone new to the platform.

Like, have you ever tried to do a remote screen sharing session and tell the other person which “tab” you mean when you look at the Xcode project settings? You have the Xcode tab bar with currently open files. You have tab icons in the navigator sidebar to the left; you have tab icons in the inspector sidebar to the right; you have tabs in the debug console pull-up-thingamob at the bottom. And you have a white editor screen with another level of master–detail-views with a sidebar of project targets and a tab-bar at the top with “Build Settings” and “Info” and the like that do not even look like interactive elements!

Close your eyes, forget that you know Xcode well, then try to make sense of what you see in this picture. Describe the portions on screen to a layperson. I’m glad I know that the left and right sidebar have distinct names (“navigator” and “inspector”, respectively) so I can refer to them by name as well to not rely on spatial arrangement forever in conversations.

It is just so much stuff. So – much – stuff!

I feel at home in Xcode, I really do. When I open the app and whip up a project, it’s like an instant stress-relief. That’s my place, alright.

But I have a really hard time helping other people on board.

And I do remember, faintly, how awkward it felt to get around in Xcode back in 2012. Back then, Interface Builder was a separate tool with a separate window. Nowadays, the main Xcode window does never change and simple swaps out the editor compartment and the sidebar contents according to context. This is the diametral opposite of a modeless interface. You have to know which mode you’re in to get where you want to go. You cannot change the editor from an Interface Builder pane to a code file and have the “Identity Inspector” stay open, like if you want to look up the name of your type again, which you forgot because all this is so much overhead, so much you have to keep in mind, that you just have to get back to the code file to make sure you copy the type name to clipboard, but oh no, the inspector has changed to totally useless file information or a live documentation snippet that you may have never seen before, and which makes you afraid, so what now, yes, get back to the Storyboard file, but now everthing is hidden again and you have to figure out where the view was, what you had to click to get to the scene, wondering why the Storyboard preview is empty at all in the first place (is this a bug? is my app broken? oh god did I make a backup?), and then finally you get there, and you do not even understand what’s going on.

So yeah. I think this is a very weird, and through its weirdness a very steep learning curve for beginners. The tools are powerful, and they look much better than they did in 2012, but I do like to think that the dedicated Interface Builder window helped me to make sense of the different parts of app development one at a time.

People still seem to get used to this, so it’s not that bad, right? Well, yeah, it’s just a pain to explain. I hope we all figure out good ways to teach newcomers this stuff so we all get the bonus of proficient developer colleagues – instead of mortally afraid computer users who try not to step into hidden landmines inside the foreign environment that they have to use to make an app work. This Interface Builder stuff is just the weirdest overhead, in my opinion, but it’s also very useful to get started with IB instead of doing all things in code, because you get results quickly and get a feeling for the UI components early. At the cost of having to grok a totally different tool on top of the new language and framework.

Working on the Zettelkasten Online Course

For about two weeks now, I’m almost exclusively working on the upcoming Zettelkasten Online Course, providing text feedback on the script and creating presentation slides. I’m picking up speed as early style decisions are settled, but there’s still a ton of stuff to do.

I guesstimate that the remainder of 2019 will be dedicated to this project, taking up the better part of my work-days.

That, in turn, means that updates and fixes for my apps take a bit longer than usual for the time being.

I’m looking forward to get the first feedback for the course. It’s the brain child of Sascha, but I’m very proud of the visualizations already and try to produce the slides with the highest craftsdwarfship possible. It’s already a lot of fun, and I think it’ll be fun to watch and learn, too.

What this course is about, you ask? Well, if you ever found yourself in a situation where you didn’t know how to finish a writing project or ever felt overwhelmed by the amount of research to be done, this course will teach you how to tackle all that. And more. It’s a complete course on knowledge management and learning. I’ll show some details here at a later point.

WordCounter v1.6 Brings Analytics to Your Productivity!

My stats for October 2019. Didn’t notice I wrote that many words in emacs.

The WordCounter update to v1.6 is online! It brings the long-awaited statistics module so you can get an overview of your productivity over any period of time. It also comes with a CSV export of the visible data.

Download the free update!

Export and the aggregate numbers will be expanded in future updates. The stats currently supplement the daily calendar history, but the history will be obsoleted as I move the daily details into the analytics part itself.

Here’s what my last 365 days looked like:

My stats for the last year.

When did I write that many words in TextMate?! It’s almost on par with Xcode. I bet it’s mostly for the book update from September …

Focusing on TextMate only for the same period. See the 7000 spring at the end of August?

Turns out that, apart from the time when I churned out the update in TextMate, Xcode was pretty much present every day. It’s a very steady companion, boringly so, even when I look at 2 years of data:

Xcode programming output for the past 2 years.

In early 2018, I was working on The Archive furiously. It’s a greenfield app, so everything I typed was new and paved the way for future structural changes. Nowadays, I have to adhere to the same structure in my code and either replace things carefully, or add to existing code. It’s less a first draft-like writing frenzy and more like a careful surgical operation. Still I’m bummed one can see the change in programming mode before and after v1.0 public release so clearly!

Alright, enough playing around with the numbers. I hope you enjoy this free update and find it as useful as I!

Get the new version of the WordCounter

X-Oriented Programming, Using Functions or Classes?

Working on a greenfield project is nice, but it also brings up all the uncertainties of the start: which components, modules, objects, interfaces do you need?

With Swift, you even have to decide if you want to design the system in an object-oriented or a functional way. As far as the core functionality is concerned, you do have this choice. (When it comes to UIKit/AppKit, you don’t.)

Thinking in objects, my tool of choice is OOP. But then I end up with classes that have 1 initializer with 2 dependencies injected, and 1 method that calls the dependencies to carry out some functionality. The very same method could be a free function.

class Foo {
    let bar: Bar
    let baz: Baz

    init(bar: Bar, baz: Baz) {
        self.bar = bar
        self.baz = baz
    }

    func perform() {
        baz.compute(bar.currentFizz())
    }
}

// or 

func perform(bar: Bar, baz: Baz) {
    baz.compute(bar.currentFizz())
}

If there are side-effects, both the class and the function will need a handler, e.g. a closure like completion: (SideEffect) -> Void. Again, this works for both cases.

With the class-based approach, the dependencies are injected upon object initialization. If Foo is a long-lived service object, that can be very early in the app’s lifetime. Afterwards, you only need to call the perform method. If the completion handler is injected on call time, you get a nice separation of the parts that change and the parts that stay the same.

With functions, in a naive approach, you have to inject everything at the same time: at call time. So the knowledge trickles down from app launch to the actual call site.

But this isn’t really true. You can prepare partial function applications in much the same way as you would with constuctor dependency injection:

typealias SideEffectHandler = (SideEffect) -> Void
func perform(bar: Bar, baz: Baz, completion: SideEffectHandler) {
    let result = baz.compute(bar.currentFizz())
    completion(result)
}

let bar: Bar = ...
let baz: Baz = ...
let preparedPerform: (SideEffectHandler) -> Void = { completion in
    perform(bar: bar, baz: baz, completion: completion)
}

preparedPerform() { /* side effect processing */ }

That’s also what you can use currying for, for example.

Which path do you choose?

I tend to stick to classes and protocols because of testing. I use mocks in my unit tests as replacements for dependencies and result handlers. It works because I can test every object in about the same way.

With a purely functional approach, you can test the functional units just as fine, but the function compositions not so much. They turn into integration tests of sorts, where you validate a couple of important paths, but not all possible combinations of the underlying parts, because that would duplicate the unit tests and be a combinatorial pain. Since integration tests are a scam when used to verify the system, it’s pointless to even try to get all their combinations right; you get far more value by testing units at their seams.

I prefer similar-looking object boundaries and similar-looking tests in most parts of my application instead of attempting to implement VIPER with pure functions.

This is not a recommendation. It stems from my cluelessness, really. How could I make this different, and better? I don’t know, yet, but I sense that this is a problem that I can eventually solve.

See also:

Win32 API Programming With Swift

With some luck, all my Windows programming wet dream might actually come true one day. There’s progress on making Swift available on Windows, and there’s progress on providing a Win32 API wrapper for Swift so you can share model code across platforms and write UI for Windows and Mac separately.

Check out the GitHub repo: https://github.com/compnerd/swift-win32

It’s experimental, but apparently way less experimental than it was a year ago!

ExactScan Leaves the Mac App Store

Berlin-based company ExactCODE, makers of ExactScan and OCRKit, experiences trouble with Catalina and a rather short time to submit bug fixes for their app before the public release of Catalina earlier this month. They decided to leave the Mac App Store behind:

  • each manual update review by Apple causes delay and drama
  • AppStore does not support paid upgrades, only new App, in-App purchase or subscriptions
  • Apple takes 30% and that is not sustainable to run a company and pay salleries
  • it is not provide to provide free updates forever
  • if you purchased our application this year we provide a direct license, if you had it significantly longer, we think a paid upgrade is fair for continuously developing, improvements, and support

[…]

There is mostly only one benefit [of using the MAS] for users: one central place for purchasee and updates. However, there are many negatives, such as: […]

I don’t know if they could’ve done more to prepare for the macOS upgrade. Recently, folks on Slack shared screenshots, and it turns out that as a serious Mac developer you apparently have external hard drives full of previous and future macOS versions, plus a stack of different Xcode versions (that are no longer available for download by Apple!) – that’s required by virtually everyone in order to support multiple OS versions and fix bugs. The Catalina beta also was very flaky.

After releasing the Catalina Golden Master build to developers on October the 3rd, we immediately finished fixing any new crash or issue we could find over the weekend. In our opinion, leaving developer just four (4!) days over a weekend with a public release on October the 7th is not very helpful nor professional.

They have a point here. But could they have fixed the same bugs earlier in preparation of the Golden Master release?

The call for App Store submissions went live on October 3rd, too, at the day of the Golden Master release. So even if they fixed all the bugs early, Apple would have had only 4 days to review all App Store submissions, which sounds like a bad idea nevertheless.

See also:

Shameless plug: I also wrote a book on selling outside the Mac App Store in case you want to leave the App Store, too, or make your company more resilient through availability in multiple stores.


→ Blog Archive