Modularity problems
Architecture of corporate Symfony-applications
Who I am
● Senior Software Engineer @ Upwork
● 10+ years of PHP (Pear -> ZF 1 -> Symfony 1 -> Yii 1 -> ....)
● 4+ years of Symfony 2
● Also experience in Java (Spring, GWT, ...), C# (.Net), Ruby (Rails), JS (...)
● KNU, Faculty of Cybernetics, Theory of Programming
How to perceive this speech
This speech ...
● … is not a manual
⇒ use Google please!
● … covers some problems of modularity
⇒ it doesn’t cover a lot of stuff.
● … displays some Symfony problems
⇒ but we love Symfony anyway =)
What is “framework”?
Library vs Framework
Library
useful pieces of
code in one place
Framework
set of libraries, tools
and principles of
application
development
Framework
● It is a platform
● It defines application structure
● It unites components
● It offers tools
● It describes best practices
Modules
Modules (plugins, extensions, bundles etc.) is a
way to extend a framework.
Symfony modules
Component is Symfony library.
You need Composer to use Component.
Bundle is Symfony module.
You also need Composer to use Bundle.
But you must enable Bundle in your AppKernel
How does Bundle extend our framework?
● Commands
● Controllers
● Public services
○ also tagged services (event listeners, annotation processors etc.)
● Service Container processing
○ add support of custom service tags
○ preconfigure other modules (prepend)
● Other common code and assets (careful!)
Symfony 2.x ⇒ 4.x
● Flex
○ Flex is a tool to simplify bundle installation.
● Bundle-less
○ Application is not a bundle
○ Symfony 4.x application directory structure is self-sufficient
Corporate Symfony applications
Specifics of big product companies
● A lot of developer teams
● A lot of code
● A lot of different applications may fit in one project
● “Core” team
Example structure of corporate applications
Symfony
Team 1
Application 1
Team 1 library
Team 2
Application 2Common library 1
Common library 2
Example problems
● Create a bundle to process some common incoming
HTTP headers
● Make an update of some widely used bundle and make
everyone to upgrade
● Create a bundle with common layouts/assets (careful!)
Corporate is not opensource
● We don’t try to create an universal solution
● Bundles can depend on corporate architecture
● Some corporate bundles can go opensource
Standard complications
Versioning
How could we prevent breakage of our application by our
dependencies?
APP Bundle-1
Team 1
We’ve broken
everything...
because we can!
Use semantic
versioning!
https://semver.org
Dependencies
What if one bundle depends on another?
APP Bundle-1 Bundle-3
Team 1 Team 2
Bundle-2
Please add Bundle-3
to your AppKernel
Migration
APP Bundle-1 Bundle-3
Team 1 Team 2
Bundle-2
OK! Will try to
add that to the
next sprint
We released
major version of
Bundle-3. Please
update!
Coupling and cohesion
High cohesion
= modules must have exact purpose and clear functionality
Low coupling
= modules have to be independent from others
SOLID on bundle level
S: Bundle should have single purpose
O: Bundle should provide an API and be protected from external changes
L: Bundle should be a bundle
I: Bundle should not make us use unnecessary features
D: Bundle should depend on APIs (interfaces) instead of other bundles
Solution:
create libraries for common interfaces
Depend on libraries in your bundle instead of other bundles
Interfaces rarely break
Example: PSR-3 (logging interface)
Service as a dependency
BundleX BundleY
Service-Y2
LibraryZ
InterfaceZ
Service-X1 Service-Y1
Service as a dependency - Symfony way
my_chat:
dependencies:
http_client: "my_http.client"
formatter: "html.formatter"
Pass service name to bundle configuration
Note: use “alias” feature to reference a service by a
name
Framework-agnostic code
● Your code should be independent from framework
(controllers too)
● But bundles still depend on Symfony (bundles extend
your framework)
Unusual complications
Dependency hell
● Great amount of dependencies
● Great amount of consumers of your dependency
○ Hard to ask all consumers to update ASAP
● Lack of proper versioning
○ Legacy code
● Requirement of a different major versions of the same
dependency
● Dependencies created by different teams using
different approaches
Dependency hell - Best practices
● KISS
● Work hard if you want to create a shared library
● Implement versioning ASAP
● Provide style guidelines
Listeners
● Listener priority
○ Example: what is the priority of a security listener?
○ How to ensure that your listener will be the first one?
○ Conflict of listeners order at the same priority
● Standard “kernel” events vs own dispatchers
● How to disable a listener?
○ master/slave requests
○ by condition from another listeners
● How to be sure that listener processed an event?
Listeners - Best practices
● Avoid listeners (if you can)
○ lazy initialization
○ explicit pipelines
○ before/after
● Final listeners
● Provide exact API
○ define priority value
Assets & Twig
● Assetic
○ Removed for Symfony 4
○ Webpack Encore doesn’t do the same stuff
● Twig
○ Static HTML code(templates) depends on your JS/CSS framework
○ Hard to manage SSR and CSR
○ You still need another templating engine for JS
● Asset management
○ npm vs composer
○ Is Encore useful?
Assets & Twig - Best practices
● Don’t provide assets by bundles
● Avoid using of templates by bundles
● Move common static web stuff to separate project
(under npm)
Bundle testing
How to test a bundle?
Tester Bundle
Bundle testing - Best practices
public function testMyBundle()
{
$container = $this->createContainer();
$container->registerExtension(new MyExtension());
$container->loadFromExtension('my', []);
$container->compile();
$this->assertTrue(is_a(
$container->getDefinition('my.service')->getClass(),
MyInterface::class,
true
));
}
Other funny complications with bundles
● Register a route from a bundle
● A/B testing and graceful feature delivery
● Advanced bundle configuration processing
○ Type check
○ What about compile time validation?
● Optional dependencies
● What is “bundle API”? Can we define it well?
● Common application configuration
● ...
Conclusions
So where are we now?
● Modules (bundles) is a good way to extend a framework
- Now we know how to use them well
- Now we know the difference between modules and libraries
● Complications
- We know the complications that may appear when project grows
- We will try to avoid complications on early stage
What about Symfony
● Symfony is not an ideal framework
- But still the best one (for PHP)
- It’s made by people (not gods)
- It can be improved
- Now we can see parts that can be improved
What about us?
Be smart!
Thanks!
Any questions?

