Reading List

The most recent articles from a list of feeds I subscribe to.

Named arguments

I shiver at the sight of a function packed with too-many-to-read-at-a-glance arguments without a description. Especially boolean flags. Boolean flags lack context. Look at this code, I have no idea what false, false, true conveys.

$page->render(false, false, true);

A pattern I often see in older code is an associative array as the single parameter. At least the intent is clear, but arrays lack IDE completion and type safety.

$page->render([
'footer' => false,
'header' => false,
'include_assets' => true,
]);

After another round of refactoring, we might end up with a bunch of fluent methods on the object.

$page
->showFooter(false)
->showHeader(false)
->includeAssets()
->render();

The fluent builder removes our gripes and provides IDE completion and type safety, but I’m not content yet. Fluent builders explode the size of an object’s public API surface.

class Page
{
private bool $showFooter = true;
private bool $showHeader = true;
private bool $includeAssets = false;
public function showFooter(bool $showFooter): self
{
$this->showFooter = $showFooter;
return $this;
}
public function showHeader(bool $showHeader): self
{
$this->showHeader = $showHeader;
return $this;
}
public function includeAssets(bool $includeAssets): self
{
$this->includeAssets = $includeAssets;
return $this;
}
//
}

That’s all boilerplate, and doesn’t even include alternative methods like withoutFooter(). It also introduces a bunch of internal (mutable) state.

$firstRender = $page
->showFooter(false)
->showHeader(false)
->includeAssets()
->render();
$secondRender = $page
->showFooter(false)
->render();

The second render wil also exclude the header and include the assets because we mutated the state earlier. We could rewrite our object to be immutable, that would lead to a more consistent implementation but introduce even more boilerplate code.

The year is now 2020 2022, and another option has presented itself: named arguments.

$page->render(
footer: false,
header: false,
includeAssets: true,
);

To me, named arguments provide the best of all worlds. Proper IDE support, type safety, no internal state required, keeps the object’s public methods to a minimum.

I didn’t expect to appreciate them so much, but I think they’re my favorite addition to PHP in a while.

Granular interfaces

A few weeks ago a spec change for an application we’re working on forced us to refactor part of the codebase. It was food for thought about the flexibility granular interfaces provide, and choosing the right abstraction at the right time. This is a short writeup on the thought process we went through as we updated our logic to support a new feature now and allow more options in the future.


Imagine we were hired to build a course platform. We’re working on the code that grants access to a course after a user purchased it.

First, we’ll create a course object with a Purchasable interface to indicate it can be purchased, and a Registrable interface to indicate a registration should be created after the customer has paid.

class Course implements Purchasable, Registrable
{
}

Somewhere down the line in our checkout code, we can loop over the order items and create registrations for each registrable product we come across.

foreach ($order->items as $orderItem) {
if ($orderItem->purchasable instanceof Registrable) {
createRegistration($orderItem->purchasable);
}
}

Later on, the client asks how they can sell a bundle of courses. Purchasing a bundle would register a customer for a bunch of courses at once.

Since a bundle can be purchased, it will implement the Purchasable interface. However, implementing the Registrable interface wouldn’t make sense. After the bundle is purchased, registrations need to be created for the underlying courses, not the bundle itself.

class Bundle implements Purchasable
{
public function __construct(
public array $courses
) {
}
}

This shows that the Registrable interface has not one but two responsibilities. It indicates that something can be tied to a registration, and it tells the system to create registrations after payment.

A course fulfills both responsibilities, but a bundle only needs to provision. Let’s introduce a new CreatesRegistrations interface only to create registrations.

class Bundle implements Product, CreatesRegistrations
{
public function __construct(
public array $courses
) {
}
public function createsRegistrationsFor(): array
{
return $this->courses;
}
}

In our checkout code, we add another check for the new interface.

foreach ($order->items as $orderItem) {
if ($orderItem->purchasable instanceof Registrable) {
createRegistration($cartItem->purchasable);
}
if ($orderItem->purchasable instanceof CreatesRegistrations) {
foreach ($orderItem->purchasable->createsRegistrationsFor() as $registrable) {
createRegistration($registrable);
}
}
}

That solves our problem, but our checkout code is getting bloated. Even worse, there are now two ways to tell our system a product will create registrations. If we want to know wether a product will create a registration, we have to check for both the Registrable and CreatesRegistrations interfaces.

We can consolidate the behavior to always use our CreatesRegistrations interface. The Course object can return a reference to itself.

class Course implements Product, Registrable, CreatesRegistrations
{
public function providesRegistrationsFor(): array
{
return [$this];
}
}

And we can revert our checkout code is back to one createRegistration call.

foreach ($order->items as $orderItem) {
if ($orderItem->product instanceof ProvidesRegistrations) {
foreach ($orderItem->product->providesRegistrationsFor() as $registrable) {
createRegistration($registrable);
}
}
}

After refactoring to a granular interface, our system became more flexible and composable. Small interfaces communicate intent more clearly, making it easier to understand the flow of a system.

That doesn’t mean we should be paralyzed to find the perfect abstraction before we start. We only realized our interface wasn’t granular enough after it grew out of its original use case. As a system evolves, abstractions should arise from current needs, not future possibilities.


As mentioned on Twitter, this guideline is formalized in the “I” in SOLID: the interface segregation principle.

Granular interfaces

