Daniel Kennett - Home

Web Name: Daniel Kennett - Home

WebSite: http://www.ikennd.ac

ID:232464

Keywords:

Daniel,Kennett,Home,

Description:

keywords:
description:
July 5th, 2020 Vacation In Saudi Arabia

Back in February, just before the world went entirely to shit, I went on holiday to Saudi Arabia. The experience was pretty incredible, and one I’ve decided to write about alongside some of my favourite photos from the trip.

You can read the post in full over at Vacation In Saudi Arabia on my photos subsite. Enjoy!


April 5th, 2020 Successfully Working From Home: It's All About Boundaries!

As the COVID-19 social distancing settles in, the novelty of working from home is starting to wear off and, even worse, we’re starting to realise that instead of the awesome feeling of “I’m always at home!”, we’re starting to suffer from… “Which also means… I’m always at work!”

Working from home can very easily end up eveloping our entire lives, making it feel like there’s no escape. It starts when you decide “Oh, since I’m not commuting, I can spend that extra time working!”, and ends when you’re sitting in bed checking work emails at midnight.

A few years ago, I worked from home fulltime for towards a year. Here are my tips for staying sane, staying productive, and most of all, staying healthy. As you’ll see, everything revolves around a critically important theme: boundaries.

Disclaimer: I’m not a mental health expert, and this entire set of tips is within giant “in my experience” and “I find that…” modifiers. Please take inspiration here if you can, but don’t force yourself to this way of working.

Another Disclaimer: This post is aimed at people who work using computers and are trying to transition into healthily working from home in a childless environment.

Problem 1: Boundaries In Workspace

The great thing about travelling outside your home to work is that it puts “work” in a completely separate physical space — which makes it really easy for your brain to map it to a separate mental space as well. It’s important to be aware that your “work space” is both the physical place where you perform your work, and the mental place in which your mind exists while doing it.

Travelling to work moves you to a new place physically, and gives your mind a comfortable routine that allows it to prepare for the workday ahead. In a similar way, travelling home from work leaves your work behind both physically and mentally — giving your mind a chance to wind down and relax.

This all falls completely to pieces when you’re working from home and your workplace is a laptop on your dining room table. There’s no physical or mental separation between home and work — and if you can’t leave work behind mentally, you’ll find yourself “quickly checking Slack” while dinner is cooking or “just looking at this email” before bed, and you’ll completely lose that separation that’s so important.

Luckily, there are many things we can do to help our minds keep work and life separate, even within the home.

Find an “office” in your home, and always call it by that name

This is easier in a house with spare bedrooms than in a one-bedroom apartment, but it can be done anywhere. Having a single, dedicated office space in your home for work will really help maintain boundaries — giving you place to “go to work”, and perhaps more importantly, leave. Even if you put your laptop on your dining room table to work, tape off that part of the table with something that won’t damage it. That is your office.


I currently have this ridiculous setup at home, because I brought my work computer back from my main office. My “office” is now the left-hand side of this desk.


Taping off a corner of table creates a completely valid office.

Once you have an office (or an “office”), be strict! The only thing you do in the office is work. When it’s time to work, go to the office, and when it’s no longer time to work, leave. If you share your home with other people, sit down and have a disscussion with them to explain that your office at home should be treated as if it’s your office at work — when you’re there, you should be treated as if you were in an office somewhere else. “Sorry, I’m in the office right now — I’ll do that when I get back home.” is a completely valid thing to say.

If you work with a computer, keep your home computer and your work computer separate… even if they’re the same computer

Now you have your physical location sorted, it’s time to work on your mental space.

If you’re lucky enough to have more than one computer, this is easy. However, if you do only have the one, this can be achieved by creating a new user on your computer and dedicating it to work. Only put work stuff on your work computer/user, and only non-work stuff on your home computer/user.

This artificial boundary provides two benefits: It doesn’t clutter your home computer/user with work stuff (and vice versa), and it makes transitioning from one to the other a physical action in getting up and moving to the other computer, or clicking a button or two to specifically tell it “I want you to be in work mode now”. This physical action will help your mind separate the two things as well.


My wife says my work picture is the less professional of the two… BUT I’M WEARING A TIE!

A particularly nice thing to do — especially if you’re sharing one computer with yourself — is to configure a different colour scheme for your home and work computer/user. It’s amazing how different the same machine can feel with a different colour scheme, and it’ll help your mind settle in and focus on what you’re doing.


Having a very clear visual distinction between your computer being in “home” mode and “work” mode can help your mind do the same.

Problem 2: Boundaries In Time

I’ll get this out of the way early: The idea that you can counter a drop in productivity by working more hours per day is a fallacy. If you would typically do an 8 hour workday in the office, doing more hours than that at home won’t help if you’re suffering a productivity drop. You’ll still get less work done, and you’ll feel like shit because you hurt your work-life balance for no reason.

In order to keep a healthy work-life balance when both are happening in one building, you need to be strict with your time boundaries as well as your workplace ones. This actually goes both ways — it’s important not to let your work time take over your home time, but it’s equally as important to not let your home time take over your work time.

What does this mean?

Well, it may be tempting to take a little 30 minute break from work during the day to, say, do the laundry. So, off you go, breaking your physical workspace boundary in the process. As you’re doing the laundry, you notice that the utility room is a bit dusty, so you whip out the vacuum — it’s only an extra 5 minutes, right? Well, since I have the vacuum out…

The next thing you know, it’s an hour later. No biggie, right? You’re working from home! You’ll just work an extra hour into the evening!

This sounds harmless, but how would you feel if you worked an extra hour at your normal workplace? It’s never a nice feeling, and you get home more tired and more grumpy than you normally would have. Dinner ends up being later, giving you less time in the evening to unwind before bed.

