WWDC 2020

Apple started their annual World Wide Developer Conference yesterday and for the first time it was delivered virtually, and free for all developers. The conference continues throughout the week and will be running over 100 live sessions with Apple engineers.

As always the event kicked off with a keynote address showing the major changes to each platform.

Apple launched a new Apple Developer app which is pretty good and contains all the video sessions from the current and past WWDCs going back to 2016.

Apple Silicon

The biggest change is the announcement that Apple will be switching from Intel processors to their own custom designed ARM chips over the next couple of years. As the performance of their A-series chips has improved in successive iPhones and iPads, I’ve wondered at what point Apple would consider putting them in a Mac.

We’ve been in this situation before. Back when Apple used PowerPC chips, they had become increasingly frustrated with the architecture. The most powerful G5 chip was to be found only in desktop models, Apple just hadn’t been able to shoehorn it into their notebooks, despite years of trying; the chip was just too big and power hungry to work within the thermal envelope of a portable.

Steve Jobs put it best when he said:

“As we look ahead, we can envision some amazing products we want to build for you, and we don’t know how to build them with the current PowerPC roadmap.”

– Steve Jobs, WWDC Keynote 2005

ddddd

He spoke of “performance per watt” as a unit, and looking at the PowerPC roadmap projected out 12 months, they were going to get 15 “units of performance per watt”, whereas Intel’s roadmap was going to deliver 70.

I think Apple have found themselves in this situation again. Intel’s move toward 7nm manufacturing isn’t going that well, and they admit that their 10nm process is doing quite poorly after years of delays. Intel seems unable to deliver the chips Apple wants in order to build their next generation products.

This time Apple doesn’t need to look externally to find a solution as they’ve been shipping their own silicon for more than ten years already. Since 2010 with the A4 chip in the original iPad, Apple claim to have delivered over two billion custom SoCs in the last two years alone, and improved GPU performance by 1000X since the original iPad. That’s pretty amazing.

Using their own silicon in a Mac will also allow them to bring some of the specialised circuits they’ve already been adding to iOS devices, such as the Neural Engine for Machine Learning, or dedicated image signal processors for things like computational photography.

I’m looking forward to see where this can take the Mac.

Privacy

Apple got a lot of mileage out of their privacy stance. It’s good to see them putting extra effort in to explain what the difference is between their approach and mainstream tech, helping users see why it’s better.

They didn’t just mention it as each new feature was revealed, they had an entire section dedicated to their position that privacy is a “fundamental human right” and their key principles to achieving it, which were:

  • Data minimisation – avoid collecting any data in the first place if you can
  • On-device intelligence – avoid sending data to the cloud wherever possible
  • Security protections – stops malicious attempts to access data
  • Transparency and control – puts users in the driving seat

In a time where mass surveillance and data gathering, the likes of which George Orwellcouldn’t even imagine, is so prevalent, I think it’s admirable that Apple is one of the few in “big tech” that is putting their money where their mouth is to defend privacy.

On iPhone, the inclusion of activity lights for the camera and microphone, showing up to the right of the notch, is a nice touch too.

On the web, Apple have been driving privacy forward for years now in Safari, with Intelligent Tracking Prevention identifying and blocking trackers from profiling your browsing activity. The latest update adds a new Privacy Report showing which trackers are being blocked, and how often they’re cropping up in your browsing sessions. It’ll also alert you if a password you’re using on a website has been compromised, and gives you fine-grained control over which browser extensions can run on which websites.

iOS 14

The biggest change for iOS must be the new home screen design. It’s never really made that much sense to me that the widgets were relegated to an almost hidden screen to the left of home. I’ve always quite liked the Metro UI on Windows Phone, and these new widgets remind me of that, but with a nicer design and more flexibility. The “Smart Stack” widget looks like it will be quite useful, showing multiple widgets in a stack, and automatically showing the most relevant at the top. It’s worth noting that these new features are not mandatory, users can keep all their home screens the way they are right now if they like.

The new “App Library” is a nice take on an old Android feature for listing all apps, I think it’s a better implementation though as it groups each app by its category, with the top two slots being reserved for “Siri Suggestions” and “Recently Added”.

The changes to iMessage are welcome too. Features like “mentions” and “threads” already exist in many other chat apps, so iMessage is playing a bit of catch-up here, but again we shouldn’t forget the privacy benefits.

