Here's my five latest blog posts - or you can browse a complete archive of all my posts since 2008.

Speaking and Playing at GOTO Oslo 2020

You’ve all heard the phrase ‘real developers ship’ – but have you ever been on a real developers’ ship? I’m really excited to be speaking at GOTO Oslo 2020 – the conference that’s taking place on a ship! We’ll kick off on board the MS Crown Seaways in Copenhagen on Tuesday morning. At 4pm, there’s a break in the schedule while we set sail for Oslo. We arrive in Oslo on Wednesday morning, for another full day of conference sessions and masterclasses - and at 4pm we set sail back to Copenhagen. I’ll be presenting The Art of Code on Wednesday evening, and then joining The Linebreakers on stage for a live set of classic rock tunes with a software twist.

Early bird tickets are on sale until February 1st from - it should be a really great event and I’d love to see you there.

"Speaking and Playing at GOTO Oslo 2020" was posted by Dylan Beattie on 17 January 2020 • permalink

Shaving the Jekyll Yak

UPDATE: Thanks to the amazing power of Detective Twitter, I think we figured out what’s going on…

I use Jekyll and Github Pages for pretty much all my standalone websites these days, and I love it – the combination of static HTML, Markdown and YAML provides just enough data-driven behaviour to avoid lots of unnecessary duplication, but without any of the costs or overheads of running databases and server-side processing.

Until today. Today, dear reader, I hit a bump. And it starts, like so many things, at the pub. At PubConf, to be more exact. Todd Gardner is taking a bit of a break from travel in 2020, so I’m going to be running PubConf London at the end of January – which means I get commit access to (yay!) for the next two months. It’s built using Jekyll and hosted on Github Pages, and I’ve had a local version of the PubConf website running on my Macbook for the last 4-5 months without any hassles… except last week, I repaved my Macbook with a clean install of macOS Catalina. And apart from a couple of weird quirks that I’ve managed to isolate, it’s all good – including all my other Jekyll sites.

So I grab a fresh clone of the PubConf source tree, do the bundle install / bundle exec jekyll serve invocation, and… boom. $ bundle exec jekyll serve
Configuration file: /Users/dylanbeattie/Projects/
NOTE: Inheriting Faraday::Error::ClientError is deprecated; use Faraday::ClientError instead. It will be removed in or after version 1.0
Faraday::Error::ClientError.inherited called from /Library/Ruby/Gems/2.6.0/gems/octokit-4.14.0/lib/octokit/middleware/follow_redirects.rb:14.
            Source: /Users/dylanbeattie/Projects/
       Destination: /Users/dylanbeattie/Projects/
 Incremental build: disabled. Enable with --incremental
jekyll 3.8.5 | Error:  wrong number of arguments (given 2, expected 1)

That’s not good. And I hadn’t even changed anything yet. So… here begins a protracted bout of yak-shaving.

First thought: perhaps macOS Catalina uses a different default version of Ruby, that’s no longer compatible with this particular Jekyll configuration. So I spend an hour or so installing rbenv, the version manager that lets you run different Rubies side-by-side. No luck – 2.4.5, 2.4.9 and the default 2.6.3 all produce the same result.

I Google the error message. Now, what I’m looking for here is something that’s recent – looks like various folks have had this error message over the years, but I’m trying to work out what might have changed with that stack recently that could be causing this error to start happening. I find this, which looks pretty promising, including this comment from 15 October:

I believe this is actually an issue with a change in sprockets 4.0.0:

I’ve never heard of Sprockets, but according to the internet “Sprockets is a Ruby library for compiling and serving web assets.” Now, there are two things here which I think are interesting:

  1. The code for uses a plugin called jekyll-assets – which I don’t use on any of my other Jekyll sites.
  2. jekyll-assets relies on Sprockets.
  3. Sprockets released version 4.0.0 on October 8th.

At this point, I remember another detail that might be interesting: the PubConf site is built using TravisCI, which means there’s a separate build pipeline I can look at that’s nothing to do with my laptop. Now, here’s where it gets really interesting. I ran a fresh build on TravisCI, using the exact same source tree that built cleanly on November 8th -and boom. Failing build. But, interestingly, it failed with a different error message:

Configuration file: /home/travis/build/PubConf/
NOTE: Inheriting Faraday::Error::ClientError is deprecated; use Faraday::ClientError instead. It will be removed in or after version 1.0
Faraday::Error::ClientError.inherited called from /home/travis/build/PubConf/
            Source: /home/travis/build/PubConf/
       Destination: /home/travis/build/PubConf/
 Incremental build: disabled. Enable with --incremental
  Liquid Exception: Liquid syntax error (/home/travis/build/PubConf/ line 111): Unknown tag 'stylesheet' included in /_layouts/default.html