I’m not normally a fan of slippery-slope arguments, but this is one of them. It’s so easy to just blur the lines “just this once”, but as time goes on, things blur together until you have no separation between work and life at all — you just kinda “do stuff” all day, then sleep, then do the same the next morning.

Let’s see what we can do to help ourselves:

Be as strict with time as you usually are

If you normally get to work at 9am, take an hour lunch, then go home at 5pm, keep that routine up at home. When it’s time to go home, either turn off that computer and leave it in your office, or log out of your work account and log in to your home one as you bring your computer “home” with you from work. As with maintaining your workplace, if you live with other people, explain to them how important it is that your work times are respected. Continuing to use phrases like “I’m at work right now, I’ll do it when I get home.” really help here.

If you get tempted to sneak in some quick housework or something else that’s suddenly possible because you’re physically at home, try not to get distracted by that when it pops into your mind. Instead, write it down on a little “To-do when I get home” list — if you finish work early, you can “go home” early and get those things done!

Replace your normal commute with a stationary one

It’s tempting to decide to give yourself more work or more home time in lieu of a commute, but your commute is an important part of your day — allowing your mind to get ready for work, and to wind down afterwards.

If your normal commute consists of sitting on public transport as you listen to podcasts/music/etc, you can continue to do that. Searching for “train view” on YouTube provides multi-hour long videos like this one — you can still stare out of the window of the train even if you’re stuck at home!

If you exercise by the form of walking or biking, you can do that too. Biking indoors can be expensive — you need an exercise bike or a “turbo trainer” to mount your real bike to. Jogging or walking on the spot is easier without needing extra equipment, but do be careful not to hurt yourself.

Problem 3: COVID-19

This is a bit of a special section, since it’s hyper-specific to the time this is being written. It’s difficult to write “tips” for this without getting preachy, so I’ll keep it brief:

It’s understandable that you’re anxious right now, and scared. There’s so many things going on that you can’t control, and a thousand people in your Twitter/Facebook/Slack linking articles every few minutes.

Heightened anxiety right now is to be expected, and reduced productivity along with it. That’s OK.

Try to filter the information firehose a little — by muting those particularly noisy people on social media, by avoiding areas of the internet full of speculation, by looking up news from a source that focuses on your local area, and so on.

While working, try to switch off the firehose entirely. Get rid of Twitter, Facebook, Slack channels dedicated to COVID-19, the lot. You can keep up-to-date and safe without up-to-the-second feeds scrolling past all day long.

While not working, try to focus on helping those you can help, rather than dewlling on those you can’t. Keeping yourself healthy means you can help keep your family and friends healthy — calling a family member to help keep spirits up will do far more good for both of you than sitting on your computer fretting about the death toll in a country halfway around the world away.

Conclusion

Maintaining a healthy work-life balance is difficult when both of those things happen in the same place. I’ve found that successfully maintaining that balance, with healthy productivity when working and healthly time away when you’re not requires that you’re very strict in a few areas:

You must be strict about where you work and where you don’t.

You must be strict about when you work and when you don’t.

Some of the suggestions here sound silly on the surface, but they have an important underlying idea: maintaining a strict separation between home and work, and retaining that buffer between the two with a stationary commute.

Being healthy also requires that you keep in mind the most important sentence in this entire post: The idea that you can counter a drop in productivity by working more hours per day is a fallacy. Especially in the beginning, you’ll have horribly unproductive days. And that’s completely OK. Turn off your computer at 5pm, leave work behind, and try again tomorrow. You got this!


April 2nd, 2019 When Should I Head Home From WWDC?

This question comes up every year, and I’ve seen it floating around Twitter today.

When should I head home from WWDC?

WWDC runs from Monday morning to Friday afternoon, but it’s mostly “done” by lunch time on Friday, with a few labs running into the afternoon. Most answers I see debate between heading home on Friday afternoon or Saturday morning.

I imagine it’s too late now since most people have probably booked their flights already, but allow me to propose an alternative.

Fly home on Monday. Especially if you’re heading back to Europe.

Let me explain.

You’ve just spent a week smack dab in front of a huge firehose of new information and exciting features. Your brain is still processing it all, and is full of exciting ideas of how you’ll spend the time between WWDC and the next public iOS release in the autumn.

Basically, you won’t rest until September.

Last year, instead of flying home right away I headed over the hills from San Jose to Santa Cruz, and spent the weekend basically doing nothing that required brainpower. I went biking on a rented bike, and took an open top train on a tour through the countryside.

Those two days were the best professional days of my entire 2018. Chilling out and letting the week’s craziness sink in at its own pace was a wonderful end to the week — instead of my WWDC week memories being capped with a stressful run to the airport and losing my weekend so I could be back at the office on Monday, it was capped with mountain biking and trains and sitting on a beach watching the sun go down.


Thanks to some local knowledge from a friendly hotel staff member, I was able to sit and watch the sun go down over the Pacific without a single other person in sight. A perfect relaxing end to one of the craziest weeks in the iOS dev calendar.

It’s incredibly important to look after your mental health, and crunching through the summer for the next iOS release is often draining. Just taking a couple of days to relax and let the new stuff settle in before hitting Xcode can do wonders.

Of course, this won’t be for everyone. However, I urge you to consider it! Hotels outside of the WWDC bubble are significantly cheaper, and if you’re travelling for your employer a lot of official company travel policies even say you’re not supposed to travel for work on weekends1!

Last year was the first time I tried this out, and I’m fairly sure this will be a standard tradition of mine going forwards. I didn’t even get a ticket last year — I was just in town for socialising and AltConf.

This year I did get a ticket, and I hope to see you there! Even better — I hope to see you chilling out somewhere the weekend after!

Much to the annoyance of managers, I’ve found. I’ve had to push back multiple times to managers trying to make me travel on weekends “because it’s cheaper”. ↩


February 4th, 2019 Editing, Previewing and Deploying Nanoc Sites Using An iPad

