Rely on @Published Property Wrapper Events, Not the Observed Object

Pop quiz!

What is the output of this program, e.g. when run in a playground or an autoclosure block?

import Combine

class ValueHolder {
    @Published var value: Int = 0
    init() {}
}

let valueHolder = ValueHolder()
let sub = valueHolder.$value.sink { value in
    print("received", value, "- persisted", valueHolder.value)
}
valueHolder.value = 4
valueHolder.value = 2
Spoiler: Solution
received 0 - persisted 0
received 4 - persisted 0
received 2 - persisted 4

The documentation indicates as much, but it can still be a surprise in your programs when you treat the @Published event as a mere signal to read multiple values from the observed object.

So remember that @Published publishes events in its willSet.

Schedule End of the Work Day Using Org

To get more structure into my day so I get work stuff done in time and have free time in the evenings to tackle other things, I’m now experimenting with notifications to end the work day.

The following is a translated version of the current data. I am using the German term "Feierabend" (which you can shout well); “end of work” is a bit clumsy, and it doesn’t sound like an exclamation.

* Current Sprint <2022-08-08 Mon>--<2022-08-20 Sat>
** <2022-08-08 Mon 16:00> End of Work
** <2022-08-09 Tue 16:00> End of Work
** <2022-08-10 Wed 16:00> End of Work
** <2022-08-11 Thu 16:00> End of Work
** <2022-08-12 Fri 16:00> End of Work
** <2022-08-13 Sat 16:00> End of Work
** <2022-08-15 Mon 16:00> End of Work
** <2022-08-16 Tue 16:00> End of Work
** <2022-08-17 Wed 16:00> End of Work
** <2022-08-18 Thu 16:00> End of Work
** <2022-08-19 Fri 16:00> End of Work
** <2022-08-20 Sat 16:00> End of Work

For years, I’ve used org-mode (or just “org”) time stamps on isolated lines, as if they were something special. But this compact way to write things is pretty nice:

  • The top-level item “Current Sprint” has the 2 weeks of work range at the end of the line. This demotes the time, and promotes the item’s textual content. (As an effect, I can see at a glance when the sprint is over from the org file’s overview, and still get each day marked in the calendar/agenda.)

  • The second level items called “End of Work” mark each work-day’s, well, end at 4 p.m. – This is absolutely new to me. Previously, work would bleed well into the evenings and thus fill whatever the time I gave it.

You can see I just started this yesterday, so there’s not much experience on this, yet, but it’s currently 16:10 here, and I’m writing this after excitingly calling it a day at the allotted time :)

Now you’ll notice that each of the 12 “End of Work” items is very repetitive. That’s how you represent a daily repeating time entry with exceptions (here: Sundays).

But I didn’t create these manually. I looked up how to duplicate org headings/outline items and advance their scheduled times. Took a bit to figure out the nomenclature.

The term to duplicate org-mode items with dates and increment the date for each copy is “cloning”. This applies regular date-time stamps like I use them, and it applies to scheduled or deadlined items (these show as overdue when not completed).

(org-clone-subtree-with-time-shift N &optional SHIFT)

org-clone-subtree-with-time-shift is bound to C-c C-x c by default

The steps to clone an item for every day of the next 2 weeks, insert:

* <2022-08-08 Mon 10:00> Some appointment
  • Select that line, then press C-c C-x c to clone the subtree (item);
  • Enter the amount of copies, e.g. 13 (for 14 in total, including the original);
  • Enter the time shift in org syntax of +1d;
  • Delete Sundays manually.

That’s going to be my approach for the forseeable future to keep a track of work time and play time (which often is also work time, but on different projects).

The weird thing this cloning does to me is to accept that this plain text time management approach is malleable. I don’t set up a rule in a programmatic or algorithmic way once, and then it sticks – no, I create 14 lines for the current sprint, then I’ll delete these, and then I’ll create 14 new ones for the next sprint. Maybe I’ll not even delete these before the next sprint because keeping them around doesn’t hurt.

It’s a bit like accepting the chaos a pet can cause in your otherwise tidy apartment.

Feels odd at first, but when you accept it, it’s quite a relief actually.

Output Port Adapter for Single Point of Configuration in Complex UI

When you have nested and complex UI components with multiple sub-view controllers, passing an optional output port (event handler or delegate) down the tree is cumbersome.

