Sven Luijten: Using interfaces in third-party packages

2024-01-11 #php /

A post on enums & interfaces. I didn't realize you could implement an interface on an enum!

This way you get the best of both worlds: the default implementations are neatly grouped in an enum, but others can extend using their own class implementing the interface.

enum ColorOption: string implements Color
case Red = 'red';
case Blue = 'blue';
case Green = 'green';
public function name(): string
return $this->value;

Tabular assertions with Pest

2024-01-09 #php #testing #pest

With tabular assertions, you describe the expected outcome in a markdown-like table format. Here's why there useful, and how to use tabular assertions with Pest.

Read more

Tabular assertions with PHPUnit

2024-01-09 #php #testing #phpunit

With tabular assertions, you describe the expected outcome in a markdown-like table format. Here's why there useful, and how to use tabular assertions with PHPUnit.

Read more

Introducing tabular assertions

2024-01-08 #php #testing #phpunit #pest

Today I tagged v1 of a new testing package: spatie/tabular-assertions. It's a distillation of a testing method I've been using in client projects the past two years. The package supports both PHPUnit and Pest out of the box.

With tabular assertions, you describe the expected outcome in a markdown-like table format.

| type | reason | price | paid |
| product | created | 80_00 | 80_00 |
| tax | created | 5_00 | 5_00 |
| tax | created | 10_00 | 10_00 |
| shipping | created | 5_00 | 5_00 |
| product | paid | 0_00 | 0_00 |
| tax | paid | 0_00 | 0_00 |
| tax | paid | 0_00 | 0_00 |
| shipping | paid | 0_00 | 0_00 |

Tabular assertions have two major benefits over other testing strategies: expectations are optimized for readability & failed assertions can display multiple errors at once.

Screenshot of a tabular assertion diff in PhpStorm

For an in-depth introduction to tabular testing, I've written two separate guides for Pest & PHPUnit.


I haven't come across this exact method anywhere else, so I had to come up with a name. If there's prior art that matches this with a better name, I'd love to know!

The idea was inspired by Jest, which allows you to use a table as a data provider.

Snapshot testing is also closely related to this. But snapshots aren't always optimized for readability, are stored in a separate file (not alongside the test), and are hard to write by hand (no TDD).

Tabular assertions have been a huge help when comparing large, ordered data sets like financial data or a time series. I hope you find it useful too!

Dan Abramov: The two Reacts

2024-01-08 #react #frontend /

Frontend frameworks often use the mental modal that a component (or entire UI) is the result of running state through a pure function. Dan Abromov shares his thoughts on the current state of React with server components.

UI = f(data)(state)

Here's how I interpret it: in the mental model we're used to, a component is a pure function that returns UI based on its props. In this case, a Greeter is rendered on the client.