This post is included in the iKennd.ac Audioblog! Want to listen to this blog post? Subscribe to the audioblog in your favourite podcast app!

Apple Podcasts Overcast Castro Pocket Casts Direct Feed

For the first time in this blog’s history, I am going to try my very best to write, edit, polish and deploy a post using only an iPad (sort of). I’ll let you know if I was successful at the end!


Unfortunately, the power button on the iMac G3’s keyboard does nothing on an iPad.

The unfortunate reality of the iPad right now (in early 2019) is that for many workflows, it simply isn’t viable as a replacement for a “real” computer. For the workflows that can be done entirely on an iPad, those that manage to do so end up allowing us to modify an old joke:

How can you tell if someone uses an iPad as a laptop replacement? Don’t worry — they’ll tell you!

This isn’t to belittle their achievements — building a viable workflow for any serious task that requires more than one app on the iPad is a real challenge, and people are damn right to be proud of their collections of Shortcuts and URL callback trees.

However, slowly but surely the iPad is getting there as a desirable computer for getting work done. Personally, the 2018 iPad Pro crossed over this line for a couple of reasons, and for the first time in the iPad’s history, it’s a computer I want to carry around with me and use for “real” work.

Self-Inflicted Development Hell

Unfortunately for me, I’m a developer. Because of that, when I see a problem, I come up with a developer solution. Most people have been able to write articles for their blog on their iPad for years - they just use Safari to log into Squarespace, Wordpress, or whatever else they’ve chosen and write away.

My blog, however, uses nanoc. Nanoc is a program that takes a pile of files, processes them, and spits out another pile of files that happens to be a website. I then upload this pile of files to my webserver, and my article is live!

To do this, I simply open my terminal, cd into the directory of my blog, then run bundle exec nanoc to generate… and we can see why this doesn’t work on an iPad.

Developer Solutions to Developer Problems

So, what do I really want to do here? I want to be able to:

Write blog posts on my iPad.

Preview them on my iPad to check for layout problems, see how the photos look, make sure the links are correct, etc.

Once I’m happy with a post, publish it to my blog.

Step one is easy enough - I find a text editor and type words into it. However, step two is where we fall over pretty hard. Many editors can preview Markdown files, but they only preview them “locally” - they don’t put the preview into my website’s layout, won’t display photos, and generally won’t parse the custom HTML I put into my posts sometimes.

To achieve this, we really need to be able to put the locally modified content through nanoc and display the output through a HTTP server. This is easy peasy on a traditional computer, but not so on an iPad.

Here we arrive at why I’m only sort of writing this post using an iPad — while I am sitting here typing this post on an iPad, I have a computers elsewhere helping me along a little bit. My solution has:

A continuous integration (CI) server watching my blog’s repository for changes, then building my blog with nanoc for each change it sees.

A static web server set up to serve content from a location based on the subdomain used to access it.

As I’m writing this, I’m committing the changes to a branch of my blog’s repository - let’s say post/nanoc-on-ipad. Once I push a commit, my CI server will pick it up, build it, then deploy it to the web server. I can then go to http://post-nanoc-on-ipad.static-staging.ikennd.ac to view the results. It’s not quite a live preview since my blog is ~400Mb of content and the build server takes a minute or two to process it all, but it’s enough that I can write my blog post with Safari in split view with my editor, and I can reload occasionally to see how it’s going.

My Setup

The first thing we need to do is get a CI server to build our nanoc site. I won’t actually cover that directly here - there are lots of CI services available, many of them free. Since nanoc is a Ruby gem, you can set up a cheap/free Linux-based setup without too much fuss.

I’m using TeamCity running on a Mac mini, mostly because I already had that set up and running for other things. TeamCity has a pretty generous free plan, and I get on with how it operates pretty well.


TeamCity’s web UI on iPad isn’t quite perfect, but it functions just fine.

The second thing we need is a web server. Now, when I suggested the idea of serving content based directly on the domain name being used, a web developer friend of mine made a funny face and started talking about path sanitisation, so I spun up a new tiny Linode that does literally nothing but host these static pages for blog post previewing. I set up an Ubuntu machine running Apache for hosting.

Now for the fun part!

Linking It All Together

We’re going to be taking advantage of wildcard subdomains so we can preview different branches at the same time. For my personal blog it isn’t something I’ll use that often, but it’s handy to have and is definitely cooler than just having a single previewing destination that just shows whatever happens to be newest.

In your DNS service, add an A/AAAA record for both the subdomain you want to use as the “parent” for all this, and a wildcard subdomain. For example, I added static-staging and *.static-staging records to ikennd.ac and pointed them to my server.

Next, we want to make Apache serve content based on the entered domain. Manually (or even automatically) adding Apache configuration for each branch is too much like hard work, but we can use mod_vhost_alias to help out out. It’s not a default module in the Apache version I had, so a2enmod vhost_alias to enable it.

My configuration looks like this:

DocumentRoot /ikenndac/public_html/contentDirectory /ikenndac/public_html/content     Options None    AllowOverride None    Order allow,deny    Allow from all    Require all granted/DirectoryVirtualHost *:80     ServerAlias *.static-staging.ikennd.ac    VirtualDocumentRoot /ikenndac/public_html/content/%0/    ErrorLog /ikenndac/public_html/static-staging.ikennd.ac.error.log    CustomLog /ikenndac/public_html/static-staging.ikennd.ac.access.log combined/VirtualHost

That VirtualDocumentRoot line is the important part here. If I go to http://my-cool-blog.static-staging.ikennd.ac, thanks to that %0 in there, Apache will look for content in /ikenndac/public_html/content/my-cool-blog.static-staging.ikennd.ac.

Once this is set up and running, our web server is ready! The final part is to get the content from our CI build onto the web server in the right place.

