πŸ”₯ Laravel Clean Code Tactics

The OG thread. Get printable PDF versions here.

Write functional code when it benefits you

39

πŸ”₯ Write functional code when it benefits you

Write functional code when it benefits you

Functional code can both clean things up and make them impossible to understand. Refactor common loops into functional calls, but don't write stupidly complex reduce()s just to avoid writing a loop. There's a use case for both.

Context matters

38

πŸ”₯ Context matters

Context matters

Above I said that moving business logic to action/service classes is good. But context matters

Here's code design advice from a popular "Laravel best practices" repo. There's absolutely no reason to put a 3-line check into a class. That's just overengineered

Use collections when they can clean up your code

37

πŸ”₯ Use collections when they can clean up your code

Use collections when they can clean up your code

Don't turn all arrays into collections just because Laravel offers them, but DO turn arrays into collections when you can make use of collection syntax to clean up your code.

Use docblocks only when they clarify things

36

πŸ”₯ Use docblocks only when they clarify things

Use docblocks only when they clarify things

Many people will disagree with this, because they do it. But it makes no sense.

There's no point in using docblocks when they don't give any extra information. If the typehint is enough, don't add a docblock.

That's just noise.

Create custom Blade directives for business logic

34

πŸ”₯ Create custom Blade directives for business logic

Create custom Blade directives for business logic

You can make your Blade templates more expressive by creating custom directives. For example, rather than checking if the user has the admin role, you could use @admin.

Use strict comparison

33

πŸ”₯ Use strict comparison

Use strict comparison

ALWAYS use strict comparison (=== and !==). If needed, cast things go the correct type before comparing. Better than weird == results

Also consider enabling strict types in your code. This will prevent passing variables of wrong data types to functions

Avoid queries in Blade when possible

32

πŸ”₯ Avoid queries in Blade when possible

Avoid queries in Blade when possible

Sometimes you may want to execute DB queries in blade. There are some ok use cases for this, such as in layout files.

But if it's a view returned by a controller, pass the data in the view data instead.

Consider using helpers instead of facades. They can clean things up

31

πŸ”₯ Consider using helpers instead of facades. They can clean things up

Consider using helpers instead of facades. They can clean things up

This is largely a matter of personal preference, but calling a global function instead of having to import a class and statically call a method feels nicer to me.

Bonus points for session('key') syntax.

Use short operators

30

πŸ”₯ Use short operators

Use short operators

PHP has many great operators that can replace ugly if checks. Memorize them.

Be friends with your IDE

29

πŸ”₯ Be friends with your IDE

Be friends with your IDE

Install extensions, write annotations, use typehints. Your IDE will help you with getting your code working correctly, which lets you spend more energy on writing code that's also readable.

Consider single-action controllers

28

πŸ”₯ Consider single-action controllers

Consider single-action controllers

If you have a complex route action, consider moving it to a separate controller.

For OrderController::create, you'd create CreateOrderController.

Another solution is to move that logic to an action class β€” do what works best in your case.

Don't use a controller namespace

27

πŸ”₯ Don't use a controller namespace

Don't use a controller namespace

Instead of writing controller actions like PostController@index, use the callable array syntax [PostController::class, 'index'].

You will be able to navigate to the class by clicking PostController.

Use custom config files

26

πŸ”₯ Use custom config files

Use custom config files

You can store things like "results per page" in config files. Don't add them to the app config file though. Create your own. In my e-commerce project, I use config/shop.php.

Don't use model methods to retrieve data

25

πŸ”₯ Don't use model methods to retrieve data

Don't use model methods to retrieve data

If you want to retrieve some data from a model, create an accessor.

Keep methods for things that change the model in some way.

Create query scopes for complex where()s

24

πŸ”₯ Create query scopes for complex where()s

Create query scopes for complex where()s

Rather than writing complex where() clauses, create query scopes with expressive names.

This will make your e.g. controllers have to know less about the database structure and your code will be cleaner.

Import namespaces instead of using aliases

23

πŸ”₯ Import namespaces instead of using aliases

Import namespaces instead of using aliases

Sometimes you may have multiple classes with the same name. Rather than importing them with an alias, import the namespaces.

Create single-use Blade includes

22

