A year ago, I wrote a recap of 2018. Now that 2019 is coming to a close, I thought it might be fun to write a similar post on what I did this year.
On a personal level
I don't want to share too much about my private life, but I can say that I'm lucky enough to, together with my girlfriend, get to raise our two little boys (they are 5 and 7 now). It's this foundation that helps me to achieve a lot of things work-wise.
Discovering hip hop
I love listening to music. Even though I considering my musical taste to be quite expansive, I try to broaden my musical horizons. I consider it a personal achievement that this year that I managed to appreciate a genre that I previously loathed: hip hop.
This appreciation of hip hop was sparkled by a podcast named Dissect. In each season, the host Cole Cuchna analyses an entire album, word for word, note by note. It's a bit like standing in a museum before a painting and having somebody next to you tell you for hours everything that is to know about that painting.
With a deeper understanding, it's easy to appreciate something more. This is true not only for music, but to various other things in life as well.
By listening to Dissect, I started to appreciate the work of the likes of Kendrick Lamar, Kanye West, Tyler The Creator, Frank Ocean,... Even if you already like these artists, I recommend listening to Dissect. You'll discover that these people do much more than just creating a pleasant song to listen to. They want to tell something meaningful with their music.
Growing Oh Dear!
Last year, together with my buddy Mattias Geniar, I launched Oh Dear!, a beautiful uptime tracker. It can also detect broken links and mixed content on any page of your site.
This year we added one major feature to it: status pages. You can read more on how and why we created status pages here here.
I'm proud that this feature is used both by the Laravel organisation and Flare. Business wise Oh Dear! is going strong: we managed to double our MRR in 2019.
At Spatie
At Spatie, it was a pretty exciting year.
Our current office can hold up to 8 people comfortably. With Rias having joined us around the summer, our team headcount is currently 10. That's why we bought a new office. We plan on moving to our new, bigger office, early 2020. I'll be sure to share some pictures at that time.
Personally, I didn't do a lot of traditional client work this year, but focused on creating products. In the first part of the year, most of my time was spent creating Flare and Ignition, which were launched in August. After that, I set out to create a premium laravel package called laravel-mailcoach. Let's take a closer look at both projects.
Creating Flare and Ignition
After having created laravel-websockets together with Marcel Pociot, we wondered if there were other things we could do together. One of the ideas we had was building a Laravel specific error tracker.
It became apparent very early on that we couldn't tackle this alone and that we needed help from our colleagues. So we upgraded our hobby project to a proper project where we could work on full time during the day. We didn't only create Flare, the Laravel specific error tracker, but also a new local error page for Laravel, called Ignition. For various reasons, we decided to keep the project a secret to the outside world.
After months of hard word by everybody in our teams, we launched Flare and Ignition at Laracon EU. I'm not ashamed to say that, even though Marcel and I meticulously prepared our talk, I was very nervous before giving it.
After the talk was done, I was happy with how it went. It also felt like a big weight had come off my shoulders. Surprising an audience with a product announcement is fun, but it takes a lot of mental energy in keeping it secret the months before. There was always the fear that I would accidentally leak something (which I did at one point during development by tweeting out a screenshot that gave away a lot of information). It was good that there were no secrets to keep anymore. I felt relieved.
Immediately after the talk, I had to decompress a little. Probably I've gone a little bit too deep in the weeks leading up to the announcement. In 2020 I want to be mindful that I won't do that again.
Looking back at Flare, I'm proud of the work that our teams have done. Working with Marcel was a fun experience, and I hope we can collaborate on something again in the future.
Technically, Flare and Ignition are things of beauty. Commercially, Flare still needs to grow. We're going to add a highly requested feature, JavaScript error tracking, very soon, and we have some more plans for the service in 2020.
Building Mailcoach
After Flare and Ignition, which were kept secret during development, I wanted to create something in the open again.
Every two weeks, I send out a newsletter on Laravel, PHP, and JavaScript. Currently, my newsletter holds about 6 000 subscribers. Because writing and sending my newsletter is a personal effort, not covered by a company, I want to keep the costs low.
For the past few years, I've used Sendy to send out newsletters. Somewhere in August, I started to have problems sending it out. Sendy offers open and click tracking. It does this by adding a small image to the mail and by replacing each link to a link to the domain Sendy runs on.
Each time I a newsletter is sent out, a lot of requests related to open and click tracking were hitting my server. With my subscriber count growing more and more, I was now DDoSing myself each time I sent out a newsletter.
This sparked the idea of just solving this problem myself. Like when starting development with other packages, I thought: "How hard can this be?". So I set out creating a Laravel package that could send newsletters. My first stab at the problem was to handle open and link tracking like Sendy. Just let the package handle it all but itself, but by moving a lot of work the queue. I hoped this would be enough to avoid DDoSing myself.
After doing a little bit more research, I found that SES and other email sending services could also track opens and clicks. They provide feedback on those via webhooks. All webhooks get throttled, so when a mail gets opened 1 000 times in a small timeframe, you won't get DDoSed through the webhook.
I think around the end of October, the laravel-email-campaigns package was ready. At that point, it was still open source. I talked to my business partners at Spatie about it. We concluded it might be a good idea to polish the package some more, add a kick-ass UI to it, so we could try to sell it. We've also decided to include a video course on it that explains how the package is built under the hood (and how we create write clean code at Spatie).
We've renamed laravel-email-campaigns to Mailcoach. Currently, it's fully functioning. I've already used it to send a newsletter to all my subscribers. There were no DDoS problems. I'm currently putting in the final touches. The video course will be recorded in the next few weeks. We're going to launch Mailcoach beginning of 2020. Pretty exciting times!
I honestly don't know if Mailcoach will be succesful commercially, but at the very least I will have built a very good solution to send out newsletters for myself.
Do subscribe at the Mailcoach site to get notified when we launch it.
Releasing open source packages
Next to Flare and Mailcoach, there was also a lot of client work done by Spatie. When working on client projects, we stumble upon problems that might occur in other client projects as well. Whenever this is the case, we create a package.
We've been creating packages for quite some time now. I don't have an exact count, but I'm pretty sure we've published over 200 packages now. In March 2018, they downloaded 10 million times. This year around October, we've hit the 50 million mark. We get postcards from people all over the world thanking us for our efforts.
These are the packages our team created in 2019:
- laravel-welcome-notification
- simple-excel
- laravel-rate-limited-job-middleware
- laravel-event-sourcing
- laravel-resource-links
- laravel-model-states
- laravel-resource-endpoints
- test-time
- laravel-webhook-client
- laravel-webhook-server
- laravel-enum
- google-time-zone
- icalendar-generator
- laravel-mix-preload
- laravel-export
- laravel-flash
- laravel-personal-data-export
- laravel-queueable-action
- enum
- laravel-eventsauce
- guzzle-rate-limiter-middleware
On our company website, you can find a big list of all the packages we've ever created.
Public speaking
In the recap of 2018, I mentioned that I wanted to do less public speaking because I was feeling early symptoms of burn out. I sort of succeeded with that goal. I did speak less than in 2018, but probably still a bit too much.
A thing I did wrong in 2019 was that I've prepared too many different talks. Making a single talk takes a lot of energy. Also, giving a new talk for the first time is stressy business for me. I still want to do some public speaking in 2020, but I'm aiming to prepare just one or maybe two talks and give those at various conferences.
The past year was lucky enough to have spoken at all Laracons: Laracon Online, Laracon US, Laracon Madrid, Laracon EU, and Laracon Australia.
I had a particularly good time at Laracon Australia. I had never been to Australia. The jet lag was terrible, but it was worth it. Hanging out with Michael, Marcus, JMac, Jess & Marcel was really nice.
I also have very fond memories of two boat trips I took with Marcel (JMac was also present on the second one), where we reflected on how our companies and we both were doing.
Here's the full list of talks I gave this year:
- 2019.03.03 - Laravel Live, Mumbai, India - Getting started with event sourcing in Laravel
- 2019.03.06 - Laracon Online - Getting started with event sourcing in Laravel
- 2019.03.27 - Full Stack Antwerp - Getting started with event sourcing in Laravel
- 2019.04.03 - Full Stack Brussels - Getting started with event sourcing in Laravel
- 2019.05.02 - Full Stack Ghent - Getting started with event sourcing in Laravel
- 2019.05.19 - AFUP Lille - Managing queues with Laravel Horizon
- 2019.05.23 - Laracon Madrid - Supercharging common controllers
- 2019.06.08 - Full Stack Ghent - Supercharging common controllers
- 2019.07.24 - Laracon US - Supercharging common controllers
- 2019.08.30 - Laracon EU - Introducing Flare and Ignition
- 2019.09.26 - Ode aan de Code, Apeldoorn, The Netherlands - Handling media in a Laravel application
- 2019.10.31 - Laracon Australia - A tour of the Flare codebase
- 2019.11.13 - Full Stack Ghent - A tour of the Flare codebase ## Organising a conference #
Together with my buddies Dries & Rias, I've been running the Full Stack user groups (previously named PHP Antwerp). To avoid burn out, I decided I wanted to do a little bit less. One of the things I chose not to invest any more time in was organizing those user groups. Though it was fun to do, there was no challenge for me anymore.
It was a hard decision, but looking back, I'm happy with the time I gained by not having that responsibility anymore. And it's great to see that Rias and Dries are making sure that a new meetup of the user group is organized every month. I still attend now and then.
One of the things that Dries and I discussed for quite some time, was the organization of a conference called Full Stack Europe. The idea was that it would be an extension of the user group and that we would focus on all aspects of web development: front-end, back-end, design, ...
Because I had never done that before, I still wanted to go through with that plan. Having attended a lot of conferences before, Dries and I both had ideas on how to provide a better experience for attendees.
Our first plan was to organize a smallish conference with about 100 attendees. Mattias Verraes, who already has a lot of experience organizing conferences, joined us as an organizer. Thanks to his expertise, we scaled up things for our first edition.
Instead of doing a one day conference in a small venue, we decided to organize a three-day conference in the Hilton Hotel in the historic center of Antwerp. It was a gamble, but it paid off.
The first edition was a big success. We had a kick-ass lineup. Everything went smoothly during the conference (a major thank you to Anneke Schoonjans, and our volunteers for that). Most of the feedback we got from our attendees was positive, and I was delighted with how things went.
Currently we're planning the second edition. You can already register tickets for Full Stack Europe 2020. One of the mistakes we made with the first edition was that we invited the speakers a little bit too late. A lot of potential speakers already had other engagements. For the 2020 edition, we've already invited some awesome people to speak.
The blog
I've been running this blog for five years.
This year a couple of significant changes happened. I've changed the domain of the blog from murze.be to freek.dev. I think for most people, it is easier to remember the new URL since it's my first name.
The second significant change that happened in 2018 is the refreshed look. I'm very grateful for the work my colleague Sebastian put into this. He also updated the look of my newsletter template.
A smaller change that happened a couple of months ago is the removal of Disqus powered comments. Even though functionally Disqus does the job, I felt that, because comments couldn't be styled, the comments felt out of place. Webmentions have replaced them. Here's how you can add them to your Laravel powered blog.
In the past 365 days, the blog served about 903 064, which is a nice 20% increase compared to last year. In the past 12 months, I published 295 posts of which I've written 48 myself. In total, there are now 1509 posts, and of 243 of those, I'm the author.
Here are links to 48 posts I wrote in the past year.
- Introducing laravel-websockets, an easy to use WebSocket server implemented in PHP
- Handcrafting mocks
- A recap of 2018
- Preventing spam submitted through forms
- laravel-backup v6 has been released
- Tools to automatically format PHP, JavaScript and CSS files
- A package to use Artisan Tinker in your browser
- A package to create personal data exports
- A Laravel package to flash messages
- Laravel event projector v2 has been released
- An important security release for laravel-query-builder
- Simplifying controllers
- When to use Gate::after in Laravel
- Implementing event sourcing: aggregates
- Implementing event sourcing: improving the developer experience
- Video: getting started with event sourcing in Laravel
- Caching the entire response of a Laravel app
- A rule to validate delimited data
- A new coat of paint for freek.dev
- Refactoring to actions
- A package to control the flow of time
- Sending and receiving webhooks in Laravel apps
- Improving assertions on Laravel fakes
- How to handle front-end authorization using Laravel, Inertia and TypeScript
- Going serverless with Hugo and Netlify
- How to add webmentions to a Laravel powered blog
- Implementing event sourcing: testing aggregates
- Supercharging common controllers
- Ignition: a new error page for Laravel
- Flare: an error tracker built for Laravel apps
- Watch the Flare reveal live
- Generating speaker cards using Tailwind and Laravel
- Creating beautiful status pages using Oh Dear!
- Event store optimizations in laravel-event-sourcing
- A package that adds resource links to your Laravel API resources
- A job middleware to rate limit jobs
- The value of the void typehint in PHP
- The mixin PHP DocBlock
- My current setup (2019 edition)
- Getting started with Domain Oriented Laravel
- A PHP package to read and write simple Excel or CSV files
- Improving Artisan commands
- Sending a welcome notification to new users of a Laravel app
- My Alfred workflows
- Video: a first look at the alpha version of Mailcoach
- Streaming a large export as a CSV file to the browser
- Automatically convert your code to PHP 7.4 syntax using Rector
Other recaps
Want to read some more recaps? Here you go!
- Mohammed Said
- Adam Wathan
- Sebastian De Deyne
- Nuno Maduro
- David Llop
- Rathes Sachchithananthan
- Javier Martinez
- Daniel Werner
- Dries Vints
- Marcel Pociot
- Bobby Bouwmann
- Stefan Bauer
- Lukas Kämmerling
- Dieter Stinglhamber
Let me know a link to your recap, and I'll include it in the list above.
Top comments (0)