Professional Software I Pay For

Panorama view of snow-covered mountains in the distance past a green valley underneath a mostly cloudy sky. Photo taken from the Wildspitz, the highest mountain in canton Zug. What does this have to do with paid software? Nothing. I just like mountains. And walking up them (walking back down again, less so).

This month I set up a new work laptop for the first time in two and a half years, and that got me thinking about the professional software I pay for (because I had to download and activate licenses for most of them).

In no particular order:

  • xScope. I love xScope. I last had to pay for this in 2014, but I use it regularly. Initially I used it to check the pixel perfection of my work, but lately I use it more to sample colors to check for accessibility. Even better now that retina screens are a thing and you probably can’t distinguish individual pixels with your naked eye. The worse my eyesight deteriorates, the more I rely on xScope.
  • Tower. GUI git client. Chances are you have to use git for work. I can’t even remember the last client/employer I had that didn’t use git for work (I do remember Visual SourceSafe…). Maybe the only subscription model work app I currently pay for. Yes, I could just use the CLI, but mostly I use Tower.
  • Kaleidoscope. File diff and merge tool. v4 uses the subscription model, but I’m still on the paid-up-front v3 for now.
  • Gifox. I use this to make gif’s out of screen recordings (mostly of the iOS Simulator) to post in tickets and pull requests. Great for documenting app behavior and more convenient than using Quick Time and dealing with video files.
  • Acorn Image editing. I’ve owned so many versions of Acorn. I mostly use this for cropping and resizing screenshots for use in tickets and pull requests.
  • Retrobatch Visual batch processor for images. I don’t use Retrobatch very often, but when I do it’s a super time/sanity-saver. Need to crop/resize/whatever 50 screenshots identically? Why do it manually when you can automate the work? I haven’t upgraded to the newly released v2 yet, but I am looking forward to it.
  • Marked 2. Markdown previewer. Preview the README’s for your repo’s and any other markdown documentation you have (or your cv).
  • Tot. Simple note app that lives in your menu bar. The Mac client is free but I’ve purchased the iOS app.

I own licenses to additional productivity apps, but these are the ones I needed to install on my work laptop right away.

Six Years In Switzerland

View of Lake Brienz, Switzerland. The water is greenish blue, forested mountains are in the distance and a blue sky with white clouds overhead.

It’s been six years now since we arrived in Switzerland. This is not quite a record for longest time in one town, but it’s getting close. This is certainly the longest I’ve been at the same address in my adult life.

So what’s happened in the past year since I wrote this post?

The Past Year

In August I attended (and spoke at) the last ever 360iDev conference.

Last Fall I did an online German test prep course, and at the end of October I passed the A1/A2 German language test that I will need to apply for permanent residency.

I continue to be active in the Swiss RPG “verein” (a non-profit club). I play regularly in a West Marches style game and a few months ago I began running the Tyranny of Dragons D&D campaign for a group of five players. I have hosted games as a DM at Zürich Pop Con, Fantasy Basel, and Free RPG Day.

I try to get out into nature as much as possible, either hiking, snowshoeing, or stand up paddling. I think I prefer showshoeing and winter hiking to downhill skiing these days as I get older.

For most of the year I continued in my role as iOS Chapter Lead for YML and heavily focused on building out a portfolio of robust, highly-tested, open source Swift packages that could be used across projects to accelerate delivery, improve accessibility, and reduce bugs. But in May after two years in the role, I was finally caught in a round of layoffs that have swept the tech industry.

I used the suddenly free time to take a six week in-person super intensive B1 German language course (for comparison, I studied for two years at the A2 level). I will consolidate my knowledge by taking another test prep course starting later this month which will culminate in the B1 Goethe exam in November. I will also enroll in a local German conversation course to help me practice.

Goals for our seventh year in Switzerland

  • Get hired locally
  • Apply for permanent residency
  • Pass the B1 Goethe German test
  • Complete the Via Engiadina hiking trail (I have hiked 6 out of 12 stages)
  • Exercise regularly

The Future

We would like to stay here another two years until our son finishes high school.

Interlude: German lessons

For the past six weeks I have been taking super-intensive in-person B1 German lessons. I studied A2 German for two years from Fall 2018 through Spring 2020, but then COVID came and I also became incredibly busy at work (first with BlockFi and then with Y Media Labs). I did an online test prep course in the Fall of last year (which helped me pass the A1/A2 language test that I will need to apply for permanent residency), but that was just a refresher and didn’t cover any new material. So it had been three years since I had learned any significant German.

