Takeaways from SymfonyLive Online German Edition 2021

I attended the SymfonyLive Online German Edition 2021 that was on the 16th of April. I didn't watch all the talks, but here are the key takeaways that I found interesting of the ones I watched.

Boring is the new hype

  • Context is important. What might be the best solution for big companies like Netflix, Stripe, etc. is not necessarily for your use-case / situation
  • Adding new tools to the toolbelt has a cost (build up knowledge, how to test, infrastructure, maintenance, deployment, CI integration, ...). Think about if the problem you are facing can be solved by tools you already have. If you already have a tool that provides a Good enough solution, ask yourself, is it worth using a "fancy new tool" for it?
  • Learning new technologies is fun. But you are probably doing a bad job (at first at least), and creating technical debt or a suboptimal solution. Is it worth maintaing that technology in the long run?
  • Symfony is a boring technology. Strict BC policy. Stable foundation: HTTP, Console, ...
  • Fabien would recommend PostgresSQL over MySQL
    • It acually supports Async Messages (LISTEN/NOTIFY feature). Can be used instead of something like RabbitMQ
      • => One less piece of infrastructure to manage
    • Also supports Locks (Advisory locks). Do you really need Redis for that? Or is Postgres good enough for your use case?
      • => One less piece of infrastructure to manage
  • Boring is about making safe choices
    • Easy to find support
    • Easier to hire people with knowledge
  • Boring Infrastructure
    • Do you build everything yourself? Or use SaaS instead?
      • SaaS helps you focus on the topics that provide real business value
  • Does not recommend using LTS Symfony version
    • Recommendation: Upgrade every 6 months
  • Fabien's ideal stack
    • Currently not: Microservices on a K8s Cluster. Too complex to manage the infrastructure. Most users probably don't really have the needs for it
    • A VM on a PaaS
    • A Managed PostgreSQL DB
    • A CDN
      • Improves uptime. Probably adds a .9%
      • Uses standard HTTP headers
      • Fabien likes to use Cloudflare (I do as well)
    • A bunch of SaaS tools

If your're interested in the topic. I'd also recommend Dan McKinley's Blog Post and Presentation about the topic.

Symfony Notifier Demystified

  • Provides functionality to send notifications to recipient
  • The following channels are available. These each support multiple Transports (except Browser)
    • Email
    • SMS
      • Twilio
      • Nexmo
      • Smsapi
      • ...
    • Chat
      • Slack
      • Telegram
      • Discord
      • LinkedIn
      • Google Chat
      • ...
    • Browser
      • Sends flash messages
  • Notifications can implement a getChannel() method. Which defines which channel it should be sent to.
  • Notifications have an importance. This can be used to select which Notification should be sent to which channel. getChannel() overrides this if set
  • Channels create a channel-specific message (e.g. SmsMessage, EmailMessage) from the given Notification
    • Channels provide interfaces (e.g. ChatNotificationInterface), which contain a for example a asChatMessage() method in the Chat Channel case: Notification is able to define how a message is created
  • Channels each have their own Composer package
  • It also provides a Monolog handler. Allows sending Monolog logs to the Notifier which can for example send a Slack message
  • Example use cases: Support requests with different possible priorities

You can find more about the Notifier Component in the Symfony Docs for it.

Hidden gems in Symfony

  • App\Kernel - A full app in a single file
    • Can subscribe to events
    • Can declare inline services by using configureContainer()
    • Allows using #Route annotations
    • Use cases
      • Useful in testing
      • Very small Microservice
      • Lambda function
  • Named Autowiring Aliases
    • Combine type and parameter name
  • Service Locators and Iterators
    • AsTaggedItem
  • Command Definition
    • public static $defaultDescription
    • #[AsCommand(name: '', description: '')]
  • Env Var Processors
    • require
    • trim
    • default
    • url
    • EnvVarLoaderInterface
      • Allows you to implement your own implementation of a environment variable provider
      • Is called on every request
      • Example use case: High availability setup. A database instance goes down. Instantly remove it from the DB settings to route DB traffic away from the failed instance
  • Process
    • Wait until callback feature: ->waitUntil() method
      • Allows making it event driven
    • Supports "prepared" command lines
      • E.g. Process::fromShellCommandLine(ls -ls "{:$path}")
      • Protection against command injection (similar to SQL injection)
  • VarDumper
    • To dump in JSON api and not break the JSON: Use server dumper
  • HttpClient
    • Async HTTPlug client
      • Uses proxies
    • AsyncDecoratorTrait
      • Allows processing responses without breaking async
  • Routing
    • Allow inline definition of requirements & defaults inside Annotation
    • stateless Attribute. Provides error if the session is used
  • Validator
    • NotCompromisedPassword validator
    • NotCompromisedPassword Annotation
    • Doctrine #EnableAutoMapping Annotation to fail validation if Doctrine constraints are violated
  • VarExporter
    • Faster than unserialize()

Schrödinger's SQL - The SQL inside the Doctrine box

  • Unit Of Work
    • Entity Manager caches Entities. To be able to get the updated version of it, entities have to be cleared from the Entity Manager using ->clear()
  • Performance
    • Lazy Loading
      • Suboptimal performance in some use-cases.
      • For example: Load entities with an array field that references another table/entity type (let's say Foo). Loop over these loaded entities and call getFoo(). Each foreach iteration will cause a separate SQL query. Not optimal
    • Eager Loading
      • Might hydrate entities with data that is never used. Also suboptimal
    • Takeaways
      • Be aware of the SQL that Doctrine executes under the hood
  • Using Doctrine does not prevent you from using plain SQL instead of DQL, where it makes sense. E.g. Window Functions, Value Lists, JSON_OBJECT()

What's new in Doctrine 2021?

  • DBAL 3
    • Statement & Result are now separated
      • Statement: For executing the statement
      • Result: For fetching query results
    • Fetch API overhauled
      • More specific fetch methods replace the existing ones
      • They now return a Result object
    • executeStatement() replaces executeUpdate(), exec() & query(). Returns count of changed rows.
    • Doctrine now does automatic reconnects. Automatically reconnects when DB is available again. Helps with long running tasks. ping() & reconnect() is not necessary anymore.
    • DBALException replaced by Exception
    • DBAL 2 is forward compatible to DBAL 3. You can already use the APIs from DBAL 3 in DBAL 2.
  • ORM
    • PHP 8 attributes are supported
    • Typed Property Defaults: Doctrine uses PHP types by default, if defined
      • Array => JSON
      • Int => Int
      • ...
    • Support for static analyser (PHPStan, Psalm) typed arrays
    • toIterable() method
  • Roadmap
    • Switch caching layer to PSR-6 caching
    • Better Value Object DQL support
    • Value Objects via nested JSON
    • Enums
    • ManyToAny Associations
    • Dynamic Column Mapping
    • Better Transaction/Unit Of Work

PHP 8

  • Symfony 6 will require PHP 8
  • Useful new features
    • get_debug_type()
    • str_starts_with(), str_ends_with(), str_contains()
    • Constructor Property Promotion
    • throw is now an expression. Allows using throw in arrow functions, after ?? or ?:, ...
      • => Less noisy error handling code
    • Nullsafe operator for method calls ?->
    • match() expression. Can be used instead of switch statements
    • Named arguments
    • Enums (PHP 8.1)

The New Testing Landscape: Panther, Foundry & More

  • ApiTestCase. Specific to APIs
  • zenstruck/foundry: Library to create data fixtures