Open-sourcing our guidelines

At Spatie we recently launched a new site: guidelines.spatie.be. It contains articles on how we go about setting things up at Spatie and a collection of styleguides. The source code of the site is available on GitHub. In this blogpost I’d like to share why and how we created our guidelines site.

Why did we create this?

Let’s start with a quote from Sandi Metz from her excellent post on why we argue about style:

I firmly believe that all of the code that I personally have to examine should come to me in a consistent format. Code is read many more times than it is written, which means that the ultimate cost of code is in its reading. It therefore follows that code should be optimized for readability, which in turn dictates that an application’s code should all follow the same style. Adhering to a common style saves you money.

Spatie is web agency. So most of the time we are working on multiple projects at the same time. When the initial project is done, more of than not, we will also maintain it for several years. To keep things manageable we try to code things in a consistent way. That way we can dive into a project and easily reason about it. I’d argue that in addition to adhering to a common code style, setting up your projects in a consistent way will save time and money too.

For years I’ve been the sole developer at Spatie. It was seemingly easy to keep things consistent because there was nobody else working on the code. But the truth is that at the time I certainly did not notice the little differences in my code style across the projects (PSR-2 wasn’t a thing back then). Now that the company is growing (Alex recently joined our team with more new members on the way) it’s getting more and more important to keep things consistent.

Like Sandi mentioned in the above quote code should be optimized for readability. Having all code in a common style will save you money because it takes less time to understand the code. But I’d argue having a style guide will save you time writing code as well. Trying to decide if the view names or route names should be camelCases or kebab-cased? Don’t waste your time and just check the relevant guidelines.

Most of these rules originate from a discussion of the entire team (or they’ve been decided by an individual who cared enough to put it in a rule). Having these rules written down avoids discussing them over and over again. Because “best practices” really are nothing more than “current practices” you should still, from time to time, re-evaluate the rules to see if they still make sense.

Behind the screens

The guidelines site itself is build with Laravel. It’s completely open source. Here’s the repo containing the code that’s actually deployed on our server.

We’ve set up the guidelines site in such a way that everybody can contribute it. At the bottom of every page there’s an Edit this page on GitHub link. Clicking it will create a PR against the repo. When we merge in the PR the code will automatically get deployed (we use Forge‘s auto deploy feature for this).

Because the guidelines are our very opinionated thoughts on how to do things, we’re not going to just accept every single PR we get. You can ‘t change our minds just by PRing a new rule. But we do welcome new rules that we agree with, or a discussion why our existing rules could be bad. And of course we’re also grateful for PRs that fix typos.

Storing the content

The content itself is stored as a set of markdown files. To display every page (expect for the home page), the PageController is used:

namespace App\Http\Controllers;

use App\Markdown\MarkdownConverter;

class PageController extends Controller
{
    public function __invoke($url)
    {
        abort_unless($page = app('navigation')->getPage($url), 404);

        return view('page', [
            'title' => $page->title,
            'editUrl' => $page->edit_url,
            'contents' => MarkdownConverter::convert($page->contents),
        ]);
    }
}

Making content private

The aforementioned PageController controller will ask the Navigation class which page should be displayed. When looking at the code of the Navigation class you’ll notice that it also tries to get content from a private directory. This private directory contains content that we don’t want to share publicly, such as semi sensitive information and custom procedures that are not interesting for the outside world.

The content of that private directory is not in our public repo, but in a separate private repo that’s being symlink so Navigation can read it. And of course that private content is only viewable by users who are logged in.

Logging in

At Spatie we use Google Apps and every team member has his or her own email-address on the spatie.be domain. Wouldn’t it be nice if anyone with a spatie.be address on Google would be able to login? Then we wouldn’t have to create credentials manually whenever we onboard a new team member.

That’s why we opted leveraging Laravel Socialite to handle logins. Socialite makes it very easy to authenticate with OAuth providers such as Google, Facebook, Github, … Installing Socialite is very easy. After it is installed and configured the necessary APIs at Google you don’t need too much to code to handle social logins.

This is the entire LoginController:

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\User;
use Socialite;

class LoginController extends Controller
{
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    public function redirectToProvider()
    {
        return Socialite::driver('google')
            ->scopes(['email'])
            ->redirect();
    }

