Tonight I got bested by a home improvement project that tutorials call "easy".

I need to remember when I'm talking about a concept to not call it easy, because the reader may be at a level where it's not easy for them. The last thing I want to do is discourage someone who's trying to learn.

My iOS Project Template

Like many of my fellow iOS developers, I often find myself starting little projects here and there. Also like my fellow iOS developers, I have developed a preferred project structure. This structure has changed quite a bit recently as I've been exposed to a different way of doing things at Lyft. We have a highly modularized codebase and I quite like that methodology. I dipped my toes in the many framework waters in my time at zulily but what we have at Lyft goes well beyond that.

As such in my personal projects I have incorporated additional modularization and automation. My goal with this post is to peel back the curtain a little bit and give you some ideas on how you might be able to use modularization to create clean boundaries between code in your project.

To kick things off, I've published my template code on GitHub.

I really like using commands via a Makefile to run automations, and further from there my aim is to have a project as self-contained as possible. What I mean by that is I don't want to rely on Ruby gems or Python modules managed by a central system on my machine. I freely admit that this is because of my ignorance to how those environments work. There have been great tools built on those platforms. But, like Orta Theroux wrote on the Artsy blog, I agree that it's time to use Swift Package Manager.

It turns out that Swift is a really nice language to write tools in. For me, as one who hasn't fully grasped Ruby or Python for tooling (though I would like to eventually) being able to use Swift to build some automation has been great. And now we can use SwiftPM to manage these dependencies for us. If you look at my Package.swift file you'll see that I'm creating a "dummy" Swift module to get all the power of swift run in the Makefile.

Make is a super old system, and I had never used it prior to joining Lyft. And I gotta say, I love it. It's a great central place to run commands to do work on my project. To add a new module, I run a script by calling make new-module. The script asks for the name of my module and goes about creating some template files and linking it in to my app.

Secret Sauce

To be honest, I've somewhat buried the lede here. If you glance over the .gitignore file you'll see an entry for *.xcodeproj. Yep, I'm ignoring Xcode project files. This is because I'm using a tool called XcodeGen to create my project files using yaml definitions in my repo.

I love this.

I love that I don't have to worry about Xcode project conflicts in git merges (of course on side projects this isn't a big deal for me). I love that I can easily rename my project on disk and it's instantly reflected the next time I generate the project. I love that I can move a group of files around, regenerate, and have my new file group or module instantly.

My modules all live inside of a Modules folder stored at the repo's root. The project.yml file is what drives the structure of the resulting Xcode project. Each module has its own definition file, which helps keep the project definition file slim.

Wrapping Up

I've been working through these pieces for over the past 6 months or so. When I got back in to Scorebook I adapted the structure, and over a couple of other small projects I've started up I've built out the shell that you see in my GitHub project. I hope some parts of it are helpful for you in some way.

As always I love talking about this stuff and am happy to answer any questions you might have. And, if you've got a better way that I'm missing the boat on please let me know. Let's help each other get better 🙂

I want to write more blog posts, but don't have a lot of topics in the queue. If there's something you'd like to hear about I'm all ears. iOS development, Swift, the Vapor framework, Seattle Sports, Batman, Jesus, whatever might make for a good topic.

I'm all ears!

🎙 Making My Podcast Debut

I was happy to join Caleb Wells on his podcast A Swiftly Tilting Planet. We chatted a lot about my story as an iOS engineer, what it's like to do that job at Lyft, and got even more excited for the coming WWDC. Plus a lot of community talk. It was a really good time talking with him.

This was my first time being on a podcast. I've mentioned to a few people that I wanted to start doing a podcast this year. I tried a couple things on my own that I haven't (and probably won't) release, so getting the message from Caleb was a huge honor. I honestly don't know if I'm going to listen to it or not – I think the idea of listening to myself talk makes me more nervous than the recording did!

I hope you find the episode enjoyable and/or helpful in some way. And if there's any feedback on the content or other tips for future recordings I'm all ears.

A Swiftly Tilting Planet Episode

I didn’t get a golden ticket to WWDC. It’s par for the course for most folks I guess, but I’m still disappointed. I’m still going to San Jose from June 2-6 and can’t wait.

I did submit a talk for AltConf and I’m hoping it gets accepted. 🤞

I finally got a shortcut set up the way I want so that I can post to my site from iOS easily. A new update to iA Writer added the ability to browse a textbundle as a folder which is exactly what I need to get going.

This summer I hope to make lightweight editors for iOS and Mac (the Mac using Marzipan if it’s good enough).

You can find the shortcut here

Scorebook Sync Log 10: Shipped!

Scorebook v1.6 shipped a little over a week ago, and it finally includes all my sync code. When I cracked the project back open late last year I decided to turn off the engine that I'd put together just to get the app back in shippable condition. But I also knew that I wanted to ship the sync shortly thereafter. Well, it took about 6 weeks for me to be comfortable enough to get it out the door.

Honestly it's a little embarrassing how long it took to get this feature out. I started writing about it over 4 years ago (if you're interested in reading through the journey, they are curated here). I thought I was going to get the feature shipped by WWDC 2015. Welp. It's out there now, and that's the important thing.

Back when I was building the feature I knew I wanted it to be as seamless as possible. A modal on startup asking the user if they want to turn it on, and then a simple switch in the Setting screen. Everything else should be handle-able by my sync code. And because their data lives in iCloud I don't have to worry myself about encrypting or having any access to user data. Mission accomplished on both fronts.

As I revisited the feature when getting back into the app there were a few deprecations that had come in since iOS 8 but the code I wrote back then was still good. I did it all in Objective-C so there weren't any crazy language changes to migrate through (thank God I didn't adopt Swift 1!).

Now I get to look forward to building truly new features. I know I want to tackle dynamic type and accessibility, and might do that next. Then come the summer I want to rethink what the gameplay setup screen looks like as well as the scorecard screen. I know the whole UI could use some updating since it's very much from the iOS 7 era of design. But for most of that I'll hold off to see what Apple has in store for us at WWDC.

Check out Scorebook 1.6 in the App Store!

Hello Dark Mode

One of the projects that's been on my mind since WWDC last year when the Mac got dark mode was adding support for it to my website. I know that Safari doesn't support it directly yet (though it does in the Technology Previews) but it will soon, and the rumors are hot and heavy that iOS 13 will have it as well. I wanted to be ready, and break outside of my normal comfort zone for a bit.

Things are getting dark around here

I'm no CSS wizard by any means, and I found a very helpful Iconfactory post detailing how they added support to their site that served as my guide. I took the time to refactor some CSS into helpful variables (a few were already in place from the Ghost theme I used to use), and it wasn't too much work to get the initial pieces in place.

The bigger work came with syntax highlighting. I use prismjs for my syntax highlighting, and it consists of 2 components: some Javascript and CSS. The JS file didn't need any changes but my default CSS uses their light theme. Thankfully CSS has handy conditional @import rules that let me use a media query. So I downloaded a separate CSS package for a dark them and applied it and all was well. This also allowed me to move the code highlighter CSS import to my main CSS file, meaning each page on the site loads exactly 1 CSS file. I count that a win in my book for maintenance.

The last thing was figuring out table styling, since I used one in my post about iOS push notifications, and that wasn't too bad either. If you want to check out what I did, the commit is right here.

If you'd like to check out what the site looks like in dark mode, download the Safari Technology Preview and flip your Mac running Mojave into dark mode.

Photo Project: Daily Batmobile

A big part of the creative process is showing up every day, and that's one place I've fallen short many times over the years. It's super easy to start something, but seeing it through is another. This year I wanted to do a creative project that would challenge me to show up every day, and I found one.

When I got my new camera a while ago I read a blog post that gave a simple piece of advice to help shoot more: take a trinket with you. The idea is to photograph it in many different settings, and being mindful of wanting to take more pictures encourages you to learn your camera and think about how you can frame the next shot. My wonderful wife got me a Hot Wheels Batmobile for me to carry around, but I didn't do much with it at the time.

I decided this year to take on the creative project of shooting a photo a day with my Batmobile and I'm pleased to report that I've shown up every day this year. Some are better than others (which is to be expected!) and a couple have made me very happy with how they've come out.

Honestly I've gone back and forth deciding whether or not I want to share them. On the one hand, it's a fun project and I'm really enjoying it. On the other hand, I know my skills aren't fantastic and it opens me up to critique (and knowing the internet, possibly some sharp barbs along the way). But I've decided to go for it and share them because I want to get better and I want to hold myself accountable this year to deliver a photo every day.

I'll be posting my photos on an iCloud shared album here. I would like a slightly better web presentation but this method is easy for me to publish from my Mac or iOS devices so that's the way I decided to go. I'm anxious to hear any feedback that you might have.

I never thought that I'd become "sharp edges guy" but the last couple of days at work I've run into doozies.

  1. The AVCaptureMetadataOutput.rectOfInterest rectangle has to be transformed into the coordinate space of the output itself - meaning that you can't give it a CGRect from your view and have it work. Instead it must be converted to the coordinate space using AVCaptureVideoPreviewLayer.metadataOutputRectConverted(fromLayerRect:).
  2. When adding a custom view to a UIBarButtonItem you need to have that view handle the tap on the item itself. Assigning a UIImageView, for example, negates the bar button item's target and action properties for some reason. Of course it's not documented.

I wonder what I'll run into tomorrow 🙂