function Greeter(props) {
return <p>Hello, {}!</p>;

Say we have a server component that know who needs to be greeted before the code hits the client. In that case, the name will come from data available on the server.

function Greeter(data) {
return function () {
return <p>Hello, {}!</p>;

The outer function is executed on the server, the inner on the client.

The true power lies in mixing and matching the paradigms. Say you want to read a translation string on the server, and greet a name on the client.

function Greeter(data) {
return function (props) {
return <p>{data.translations.hello}, {}!</p>;


2023-12-29 #misc

Before I launched Svelte by Example, I called for early access testers in this newsletter. I don't ask for feedback often, I had to push myself to do this.

Sometimes I'm scared of receiving feedback that I'll agree with, but would push back the release when I want to get it out. Sometimes I'm scared of receiving feedback that could invalidate the entire idea. Sometimes I know there are problems but hope they'll magically go away if I ignore them, feedback might resurface them. Sometimes I'm overconfident and don't think it's worth getting another opinion.

No good excuse to be found. These are fears, and it's worth getting over them. Because if any of them are rooted in truth, they'll com back and haunt me rather sooner than later.

A few people responded to my request (thank you!), and it quickly became clear the ask was worth it. The first version of Svelte by Example became way better because of it. The examples became more consistent, the design improved, a bunch of typos were edited out. I didn't process all feedback. Sometimes it doesn't match what you have in mind, and that's fine.

I've learned my lesson: time to get over myself and ask for feedback whenever I can.

Svelte 5 preview review

2023-12-27 #svelte

The Svelte team set up a miniature documentation site highlighting the new features coming to Svelte 5. Here's a quick review of my three favorites: runes, events, and snippets.

Read more

How not to update every package in existence, break your local environment, and spend the afternoon dealing with things you did not want to deal with when installing a package with Homebrew

2023-12-18 #cli

Friendly reminder that you can disable Homebrew's default auto update behaviour with HOMEBREW_NO_AUTO_UPDATE=1.

HOMEBREW_NO_AUTO_UPDATE=1 brew install git-secret

If you want to set and forget the setting, add it to your ~/.bashrc or ~/.zshrc.


The CSS scroll-margin property

2023-12-18 #css

Last week I remembered the scroll-margin property existed.

I was adding anchors to the headings of a page so visitors can directly link to a section. However, when that link was visited, the heading was glued against the top of the viewport. I prefer some margin between the browser chrome and the text to let it breath.

There's a CSS property for that: scroll-margin. It does nothing in most cases, but when you visit a URL that points to an anchor on the page, it will offset the element from the viewport.

h2 {
scroll-margin-top: 1rem;

You can read all about scroll-margin in the MDN docs.

Chris Coyier: '100 people'

2023-12-18 #project-management /

An interesting thought exercise on working together, what's the optimal number of people to work as a team without spoiling the broth?

Let’s say you have 100 people. They can break into groups of any size. Each group gets 100 toothpicks. The goal: build the tallest structure with the toothpicks. What is the optimal group size?

How Jim Nielsen takes & publishes notes

2023-12-13 #blogging /

I always enjoy reading about other people's processes.

99% of the time, this is how my note-taking process goes:

  • I’m catching up on my RSS feed (on my phone in the Reeder app)
  • I read something that strikes me as interesting, novel, or insightful.
  • I copy/paste it as an blockquote into a new, plain-text note in iA writer.
  • I copy/paste the link of the article into iA writer.
  • I finish reading the article and copy/paste anything else in the article that strikes me.
  • I add my own comments in the note as they pop into my head.
  • I move on to the next article in my RSS feed.
  • Repeat.


I like to let my notes sit for a couple days (or even weeks). I find that if I come back to a note and still find it interesting/insightful that means it’s worth keeping, so I put in the work of cleaning it up and publishing it.

Time is underestimated as a filter for content.

Cleaning up package.json keys

2023-12-11 #javascript #npm

I'm in the process of cleaning up some npm packages that haven't been touched in a while, and part of that is pruning all the cruft that has been accumulated in package.json over the years.

I was looking for a canonical order to sort the keys by, and thought the order the npm docs specify the configuration options made sense.

Of course, after manually sorting one package.json file—which probably took 2 minutes—I decided to spend 30 minutes to find our how I could automate sorting the other two.

Luckily there's an npm package for everything. With the sort-package-json package you can go sort your package.jsons in a logical order.

npx sort-package-json **/*/package.json

That's all I had to do to keep my monorepo clean and tidy.

Git gud at communication

2023-12-06 #pm /

Another blam on the Thunk blog:

Product Managers, Agile, and other product development processes solve communication problems. If everyone had telepathic powers, those problems would shrink or disappear. The next best thing to telepathy is a team who excels at communication. If your team communicates to bridge these knowledge gaps, your need for PMs and Agile will shrink.

iA on AI

2023-12-06 #ia /

A nuanced take on AI by the makers of iA Writer.

Rocks, pebbles, sand

2023-12-05 #pm /

A product management mindset from Jason Cohen.

If you do little things first, there’s no time for big things.
If do big things first, then you can fill in the smaller things.


It’s not important that every sprint is perfectly balanced between all types of work. It is important that we’re balanced over a period several months, otherwise something important is getting starved. Indeed, it’s often wise to build imbalanced sprints intentionally, because that means greater focus, less context-switching, and therefore getting more quality work done.