~mrlee/www.leemeichin.com

96c174086a4170b16cff18d6902d9fd65be8c6d2 — Lee Meichin 16 days ago 047145e
Emphasis to italics
M posts/a-damn-good-listen.org => posts/a-damn-good-listen.org +1 -1
@@ 20,7 20,7 @@ Seriously though, I'm the sort of person who genuinely enjoys hearing people out

So many problems we have as individual people exist and grow out of proportion because the space or audience required to express those feelings was never up for offer. Raw emotions are dismissed, ignored, and twisted away from their original intent all the time, and all that arises from it is frustration, resentment, and in the worst case, the realisation of emotional abuse.

For example, I was first diagnosed as clinically depressed back in 2010 after breaking up with my ex-girlfriend at the time. I lost her, and the dog who'd been with me for most of my ◊em{entire life}, since I was maybe 2 years old, died at the age of 21. That's crazy for a dog, but the loss hurt like nothing else. And my grandad died and I dropped out of uni just before the final exams. But really my dog Suki welcoming the afterlife was the straw that broke the camel's back. My mum understood, and she came to the doctor with me for emotional support. My dad, upon hearing about it, made it all about himself. Told me I'm living a shit life, it's always been shit, and he should have done more to make it not shit.
For example, I was first diagnosed as clinically depressed back in 2010 after breaking up with my ex-girlfriend at the time. I lost her, and the dog who'd been with me for most of my /entire life/, since I was maybe 2 years old, died at the age of 21. That's crazy for a dog, but the loss hurt like nothing else. And my grandad died and I dropped out of uni just before the final exams. But really my dog Suki welcoming the afterlife was the straw that broke the camel's back. My mum understood, and she came to the doctor with me for emotional support. My dad, upon hearing about it, made it all about himself. Told me I'm living a shit life, it's always been shit, and he should have done more to make it not shit.

He wasn't listening at all, he just took my extreme vulnerability and swapped it in for his own so he could go on about being a bad father. I must have spent more time listening to him and reassuring him, as if I just announced I had late stage cancer and had a few months to live.


M posts/a-decade-of-work.org => posts/a-decade-of-work.org +4 -4
@@ 20,7 20,7 @@ That was about the age that I went to sixth form, and I was lucky enough to get 

I essentially got into programming as a joke, because a friend in my new social circle wanted a website, or at least hinted at it. I can't fully remember what was on the site, but I used part of my part-time income from Tesco to buy a .co.uk domain in his name and point it to a little HTML thing I made and hosted through the registrar's free web hosting service. All I needed was an FTP client and a bit of dragging and dropping.

