For years, I have tried without success to establish a habit of consistent exercise. Over the course of my adult life, I have hired personal trainers, purchased home fitness equipment, joined various gyms.
Some of these attempts at establishing a lasting habit managed to last weeks, some months, one stretch went over a year.
But, in the end, none of these workout routines ever felt like a natural part of me. They always required a significant amount of willpower and I never really found much enjoyment in them. Those conditions are not favorable to forming a lifelong habit.
A New Hope
After some reflection I realized that there is a form of exercise that I enjoy.
I like to dance.
This is not to say I am graceful, talented, or skilled at dancing. But I definitely enjoy it. When a song starts playing, it is difficult for me not to move to the music in some way.
So, how to put that realization to some practical use?
After all, I’ve enjoyed dancing for as long as I can remember, but it has never become a habit, and I hadn’t really thought about it as exercise.
Over the summer a few things came together to spark an idea that seemed promising:
First, the addition of the dance workout in watchOS 7 validated that yes, dancing is an exercise. Maybe even more important for me is that dance workouts can now be measured and tracked in the Apple fitness ecosystem.
One key principle in establishing a habit is the need for a cue to trigger the behavior.
And then it hit me:
If sometime during the day loud dance music suddenly started playing in my house, it would be difficult for me to not get up and dance.
This led me to the Home app where I found out I could set up a Scene to play a particular playlist on my HomePod. And I could set up an Automation to play that Scene every day at a particular time.
In Apple Music, I already had a Dance playlist that I hadn’t really touched in years from way back in the early iTunes days.
I set it all up and the daily Dance Party! was born.
One suggestion in Atomic Habits is that when establishing a habit, the consistency of repeating the habit is more important than the length of time or progress made during any one iteration of the habit.
So, I made the commitment to myself that once the dance party started, I would definitely dance all the way through the first song. And if I wasn’t feeling it after that, I could consider the dance party done for the day.
The first dance party was on Sept 23, 2020 and I’ve now successfully had a dance party every day for the last six weeks!
A typical dance part lasts 20 - 25 minutes.
Another part of the daily ritual is, when that first song starts playing, as I get up to dance I yell out “Dance Party!” to nobody in particular. It’s a bit of cheesy forced enthusiasm that helps kick things off.
Finally, I use a technique called habit stacking to follow my dance workout with a cool down workout where I do about 10 minutes of stretching. Between the two workouts I close my Exercise ring for the day.
You’d think that having a scheduled time set up that I would never be surprised by a dance party. But you’d think wrong. I’ve been woken from weekend naps and startled from coding by the daily dance party.
Will this last? I can’t say.
But, I know this feels different than other things I’ve attempted. I’m excited about it and I’m largely having fun doing it. And on days when I’m really not in the mood, I do keep that commitment to dance through a single song. So far, even on those day, my brain has successfully slipped into “well, might as well finish” mode and I’ve done a full dance party.
I don’t tweet about it every day, but if you do see me tweet “Dance Party!” now you’ll know exactly what I’m up to. •
After posting about renovating the site and designing my own HTML and CSS, I was asked why I didn’t use something like Squarespace.
There are a number of reasons: cost, control, and simplicity.
As far as I can tell, Squarespace charges per site, which really starts to add up if you tend towards multiple relatively low-traffic sites.
Since I seem to wind up working on loosely connected but disparate projects, I already have a few sites—often just single-page sites—with the prospect for more.
So cost is certainly a factor for me with Squarespace in particular.
Control and Simplicity
A bigger reason is control and simplicity.
I can never seem to find a template that I’m happy with. I can usually find a template that’s ‘good enough’. This is what happened with the original Wordpress version of this site. It is also currently the case with the LIVE near WWDC site which is hosted by Squarespace. Both Wordpress and Squarespace have visual page builders, but of course they are based on the chosen template. I also browsed through many Jekyll templates before deciding to do my own HTML and CSS.
What I’ve found in using Wordpress or Squarespace is if I can’t find an existing template that matches what I want I have two choices: settle for what the template already does or figure out how to modify the template.
Of course, a third choice is to not use a template at all.
Put another way, the choices are:
Use the abstraction as-is
Modify the abstraction as needed
Don’t use the abstraction, use the underlying layer
Throughout my time writing software for macOS and iOS, I’ve followed the principle of working at the highest layer of abstraction that allows you to accomplish the task at hand.
Behind that principle is the idea that you can use that higher level of abstraction to get something done without needing a deep understanding of the underlying layers.
In this case, the task at hand is getting pages to look the way I want.
Option 1 is off the table since I can never find a template that fully accomplishes that. I can’t just use a template as-is.
Option 2 is to modify the abstraction as needed. Modifying the templates requires understanding the mechanics of the templating in that particular system. It also requires a strong understanding of the underlying layer, HTML and CSS. Finally, it requires understanding how that particular template is using HTML and CSS, so that tweaks to the template don’t introduce bugs.
Option 3 requires a strong understanding of HTML and CSS and no understanding of templates at all. But, it also does require creating an entire design from scratch and figuring out how to handle things that are handled automatically on platforms like Squarespace or Wordpress, like RSS feeds.
So the first option is out because it does not provide enough control. The second option seems to combine the worst of both worlds—a need to understand the underlying layer, plus a need to understand the mechanics of the abstraction.
It’s no spoiler that I’ve gone with the third option. If I want to do any customizing at all, I need a decent understanding of HTML and CSS anyway, so I might as well put my focus there and not worry about templates at all for the moment.
When you can’t use an abstraction as-is, it loses its simplicity. A hybrid of the abstraction and the underlying layer typically combines the complexity of the underlying layer with the complexity of the abstraction. When that happens, there may be more simplicity in working at the underlying layer. That’s where my thinking has led me in this case.
I just finished something that has been on my to do list for a long while.
The results are right in front of you.
I just redesigned this site and migrated from Wordpress to a static site generated by Jekyll.
Eight years ago, when I started blogging, I wanted to get rolling quickly. I signed up for a free Wordpress account, picked a theme that seemed okay, and went from there.
I never particularly liked the way the site looked but it was acceptable enough as I focused on other things.
Now I feel much happier about the site, both the result and the process that led to the result. I’ve gotten a chance to dig into HTML and CSS which I have not done for a long time. I’ve also had the chance to learn enough about Jekyll to get up and running.
I may curse my decision sometime in the future when I realize something I want to do is going to take a lot of time that I’d rather not spend.
But for today, I’m going to enjoy the small victory of completing something I’ve been wanting to do for a long while. •
Just opened the box and set up a pair of AirPods Pro about fifteen minutes ago.
First, I needed to update my iPhone to iOS 13.2 which includes the support for AirPods Pro.
Pairing was as easy as with AirPods, open the case near your iPhone and a screen appears to walk you through the process.
The noise cancelling is impressive. It’s a chilly morning in Northern California and my furnace is on, making a very noticeable amount of noise.
With the AirPods in and noise cancelling turned on, I honestly couldn’t tell you if the furnace is still running or if it reached the target temperature and turned off.
It turns out as I wrote the previous sentence, the furnace had turned off. So I went into the Nest app, adjusted the target temperature upward and the furnace came back on.
I heard absolutely no difference with noise cancelling turned on.
I had to switch off noise cancelling to confirm with my ears that the furnace definitely had come back on.
I have a pair of Bose over-the-ear noise cancelling headphones that I primarily used on flights. They are very bulky and so I’ve fallen out of the habit of bringing them along.
I will definitely be bringing my AirPods Pro on flights.
Figuring out the way to click or long click on the stem is taking a little bit of getting used to, but it’s only been fifteen minutes. The key is finding the flat part of the stem as the surface to press against.
One thing that could use improvement is the discoverability of the settings for AirPods Pro.
You reach the settings in the Bluetooth settings section, by pressing the info button in the AirPods Pro entry in the list of paired devices.
Searching for AirPods Pro in the Settings app brings up no entries. I imagine the names of paired devices are not part of the search.
Since you don’t need to visit the Bluetooth settings to set up the AirPods Pro, it never occurred to me that is where you would customize them or run the Ear Tip Fit Test.
(If you were wondering, the default ear tips provided a good fit out of the box.)
So, my first fifteen minutes (okay, now thirty minutes) with AirPods Pro have been good ones. I’m looking forward to my next flight to use noise cancellation without carrying a bulky pair of headphones. •
Since the Swift Package Manager (Swift PM or SPM) was introduced in late 2015 it has seemed like a natural fit for Xcode and SPM packages to work well together at some point in the future. At WWDC 2019, Apple announced that future was arriving in Xcode 11.
Xcode 11 provides two new ways to work with Swift Package Manager packages:
Open an SPM package in Xcode
Add SPM package dependencies to an Xcode project
These two new capabilities join a long-standing SPM feature:
Generate an Xcode project for an SPM package
Each of the these approaches are different both conceptually and in the nitty gritty details of what files they put where.
Open an SPM Package in Xcode
In Xcode 11, you can open a Swift Package Manager package directly in Xcode without needing a .xcodeproj Xcode project file.
Conceptually, you are working in a Swift Package Manager-centric world with the added ability of using Xcode to edit, build, and test your Swift package.
Note that this does not give you all of the settings and flexibility of an Xcode project. You cannot specify build phases, include resources, do code signing for an app, or any other functionality that is not currently supported by Swift Package Manager.
But being an Xcode project is not the purpose of this particular feature. This feature is all about using Xcode as an IDE for Swift PM packages.
What happens on disk?
Opening a package in Xcode adds a hidden .swiftpm/xcode directory to the package.
As you might guess, the xcode directory contains files Xcode uses such as a package.workspace file containing information about the workspace and xcuserdata and xcshareddata directories.
The .gitignore file generated when creating a new package includes xcuserdata as ignored. You will likely not want to add these files to your git repository. The files in xcshareddata on the other hand include shared schemes generated by Xcode which you may want to check into git to share among team members.
You will probably want to use the same policy of which Xcode-centric files to check in or ignore that you are using for Xcode projects.
The checked-out dependencies and build products are stored in the hidden .build directory, just like building the Swift package using swift build on the command line.
So, with a fairly small footprint of additional files, you can now use Xcode for Swift PM package development.
Add SPM Package Dependencies to an Xcode project
Also in Xcode 11, you can add Swift Package Manager packages as dependencies of an Xcode project.
Conceptually, you are working in an Xcode project-centric world with the added ability of having Xcode manage dependencies on Swift packages.
You specify the source URL and version of the package you want to use in your project. Xcode will automatically download the correct package version and any dependencies of that package. The dependencies are recorded in your Xcode project file, similar to dependencies on frameworks and libraries.
This is a significant addition. For the first time, Xcode has a native mechanism for managing and updating dependencies.
Developers in the Xcode ecosystem have traditionally turned to third-party solutions such as CocoaPods or Carthage for this functionality, or used git submodules in projects to combine code from different git repositories.
Xcode 11 opens the door to dependency-handling workflows that are actively supported by Apple and its tools.
But I don’t use Swift yet!
Even if your projects are not in Swift yet, you can create SPM packages with targets and products of C-based languages including Objective-C. The only Swift that must be in a package is the declarative Package.swift manifest file.
What happens on disk?
Adding SPM package dependencies to an Xcode project will add a Package.resolved file to the project’s workspace at xcshareddata/swiftpm. This file contains the resolved versions of each dependency. This file is intended to be included in source control so team members and continuous integration systems can use the same dependency versions.
As you might expect, the package dependencies will be referenced in the project’s project.pbxproj file.
There are no additional changes to the Xcode project and no hidden directories added. Everything else, including the downloaded package sources and build artifacts are located in the Xcode derived data directory for that project. The SourcePackages directory in the project’s derived data contains the checkouts and repositories for the Swift packages.
In addition to adding remote package dependencies to the project, Xcode will also recognize local package dependencies. This is useful, for example, if you are developing an app and a supporting package at the same time.
The addition of Swift package dependency management in Xcode gives you a powerful new option in structuring your projects’ dependencies.
Old Original SPM-Generated Xcode Project
Since the early days of the Swift Package Manager, you could generate an Xcode project for a package with the command swift package generate-xcodeproj.
This feature has always had limitations and drawbacks. With the new capability of opening a package directly in Xcode, you should never need to use this feature. But, it is still a temping option when looking at swift package help, so it might be helpful understanding why you don’t want to use this.
The SPM-generated Xcode project is intended as a convenience to use Xcode to view and edit your package. It is not meant to be a long-lasting resource.
If you make changes to the package’s manifest, add or remove dependencies, or make any significant changes, you need to regenerate the Xcode project. It is intended to be a transient resource, a convenient throwaway project to allow you to use Xcode to edit and build the package.
Because of this, the generated Xcode project was not intended to be shared or checked-in to source control. This is confirmed by looking in the .gitignore file automatically generated by SPM where /*.xcodeproj is on the list of files to be ignored.
The generated Xcode project stores some items within the xcodeproj directory including an Info.plist file per target in the package.
If your package has any C-based library targets, (for instance if you are exposing an existing C library to Swift), then the generated Xcode project contains a directory GeneratedModuleMap which contains a module map for each C-based target. The module map file contains a hard-coded path which includes the current user’s home directory. This makes the generated Xcode project decidedly un-shareable.
I am unable to think of a good use case for a generate Xcode project file now that Xcode 11 has the ability to open Swift packages directly. This functionality now seems obsolete.
With the introduction of Xcode 11, there are now three main ways to work with Swift Package Manager packages in Xcode:
Swift Package Manager-centric
Use Xcode as an IDE for Swift PM packages. No Xcode project required.
Add Swift PM packages to an Xcode project. Xcode manages the dependencies.
Swift Package Manager generated Xcode project
Don’t use any more. Just open the package directly in Xcode 11.
The WWDC 2019 session Adopting Swift Packages in Xcode contains a number of demos showing how to use Xcode with Swift PM packages and is a good resource for getting started.
Xcode 11 makes great strides in working with Swift PM packages in two complimentary ways. •