The improvements to Maps (especially navigation) looked quite nice, but they tend to be quite US-centric, rolling out to other countries quite slowly. For example their take on Google’s Street View, named “Look Around”, is still US-only. Again though, privacy is at the forefront with Apple claiming (emphasis mine):

“Maps is the best way to navigate and explore the world, all while protecting your privacy.”

Here’s hoping they can speed up the rollout of these features worldwide so everyone can benefit.

iPad OS

iPadOS is growing up again. A lot of the features were “quality of life” improvements, bringing parity with the Mac, things like proper sidebars with drag and drop, full Spotlight search integration and so on.

The standout feature for me was “Scribble” which allows you to use Apple Pencil to convert handwriting to text in any text field on the system. When I was studying at University I invested in a Toshiba Portégé 3500 hybrid laptop/tablet which ran Windows XP Tablet PC Edition. You could use it in a standard notebook configuration, or you could flip the screen around so it closed facing outwards and use it as a tablet with an included stylus.

It allowed you to take handwritten notes, which would be converted to text, mixed with diagrams and so on. This was most definitely a great idea that was way ahead of it’s time. Sadly the technology of the era just wasn’t up to the task, but the concept itself has always appealed to me, and it’s brilliant to see it here again in iPad OS 14. The Portégé was 3.2cm thick and weighed 1800g, compared to the iPad which is only 5.9mm thick and weighs a mere 471g. I would have loved this device back when I was a student. To be able to carry all of my textbooks and take down all my notes, sketches, diagrams all on this single lightweight device would have been incredible.

macOS Big Sur

No longer do Apple fans have to explain to people that the X is pronounced “ten” as this is the first macOS since 2001 that isn’t version 10. There’s quite a big change to the UI, bringing back some of the depth that was missing since the flat design of Yosemite debuted.

There are lots of rounded corners in windows, buttons, menus, and icons, which unifies some of the design language between iOS and macOS, but rather than totally iOS-ify the Mac, Apple seems to recognise and acknowledge that the Mac has its own personality, and they should embrace that rather than extinguish it.

It also made me think that a change in Mac form factor might be around the corner. iPhone and iPad already have displays with rounded corners, perhaps the first Macs to use Apple Silicon will feature rounded displays to match? In Luke Miani’s video review he shares this view but also observes that these big round buttons are “more touch friendly” too, possibly indicating touch screen Macs could be on the way in the future.

The ability to run iPhone apps natively on Apple Silicon will be interesting to see. My concern here is that the current generation of Catalyst applications haven’t been very good so far. Could this lead to a dumbing down of Mac applications? I hope not, but Apple still have a bit of work to do with Catalyst to prove that you can create apps that look and feel like proper Mac apps.

At the same time, I do think the shared architecture will make it easier for developers to build applications that run across all Apple devices, optimising the UI for each device, but without needing to re-engineer the entire backend of the app each time. This is the strategy Microsoft were pushing with Windows 8 and Windows Phone, unfortunately that didn’t work so well, but I have more faith in Apple here to deliver on this.

Interestingly, Apple seems to be reversing course on extensions in Safari, having all but removed them in previous versions, they are embracing them again through a new technology called Safari Web Extensions. This seems very similar to the WebExtensions API that Firefox uses and should allow extension authors to write extensions that work on multiple browsers, with just a few browser-specific changes.

Apple were also keen to highlight the industry leading performance of Safari, claiming the new version is 50% faster than Chrome, plus the extra battery life you’ll get from Safari (1 to 3 hours more depending on the activity) compared to Chrome and Firefox. I’m looking forward to the final benchmarks to confirm this claim, but Safari does have a track record of being much lighter and faster than other browsers.

Everything Else

Since this article is getting quite long, some final thoughts on a variety of things Apple mentioned during the keynote:

  • Built-in curated Guides for Maps looks nice for people visiting new cities, once the current pandemic is behind us. Things like cycling directions taking elevation, road density and business into account are nice for optimising your cycle route. Maps gains EV charger location support but goes a bit further and can take into account the charger type your vehicle uses, so you don’t end up stuck at a site with the wrong one.
  • Spatial audio for AirPods Pro looks incredible, automatically switching between multiple devices based on which ones you’re using is a game changer for bluetooth audio, which is otherwise clunky when dealing with multiple devices.
  • I liked their idea of a “Nutritional Information” table for app privacy covering what data will be collected and what it will be used for so you can see at a glance what to expect. I think this metaphor will help people understand the importance.
  • The open-sourcing of HomeKit, and the cross-partner Home Automation approach sounds like a great idea, hopefully we’ll see more compatibility across the home automation ecosystem with this, all with a focus on privacy.
  • Adaptive Lighting is basically “Night Shift” but for your light bulbs – very nice.