When I found myself suddenly idle at the beginning of May, I realized that I had been granted an opportunity to continue my studies. I decided on a so-called “super intensive” German course that would cover the entire B1 level of German in just six weeks (with three hours of class every weekday). The language school location was not the best for me, but the closest schools offered nothing comparable. So for the last month and a half I’ve spent three and a half hours each day commuting to and from the language school. Fortunately Swiss public transport is top-notch and I can read, relax, or study on the trains and buses. Between the classes, the commute, and the homework, this was essentially a full-time endeavor.

The first week (and especially the first day or two) was especially tough as I adjusted myself to German-learning mode for the first time in three years. I’m proud to say that I completed the course and even aced the end-of-term test. My hope is that this will open up opportunities for me to do freelance development work with local companies (those that might not operate in English), although I may need to learn even more German. Regardless it will be helpful for my day-to-day life.

Sprachzertifikat, Deutsch B1, Mark Pospesel

My goal is to take an online test prep course again this Fall and then take an official Goethe B1 German test in November. I also intend to enroll in a weekly German discussion group that will meet locally on Thursday evenings.

Open Source Diaries: Y—Matter Type

Y—Matter Type

This is the second article in a series that details the Open Source Work for iOS that I have been leading at YML.

Typography

The inspiration for the Y—Matter Type library came from the most common mistake I see when converting designs to code on iOS: overlooking line height. Designs define typographies (or text styles), which describe how text should be rendered on screen. The four basic parameters of a typography are:

  • font family
  • font weight
  • font size
  • line height
Font family: Helvetica Neue
Font style: Regular
Font size: 16px
Line height: 24px

For example, a design might call for a regular weight Helvetica Neue font with 16 pt font size and 24 pt line height. The first three parameters tell you which font to load on iOS, but the fourth parameter is typically just ignored outright.

let font = UIFont(name: "HelveticaNeue", fontSize: 16)

The code above generates the correct font, but what is its line height? Is it 16? It turns out that for a 16pt regular Helvetica Neue font, it is 18.64. A UILabel generated with that font will have a height of 19 on a 2x retina device (rounding up to the nearest pixel). But the designs expect that label to be 24 points tall per line of text. Of course you could constrain the label to have a height of 24, but then it could not support Dynamic Type. Also if it contains multiple lines of text, you don’t necessarily know how many lines it will wrap to and so couldn’t possibly constrain the height correctly.

The way you get line height to render in UILabel, UIButton, UITextView is by using paragraph styles and attributed strings. (To my knowledge SwiftUI does not yet support line height in any of its text views, which is one reason why I continue to utilize UIKit.) But applying paragraph styles via attributed strings to every button and label in an application would also be burdensome (which is why it typically just gets ignored).

To solve this, we created a Typography model object that captures all the parameters of design system typography and then accurately renders text in UIKit (which can then be hosted in SwiftUI if necessary). In addition to the most common parameters listed above, Typography also supports:

  • letter spacing (kerning)
  • paragraph indent
  • paragraph spacing
  • text case (uppercase, lowercase, title case)
  • text decoration (underline, strikethrough)

Typography objects are determined by the design (and with proper transformation can be automatically generated from design files) and then rendered via subclasses for all the text-based UIView classes.

Y—Matter Type declares TypographyLabel, TypographyButton, TypographyTextField, and TypographyTextView classes to replace use of UILabel, UIButton, UITextField, and UITextView, respectively.

Accessibility Features

Typography supports Dynamic Type scaling and the Accessibility Bold Text feature by default for any custom font.

Adopting Typography is a bit of a paradigm shift because you no longer work with fonts, only typographies. That’s because the exact font chosen will be determined at run time based on the current trait collection. For example, the following label might actually use a Helvetica Medium font instead of Helvetica Regular if the user has enabled the Bold Text setting.

let body = Typography(
    familyName: "HelveticaNeue",
    fontWeight: .regular,
    fontSize: 16,
    lineHeight: 24
)
let label = TypographyLabel(typography: body)

The Bold Text feature works by having information about an entire font family (what weights are available) and not just a single font. If we know all the available weights, then we can vend the next heavier weight (if any) when Bold Text is enabled.

Dynamic Type scales Typography proportionately with line height. So the 16/24 Typography shown above scaled to 200% would use a 32pt font rendered with a 48pt line height.