nanoc has the deploy command, but as far as I can figure out, it doesn’t support dynamically setting the destination directory, so we can’t use that. Instead, my blog’s repository contains a script to do the work:

# Get the current branch nameBRANCH_NAME=`git rev-parse --abbrev-ref HEAD`# Replace anything that's not a number or letter with a hyphen.SANITIZED_BRANCH_NAME=`echo "${BRANCH_NAME}" | tr A-Z a-z | sed -e 's/[^a-zA-Z0-9\-]/-/g'`SANITIZED_BRANCH_NAME=`echo "${SANITIZED_BRANCH_NAME}" | sed 's/\(--*\)/-/g'`# Build the right directory name for our HTTP server configuration.DEPLOY_DIRECTORY_NAME="${SANITIZED_BRANCH_NAME}.static-staging.ikennd.ac"echo "Deploying ${BRANCH_NAME} to ${DEPLOY_DIRECTORY_NAME}…"# Use rsync to get the content onto the server.rsync -r --links --safe-links output/ "website_deployment@static-staging.ikennd.ac:/ikenndac/public_html/content/${DEPLOY_DIRECTORY_NAME}/"

A couple of notes about using rsync to deploy from CI:

Since CI runs headless, it’s unlikely you’ll be able to use a password to authenticate through rsync - you’ll need to set up SSH key authentication on your HTTP and CI servers. I won’t cover that here, but there are tutorials aplenty for this online.

If your CI still fails with auth errors after setting up SSH key authentication, it might be failing on a The authenticity of host … can’t be established prompt. If deploying to your HTTP server works from your machine but not in CI, SSH into your CI server and try to deploy from there.

Deploying the Final Result

The beauty of this process that that we’ve been deploying the entire time! If you follow git flow and your master branch only ever has finished content in it, you could point your main domain to the same directory that the CI server puts the master branch and you’re done! If your master branch isn’t that clean, you could make a new deployment branch and do the same there.

My “public” blog is hosted from a completely different machine than the one the CI publishes to, so that’s currently a manual step for me. However, it we be easy enough to modify my static-staging-deploy.sh script to rsync to a different place if it detects that it’s on the deployment branch.

Conclusion

Phew! This was a bit of a slog, but the outcome is pretty great. With everything connected together, I can work on my iPad and get a full-fat preview of my blog as I write. No “real” computer required (except the one running the CI server and the other one running the HTTP server)!


I kind of want a mouse…

It’s not perfect, of course. Like many “I can do real work on my iPad!” workflows, it’s a pile of hacks — but I’m at least part of that club now!

The real downside to this is the latency between pushing a change and it showing up online. This is mostly caused by my setup, though:

My CI server isn’t on a public-facing IP, which means GitHub webhooks can’t reach it. This means that the server has to poll for changes, adding quite a lot of time until the build actually starts.

It takes the CI server towards a minute to build my blog and deploy it to the HTTP server. The vast majority of this time is taken with processing all the photos and videos that have accumulated here over the years — splitting that out to a separate repository will significantly reduce the amount of time it takes.

All in all, though, I’m really happy with the outcome of this experiment. Real computers can suck it!

Apps Used To Write This Blog Post

I was pretty successful in writing this post on my iPad. I used the following apps:

Working Copy for text editing and git work.

Prompt for SSHing into my HTTP server to tweak some configuration.

Cascable for copying photos from my camera and light editing.

Affinity Photo for sizing photos down to the right dimensions for my blog.

Maybe next time I’ll even manage to do the Audioblog recording on my iPad!


February 2nd, 2019 Despair, Thy Name is App Store

I’m sitting here at 2am, the glow of my laptop screen illuminating my hands as I type. My wife is upstairs, worried about me but powerless to soothe my mind. She can’t sleep either.

Most of the time, it’s fine. It’s fun. I write an app and ship it to the world. I don’t make a huge amount of money from it, but topped up with a little bit of income from part-time consulting, I have a nice little business. I’m proud of it.

Sometimes, it’s not fun. The problem with running a small business is that you’re a tiny cog in multiple corporate machines. Not important enough to get noticed, but dependent enough on them that a tiny blip in their system can ruin you. The last time I was up at 2am, staring at my laptop with a worried wife upstairs was also because of Apple. That time it was App Review, or something. Probably something to do with subscriptions.

On Wednesday afternoon, I accidentally shipped the worst bug of my career. On Thursday morning, I fixed it, pushed an update to the App Store, and thankfully it got approved quickly.

Unfortunately, there’s currently a glitch in the App Store, and it’s still serving the broken version of my app to the world alongside the release notes and version metadata of the fixed one. “Fixed the crash!” it gleefully claims, cruelly delivering a very much unfixed binary. I’ve since uploaded a second update in the hopes that it’d get unstuck. No dice. The App Store is now serving a build from two versions ago alongside metadata from the current version.

There’s no way to call in to Developer Support that I can find any more, and the old numbers I have don’t work. The contact site is selling me the EU call centres have closed and won’t let me contact the US ones. None of them reopen until Monday now, anyway.

I’ve spent the entire day trying to fix this. An hour on the phone with EU Developer Support, who were trying to help but ultimately were powerless.

My only two options now are to let the fates decide when my problem gets fixed, or to completely remove my app from the App Store. Both options are bad. I can’t speak to anyone at Apple for well over 48 hours. Pulling the app makes it look like my business has disappeared and customer faith plummets. Leaving it up risks hitting that one user who’ll shout from the rooftops how you’re a scam artist and stealing people’s money.

When this tiny blip in the App Store’s CDN propagation goes away, I’ll forget about it soon enough. Hell, in the morning this post will probably seem melodramatic even to me, even if the problem is still ongoing. Especially if it’s resolved.

I’m writing this for the next time I’m sitting at my laptop at 2am, head in my hands, wondering why I’m gambling my livelihood and reputation on a company that takes 30% of my app’s sales and delivers, well… this.