jekyll 3.8.5 | Error:  Liquid syntax error (/home/travis/build/PubConf/ line 111): Unknown tag 'stylesheet' included 
The command "./_tools/build" exited with 1.

OK, so let’s take a closer look at what happens if I lock my local Ruby for this project to 2.4.5, the same version that’s used on TravisCI: $ rbenv local 2.4.5 $ ruby --version $ ruby 2.4.5p335 (2018-10-18 revision 65137) [x86_64-darwin19] $ rm Gemfile.lock $ gem install jekyll $ gem install bundler $ bundle $ bundle exec jekyll serve

Now, it still didn’t work – but check this out: I’m now getting the same error locally as I get on TravisCI:

Liquid Exception: Liquid syntax error (/Users/dylanbeattie/Projects/ line 111): Unknown tag 'stylesheet' included in /_layouts/default.html
jekyll 3.8.5 | Error:  Liquid syntax error (/Users/dylanbeattie/Projects/ line 111): Unknown tag 'stylesheet' included 

This is progress! Because if my local system fails the same way as TravisCI does, then it stands to reason if I can get it working locally, the same fix will work on the Travis setup.

So… what the hell does Unknown tag 'stylesheet' included mean? Well, like before, there’s a bunch of search results for this, but none of them suggest anything that’s changed within the last few months.

But I did find this issue on the jekyll-assets Github repository, which includes this comment from envygeeks:

Our website is an unreliable source of documentation (right now, I’m working on adding that to my pipeline.. it’ll be a few weeks yet.) Yes, every tag but {% asset %} has been removed. As for the GitHub-pages issue, this issue belongs to them, we’ve not changed anything by way of integration with Jekyll, other than how we hook in, we have people who happily use Jekyll-Assets 3.x with Github Pages and have no problems.

The smoking gun here:

Yes, every tag but {% asset %} has been removed.

Now, this comment is from January 2018. Which suggests that the {% stylesheet %} tag that’s used in the PubConf code templates has been deprecated since the release of jekyll-assets v3.0.0, in November 2017.

Now this is seriously weird. Sure, it explains what’s broken, and the fix is easy – add gem "jekyll-assets", "~> 2.3.2" to the group: jekyll_plugins do section in the project’s Gemfile – but doesn’t give us any clues at all as to why this didn’t break until now. Because as far as I can tell, on 8th November 2019 – just over a month ago – TravisCI was quite happily running that build and ending with jekyll-assets version 2.something and everything just worked. Despite the fact it, apparently, should have stopped working on November 2017, two years earlier, when the first 3.x version of jekyll-assets was shipped.

So, the sprockets thing was a rabbit hole, it’s nothing to do with macOS Catalina, and chatting with Todd, turns out he’s got another site with an identical configuration, on a freshly-paved laptop, that’s pulling down jekyll-assets 2.4.0 without having to specify a version.

If anybody has any bright ideas as to what’s going on, I’d be really curious to hear them. But, as happens so often in the wonderful world of modern web development, I got better things to do than try to figure out what caused the weird impossible bug that’s not only now fixed, but according to all the available evidence should never even have happened in the first place…


One of the best reasons I’ve found for writing blog posts like this is that you get a lot more eyeballs on the problem than just your own – and thanks to some sterling work by @shiftkey, we figured it out. Or at least came up with a pretty plausible explanation.

Travis CI has a 28-day bundler cache, which means if you run a build within 28 days of the previous build, it’ll reuse the same set of dependencies. And it’s been a busy few years for PubConf, with events taking place frequently enough that it’s entirely possible this is the first time since 2017 that 28 days has passed without somebody or something kicking off a Travis CI build. So when I kicked off that build yesterday, that was the first time in literally years that Travis has built the whole project from scratch – and so picked up v3.x of the jekyll-assets plugin.

But really, what’s at the root of all this grief is our old friend, the leaky abstraction. Jekyll and Github Pages offer a really simple, elegant solution for creating static websites – and most of the time, you can just run the handful of commands in the documentation, write your Markdown, git push it and everything works. You don’t have to know about Ruby versions and bundler and Gemfile.lock – all that stuff is supposed to be abstracted away so you can focus on writing content. And it all works great, right up until it doesn’t. We could probably have avoided this problem by locking the plugin to a specific version, or by committing Gemfile.lock to revision control – but there’s drawbacks to both of those approaches, and neither of them warrants any mention in the documentation for Jekyll or for the jekyll-assets plugin.