Overview

The goals of the Y—Matter Type package are to:

  • Support line height and other typographical properties (letter spacing, text decorations, text cases, and more) across labels, buttons, text fields, and text views
  • Support Dynamic Type scaling and Accessibility Bold Text on custom fonts
  • Accelerate accurate translation of Figma designs into code by having text-based elements with the exact same intrinsic size (based upon line height) as the corresponding elements in Figma

I am proud that we delivered low-level components that make it trivial to accurately render text as per designs while at the same time including Dynamic Type and Bold Text support with little additional burden for the developer. To my knowledge no client has ever asked for Bold Text support (or even knew it existed really), but we build that in for their users anyway.

Together with Y—CoreUI, Y—Matter Type is part of how we build iOS apps at YML.

Open Source Diaries: Y—CoreUI

Y—Core UI

This is the first article in a series going into detail about the Open Source Work for iOS that I have been leading at YML.

One of the first Swift package we created and released was Y—CoreUI. As its name suggests, it is one of our core libraries for doing UI work on iOS. It consists primarily of:
1. UIView extensions for declarative Auto Layout
2. UIColor extensions for WCAG 2.0 contrast ratio calculations
3. Protocols to aid loading string, color, and image assets
4. Model objects to declare drop shadows and animations

UIView extensions for declarative Auto Layout

I’m a big proponent of building UI’s entirely in code when working in UIKit. NSLayoutConstraint is an old friend, but cumbersome to use. These layout extensions just create NSLayoutContraint‘s but in a more declarative and less verbose manner and with smart defaults for most parameters. Want to constrain a subview to all 4 sides of its superview?

subview.constrainEdges()

Want to pin a subview to the center of its superview?

subview.constrainCenter()

It’s that simple. Need to do something more complex like centering a view horizontally but ensuring that it doesn’t overflow its superview? That’s also simple.

subview.constrainCenter(.x)
subview.constrainEdges(.horizontal, relatedBy: .greaterThanOrEqual)

(That last line is clever enough to invert the relationship and created the .trailingAnchor constraint with the .lessThanOrEqual relation.)

UIColor extensions for WCAG 2.0 contrast ratio calculations

Dark and light pink color swaths with text reading #82007D, Contrast 7.23, #FFD6F9

I think this is my favorite part of this library. WCAG 2.0 specifies contrast requirements for foreground and background colors that appear together to meet AA or AAA levels of compliance (I like this handy checker). This ratio works by converting the color into LCh color space (great article on LCh) and comparing the Luminance values. There are various design tools to check these contrast ratios, but what if we could do it programmatically as part of unit tests and across both light and dark modes and regular and increased contrast modes?

XCTAssert(
    foregroundColor.isSufficientContrast(
        to: backgroundColor,
        context: .normalText,
        level: .AA
    )
)

As a bonus we expanded the calculations to work when the foreground color is not opaque (this is the case for Apple’s system colors such as UIColor.secondaryLabel). If you need the exact contrast ration value, there’s a method for that as well.

let ratio: CGFloat = foregroundColor.contrastRatio(to: backgroundColor)

Protocols to aid loading string, color, and image assets

These are a series of protocols that make it simple and testable to load localized strings, colors, images, and even SF Symbols using enums. Of course it’s trivial to load a color from an asset catalog using UIColor(named: "someName"), but from my viewpoint this has some drawbacks:
1. not easily unit testable
2. fails silently (returns nil)

Y—CoreUI provides a Colorable protocol that any string-based enum automatically conforms to and adds the following methods:

var color: UIColor { get }
func loadColor() -> UIColor?

loadColor() is failable and ideal for unit testing, while color is guaranteed to return a color (by default UIColor.systemPink as a fallback color), but will also log a warning to the console if it falls back. Usage and unit testing is simple:

enum WarningColors: String, Colorable, CaseIterable {
    case warning50
    case warning100
}

func test_warningColors_deliversColors {
    WarningColors.forEach {
        XCTAssertNotNil($0.loadColor())
    }
}

The Localizable, ImageAsset, and SystemImage protocols do the same thing for localized string resources, image assets, and system images (SF Symbols), respectively.

Model objects to declare drop shadows and animations

