When I’m working on a feature or refactor, I often leave @todo comments to remain in flow and deal with other points later.
I don’t mind committing them to my feature branch, as long as I work them away before merging in.
On large branches, it can be easy to forget about that todo I left in there a few days ago.
class PodcastController
{
public function process(Podcast $podcast): void
{
$podcast->process();
// @todo Broadcast event to trigger webhooks
return $podcast;
}
Before I merge, I pipe git diff into a grep call to scan for changes that include @todo.
git --no-pager diff main..feature-branch | grep -i "^\+[^$]*@todo"
+ // @todo Broadcast event to trigger webhooks
If you want to double check your changes before comitting, you can use the same command with git diff HEAD.
git --no-pager diff HEAD | grep -i "^\+[^$]*@todo"
Pouring this in a bash function
Here’s a quick bash function to scan for todos:
function todos() {
git --no-pager diff ${1:"HEAD"} | grep -i "^\+[^$]*@todo"
}
Use it without an argument to look for todos you haven’t committed yet, or pass the revisions you want to compare between.
# Look at current changes
todos
# Look for todos added between main and feature-branch
todos main..feature-branch
In Laravel, you can register a class as a singleton to always resolve the same object.
However, you might want to build another instance of the class. You could manually construct the class without Laravel’s container, but if it has a bunch of dependencies it can be tedious.
With the build method, Laravel won’t resolve a registered instance of the class, but build a new one with the container.
// AppServiceProvider::register()
$this->app->singleton(MastodonClient::class);
// Resolve the singleton instance from the container
$mastodon = resolve(MastodonClient::class);
// Build a new instance
$anotherMastodon = app()->build(MastodonClient::class);
This can be useful when a Laravel package registers a class as a singleton but you need another instance.
This one’s permanently stored in my Pinboard — a conversation I had this morning triggered a re-read.
“A user is only part of one team”. Until we decide to add multi-team support, and the $user->team BelongsTo relation suddenly needs to be replaced in 50 places.
Golden advice from swyx:
It is a LOT easier to scale code from a cardinality of 2 to 3 than it is to refactor from a cardinality of 1 to 2.
Freek shares a few patterns we employ to let developers override behaviour in our packages.
One of the ways we keep maintenance burden low is by making our packages customizable. In this blog post, I’d like to cover some of our best tips to make a Laravel package easy to customize. Some of these tips will apply to regular projects as well.
Rauno Freiberg (designer at Vercel) shares his web guidelines for web interfaces. A few that stood out for me:
- Inputs should be wrapped with a
<form> to submit by pressing Enter - Interactive elements should disable
user-select for inner content - Actions that are frequent and low in novelty should avoid extraneous animations
Read them all on Rauno’s (beautiful) website, and check out the Craft section while you’re there.
Is it weird to have a favorite operator? Well, the pipe operator |> is mine. Not only does it look cool, it opens a world of possibilities for better code.
Unfortunately, it’s not available in any of the languages I use on a daily basis. There are proposals to add it to PHP and JavaScript, but we’re not there yet. I’d like to expand on why I think the pipe operator would be a valuable addition to the language from a PHP developer’s perspective.
Read more
I like to browsing through past work when I’m in need of inspiration, trying to reflect on the present, or in a nostalgic mood. Not just finished work, the things that didn’t make it can be even more inspiring to look back at.
With modern software, artifacts of work in progress are becoming more and more rare. Gone are the days of essay_final_v2, a project’s history is often contained in a single file (which isn’t even a file anymore with tools like Figma,…).
Per Alex Chan, taking screenshots while you work is a great way to build a journal of sorts.
I have dozens and dozens of screenshots of things I’ve made (and a handful of screen recordings, too). They’re a sort of “visual journal” of fun, silly and interesting things I’ve done on my computer.
The best time to take these screenshots is as I’m doing the work – when I have all the required context. And unlike the raw files, images are a stable format that I’ll be able to read for a very long time. I don’t need any context to look at an image; I just look at it in an image viewer.
I reconfigured CleanShot to store screenshots I save to a folder on iCloud Drive instead of my desktop. Out of sight, out of mind. Until I want to take a stroll through my visual record.
Static methods tend to have a bad reputation in PHP, but I believe (stateless) static methods are underused. In static functions, there’s no internal state to take into account. Calculator::sum(1, 2) only depends on its input, and will always return 3.
While researching for another post, I came across an article from Mathias Verraes that already says everything I wanted to say.
It is stateless, it is free of side effects, and as such, it is entirely predictable. You can call the exact same function with the exact same argument as often as you like, and you will always get the exact same result back.
This is a friendly reminder to keep leading slashes in mind in .gitignore files.
The other day, I pulled down a project and couldn’t get the CSS to build because files were missing. It turned out another developer created a new resources/css/vendor directory to override styles for third-party components. A fine name, but vendor was ignored so they were quietly missing from the repository. We updated .gitignore to use /vendor instead and all was well.
# Ignores all vendor files
vendor
# Only ignores vendor at the project root
/vendor
During my latest
redesign, I replaced Hugo’s default code highlighting with
Torchlight. In this post, I’ll explain how I set up Torchlight CLI for my Hugo site. (Although this can be applied to any static site.)
Read more
Nat Eliason on ideas and fermented jalapeños:
Good ideas require boredom. If you constantly ingest new information, the existing information can never be digested.
Coming up with ideas is a passive undertaking, not an active one. You can’t summon good ideas like a genie. They sneak up on you when your mind has enough space to wander.
Local storage tends to be the obvious place to persist data locally in a web application. We tend to grab straight for
localStorage, but it’s not the only tool in our workbox. Another option is
sessionStorage. Let’s review their similarities and differences, and determine when to use which.
Read more
Elise Hein compiled a few arguments in favor of using CSS attribute selectors more often. Two examples stood our for me.
Consider existing attributes. Whenever we add state we should take a step back and consider if we can leverage a standard. I often add an .is-active class to links in navbars. However, there’s an ARIA attribute for that. In addition to using a standard, our site becomes more accessible.
a[aria-current="page"] { }
Make invalid states impossible with data attributes. In HTML, we could accidentally end up with a card that .is-small.is-large. Using a data attribute enforces a single value for the attribute.
.card.is-small { }
.card.is-large { }
// vs
.card[data-size="small"] { }
.card[data-size="large"] { }
Read the full post on Elise Hein’s blog.
This blog’s design has remained roughly the same the past two years. I tweaked the style a lot, but changes were incremental and stay true to the neutral black and white style. Codebases rot over time, and small changes slowly but surely introduce technical debt. I started cleaning house, and before I knew it I was embarked in a full redesign.
Read more
I shiver at the sight of a function packed with too-many-to-read-at-a-glance arguments without a description.
Read more