The other problem with abstractions is that the more complexity they’re hiding, the harder it is to figure out what’s going on when something stops working. Remember, this thing started out as:

jekyll 3.8.5 | Error:  wrong number of arguments (given 2, expected 1)

when the actual thing that went wrong was something closer to:

jekyll 3.8.5 | Error: you haven't run a fresh build in over two years and we've just picked up a major release of the jekyll-assets plugin that hasn't been used in this project before, and which is no longer compatible with the syntax that's used in your website templates. You'll either need to update your templates so you're using the new asset tags required by jekyll-assets 3.x, or modify your _config.yml to specify that you need version 2.x of the jekyll-assets plugin.
"Shaving the Jekyll Yak" was posted by Dylan Beattie on 12 December 2019 • permalink

NDC Meetups in Portugal in January

I’m going to be heading out to Portugal in January to speak at some free meetups – if you’re in Lisbon or Porto and want to kick off 2020 with some cool tech events, come along! I’m gonna be in Porto on January 7th and Lisbon on January 8th talking about the secrets to happy code. It’s a talk that covers a whole range of ideas, from psychology and neurochemistry to user experience design, logging and monitoring, and how we developers can use those ideas to ship better software and create happier teams. Plus pizza, drinks, awesome people and plenty of time to chat.

Thanks to NDC Conferences for putting the whole thing together, and to Farfetch for hosting. And if you like the sound of this, you should check out NDC Porto – two days of workshops and two days of conferences with a fantastic lineup of international speakers, all set in one of the most beautiful cities I’ve ever visited.

The January meetups are free, but you’ll need to register if you’re coming along:

And if anyone wants to join me for francesinhas after the Porto meetup, I’m definitely up for that. :)

"NDC Meetups in Portugal in January" was posted by Dylan Beattie on 11 December 2019 • permalink

Better Meetings with Agenda Defender

Have you ever been to one of those meetings that has an agenda something like this?

13:00 Update from CEO (5 mins)
13:10 Update from CFO (5 mins)
13:20 Update on the Singapore project (Alex)
13:30 Update on the OAuth2 project (Chris)
13:45 Any other business
13:55 FINISH

Everyone arrives on time, you kick off at 13:00 as scheduled… but then after twenty minutes, the CEO is still talking, the agenda has been completely forgotten, and you’re all trying to work out whether they’re going to just skip everyone else’s updates so they can wrap up at 2pm as scheduled, or the one-hour meeting is just going to drag on and on until it’s taken up most of the afternoon and that’s the day wiped out?

I have. And, yes, on a handful of occasions I’ve been the person doing the talking – sorry! But sticking to an agenda when you’re talking is hard – like a lot of so-called “soft skills”, participating in meetings effectively is way harder than most people think. Being able to plan and deliver a five-minute update in five minutes, or a half-hour presentation in exactly half an hour, is a skill that takes time and effort to improve.

So I built a thing that can help. It’s called Agenda Defender, it’s at, and it can help you and your team keep your meetings on schedule.

First, type (or paste) your agenda. Local times, 24-hour clock, one line per item, with the finish time as the last entry.

Agenda Defender: schedule view

Click “Let’s go!” and it’ll turn each agenda item into a live progress bar. And that’s it.

Agenda Defender: live view

Sure, one little web app probably isn’t going to fix dysfunctional communication styles overnight – if you work somewhere where long rambling meetings that wander all over the place are a regular occurrence, introducing something like this might come as a bit of a shock. First few times you try it, you’ll get some resistance – especially from those people who think having a slot on the agenda means they can talk for as long as they want. But if we’re going to improve, we really need two things – feedback, so we know what we’re doing wrong, and incentive, so we have a reason to pay attention to the feedback. And once you’ve tried running meetings with Agenda Defender a few times, folks will get the hang of it – the live schedule will make it easier to pace yourself when you’re speaking, and the fact everybody can see who’s hitting their scheduled slots gives everybody an incentive to keep things on track. And if you do need to reschedule, or shuffle things around mid-meeting, no problem – just edit the agenda and start again.

Tired of meetings that should have been an email? Fed up with delivering features that you thought were perfect, only to hear “um… that’s not quite what we wanted”? Wasting time on writing documentation nobody’s ever going to read? Check out my Communication for Developers workshop, and find out how I can help you and your organisation build the right thing, faster, and go home smiling when you’re done.

"Better Meetings with Agenda Defender" was posted by Dylan Beattie on 02 December 2019 • permalink

About That Announcement

Remember: everything on this site, including this post, is my personal opinion, and does not reflect any official position of either Skills Matter or of the London .NET User Group.