There are two straight-forward approaches:

  1. Sub-components use the output port directly: When you inject the object reference, you may need to pass it down the whole view controller tree to reach all leaves.
  2. Sub-components are isolated from entry point: There’s one public interface for the port that is used by the module’s entry point, but internally, all sub-components have private wirings to communicate with the entry point.

The second option is “cleaner”, but for a two or three object component might also feel a bit too much.

With the detail hidden inside the 'module', and just one public property exposed, there's different ways to implement the 'arrows' in that diagrams'

A pattern I found useful is to inject a forwarding adapter early on as the actual port adapter, and replace its reference to the actual object at runtime:

  • The output port that is exposed changes an internal reference inside the adapter, i.e. in one place only.
  • The (private or internal) adapter itself is used as the actual output port of sub-components. It’s injected during setup eagerly once
public protocol WidgetEventHandler {
    func manipulateWidget()
}

public class WidgetListViewController: NSViewController {
    private final class WidgetEventHandlerForwarding: WidgetEventHandler {
        /// Runtime-replaceable reference.
        var base: WidgetEventHandler? = nil

        func manipulateWidget(manipulateWidget) {
            /// Forward, if possible.
            base?.manipulateWidget()
        }
    }

    private let eventHandlerForwarder = WidgetEventHandlerForwarding()

    /// Public output port configuration API looks normal:
    public var eventHandler: WidgetEventHandler? {
        get { eventHandlerForwarder.base }
        set { eventHandlerForwarder.base = newValue }
    }

    public override func awakeFromNib() {
        super.awakeFromNib()
        // ...
        // Wire sub-components to the forwarder immediately:
        self.detailViewControllerA.eventHandler = eventHandlerForwarder
        self.detailViewControllerB.eventHandler = eventHandlerForwarder
        self.detailViewControllerC.eventHandler = eventHandlerForwarder
    }
}

Here, the forwarder implements the WidgetEventHandler protocol and, well, forwards to base if it’s set.

If you have a complex UI with multiple event handlers, delegates, data sources, and whatever else, you could opt for multiple forwarders – or lump them all together into one, if that makes sense. It can absolutely make sense, because “being the façade for various output ports” is a single concern, too. If the public facing component is complex but has a coherent data set, there shouldn’t be a lot of confusion.

Emacs Blogging: Insert Tag from YAML Frontmatter Posts

My blog posts here usually have a line like:

tags: [ swift, xcode, codesigning ]

For tags I don’t use a lot, I sometimes don’t remember how to write them. So I do the only sane thing – and go to my website’s list of tags and look for a match.

Got annoyed by that now after a couple of years :)

Extract All Tags from All Posts

Using rg, I can match these lines and focus on group matches inside without piping the output through sed or similar.

The regular expression that works good enough for me:

^tags:\s\[([a-zA-Z0-9 -_]+)\]

The first group here then returns " swift, xcode, codesigning " for the example above with the right ripgrep incantation:

$ rg --context 0 \
     --no-filename \
     --no-heading \
     --replace "\$1" \
     -- <<regex here>>

This produces just the string inside the tags: [...] brackets, without filename, and no empty lines in between.

Here’s the Emacs Lisp version to get these lines:

(defun ct/all-tag-lines ()
  "Extract the array contents of YAML lines for `tags: [...]'."
  (let ((project-dir (cdr (project-current)))
        (regex "^tags:\\s\\[\\s*([a-zA-Z0-9 -_]+)\\s*\\]"))
    (shell-command-to-string
     (concat "rg --context 0 --no-filename --no-heading --replace \"\\$1\" -- " (shell-quote-argument regex) " " project-dir))))

Now time to clean this up and make this usable.

Transform the Extracted YAML Lines Into Filterable Lists in Emacs

Samples output from rg is e.g.:

zettelkasten, reading, archive
calendarpasteapp
zettelkasten, writing, personal, craft
nv, zettelkasten, software, review
writing, productivity, quantified-self

I need to split the lines into individual tags and then remove duplicates like zettelkasten.

  • Split string by lines, trimming whitespace:

      (split-string "..." "\n" nil " ")
    
  • Split lines by comma and/or spaces to extract individual tags, dropping empty strings:

      (split-string "..." "[, ]+" t " ")
    
  • Combined:

      (split-string "..." "[, \n]+" t " \n")
    