A large part of our jobs as iOS developers is rendering user interfaces from designs, but this can some times be difficult because the way designs are described in design files can differ from how they are implemented on iOS. For example, Figma and Sketch describe drop shadows as they are defined for the web using the parameters: horizontal offset, vertical offset, blur radius, and spread. On iOS though we have shadowRadius, which when you look in Stack Overflow contains incorrect answers as to how to convert blur radius to shadowRadius. In Y—CoreUI we defined an Elevation object that describes a drop shadow in web/design terminology and knows how to properly apply them to views. This includes correctly calculating spread for rects and round rects. The Elevation object was designed to be automatically generated from Figma tokens using transformation tools such as Style Dictionary.

Another useful model object is Animation which lets us build components with customizable animations without necessarily knowing exactly which type of animation will be chosen. We leverage this for the animations in our snackbar/toast library, Y—Snackbar.

/// Animation curve
public enum Curve: Equatable {
    /// Regular animation curve
    case regular(options: UIView.AnimationOptions)
    /// Spring animation
    case spring(damping: CGFloat, velocity: CGFloat, options: UIView.AnimationOptions = [])
}

That wraps up a cursory overview of YML’s core iOS UI library. In my next article I will describe its companion library for rendering design system typography, Y—Matter Type.

Open Source work

As part of my role as iOS Chapter Lead at YML, I lead a team that builds reusable code that can be shared across projects to accelerate development, reduce bugs through the use of well-tested code, and inject accessibility features into projects with little additional overhead.
Animated GIF of two tags reading
Over the past year or so we have started releasing this code as a series of open source Swift packages on GitHub. To date we have released 14 Swift packages! The easiest way to view them is actually on the Swift Package Index.

These packages are already part of several shipping products. You might have used them to order your food, buy your groceries, sell your car, or schedule a doctor’s appointment.

I’m incredibly proud of this work and our little team. Every package in this collection is:

  • distributed as a Swift package
  • Apache 2.0 licensed
  • linted to identical standards (with SwiftLint, naturally)
  • highly unit tested (90–100% code coverage)
  • public apis 100% documented
  • includes an auto-generated documentation website hosted via GitHub Pages. (Example here) (courtesy of Jazzy)
  • protected through GitHub Actions to pass strict linting and unit tests

Over the next week I plan to write a series of posts that go into more detail on some of the projects. Many of them include some pretty cool accessibility features that I am proud to have shipped and to have included in apps that reach tens of millions of users.

Open Source Diaries

Exercise

I joined a gym this week for the first time in I’m not sure how many years. Certainly at least since 2017. As a full-time software engineer (i.e. someone who sits in an office chair all day) I struggle with finding the time and motivation for fitness. I’m in my 50’s now, so I need to invest more in keeping myself (somewhat) in shape because with every year it becomes harder to get back into shape when you fall out of it. I have been doing well for the past 3 weeks: going for outdoor walks for about an hour every day (and some days hiking for much longer), which is good for cardio but doesn’t exercise my upper body at all. Also it can become a bit boring doing that every day for an hour. I try to vary the walks (I’m lucky to be surrounded by amazing scenery and to live in a walking-friendly area), but it’s still walking for an hour.

In order to mix things up and to give myself some strength training in addition to cardio, I decided to join a gym. I met with a trainer to discuss my goals, and he created a workout routine for me. My goal is to go 3 days a week and maybe attend the occasional spinning class or else go just to do an hour of cardio on days when it’s too cold/hot/wet to want to spend an hour outside. The gym is a 10-15 minute walk from home, so if I walk there and back I’ll get some extra exercise as well. Or I might bike there, but I need to change the pedals on my bicycle before I can do that.

One new thing I’ve done this year is to change the Exercise and Stand goals on my Apple Watch from their defaults. I reduced the Stand hours to 10 because I really only care about the notifications during my work hours. In the evening while I’m relaxing on the couch, I don’t need my Watch to nag me to move around. I’m increasing my daily Exercise goal by 5 minutes each week until I reach 60 (currently I’m at 45).

The important thing for me to succeed in an exercise routine is to create habits. So I need regular days to go to the gym or to walk outside, etc. Without a habit it quickly falls apart, and before long I’ll find that I haven’t exercised in a month.

Five Years in Switzerland

Five years ago today we arrived in Switzerland to start a new phase of our lives. 2022 has been a definite improvement for us over the previous two years. COVID of course is still a specter looming over us, but we’ve learned how to live with it (being vaccinated and twice-boosted helps). We’ve traveled extensively within Switzerland, getting to know some of the most scenic parts of the country (focusing on the mountains and high alpine valleys).