A screenshot of the website announcing their plans to charge members a $2 fee to register for events, 15 October 2019

The online community platform (hereafter known simply as Meetup) has just announced that “beginning in October, members of selected groups will be charged a small fee to reserve their spot at events”. ( link) From the phrasing of their announcement, it sounds like Meetup will be charging people a $2 fee to register to attend an event – even if the event is free – and that 100% of that revenue will go to Meetup and none of it is passed on to the event organisers.

I’ve organised a .NET meetup group in London since 2016. Since 2018, I’ve also been CTO at Skills Matter, a company based in London that hosts hundreds of free meetups and tech events every year. That’s given me some fairly unique insights into the relationship between the Meetup platform, the people who organise and attend free community events, and the logistics behind running a free event.

Meetup is an odd platform. It’s a lowest common denominator, that’s used by songwriting clubs, running groups, coffee mornings and book clubs, as well as the tech meetups that we all know and love. And over the last few years, they’ve made changes to that platform that’s made it harder to run a tech meetup on their platform. For example, they’ve deprecated their rich text editor in favour of a minimal plain-text interface that makes it much more difficult to include speaker biographies and photographs in an event description.

Many people also aren’t aware that group organisers have no access to our group members’ contact information. They provide tools that let us contact attendees by email, but there’s no way to download a list of members’ email addresses. And it costs. The London .NET User Group is part of the .NET Foundation, which means they pay our subscription costs, but even running free events on their platform costs $19.99 per group, per month.

As a technology platform, it’s not great. It has mediocre usability and a very limited feature set. We can’t share slides or videos. There’s no way to share feedback with our speakers. There’s no facility for attendees to share their dietary requirements. There’s no sort of statistical modelling or forecasting to give organisers some idea of how many people will actually show up – I know of people in the LDNUG group on Meetup who have RSVPed ‘yes’ to every single event since 2016 and have never actually showed up to one, but it will still quite happily list them as ‘attending’ every single time, so good luck figuring out how much beer and pizza you’re going to need on the night. Patricia Aas very neatly summarised it thus:

But we still run London .NET on Meetup, and here’s why. When I announce one of our events on Meetup, I know I’ll get 50-100 RSVPs within 48 hours. If it’s a well-known speaker, I’ll get more like 200. And around 20% of those RSVPs will be complete strangers – people who have never been to one of our events before, who aren’t on any of our Slack chats or following us on Twitter. The only way those people even know that our event is even happening is that they found it on Meetup – and Meetup is so dominant in this space that if your event’s not on Meetup, it may as well not exist.

The recent announcement here about charging attendees to register is interesting. Now, $2 is not a big deal for tech events – here in London that’s significantly less than a cup of coffee. And I wouldn’t be surprised if it’s part of some long-term strategy by Meetup to pivot to a subscription model by jacking the prices up now, and then offering a subscription model in a few months time that looks very reasonable by comparison (“Hey, check out Meetup Unlimited – only $5/month to register for as many events as you want!”). After all, Meetup is owned by WeWork, who are losing vast amounts of money right now and probably desperate for revenue; I suspect if you took a look at their business plan, free meetup attendees are listed under ‘stuff that doesn’t make enough money’. There’s a great write-up by Quincy Larson, the founder of, about this as well.

But the impact of that change, from free to $2, is far more psychological than financial – and that’s why it might be a game-changer. The announcement has already inspired people around the world to start working on their own version of Meetup – I’m on a Discord channel right now where the FreeCodeCamp folks are coordinating one such solution, and over 100 people have joined that channel in the time it’s taken to write this post. Only time will tell whether this is a flash in the pan or genuine critical mass, but their solution is called Chapter, it’s over at, and it’s definitely worth keeping an eye on.

Now, I love the way the tech community rallies like this around an opportunity – but we really don’t need a dozen different open-source codebases hosted on hundreds of isolated websites, each of them running a handful of local groups. And when you get into mobile apps, where you can’t just spin up a Docker container and import your data, the fragmentation problem is even more pronounced. The problem that Meetup solves is not a hard technical problem. It’s a social problem. If people can’t find your group, nobody’s going to come to your event.

That’s not a problem you can solve with database schemas and JavaScript frameworks. Sure, tech plays a role here – but if there’s one thing we can all learn from Meetup, it’s that mindshare and user adoption are way more important than features and design when it comes to growing user groups, events and communities. People will put up with poor usability and terrible design if it connects them to the right people – and if it doesn’t, there’s no amount of shiny technology and beautiful UX that’s going to make up for it.

I’ll be really interested to see what happens next.

"About That Announcement" was posted by Dylan Beattie on 15 October 2019 • permalink