    public function handleProviderCallback()
    {
        $user = Socialite::driver('google')->stateless()->user();

        abort_unless(ends_with($user->getEmail(), [email protected]'), 403);

        $authenticatableUser = User::findOrCreate($user);

        auth()->login($authenticatableUser, true);

        return redirect('/');
    }

    public function logout()
    {
        auth()->logout();

        return redirect('/');
    }
}

When visiting /login the app will execute the redirectToProvider method. The user will get redirected to a login page at Google. When users provide the right credentials Google will redirect them back to our site. That response from Google is handled in handleProviderCallback. There we abort unless the email-address of logged in user ends with @spatie.be. And then there’s a piece of boring code. Because a socialite user isn’t directly authenticatable we find (or create) a regular user in the database and log that one in.

In closing

If you’re working in a company that doesn’t follow any guidelines to keep code and configuration consistent, I highly recommend talking to your team and convincing them of the value of writing such guidelines down. Take the time to discuss and agree on some common rules. I bet nearly everybody on your team will find such guidelines helpful and it’ll make it easy for newcomers to your team.

You could opt to just follow our guidelines or create your own set of rules. If you choose the latter, maybe you could use the code of our guidelines site to set up your own.

The site and the writing down of the guidelines was largely spearheaded my colleague Sebastian, who, as always, did an excellent job.

That site isn’t the first thing we’ve open sourced. Take a look at the opensource pages on our company site to find out the Laravel, PHP and JavaScript packages we previously created.

Use your Laravel named routes in JavaScript

Daniel Coulbourne, an engineer at Tighten Co and co-host of the amazing Twenty Percent Time podcast, recently released Ziggy, a tool to share your Laravel named routes with JavaScript.

Ziggy creates a Blade directive which you can include in your views. This will export a JavaScript object of your application’s named routes, keyed by their names (aliases), as well as a global route() helper function which you can use to access your routes in your JavaScript.

https://github.com/tightenco/ziggy

Laravel/MySQL JSON documents faster lookup using generated columns

In an older post on his blog Mohamed Said demonstrates how you can leverage virtual columns to speed up queries on data stored as JSON.

Laravel 5.3 is shipped with built-in support for updating and querying JSON type database fields, the support currently fully covers MySQL 5.7 JSON type fields updates and lookups,

Let’s see how we may create a generated column to store users favorite color for later indexing.

https://themsaid.com/laravel-mysql-json-colum-fast-lookup-20160709

Using global mixins in Vue.js

Recently I needed to add some global functionality to nearly all Vue components in an app. My colleague Seb told me a good way to achieve this: global mixins. In this post I’d like share that knowledge.

In Vue a mixin is some functionality bundled in a file that can be added to one or more Vue components. It’s very similar to a trait in PHP.

Let’s take a look at how such a regular mixin looks like. It’s really nothing more than a .js with some stuff in it. Here’s one with a computed property to grab some global info of the current user that has been set on the window object.

export default {
    computed: {
        currentUser() {
            return window.currentUser;
        },
    },
};

If you import and register the mixin you can use it.

<script>
import Auth from './mixins/Auth';

export default {
   mixins: [ Auth ],

   created() {
      // Let's use the function provided by the mixin.
      console.log(`${this.currentUser.name} is currently logged in.`);
   },
}
</script>

Nice. But image now you want to use the same mixin on almost every component in your app. Registering that mixin will grow old pretty fast. Enter global mixins. It’s extremely simple. Just register the mixin where you set up Vue. Commenly this would in app.js:

import Vue from 'vue';
import Auth from './mixins/Auth';

Vue.mixin(Auth); 

And with that you can use the functions defined in the mixin in any component:

<script>
export default {
   created() {
      // No need to import the mixin anymore.
      console.log(`${this.currentUser.name} is currently logged in.`);
   },
}
</script>

We can make a small improvement to this. In the Vue world things that are globally accessible (such as this.$set, this.$root, …) are commonly prefixed with $. We could follow that convention too:

The mixin:

export default {
    computed: {
        $currentUser() {
            return window.currentUser;
        },
    },
};

A component:

<script>
export default {
   created() {
      // so nice
      console.log(`${this.$currentUser.name} is currently logged in.`);
   },
}
</script>

And that’s really all there is to it.

What’s in our .babelrc?

Sebastian De Deyne, my colleague and all round wizard at Spatie, wrote a new blogpost on how we use Babel.

A lot has been going in in JavaScript the past few years. One of my favorite things has been the usage of babel, which allows us to write future JavaScript syntax today. The babel ecosystem has tons of plugins and configuration options, I’d like to elaborate on our usage at Spatie.

https://sebastiandedeyne.com/posts/2017/whats-in-our-babelrc

CSS Utility Classes and “Separation of Concerns”

In my day to day work I don’t write any css at all, but I still very much enjoyed this blogpost by Adam Wathan where he shares some interesting things about how css should be structured and he makes the case for using utility classes to make visual tweaks.

When you think about the relationship between HTML and CSS in terms of “separation of concerns”, it’s very black and white.

You either have separation of concerns (good!), or you don’t (bad!). This is not the right way to think about HTML and CSS. Instead, think about dependency direction.

One of the biggest benefits of using small, composable utilities is that every developer on your team is always choosing values from a fixed set of options.

https://adamwathan.me/css-utility-classes-and-separation-of-concerns/

The disadvantages of single page applications

Adam Silver lists a bunch of problems you need to solve if you opt to build a single page application.

Ironically, SPAs are harder to design and harder to build. And yet, they typically produce slow, disagreeable experiences for users.

Javascript is never going to beat the browser at what it does best—browsing. We can still give users rich and enhanced experiences without cramming an entire site into one document.

We should let the browser manage the browsing experience, and spend our time solving real user problems.

https://adamsilver.io/articles/the-disadvantages-of-single-page-applications/

Precision Through Imprecision: Improving Time Objects

Ross Tuck is probably one of my favourite bloggers. He doesn’t publish something often (his previous post is from 2015), but when he does it’s very much worth your time.

The important takeaway here isn’t “value objects, yay, inline juggling, boo!” It’s that we were able to remove several classes of errors by reducing the precision of the DateTime we were handling. If we hadn’t done that, the value object would still be handling all of these edges cases and probably failing at some of them too.

Reducing the quality of data to get a correct answer might seem counter-intuitive but it’s actually a more realistic view of the system we’re trying to model. Our computers might run in picoseconds but our business (probably) doesn’t. Plus, the computer is probably lying anyways.

http://rosstuck.com/precision-through-imprecision-improving-time-objects

Calculating distance using MySQL

Logan Henson, a developer at Tighten, wrote a new post on the company blog about MySQL’s cool ST_Distance_Sphere function.

On a client project recently, we had to make it easy to filter database query results based on the distance between a user and an entity in our database. It’s easy to get overwhelmed in that context, worrying about the crazy amount of PHP calculations you’re going to have to run.

If you need to calculate this, you can actually get surprisingly far by just using MySQL!

https://tighten.co/blog/a-mysql-distance-function-you-should-know-about

Language features and code properties

Josh Justice gives some solid advice on how to pick the right language for your next projects.

So to ask the question “should I use an OO or FP language (or style)” is to skip several steps. I think a better series of questions are: First, what properties would be beneficial for your application to have: concurrency? Immutability? Encapsulation? There are a lot of things you won’t know about your application at first, but you can at least know if it will be a backend app, JavaScript browser app, or native mobile app; if it will be CPU-bound or IO-bound; and if it will process data inputted by humans or automatically generated by machines. All of those factors can influence which properties you need.

Once that’s decided, the next question is, in a given language, are those properties guaranteed, easy, difficult, or not realistically achievable?

http://codingitwrong.com/2017/07/27/language-features-and-code-properties.html

Why using Yoda conditions you should probably not be

Grégoire Paris wrote down his opinion on why he dislikes Yoda conditions.

So how do Yoda conditions work? Well it is basically a knee-jerk reaction you have to develop: whenever you write a condition, put the operand that cannot be assigned on the left. This should give you an error message if you make an assignment when you actually meant to make a comparison.

https://dev.to/greg0ire/why-using-yoda-conditions-you-should-probably-not

Personally, I’m not a big fan of Yoda conditions either. My feeling is the the cost of decreased readability is just too high for the small value that Yoda conditions bring to the table.

Cruddy by design

At this year’s Laracon US Adam Wathan gave a talk titled “Cruddy By Design” on how to structure your controllers better. After the conference he published a new GitHub repo that contains the demo app he refactored on stage. The 4 main tips to improve your code come as PRs on the repo with a full description on why the change is valuable. Very cool stuff.

Using this convention as a “rule” is a good way to force yourself to keep your controllers from becoming bloated, and can often lead to learning interesting new things about your domain.

For the presentation, I put together a demo app called “CastHacker” that showcases podcasts about software development. It’s not a “real” app by any means (lots of imaginary features, no tests, etc.); it’s just enough code to demonstrate the concepts from the presentation. Feel free to clone it and play with it locally if you like though.

I’ve written up each refactoring I shared in the presentation as a detailed pull request.

https://github.com/adamwathan/laracon2017

Generate pdfs with Google Chrome on a Forge provisioned server

While working on one of our projects my colleague Sebastian had to create a pdf with some text and charts. In a new post on his blog he explains how he leveraged headless Chrome to create the pdf.

This week I needed to export some charts generated with HTML & JavaScript as a pdf file. I already had implemented the charts on a webpage so I wanted a solution that allowed me to use my existing code for the pdfs.

Headless Chrome to the rescue! Chrome can run as a cli tool, and print a pdf file from a url. Al I had to do was make some layout tweaks to make everything printer-friendly.

https://sebastiandedeyne.com/posts/2017/generate-pdfs-with-google-chrome-on-a-forge-provisioned-server

Meanwhile support for creating pdfs has been added to our Browsershot package (which also uses headless Chrome under the hood).

Here’s how you can convert a webpage to a pdf using the package:

Browsershot::url('https://example.com')->save('example.pdf');

A tool to automatically rerun PHPUnit tests when source code changes

In the JavaScript world Jest, built by Facebook, is an excellent tool to run tests. Not only can it automatically rerun your tests when source code changes, but there’s also an interactive mode where you can set a filter on which tests to run while the tool is running. Would it be great if we could have these awesome features while working with PHPUnit?

Our newly released phpunit-watcher tool provides a Jest like experience. You can simply install it by running composer global require spatie/phpunit-watcher.

When you start it with phpunit-watcher watch this is what it looks like.

By default it will watch all files in the src, app and tests subdirectories in the directory where it is started. If any of the files in those directories changes (or when a file in there gets created or deleted) the tests will rerun automatically. Cool, right? If you need to watch another directory just add a file named .phpunit-watcher.yml in your project directory. Here’s some example content:

watch:
directories:
- myApplication
- tests
fileMask: '*.php'

Extra options can be passed to PHPUnit just by tacking them on the phpunit-watcher command. Here’s an example where we only run tests whose name contains the word “includes”:

Now, if you want to get rid of that filter, there’s no need to stop the tool. Like the little manual at the bottom will tell you, just press “a” to run all tests again. If you only want to run tests in a specific file or path, just type “p” to get to this screen:

On that screen, just type the name of the file or directory that you want to filter on.

And that’s all there’s really to it. The tool is fairly new, but the past days I’ve really enjoyed using our own tool myself and I wonder how I could ever have worked without it. Now I know that some IDE’s, such as PHPStorm, ship with a PHPUnit watcher built-in, but our tool feels nicer (that’s very subjective of course) and will work in combination with any editor or IDE (that’s very objective).

Some cool packages are powering our tool. The watching part is covered by the awesome Resource-watcher package. The interactivity is enabled by ReactPHP. I also want to give a shoutout to Colin O’Dell who helped fix a nasty performance problem and Christoper Pitt who wrote a nice blogpost that kickstarted the work on this package.

If you want to know more about phpunit-watcher, be sure to check it out on GitHub. This is not the first time we’ve created something inspired by Jest. Take a look at this package which brings Jest’s snapshot testing to PHPUnit. Want to see some mooarrrr packages we created previously, then check out the opensource pages on our company website.

How to write JavaScript-style test watchers in PHP

Christoper Pitt published another excellent piece over at Sitepoint. This time he describes how he built a watcher to automatically recompile his preprocessed code and rerun the tests.

In order to reduce the burden of invoking the transformation scripts, boilerplate projects have started to include scripts to automatically watch for file changes; and thereafter invoke these scripts.

These projects I’ve worked on have used a similar approach to re-run unit tests. When I change the JavaScript files, these files are transformed and the unit tests are re-run. This way, I can immediately see if I’ve broken anything.

https://www.sitepoint.com/write-javascript-style-test-watchers-php/

Diving into Laravel Horizon

Laravel Horizon is a kickass dashboard for viewing queued jobs. Co-creator Mohammed Said published two posts about the inner working of the tool. The first one on the Diving Laravel site highlights the overall configuration and how the master supervisor works.

Laravel Horizon is a queue manager that gives you full control over your queues, it provides means to configure how your jobs are processed, generate analytics, and perform different queue-related tasks from within a nice dashboard.

In this dive we’re going to learn how Horizon boots up and handles processing jobs using different workers as well as how it collects useful metrics for you to have the full picture of how your application dispatches and runs jobs.

https://divinglaravel.com/horizon/before-the-dive

The second one, published on his own blog, shows how queued jobs can get tagged.

Laravel Horizon is shipped with many amazing features that help you understand what goes on with your queue workers, my personal favorite feature is the ability to tag jobs for further investigation.

https://themsaid.com/tagging-jobs-in-laravel-horizon-20170731

A recap of Laracon US 2017

Laracon US 2017 was an amazing conference. Sid published this excellent recap that contains many links to slides and related content.

I attended my first Laracon in person and I have to say I really enjoyed the experience — maybe more than I expected to. It was well organised and the talks were diverse, informative and actionable. Day 1 was all technical and mostly revolved around Laravel. Day 2 had a different mix of talks and the non-technical ones were thought-provoking and entertaining.

https://medium.com/koomai/laracon-2017-a-recap-and-links-galore-c233be2de670

Webpack Academy

Sean Larkin, core team member of Webpack, will be leaving his current job at Mutual of Omaha for a new position at Microsoft. Because on his team he was the one most familiar with the webpack setup of the project, he looked for a way to transfer his knowledge. He landed on creating a video course on webpack that’s free for everyone.

I decided to create Webpack Academy, a training and educational platform for those wanting to learn more about webpack. This was a perfect way to not only allow me to give back to my team — by giving them free access to all of the content — but to also benefit the community by sharing it with everyone.

https://webpack.academy/