Wrapping up

Tim Cook said a couple of times throughout the keynote:

“We haven’t stopped innovating”

I think this is true. Although there wasn’t one big item revealed that blew people away, I think the scale of what they’re trying to do across the board right now – to create a unified platform across desktop, notebook, phone, tablet, watch and television – is very ambitious and exciting. It’s also good to see Apple recognising and trying to address where they’re weaker, for example by finally allowing people to change some default applications on iPhone, and opening up Siri and HomePod to work with more applications.

I for one will be looking forward to seeing what happens next.

Jekyll and GitHub Actions

When deciding to resurrect this blog, I first had to do some research to choose the right software to do the job. The original blog years ago was deployed using WordPress and while I’m still a fan of WordPress I wanted to keep things super simple this time around.

At work last year I redid some internal documentation for a large Ansible automation project and had a few things in mind:

  1. The documentation for the code should live with that same code to make it easy to keep up to date as the code changes.
  2. The documentation should be as lightweight as possible, avoiding the need to maintain any hosting software or databases.
  3. The documentation should be easy to write so it doesn’t feel like a chore.

These requirements made me immediately think of Markdown. We could commit Markdown alongside the code itself, write it easily, use any editor, read it locally and so on.

Paired with a static site generator, you can actually get some really nice looking documentation with a minimum of effort. The generator takes the Markdown files, and creates static HTML pages using a template.

For the work project we ended up using software called MkDocs which is very good, but focussed around project documentation; for this site I needed to look at something more focussed on blogging. I had already decided I wanted to try GitHub Pages so that publishing a new post would be as easy as committing to a repository, and the new post would be generated and made available almost right away.

Jekyll is a static site generator that is supported by GitHub Pages out of the box and is written in Ruby, which I have experience with, so it felt like a good place to start.

I followed the quick-start instructions on the Jekyll website and was up and running pretty quickly, but I’m a tinkerer, I like to dig deeper into things and see how they work, so I found myself cloning the default theme to see exactly how it built a page and how I could customise it.

Most of the customisations I made were small, things like adding the estimated reading time to each post, displaying the categories the post belongs to, adding ARIA tags for accessibility and so on.

Committing all of this to a GitHub repository and turning GitHub Pages on in the repo settings was painless and everything worked as expected, hurray!

My next issue was that I wanted to add archive pages to list posts by category or date, so that I wouldn’t need to add this later once I actually had some content. Going back to the earlier goal of simplicity I wanted the tool to handle generating archive pages for me, but out of the box Jekyll can’t do this. It is however extensible through plugins, and I was able to find and install a plugin called jekyll-archives, but here I hit a snag; this plugin isn’t supported by the version of Jekyll that is used by GitHub Pages.

What to do? Well luckily for me, GitHub have recently launched their own CI/CD automation workflow called GitHub Actions, allowing you to perform certain actions when code is committed to a repository, so we have an option to run Jekyll directly instead of relying on the one integrated with GitHub Pages. This allows us to do anything you could do normally with Jekyll, including use custom plugins.

Building a workflow

GitHub Pages can be configured to skip running Jekyll itself and instead just take an existing set of static HTML files from a branch named gh-pages and use those, so I needed to setup a workflow for GitHub Actions that would do the following:

  • Checkout the latest revision of the repository
  • Set up a Ruby environment and install Jekyll
  • Run the jekyll build command
  • Push the result of the build command to the gh-pages branch

To create a GitHub Action you define the workflow in YAML format and commit that file into a .github/workflows/ folder in your repository, after which you’ll see it listed under the Actions tab of your repository. So let’s translate each step above into an action in our workflow, using the actions available.

Workflow start

We want to start by naming the workfow and configuring it to run any time commits are pushed to the master branch, we also configure the workflow to be run inside an Ubuntu linux environment which is setup fresh each time the workflow runs. We define the steps key which we will fill in as we go.

---
name: "Build Jekyll and push to 'gh-pages' branch"
on:
  push:
    branches:
      - master

jobs:
  build:
    runs-on: ubuntu-latest
    steps:

Checkout the code

The first item to add to steps is an action to checkout the latest revision of the master branch, which is done like so:

- name: Checkout
  uses: actions/checkout@v2

Ruby

