I’d like to share with you a very good video From Marco Pivetta who is part of the Doctrine Project core team
Tried to summarize the video in points:
- Doctrine is for: OLTP, DDD, Object Oriented, not for reporting, use SQL instead
- Entities should work without ORM and without DB
- Design the Entities first
- Entities represent your Domain
- Design the database after modeling your domain
- Entities are not typed array
- You have to think about how objects talk to each other instead of what the objects contain
- No behavior = No need for ORM
- Respect Law of Demeter (LOD) https://en.wikipedia.org/wiki/Law_of_Demeter
- Keep collections hidden in your Entities
- Entities should always be in a valid state
- Use named constructors, ex.
public static function fromUserInput()
- Avoid entity Setters
- Don’t couple with the application layer
- Avoid writing business logic inside LifeCycle Callback
- Avoid auto-generated identifiers, use UUID instead
- Avoid derived primary keys, use UNIQUE instead
- Avoid composite primary keys
- Don’t deal with UNIQUE constraint problem inside the application
- Try to design data structures in such a way that are append only
- Avoid soft deletes, as they break data integrity, use audit log or archiving instead
- Use Annotations Mapping in private packages
- Use XML Mapping in public packages
- Eager loading is useless, avoid it
- Avoid Bi-Directional Associations, because they are overhead, use DQL instead
- Use custom repositories for improved expressiveness
- Query functions are better than repositories
- Avoid
ObjectManager::getRepository()
, as it is aServiceLocator
, inject Repositories instead - Use
$repository->find()
that can return null - Use
$repository->get()
that throws exceptions to simplify error logic and can not return null - Avoid two-phase commit
- Communicate between boundaries via identifiers not object references
- The Paginator is a monster, use custom query instead
- Do not normalize without the need for it, Otherwise you’re digging your own grave
- Consider using Separate DBs (Transactional Data != Reporting Data)