This time it’ll be fine. The next time too, if I’m honest. But after that? I don’t know how many more times I can take this. Then again, this kind of stuff happening occasionally is pretty much par for the course in small business.

Sorry to complain. Stiff upper lip, and all that.


December 20th, 2018 Introducing the iKennd.ac Audioblog!

This post is included in the iKennd.ac Audioblog! Want to listen to this blog post? Subscribe to the audioblog in your favourite podcast app!

Apple Podcasts Overcast Castro Pocket Casts Direct Feed

For well over a year, I’ve been talking about doing a podcast. In fact, in late November 2017 I made a handshake promise with a friend that we’d both get the first episode of our podcasts out “by Christmas at the latest!”, so I’d already been going on ab-out it for far too long a year ago. (She hasn’t released hers either, so we did at least do the same thing!)

The thing is, I have lofty plans for my podcast. It’ll have guests, and a theme that runs through each episode. Hopefully, it’ll carve out its own unique little niche within the rather crowded genre of developer podcasts and will provide some genuine value and interest to its listeners.

The problem with starting a podcast with the goal of having guests, and a central theme, and its own unique little niche, and genuine value and interest… is that it’s a lot of work. Especially if it’s your first podcast. I did make some decent strides — I have the equipment, and I did some work on the first few episodes (even finding guests!).

However, I don’t want to waste my guests’ time by putting out shoddy work, and I want to to start out the gate with a great first episode… and, well, writing this now, I realise how unrealistic my own expectations were, which explains over a year of procrastination.

So, I hereby announce… I am not starting a podcast just yet. (Pause for applause.)

The thing is, I really love contributing to the community. Even though my blog has been relatively quiet for the past couple of years, I’ve been giving talks here and there. In September, I gave a talk at the Swift and Fika conference here in Stockholm entitled Adventures in API Design, in which I mixed some stories of what I’ve been up to over the past couple of years with some useful advice about designing APIs. More recently, I spoke at a CocoaHeads meeting about writing command-line apps with Swift Package Manager, in which I talked about drone photography and some tips and tricks for writing little command-line apps in Swift.

I don’t have any formal training in giving talks, but with each one of these I give, I get better. I still say the word “so” far too much, and I forget to breathe half the time so I end up out of breath, but I’m improving! And, importantly, I’m having a lot of fun! And, most importantly, people tell me they like my talks and get something useful from them.

I really want to get started with my awesome, guest-filled podcast. However, I need to learn and get better at it before I can.

So, I hereby announce… The iKennd.ac Audioblog (Pause for applause?)

In order to get comfortable with my equipment and being behind a mic, with audio editing, and the whole experience of hosting a podcast, I’m starting an audioblog. It’s like an audiobook, but a for a blog! For each post on this blog going forward, I’m going to try to make an audio counterpart that’s of a decent quality and engaging to listen to. I have a couple of really meaty posts planned for the next couple of months, so recording these should give some great practice for when Daniel’s Awesome, Guest-Filled Podcast1 comes along sometime in 2019.

In fact, this post is on the audioblog! Why not give it a listen? I’m genuinely interested in hearing any feedback on audio quality, how I sound, if I manage to make the listening experience engaging, and so on.

You can subscribe to the audioblog via links at the top of this post.

Title TBD. ↩


November 2nd, 2018 Why Publishing Some Nice Autumnal Photos Online Made Me Write An App

Don’t care about programming and just want to see some pretty photos of colourful trees? Check out Autumn From The Air on my new photos subsite. Enjoy!

A few months ago, I bought a drone with the idea of expanding the horizons of my photography hobby a little. I even had a dream photograph in mind - a rolling shot of my car driving along a mountain road. A few weeks later, I was standing on the side of a mountain road in the Alps, trying to take pictures of my car as my wife drove it up and down a section of mountain road.

As it turns out, taking a long exposure of moving object A with moving camera B while standing in stationary position C is incredibly difficult. Over a couple of sessions I took hundreds of photographs, and got four that I’m happy with.


This photograph took many, many tries to get.


This photograph did not.

This was amazing! I have a flying camera! It’s basically an infinitely adjustable tripod! I can even take rolling shots like this without hanging out of the back of a car!!


It’s just a fancy tripod, really.

Bureaucracy Strikes!

Excited about the possibilities of this magic new camera, I came home and started learning and experimenting, having a lot of fun in the process. However, here in Sweden the laws surrounding aerial photography are very strict — you’re not allowed to publish any aerial photographs without approval from Lantmäteriet, a Swedish agency dealing with land and property.

There’s a valid discussion on how sensible this law is for private drone usage, since it’s a law written in mind for imagery taken with planes and helicopters. Still, the law’s the law, and I had a great set of autumn photos I wanted to share. Lantmäteriet has an online form for this, which requires each image’s location, street address, and property allocation (which is looked up on Lantmäteriet’s own map).

This submission process is, quite frankly, a massive pain in the ass. It took me 45 minutes to build the submission for 24 photos - manually pasting the coordinate into Maps, doing an address lookup, then going to the Lantmäteriet map to perform the other lookup there, scrolling and clicking around the map because you can’t give it WGS841 coordinates.


Zzzzzzz…

Like Everything, This Can Be Solved With Software!

I finished my submission, then immediately got to work automating this, because screw doing that again.

The most complicated part of the process is converting the WGS84 coordinates in my images’ geotags into the SWEREF coordinate system that Lantmäteriet uses. It turns out that doing this well is hard, and I found some existing code to port over - it’s several hundred lines!

After a few evenings of hacking, my 45 minutes of manually looking up things on two different maps can be reduced to typing this into my terminal:

$ lantmateriet-lookup -i *.jpg -html results.html

…then waiting 30 seconds while it does its magic. Lovely! Under the hood, it’s:

