Decouple your framework now, thank me later
-
Upload
michelangelo-van-dam -
Category
Engineering
-
view
298 -
download
1
Transcript of Decouple your framework now, thank me later
DECOUPLE YOUR FRAMEWORK NOW, THANK ME LATERMICHELANGELO VAN DAM - @DRAGONBE
MICHELANGELO VAN DAM
CEO at in2it Lead PHP architect Community leader Coach & mentor FOSS contributor Public speaker
FRAMEWORKS ARE GREAT!
• They abstract common tasks like email, database connectivity, routing and a ton more…
• They allow us to quickly develop complex applications
• They offer good to great security and robustness
BUT…
• Frameworks have a nasty aftertaste when building business logic
• You need to use their database, log or cache adapter everywhere
• View templates are requiring framework components like translations, escaping and other trivial purposes
• Best practices require to use modules, bundles or features to separate business logic components
IMPROVEMENTS THROUGH STANDARDS
• The PHP-FIG standards motivates frameworks to use great components to abstract functionality and ensure interoperability with other frameworks and tools
• Major frameworks already offer this straight off the bat
• But add their own “secret sauce” to link it within their framework, even when using Dependency Injection
WHAT ARE THE CHALLENGES?
UPGRADE (OR CHANGE) YOUR FRAMEWORK
UPGRADE TO THE LATEST PHP VERSION
BUSINESS LOGIC AND FRAMEWORKS MIXED
Framework X Business Logic
BL DB
FW DB
FW Logging
FW Mail
FW Service
BL Logging
BL Mail
BL Services
APPLYING INTERFACES IN BETWEEN
Framework X Business Logic
FW DB
FW Logging
FW Mail
FW Service
BL DB
BL Logging
BL Mail
BL Services
DB Interface
Logging Interface
Mail Interface
Service Interface
RESTAURANT PRINCIPLE
THE HOSTESWILL BRING YOU TO YOUR TABLE AND GIVES YOU THE MENU AND WINE LIST.
A WAITERWILL TAKE YOUR ORDER FOR DRINKS AND FOOD
BARTENDERWILL PREPARE YOUR DRINKS
KITCHENWILL PREPARE YOUR MEAL
YOUR WAITERBRINGS YOUR DRINKS
YOUR WAITERWILL DELIVER YOUR FOOD
YOUR WAITERWILL GIVE YOU THE BILL WHEN DONE
YOUR WAITER
• Interfaces with the hostess to get started
• Interfaces with you to take your order
• Interfaces with the bar for drinks
• Interfaces with the cash register to present you a bill
YOUR WAITER
• Receives notification you have arrived at your table
• Receives your order from you
• Receives drinks from the bartender
• Receives food from the kitchen
• Receives money from you
HOW DO WE DO THIS IN CODE?
INTERFACESDESIGN BY CONTRACTS
WHAT ARE INTERFACES
• Interfaces define a requirement without concrete implementation
• There’s no limit on interfaces implemented
• Everyone understands the “contract” immediately
• One interface per goal, feature or purpose
COMMON INTERFACES IN PHP
• Countable
• Iterator (and derivates)
• See language.oop5.interfaces on php.net for more details!
CUSTOM INTERFACES
interface TableGatewayInterface { public function find(int $id): array;
public function fetchRow( array $where = [], array $order = [] ): array;
public function fetchAll( array $where = [], array $order = [], int $count = 0, int $offset = 0 ): array;
public function insert(array $data): int;
public function update(array $data, array $where = []): int; }
BONUS: VERY TESTABLE!!!
• No need to implement concrete code, just use interfaces to guide your development
• A class can implement multiple interfaces, testing can occur on a single interface functionality at a time.
EVENTS
WHAT ARE EVENTS?
• Events allow us to run tasks in the background and call back when completed.
• Implements the observer pattern (e.g. SplSubject & SplObserver)
• One observer can have many subscribers
• A subscriber can subscribe to many observer objects
EXAMPLE
$memberService = new MemberService(); $memberService->attach(new DBObserver()); $memberService->attach(new LogObserver()); $memberService->attach(new EmailObserver()); $memberService->attach(new CacheObserver()); $memberService->attach(new SearchObserver()); $memberService->register(new Member('John', 'Doe', '[email protected]'));
EVENT OBSERVATION
Register
DB
Log
Cache
Search
Storing in DB
Logging
Sending email
Write to cache
Update indexes
EVENT OBSERVATION AFTER EVENTS
Register
DB
Log
Cache
Search
Storing in DB
Logging
Sending email
Write to cache
Update indexes
BENEFITS
• Reusable logic
• Runs in the background, so no delays
• Scalable
GLUING ALL TOGETHER
Core Business Logic
Silex Web Frontend
Apigility API
Phalcon Web Backend
Core Business Logic
Slim Web Frontend
Zend Expressive
API
Python Web Backend
GLUE CLASS TO INTERACT 1/3
class SilexServiceProvider implements ServiceProviderInterface { public function register(Container $container) { $dsn = $container['cb_config_db.dsn'] ?: ''; $username = $container['cb_config_db.username'] ?: ''; $password = $container['cb_config_db.password'] ?: ''; $pdo = new \PDO($dsn, $username, $password);
$authorTable = new AuthorTable($pdo); $authorHydrator = new AuthorHydrator(); $author = new Author();
$bookTable = new BookTable($pdo); $bookHydrator = new BookHydrator(); $book = new Book(); $memberTable = new MemberTable($pdo); $memberHydrator = new MemberHydrator(); $member = new Member();
GLUE CLASS TO INTERACT 2/3
$serviceLocator = new ServiceLocator(); $serviceLocator ->set('\Cloudbooks\Author\Model\AuthorTable', $authorTable) ->set('\Cloudbooks\Author\Model\AuthorHydrator', $authorHydrator) ->set('\Cloudbooks\Author\Entity\Author', $author) ->set('\Cloudbooks\Book\Model\BookTable', $bookTable) ->set('\Cloudbooks\Book\Model\BookHydrator', $bookHydrator) ->set('\Cloudbooks\Book\Entity\Book', $book) ->set('\Cloudbooks\Member\Model\MemberTable', $memberTable) ->set('\Cloudbooks\Member\Model\MemberHydrator', $memberHydrator) ->set('\Cloudbooks\Member\Entity\Member', $member); }
GLUE CLASS TO INTERACT 3/3
$container['cb_author_service'] = $container->factory(function () use ($serviceLocator) { $serviceFactory = new AuthorServiceFactory(); return $serviceFactory->createService($serviceLocator); }); $container['cb_book_service'] = $container->factory(function () use ($serviceLocator) { $serviceFactory = new BookServiceFactory(); return $serviceFactory->createService($serviceLocator); }); $container['cb_member_service'] = $container->factory(function () use ($serviceLocator) { $serviceFactory = new MemberServiceFactory(); return $serviceFactory->createService($serviceLocator); }); }
LET’S RECAP
https://github.com/sensiolabs-de/deptrac
THANK YOU!