Desmistificando o cairngorm

2,029 views

Published on

Published in: Technology, Education

Desmistificando o cairngorm

  1. 1. Desmistificando o Cairngorm Eric Cavalcanti [email_address] @ericoc 06 de Fevereiro de 2010
  2. 2. Sobre mim <ul><li>Eric Cavalcanti </li></ul><ul><ul><li>Engenheiro de Software Sênior do C.E.S.A.R (Centro de Estudos e Sistemas Avançados do Recife) </li></ul></ul><ul><ul><li>Mestre em Engenharia de Software pelo C.E.S.A.R </li></ul></ul><ul><ul><li>Certificado Scrum Master pela Scrum Alliance </li></ul></ul><ul><li>Background </li></ul><ul><ul><li>Trabalha com desenvolvimento de Software há mais de 10 anos . </li></ul></ul><ul><ul><li>Desenvolvedor Web/Mobile utilizando Java, .NET, PHP e Adobe Flex. </li></ul></ul><ul><ul><li>Instrutor Adobe Flex da Imedia Brasil. </li></ul></ul><ul><ul><li>Idealizador e principal desenvolvedor do projeto FireScrum : Ferramenta Open Source de Apoio à Gestão de Projetos utilizando Scrum (Flex e Java) </li></ul></ul>
  3. 3. O que é o Cairngorm? <ul><li>Cairngorm é um framework arquitetural baseado no MVC para o desenvolvimento de aplicações em Adobe Flex </li></ul>
  4. 4. História <ul><li>Cairngorm foi um dos primeiros frameworks arquiteturais para Adobe Flex </li></ul><ul><li>Primeira versão foi desenvolvida para Flash, antes mesmo do Flex existir. </li></ul><ul><li>Foi desenvolvido pela interation::two , na qual foi adquirida pela Macromedia em 2005 </li></ul><ul><li>Última versão estável (2.2.1) foi lançada em 30 de maio de 2007 </li></ul><ul><li>Versão 3 Beta foi anunciada em 5 de outubro de 2009 </li></ul>
  5. 5. Pontos fortes <ul><li>Fornece uma arquitetura bem definida e baseada em padrões </li></ul><ul><li>Padrões bem conhecidos como MVC, Singleton e Observer </li></ul><ul><li>Organização do código </li></ul><ul><li>Compartilha uma terminologia comum a todos da equipe </li></ul><ul><li>Encoraja desenvolvedores a identificar, organizar e separar o código baseado em papéis e responsabilidades </li></ul><ul><li>Facilidade de manutenção </li></ul><ul><li>Facilita a construção de aplicações desenvolvidas por equipe </li></ul><ul><li>Bem documentado </li></ul>
  6. 6. Pontos fracos <ul><li>O nome! “Cairn... O quê?” </li></ul><ul><li>É necessário escrever várias classes para um simples Use Case. </li></ul><ul><li>Curva de aprendizado alta </li></ul><ul><li>Nem sempre modificar a view pelo model é suficiente em todos os casos </li></ul>
  7. 7. Vamos desmistificá-lo!
  8. 8. <ul><li>Model – Armazena dos dados e o estado da aplicação </li></ul><ul><li>View – &quot;Renderiza&quot; o model em uma forma específica para a interação, geralmente uma interface de usuário. </li></ul><ul><li>Controller – Controla o fluxo da sua aplicação invocando alterações no Model </li></ul>
  9. 9. Fluxo Básico do Cairngorm
  10. 10. Aplicação de exemplo
  11. 11. VO (Value Object) <ul><li>Objeto que armazena somente dados </li></ul><ul><li>[ Bindable ] </li></ul><ul><li>public class ContatoVO </li></ul><ul><li>{ </li></ul><ul><ul><li>public var id:int; </li></ul></ul><ul><ul><li>public var nome:String; </li></ul></ul><ul><ul><li>public var telefone:String; </li></ul></ul><ul><ul><li>public var email:String; </li></ul></ul><ul><li>} </li></ul>
  12. 12. Controller CairngormEvent FrontController Command
  13. 13. CairngormEvent Olá! Eu sou o FrontController ! Chame um CairngormEvent sempre que precisar alterar o Model !
  14. 14. CairngormEvent Eu sou o AdicionarContatoEvent ! É só me instanciar passando o ContatoVO que deverá ser adicionado e me lançar ! public class AdicionarContatoEvent extends CairngormEvent { public static const EVENT_ID :String = &quot;ADICIONAR_CONTATO_EVENT&quot; ; public var contato:ContatoVO ; public function AdicionarContatoEvent( contato:ContatoVO ) { super ( EVENT_ID ); this . contato = contato; } }
  15. 15. CairngormEvent Vejam como é simples me utilizar!! // Cria um contato e atribui as informações var contato:ContatoVO = new ContatoVO(); contato.nome = txtNome.text; contato.telefone = txtTelefone.text; contato.email = txtEmail.text; // Cria um evento do tipo AdicionarContatoEvent informando o contato a ser adicionado var contatoEvent :AdicionarContatoEvent = new AdicionarContatoEvent(contato); // Lança o evento contatoEvent .dispatch();
  16. 16. FrontController Eu capturo o evento e tenho um mapeamento que diz qual Command deverá ser chamado para cada evento !
  17. 17. FrontController Por exemplo: para um AdicionarContatoEvent eu chamo o AdicionarContatoCommand !
  18. 18. FrontController public class AgendaController extends FrontController { public function AgendaController() { addCommand( AdicionarContatoEvent.EVENT_ID, AdicionarContatoCommand ); addCommand( AtualizarContatoEvent.EVENT_ID, AtualizarContatoCommand ); addCommand( ExcluirContatoEvent.EVENT_ID, ExcluirContatoCommand); } } Vejam como eu faço o mapeamento entre um CairngormEvent e um Command !!
  19. 19. Command Eu capturo os dados contidos no CairngormEvent que me chamou e altero o Model .
  20. 20. Command Eu faço isso através do meu método execute . <ul><li>public class AdicionarContatoCommand implements ICommand </li></ul><ul><li>{ </li></ul><ul><li>public function execute(event:CairngormEvent): void </li></ul><ul><li>{ </li></ul><ul><ul><li>//Captura os dados do evento </li></ul></ul><ul><ul><li>//Atualiza o model </li></ul></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  21. 21. Epa!! Você não pode dizer que vai atualizar o Model sem antes me apresentar! Eu sou o ModelLocator , o cara que centraliza e armazena as informações do Model . Então o Command deve alterar as informações que EU TENHO !
  22. 22. ModelLocator package com.flexforkids.model { ... [ Bindable ] public class AgendaModelLocator { public var contatos:ArrayCollection = new ArrayCollection(); public var contatoAtual:ContatoVO; public static const TELA_PRINCIPAL : uint = 0; public static const TELA_FORM_USUARIO : uint = 1; public var applicationView:uint = TELA_PRINCIPAL; ... private static var _instance:AgendaModelLocator; public function AgendaModelLocator(param: ForceInstance ){} public static function getInstance() :AgendaModelLocator { if (_instance== null ) { _instance = new AgendaModelLocator( new ForceInstance()); } return _instance; } } } class ForceInstance { } Aqui estou eu!
  23. 23. Atualizando o Model public class AdicionarContatoCommand implements ICommand { public function execute(event:CairngormEvent): void { var adicionarContatoEvent:AdicionarContatoEvent; adicionarContatoEvent = event as AdicionarContatoEvent; AgendaModelLocator.getInstance().contatos.addItem(adicionarContatoEvent.contato); } } Agora que nosso amigo se apresentou, vejam como eu o atualizo !
  24. 24. Views e ModelLocator [ Bindable ] private var _model:AgendaModelLocator = AgendaModelLocator.getInstance(); <view:ContatosView contatos=&quot; { _model.contatos } &quot; > </view:ContatosView> [ Bindable ] public var contatos:ArrayCollection; <mx:DataGrid dataProvider=“ { contatos } &quot; > <mx:columns> <mx:DataGridColumn headerText=&quot; Nome &quot; dataField=&quot; nome ” /> <mx:DataGridColumn headerText=&quot; Telefone &quot; dataField=&quot; telefone &quot; /> <mx:DataGridColumn headerText=&quot; E-mail &quot; dataField=&quot; email “ /> </mx:columns> </mx:DataGrid> E como as views recebem referências aos dados do ModelLocator , elas são automaticamente atualizadas ! AgendaKids.mxml ContatosView.mxml
  25. 25. MVC do Cairngorm <ul><li>Model – ModelLocator </li></ul><ul><li>View – MXML e classes .as </li></ul><ul><li>Controller – FrontController </li></ul><ul><ul><li>Command </li></ul></ul><ul><ul><li>CairngormEvent </li></ul></ul>
  26. 26. Revisão do Fluxo Básico do Cairngorm
  27. 27. Ei!! Dessa forma que vocês mostraram os dados estão locais . E se esses dados precisarem representar informações vindas de um back-end ? Desenvolvedor
  28. 28. Business Delegate Olá! Eu tenho uma proposta pra vocês! Me chamo Business Delegate ! Forneço serviços de back-end ! É só solicitar pra mim, que eu me encarrego de acessar o back-end !
  29. 29. O acordo! Então de agora em diante sempre que eu precisar acessar o back-end eu chamo você?
  30. 30. O acordo! Exato! Mas tem uma coisa, você precisa me dizer para quem devo responder quando eu trouxer os dados do back-end ! E sendo assim, quem for receber o resultado ( Responder) deverá atualizar o Model .
  31. 31. O acordo! Ok! Não se preocupe, no caso, você responderá para mim mesmo. Ou seja, além de Command eu também serei um Responder .
  32. 32. Command Turbinado! <ul><li>public class AdicionarContatoCommand implements ICommand, IResponder </li></ul><ul><li>{ </li></ul><ul><li>private var _model:AgendaModelLocator = </li></ul><ul><li>AgendaModelLocator.getInstance(); </li></ul><ul><li>public function execute (event:CairngormEvent): void </li></ul><ul><li>{ </li></ul><ul><ul><li>var adicionarContatoEvent:AdicionarContatoEvent; </li></ul></ul><ul><ul><li>adicionarContatoEvent = event as AdicionarContatoEvent; </li></ul></ul><ul><ul><li>var delegate:ContatoDelegate = new ContatoDelegate( this ); </li></ul></ul><ul><ul><li>delegate.salvarContato(adicionarContatoEvent.contato); </li></ul></ul><ul><li>} </li></ul><ul><li>public function result (data:Object): void </li></ul><ul><li>{ </li></ul><ul><ul><li>_model.contatos.addItem(data.result); </li></ul></ul><ul><ul><li>_model.applicationView = AgendaModelLocator.TELA_PRINCIPAL; </li></ul></ul><ul><li>} </li></ul><ul><li>public function fault (info:Object): void </li></ul><ul><li>{ </li></ul><ul><ul><li>_model.mensagemErro = &quot;Error &quot; + info.fault; </li></ul></ul><ul><ul><li>Alert.show(_model.mensagemErro); </li></ul></ul><ul><li>} </li></ul><ul><li>} </li></ul>Aqui estou eu reformulado para utilizar o Business Delegate !
  33. 33. Service Locator Pessoal, esse é o Service Locator que trabalha para mim! Ele é quem armazena os RemoteObject , WebService e HTTPService .
  34. 34. Service Locator <?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?> <cairngorm:ServiceLocator xmlns:cairngorm=&quot; com.adobe.cairngorm.business.* &quot; xmlns:mx=&quot; http://www.adobe.com/2006/mxml &quot; > <mx:RemoteObject id=&quot; ro &quot; destination=&quot; zend &quot; endpoint=&quot; http://localhost/agendakids/server.php &quot; source=&quot; AgendaService &quot; /> </cairngorm:ServiceLocator> Nesse caso específico, eu tenho um RemoteObject que faz acesso ao PHP via Zend AMF !
  35. 35. Business Delegate public class ContatoDelegate { private var _responder:IResponder; private var _service:Object; public function ContatoDelegate( responder:IResponder ) { this ._responder = responder; this ._service = ServiceLocator.getInstance().getRemoteObject( &quot;ro&quot; ); } public function salvarContato(contato:ContatoVO ): void { var token:AsyncToken = this ._service.salvarContato(contato); token.addResponder( this ._responder); } ... } Não vão contar para o Command ! Mas é assim que eu trabalho internamente!
  36. 36. Fluxo Completo do Cairngorm
  37. 37. Estrutura de Pastas e Arquivos
  38. 38. Bem! Eu acho que agora comecei a entender de verdade esse Cairngorm. Mas a pergunta que não quer calar: “É possível reduzir a quantidade de classes necessárias?” Desenvolvedor
  39. 39. SIM! Vamos ver uma das possibilidades!
  40. 40. Imersão no CairngormEvent
  41. 41. Front Controller <ul><li>public class AgendaController extends FrontController </li></ul><ul><li>{ </li></ul><ul><li>public static const ADICIONAR_CONTATO_EVENT : String = &quot;ADICIONAR_CONTATO_EVENT&quot; ; </li></ul><ul><li>public static const ATUALIZAR_CONTATO_EVENT : String = &quot;ATUALIZAR_CONTATO_EVENT&quot; ; </li></ul><ul><li>public static const CONSULTAR_CONTATOS_EVENT : String = &quot;CONSULTAR_CONTATOS_EVENT&quot; ; </li></ul><ul><li>public static const EXCLUIR_CONTATO_EVENT : String = &quot;EXCLUIR_CONTATO_EVENT&quot; ; </li></ul><ul><li>public static const EXIBIR_TELA_CONTATO_EVENT : String = &quot;EXIBIR_TELA_CONTATO_EVENT&quot; ; </li></ul><ul><li>public static const EXIBIR_TELA_PRINCIPAL_EVENT : String = &quot;EXIBIR_TELA_PRINCIPAL_EVENT&quot; ; </li></ul><ul><li>public static const SELECIONAR_CONTATO_EVENT : String = &quot;SELECIONAR_CONTATO_EVENT&quot; ; </li></ul><ul><li>public function AgendaController() </li></ul><ul><li>{ </li></ul><ul><ul><li>addCommand( ADICIONAR_CONTATO_EVENT, AdicionarContatoCommand ); </li></ul></ul><ul><ul><li>addCommand( ATUALIZAR_CONTATO_EVENT, AtualizarContatoCommand ); </li></ul></ul><ul><ul><li>addCommand( CONSULTAR_CONTATOS_EVENT, ConsultarContatosCommand ); </li></ul></ul><ul><ul><li>addCommand( EXCLUIR_CONTATO_EVENT, ExcluirContatoCommand ); </li></ul></ul><ul><ul><li>addCommand( EXIBIR_TELA_CONTATO_EVENT, ExibirTelaContatoCommand ); </li></ul></ul><ul><ul><li>addCommand( EXIBIR_TELA_PRINCIPAL_EVENT, ExibirTelaPrincipalCommand ); </li></ul></ul><ul><ul><li>addCommand( SELECIONAR_CONTATO_EVENT, SelecionarContatoCommand ); </li></ul></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  42. 42. Usando o data do CairngormEvent // Cria um contato e atribui as informações var contato:ContatoVO = new ContatoVO(); contato.nome = &quot;Eric Cavalcanti&quot; ; contato.email = &quot;ecavalcanti@gmail.com&quot; ; contato.telefone = &quot;99999999&quot; ; // Cria um evento do tipo AdicionarContatoEvent informando o contato a ser adicionado var contatoEvent :AdicionarContatoEvent = new AdicionarContatoEvent(contato); // Lança o evento contatoEvent .dispatch(); // Cria um contato e atribui as informações var contato:ContatoVO = new ContatoVO(); contato.nome = &quot;Eric Cavalcanti&quot; ; contato.email = &quot;ecavalcanti@gmail.com&quot; ; contato.telefone = &quot;99999999&quot; ; // Cria um evento do tipo CairngormEvent var contatoEvent :CairngormEvent = new CairngormEvent(AgendaController.ADICIONAR_CONTATO_EVENT); // Atribui o contato ao data do Evento contatoEvent .data = contato; // Lança o evento contatoEvent .dispatch();
  43. 43. Usando o data no Command <ul><li>public class AdicionarContatoCommand implements ICommand, IResponder </li></ul><ul><li>{ </li></ul><ul><li>... </li></ul><ul><li>public function execute(event:CairngormEvent): void </li></ul><ul><li>{ </li></ul><ul><ul><li>var adicionarContatoEvent:AdicionarContatoEvent; </li></ul></ul><ul><ul><li>adicionarContatoEvent = event as AdicionarContatoEvent; </li></ul></ul><ul><ul><li>var delegate:ContatoDelegate = new ContatoDelegate( this ); </li></ul></ul><ul><ul><li>delegate.salvarContato(adicionarContatoEvent.contato); </li></ul></ul><ul><li>} </li></ul><ul><li>... </li></ul><ul><li>} </li></ul><ul><li>public class AdicionarContatoCommand implements ICommand, IResponder </li></ul><ul><li>{ </li></ul><ul><li>... </li></ul><ul><li>public function execute(event:CairngormEvent): void </li></ul><ul><li>{ </li></ul><ul><ul><li>var delegate:ContatoDelegate = new ContatoDelegate( this ); </li></ul></ul><ul><ul><li>delegate.salvarContato(event.data as ContatoVO); </li></ul></ul><ul><li>} </li></ul><ul><li>... </li></ul><ul><li>} </li></ul>
  44. 44. Comparando
  45. 45. Links <ul><li>Cairngorm - http://opensource.adobe.com/wiki/display/cairngorm/Cairngorm </li></ul><ul><li>Introducing Cairngorm - http://www.adobe.com/devnet/flex/articles/introducing_cairngorm.html </li></ul><ul><li>Developing Flex RIAs with Cairngorm microarchitecture - http://www.adobe.com/devnet/flex/articles/cairngorm_pt1.html </li></ul><ul><li>Getting Started with Cairngorm - http://www.davidtucker.net/category/cairngorm </li></ul><ul><li>Adobe Cairngorm Plugin - http://opensource.adobe.com/wiki/display/cairngorm/Plugin </li></ul><ul><li>Enterprise IDE Plugin - http://www.idefactory.com </li></ul><ul><li>FireScrum- http://www.firescrum.com </li></ul><ul><li>Bitstrips- http://www.bitstrips.com </li></ul>
  46. 46. Obrigado! Eric Cavalcanti [email_address] @ericoc

×