De symfony 2013 dr. jenkins y mr. hyde - slides-842359017

1,708 views
1,637 views

Published on

1 Comment
0 Likes
Statistics
Notes
  • Be the first to like this

No Downloads
Views
Total views
1,708
On SlideShare
0
From Embeds
0
Number of Embeds
899
Actions
Shares
0
Downloads
22
Comments
1
Likes
0
Embeds 0
No embeds

No notes for slide

De symfony 2013 dr. jenkins y mr. hyde - slides-842359017

  1. 1. Dr. Jenkins y Mr. HydeActo I - Los personajesActo II - Envuelvelo en una API "REST"Acto III - Dos en unoActo IV - Sangre, sudor y migracionesActo V - URLs y Redisdesymfony 2013 Dr. Jenkins & Mr. Hyde
  2. 2. ACTO I - Los personajesdesymfony 2013 Dr. Jenkins & Mr. Hyde
  3. 3. Mr. HydeBodaclickdesymfony 2013 Dr. Jenkins & Mr. Hyde
  4. 4. • PHP 4 Spaghetti western• Ausencia MVC• Inicio del desarrollo en 2000• Reescritura del 90% en 2007• + de 25 desarrolladores• 4 Bases de datos• Más de 1.5M de líneas de código• Formado por: Directorio, CRM+ERP, Lista de bodas,Estadisticas, Extranet para clientes, CMS, Área decontenidos, WebTV, Etc.Mr. Hydedesymfony 2013 Dr. Jenkins & Mr. Hyde
  5. 5. desymfony 2013 Dr. Jenkins & Mr. Hyde
  6. 6. Dr. JenkinsCoredesymfony 2013 Dr. Jenkins & Mr. Hyde
  7. 7. • REST• PHP 5.4• Symfony 2.1.x• LAM• SQLite• Redis con Twemproxy• MongoDB• RabbitMQ• Jenkins, PHPUnit & Capifony• SatisDr. Jenkinsdesymfony 2013 Dr. Jenkins & Mr. Hyde
  8. 8. Joel Spolsky (Stack Overflow co-founder) dijo:(sobre Netscape)" Bueno, si. Lo hicieron. Lo hicieron al tomar la peordecisión estratégica que una empresa de software puede hacer:decidieron re-escribir el código desde 0"fuente: http://www.joelonsoftware.com/articles/fog0000000069.htmlDan Milsten, fundador de Hub8, en un post en On Startups (publicadopor Dharmesh Shah, inversor de Stack Exchange):"Prepárate para que este proyecto no termine jamás.Lo primero yabsolutamente crítico que tienes que entender sobre empezar unareescritura es que va a tomar muchísimo más de lo que esperas. Inclusodespués de que quitas el típico optimismo del desarrollador. He aquíporqué: Migrar datos es lo peor que puedes echarte a la cara, más alláde cualquier otra cosa.“fuente: http://onstartups.com/tabid/3339/bid/97052/How-To-Survive-a-Ground-Up-Rewrite-Without-Losing-Your-Sanity.aspxRe-escribir desde 0, según los expertosdesymfony 2013 Dr. Jenkins & Mr. Hyde
  9. 9. ACTO II - Envuelvelo en una API "REST"desymfony 2013 Dr. Jenkins & Mr. Hyde
  10. 10. EntidadesSobrenaturalesdesymfony 2013 Dr. Jenkins & Mr. Hyde
  11. 11. Las bases de datosBBDD 1BBDD 3 BBDD 4BBDD 2desymfony 2013 Dr. Jenkins & Mr. HydeBBDD 1BBDD 3 BBDD 4Relacionadas entre si por claves extranjeras mantenidas por software
  12. 12. //namespace BDKLegacyDbBundleEntity;/*** @ORMTable(name="boda.CLIENTE")* @ORMEntity*/class Cliente{//.../*** @ORMManyToMany(targetEntity="Tags")* @ORMJoinTable(name="bodamoll.b_tags",* joinColumns={@ORMJoinColumn(name="id_cliente", referencedColumnName="ID")},* inverseJoinColumns={@ORMJoinColumn(name="id_tag", referencedColumnName="id")}* )*/private $id_tag;//...Hackeando las DQLdesymfony 2013 Dr. Jenkins & Mr. Hyde
  13. 13. public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs){if ($this->kernel->getEnvironment() != test) {return;}$classMetadata = $eventArgs->getClassMetadata();$assoMap = $classMetadata->getAssociationMappings();foreach ($assoMap as $asso) {if (isset($asso["joinTable"])) {$asso["joinTable"]["name"] = str_replace(".", "_", $asso["joinTable"]["name"]);$classMetadata->setAssociationOverride($asso["fieldName"],$asso);}}$tableName = $classMetadata->getTableName();$classMetadata->setPrimaryTable(array(name => str_replace(".", "_", $tableName)));}Hackeando las DQLdesymfony 2013 Dr. Jenkins & Mr. Hyde
  14. 14. desymfony 2013 Dr. Jenkins & Mr. HydeUn Jenkins feliz
  15. 15. API Legacy.../api/[public|secured]/legacy/...desymfony 2013 Dr. Jenkins & Mr. Hyde
  16. 16. //namespace BDKLegacyBundleTestsControllerLegacyController;//PostPublicUserControllerTest$user = [legacy => [...],core => [...],];$client->request(POST, "/api/public/legacy/novio{$oauthString}",$user, array());API Legacy - Envíodesymfony 2013 Dr. Jenkins & Mr. Hyde
  17. 17. //namespace BDKLegacyBundleController;// class UserPublicControllerpublic function postNovioAction(Request $request){$view = FOSView::create();$viewData = $this->container->get(bdk.legacy.rest_manager)->postUser($request, ProfileType::USER);return $view->setStatusCode($viewData[status])->setData($viewData[data]);}API Legacy - Recepcióndesymfony 2013 Dr. Jenkins & Mr. Hyde
  18. 18. API Bridge.../api/[public|secured]/...desymfony 2013 Dr. Jenkins & Mr. Hyde
  19. 19. //Legacy$user = ["legacy" => [...],"core" => [...],];//Bridge$user = ["name" = "", "surname"= "", .... ];$client->request(POST, "/api/public/users{$this-> oauthString}&profile=user",$user, array());API Legacy - Envíodesymfony 2013 Dr. Jenkins & Mr. Hyde
  20. 20. // namespace BDKLegacyBundleController;// class BridgeUserPublicControllerpublic function postUsersAction(Request $request, $profile){$em = $this->get(doctrine.orm.legacy_entity_manager);//...$mapper = new CoreArrayToLegacyNovioArrayMapper($em);$coreArray = $request->request->all();$params = [core => $coreArray,legacy => $mapper->map($coreArray)];$request->request->replace($params);$view = FOSView::create();$viewData = $this->container->get(bdk.legacy.rest_manager)->postUser($request, ProfileType::USER);return $view->setStatusCode($viewData[status])->setData($viewData[data]);}API Legacy - Recepcióndesymfony 2013 Dr. Jenkins & Mr. Hyde
  21. 21. ACTO III - Dos en unodesymfony 2013 Dr. Jenkins & Mr. Hyde
  22. 22. FrontalloginúnicoApp.nuevaApp.antiguaPerfil delusuarioOAuthLogindesymfony 2013 Dr. Jenkins & Mr. Hyde
  23. 23. FrontalloginúnicoApp.nuevaApp.antiguaPerfil delusuarioOAuth + Token WSSE (login)Logindesymfony 2013 Dr. Jenkins & Mr. Hyde
  24. 24. FrontalloginúnicoApp.nuevaApp.antiguaPerfil delusuarioInfo delusuarioAcceso al perfil del usuarioOAuth + Token WSSE (login)Logindesymfony 2013 Dr. Jenkins & Mr. Hyde
  25. 25. Perfil delusuarioEnlaces a la plataforma antiguaLoginFrontalloginúnicoApp.nuevaApp.antiguaPerfil delusuarioInfo delusuarioOAuth + Token WSSE (login)Acceso al perfil del usuariodesymfony 2013 Dr. Jenkins & Mr. Hyde
  26. 26. Internet ReverseProxyPerfil del usuario - Reverse Proxybodaclick.com/^((?!my).)*$bodaclick.com/mydesymfony 2013 Dr. Jenkins & Mr. Hyde
  27. 27. desymfony 2013 Dr. Jenkins & Mr. Hyde
  28. 28. Perfil del usuario - Reverse Proxydesymfony 2013 Dr. Jenkins & Mr. HydeInternet ReverseProxybodaclick.com/^((?!my).)*$bodaclick.com/myiframe
  29. 29. ACTO IV - Sangre, sudor y migracionesdesymfony 2013 Dr. Jenkins & Mr. Hyde
  30. 30. • 4 bases de datos• Datos inconsistentes• Emails repetidos• Fechas como 0000-00-00• Enums• Tenemos tablas con más de 100 campos• Campos por defecto a 0000-00-00• Tablas tanto innodb como MyISAM• Cotejamientos diferentes (utf8, latin)• Tablas > 6 GBAPI Legacy - Mapeodesymfony 2013 Dr. Jenkins & Mr. Hyde
  31. 31. desymfony 2013 Dr. Jenkins & Mr. Hyde
  32. 32. Fuerza brutaMigracionesdesymfony 2013 Dr. Jenkins & Mr. Hyde
  33. 33. protected function migrateUser($override, $limit = 0){//...foreach ($oldUsers as $oldUser) {try {$userArray = $mapper->getUserCoreArray($oldUser);$userArray = $this->trimUserArray($userArray);$coreUser = $this->persistToCore($userArray, $oldUser, $override);$oldUser->setNewId($coreUser->getUser()->getId());$this->legacyEm->persist($oldUser);$this->legacyEm->flush();} catch (Exception $e) {//...}}}Migración por comando únicodesymfony 2013 Dr. Jenkins & Mr. Hyde
  34. 34. DivididasMigracionesdesymfony 2013 Dr. Jenkins & Mr. Hyde
  35. 35. MigrateUserCommand RabbitMQConsumidor de MapeosDatos mapeadosMigración en dos pasosdesymfony 2013 Dr. Jenkins & Mr. HydeMySQL MySQLApp. nueva App. antigua
  36. 36. protected function migrateUser($override, $limit = 0){//...foreach ($oldUsers as $oldUser) {try {$userArray = $mapper->getUserCoreArray($oldUser);//Usamos RabbitMQ$data[oldUser] = $oldUser;$data[userArray] = $userArray;$this->getContainer()->get(old_sound_rabbit_mq.migration_producer)->publish($serializer($data));} catch (Exception $e) {//...}}//...}Migración por comando y consumidordesymfony 2013 Dr. Jenkins & Mr. Hyde
  37. 37. protected function execute(AMQPMessage $migration){//...try {$coreUser = $this->persistToCore($userArray, $oldUser, $override);$oldUser->setNewId($coreUser->getUser()->getId());$this->legacyEm->persist($oldUser);$this->legacyEm->flush();} catch (Exception $e) {//...}//...}Migración por comando y consumidordesymfony 2013 Dr. Jenkins & Mr. Hyde
  38. 38. PerezosasMigracionesdesymfony 2013 Dr. Jenkins & Mr. Hyde
  39. 39. class SecurityController extends Controller{public function postTokenAction(){//...$username = $request->get(_username);$password = $request->get(_password);$preLoginEvent = new PreUserLoginEvent($username,$password);$this->get(event_dispatcher)->dispatch(UserEvents::PRE_LOGIN, $preLoginEvent);//...}}Migración por evento - Lanzamientodesymfony 2013 Dr. Jenkins & Mr. Hyde
  40. 40. ...Perezosas (Listener)//namespace BDKLegacyBundleEventListener;//class UserLoginCreateUserProfileListenerpublic function onPreUserLogin(PreUserLoginEvent $event){//...$coreUser = $this->legacyUserManager->createCoreUser($userArray,ProfileType::USER,[Create, Default]);//...}Migración por evento - Listenerdesymfony 2013 Dr. Jenkins & Mr. Hyde
  41. 41. Perezosas,asíncronas einversasMigracionesdesymfony 2013 Dr. Jenkins & Mr. Hyde
  42. 42. Evento asíncrono comunicado al driverAsyncEventDispatcherControladorEventopropiodesymfony 2013 Dr. Jenkins & Mr. Hyde
  43. 43. //abstract class AsyncWeddingEvent implements AsyncEventInterface;//class PostCreatWeddingEvent extends AsyncWeddingEvent;$event = new PostCreateWeddingEvent();$event->setWedding($wedding);$event->setUserProfile($userProfile);$this->container->get(bdk.async_event_dispatcher)->dispatch($event);Evento asíncrono lanzadodesymfony 2013 Dr. Jenkins & Mr. Hyde
  44. 44. Evento asíncrono comunicado al driverListener/Publicadoro DriverAsyncEventDispatcherControladorEventopropiodesymfony 2013 Dr. Jenkins & Mr. Hyde
  45. 45. Evento asíncrono para un sistema pub/subSistema Pub/SubListener/Publicadoro DriverAsyncEventDispatcherControladorEventopropiodesymfony 2013 Dr. Jenkins & Mr. Hyde
  46. 46. //Resources/config/async_drivers.ymlservices:bdk.wedding.async_event_driver_create:class: BDKWeddingBundleModelEventDispatcherAsyncDriverRabbitMQDriverarguments: [@old_sound_rabbit_mq.wedding_event_producer, @serializer]calls:- [setRoutingKey, [create.wedding.event]]tags:- { name: bdk.async_event_dispatcher, event: bdk.async.post_create_wedding }Configuración del driverdesymfony 2013 Dr. Jenkins & Mr. Hyde
  47. 47. Evento asíncrono para un sistema pub/subSistema Pub/SubSubscriptor MySQLMySQLListener/Publicadoro DriverAsyncEventDispatcherControladorEventopropiodesymfony 2013 Dr. Jenkins & Mr. HydeApp. nueva App. antigua
  48. 48. Evento asíncrono para un sistema pub/subConsumidor MySQLMySQLListener/Productoro DriverAsyncEventDispatcherControladorEventopropiodesymfony 2013 Dr. Jenkins & Mr. Hyde*.wedding.eventRabbitMQTopic ExchangeApp. nueva App. antigua
  49. 49. //BDKLegacyBundleEventListenerAsyncWeddingEventListenerclass WeddingEventListener implements ConsumerInterface{//...if ($wedding->getProvince()) {$legacyCountry = $this->legacyEm->getRepository(BDKLegacyDbBundle:Pais)->findOneByCodPais($wedding->getProvince()->getCountry());$legacyProvince = $this->legacyEm->getRepository(BDKLegacyDbBundle:Provincia)->findOneBy([idPais => $legacyCountry->getId(), provincia =>$wedding->getProvince()->getName()]);$legacyEventUser->setProvinciaId($legacyProvince->getId());}//...}Consumidordesymfony 2013 Dr. Jenkins & Mr. Hyde
  50. 50. MixtasMigracionesdesymfony 2013 Dr. Jenkins & Mr. Hyde
  51. 51. Migración perezosa mixtaMongoDbMySQLMySQLLegacyInternetInternetdesymfony 2013 Dr. Jenkins & Mr. HydePerfil delusuarioApp. antiguaApp. nueva
  52. 52. //postLoad//...$service = $em->getClassMetadata(BDKWeddingBundle:Wedding)->reflClass->getProperty(service);$service>setAccessible(true);$service>setValue($wedding,$this->dm->getReference(BDKWeddingBundle:Service,$wedding->getServiced()));Cargar datos desde MongoDBdesymfony 2013 Dr. Jenkins & Mr. Hyde
  53. 53. ACTO V - Routingdesymfony 2013 Dr. Jenkins & Mr. Hyde
  54. 54. /var/.../reportajes/45.php//45.php$ruta = "/desymfony-2013.html";//...Urls físicasdesymfony 2013 Dr. Jenkins & Mr. Hydebodaclick.com/desymfony-2013.html//desymfony-2013.html$idReportaje = 45;cargaContenido();//...<a href=‘url(“reportaje=45”)’> Texto </a>
  55. 55. Urls via redisSET www.bodaclick.com:reportaje:45/desymfony-2013.htmldesymfony 2013 Dr. Jenkins & Mr. Hyde<a href=‘url(“reportaje=45”)’> Texto </a> bodaclick.com/desymfony-2013.html//desymfony-2013.html$idReportaje = 45;cargaContenido();//...
  56. 56. desymfony 2013 Dr. Jenkins & Mr. Hyde
  57. 57. @etorras79etorras@BodaclickITEnrique Torras, como Mr. Hyde• Ingeniero en Informática• Desarrollando web desde 2004• Actualmente dirige el área dedesarrollo en Bodaclickdesymfony 2013 Dr. Jenkins & Mr. Hydeslideshare.net/etorras
  58. 58. @eguliasegulias• Desarrollador web desde 2006• Coqueteando con Symfony (yotros frameworks) desde 2007• Miembro de Symfony Madrid• Actualmente trabajando comolíder de equipo en Bodaclick@BodaclickITEduardo Gulias, como Dr. Jenkinsslideshare.net/eguliasjoind.in/talk/view/8834desymfony 2013 Dr. Jenkins & Mr. Hyde
  59. 59. ¿?desymfony 2013 Dr. Jenkins & Mr. Hyde

×