Modularity problems

  • 1.
    Modularity problems Architecture ofcorporate Symfony-applications
  • 2.
    Who I am ●Senior Software Engineer @ Upwork ● 10+ years of PHP (Pear -> ZF 1 -> Symfony 1 -> Yii 1 -> ....) ● 4+ years of Symfony 2 ● Also experience in Java (Spring, GWT, ...), C# (.Net), Ruby (Rails), JS (...) ● KNU, Faculty of Cybernetics, Theory of Programming
  • 4.
    How to perceivethis speech This speech ... ● … is not a manual ⇒ use Google please! ● … covers some problems of modularity ⇒ it doesn’t cover a lot of stuff. ● … displays some Symfony problems ⇒ but we love Symfony anyway =)
  • 5.
  • 6.
    Library vs Framework Library usefulpieces of code in one place Framework set of libraries, tools and principles of application development
  • 7.
    Framework ● It isa platform ● It defines application structure ● It unites components ● It offers tools ● It describes best practices
  • 8.
    Modules Modules (plugins, extensions,bundles etc.) is a way to extend a framework.
  • 9.
    Symfony modules Component isSymfony library. You need Composer to use Component. Bundle is Symfony module. You also need Composer to use Bundle. But you must enable Bundle in your AppKernel
  • 10.
    How does Bundleextend our framework? ● Commands ● Controllers ● Public services ○ also tagged services (event listeners, annotation processors etc.) ● Service Container processing ○ add support of custom service tags ○ preconfigure other modules (prepend) ● Other common code and assets (careful!)
  • 11.
    Symfony 2.x ⇒4.x ● Flex ○ Flex is a tool to simplify bundle installation. ● Bundle-less ○ Application is not a bundle ○ Symfony 4.x application directory structure is self-sufficient
  • 12.
  • 13.
    Specifics of bigproduct companies ● A lot of developer teams ● A lot of code ● A lot of different applications may fit in one project ● “Core” team
  • 14.
    Example structure ofcorporate applications Symfony Team 1 Application 1 Team 1 library Team 2 Application 2Common library 1 Common library 2
  • 15.
    Example problems ● Createa bundle to process some common incoming HTTP headers ● Make an update of some widely used bundle and make everyone to upgrade ● Create a bundle with common layouts/assets (careful!)
  • 16.
    Corporate is notopensource ● We don’t try to create an universal solution ● Bundles can depend on corporate architecture ● Some corporate bundles can go opensource
  • 17.
  • 18.
    Versioning How could weprevent breakage of our application by our dependencies? APP Bundle-1 Team 1 We’ve broken everything... because we can!
  • 19.
  • 20.
    Dependencies What if onebundle depends on another? APP Bundle-1 Bundle-3 Team 1 Team 2 Bundle-2 Please add Bundle-3 to your AppKernel
  • 21.
    Migration APP Bundle-1 Bundle-3 Team1 Team 2 Bundle-2 OK! Will try to add that to the next sprint We released major version of Bundle-3. Please update!
  • 22.
    Coupling and cohesion Highcohesion = modules must have exact purpose and clear functionality Low coupling = modules have to be independent from others
  • 24.
    SOLID on bundlelevel S: Bundle should have single purpose O: Bundle should provide an API and be protected from external changes L: Bundle should be a bundle I: Bundle should not make us use unnecessary features D: Bundle should depend on APIs (interfaces) instead of other bundles
  • 25.
    Solution: create libraries forcommon interfaces Depend on libraries in your bundle instead of other bundles Interfaces rarely break Example: PSR-3 (logging interface)
  • 26.
    Service as adependency BundleX BundleY Service-Y2 LibraryZ InterfaceZ Service-X1 Service-Y1
  • 27.
    Service as adependency - Symfony way my_chat: dependencies: http_client: "my_http.client" formatter: "html.formatter" Pass service name to bundle configuration Note: use “alias” feature to reference a service by a name
  • 28.
    Framework-agnostic code ● Yourcode should be independent from framework (controllers too) ● But bundles still depend on Symfony (bundles extend your framework)
  • 29.
  • 30.
    Dependency hell ● Greatamount of dependencies ● Great amount of consumers of your dependency ○ Hard to ask all consumers to update ASAP ● Lack of proper versioning ○ Legacy code ● Requirement of a different major versions of the same dependency ● Dependencies created by different teams using different approaches
  • 31.
    Dependency hell -Best practices ● KISS ● Work hard if you want to create a shared library ● Implement versioning ASAP ● Provide style guidelines
  • 32.
    Listeners ● Listener priority ○Example: what is the priority of a security listener? ○ How to ensure that your listener will be the first one? ○ Conflict of listeners order at the same priority ● Standard “kernel” events vs own dispatchers ● How to disable a listener? ○ master/slave requests ○ by condition from another listeners ● How to be sure that listener processed an event?
  • 33.
    Listeners - Bestpractices ● Avoid listeners (if you can) ○ lazy initialization ○ explicit pipelines ○ before/after ● Final listeners ● Provide exact API ○ define priority value
  • 34.
    Assets & Twig ●Assetic ○ Removed for Symfony 4 ○ Webpack Encore doesn’t do the same stuff ● Twig ○ Static HTML code(templates) depends on your JS/CSS framework ○ Hard to manage SSR and CSR ○ You still need another templating engine for JS ● Asset management ○ npm vs composer ○ Is Encore useful?
  • 35.
    Assets & Twig- Best practices ● Don’t provide assets by bundles ● Avoid using of templates by bundles ● Move common static web stuff to separate project (under npm)
  • 36.
    Bundle testing How totest a bundle? Tester Bundle
  • 37.
    Bundle testing -Best practices public function testMyBundle() { $container = $this->createContainer(); $container->registerExtension(new MyExtension()); $container->loadFromExtension('my', []); $container->compile(); $this->assertTrue(is_a( $container->getDefinition('my.service')->getClass(), MyInterface::class, true )); }
  • 38.
    Other funny complicationswith bundles ● Register a route from a bundle ● A/B testing and graceful feature delivery ● Advanced bundle configuration processing ○ Type check ○ What about compile time validation? ● Optional dependencies ● What is “bundle API”? Can we define it well? ● Common application configuration ● ...
  • 39.
  • 40.
    So where arewe now? ● Modules (bundles) is a good way to extend a framework - Now we know how to use them well - Now we know the difference between modules and libraries ● Complications - We know the complications that may appear when project grows - We will try to avoid complications on early stage
  • 41.
    What about Symfony ●Symfony is not an ideal framework - But still the best one (for PHP) - It’s made by people (not gods) - It can be improved - Now we can see parts that can be improved
  • 42.
  • 43.