Extracting a geotag from each image using ImageIO. Using CoreLocation to do a reverse geocode to get an address. Converting the WGS84 geotag coordinate into SWEREF. Doing a lookup on what is definitely a public Lantmäteriet API to get the property allocation. Writing the results of all that into a table for submission to Lantmäteriet.

This is going to save a bunch of time for anyone that takes photos with a drone in Sweden, so I’ve made it open-source - you can find it here: lantmateriet-lookup on GitHub.

…I Was Promised Autumn Photos?

While I was faffing about with all of this, Lantmäteriet approved my original submission. Hooray!


The slow currents of Mälaren disturb mud around an underwater rock.

I put together a photo story of my favourite aerial photos of the area around where I live, which you can find over on my new photos subsite: Autumn From The Air. Enjoy!

WGS84 is the coordinate system used by GPS and many other mapping and navigation systems. If you see a GPS or map coordinate as you’re going about your business, it’s very likely that it’s a WGS84 coordinate. ↩


April 6th, 2018 App Store Subscriptions And You

For the average iOS developer, implementing App Store subscriptions is easily the most legalese-filled part of the entire process of making an app and shipping it to the world.

What makes this more difficult is that right now, App Store subscriptions for “normal” apps (i.e., those that aren’t content services like magazines or Netflix) are reasonably new, and Apple appears to be finessing the rules over time. This can cause a frustrating situation as you try to do your best but end up getting repeated rejections due to your app not meeting the rules.

At the time of writing, I’ve been shipping an app that uses subscriptions for eight months, and have had multiple subscription-related rejections happen between my first release and now due to changing rules and changing enforcement of existing rules. The information in this post is a combination of my experience, as well as conversations with App Review both via email and phone. Hopefully the additional context provided by speaking to a human being from App Review on the phone will be as helpful to you as it was for me.

Important: This post was as correct as I could make it at the time of writing (early April 2018). The App Store review guidelines are a constantly changing thing, particularly in the area of subscriptions. You must do your own due diligence.

The Paid Applications Contract

A lot of the confusion from this stems from the fact that half of the rules for subscriptions aren’t in the App Store Review Guidelines, but are instead located inside your Paid Applications Contract. You can find this in the Agreements, Tax, and Banking section of iTunes Connect.

Assuming that you have the standard contract, in-app subscription terms can be found in section 3.8.

Important: Your ability to sell apps on the App Store depends on your adherence to and understanding of this contract. Since this is a legal document, I will not be able to help you with it. This post is intended to be a guideline only, and I can’t be held responsible if you encounter problems following it. If you have questions or problems with this contract, consult a lawyer.

What We’re Building

This is a screenshot of my app’s store. It provides users the option of buying a one-off In-App Purchase or one of two subscription options. This store page was approved by App Review in early April 2018.

As well as getting the in-app UI correct, you must also include details of your subscriptions in your app’s App Store description. We cover this towards the end of the post.

You Must Be Clear About Pricing And Billing Frequency

You must be very clear about several things:

That the user will be paying for a recurring subscription. How much the user will pay each time. How often they will pay. The pricing must be in the user’s App Store currency.

You’ll see in my screenshots that my device is set to English, but I’m being presented prices in Swedish krona (SEK). This because I live in Sweden (so my cards are all in SEK) but I’m bad at Swedish, so my iPhone is set to English. You can’t use the system locale for In-App Purchase pricing - instead, the SKProduct objects you get in the App Store will contain the locale you should use for displaying prices.

A common thing to do is to offer multiple subscription options, giving the user better value for money if they commit to a longer subscription period. This is fine, but you must list the actual amount that will be charged in your pricing.


While this is good at showing the increased value of the longer subscription, exactly how much money is charged when is unclear. This is not allowed.


How much money is charged when is much clearer here. This is allowed.

You Must Be Clear About Trials

If you offer a free trial, you need to be clear about that as well.

Important: If the user takes up a subscription with a free trial then later cancels, if they want to re-subscribe they will not get a second free trial. You must reflect this in your UI so you don’t end up promising a free trial that the user won’t get.

One way to do this is to fully parse your application’s receipt — each subscription period will have an entry in the receipt. If you have one or more entries for your subscription’s identifier and all of them have expired, the user had a subscription in the past and won’t receive a free trial if they re-subscribe.


The user is eligible for a free trial, so we make it clear that they’ll get a free trial and then they’ll be charged.


If the user is not eligible for a trial, we don’t mention it at all.

You Must Include The Correct Legalese

This is the one that seems to cause the most problems, since legalese is hard and there’s a lot of it.

It’s very important to Apple that it’s impossible for the user to buy a subscription without seeing the legalese. This means that you can’t hide it behind a “Subscription Terms” button - this would be a fork in the flow, and is not allowed.

An exception to this is that you are allowed to have the legalese scroll off the bottom of the screen, as long as it is completely clear that there’s more content to read, and that you’re not hiding all of the legalese “below the fold”.


Here, the legalese is entirely hidden off the bottom of the screen. Even though the user can scroll to it, this is not allowed.


Here, it's very clear that there's legalese to read, and that you can scroll to read more. This is allowed.

You must also include a link to your website’s Terms Conditions, as well as your Privacy Policy, alongside your buy buttons and legalese. It is allowed to have these be one page.

You can find the legalese you need to include in section 3.8b of your Paid Applications Contract. It can be a little confusing since the language is still very much aimed at magazines in places, but you should write language that makes sense for your app rather than just copy and pasting. Don’t be too put off - it’s possible to be very efficient with words and include everything without too much text.


Here we can see my store page on an iPhone X, which is big enough to display everything without scrolling. The legalese paragraphs and Terms/Privacy buttons are visible here.

At the time of writing, the standard contract requires that we state the following information to users.

Important: This was correct in my contract at the time of writing (early April 2018). You must check your own contract!

Title of publication or service

The name of your app or subscription. Ours is Cascable Pro.

Length of subscription

In my examples here, this is in the subtitle of the buy buttons.

Price of subscription

Also in the subtitle of the buy buttons.

Payment will be charged to iTunes Account at confirmation of purchase

Covered in the first paragraph of my legalese.

Subscription automatically renews unless auto-renew is turned off at least 24-hours before the end of the current period

Covered in the first paragraph of my legalese.

Account will be charged for renewal within 24-hours prior to the end of the current period, and identify the cost of the renewal

Covered in the first paragraph of my legalese.

Subscriptions may be managed by the user and auto-renewal may be turned off by going to the user’s Account Settings after purchase

Covered in the first paragraph of my legalese.

Links to Your Privacy Policy and Terms of Use

Green button at the bottom of my legalese.

Any unused portion of a free trial period, if offered, will be forfeited when the user purchases a subscription to that publication, where applicable

This one is a little confusing at first, since the language seems geared towards magazines and in most apps it’s impossible to buy something that would render an active subscription invalid. However, after speaking to App Review, I was advised that even if it didn’t completely make sense for normal use of my app, I should include it unless I had very strong opinions about it not being there — at which point they’d have to have internal discussions about what to do. I feel like “internal discussions” means “a very long wait”, so I was eager to avoid this.

Since it is technically possible to buy two Cascable Pro products at once if you really try hard1, I wrote the second paragraph of my legalese with this in mind.

You Must Also Include Subscription Details In Your App Store Description

When submitting your app to the App Store, you must also detail your subscriptions in the same manner as in the app, including:

A list of the subscriptions, including their durations and prices. The same legalese as you put on your in-app store page. A link to your Terms Conditions and Privacy Policy pages.

Since your app’s description is static content, the rules are a little more lax regarding the prices. So far, I’ve been fine listing the “normal” prices of the subscriptions in US dollars in all languages. You should still be able to run promotions etc without updating the price in your app description.

Good luck!

Install the free version of Cascable on two devices with the same Apple ID. Purchase a subscription on the first device, then purchase a different subscription on the second without doing a “Restore Purchases”. Tada! Two subscriptions. ↩


January 16th, 2017 Excuse Me Sir, But Can I Rattle Your MacBooks?

Back in 2001 I had a G4 Cube that I loved dearly, and a then state-of-the-art iPod that plugged into one of its two Firewire ports. Unfortunately, that Cube loved to fry its Firewire ports — several trips to the repair centre meant walking miles to my friend’s house so I could rip my CDs to his second-generation iMac and then onto my iPod.

Since then, I’ve had great luck with Apple products. Apart from a PowerMac G5 that couldn’t survive having Coke poured into it and the odd iPhone that didn’t like being smashed into the ground, I’ve had 15 years of mostly trouble-free experience with Apple hardware.

Unfortunately, this has come to an end with the 2016 MacBook Pro. Now, I’m not normally one to complain about stuff on my blog, but I feel the journey I’m still undergoing with this machine is kind of fascinating — and an interesting insight into what happens when good customer service and poor products clash. Also, this is by far the worst experience I’ve had with Apple hardware in my life.

MacBook Pro #1 #2: A Normal DoA Experience

In December, my wife borrowed my MacBook Pro for something and called to me: “Did it always make this noise?”, demonstrating a metallic, springy-sounding noise when she placed it onto a table. We shall call this metallic, springy-sounding noise Rattle A, which will be important later.

No, it did not.