To delete duplicates, delete-dups does the trick:

(defun ct/all-tags ()
  "Return a list of unique tags across all articles."
  (delete-dups
   (split-string (ct/all-tag-lines) "[, \n]+" t " \n")))

This returns an (unsorted) list of unique tag strings.

zettelkasten
reading
archive
calendarpasteapp
writing
personal
craft
nv
software
review
productivity
quantified-self

With that, I’m almost finished. I can pass this to completing-read to get – well, the name reveals almost as much: – interactive completion for matches in this selection.

And I ultimately want to insert the match, not just produce a result programmatically.

So this is the “public”, i.e. user facing function I’m using:

(defun ct/insert-project-tag ()
  "Select and insert a tag from YAML frontmatter tags in the project."
  (interactive)
  (insert (completing-read "Tag: " (ct/all-tags))))

Since I’m using the built-in project.el package, I added a key binding to C-x p t (am actually using SPC p t in command mode) to insert a tag:

(define-key project-prefix-map (kbd "t") #'ct/insert-project-tag)
Ah well, looks like I have singular/plural form duplicates already. Gah.

Up next, I’d maybe like to push this completion from a selection in the mode-line to completion-at-point, i.e. to get suggestions and auto-completion in-place while I type.

Judging by the speed I implemented these things in the past, it should be ready by 2026.

Disambiguate Code Signing Identities

I’ve recently added the code signing identities for a client to my dev Mac. Some old code signing scripts then failed to run:

🛑 Apple Development: ambiguous (matches “Apple Development: Christian Tietze (xxxxxxxxxx)” and “Apple Development: Christian Tietze (xxxxxxxxxx)” in /Users/myuser/Library/Keychains/login.keychain-db)

Never encountered that before, to be frank.

Turned out that the script was using the $CODE_SIGN_IDENTITY environment variable, which is just the string “Apple Development”. ⌘F looking through the other environment variables at my disposal, I found $EXPANDED_CODE_SIGN_IDENTITY, which is a hash, and $EXPANDED_CODE_SIGN_IDENTITY_NAME, which is the expanded form that the error message quoted above uses.

I tried both, and both work. The codesign man pages say as much: either provide a partial matching string, which only works if there’s just one match, or a complete form, or 4 characters of a hash. The $EXPANDED_CODE_SIGN_IDENTITY is more than 4 characters long, but that’s looking like the hash.

The failing script must be pretty ancient, because all my notes with copypasta inside that involve code signing use $EXPANDED_CODE_SIGN_IDENTITY already.

New Library Pages

I’ve added a new section to this site. Wanted to call it /books, but that’s taken and about my books :)

So I added the new /library index. It shows books added to my personal library sorted by year I read them.

At the moment, there’re only these three, all of which I needed (wanted) for the previous post:

This collection is bound to grow. I missed something like this for a couple of years. An overview of posts about book would’ve been nice for lots of reasons.

Now the basics are prepared.

TDD Is About Writing Counter-Factual Statements

Writing unit tests first, in the manner of test-driven development, is some kind of “wishful programming”: you create a counter-factual situation in the test code, e.g. one that uses types and methods that don’t even exist.

Then you add the implementation to make the counter-factual statements (and failing tests) the actual reality.

You turn a lie into the truth, a thought-experiment into reality.

See also:


I’m not sure what to do with this association, yet. It just came to mind when used the term “wishful programming”, or “wishful thinking”, in a conversation recently.

In the tradition of linguistics and analytical philosophy, “counterfactuals” are a whole subject to study. Since I’ve now made the mental connection from TDD to “counterfactuals”, maybe I can back-port some interesting tid-bits from linguistics to TDD. It’s not very likely – then again, folks figured out how to replicate the good parts of a fringe book on architecture to Design Patterns for programming.

I picked up this term from Gio Lodi’s book, Test-Driven Development in Swift, by the way.

Key Binding to Select Paragraph or Org Element

I used to rely on M-h to mark the structural element in Emacs; in text buffers, that’d be the paragraph, in org buffers, that was the whole outline item (when the cursor was in the heading line, at least).

Ever since I installed Emacs for Mac OS X which now is also on Emacs 28.1, this shortcut wouldn’t work for me anymore, because my Meta key is my left Command key, and Cmd-H is the macOS shortcut to hide the frontmost app.