In the Spring I returned to the US for the first time in three years and finally got to visit family.

I attended (and spoke at) an in-person tech conference for the first time in three years (and promptly got COVID). I’ve been serving as iOS Chapter Lead and building internal IP at YML for over a year now. The role continues to bring me enjoyment and satisfaction.

I hike regularly and when it’s too hot to hike I hit the lake on our paddle board or our foldable kayak.

Integrating into Swiss society remains a challenge, but over the past year I have finally joined and am active in a Swiss “verein” (a non-profit club): Swiss RPG. It’s an RPG club through which I run a D&D campaign (The Wild Beyond The Witchlight) and play in a West Marches-style shared community world. My son and I got into D&D 5e in a big way last year. Now instead of doom-scrolling Twitter I hang out in the Swiss RPG Discord discussing the merits of different character builds or how to DM particular adventures. This past year we also attended our first fantasy convention, Fantasy Basel where we were able to play some in-person D&D at the Swiss RPG booth.

At the end of this month I resume German lessons after a two-year hiatus. In October I plan to take the A1/A2 Goethe test that is a requirement for applying for permanent residency.

I’m looking forward to at least another year living in this beautiful country.

360iDev

I’m excited to be attending and speaking at 360iDev 2022 in Denver, Colorado at the end of this month. 360iDev was one of my first iOS conferences and is also one of my perennial favorites. The Wilker’s are really good people, and I’m excited to get to attend after a long hiatus.

On Sunday morning 28 August I will lead a half-day tutorial on engineering design systems and on Monday 29 August just after lunch, I present a conference talk on typography. (Yes, I’m obsessed with design systems and with typography in particular. My goal is to enable teams to build UI’s quickly and accurately with as many accessibility features as possible.)

Engineering Design Systems

Format: half-day tutorial

Many companies are coming to realize the many benefits that design systems bring. A good design system (and its accompanying set of engineered components) can improve design quality and consistency and provide significant reduction in production times for both design and development teams. But how do you engineer the components depicted in the design system? In this talk we will learn how to consume design files and then engineer our own mini design system beginning with the foundations of color, spacing, and typography. We will use our foundations to create a few simple elements, and then we will assemble those into a card component, form fields, and finally a form. Along the way we will consider accessibility through the lens of dark mode, increased color contrast, landscape support, Dynamic Type, and bold text support.

Engineering Beautiful and Accessible Text

Format: conference talk

An integral part of design systems and style guides is typography. Typography declares how text will appear in your product by specifying the font family, size, weight, line height, etc. While much of our focus on design goes towards colors, icons, and images, text is the primary way users interact with the majority of apps. Learn how to implement typography in your apps in a way that is accurate to the source designs, fully accessible, and that makes assembling pixel perfect implementations of the source designs a breeze.

Tickets are still available.

I’m also hoping to host a D&D one-shot during the hackathon/game night during the conference. So come geek out about design systems and typography, and then roll some dice with me.

AppDevCon

I’m excited to be attending and speaking at AppDevCon 2022 in Amsterdam.

On Thursday 23 June I give a half-day tutorial on engineering Design Systems and on Friday 24 June I present a conference talk on typography.

Engineering Design Systems

Format: half-day tutorial

Many companies are coming to realize the many benefits that design systems bring. A good design system (and its accompanying set of engineered components) can improve design quality and consistency and provide significant reduction in production times for both design and development teams. But how do you engineer the components depicted in the design system? In this talk we will learn how to consume design files and then engineer our own mini design system beginning with the foundations of color, spacing, and typography. We will use our foundations to create a few simple elements, and then we will assemble those into a card component, form fields, and finally a form. Along the way we will consider accessibility through the lens of dark mode, increased color contrast, landscape support, Dynamic Type, and bold text support.

Engineering Beautiful and Accessible Text

Format: conference talk

An integral part of design systems and style guides is typography. Typography declares how text will appear in your product by specifying the font family, size, weight, line height, etc. While much of our focus on design goes towards colors, icons, and images, text is the primary way users interact with the majority of apps. Learn how to implement typography in your apps in a way that is accurate to the source designs, fully accessible, and that makes assembling pixel perfect implementations of the source designs a breeze.

Tickets are still available.

Hit me up if you’re in Amsterdam as I will be there for 6 days / 5 nights.