Next we want to setup a Ruby environment and there is an action that can handle that for us:

- name: Set up Ruby
  uses: actions/setup-ruby@v1
  with:
    ruby-version: 2.6

Now we should have a Ruby environment and our Jekyll project checked out ready to go, we need to install Jekyll and it’s dependencies from the Gemfile in our project. Here we don’t need any particular action, we just want to run a command:

- name: Bundle install
  run: |
    bundle install

Jekyll

Next we run Jekyll’s build command against our project and tell it to place the resulting static HTML files in a folder named:

- name: Bundle install
  run: |
    bundle exec jekyll build -d target

Now we should have the static content ready to commit to the gh-pages branch, but I wasn’t sure how to proceed, I came across a blog post by Benjamin Lannon which shows that you can run git commands normally, however I wanted to commit to a different branch (gh-pages in this case) and only commit the result of the jekyll build command, to avoid accidentally including non-content, such as the Gemfile. After a bit of Googling I found this very helpful Gist which showed a very tidy way of avoiding this issue entirely.

Using the subtree split feature of Git we can split the repository apart by taking only the commits that affected our target folder created in the previous step. Since this will be a single commit containing the entire generated site, we then force push that to the desired branch for GitHub Pages to pick up and deploy for us.

Git config

Let’s configure a user for the commits to be made as:

- name: Setup Git config
  run: |
    git config user.name "GitHub Actions Bot"
    git config user.email "<>"

Next we create the commit using git subtree split:

- name: Commit
    run: |
      git add target
      git commit -m "$(git log -1 --pretty=%B)"
      git subtree split --prefix target -b gh-pages
      git push -f origin gh-pages:gh-pages

That’s it! Now we should be able to use the full functionality of Jekyll and any plugins we like, but we still get the simplicity of pushing a single commit to our repository, in order to publish new content. There are a couple of enhancements we can make to speed up the performane of this workflow though.

Caching

Rather than setting up the Ruby environment from scratch every time, we want to cache the gems we’re using so that they can be installed much quicker next time. There’s a Cache action we can use to do this for a variety of languages including Ruby.

First we need to include the Cache action in our workflow, place this new task above the Set up Ruby task:

- uses: actions/cache@v2
  with:
    path: vendor/bundle
    key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
    restore-keys: |
            ${{ runner.os }}-gems-

This will instruct GitHub Actions to cache the data in vendor/bundle using a specific key, in this case the key includes the operating system of the system running our workflow, and the hashFiles function is used to generate a hash for a given file, in this case our Gemfile.lock, so that we only rebuild our cache if the Gemfile (and therefore the hash) changes.

Next we need to configure Bundler to actually use this cache when installing gems. Modify the Bundle install task to look like this:

- name: Bundle install
  run: |
    bundle config path vendor/bundle
    bundle install

Summary

Putting it all together, here is the here is the complete workflow configuration we just built:

---
name: "Build Jekyll and push to 'gh-pages' branch"
on:
  push:
    branches:
      - master

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set up Ruby
        uses: actions/setup-ruby@v1
        with:
          ruby-version: 2.6

      - name: Bundle install
        run: |
          bundle install

      - name: Bundle install
        run: |
          bundle exec jekyll build -d target

      - name: Setup Git config
        run: |
          git config user.name "GitHub Actions Bot"
          git config user.email "<>"

      - name: Commit
          run: |
            git add target
            git commit -m "$(git log -1 --pretty=%B)"
            git subtree split --prefix target -b gh-pages
            git push -f origin gh-pages:gh-pages

      - uses: actions/cache@v2
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-gems-

      - name: Bundle install
        run: |
          bundle config path vendor/bundle
          bundle install

That’s it! We should now have a self-contained automatic workflow for publishing new content to the blog by simply commiting a new Markdown document. We have caching in place to make the process as efficient as possible, and tasks are only executed if something has changed.

First Post

A long time ago I bought my first Mac and started writing a blog with tips, software reviews and so on, to document my experience switching from Windows to Mac. Not long after that, I’d started a new job at a tech startup, there was a lot of work to do and a lot of things to be learned, so I kinda got out of the habit of posting.

More recently I was speaking to a friend who has a blog they actually do keep up to date and they were saying how much they enjoyed writing, so I decided it was time to dust off the keyboard and try to get back into the habit myself.

After a couple of weeks procrastinating tinkering with blogging software and CSS I’m finally “back on the air”. Let’s see how this goes. 🤞