I’m rather happy about Emacs for Mac OS X’s adherence to default macOS shortcuts.

So I looked for alternative key bindings.

My modal input scheme (Xah Fly Keys) has selection shortcuts on the number keys 6, 7, 8 and 9. But the one on 9 never made sense to me, so I now use that key to select the paragraph or org-element.

My own function that does the selection:

(defun ct/mark-paragraph ()
  "Mark the paragraph or structural element, depending on the mode."
  (interactive)
  (cond
   ((derived-mode-p 'org-mode)
    (org-mark-element))
   ((derived-mode-p 'web-mode)
     (web-mode-mark-and-expand))
   (t
    (mark-paragraph))))

This function is extensible to e.g. select an enclosing HTML element in web-mode or a function or type or other structural element in C code or Swift. I have yet to add these.

Update: Screw it, I just added the HTML variant. Didn’t even know it was bound to C-c RET until I looked for a suitable function.

I’m using derived-mode-p to test for both same modes, and derived modes; so e.g. (derived-mode-p 'outline-mode) will also return non-nil when visiting an org-mode buffer, since org-mode is derived from outline-mode. Got this tip from a post by Bozhidar Batsov.

A better name would maybe be ct/mark-paragraph-dwim because it’s context sensitive and does different things in different modes.

The key binding isn’t interesting, but here it is for completion:

(define-key xah-fly-command-map (kbd "9") #'ct/mark-paragraph)
;; was 'xah-select-text-in-quote

TableFlip v1.4.0 Released

I’ve released an update to existing users of TableFlip last week. It works well so far, so now’s the time for the official announcement of the new version, available for direct download.

Most notable changes:

  • TableFlip now guesses sophistically determines the delimiter in CSV files, if needed. So you can use ; or \t just fine, which means export from Numbers works out of the box.
  • Non-comma-delimiters also “stick” when saving. No auto-replacement to comma anymore.
  • The CSV loading and saving is more robust, especially with quoted content. There’s been issued reported in the past, and these should now be fixed. Thanks for your emails and sample files, folks! ❤️

For my nerdy readers, behind the scenes I also upgraded Sparkle from the XPC branch to the actual Sparkle 2.0 stuff. I sincerely hope it will ingest the upcoming updates, too. (It’d not be the first time I broke the update mechanism of one of my apps, heh.)

What is TableFlip, you ask?

TableFlip is a fast tabular data editor – the ideal companion app for Markdown users who want beautiful tables in their documents. Open the file in both TableFlip and your text editor, and you’re set: TableFlip lets you edit all tables it finds inside your document and updates live as you edit your text.

Well, and you can edit CSV files, too, and export to LaTeX.

TableFlip v1.4.0 is available from the website and the Mac App Store.

DevCleaner for Xcode

Found DevCleaner for Xcode yesterday and gave it a spin. It’s freeware on the Mac App Store with a tip jar.

Developers who ever nuked their Derived Data folder (I have an alias in my .profile for that) know how much stuff Xcode collects over the years. And then there’s outdated iOS Simulator versions nobody needs anymore. And log files, of course, by Xcode.

I’m pleased to say that DevCleaner does a good job at enabling me to select what I want to remove from the set of things that could be obsolete.

I have Xcode 14 beta installed (to my dismay), so DevCleaner suggested all Xcode 13.x related things could go away. It tries to be smart and helpful here, but I kept the Xcode 13.4.1 logs just in case. The option is there.

Where in the past I would occasionally nuke all Derived Data, DevCleaner shows these folders in a sensible way, with a reference to the project location. I usually create throwaway projects to test and debug something in my Downloads folder. The derived data of these projects is absolutely useless after a month, week, or sometimes even a day. Since DevCleaner shows where the original project was located, I’ve been able to delete data for every long-gone project that was in my Downloads folder.

I cannot stress enough how cool I find this.

Deleting derived data folders is often hard to do by name alone: when I download a new version of a 3rd part dependency that I am using in my apps, and open the project in my Downloads folder, and play around with it, then I have two derived data folders for this dependency, but only one is relevant for the actual project. Either I don’t care and delete both when I know building them is trivial, or I don’t bother at all and they stay around forever.

I really, really like this feature.

Would be even better if I could sort or filter by origin path, but it’s ok the way it is.


→ Blog Archive