πŸ”₯ Create single-use Blade includes

Similar to single-use traits.

This tactic is great when you have a very long template and you want to make it more manageable.

There's nothing wrong with @including headers and footers in layouts, or things like complex forms in page views.

Create single-use traits

21

πŸ”₯ Create single-use traits

Create single-use traits

Adding methods to classes where they belong is cleaner than creating action classes for everything, but it can make the classes grow big

Consider using traits. They're meant primarily for code reuse, but there's nothing wrong with single-use traits

Use custom collections

19

πŸ”₯ Use custom collections

Use custom collections

Creating custom collections can be a great way to achieve more expressive syntax. Consider this example with order totals.

Don't use abbreviations

18

πŸ”₯ Don't use abbreviations

Don't use abbreviations

Don't think that long variable/method names are wrong. They're not. They're expressive.

Better to call a longer method than a short one and check the docblock to understand what it does

Same with variables. Don't use nonsense 3-letters abbreviations

Create fluent objects

17

πŸ”₯ Create fluent objects

Create fluent objects

You can also create objects with fluent APIs. Gradually add data by with separate calls, and only require the absolute minimum in the constructor.

Each method will return $this, so you can stop at any call.

Use Data Transfer Objects (DTOs)

16

πŸ”₯ Use Data Transfer Objects (DTOs)

Use Data Transfer Objects (DTOs)

Rather than passing a huge amount of arguments in a specific order, consider creating an object with properties to store this data.

Bonus points if you can find that some behavior can be moved into to this object.

Don't just write procedural code in classes

15

πŸ”₯ Don't just write procedural code in classes

Don't just write procedural code in classes

This ties the previous tweet with the other tips here. OOP exists to make your code more readable, use it. Don't just write 400 line long procedural code in controller actions.

Here's code from my first Laravel project 😬

Dedicate a weekend towards learning proper OOP

14

πŸ”₯ Dedicate a weekend towards learning proper OOP

Know the difference between static/instance methods & variables and private/protected/public visibility. Also learn how Laravel uses magic methods.

You don't need this as a beginner, but as your code grows, it's crucial.

Create helper functions

13

πŸ”₯ Create helper functions

Create helper functions

If you repeat some code a lot, consider if extracting it to a helper function would make the code cleaner.

Avoid helper *classes*

12

πŸ”₯ Avoid helper *classes*

Avoid helper *classes*

Sometimes people put helpers into a class.

Beware, it can get messy. This is a class with only static methods used as helper functions. It's usually better to put these methods into classes with related logic or just keep them as global functions.

Extract methods

11

πŸ”₯ Extract methods

Extract methods

If some method is too long or complex, and it's hard to understand what exactly is happening, split the logic into multiple methods.

Consider using form requests

10

πŸ”₯ Consider using form requests

Consider using form requests

They're a great place to hide complex validation logic.

But beware of exactly that β€” hiding things. When your validation logic is simple, there's nothing wrong with doing it in the controller. Moving it to a form request makes it less explicit

Use events

9

πŸ”₯ Use events

Use events

Consider offloading some logic from controllers to events. For example, when creating models.

The benefit is that creating these models will work the same everywhere (controllers, jobs, ...) and the controller has one less worry about the details of the DB schema

Create model methods for business logic

8

πŸ”₯ Create model methods for business logic

Create model methods for business logic

Your controllers should be simple. They should say things like "create invoice for order". They shouldn't be concerned with the details of how your database is structured.

Leave that to the model.

Create action classes

7

πŸ”₯ Create action classes

Create action classes

Let's expand on the previous example. Sometimes, creating a class for a single action can clean things up.

Models should encapsulate the business logic related to them, but they shouldn't be too big.

Create variables when they improve readability

5

πŸ”₯ Create variables when they improve readability

Create variables when they improve readability

The opposite of the previous tip. Sometimes the value comes from a complex call and as such, creating a variable improves readability & removes the need for a comment.

Remember that context matters & your end goal is readability

It's about the *micro*

1

πŸ”₯ It's about the *micro*

Using some "macro" philosophy for structuring your code, like hexagonal architecture or DDD won't save you.

A clean codebase is the result of constant good decisions at the micro level.

We're writing a book, you can get it for free here.