Skip to content

Instantly share code, notes, and snippets.

@bourdeau
Last active May 9, 2019 06:06
Show Gist options
  • Save bourdeau/f05288cc288b40a687be13eaa5ed5f21 to your computer and use it in GitHub Desktop.
Save bourdeau/f05288cc288b40a687be13eaa5ed5f21 to your computer and use it in GitHub Desktop.

APPLICATION DESIGN

Inheritance & Composition 😱

Don't use inheritance as another way to copy/paste code.

class EmailRubbish
{
    public function sendEmail(string $email, string $subject): void
    {
        // spam poor user...
    }
}

// Is a Cart some kind of Email?
class RubbishCart extends EmailRubbish
{
    public function rubbishCheckout(): void
    {
        // do checkout stuff
        $this->sendEmail($this->user->getEmail(), 'Payment succeeded, you are now poorer!');
    }
}
// Is Love some kind of Email? 💔
class RubbishLove extends EmailRubbish
{
    public function youWillLoveMyMum(): void
    {
        // do Love stuff ❤️ (NOT WITH MY MUM!!)
        $this->sendEmail($this->user->getEmail(), 'You have a new match on Tinder!');
    }
}

That's called "horizontal code reuse", as opposed to the "vertical code reuse" of inheritance.

READ the Law of Demeter

Use final Class & Interface ❤️

final is your friend. It pushes you to use DI and avoid inheritance and bad patterns. Use it as much as possible. Please read : When to declare classes final by Ocramius.

Don't use Service Locator

Service locator, i.e $this->getRepository(User::class)->find($id); is bad! Read PSR-11 paragraph 1.3. PhpStorm is not your friend by allowing go to on this, most language servers won't. Use DI properly and inject only what you need (cf. Symfony 4, auto wiring and stuff).

ORM

Auto increment Id is rubbish, use UUID

UUID has been here for over 15 years, there is absoluetly no excuses to still use Auto increment Id.

When you create an object with an attribute wich is an auto increment id you have an invalid object. Why? Because you first have to store it to the db to get this id, so you can't send it back for instance. Instead use UUID. Even better: no one will ever iterates over the few likes you had on Tinder... 🍌✂️🍑

Avoid Setters

Setters & Getters are useless on entities. What is the point of using a Serializer to call setters & getters? Create DTO.

ORM for large data set

Don't use an ORM to deal with a large amount of data, it's not design for this. It hydrates objects, Reflection classes and do a lot of other stuff that is not initialy designed for. Consider memory leaks.

Anemic entities

Entities are not a db table representation, they are a model ought to do stuff.

Lazy Loadinng, Extra Lazy and EAGER

Don't use EAGER. You will have n+1 query performances issues. Use join in your Repositories. If you use Extra Lazy it probably means you've reach the limit of the ORM and will face UnitOfWork that will create memory leaks.

ManyToMany relations

One usually don't need them. One usually does $user->getProducts() rather than $product->getUsers(). Think about when you will serialize/deserialize those Collection.

Lifecycle Callbacks (prePersist, etc.)

It's an ORM hack, they will trigger the event each time you serialize or deserialise the object. Don't use them. They're a performance killer and make stuff very complicated to debug and understand. The only case would be for internal state mutation like to update a dateTime.

Immutable Entity

Go for immutable entities, just append data. No more cache problems, you can do analytics, etc. Go Event Sourcing, Go Kafka 😋

Soft Delete

Stop making soft delete, it's mutation. Your db is then half invalid think about the queries problem you will have billions of entries.

Entity Validation

Entity are supposed to be always valid. Don't use Symfony Validator for it. Any invalid object should be pushed in a different objetc. Use DTO (Data Transfert Object).

Annotations & XML

Use Annotations for private package and use XML for OpenSource stuff. XML make it easier to replace the maping.

Serialization & stuff

Symfony Forms are garbage

They're good for your grand ma blog and still... Don't use them. Period.

TEST

One should make the difference between:

  • functional testing (i.e: you Mock nothing)
  • integration testing (i.e: you only Mock your code)
  • unit testing (i.e: you Mock everything outside the method)

Don't Mock what is not your code

Create Mock only your own code not dependencies! First because most of the time you can't, as usually depencies have their classes declared final so one can't inheritate to create a Mock and pass TypeHint and because their is no need. Then because you don't know how the dependency work and their behaviour might change. For example if one day $myUserRepo->find($id) return something else than your Object or Null your test will pass but your code will fail. But you can Mock the Interface your dependency implement instead. If you need to Mock the class you are testing (Partia Mocking), it's probably because your classes does too much and is violating SOLID.

"I love the fact that whenever I think of doing something wrong, phpspec and prophecy tell me to get back on the right path. If you don't want to design properly, phpspec is not the tool for you. There's no such thing as "over design"." - Jakub Zalas

OTHER

FRAMEWORKS are DEAD!

This is said... uses PHP-DI, take a look at Nette, we are in 2019 we uses components not Frameworks. No one cares about Frameworks anymore. Frameworks = Coupling = Rubbish. No one cares about how one method works as long as there is an interface that works. Think Design by Contract.

Stop Monolithic go Micro Services

It's hard to scale a monolithic app. What would the Parliement look like if all the people of a country were going there to vote? Send a representant, somone who will communicate for you, an interface. It's more DevOps stuff I know. But no more Git conflicts, no more code you don't care about, it's SOLID, it's King Kong!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment