Reading List

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

A blog post is a very long and complex search query to find fascinating people and make them route interesting stuff to your inbox

A lovely essay by Henrik Karlsson on writing, blogging, and the power of the internet.

When writing in public, there is a common idea that you should make it accessible. This is a left over from mass media. Words addressed to a large and diverse set of people need to be simple and clear and free of jargon. […]

That is against our purposes here. A blog post is a search query. You write to find your tribe; you write so they will know what kind of fascinating things they should route to your inbox. If you follow common wisdom, you will cut exactly the things that will help you find these people.

Fibonacci estimates

Estimating software projects will never be my strong suit, but I've learned using numbers from the Fibonacci sequence to judge the size sets me off to a good start.

To estimate a task (in hours or days), I only use numbers from the Fibonacci sequence:

1, 2, 3, 5, 8, 13, 21, 34, 55…

The further along the Fibonacci sequence, the bigger the difference with the next number becomes. This aligns well with how we should estimate, because the bigger the task, the more unknowns there are.

How I built customizable themes using CSS custom properties & HSL

I published an article on the Mailcoach blog explaining the setup around customizable themes for newsletter archives.

I relied on CSS custom properties and HSL colors to allow users to customize their newsletter archives without fiddling with too many options.

Colors are often defined in RGB, but RGB is difficult to transform without custom functions. We ask the user to define the primary color in HSL instead. The benefit of HSL is that it’s easy to control a color by tweaking the parameters.

PHP wishlist: Nested properties

Next on my PHP wishlist are nested properties. This idea is less realistic than others, it’s more me thinking out loud. I don’t have a good syntax proposal for this, and I’m not even sure it’s the best solution for my problem. But it’s the best I’ve come up with so far.

When I want a typed object, I need to create a class in a new file, and give it a name. (While technically not required, one class per file is highly recommended to work well with tools and IDEs we have to our disposal.)

It’s too expensive to add types in PHP.

As an example, let’s build a headless CRM. We’ll start with a ContactResource class. A Resource class is a JSON-serializable class that can be used in an API response. It can be created from an entity or model.

class ContactResource extends Resource
{
public function __construct(
public int $id,
public string $name,
public string $email,
) {
}
public static function fromContact(Contact $contact): self
{
return new self(
id: $contact->id,
name: $contact->name,
email: $contact->email,
);
}
}

In addition to the contact’s attributes, I want to add a list of related endpoints to exposed through the API. While I could set an associative array, I prefer types because they’re strict, explicit, support IDE autocompletion, and allow tools to process them with reflection.

I’ll create a ContactResourceEndpoints class and file, and add it as a property to ContactResource

// ContactResourceEndpoints.php
class ContactResourceEndpoints
{
public function __construct(
public string $index,
public string $store,
public string $update,
public string $delete,
) {
}
}
// ContactResource.php
class ContactResource extends Resource
{
public function __construct(
public int $id,
public string $name,
public string $email,
public ContactResourceEndpoints $endpoints,
) {
}
public static function fromContact(Contact $contact): self
{
return new self(
id: $contact->id,
name: $contact->name,
email: $contact->email,
endpoints: new ContactResourceEndpoints(
index: action([ContactController::class, 'index']),
store: action([ContactController::class, 'store']),
update: action([ContactController::class, 'update'], $contact->id),
delete: action([ContactController::class, 'delete'], $delete->id),
),
);
}
}

Having to maintain another file, in another place, with another name adds a lot of friction. This pushes developers to use less types (by using an assiative array) or worse: create the wrong abstraction (abstract class Endpoints is not a good use of inheritence).

More downsides:

  • ContactResourceEndpoints isn’t meant to be used anywhere else, so it doesn’t warrant its own name or class.
  • Looking at the constructor, it’s not clear which properties are in ContactResource, I need to click through to a deeper class to get all the information.
  • We could inline the properties on ContactResource, but besides looking messy it can cause clashes.

In TypeScript, these tradeoffs don’t exist as you can nest objects in your type declarations.

type ContactResource = {
id: string;
name: string;
email: string;
endpoints: {
index: string;
store: string;
update: string;
delete: string;
};
}

I’d love to see something similar in PHP.

class ContactResource extends Resource
{
public function __construct(
public int $id,
public string $name,
public string $email,
public $endpoints: (
string $index,
string $store,
string $update,
string $delete,
),
) {
}
public static function fromContact(Contact $contact): self
{
return new self(
id: $contact->id,
name: $contact->name,
email: $contact->email,
endpoints: (
index: action([ContactController::class, 'index']),
store: action([ContactController::class, 'store']),
update: action([ContactController::class, 'update'], $contact->id),
delete: action([ContactController::class, 'delete'], $delete->id),
),
);
}
}

Removing the need for another file makes it cheaper to add proper types to your objects. Nested properties are also “anonymous” as they don’t have a name, which restricts them to be reused.

This is not an RFC, and there’s a fair chance this syntax will clash with another PHP feature. But bear with me; this is just an idea I’m throwing on the table. I’d love to hear other viewpoints!


More on my PHP wishlist:

Event sourcing on PHP Annotated

I had the pleasure to have a conversation with Brent on PHP Annotated about event sourcing.

We talked about event sourcing in general, benefits, difficulties, and how we’re using it in production.