Before I even knew it I had 'PHP4 for dummies' and 'MySQL for dummies' on the desk under my weird bunk-bed setup, and I only found out about this stuff through faffing around with those phpBB forums and looking at the configs. I remember ◊em{why} I sought that out though: I had a different website and noticed that it always displayed the current time when you refreshed it. I searched for how to do it and found examples in PHP, mostly from the comments section that each page of PHP docs had. It was literally as simple as changing the file extension from ◊code{html} (or ◊code{htm}) to ◊code{php} and then adding ◊code{<?php echo date(); ?>} wherever you wanted it. Deploying it was a case of dragging and dropping through FTP as most of these shared hosts offered PHP by default.
Before I even knew it I had 'PHP4 for dummies' and 'MySQL for dummies' on the desk under my weird bunk-bed setup, and I only found out about this stuff through faffing around with those phpBB forums and looking at the configs. I remember /why} I sought that out though: I had a different website and noticed that it always displayed the current time when you refreshed it. I searched for how to do it and found examples in PHP, mostly from the comments section that each page of PHP docs had. It was literally as simple as changing the file extension from ◊code{html} (or ◊code{htm}) to ◊code{php} and then adding ◊code{<?php echo date(); ?>/ wherever you wanted it. Deploying it was a case of dragging and dropping through FTP as most of these shared hosts offered PHP by default.

That was literally my first line of dynamic code.



@@ 28,15 28,15 @@ Skip ahead a few years, all the way to 2012 when I moved to London. I'd worked a

I won't talk much about the code, although my years at New Bamboo were truly formative. One thing has stuck with me since then though, over the 8 years since I was told it. My boss at the time saw I was struggling with managing the expectations of the client I was working with, and I was trying too hard to do things alone and hoping for the best instead of reaching out for the help that was readily available. I must have only been about 5 months into the job at that point. My boss took me into our boardroom, the table of which doubled up as a pingpong table, asked if I was alright, and then said something I've never forgotten since:

◊em{"Being a great developer is about a lot more than writing great code."}
/"Being a great developer is about a lot more than writing great code."/

Of course, at the time I was ashamed for mucking up and felt embarrased, but I was being given a piece of advice that would, in hindsight, radically change the direction of my career. I since became fascinated with the role of a scrum master, and took on the position full time myself. And as I moved into different positions at different companies (like Typeform and Friday Pulse), I continually realised that my favourite thing about programming wasn't just the raw challenge of solving a problem in code, but in the ◊em{people} side of it. I'm not talking about management per se, it's more about what else you can do with a good amount of knowledge and a strong desire to mentor and encourage those around you so they too can boost themselves up.
Of course, at the time I was ashamed for mucking up and felt embarrased, but I was being given a piece of advice that would, in hindsight, radically change the direction of my career. I since became fascinated with the role of a scrum master, and took on the position full time myself. And as I moved into different positions at different companies (like Typeform and Friday Pulse), I continually realised that my favourite thing about programming wasn't just the raw challenge of solving a problem in code, but in the /people/ side of it. I'm not talking about management per se, it's more about what else you can do with a good amount of knowledge and a strong desire to mentor and encourage those around you so they too can boost themselves up.

That's been an ongoing theme since mid-2015, even as I moved to Latvia and then eventually returned to London, and if anyone asks me what I consider to be great achievements when I interview, or have a conversation, I will always point to those people who I saw fluorish because they were given the time, space and effort to do so.

Now it's 2020, and not much has changed except that I enjoy the programming side of things a lot more than I used to. You could say that those two sides of the coin have started to merge into one imperfect sphere. Language is all communication and, these days, I enjoy trying to solve problems in different languages just so I can learn how to communicate similar technical things better in terms that I'm more familiar with. The same as I enjoy learning spoken languages to empathise in the same way.

The world has changed ◊em{a lot} in all that time, and I now find myself in my thirties. Not once in my life did I ever think or believe I would be doing this kind of thing as a career, and I've grown to love it. If I were to tell my teenage self anything, knowing all of this... I would keep my mouth shut. He managed to figure it out just fine.
The world has changed /a lot/ in all that time, and I now find myself in my thirties. Not once in my life did I ever think or believe I would be doing this kind of thing as a career, and I've grown to love it. If I were to tell my teenage self anything, knowing all of this... I would keep my mouth shut. He managed to figure it out just fine.

◊footnotes{
  ◊^[1]{◊<>["https://en.wikipedia.org/wiki/Dynamic_HTML"]}

M posts/agile-lipstick.org => posts/agile-lipstick.org +3 -3
@@ 28,7 28,7 @@ The manifesto, at that point in time, was conceived via the process of introspec
  Through this work we have come to value:
}

◊em{This work} is their iterative process. As if to reinforce the previous understanding, they discovered a pattern throughout and realised that things they valued ◊em{more} when developing software were:
/This work} is their iterative process. As if to reinforce the previous understanding, they discovered a pattern throughout and realised that things they valued ◊em{more/ when developing software were:

◊blockquote{
  ◊p{Individuals and interactions}


@@ 47,10 47,10 @@ And you can't just let the business fall back into old habits just because somet

Fuck that noise, just put the agile lipstick on your pig instead! Throw in a daily standup, run a retrospective, rationalise the legitimate issues away, and use sprints and estimates to track performance. Write a few blogs about it when you're done, and move onto to superficially changing the next unwitting client.

Now ◊em{that} is easy.
Now /that/ is easy.

◊footnotes{
  ◊^[1]{◊<>["https://www.coachingdevelopment.com/"] - if you're based in London or Ireland this is ◊em{so} worth it.}
  ◊^[1]{◊<>["https://www.coachingdevelopment.com/"] - if you're based in London or Ireland this is /so} worth it./
  ◊^[2]{◊<>["https://en.wikipedia.org/wiki/Eternal_September"]}
  ◊^[3]{◊<>["https://uk.bookshop.org/a/6865/9780321934116"]}
  ◊^[4]{◊<>["https://uk.bookshop.org/a/6865/9781118127308"]}

M posts/blogging-in-haskell.org => posts/blogging-in-haskell.org +1 -1
@@ 14,7 14,7 @@ The major appeal so far has been the immense ease of customisation. Hakyll itsel

The main difference is that you don't pull down a ◊code{hakyll} binary and then throw a ◊code{yaml} file together in order to configure a few pre-defined properties; you're instead given a basic implementation of a generator, using hakyll's own library, and thus have complete control over routing, page generation, templating, and so on. This generally lives in a ◊code{site.hs} file and it's not difficult to follow even for relative newbies to Haskell. The structure of everything else is entirely up to you.

Once you compile this file, you end up with a nice binary, e.g. ◊code{site}, and ◊em{that} is what you use to generate your site. It is beautiful in its elegance and I'm eager to see what I can add to this site while also learning some more Haskell at the same time.
Once you compile this file, you end up with a nice binary, e.g. ◊code{site}, and /that/ is what you use to generate your site. It is beautiful in its elegance and I'm eager to see what I can add to this site while also learning some more Haskell at the same time.

As an example, on the home page, there is a ◊code{git log} output section. It's fairly primitive, although I intend to build out the functionality a bit more. Writing the functionality was fairly effortless, with the help of some other authors on the net:


M posts/can-you-crack-the-code.org => posts/can-you-crack-the-code.org +6 -6
@@ 37,7 37,7 @@ I presume you've seen this kind of puzzle before: there is a lock that requires 

◊h2{A brief introduction}

If you're unaware of Prolog, it's a ◊em{logical progamming} language that, in its most simplest terms, takes a bunch of facts and rules and then gives you the tools to query them to get the outcome you want. In more complicated terms, a cursory search on the intertubes will lead you to a vast collection of academic papers that explain more. This is not the kind of language that is casually blogged about by the masses, as with more mainstream ones like CSS, HTML, or ColdFusion.
If you're unaware of Prolog, it's a /logical progamming/ language that, in its most simplest terms, takes a bunch of facts and rules and then gives you the tools to query them to get the outcome you want. In more complicated terms, a cursory search on the intertubes will lead you to a vast collection of academic papers that explain more. This is not the kind of language that is casually blogged about by the masses, as with more mainstream ones like CSS, HTML, or ColdFusion.

◊q["Dennis Merritt" 2017]{
  Programming in Prolog is significantly different from conventional procedural programming and requires a readjustment in the way one things about programming. Logical relationships are asserted, and Prolog is used to determine whether or not certain statements are true, and if true, what variable bindings make them true. This leads to a very declarative style of programming.◊^[1]


@@ 80,7 80,7 @@ So far, so boring. We stated `president(trump)` as a fact in our first prolog fi

The fuck? What is ◊code{X}?

◊code{X} is a variable, or a placeholder if you like. Any word starting with a capital letter is a variable, and when you pass one in a query Prolog will supply the results of the query to those variables. In this case, we're essentially saying ◊em{"who are all the presidents? I don't know their names so put them all in ◊code{X} for me"}.
◊code{X} is a variable, or a placeholder if you like. Any word starting with a capital letter is a variable, and when you pass one in a query Prolog will supply the results of the query to those variables. In this case, we're essentially saying /"who are all the presidents? I don't know their names so put them all in ◊code{X} for me"/.

Let's try one more thing, which should explain enough about Prolog to be dangerous.



@@ 88,7 88,7 @@ Let's try one more thing, which should explain enough about Prolog to be dangero
  president(X), cheese(X). % brie.
}

◊em{Now we're cookin' wi' gas!} as we'd say back up north. A lot of what you do in prolog is chain little sentences like this together (using the comma operator ◊code{,}, which means ◊code{and}), and in this instance we're asking Prolog to get all the presidents, put them in ◊code{X}, and then show me only the presidents that are also a cheese. The ◊code{.} finishes the sentence, or the query. Let's do a similar query to wrap this intro up, and you can see if your guess at the answer is the same as what this produces.
/Now we're cookin' wi' gas!} as we'd say back up north. A lot of what you do in prolog is chain little sentences like this together (using the comma operator ◊code{,}, which means ◊code{and}), and in this instance we're asking Prolog to get all the presidents, put them in ◊code{X}, and then show me only the presidents that are also a cheese. The ◊code{./ finishes the sentence, or the query. Let's do a similar query to wrap this intro up, and you can see if your guess at the answer is the same as what this produces.

◊codeblock['prolog]{
  president(X), person(X). % trump, obama.


@@ 125,7 125,7 @@ Here's the puzzle again, for reference:

◊hr{}

According to Leon Sterling and Ehud Shapiro in ◊em{The Art of Prolog}◊^[3], this type of problem falls quite neatly under the umbrella of non-deterministic programming. This is because we're essentially going to build an algorithm that will use what they describe as a ◊code{generate and test} solution. We're going to write something that will take our clues and run through all the possible answers until it lands on the only one that fits. We're not aiming for beautiful optimisation here so this good enough, although the code we write will be tightly coupled to the exact puzzle provided.
According to Leon Sterling and Ehud Shapiro in /The Art of Prolog}◊^[3], this type of problem falls quite neatly under the umbrella of non-deterministic programming. This is because we're essentially going to build an algorithm that will use what they describe as a ◊code{generate and test/ solution. We're going to write something that will take our clues and run through all the possible answers until it lands on the only one that fits. We're not aiming for beautiful optimisation here so this good enough, although the code we write will be tightly coupled to the exact puzzle provided.

So, let's begin with our set of rules:



@@ 140,7 140,7 @@ So, let's begin with our set of rules:
}

◊aside{
  If you're curious about the first `use_module` statement, beyond knowing that it makes things easier, check out the docs on ◊em{Constraint Logic Programming over Finite Domains}.◊^[4]
  If you're curious about the first `use_module` statement, beyond knowing that it makes things easier, check out the docs on /Constraint Logic Programming over Finite Domains/.◊^[4]
}

These clues don't really mean anything by themselves, they're simple facts in Prolog terms, so we need to add a bit more to give these some meaning. All of this will go into the same file, as we're not ready to query yet.


@@ 157,7 157,7 @@ These clues don't really mean anything by themselves, they're simple facts in Pr
  wrong(Digit, [D|Ds]) :- Digit #\= D, wrong(Digit, Ds).
}

I'll leave the in-depth explanation of these rules to another post for the sake of brevity, and also because I'm not that much of a Prolog expert. These are all used to add meaning to the facts, as with these rules we can now define logic such as ◊em{one number is correct but in the wrong position}, and ◊em{none of the numbers are correct}. We just have to painstakingly mix and match them.
I'll leave the in-depth explanation of these rules to another post for the sake of brevity, and also because I'm not that much of a Prolog expert. These are all used to add meaning to the facts, as with these rules we can now define logic such as /one number is correct but in the wrong position}, and ◊em{none of the numbers are correct/. We just have to painstakingly mix and match them.

The next bit is quite long, but this query is where we make the sausage. Commentary will be written inline for ease of copy and paste, until I come back and edit this post with a more digestible version.


M posts/celebrate-each-other.org => posts/celebrate-each-other.org +2 -2
@@ 22,9 22,9 @@ When I joined Babylon in early 2019, one of the first things I did after settlin

Honestly, I live for that shit :D I love public displays of recognition because, so often, this stuff never happens until you're gone and people miss whatever you did that made them so happy or grateful. Just a simple line of text with thank you or an explanation, along with hundreds of other similar lines meant for other people, that everybody could read through and really share in that celebration of each other, not just success.

And that, for me, is my key learning after all these years. 'Celebrating success' is such an overused and misunderstood term that you never really see it happen. Besides which, there is plenty of failure that is also worth celebration. And plenty of stuff that doesn't fit into the bucket of success or failure that deserves celebrating too. And you can be successful ◊em{within} a failure.
And that, for me, is my key learning after all these years. 'Celebrating success' is such an overused and misunderstood term that you never really see it happen. Besides which, there is plenty of failure that is also worth celebration. And plenty of stuff that doesn't fit into the bucket of success or failure that deserves celebrating too. And you can be successful /within/ a failure.

What I'm saying in a pretty long-winded way is that we people make the success what it is, and success comes in so many diverse forms! It's not just a project delivered on time, or a feature boosting MRR, or an uptick in retention against churn or whatever abstract work-related metric you can conjure up. It's not just a business goal, it's a ◊em{fucking plethora} of personal goals, desires, likes, dislikes, passions, and serendipitous interactions, all of which can mingle and mesh until you get that moment of genius, or you go home feeling happy and contented. Or whatever it is you want from life.
What I'm saying in a pretty long-winded way is that we people make the success what it is, and success comes in so many diverse forms! It's not just a project delivered on time, or a feature boosting MRR, or an uptick in retention against churn or whatever abstract work-related metric you can conjure up. It's not just a business goal, it's a /fucking plethora/ of personal goals, desires, likes, dislikes, passions, and serendipitous interactions, all of which can mingle and mesh until you get that moment of genius, or you go home feeling happy and contented. Or whatever it is you want from life.

Celebrate each other, celebrate yourselves. 🥳


M posts/devops.org => posts/devops.org +1 -1
@@ 12,7 12,7 @@ Enterprise might not be the best word, but it's the only one I have right now, a

Let's talk about bugs and production servers. Before Bablyon I had not worked in a single place that restricted access to production. As a developer working primarily with Ruby on Rails applications, getting prod access on Heroku or AWS was practically an onboarding step, and that meant I could easily boot up a console and modify the application runtime on the fly. This is an amazingly powerful tool in development and testing environments, it's basically just a boostrapped REPL, but expose that in production and a malicious actor could wreak all sorts of havoc without leaving a trace. This is even worse if your rails app is running under `root` for some reason (e.g. through a poor Docker setup), as you can quite easily jump into a shell from there.

You couldn't do any of this at Bablyon because production and preprod were locked down ◊em{tight}, and even seeing production logs required a background check. This didn't really make debugging worse, because instead there was a huge investment in tooling (internal and external) and developer experience to balance it out. One of my favourite outcomes of this is the creation of an open source tool for managing a Kubernetes cluster, called `shipcat`◊^[1]. You know it's good when it has its own cute logo.
You couldn't do any of this at Bablyon because production and preprod were locked down /tight/, and even seeing production logs required a background check. This didn't really make debugging worse, because instead there was a huge investment in tooling (internal and external) and developer experience to balance it out. One of my favourite outcomes of this is the creation of an open source tool for managing a Kubernetes cluster, called `shipcat`◊^[1]. You know it's good when it has its own cute logo.

What I've since realised is that this particular crutch (live debugging in production) prevents the business from properly investing in safer and more compliant tools for engineers to investigate issues. You want proper structured logging, good alerting on error conditions, and a whole slew of observability (o11y) tools that can help you diagnose the system from the outside-in without compromising it. You want to have a team of impassioned engineers who enjoy working on internal productivity/efficacy, creating new tools to address pain-points in the organisation's development and support lifecycle.


M posts/do-you-really-need-those-microservices.org => posts/do-you-really-need-those-microservices.org +1 -1
@@ 14,7 14,7 @@ Anyway, I love being asked this question because after a good five years of work

First and foremost, I believe the main benefit of a business switching to microservices is the manifestation of Conway's Law◊^[1] in practice. Prior to making the switch in architecture, the business most likely decided on an organisational structure that exchanges large, difficult to manage teams for a distributed collection of smaller, self-sufficient, self-empowered teams. More often than not these follow a squad and chapter model, otherwise reduced to 'the Spotify model', and a hierarchy of cross-functional teams is established. Once that structure is put in place and people are shuffled around a bit, the question of ownership in a mixed-responsibility, mixed-domain codebase becomes apparent. Microservices are thus the solution to a perceived conflict between squads and they shift a lot of that conflict from the teams themselves, to the channels in-between them.

Under no circumstance is the technical implication of such a change considered, particularly in older codebases for which this change would introduce a significant level of disruption. The organisational benefits of distributing teams and workload are substantial, but the drawbacks of distributing ◊em{code} are similarly worthy of consideration too, and it often becomes a gateway to extra complexity as once-simple tasks find themselves spread apart over various network calls and machines.
Under no circumstance is the technical implication of such a change considered, particularly in older codebases for which this change would introduce a significant level of disruption. The organisational benefits of distributing teams and workload are substantial, but the drawbacks of distributing /code/ are similarly worthy of consideration too, and it often becomes a gateway to extra complexity as once-simple tasks find themselves spread apart over various network calls and machines.

I don't consider this a dealbreaker, but in my experience I've always felt like there's a step missing between the singular, monolithic codebase and the highly distributed microservice architecture. There's a hell of a lot you can do in that singular codebase, in terms of taking smaller steps towards a service-oriented architecture, or a domain-driven one. 


M posts/enough.org => posts/enough.org +1 -1
@@ 34,7 34,7 @@ So it is with ambition for the sake of ambition. Working towards something witho

When is it enough?

At one point in time, I didn't really have a concept of this. There would always be more, always something to do better, always some way to ◊em{be} better, by whatever definition 'better' had at the time.
At one point in time, I didn't really have a concept of this. There would always be more, always something to do better, always some way to /be/ better, by whatever definition 'better' had at the time.

These days that feels more like an endless treadmill, always chasing the carrot dangling an arm's length away and beating yourself with the stick when you fail to reach it.


M posts/gettin-ziggy-with-it-pi-zero.org => posts/gettin-ziggy-with-it-pi-zero.org +6 -6
@@ 8,7 8,7 @@

Alright, you can read the article first and shoot me later for a title like that, and what will inevitably become a series of Zig-based puns.

Zig, for the unaware, is a fancy language that looks to be to C what Rust is to C++. Honestly, I recommend you read the summary on the main page◊^[1] to find out more yourself, as the best I can do is to just parrot what has already been written. However, you can see it as a valid ◊em{alternative} to C and Zig itself has claimed that it wants to be a better version of C than C itself. An ambitious challenge, for sure. To that end, Zig itself ships its own C compiler.
Zig, for the unaware, is a fancy language that looks to be to C what Rust is to C++. Honestly, I recommend you read the summary on the main page◊^[1] to find out more yourself, as the best I can do is to just parrot what has already been written. However, you can see it as a valid /alternative/ to C and Zig itself has claimed that it wants to be a better version of C than C itself. An ambitious challenge, for sure. To that end, Zig itself ships its own C compiler.

I've been interested in giving Zig a spin for quite a while, and once my Raspberry Pi Zero W◊^[2] and OLED display◊^[3] arrived in the post, I decided that this would be my best opportunity to try it out. I'm not really going to cover the process of wiring up the hardware, suffice to say that once you've got your Pi Zero you'll need to be able to SSH into it, and that you'll need a [solderless] GPIO header◊^[4] to plug the OLED display into. I recommend the Zero ◊b{W} because the W means 'WiFi', which means that if you connect it to your network you can SSH in without faffing around with USB cables and what not. It's not a requirement, though.



@@ 16,7 16,7 @@ With that out of the way, let's see if we can write something in Zig to power th

Instead, we will be directly using the i◊sup{2}c dev interface◊^[6]. If you're using Debian and/or Ubuntu on your Pi and your own machine, you can grab these libraries with a simple ◊code{sudo apt install i2c-dev}. You will need to enable i◊sup{2}c on your Pi separately though, through ◊code{sudo raspi-config}◊^[7].

Ready to... get Ziggy with it? Oh, I bet you are. 😋 If you want to skip to the end and just grab the code, though, you can find this all on GitHub◊^[8]. I called it Stardust, like ◊em{Zig}gy Stardust. Get it?
Ready to... get Ziggy with it? Oh, I bet you are. 😋 If you want to skip to the end and just grab the code, though, you can find this all on GitHub◊^[8]. I called it Stardust, like /Zig/gy Stardust. Get it?

🥁



@@ 54,9 54,9 @@ The next step is to define a ◊code{main} function that grabs a file descriptor
  }
}

You might have noticed something odd: we're not really writing much Zig here, it's practically 95% interop with C. The beauty of Zig is that this interop is so simple and intuitive that it's the ◊em{easiest} way to get started if you're going to be linking against existing C libraries. Get the software working first, abstract it later, as they say, and you might already start to get an idea of what we could convert into idiomatic Zig libraries in future.
You might have noticed something odd: we're not really writing much Zig here, it's practically 95% interop with C. The beauty of Zig is that this interop is so simple and intuitive that it's the /easiest/ way to get started if you're going to be linking against existing C libraries. Get the software working first, abstract it later, as they say, and you might already start to get an idea of what we could convert into idiomatic Zig libraries in future.

The actual Zig code you see though, is quite different to the C stuff. That ◊code{defer fd.close()}, for example, ◊em{ensures} that the file descriptor we opened up will be closed when we're done. If we don't do that, then it'll stay open and there'll be a leak.
The actual Zig code you see though, is quite different to the C stuff. That ◊code{defer fd.close()}, for example, /ensures/ that the file descriptor we opened up will be closed when we're done. If we don't do that, then it'll stay open and there'll be a leak.

There's also the ◊code{try} macro, used in combination with the ◊code{!void} return type, which will be super familiar if you've written some Rust and have dealt with option types. It's short hand for executing the code and catching/dealing with the error, with ◊code{!void} being another shorthand for ◊code{anyerror!void}, namely: this function returns either nothing, or an error if there is one.



@@ 121,7 121,7 @@ Let's move on and make this kitten purr. Meow 🐈.

◊h2{Getting this show on the road}

In true ◊em{draw the rest of the fucking owl} fashion◊^[11], what follows is a bit of a code-dump since the primary method of communicating with your OLED display is to, literally, write a few bytes to a file. The registers available and what can be written to them are often described in a meticulously detailed datasheet◊^[12], but they're not exactly light reading and we can save a bit of time by grabbing the info from elsewhere. A lot of the constants that follow are gracefully derived from those listed in a certain ◊code{owenosborn}'s wiringPi-based driver.◊^[13]. Credit where credit's due, eh.
In true /draw the rest of the fucking owl} fashion◊^[11], what follows is a bit of a code-dump since the primary method of communicating with your OLED display is to, literally, write a few bytes to a file. The registers available and what can be written to them are often described in a meticulously detailed datasheet◊^[12], but they're not exactly light reading and we can save a bit of time by grabbing the info from elsewhere. A lot of the constants that follow are gracefully derived from those listed in a certain ◊code{owenosborn/'s wiringPi-based driver.◊^[13]. Credit where credit's due, eh.

◊codeblock['zig]{
  const SET_CONTRAST = 0x81;


@@ 265,7 265,7 @@ Once you're done, rebuild the binary and ◊code{scp} it over, like you did the 

◊hr{}

Hopefully that worked, but if it didn't, get in touch with your feedback at wtf@mrlee.dev and help contribute to this post being a better, more informative read. After all, ◊em{works on my machine!} can only go so far.
Hopefully that worked, but if it didn't, get in touch with your feedback at wtf@mrlee.dev and help contribute to this post being a better, more informative read. After all, /works on my machine!/ can only go so far.

◊footnotes{
  ◊^[1]{◊<>["https://ziglang.org"]}

M posts/growing-up.org => posts/growing-up.org +2 -2
@@ 8,11 8,11 @@

Way back in 2002, or perhaps 2003, I'd acquired a copy of Macromedia Dreamweaver and started playing about with HTML. The timeline is a bit blurry, considering that it's almost twenty years ago. CSS wasn't really a thing yet, though, and IE6 was still the main browser of choice. Eventually CSS became a thing and one of my first real 'projects' was to create a user style that hid all the ads on the Gamesradar forum I used to spend time on. You had to switch to Firefox and then dump the CSS in your 'profile' folder; it was a total hack and there was more documentation than code.

I didn't realise that I'd be setting myself up for a career in programming, in fact I remained blissfully ignorant of this prospect even as I bought books like ◊em{MySQL 5.5 for Dummies} and ◊em{PHP 4 For Dummies}. All I wanted to do was show the current time and date on the page and that quite quickly escalated into building a custom blog, using a database to store the posts. That then snowballed into messing with web frameworks like CakePHP and CodeIgniter.
I didn't realise that I'd be setting myself up for a career in programming, in fact I remained blissfully ignorant of this prospect even as I bought books like /MySQL 5.5 for Dummies} and ◊em{PHP 4 For Dummies/. All I wanted to do was show the current time and date on the page and that quite quickly escalated into building a custom blog, using a database to store the posts. That then snowballed into messing with web frameworks like CakePHP and CodeIgniter.

I actually didn't want a career in web development, I didn't really know what I wanted. It sounded like 'working with computers' and my mum in particular was pressuring me a lot with that. To her credit, she was technically correct, although I think she was more keen about me doing more hands-on work, like building and repairing computers, so there'd be someone in the family who could do it.

Despite this, and my rebellious teenage opposition to doing anything that wasn't ◊em{my} idea, I'd spent years unknowingly educating myself as I spent time on various web dev forums offering advice, answering questions, and asking questions of my own. Stack Overflow came and many of those forums faded into obscurity, which is a shame since Stack Overflow preferred clear, unambiguous answers, and with a forum you could engage in a conversation around a problem and more organically hash out a solution. The lesson wasn't in the solution really, but in the discussion that preceded it, and it allowed me to develop an intuition.
Despite this, and my rebellious teenage opposition to doing anything that wasn't /my/ idea, I'd spent years unknowingly educating myself as I spent time on various web dev forums offering advice, answering questions, and asking questions of my own. Stack Overflow came and many of those forums faded into obscurity, which is a shame since Stack Overflow preferred clear, unambiguous answers, and with a forum you could engage in a conversation around a problem and more organically hash out a solution. The lesson wasn't in the solution really, but in the discussion that preceded it, and it allowed me to develop an intuition.

After some time doing small-scale freelance work, managing phpBB instances and such like, I landed my first job for a little web marketing company that made websites for local businesses. It was mostly a case of repackaging Drupal apps with some theme on top, but we got given other project work too. For some reason that also had to be done in Drupal. I never wanted to work with Drupal again after all that. However, this was the first time I'd worked with another web developer, let alone a team, face to face in an office.


M posts/hakyll-on-devops-pipelines.org => posts/hakyll-on-devops-pipelines.org +2 -2
@@ 15,7 15,7 @@ In a way, this is total overkill for a static site. If I have the repo cloned on

It's flawed compared to using ◊code{rsync}, as it won't remove existing files, but it does the job in less than a second or two.

The thing is, this isn't so quick if I want to publish a post from a different computer that doesn't have any programming tools installed. I would have to install ◊code{stack}◊^[1], which is a build tool for Haskell, and then I would have to run ◊code{stack build}. This can take at least half an hour as the command will pull down the correct version of ◊code{GHC} and a 'snapshot' (basically a huge collection of all the Hackage◊^[2] libraries available for that build) before it even ◊em{thinks} about compiling my ◊code{site.hs} file. It also means to committing a few gigs of storage space for all of that.
The thing is, this isn't so quick if I want to publish a post from a different computer that doesn't have any programming tools installed. I would have to install ◊code{stack}◊^[1], which is a build tool for Haskell, and then I would have to run ◊code{stack build}. This can take at least half an hour as the command will pull down the correct version of ◊code{GHC} and a 'snapshot' (basically a huge collection of all the Hackage◊^[2] libraries available for that build) before it even /thinks} about compiling my ◊code{site.hs/ file. It also means to committing a few gigs of storage space for all of that.

I like to write from my little Surface Pro when I'm out and about, so I'd rather not do a full-blown compilation on that for the sake of my battery. Enter Azure DevOps Pipelines◊^[3].



@@ 121,7 121,7 @@ So, that's the first step done, but what about actually publishing a post? I hav
    steps: ...
}

The key to this step is the condition. This will run only if the ◊code{build} job was successful, ◊em{and} the branch being built is the master branch. Practically, this only runs if I push straight to master or merge a PR. The staging version runs only on PRs.
The key to this step is the condition. This will run only if the ◊code{build} job was successful, /and/ the branch being built is the master branch. Practically, this only runs if I push straight to master or merge a PR. The staging version runs only on PRs.

◊codeblock['yaml]{
  - task: DownloadBuildArtifacts@0

M posts/human-after-all.org => posts/human-after-all.org +2 -2
@@ 30,13 30,13 @@ Whew, better bring this back to the topic I had in mind before I go off on anoth

◊strong{Compassion}.

I like compassion. Actually no, I ◊em{love} it. It's an amazing word that can mean many things to many people, but I like to think it's what gives this world the soul it has; it's certainly responsible for a lot of good. The Compassionate Mind◊^[3] dedicates over 500 pages and thousands upon thousands of words to this, and this is what the blurb has to say about it:
I like compassion. Actually no, I /love/ it. It's an amazing word that can mean many things to many people, but I like to think it's what gives this world the soul it has; it's certainly responsible for a lot of good. The Compassionate Mind◊^[3] dedicates over 500 pages and thousands upon thousands of words to this, and this is what the blurb has to say about it:

> Not only does compassion help to soothe distressing emotions, it actually increases feelings of contentment and well-being.

To my mind, spending mental energy on identifying and labelling different kinds of toxic people will never bring you contentment and inner-peace. I think you'll actually end up with more distressing emotions as you figure out how to deal with this knowledge.

What if you're worried about being toxic yourself? Same thing, you're just being dominated by it indirectly and defining yourself by what you're not. Contentment and inner-peace is found in what you ◊em{are}, who you are, not the other way around.
What if you're worried about being toxic yourself? Same thing, you're just being dominated by it indirectly and defining yourself by what you're not. Contentment and inner-peace is found in what you /are/, who you are, not the other way around.

The reason I'm saying this is because it works at a cultural level too. If the first thing you tell to a potential hire is that you don't hire toxic employees, or your culture isn't toxic, you're just begging the question. Why the hell is _that_ on your mind and not all the good stuff you could be saying instead? What are you hiding with your preoccupation?


M posts/i-am-here.org => posts/i-am-here.org +2 -2
@@ 8,7 8,7 @@

I've been no stranger to depression and burnout. The former is more or less something I've grown to become friends with, as bizarre as it sounds. And as dark and troubling as those times have been, at their worst, they're equally the reason where I find myself where I am now, having experienced all that I have. I wish Trump didn't abuse the words 'tremendous' and 'beautiful' so much, because there can be great beauty in these harrowing experiences once you can look back on them and see how you've grown, changed, since.

I can tell when I start to grow burned out not because I feel more depressed, but because I start to try too hard or overcompensate for perceived failures. It's the classic feeling of not being ◊em{enough}, and trying to pursue ever loftier goals as a way of becoming ◊em{more} enough. It inevitably ends in abject failure and if I was to ask anyone else around me while that was happening, they would quite rightly tell me that I am being too hard on myself and nobody is beating me up the way I am. The inner critic is strong in this one, and he doesn't always want to admit or accept that he is totally enough as he is, and he should slow down and enjoy this eccentric life of his. I mean, we're all eccentric in our own ways; it's by no means an insult compared to an allegation of being ◊em{normal}.
I can tell when I start to grow burned out not because I feel more depressed, but because I start to try too hard or overcompensate for perceived failures. It's the classic feeling of not being /enough}, and trying to pursue ever loftier goals as a way of becoming ◊em{more} enough. It inevitably ends in abject failure and if I was to ask anyone else around me while that was happening, they would quite rightly tell me that I am being too hard on myself and nobody is beating me up the way I am. The inner critic is strong in this one, and he doesn't always want to admit or accept that he is totally enough as he is, and he should slow down and enjoy this eccentric life of his. I mean, we're all eccentric in our own ways; it's by no means an insult compared to an allegation of being ◊em{normal/.

It's funny, really. Life for me really began in 2012 when I moved from my parents home in Bolton to my own rented room in London. It wasn't glamourous in the slightest but the freedom and independence was well worth it. I'd joined an agency called New Bamboo that specialised in building software in Ruby on Rails, in an agile way, and their decision to hire me--a junior PHP engineer at the time with only a year of professional experience--basically changed my life. Even now, 8 years later, I don't know anyone from there who looks back on that time unfavourably. In fact, we often lament how hard it is to find somewhere even remotely similar to them. The culture was one of a kind and I greatly matured through it, making some excellent friends who are still close-knit to this day.



@@ 28,7 28,7 @@ That's one hell of a tortured metaphor, but I think we all have our own individu

To bring this back to the start, I would not change a thing as my place in this moment is entirely a function of all that shit, and all that wonder, I've been through over the years, going right back to my birth and my childhood as an adopted, abused kid. All of the pain, both given and received, and the pleasure, have served a purpose and I appreciate those experiences as I would not think or feel the way I currently do were it not for them. I would not value empathy and compassion and inclusivity so massively. And rather than focussing so heavily on just how shitty some of those moments have been, the amazing memories that have come from my struggle through it all are equally incalculable.

This isn't to say all my problems are solved, or I'm finished with my process. That's ◊strong{pure BS} as this stuff lasts an entire lifetime as you learn, grow and adapt to new situations. But the track record I have must be pretty good if I'm ◊em{here}, right?
This isn't to say all my problems are solved, or I'm finished with my process. That's ◊strong{pure BS} as this stuff lasts an entire lifetime as you learn, grow and adapt to new situations. But the track record I have must be pretty good if I'm /here/, right?

◊footnotes{
  ◊^[1]{◊<>["https://en.wikipedia.org/wiki/Breathwork"]}

M posts/isolation-aloneness-and-loneliness.org => posts/isolation-aloneness-and-loneliness.org +1 -1
@@ 20,7 20,7 @@ Don't get me wrong, everyone needs love, support, acknowledgement, recognition..

Eventually though, that continual desire to receive this energy from other people (as opposed to finding it within yourself somehow) is going to result in a self-fulfilling prophecy where you are convinced that you are lonely, or a loner, purely because you've taught yourself to believe that.

I have to say that I'm endlessly grateful to my closest, bestest friends for pointing out to me that it does't really have to be that way, so it was about five years ago that I started learning the difference between ◊em{lonely}-ness and ◊em{alone}-ness (deliberate mis-spellings for emphasis).
I have to say that I'm endlessly grateful to my closest, bestest friends for pointing out to me that it does't really have to be that way, so it was about five years ago that I started learning the difference between /lonely}-ness and ◊em{alone/-ness (deliberate mis-spellings for emphasis).

I seriously enjoy being alone, and to understand the difference there was hugely empowering to me. It's truly a liberating distinction that unlocks so many opportunities that were previously unavailable because of the expectation they had to be done 'with someone' or with a group. Maybe out of a desire to be romantic, or to share with someone, or just because society finds it weird if you don't.


M posts/my-favourite-thing-about-programming.org => posts/my-favourite-thing-about-programming.org +1 -1
@@ 57,7 57,7 @@ With emacs in particular, it made it trivially easy for me to launch a Rails con

I mapped it to a certain keybinding and a panel would open to the side within a second, ready for me to use. I don't think I'd have the patience to try and reproduce that in, say, VS Code, without using a task runner. Emacs itself is entirely programmable so you don't need to worry about setting up extension boilerplate to make minor modifications.

I should round this post off with an even three examples, so my final two are Smalltalk and Prolog. I haven't managed to build anything in it yet, as the learning curve is quite unlike any other. However, aspects of Smalltalk live on in languages like Ruby, where everything is an object and everything is defined in terms of message passing. I think Objective-C can be counted there too, although both languages diverge from some of Smalltalk's ideals in the name of pragmatism. My short term goal with Smalltalk is to (attempt to) implement a raytracer as described in ◊em{The Ray Tracer Challenge} by James Buck◊^[1], so I can better understand the language and apply what I've learned elsewhere. 
I should round this post off with an even three examples, so my final two are Smalltalk and Prolog. I haven't managed to build anything in it yet, as the learning curve is quite unlike any other. However, aspects of Smalltalk live on in languages like Ruby, where everything is an object and everything is defined in terms of message passing. I think Objective-C can be counted there too, although both languages diverge from some of Smalltalk's ideals in the name of pragmatism. My short term goal with Smalltalk is to (attempt to) implement a raytracer as described in /The Ray Tracer Challenge/ by James Buck◊^[1], so I can better understand the language and apply what I've learned elsewhere. 

Prolog is on my list, and I keep coming back to it every couple of months to see what I'm inspired to do. I find it, and logic programming, intriguing, and I wonder how many problems would be solved a bit more easily that way compared to how we usually smush things together in procedural or OOP languages. Watch this space for more insight, I guess.


M posts/past-mistakes.org => posts/past-mistakes.org +1 -1
@@ 10,7 10,7 @@ I think everyone needs at least one blog post under their belt that describes mi

1. Liberal application of the word 'just'

"Why don't you ◊em{just} do this other thing instead?" Uuughhh...this word, which serves as punctuation as much as the word 'fuck' does in Glasgow, is bound to rile anyone up after the umpteenth attempt at trivialising the problem they have.
"Why don't you /just/ do this other thing instead?" Uuughhh...this word, which serves as punctuation as much as the word 'fuck' does in Glasgow, is bound to rile anyone up after the umpteenth attempt at trivialising the problem they have.

It still slips out occasionally, and I should really wash my mouth out with soap after it, but the true magnitude of this error only becomes apparent when you start paying attention to how often everyone else does it too.


M posts/permanent-solutions-to-temporary-problems.org => posts/permanent-solutions-to-temporary-problems.org +3 -3
@@ 10,15 10,15 @@ Depression fucking sucks. It sucks to suffer from it; it sucks to see others suf

I lost contact with my landlord sometime last year, and obviously as a private tenant that raised some concerns as my main point of contact for my flat had vanished off the face of the earth. He'd deleted his email address and his phone number was deactivated. To be honest I thought nothing of it for a while, and the last thing he told me was that he was bogged down with work at the NHS. Not a particularly good sign given the situation with COVID.

At the beginning of the year I received a letter from the solicitors managing his estate: he died last November. Receiving this kind of news presents a veritable cocktail of emotions; a confusing mix of relief, catharsis, and sadness. Finally ◊em{you know}, so in that there's some closure, but also... fuck. What a shame.
At the beginning of the year I received a letter from the solicitors managing his estate: he died last November. Receiving this kind of news presents a veritable cocktail of emotions; a confusing mix of relief, catharsis, and sadness. Finally /you know/, so in that there's some closure, but also... fuck. What a shame.

The letter from the solicitors asked me to start paying my rent to a different account, so naturally I had to ask for some evidence to verify this claim. A death certificate would suffice, I said, and not more than a couple of days later I got an email with one in it, along with a letter from the coroner.

Cause of death: ◊em{suspension}.
Cause of death: /suspension/.

That's a euphemistic way to say that my landlord committed suicide by hanging himself. Fuuuck.

The thing is, I don't have to love this man or feel close to him to be upset by that news. I feel ◊em{for} him, because I can only imagine what it takes to get to that state of sheer torment and utter desperation that the point of no return becomes a beacon of hope. A permanent solution to a temporary problem as it were, though I am in no place to make any kind of claim about the situation he was in.
The thing is, I don't have to love this man or feel close to him to be upset by that news. I feel /for/ him, because I can only imagine what it takes to get to that state of sheer torment and utter desperation that the point of no return becomes a beacon of hope. A permanent solution to a temporary problem as it were, though I am in no place to make any kind of claim about the situation he was in.

I can only imagine that because I've been there myself, more than once. It's not something I could put into words, and nor would I want to relive it such that I could. I wouldn't want the people I love, who supported me at that time, to go back and find the words for it either. But I've been there, and those people closest to me have been there by extension. They shouldered some of my emotional burden themselves so that I could try and cope with a lighter load.


M posts/rewrite-it-in-lisp.org => posts/rewrite-it-in-lisp.org +1 -1
@@ 6,7 6,7 @@
:END:
:PUBLISHED: t

I finally got around to paying some money for ◊em{Beautiful Racket}◊^[1], a fantastic online-only book that introduces you to Racket by guiding you through building a few language implementations. In that sense it's not unlike ◊em{Write Yourself a Scheme in 48 Hours}◊^[2], except that book focusses on Haskell and (through no fault of its own) lacks the wonderful presentation of Beautiful Racket.
I finally got around to paying some money for /Beautiful Racket}◊^[1], a fantastic online-only book that introduces you to Racket by guiding you through building a few language implementations. In that sense it's not unlike ◊em{Write Yourself a Scheme in 48 Hours/◊^[2], except that book focusses on Haskell and (through no fault of its own) lacks the wonderful presentation of Beautiful Racket.

Developing a soft spot for a lisp feels like a rite of passage for a typical programmer, alongside owning a copy of SICP and using emacs as your main editor. And for good reason, really; the beauty of writing lisp is that you are basically working directly with an AST instead of dealing with a special syntax that is parsed into one. It's powerfully expressive, if not a little intimidating at first.


M posts/ruby-sorcery-ractor-2.org => posts/ruby-sorcery-ractor-2.org +4 -4
@@ 57,9 57,9 @@ The anatomy of an HTTP request is divided, essentially, into three parts:

The first line states the request method (i.e. ◊code{GET}, ◊code{POST}, etc.) and the target of the request, which will often be a relative path on the server but can also be a full URL.

◊aside{Note that there is also a concept of HTTP 'trailers', which are headers that appear ◊em{after} the body◊^[2]. These are only used for certain kinds of chunked requests and are way out of scope for this post.}
◊aside{Note that there is also a concept of HTTP 'trailers', which are headers that appear /after} the body◊^[2]. These are only used for certain kinds of chunked requests and are way out of scope for this post./

What follows is a list of headers, which are key/value pairs used to provide extra information about the request. For the sake of simplicity, most of these will be ignored, and there are ◊em{many} of them.
What follows is a list of headers, which are key/value pairs used to provide extra information about the request. For the sake of simplicity, most of these will be ignored, and there are /many/ of them.

Finally, there is a place for the body of the request. This is optional, but it must have an empty line both before and afterwards if it is present. A typical request body may contain URLEncoded form data, which is how your typical HTML forms work, but there is not much of a restriction provided that the ◊code{Content Type} header describes the format of the payload, e.g if it's JSON, XML, or perhaps even something like an image or a video.



@@ 110,13 110,13 @@ Something like this should do the trick, and provide a foundation to build on.

◊aside{Why all the ◊code{loop}s and ◊code{while} loops? Ractors behave a bit like Enumerators◊^[5], which means that if they stop yielding values or actually return a value, the Ractors close and can no longer be used.}

What we have here is a Ractor that waits for incoming HTTP request messages, and then parses them into something that the server can more easily work with by pulling out important info like the request location, the HTTP method, the content type, and the body. In this example, Ruby's pattern matching features are liberally employed to handle the parsing in some places; this is more for the sake of demonstration to show that it ◊em{can} be done, not necessarily that it always ◊em{should} be.
What we have here is a Ractor that waits for incoming HTTP request messages, and then parses them into something that the server can more easily work with by pulling out important info like the request location, the HTTP method, the content type, and the body. In this example, Ruby's pattern matching features are liberally employed to handle the parsing in some places; this is more for the sake of demonstration to show that it /can} be done, not necessarily that it always ◊em{should/ be.

In any case, once the ◊code{HttpRequest} object is constructed, it is yielded so that another Ractor can use the object, and therefore it will sit in a queue (or a mailbox, in actor model parlance) until it is taken from it. As a final housekeeping step, the string scanner instance used to parse the request is terminated. It's always a good idea to clean up after yourself if the language provides you the mechanism to do so.

Going back to the functionality at hand; this basically shunts the parsing of HTTP requests into another thread, which means that the Ractors responsible for managing the TCP layer can stay responsible for that, and hand over the application-layer responsibilities to other actors/processes/Ractors.

The TCP server now requires an upgrade: it's going to read input but it can no longer work on a line-by-line basis, because a HTTP message takes up many lines. The only thing we can really depend on is that it always ends with ◊em{two} carriage returns (CR-LF characters, or '\r\n' in a string).
The TCP server now requires an upgrade: it's going to read input but it can no longer work on a line-by-line basis, because a HTTP message takes up many lines. The only thing we can really depend on is that it always ends with /two/ carriage returns (CR-LF characters, or '\r\n' in a string).

◊codeblock['ruby]{
  Ractor.new do

M posts/ruby-sorcery-ractor.org => posts/ruby-sorcery-ractor.org +4 -4
@@ 24,7 24,7 @@ An actor is something that has one or more addresses, and receives messages; but

In addition to receiving messages, then, an actor can also send messages to another actor. On top of that, it can also create new actors as children of itself.

The final missing piece is that an actor can hold internal state, or in other words, store data. This is inaccessible to any other actor and therefore the ◊em{only} way to manipulate data inside an actor is to send it a message that it understands.
The final missing piece is that an actor can hold internal state, or in other words, store data. This is inaccessible to any other actor and therefore the /only/ way to manipulate data inside an actor is to send it a message that it understands.

How does it fit together? An actor can have multiple addresses, and many actors can share the same address. This means that you can achieve scaling by having more actors listen on an address, effectively load-balancing incoming messages, and you can create more powerful actors that perform different tasks based on those same messages.



@@ 45,7 45,7 @@ You can consider technologies like Kubernetes◊^[7], Kafka◊^[8], and Web Work

For example, in Kubernetes (K8S), the orchestrator is an actor that behaves as a supervisor. It is responsible for monitoring all of the other services that are deployed in the cluster and ensuring that they're kept alive. If a service goes down, it will attempt to reboot it. The service is also an actor, as it can talk to other services. It can change its own state (e.g. in-memory or with a database), but it cannot (or should not) reach into other services to do the same.

Kafka offers three concepts of an actor: a producer, which is an actor that can only send messages; a consumer, which is an actor that can only receive messages ◊em{but also} create more producers to send messages; and a broker, which acts as a storage layer as well as a supervisor of sorts.
Kafka offers three concepts of an actor: a producer, which is an actor that can only send messages; a consumer, which is an actor that can only receive messages /but also/ create more producers to send messages; and a broker, which acts as a storage layer as well as a supervisor of sorts.

Similarly, an email inbox is another application of the pattern. Your email inbox is attached to one or more email addresses (or aliases), and messages that are meant for you are sent to your address (or many at once). Eventually, they will arrive in your inbox and you can then read the email and decide to archive it, delete it, report it as spam, and so on. This is also the case for a mailing list, where messages sent to the mailing list's address will eventually be distributed to every subscriber's address.



@@ 53,7 53,7 @@ Similarly, an email inbox is another application of the pattern. Your email inbo

Ruby's implementation of the actor model is called Ractor. There's a little bit of history here: it was originally called Guilds, and it's been in the making for a good few years now.

Ruby 3.0 introduces Ractor to the general community, however it is still marked as experimental. This means that the API may change in later versions, or behaviours may change based on feedback, and while you might be fine to run Ractors in production...well... ◊em{caveat emptor}◊^[10].
Ruby 3.0 introduces Ractor to the general community, however it is still marked as experimental. This means that the API may change in later versions, or behaviours may change based on feedback, and while you might be fine to run Ractors in production...well... /caveat emptor/◊^[10].

First things first, quick recap on Actors:



@@ 63,7 63,7 @@ First things first, quick recap on Actors:
  ◊li{An actor can mutate its own state but not another actor's state}
}

In order to guarantee thread-safety, some aspects of the language have had to change. Most objects in Ruby are unshareable by default, which is different to how a ◊code{Thread} behaves, and this means that code inside a ractor essentially cannot read ◊em{anything} outside of its own scope, which includes global variables and constants.
In order to guarantee thread-safety, some aspects of the language have had to change. Most objects in Ruby are unshareable by default, which is different to how a ◊code{Thread} behaves, and this means that code inside a ractor essentially cannot read /anything/ outside of its own scope, which includes global variables and constants.

Rather than rewording the Ruby manual on Ractors◊^[11], let's dig into a practical example and build a basic echo server over TCP.


M posts/ruby-sorcery.org => posts/ruby-sorcery.org +3 -3
@@ 9,11 9,11 @@

I recently realised that despite many new additions to the Ruby language and ecosystem, I've never really had an opportunity to take advantage of many of them. Of course, some new language features are more useful than others, particularly when it comes to maintaining code as a team, but what is also interesting is that they also support less conventional, or immediately-apparent, use-cases.

The first part of this series of posts is all about ◊em{Pattern Matching}.
The first part of this series of posts is all about /Pattern Matching/.

◊h2{Pattern matching}

Ruby's pattern matching support, introduced experimentally in 2.7, is a lot more powerful than you may expect. All you need is to replace ◊code{when} with ◊code{in} and your ◊code{case} statements become capable of matching against ◊em{anything}.
Ruby's pattern matching support, introduced experimentally in 2.7, is a lot more powerful than you may expect. All you need is to replace ◊code{when} with ◊code{in} and your ◊code{case} statements become capable of matching against /anything/.

◊codeblock['ruby]{
  require 'base64'


@@ 104,7 104,7 @@ That's fairly basic, what about pattern matching poker? Matching one card is eas
  end
}

Now that a hand of cards is represented, it should be possible to use pattern matching to find a winning play, say... a Royal Flush. For this to work, ◊em{variable pinning} is required, because a Royal Flush requires the colour and suit to be the same for each card.
Now that a hand of cards is represented, it should be possible to use pattern matching to find a winning play, say... a Royal Flush. For this to work, /variable pinning/ is required, because a Royal Flush requires the colour and suit to be the same for each card.

This particular solution depends on the hand being ordered, but that's fine, a lot of computational problems become simpler if you sort them first. For the sake of example, assume that has already happened.


M posts/the-bookshelf.org => posts/the-bookshelf.org +4 -4
@@ 6,7 6,7 @@
:CATEGORY: personal
:END:

They say you can learn a lot about a person by the contents of their bookshelf. If you were to look at mine you'd see the beginnings of a hoarding mentality. Not unlike my Steam library, there are some books on my shelf that I will probably never read. But at least I can be pretentious and say I have them, so long as I can bullshit my way through any conversation about them. Yes, I'm talking about you, ◊em{Structure and Interpretation of Computer Programs}.
They say you can learn a lot about a person by the contents of their bookshelf. If you were to look at mine you'd see the beginnings of a hoarding mentality. Not unlike my Steam library, there are some books on my shelf that I will probably never read. But at least I can be pretentious and say I have them, so long as I can bullshit my way through any conversation about them. Yes, I'm talking about you, /Structure and Interpretation of Computer Programs/.

There's quite an eclectic mix, all things considered, although many of the books are more useful as references rather than things I'd read cover-to-cover. I've got a few books about Complex PTSD--which is something about my mental health that I have to deal with--and a bunch of books relating to coaching, which has been one of my ways of dealing with it. The same can be said for the few books I have relating to Tantra, Sanskrit and spirituality in general.



@@ 19,9 19,9 @@ I added a few new books to the collection this year, and have been reading them 

◊h2{The Phoenix Project}◊^[1]

As far as Corporate Thrillers for Business Analysts go, The Phoenix Project easy enough to read and has some entertainment value. The cast is awash with wholly unsympathetic characters, the corporate setting oozes with toxicity, and it's impossible to turn a page without ◊em{someone} being an asshole.
As far as Corporate Thrillers for Business Analysts go, The Phoenix Project easy enough to read and has some entertainment value. The cast is awash with wholly unsympathetic characters, the corporate setting oozes with toxicity, and it's impossible to turn a page without /someone/ being an asshole.

I didn't rate it and if its follow up ◊em{The Unicorn Project} is any similar, then I think I'll give that one a pass. The Devops Handbook is still on my list, though.
I didn't rate it and if its follow up /The Unicorn Project/ is any similar, then I think I'll give that one a pass. The Devops Handbook is still on my list, though.

◊h2{Extreme Ownership}◊^[2]



@@ 29,7 29,7 @@ I had to keep an open mind when starting this one, but eventually I gave up beca

The book mostly follows a pattern of telling a war story (each one accompanied by a considerable body count) and then relating that experience to corporate leadership. As if the death of a few dozen Iraqis is comparable to a VP of Finance owning up to their failures to run a project.

Let's be fair, the advice is sound if you can put the chest beating and the hoo-rah to one side and focus purely on the advice. And the advice, taken outside of that context, ◊em{is} sound. But it's also shallow and, in essence, a vehicle for the authors to sell consulting and coaching services to business executives.
Let's be fair, the advice is sound if you can put the chest beating and the hoo-rah to one side and focus purely on the advice. And the advice, taken outside of that context, /is/ sound. But it's also shallow and, in essence, a vehicle for the authors to sell consulting and coaching services to business executives.

This one just wasn't for me.


M posts/the-goose-is-out.org => posts/the-goose-is-out.org +5 -5
@@ 6,7 6,7 @@
:CATEGORY: personal
:END:

I was browsing HN over my coffee this morning and came across an interesting thread◊^[1] linking to a post titled ◊em{When Buddhism Goes Bad}◊^[2]. That wasn't actually the title I read, as on HN the more neutral subtitle -- ◊em{How My Mindfulness Practice Led Me To Meltdown} -- was chosen instead.
I was browsing HN over my coffee this morning and came across an interesting thread◊^[1] linking to a post titled /When Buddhism Goes Bad}◊^[2]. That wasn't actually the title I read, as on HN the more neutral subtitle -- ◊em{How My Mindfulness Practice Led Me To Meltdown/ -- was chosen instead.

This is one of those posts I can relate to, at least in part, because of the experiences I've had myself. The thread on HN was itself interesting too, although ironically quite judgmental for a conversation about buddhism, meditation, and mindfulness. I'm not going to talk about those though--you can read those for yourself after all. Instead I'm going to offer my own perspective, now I can safely look back on the whole several-year long ◊del{ordeal}journey.



@@ 24,13 24,13 @@ Let's get one thing out of the way before I continue: yes, there are people out 

The story describes the obvious paradox of the situation: you can either break the bottle and keep the goose, or you can kill the goose and keep the bottle. You can't have both though. Ultimately, you are the goose and the bottle is your ego and the act of meditation allows you to become aware of your ego, outside of it, without breaking it.

But that's not ◊em{really} it, not for me anyway. Taking a grown-ass goose out of a glass bottle is difficult, but so is stuffing that goose back inside it. Geese are assholes; it's an easy way to get your ass kicked.
But that's not /really/ it, not for me anyway. Taking a grown-ass goose out of a glass bottle is difficult, but so is stuffing that goose back inside it. Geese are assholes; it's an easy way to get your ass kicked.

My journey took me through several therapists who specialised in the kind of approaches you won't find through the NHS. There was Reichian Breathwork◊^[4] at first, but then I mostly found specialists in Somatic Experiencing◊^[5]. At the same time I went on a few retreats that built their foundation on tantric practices◊^[6]. In a nutshell, basically a combination of meditative practice and therapy.

Had I not had the support of a therapist, a remarkably close friend, and all of my other closest frients, I would be another person writing about how meditation fucked me up--How Tantra Went Tits Up. I ended up in an absolutely ◊em{terrible} state: depression out of control, suicidal, self-harming, and barely functional without breaking down or spending hours soaking my pillow with my face.
Had I not had the support of a therapist, a remarkably close friend, and all of my other closest frients, I would be another person writing about how meditation fucked me up--How Tantra Went Tits Up. I ended up in an absolutely /terrible/ state: depression out of control, suicidal, self-harming, and barely functional without breaking down or spending hours soaking my pillow with my face.

Basically, the years of therapy, and the intertwining meditative practices, were revealing so much stuff--◊em{repressed} stuff--from my past and I just didn't have the resource or the faculty to cope with the onslaught of realisation. My coping mechanisms weren't that great in the first place, which is why I had my therapist.
Basically, the years of therapy, and the intertwining meditative practices, were revealing so much stuff--/repressed/ stuff--from my past and I just didn't have the resource or the faculty to cope with the onslaught of realisation. My coping mechanisms weren't that great in the first place, which is why I had my therapist.

A different goose was out, and there was no chance of putting it back in. You can't just take a realisation you don't like and re-repress it into the farthest reaches of your mind again, you have to deal.



@@ 40,7 40,7 @@ In other words, the goose is out and you've formed a co-dependent relationship w

There's a lot of detail missing in this post so far, I've only focussed on the difficult bits and left out the many beautiful moments that were truly astonishing, and the other bajillion moments that were all different kinds of positive and memorable. As the original post that spurred this one stated, people don't often talk about the difficult bits, you just get the glossy brochure promising bliss, abundant light, and inner peace. And you get plenty of others looking for somewhere to place the blame.

Honestly, I didn't really get out of that therapy trap I dug for myself until I went on medication and spent around 18 months just taking each day as it came. That gave me enough time and space to integrate all of the stuff I'd learned, dealt with, and realised over the previous six years, without trying to ◊em{do more}. That's really all I needed to let everything properly digest and I certainly feel more resilient for it now.
Honestly, I didn't really get out of that therapy trap I dug for myself until I went on medication and spent around 18 months just taking each day as it came. That gave me enough time and space to integrate all of the stuff I'd learned, dealt with, and realised over the previous six years, without trying to /do more/. That's really all I needed to let everything properly digest and I certainly feel more resilient for it now.

I've more or less closed the book on that chapter of my life, but that's not to say that it hasn't shaped the chapters to come--and significantly so. Whoever this person is now, I think he's hugely better off than he was before it all. And this particular goose of his has been successfully tamed (or at least I hope so).


M posts/things-ive-changed-my-mind-on.org => posts/things-ive-changed-my-mind-on.org +2 -2
@@ 6,7 6,7 @@
:CATEGORY: programming
:END:

Earlier today I read a blog post titled ◊em{Software development topics I've changed my mind on after 6 years in the industry}◊^[1] and it made me reflect on how my own thinking has (hopefully) evolved over my decade long career. I'm not going to discuss the content of the linked post, except to say that as much as I empathise with the author and have been an angry programmer myself, the overly aggressive tone that occasionally slips out isn't really my cup of tea.
Earlier today I read a blog post titled /Software development topics I've changed my mind on after 6 years in the industry/◊^[1] and it made me reflect on how my own thinking has (hopefully) evolved over my decade long career. I'm not going to discuss the content of the linked post, except to say that as much as I empathise with the author and have been an angry programmer myself, the overly aggressive tone that occasionally slips out isn't really my cup of tea.

A lot of things can happen in ten years, and if nothing else my 30-something year old self feels substantially less enlightened than his more youthful counterpart. I look forward to reading this again in future and seeing what I think about it then.



@@ 20,7 20,7 @@ Corrollary: Having an answer to everything (or being overconfident) is a hard ha

One idea is to set up an innovation budget◊^[2], but it's not the only one.

◊h3{PHP is a legitimate--if not ◊em{superior}--option to start a new project with and it deserves another chance.}
◊h3{PHP is a legitimate--if not /superior}--option to start a new project with and it deserves another chance./

The language has matured spectacularly since 7.1 onwards.


M posts/time-travel.org => posts/time-travel.org +12 -12
@@ 6,9 6,9 @@
:CATEGORY: personal
:END:

Once upon a time, a ◊em{golden oldie} referred to a song released in the 50s, 60s or 70s, and modern music doesn't really go much further back than that.
Once upon a time, a /golden oldie/ referred to a song released in the 50s, 60s or 70s, and modern music doesn't really go much further back than that.

More generally, it's the music your parents would listen to if you're around my age (early/mid thirties). You know, ◊em{you whippersnappers wouldn't know good music if it slapped you in the face}, ◊em{you kids don't half listen to some tripe these days}. Classic get-off-my-lawn commentary from the older generation.
More generally, it's the music your parents would listen to if you're around my age (early/mid thirties). You know, /you whippersnappers wouldn't know good music if it slapped you in the face}, ◊em{you kids don't half listen to some tripe these days/. Classic get-off-my-lawn commentary from the older generation.

It's only a matter of time before the latest cohort of unruly youth passes their first decade of onboarding and sees _me_ as one of the older generation.



@@ 20,13 20,13 @@ Continue reading if you'd like to join me on a musical trip down memory lane.

◊h2{Grizzly Bear - Veckatimest (2009)}

◊em{Two Weeks} was arguably the hit single from Grizzly Bear's sophomore record and it got major play time on XFM and BBC Radio 6. I would eventually get massively into this band and see them play live in Leeds, but that's not what I remember so vividly.
/Two Weeks/ was arguably the hit single from Grizzly Bear's sophomore record and it got major play time on XFM and BBC Radio 6. I would eventually get massively into this band and see them play live in Leeds, but that's not what I remember so vividly.

I worked as a cashier and early-morning change-runner at my local Tesco back then, and during one break time received a Facebook message from the cousin of one my friends, who was from Sacramento in California if I remember correctly. She asked if I could pick her up from Manchester Airport and I thought, heh, why not? This was the beginning of a whirlwind romance that ended just as quickly as it started (blink and you'd miss it) and ◊em{Veckatimest} was the soundtrack to it all.
I worked as a cashier and early-morning change-runner at my local Tesco back then, and during one break time received a Facebook message from the cousin of one my friends, who was from Sacramento in California if I remember correctly. She asked if I could pick her up from Manchester Airport and I thought, heh, why not? This was the beginning of a whirlwind romance that ended just as quickly as it started (blink and you'd miss it) and /Veckatimest/ was the soundtrack to it all.

It was the height of summer and the weather was glorious. I showed her the sights around Manchester, she showed me how to dance the way she did back home. It was wild and not meant to be.

Whenever I listen to ◊em{Two Weeks} I'm instantly transported back into my little blue Ford Ka, scooting down the M61 towards Chorley with the windows open, the cool breeze, and the blazing sun bearing down upon us.
Whenever I listen to /Two Weeks/ I'm instantly transported back into my little blue Ford Ka, scooting down the M61 towards Chorley with the windows open, the cool breeze, and the blazing sun bearing down upon us.

This was probably one of the first times I really embraced spontaneity and went with the flow, although it was also a point in time where I was unaware of several issues that I would later struggle with. A lot.



@@ 34,9 34,9 @@ Oh to be ignorant.

◊h2{Arctic Monkeys - AM (2013)}

I was hooked by the Arctic Monkeys as soon as I heard their first single, ◊em{I Bet That You Look Good On The Dancefloor}, a little bit before they released their debut album in 2006. I can still put on ◊em{Whatever People Say I Am, That's What I'm Not} and recite the lyrics from heart, as I'd sing along with it in the car so much when driving home from sixth-form, or from meeting friends further up in Lancashire.
I was hooked by the Arctic Monkeys as soon as I heard their first single, /I Bet That You Look Good On The Dancefloor}, a little bit before they released their debut album in 2006. I can still put on ◊em{Whatever People Say I Am, That's What I'm Not/ and recite the lyrics from heart, as I'd sing along with it in the car so much when driving home from sixth-form, or from meeting friends further up in Lancashire.

◊em{AM}, however, is something else. I lived in Poplar in East London then and would commute to work from the DLR at All Saints, passing through Poplar and then into Bank or Tower Hill. By the time I got past Poplar, ◊em{Arabella} would begin and I'd stare out of the window towards Canary Wharf as the DLR pootled past, watching the strange new Crossrail station come to form as each diamond-shaped glass panel was fitted into place across the days, weeks... months.
/AM}, however, is something else. I lived in Poplar in East London then and would commute to work from the DLR at All Saints, passing through Poplar and then into Bank or Tower Hill. By the time I got past Poplar, ◊em{Arabella/ would begin and I'd stare out of the window towards Canary Wharf as the DLR pootled past, watching the strange new Crossrail station come to form as each diamond-shaped glass panel was fitted into place across the days, weeks... months.

I've always enjoyed riding the DLR over using the Tube or traditional trains, and I wonder if part of it is because of moments like that.



@@ 48,7 48,7 @@ Blossom was released while I was living in and working remotely from Jūrmala, L

While I worked remotely, I didn't work very much from my flat at the Dzintari side of Jūrmala. I did a fair bit from the train and from various coffee shops in the capital and near the flat.

On this day in particular, again in the middle of summer, I had my Discover Weekly playlist on and ◊em{Doing Good} started as I walked through the city to my appointment. I was just passing ◊em{Latvijas Nacionālā opera} as it happened and felt compelled to take a quick detour towards it, and the nice garden in front.
On this day in particular, again in the middle of summer, I had my Discover Weekly playlist on and /Doing Good} started as I walked through the city to my appointment. I was just passing ◊em{Latvijas Nacionālā opera/ as it happened and felt compelled to take a quick detour towards it, and the nice garden in front.

This is one of many memories, but it sticks in my mind because I moved to Latvia after spending two years in Barcelona, and I did it fully knowing that I would be leaving my BCN friends and support network behind and essentially starting anew.



@@ 60,19 60,19 @@ I miss that feeling.

◊h2{The Killers - Hot Fuss (2004)}

◊em{Hot Fuss} was the first album I ever bought with my own money. It's hard to point to one specific moment for this, but it takes me right back to my teenage years.
/Hot Fuss/ was the first album I ever bought with my own money. It's hard to point to one specific moment for this, but it takes me right back to my teenage years.

I grew up in Salford, in the north west of England, and so most of my formative years were spent between Manchester and Bolton. A bit of Lancs and a bit of Manc.

Manchester in particular is an amazing cultural hotspot for music and The Killers themselves sought to emulate that with their debut album. There was Joy Division, New Order, Happy Mondays, The Stone Roses, and an entire scene known as ◊em{Madchester}. That was itself a bit before my time as I was only a toddler when it all kicked off, but it has left an indelible mark on the city.
Manchester in particular is an amazing cultural hotspot for music and The Killers themselves sought to emulate that with their debut album. There was Joy Division, New Order, Happy Mondays, The Stone Roses, and an entire scene known as /Madchester/. That was itself a bit before my time as I was only a toddler when it all kicked off, but it has left an indelible mark on the city.

Elbow might be one of my absolute favourite Mancunian exports. Oasis is often met with a sigh but they did put out some pure fuckin' belters.

But I digress. ◊em{Mr Brightside} is the song of every night I went out clubbing with my friends, or with workmates from Tesco at the time, or both.
But I digress. /Mr Brightside/ is the song of every night I went out clubbing with my friends, or with workmates from Tesco at the time, or both.

It's the song of the foam parties at 5th Avenue (fondly known as 5th Chav) we'd feverishly anticipate on every bank holiday, starting at around 8pm on the Sunday night and ending in a taxi trip home at 3am smelling like washing up liquid mixed with £1 vodka red bulls. It's the song of more expensive, foamless nights at 42nd Street (fondly known as 42s), but 5th Ave was where it was at.

Towards the end you'd get ◊em{Mr Brightside} and ◊em{I Am The Resurrection}, practically a Manc anthem, and just as the beat dropped and built back up the floodgates would open and unthinkable quantities of lathered up soap would be splattered across the dancefloor, soaking into your clothes, getting into your eyes, tainting your cheap drink, and coating your lungs as you yelled along to the lyrics and bounced blindly across the room to link arms with whoever else was nearby. It was romantic in its own way.
Towards the end you'd get /Mr Brightside} and ◊em{I Am The Resurrection/, practically a Manc anthem, and just as the beat dropped and built back up the floodgates would open and unthinkable quantities of lathered up soap would be splattered across the dancefloor, soaking into your clothes, getting into your eyes, tainting your cheap drink, and coating your lungs as you yelled along to the lyrics and bounced blindly across the room to link arms with whoever else was nearby. It was romantic in its own way.

It's the song of practically every single night I spent on the town, visiting the handful of indie clubs we had between Manchester and Bolton.


M posts/to-simpler-times.org => posts/to-simpler-times.org +2 -2
@@ 16,7 16,7 @@ I've tripped up on this a few times lately because I was locked into a certain w

The first issue was how this site is built. Hakyll is a library for building a static site generator (SSG), so you build your own program using Hakyll's functions, add in whatever else you want because it's a simple Haskell program, and then use the resulting binary to convert your markdowns and org-modes and LaTeXes (LaTiCeS?) into beautiful HTML.

Naturally I had to keep this binary stored somewhere because re-running a 30+ minute build is a little bit wasteful (Hakyll pulls in pretty much ◊em{all} of Pandoc). At first, I gravitated towards using build caches in CI or temporary artifact stores, and so long as they didn't expire I wouldn't trigger a rebuild. Then there was some exploration around binary caches in Haskell, or using a service like bintray to host the file.
Naturally I had to keep this binary stored somewhere because re-running a 30+ minute build is a little bit wasteful (Hakyll pulls in pretty much /all/ of Pandoc). At first, I gravitated towards using build caches in CI or temporary artifact stores, and so long as they didn't expire I wouldn't trigger a rebuild. Then there was some exploration around binary caches in Haskell, or using a service like bintray to host the file.

Even though it worked it all felt a bit... manky. It's clearly not the way software has been distributed for a long time, and the idea of hopping from one SaaS to another on their free or open source accounts is just not a good one. But alas, that's where we find ourselves these days.



@@ 63,7 63,7 @@ The site has moved once again, back to a VPS hosted somewhere in the UK. Caddy

Deploying to this server is a case of firing off a couple of ◊code{ssh}, ◊code{scp} or ◊code{rsync} requests using a separate user with its own SSH key, and as soon as the command is finished running the changes are visible online.◊^[5]

This leads me to the final bit. Modern tech feels more complicated as it tends towards distributed solutions: put thing ◊em{x} here, deploy service ◊em{y} there, sync them up with webhooks, and hope the network holds up to the task. Earlier tech feels more complicated because the documentation is intricate and detailed and requires some fidgeting around with.
This leads me to the final bit. Modern tech feels more complicated as it tends towards distributed solutions: put thing /x} here, deploy service ◊em{y/ there, sync them up with webhooks, and hope the network holds up to the task. Earlier tech feels more complicated because the documentation is intricate and detailed and requires some fidgeting around with.

It took me just about a day to figure out how to host my own ◊code{apt} repository for Debian◊^[6], compiling information from various manuals, blog posts and examples. It was mostly a case of creating a GPG key and setting up a correct directory structure for ◊code{apt-ftparchive}◊^[7] to do its business, with a little bit of extra config. I'll go into detail about that another time, but let it be said it does the job tremendously in any Debian-based CI pipeline.


M posts/using-ruby-c-in-ruby.org => posts/using-ruby-c-in-ruby.org +3 -3
@@ 6,11 6,11 @@
:CATEGORY: programming
:END:

A thought occurred to me in my mask-wearing, lockdown-addled brain last night: why the hell did I choose ◊em{now} to stop drinking? It's for my own good, I told myself, and so my thoughts shifted further into the absurd with nary a mind-altering substance in sight to stop them.
A thought occurred to me in my mask-wearing, lockdown-addled brain last night: why the hell did I choose /now/ to stop drinking? It's for my own good, I told myself, and so my thoughts shifted further into the absurd with nary a mind-altering substance in sight to stop them.

One of those thoughts stuck out in particular, because of how ridiculous it sounded: could you optimise your Ruby code by using FFI with Ruby's C bindings? I'm not talking about making a native extension in pure C, I'm talking about making Ruby talk to itself through a foreign function interface using the ffi gem◊^[1].

Let's apply some method to this madness and set up some bindings, otherwise we're dead in the water. Let's be descriptive and call our FFI module ◊code{LibRuby}. No naming conflicts at all there, ◊em{no sirree}!
Let's apply some method to this madness and set up some bindings, otherwise we're dead in the water. Let's be descriptive and call our FFI module ◊code{LibRuby}. No naming conflicts at all there, /no sirree/!

◊codeblock['ruby]{
  require 'ffi'


@@ 83,7 83,7 @@ For every step in this post up to creating a ◊code{String} object, we've been 

The string object is different, however, as on the C side of things Ruby is taking a pointer to a C string (a ◊code{const char *}), allocating memory, and giving back a pointer to the new object. Eventually the GC will run and free up the memory at the pointer's address, and the string will no longer exist. You'll probably find something else at that address instead, or just garbage.

Disabling the GC in this instance is a ◊strong{shitty hack} because it's a direct admission that the code is ◊em{not memory safe}. Hopefully you didn't need me to tell you that, though, and the quality of the code in this post was self-evident.
Disabling the GC in this instance is a ◊strong{shitty hack} because it's a direct admission that the code is /not memory safe/. Hopefully you didn't need me to tell you that, though, and the quality of the code in this post was self-evident.

How would you fix it? Well, now we've found out that we ◊code{can} write Ruby with itself we'll explore that next time. And there'll be benchmarks, too.