How to build customizablemultitenant web applications       Stephan Hochdörfer, bitExpert AG  "Building an application so ...
About me Stephan Hochdörfer, bitExpert AG Department Manager Research Labs enjoying PHP since 1999 S.Hochdoerfer@bitEx...
Single Tenancy
Developer   vs.   Businessman
Single Tenancy – more customers
Single Tenancy – even more customers
Where will this lead to?
Maintenancenightmare!
Single Tenancy                  Tenant 1                 Application                 Database                 Hardware
Single Tenancy        Tenant 1      Tenant 2      Tenant 3       Application   Application   Application       Database   ...
Multi Tenancy       Tenant 1    Tenant 2     Tenant 3                  Application                  Database              ...
What should be customizable?
What should be customizable?       Tenant 1    Tenant 2     Tenant 3                  Application                  Databas...
What should be customizable?       Tenant 1    Tenant 2     Tenant 3                  Application                  Databas...
Frontend | Branding How to skin an application?
Application | Frontend How to skin an application?                         Remember:                   It`s a web applicat...
Application | Frontend How to skin an application?                         HTML
Application | Frontend How to skin an application?                         HTML + CSS
Application | Frontend
Application | Frontend
Application | Frontend
Application | Frontend How to customize?  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/...
Application | Frontend How to customize?  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/...
Application | Frontend How to customize?  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/...
Application | Frontend Feature driven CSS                         Wait, there`s more...
Application | Frontend Feature driven CSS                         display: none
Application | Frontend Next level...
Application | Backend Menubar generation <?php if($user->hasEnabled(Module::ORDERMANAGEMENT)) {   if($user->canAccess(Orde...
Application | Backend Menubar generation <?php if($tenant->hasModule(Module::ORDERMANAGEMENT) {   if($user->hasEnabled(Mod...
Application | Backend Menubar generation                        Modularize!
Application | Backend Menubar generation                 Module 1      Module 2        Module 3                           ...
Application | Backend Menubar generation              Configuration for tenant 1                 Module 1            Modul...
Application | Backend Menubar generation              Configuration for tenant 2                 Module 1            Modul...
Application | Backend Optimize workflows <?php if(CC == $paymentType) {   // handle credit card payment } else if(COD == $...
Application | Backend Optimize workflows <?php if(CC == $paymentType) {   // handle credit card payment for some tenants! ...
Application | Backend Optimize workflows                  Decouple functionality!
Application | Backend Optimize workflows <?php $paymentType = CC; // set via request $payment     = PaymentFactory::create...
Application | Backend Optimize workflows <?php $paymentType = CC; // set via request $payment     = PaymentFactory::create...
Application | Backend Optimize workflows               How to add custom logic?
Application | Backend Custom logic - Subclassing?                               Abstract                               Pay...
Application | Backend Custom logic                        Any alternatives?
Application | Backend Custom logic                        Let`s add hooks...
Application | Backend Custom logic - Hooks <?php $paymentType = CC; // set via request $payment     = PaymentFactory::crea...
Application | Backend Custom logic         How to set the dependencies?
Application | Backend Custom logic                Inject the dependencies!
Application | Backend Custom logic – Dependency Injection <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www...
Application | Backend Custom logic                        Any improvements?
Application | Backend Custom logic <?php $paymentType = CC; // set via request $payment     = PaymentFactory::create($paym...
Application | Backend Custom logic <?php $paymentType = CC; // set via request $payment     = PaymentFactory::create($paym...
Application | Backend Custom logic         Aspect-oriented programming
Application | Backend Custom logic – Aspects for the masses! /**  * @aspect  */ class CustomPaymentProcessingAspect {     ...
Application | Backend Custom logic - Result <?php $paymentType = CC; // set via request $payment     = PaymentFactory::cre...
Application | Backend Next level...
Database Database – Where to store the data?
Database Database – Where to store the data?           We need to store data for a tenant!
Database Database – Where to store the data?           Database per Tenant?
Database Database – Where to store the data?           Database per Tenant?            Schema per Tenant?
Database Database – Where to store the data?           Database per Tenant?            Schema per Tenant?             Tena...
Database Database – How to access the data?                    vs.           ORM             dynamic statements
What`s beyond?                 Generalize you should!
What`s beyond? Multi Tenancy                 Software system family
What`s beyond? No single solution!
What`s beyond? A factory for mass production!
What`s beyond? Multi Tenancy – Single Instance                 Tenant 1    Tenant 2     Tenant 3                          ...
What`s beyond? Multi Tenancy – Multi Instance                 Tenant 1    Tenant 2     Tenant 3                           ...
What`s beyond? Generative Programming                         Configuration                          Configuration        ...
What`s beyond? Generative Programming                         Configuration                          Configuration        ...
What`s beyond? Generative Programming - Goal     Create an optimized application!
What`s beyond? Generative Programming - Goal     Create an optimized application             for one tenant!
What`s beyond? Generative Programming – Bonus points       Reduce application complexity
What`s beyond? Generative Programming – Bonus points  FileFrm FILEOrderService_php5 {    private String PreProcessor = "";...
What`s beyond? Generative Programming – Bonus points  FileFrm FILEOrderService_php5 {    [...]      private void configure...
Application | Backend Generative Programming – Bonus points Example: Preprocessor: Postprocessor: Output:
Application | Backend Generative Programming – Bonus points Example: Preprocessor: Postprocessor: Output: <?php $paymentTy...
Application | Backend Generative Programming – Bonus points Example: Preprocessor: $this->paymentPreProcessor->run($paymen...
Application | Backend Generative Programming – Bonus points Example: Preprocessor: $this->paymentPreProcessor->run($paymen...
What`s beyond? Generative Programming – Bonus points        Reduce maintenance support
What`s beyond? Generative Programming – Bonus points                          Implementation             Feature          ...
What`s beyond? Generative Programming – Bonus points                    Feature                 Implementation            ...
What`s beyond? Generative Programming – Bonus points                   Customer                    Feature                ...
What`s beyond? Generative Programming – The book
http://joind.in/2497
Flickr Creditshttp://www.flickr.com/photos/andresrueda/3452940751/http://www.flickr.com/photos/andresrueda/3455410635/
Upcoming SlideShare
Loading in …5
×

How to build customizable multitenant web applications - PHPBNL11

4,908 views
4,125 views

Published on

Published in: Technology, Business
1 Comment
2 Likes
Statistics
Notes
No Downloads
Views
Total views
4,908
On SlideShare
0
From Embeds
0
Number of Embeds
193
Actions
Shares
0
Downloads
80
Comments
1
Likes
2
Embeds 0
No embeds

No notes for slide

How to build customizable multitenant web applications - PHPBNL11

  1. How to build customizablemultitenant web applications Stephan Hochdörfer, bitExpert AG "Building an application so customizable its the last application youll ever need to build" Harrie Verveer
  2. About me Stephan Hochdörfer, bitExpert AG Department Manager Research Labs enjoying PHP since 1999 S.Hochdoerfer@bitExpert.de @shochdoerfer
  3. Single Tenancy
  4. Developer vs. Businessman
  5. Single Tenancy – more customers
  6. Single Tenancy – even more customers
  7. Where will this lead to?
  8. Maintenancenightmare!
  9. Single Tenancy Tenant 1 Application Database Hardware
  10. Single Tenancy Tenant 1 Tenant 2 Tenant 3 Application Application Application Database Database Database Hardware Hardware Hardware
  11. Multi Tenancy Tenant 1 Tenant 2 Tenant 3 Application Database Hardware
  12. What should be customizable?
  13. What should be customizable? Tenant 1 Tenant 2 Tenant 3 Application Database Hardware
  14. What should be customizable? Tenant 1 Tenant 2 Tenant 3 Application Database Hardware
  15. Frontend | Branding How to skin an application?
  16. Application | Frontend How to skin an application? Remember: It`s a web application!
  17. Application | Frontend How to skin an application? HTML
  18. Application | Frontend How to skin an application? HTML + CSS
  19. Application | Frontend
  20. Application | Frontend
  21. Application | Frontend
  22. Application | Frontend How to customize? <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>My App</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="stylesheet" type="text/css" href="css/styles/myapp.css" /> </head> <body> </body> </html>
  23. Application | Frontend How to customize? <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>My App</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="stylesheet" type="text/css" href="css/styles/<?php echo $tenant ?>.css" /> </head> <body> </body> </html>
  24. Application | Frontend How to customize? <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>My App</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="stylesheet" type="text/css" href="css/styles/myapp.css" /> <link rel="stylesheet" type="text/css" href="css/styles/<?php echo $tenant ? >.css" /> </head> <body> </body> </html>
  25. Application | Frontend Feature driven CSS Wait, there`s more...
  26. Application | Frontend Feature driven CSS display: none
  27. Application | Frontend Next level...
  28. Application | Backend Menubar generation <?php if($user->hasEnabled(Module::ORDERMANAGEMENT)) { if($user->canAccess(OrderManagement::LIST_ORDERS)) { $this->renderLink(OrderManagement::LIST_ORDERS); } if($user->canAccess(OrderManagement::ADD_ORDER)) { $this->renderLink(OrderManagement::ADD_ORDER); } if($user->canAccess(OrderManagement::CANCEL_ORDER)) { $this->renderLink(OrderManagement::CANCEL_ORDER); } }
  29. Application | Backend Menubar generation <?php if($tenant->hasModule(Module::ORDERMANAGEMENT) { if($user->hasEnabled(Module::ORDERMANAGEMENT)) { if($user->canAccess(OrderManagement::LIST_ORDERS)) { $this->renderLink(OrderManagement::LIST_ORDERS); } if($user->canAccess(OrderManagement::ADD_ORDER)) { $this->renderLink(OrderManagement::ADD_ORDER); } } }
  30. Application | Backend Menubar generation Modularize!
  31. Application | Backend Menubar generation Module 1 Module 2 Module 3 register at start up Application core
  32. Application | Backend Menubar generation Configuration for tenant 1 Module 1 Module 2 Module 3 register at start up Application core
  33. Application | Backend Menubar generation Configuration for tenant 2 Module 1 Module 2 Module 3 register at start up Application core
  34. Application | Backend Optimize workflows <?php if(CC == $paymentType) { // handle credit card payment } else if(COD == $paymentType) { // handle cash on delivery payment }
  35. Application | Backend Optimize workflows <?php if(CC == $paymentType) { // handle credit card payment for some tenants! if(in_array($tenant->getName(), array(tenant1, tenant2)) { // insert logic here... } } else if(COD == $paymentType) { // handle cash on delivery payment for some tenants! if(in_array($tenant->getName(), array(tenant3)) { // insert logic here... } }
  36. Application | Backend Optimize workflows Decouple functionality!
  37. Application | Backend Optimize workflows <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType); $payment->execute($order);
  38. Application | Backend Optimize workflows <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); $payment->execute($order);
  39. Application | Backend Optimize workflows How to add custom logic?
  40. Application | Backend Custom logic - Subclassing? Abstract Payment CC Payment CCPayment CCPayment Tenant 1 Tenant 2
  41. Application | Backend Custom logic Any alternatives?
  42. Application | Backend Custom logic Let`s add hooks...
  43. Application | Backend Custom logic - Hooks <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); if($this->paymentPreProcessor instanceof IPaymentPreProcessor) { $this->paymentPreProcessor->run($payment, $tenant, $order); } $payment->execute($order); if($this->paymentPostProcessor instanceof IPaymentPostProcessor) { $this->paymentPostProcessor->run($payment, $tenant, $order); }
  44. Application | Backend Custom logic How to set the dependencies?
  45. Application | Backend Custom logic Inject the dependencies!
  46. Application | Backend Custom logic – Dependency Injection <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.bitexpert.de/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bitexpert.de/schema/ http://www.bitexpert.de/schema/bitFramework-beans.xsd"> <bean id="MyApp.Service.Order" class="MyAppServiceOrder.php"> </bean> <bean id="Tenant1.Service.Order" class="MyAppServiceOrder.php"> <property name="paymentPreProcessor" ref="Tentant1.Payment.PaymentValidation" /> </bean> <bean id="Tenant2.Service.Order" class="MyAppServiceOrder.php"> <property name="paymentPreProcessor" ref="Tentant2.Payment.StrictValidation" /> <property name="paymentPostProcessor" ref="Tentant2.Payment.PushOrderToSAP" /> </bean> </beans>
  47. Application | Backend Custom logic Any improvements?
  48. Application | Backend Custom logic <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); if($this->paymentPreProcessor instanceof IPaymentPreProcessor) { $this->paymentPreProcessor->run($payment, $tenant, $order); } $payment->execute($order); if($this->paymentPostProcessor instanceof IPaymentPostProcessor) { $this->paymentPostProcessor->run($payment, $tenant, $order); }
  49. Application | Backend Custom logic <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); if($this->paymentPreProcessor instanceof IPaymentPreProcessor) { $this->paymentPreProcessor->run($payment, $tenant, $order); } $payment->execute($order); if($this->paymentPostProcessor instanceof IPaymentPostProcessor) { $this->paymentPostProcessor->run($payment, $tenant, $order); }
  50. Application | Backend Custom logic Aspect-oriented programming
  51. Application | Backend Custom logic – Aspects for the masses! /** * @aspect */ class CustomPaymentProcessingAspect { /** * @around MyAppServiceOrder->processPayment */ public function customFilter(AOPJoinPointInterface $joinPoint) { // @TODO: implement pre-processing logic // ... $result = $joinPoint->getAdviceChain()->proceed($joinPoint); // @TODO: implement post-processing logic // ... return $result; } }
  52. Application | Backend Custom logic - Result <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); $payment->execute($order);
  53. Application | Backend Next level...
  54. Database Database – Where to store the data?
  55. Database Database – Where to store the data? We need to store data for a tenant!
  56. Database Database – Where to store the data? Database per Tenant?
  57. Database Database – Where to store the data? Database per Tenant? Schema per Tenant?
  58. Database Database – Where to store the data? Database per Tenant? Schema per Tenant? Tenant Id per Row?
  59. Database Database – How to access the data? vs. ORM dynamic statements
  60. What`s beyond? Generalize you should!
  61. What`s beyond? Multi Tenancy Software system family
  62. What`s beyond? No single solution!
  63. What`s beyond? A factory for mass production!
  64. What`s beyond? Multi Tenancy – Single Instance Tenant 1 Tenant 2 Tenant 3 Application Database Hardware
  65. What`s beyond? Multi Tenancy – Multi Instance Tenant 1 Tenant 2 Tenant 3 Application Database Hardware
  66. What`s beyond? Generative Programming Configuration Configuration 1 ... n Implementation Implementation Generator Product components Generator Product components Generator Generator application application
  67. What`s beyond? Generative Programming Configuration Configuration Tenant 1 Tenant 1 Implementation Implementation Generator components Generator components Tenant x Tenant x Generator Generator application application
  68. What`s beyond? Generative Programming - Goal Create an optimized application!
  69. What`s beyond? Generative Programming - Goal Create an optimized application for one tenant!
  70. What`s beyond? Generative Programming – Bonus points Reduce application complexity
  71. What`s beyond? Generative Programming – Bonus points FileFrm FILEOrderService_php5 { private String PreProcessor = ""; private String PostProcessor = ""; public FILEOrderService_php5() { setFilename("Order.php5"); setRelativePath("/classes/MyApp/Service"); } private void assign() { BEGINCONTENT() <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); <!{PreProcessor}!> $payment->execute($order); <!{PostProcessor}!> ENDCONTENT() } }
  72. What`s beyond? Generative Programming – Bonus points FileFrm FILEOrderService_php5 { [...] private void configure() { if(this.getConfiguration().hasFeature(PreProcessor)) { PreProcessor = this.getPreProcessorContent( this.getConfiguration.getTenant() ); } if(this.getConfiguration().hasFeature(PostProcessor)) { PostProcessor = this.getPostProcessorContent( this.getConfiguration.getTenant() ); } } }
  73. Application | Backend Generative Programming – Bonus points Example: Preprocessor: Postprocessor: Output:
  74. Application | Backend Generative Programming – Bonus points Example: Preprocessor: Postprocessor: Output: <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType); $payment->execute($order);
  75. Application | Backend Generative Programming – Bonus points Example: Preprocessor: $this->paymentPreProcessor->run($payment, $tenant, $order); Postprocessor: Output:
  76. Application | Backend Generative Programming – Bonus points Example: Preprocessor: $this->paymentPreProcessor->run($payment, $tenant, $order); Postprocessor: Output: <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType); $this->paymentPreProcessor->run($payment, $tenant, $order); $payment->execute($order);
  77. What`s beyond? Generative Programming – Bonus points Reduce maintenance support
  78. What`s beyond? Generative Programming – Bonus points Implementation Feature component
  79. What`s beyond? Generative Programming – Bonus points Feature Implementation component
  80. What`s beyond? Generative Programming – Bonus points Customer Feature Implementation component
  81. What`s beyond? Generative Programming – The book
  82. http://joind.in/2497
  83. Flickr Creditshttp://www.flickr.com/photos/andresrueda/3452940751/http://www.flickr.com/photos/andresrueda/3455410635/

×