A few weeks ago a spec change for an application we’re working on forced us to refactor part of the codebase. It was food for thought about the flexibility granular interfaces provide, and choosing the right abstraction at the right time. This is a short writeup on the thought process we went through as we updated our logic to support a new feature now and allow more options in the future.


Imagine we were hired to build a course platform. We’re working on the code that grants access to a course after a user purchased it.

First, we’ll create a course object with a Purchasable interface to indicate it can be purchased, and a Registrable interface to indicate a registration should be created after the customer has paid.

class Course implements Purchasable, Registrable
{
}

Somewhere down the line in our checkout code, we can loop over the order items and create registrations for each registrable product we come across.

foreach ($order->items as $orderItem) {
if ($orderItem->purchasable instanceof Registrable) {
createRegistration($orderItem->purchasable);
}
}

Later on, the client asks how they can sell a bundle of courses. Purchasing a bundle would register a customer for a bunch of courses at once.

Since a bundle can be purchased, it will implement the Purchasable interface. However, implementing the Registrable interface wouldn’t make sense. After the bundle is purchased, registrations need to be created for the underlying courses, not the bundle itself.

class Bundle implements Purchasable
{
public function __construct(
public array $courses
) {
}
}

This shows that the Registrable interface has not one but two responsibilities. It indicates that something can be tied to a registration, and it tells the system to create registrations after payment.

A course fulfills both responsibilities, but a bundle only needs to provision. Let’s introduce a new CreatesRegistrations interface only to create registrations.

class Bundle implements Product, CreatesRegistrations
{
public function __construct(
public array $courses
) {
}
public function createsRegistrationsFor(): array
{
return $this->courses;
}
}

In our checkout code, we add another check for the new interface.

foreach ($order->items as $orderItem) {
if ($orderItem->purchasable instanceof Registrable) {
createRegistration($cartItem->purchasable);
}
if ($orderItem->purchasable instanceof CreatesRegistrations) {
foreach ($orderItem->purchasable->createsRegistrationsFor() as $registrable) {
createRegistration($registrable);
}
}
}

That solves our problem, but our checkout code is getting bloated. Even worse, there are now two ways to tell our system a product will create registrations. If we want to know wether a product will create a registration, we have to check for both the Registrable and CreatesRegistrations interfaces.

We can consolidate the behavior to always use our CreatesRegistrations interface. The Course object can return a reference to itself.

class Course implements Product, Registrable, CreatesRegistrations
{
public function providesRegistrationsFor(): array
{
return [$this];
}
}

And we can revert our checkout code is back to one createRegistration call.

foreach ($order->items as $orderItem) {
if ($orderItem->product instanceof ProvidesRegistrations) {
foreach ($orderItem->product->providesRegistrationsFor() as $registrable) {
createRegistration($registrable);
}
}
}

After refactoring to a granular interface, our system became more flexible and composable. Small interfaces communicate intent more clearly, making it easier to understand the flow of a system.

That doesn’t mean we should be paralyzed to find the perfect abstraction before we start. We only realized our interface wasn’t granular enough after it grew out of its original use case. As a system evolves, abstractions should arise from current needs, not future possibilities.


As mentioned on Twitter, this guideline is formalized in the “I” in SOLID: the interface segregation principle.

Using markdown in HTML (in markdown) in Hugo

The markdown specification allows you to inline HTML in a markdown document.

This is a regular paragraph.
<table>
<tr>
<td>Foo</td>
</tr>
</table>
This is another regular paragraph.

But once you’re in HTML, you can’t write markdown anymore. If you’d want to italicize Foo, this won’t work:

<table>
<tr>
<td>*Foo*</td>
</tr>
</table>

On my blog, I sometimes want to wrap a whole chunk of markdown in an HTML, like a div with a class name.

<div class="highlight">
This is [markdown](https://daringfireball.net/projects/markdown/syntax#html).
</div>

The solution is a custom shortcode, located in layouts/shortcodes/markdown.html.

{{ .Inner }}

The shortcode does nothing more than parse the inner contents as markdown. So I can happily switch back to markdown from HTML.

<div class="highlight">
{{% markdown %}}
This is [markdown](https://daringfireball.net/projects/markdown/syntax#html).
{{% /markdown %}}
</div>

There might be a more idiomatic way to do this but I haven’t come across any clues. If there is I’d love to know about it, but for now this works like a charm.

Non-reactive data in Alpine.js

Sometimes you want to store data in your Alpine component without wrapping it in a JavaScript proxy (which is how Alpine keeps everything reactive).

For example, third party libraries might have issues when wrapped in a proxy. Chart.js is one of those. If you store a Chart.js instance in Alpine data, the chart will error.

To prevent Alpine from making the property reactive, the property shouldn’t be on the data object in the first place. One way to create state without storing it on an object is with the revealing module pattern.

<div x-data="chart">
<canvas x-ref="canvas"></canvas>
</div>
Alpine.data('chart', () => {
let chart;
return {
init() {
chart = new Chart(this.$refs.canvas, { … });
},
update() {
// Fetch new data…
chart.update();
},
};
});

With the revealing module pattern, the data is stored in a regular variable, and privately available in the component.

If you need to expose it to the outside world, you can add a getter.

Alpine.data('chart', () => {
let chart;
return {
init() {
chart = new Chart(this.$refs.canvas, { … });
},
// …
get chart() {
return chart;
},
};
});