A call to Apple later and a new MacBook Pro (MBP #2) is being assembled and shipped to me. Great! Unfortunately, since I ordered a machine with a custom spec, it’s coming all the way from China. At the moment, it’s no big deal — the occasional DoA product is part of life.


MBP #1’s rattle.

A couple of weeks later, the new machine arrived at my door. I unbox it, and give it a little side-to-side shake. Immediately out of the box, it makes a plasticky clonking sound which you can feel through your hands. We shall call this plasticky clonking sound Rattle B.

After some bitching on Twitter, another call to Apple and about 45 minutes on hold gets me put through to some senior department. Very sorry for my bad luck, a second replacement (MBP #3) is being assembled and shipped to me, again from China. The agent agreed that it’d be silly to transfer my data to MBP #2 when MBP #3 is on its way, so a return for MBP #2 is arranged. The next day, it leaves my house.


MBP #2’s rattle.

MacBook Pro #3: Excuse Me Sir, But Can I Rattle Your MacBooks?

This is where it starts to get a bit abnormal.

MBP #3 turns up, and immediately out of the box it exhibits Rattle B. I call Apple again, and eventually get to a nice lady in after-sales who’s very sympathetic to my bad luck, and is adamant that they’ll keep sending me MacBook Pros until I get one that doesn’t rattle.

However, I’ve been doing some of my own research and I’m starting to think that Rattle B is a systemic problem. I explain my (entirely anecdotal) thinking and we come up with a plan: I’ll go to the Apple Store and see if any machines on display there exhibit the same problem. If not, I’m just having terrible luck, right?

So, at opening time on Saturday morning I walk into the Apple Store and try to explain to the employees there that:

I want to shake their MacBook Pros. I’m not crazy.

After surprisingly little convincing, they let me go ahead. In the eight MacBook Pros I tried, two of them exhibited Rattle B.


A rattling MacBook Pro at the Apple Store.

I return home resigned to having a MacBook Pro with Rattle B. Annoying, but I don’t tend to shake my MacBook Pro much, so it’s not a huge issue to live with. I take the machine out of the box, unwrap the plastic and set it down on the table.

Clank.

Praying that I’m hallucinating, I pick it up and set it down again.

Clank.

MBP #3 exhibits both Rattle A and Rattle B. Superb. Time for a Twitter rant.


MBP #3’s rattle.

MacBook Pro #4: Maybe I Am Crazy!

At 10am this morning, the phone rings with the promised callback from the lady I spoke to on Friday.

After explaining my results at the Apple Store and the fact MBP #3 is the worst one so far, we come up with another plan, and we see what happens when your customer service greatly outclasses the quality of your product:

MBP #4 is being assembled and shipped, again from China. However, this time it’s being shipped to the Apple Store, where I can inspect it and hand it straight off for repair if it continues to show these problems.

I’d like to repeat that last part, for emphasis: An agreed plan with customer service is for the product to be shipped to a store with the expectation that it’ll immediately go in for repair.

What Next?

If this were almost any other company (or if I were new to Apple), I’d have given up at MBP #2. However, Apple have 15 years of good experience in the bank, as well as very good customer service trying their hardest to make this current issue right.

However, all that goodwill is goneMBP #4 will be their last chance. The Apple Store is a 1hr 30min round trip from my home, something I’ll probably have to do twice — once to find out MBP #4 rattles too, and again to collect it after it’s been repaired.

Here’s a timeline, for brevity:

2016-12-17First call to Apple about MBP #1.2017-01-02MBP #2 arrives.2017-01-02Call to Apple about MBP #2.2017-01-04MBP #2 is collected for return to Apple, MBP #3 is ordered. 2017-01-09MBP #3 leaves China.2017-01-13MBP #3 arrives.2017-01-14"Excuse me, but can I rattle your MacBooks?" at the Apple Store.2017-01-16Call Apple, MBP #4 is ordered for delivery to the Apple Store.

Some reaction I’ve received on Twitter is questioning why I care so much about a rattle. This machine cost 32,595 SEK (~$3,650 USD, ~£2,990 GBP, ~€3,400 EUR), and for that ludicrous amount of money, I expect a computer with all of its components attached together properly. I don’t think that’s unfair, and so far Apple customer support agrees with me.

The interesting question comes if MBP #4 still rattles. While I’m fortunate that this machine isn’t (yet) my primary computer, I have a business to run and unfortunately I’m a Mac and iOS developer, which basically requires that I own a Mac. I really want this MacBook Pro to replace my iMac so I can have a more portable work machine, but if Apple can’t sell me a computer I’m happy with — what then?

In the words of the greats: I’m not angry, I’m just disappointed. Maybe I should develop for Windows Phone instead.


October 28th, 2016 Launching Cascable 2.0

Cascable is the app I’ve been working on since early 2013 — firstly as a side project, then as a full-time endeavour starting mid-2015. You can read more about this journey in my Secret Diary of a Side Project series of posts, the first one of which can be found here.

“It won’t be as stressful as the 1.0 release”, I lied to my myself as much as my wife when she asked me how I was feeling about launching Cascable 2.0 the next day. I’d woken up a couple of times during the night in the past couple of weeks gnashing my teeth, causing a big chip in one of my teeth.

The truth is, the 2.0 launch ended up being much more stressful than 1.0, although I genuinely didn’t see it coming. Cascable 1.0 was a product of a side project — it shipped a few months after I quit Spotify, and a lot of that post-Spotify time was working on ancillary details like the website, marketing, documentation, and so on.

Getting to 2.0

Version 2.0 shipped on August 11th, 2016 and was the result of nine solid months of work, starting in October 2015 with this tweet:

Nine months is a very long time to be working on a single update, and it can be really damaging to your self esteem, particularly when working alone. Roughly 300 tickets were solved between starting 2.0 and shipping it. That’s 300 issues. 300 things wrong with my code. 300 times myself or someone else had opened up JIRA and created a ticket to describe something was missing or broken with my code.

Of course, this is part and parcel of being a developer. However, you typically have other developers working alongside you to share the burden and a reasonable release cadence that (hopefully) provides real-world evidence that your work is good enough for production.

In the weeks before the launch, I didn’t feel stressed at all — we’d had a very long TestFlight period with over 100 testers over all the different camera brands Cascable now supports and all of the major issues were ironed out. I’d enforced a feature-freeze at the beginning of June, and a ship-to-App Store date of July 29th. That’s two months in feature freeze and two weeks between uploading to the App Store and releasing — plenty of time to iron out any issues before shipping, and plenty up time to iron out any App Store problems before releasing.

Plus, this time I had help in the form of Tim, who’d been diligently working away at the website for weeks — this time, it was finished by the time I’d hit code freeze and better than ever - much more content and some lovely extras like a nicely made video.

Everything should be wonderful, right? Lots of time to iron out bugs, help with shipping and over 100 people using the app for a few months should make this launch something to be excited about.

However, those nine months of JIRA tickets had taken their toll. My self-confidence was incredibly low, and I was scared to death that we’d launch and some stupid mistake I’d made would cause the app to crash for everyone, ruining the app’s (and my) credibility. Cascable would be a laughing stock, and I’d have to go find a real job again.

On top of this, with 2.0 Cascable would be transitioning from paid-up-front to free with In-App Purchases to unlock the good stuff. It’s a move we needed to make — a $25 up-front payment is an impossible sell on mobile — but a huge risk of doing this (and well-known enough that it was the first thing every developer friend I have mentioned when I told them of this plan) is receiving a massive amount of support email from free users and unfair one-star reviews.

“You realise that you’ll immediately get people downloading it without looking then leaving you one-star reviews because it isn’t Instagram right?”, said one.

As the Cascable launch approached, my belief in my own abilities was at an all-time low, and I was expecting to be buried in an avalanche of one-star reviews and email.

Launch Day

Launch day came, and the app was sitting in iTunes Connect, waiting for me to click the “Release” button. An attempt at having it happen automatically was stymied by a problem with iTunes Connect that resulted in hours on the phone with iTunes Connect support, which ended up making the problem worse. In the end, I had to yank the previous version from sale a few days before 2.0’s launch. D’oh!


This is not the history of a smooth release process!

I clicked the “Release” button, and braced myself for a horrible week.