logo
  • Home
  • Acerca
  • Autores
  • Faq
  • Rede
  Twitter   Feed-me! RSS!
Dez 14

Dicas para ser levado a sério

Escrito por Igor Musardo em .NET, 1, 2.0, 4, api, app, AR, arte, Artigo, auto, BI, C#, Censo, class, cliente, Curso, Dica, Emprego, err, fonte, for, Geral, html, ide, IE, if, image, int, Liderança, lista, Mercado de Trabalho, mg, Motivação, O, on, Outros, Pessoal, problema, pt, RIA, Ria’s Geral, S+S, UI, VOZ, XP @ 12 14th, 2011 | via http://www.igormusardo.com.br | Sem comentários
Igor Musardo
? X
  • Bookmarks

Blinkbits BlinkLists BlogLines Blogmarks Buddymarks CiteULike Co.mments Del.icio.us Digg Diigo

Fark Feed Me Links Furl Google Linkagogo ma.gnolia Mister Wong Newsvine Propeller Rawsugar

Reddit Rojo Simpy Sphinn Spurl Squidoo StumbleUpon Tailrank Technorati Yahoo

More »

Voc? j? percebeu que, em qualquer grupo, algumas pessoas s?o naturalmente levadas a s?rio, e outras n?o? E isso raramente tem rela??o com ser ou n?o sisudo – o indiv?duo de gravata com mais cara de brabo e sem gra?a numa equipe pode n?o ser levado a s?rio por ningu?m, e o colega que est? sempre de bom humor pode ser visto com respeito por todos.

O que h? em comum entre as pessoas que s?o levadas a s?rio? ? dif?cil fazer uma lista completa, mas no caso das pessoas em posi??o de lideran?a (formalizada ou n?o), eu gosto de uma defini??o de W. E. B. Griffin: o que elas dizem tem um tom especial, que indica “eu serei levado a s?rio” – ou “eu serei obedecido”, no caso da lideran?a aliada a chefia formal. Mas esse tom n?o ? produzido pela voz, e sim pelas atitudes, que aos poucos conquistam o respeito dos que est?o ao seu redor.

E o que os outros v?em em n?s, por interm?dio das nossas atitudes, come?a nas nossas escolhas e no modo como n?s mesmos nos vemos – em outras palavras, o caminho come?a quando n?s mesmos come?amos a nos levar suficientemente a s?rio. O artigo “5 Reasons People Don’t Take You Seriously and How to Fix It” apresenta uma s?rie de raz?es pelas quais as pessoas podem n?o estar levando voc? a s?rio, e convido voc? a pass?-las rapidamente em revista neste meu resumo.

Vamos a elas:

N?o manter a palavra

Isso n?o significa exatamente a mesma coisa que “ser mentiroso”, neste contexto. Significa anunciar freq?entemente planos e inten??es que na pr?tica voc? acaba n?o realizando, fazer promessas que n?o poder? cumprir, ou mesmo que n?o pretende cumprir. A cada m?s voc? anuncia que vai fazer uma dieta, que vai melhorar as condi??es de trabalho da equipe, e que no s?bado que vem vai levar a fam?lia toda para a praia – e nunca cumpre? Ent?o pare de anunciar que vai fazer as coisas que dependem apenas de voc?, e adote a pol?tica de faz?-las primeiro, e anunciar seu sucesso depois.

N?o dar continuidade

Voc? come?a e n?o prossegue? Paga a academia e s? vai na primeira semana? Come?a o curso de ingl?s e deixa de ir j? no segundo m?s? Ningu?m vai lev?-lo a s?rio assim. Comece a compor planos de metas sucessivas, em degraus, e persiga cada uma das metas com aten??o. E comece menos coisas. E… veja novamente o item 1.

N?o separar trabalho e vida pessoal

N?o h? problema nenhum em ir para a happy hour com os colegas de trabalho, ser pr?ximo dos clientes, ou ter amizades reais no ambiente de trabalho. Mas – a n?o ser em casos espec?ficos – colegas de equipe e clientes n?o deveriam ser todos os seus *melhores* amigos, e deve haver um limite a partir do qual a sua vida pessoal fica reservada em rela??o ao conjunto geral deles. Todo mundo tem seus desafios, e uma parte deles precisa transparecer; a outra parte deve ficar acess?vel apenas a quem tem interesse positivo e genu?no nela – n?o necessariamente seus colegas, clientes ou fornecedores.

Dar mais desculpas do que resultados

Releia o item 1, e depois fa?a mentalmente uma lista das pessoas que voc? conhece e que t?m sempre uma desculpa na ponta da l?ngua para explicar por que n?o cumpriram aquilo que disseram que fariam, ou por que a culpa n?o ? dela. Dar desculpas ? um h?bito companheiro da procrastina??o, e leva as pessoas a n?o levarem voc? a s?rio. Fa?a acontecer, ou n?o se proponha.

Andar com a turma errada

Esta tem v?rias alternativas – se as pessoas com quem voc? se associa s?o exatamente as que voc? deseja se associar, francamente, permane?a com elas e se concentre em outras formas de ser visto com seriedade pelos demais. Mas se voc? est? associado sem raz?o, e freq?entemente questiona a atitude e as decis?es destas pessoas, pare para pensar se quem olha de fora n?o faz os mesmos questionamentos em rela??o a voc?. Mas seja aut?ntico – nada de abandonar amizades genu?nas ou virar a casaca pensando apenas na sua imagem – isso s? far? com que ainda mais pessoas deixem de levar voc? a s?rio.
Agora, fa?a voc? um r?pido censo mental das pessoas em posi??o de lideran?a com quem convive no trabalho ou em outro lugar, e que n?o s?o levadas a s?rio pelos seus p?blicos, e em seguida fa?a tamb?m uma auto-an?lise – talvez voc? reveja algum conceito! Depois compartilhe conosco nos coment?rios quais as caracter?sticas mais freq?entes que impedem os seus colegas de levarem a s?rio os l?deres das suas equipes!
Fonte: Efetividade

Nov 12

Até logo, eBehavior – Inteligência para eCommerce

Escrito por Igor Musardo em 1, 2.0, 4, 6, AR, Behavior, BI, C#, class, cliente, Desenvolvedor, Dica, DRE, email, err, Ferramenta, for, Geral, IE, if, image, int, Liderança, Mercado de Trabalho, mg, Motivação, O, on, Partilha, Pessoal, produto, Projetos, pt, RIA, Ria’s Geral, S+S, team, Tema, Twitter, UI, Ved, vs @ 11 12th, 2011 | via http://www.igormusardo.com.br | Sem comentários
Igor Musardo
? X
  • Bookmarks

Blinkbits BlinkLists BlogLines Blogmarks Buddymarks CiteULike Co.mments Del.icio.us Digg Diigo

Fark Feed Me Links Furl Google Linkagogo ma.gnolia Mister Wong Newsvine Propeller Rawsugar

Reddit Rojo Simpy Sphinn Spurl Squidoo StumbleUpon Tailrank Technorati Yahoo

More »

Por decis?es pessoais e por n?o mais compartilhar do mesmo sonho, estou me desligando com muito pesar da eBehavior.

Foi um ano de muito aprendizado, v?rias amizades feitas e principalmente de muito trabalho.

Sinto tremendo orgulho e honrado por ter passado por todas as ?reas da empresa, entrei como desenvolvedor onde pude conhecer por dentro a magia da recomenda??o acertiva de produtos e cross-intelligence que a eBehavior tem. Com o crescimento do time de dev assumi a Coordena??o da equipe e gerenciamentos dos projetos, onde melhorei o meu gerenciamento de pessoas, prazos, escopos e riscos que envolvem projetos de alta escalabilidade e disponibilidade como os da eBehavior. A empresa continuou a crescer ent?o assumi com orgulho a posi??o de Gerente de Produto com a grande responsabilidade de ditar o direcionamento dos produtos da eBehavior que cumpri com muita dedica??o e chatisse com os devs para o conseguirmos o melhor para o cliente, e ? uns dois meses atr?s com a sa?da do diretor comercial, assumi a responsabilidade de atuar frente aos clientes os ajudando no entendimento das ferramentas, na melhor configura??o e otimiza??o delas para suas lojas, estudando e entendendo cada empresa, cada loja, cada consumidor para essa otimiza??o. Foi um ano muito intenso para mim e para todos que estavam ao meu lado.

Agrade?o enormemente ao Andr? pela oportunidade de ter participado do projeto eBehavior durante esse um ano e principalmente por ter tido a possibilidade de passar de ponta a ponta na empresa.

Saio com a grata sensa??o de dever cumprido e desejando muito sucesso a esse time de guerreiros da eBehavior. Que um dia ir? mudar o rumo do ecommerce brasileiro e mundial.

Meus planos s?o de continuar atuando como desenvolvedor e consultor para eCommerce, uma ?rea que me aprofundei muito durante esse um ano de casa.

Deixo aqui o meu muito obrigado a todos com que eu conversei pessoalmente, por telefone, por email e at? para quem n?o conheci mas que de alguma forma participou do meu trabalho. Pois cada um de voc?s contribuiram de forma significativa para o meu crescimento pessoal e profissional.

Mais uma vez, obrigado e at? logo!

Igor Musardo

Fev 13

Da Imaturidade à Agilidade

Escrito por Edgard Davidson em 1, 4, 6, Agile, Air, api, AR, arte, Artigo, bar, BI, busca, class, cliente, control, cultura, Curso, Cursos, Desenvolvedor, desenvolvedores, Desenvolvimento, Desenvolvimento de Software, Dica, Documentação, DRE, empresas, err, erro, Excel, exemplo, Ferramenta, Flex, for, gestão, Gráfico, ide, IE, if, image, int, lite, Livro, Mercado, Mestrado, mg, Motivação, O, on, Opinião, Outros, padrão, problema, problemas, processo, produto, Projetos, pt, RIA, Ria’s Geral, Scrum, serviço, Serviços, Software, Sugestões, TAT, Tecnologia, UI, Vários, Ved, vs, XP @ 02 13th, 2011 | via http://edgarddavidson.com | Sem comentários
Edgard Davidson
? X
  • Bookmarks

Blinkbits BlinkLists BlogLines Blogmarks Buddymarks CiteULike Co.mments Del.icio.us Digg Diigo

Fark Feed Me Links Furl Google Linkagogo ma.gnolia Mister Wong Newsvine Propeller Rawsugar

Reddit Rojo Simpy Sphinn Spurl Squidoo StumbleUpon Tailrank Technorati Yahoo

More »

…Houve um tempo em que eu achava que métodos ágeis eram um excelente álibi para programador preguiçoso. E, ainda hoje, as vezes fico pensando sobre o significado do nome “ÁGIL”. Será que esse nome contempla, de fato o seu propósito, ou é um nome meramente “marketeiro”? Veja só:  No dicionário, o significado de “ágil” é ser rápido e flexível, por sua vez, no dicionário, o antônimo de ágil é lento e vagaroso.  Ora, ninguém quer ser taxado como lento e vagaroso!  Sendo assim, se eu não quero ser taxado de lento e vagaroso, então por eliminação eu sou ágil.

Esse clichê formado sobre a palavra ÁGIL distorceu um pouco as coisas. Muitas empresas e desenvolvedores que não conseguiam implantar processos de desenvolvimentos de software maduros, e que por muitas vezes cairam no mito da Fantástica Fábrica de Software,  começaram a se intitular como ágil. Nesse contexto continuo achando que métodos ágeis são um excelente álibi para programador preguiçoso.

A questão é que desenvolver software é uma tarefa que dependente de  tecnologia, processos, e, sobretudo, do conhecimento das pessoas.  Como já diria Fred Brooks em seu famoso artigo No Silver Bullet, não existe bala de prata, não existe ferramenta, metodologia ou qualquer outra mágica que resolva milagrosamente todos os problemas.

Segundo [Filho, 2008]:  “em uma organização imatura os mesmos problemas se repetem de projeto em projeto, o trabalho é excessivo e estressante e frequentemente há a necessidade de corridas desesperadas contra os prazos, a qualidade de vida no trabalho é ruim, o ambiente é desgastante e os profissionais são desmotivados. Os erros relativos ao processos de desenvolvimento de software são comuns em organizações  que utilizam processos imaturos, ocorrendo também naquelas que possuem processos rígidos, complexos e burocráticos e naquelas em que os processos apesar de existirem são seguidos parcialmente, ou em última instância, não são seguidos.”

Não obstante, o mercado tem exigido produtos de software ainda mais sofisticados e em prazos de desenvolvimento mais curtos. A referida exigência, tem instigado a pesquisa na área engenharia de software, objetivando encontrar meios para garantir que o software seja produzido atendendo às expectativas do cliente e aos atributos de qualidade definidos pela organização fornecedora de software e esperados pelo mercado.

Antes  de enfatizar a importância da agilidade do processo, é preciso entender o que ela realmente significa. Em suma, é a capacidade que uma organização possui para responder rapidamente às forças , fraquezas, oportunidades e ameaças do mercado. Há inúmeras situações práticas, onde agilidade do processo é altamente desejado, incluindo: apresentando um novo produto, entrar em um novo mercado,  responder à entrada de concorrentes, responder a alterações de requisitos em produtos em construção, etc.

Outro aspecto, é que o processo de desenvolvimento de software é complexo e precisa favorecer a criatividade e a inovação, e ter um nível adequado de flexibilidade para beneficiar a engenharia de processos na melhoria contínua. O grande desafio na proposta de um processo é conseguir um conjunto de regras que guiem o desenvolvimento sem comprometer a criatividade e a motivação dos desenvolvedores e sem travar a organização para a constante evolução da tecnologia e as adequações necessárias.

Uma abordagem adotada para romper a barreira da imaturidade é a definição de um processo de desenvolvimento de software padrão. O referido processo descreve as atividades que devem ser realizadas no desenvolvimento de software em todos os projetos da organização. A idéia é que isso favoreça que a organização atinja a conformidade com os padrões de qualidade esperados. Na literatura existem várias definições para processos de desenvolvimento de software:

  • “Uma sequência de passos executadas para um determinado propósito; por exemplo, o processo de desenvolvimento de software.” [IEEE, 1994]
  • “Um processo ´e um conjunto de passos parcialmente ordenados, constituídos por atividades, métodos práticas e transformações usado para atingir uma meta.” [Filho, 2008]
  • “O processo de software ´e um conjunto de atividades que leva à produção de um produto de software.” [Sommerville, 2007]

De forma bem resumida, o processo de desenvolvimento de software formal descreve por meio da sua documentação: o que é feito , quando é feito, por quem é feito, como é feito, além dos insumos que usa e os produtos de saída. Em outras palavras, o processo enfatiza a padronização para possuir um parâmetro de medida e de controle e para poder circunscrever o erro em busca de qualidade. Contudo, embora seja necessário definir um processo de desenvolvimento de software, só isso não é suficiente para a construção satisfatória de um software. Existem vários fatores envolvidos que influenciam diretamente a construção do software, por exemplo: a capacitação das pessoas envolvidas, as tecnologias e ferramentas utilizadas, a cultura organizacional, entre outros.

Um processo de desenvolvimento de software não é definido do zero. Na literatura existem vários modelos que descrevem orientações para a definição e implantação de processos, dentre eles a ISO 12207/15504, CMMI e MPS-BR. Nesta linha, o processo de desenvolvimento de software deve estabelecer :

  • atividades a serem realizadas durante o processo, sua estrutura e organização (decomposição e precedência), incluindo a definição de um modelo de ciclo de vida quando pertinente;
  • artefatos requeridos e produzidos por cada uma das atividades do processo;
  • procedimentos (métodos, técnicas, roteiros e padrões) a serem adotados na realização das atividades;
  • recursos necessários (humanos, hardware e software) para a realização das atividades.

Em busca de eliminar a imaturidade, as organizações investem em definir e implantar um processo baseando-se em modelos de maturidade como CMMI e MPS-BR. Entretanto, esses modelos são densos, repletos de subprocessos que devem ser implementados em cada área de processo de cada nível de maturidade (no caso de CMMI) .

Um nível de maturidade é um patamar evolutivo bem definido que que “determina” a capacidade que uma organização possui em desenvolvimento de software. Cada nível visa alcançar um processo de desenvolvimento de software cada vez mais maduro.  Os níveis são uma forma de priorizar as ações de melhoria, de tal forma que se aumente a maturidade do processo de forma continua. Assim, os níveis de maturidade são cumulativos, ou seja, um nível de maturidade mais alto inclui os atributos dos níveis mais baixos. Uma vez que os modelos são projetados para descrever níveis discretos de melhoria de processo, níveis de capacidade provêem uma ordem recomendada para abordar a melhoria de  processo dentro de cada área de processo.

É  esperado que a cada nível alcançado pela organização, mais madura ela se torna em desenvolvimento de software. Um bom processo não garante que os produtos produzidos são de boa qualidade, mas é um indicativo de que a organização é capaz de produzir bons produtos.  Para que isso seja alcançado, um bom processo de desenvolvimento de software baseado em modelos de maturidade como CMMI e MPS-BR só podem ser considerados maduros se houver uma equipe de Quality Assurance atuante, autônoma e não condicionada. Essa equipe trabalha constantemente na garantia e no controle de qualidade do processo e do produto, respectivamente.

Quando uma organização atinge o nível 5 no CMMI ou A do MPS-BR, ela entra em um espiral de melhoria continua.  A equipe de projeto e  a equipe de qualidade reportam para a equipe de definição de processo gargalos e deficiências do processo atual, e complementam com sugestões para melhoria de processo. A equipe de definição de processo por sua vez avalia todas as sugestão, e, se pertinentes, implantam a melhoria no processo. Isso se torna um ciclo de inspeção e adaptação do processo.  Quanto mais madura a equipe, menos atividades de inspeção técnica e verificação são necessárias para garantir a conformidade com o processo e mais esforços podem ser realocado para garantir a conformidade do produto. Veja o post sobre Conformidade com o Produto vs. Conformidade com o Processo.

No gráfico acima tentei ilustrar o que percebo sobre a agilidade de processos. Quando se fala em agilidade em processo, já estamos condicionados a pensar em métodos ágeis de desenvolvimento de software como Scrum, eXtreme Programming , princípios Lean etc. No entanto, agilidade, na essência,  se aplica em um ambiente de desenvolvimento formal também.  No início, quando a organização não possui nenhum processo definido o ambiente não é estável, e, frequentemente, ela depende da competência e heroísmo das pessoas para atingir seus objetivos. Neste ambiente, a rigidez de processo é baixa, informal e caótico, mas apesar disso as organizações muitas vezes produzem produtos e serviços que funcionam. Entretanto, elas freqüentemente estão expostas a vários problemas de projeto como: exceder o orçamento e o cronograma planejado, baixa qualidade, não cumprir compromissos, abandonar processos em momentos de crises e não ser capazes de repetir sucessos do passado.

Para não ficar tão expostas aos problemas de projeto citados, as organizações partem para implantação de processos, e, a medida que esses processos são implantados e os níveis de maturidade de processo são obtidos, mais “rígido”, mais “burocrático”  o processo se torna.  No entanto, entendo que a tão criticada rigidez e burocracia de processos formais é uma fase transitória, de aprendizado, de padronização e, sobretudo de amadurecimento.  Nos níveis mais altos de maturidade o objetivo é a simplificação, a “des-burocratização” de processo. Lendo isto alguém poderia estar perguntando: “Ora! Então porque a organização não vai direto para esse estado?”  Bom, imagino que isso se torna necessário na caminhada da Imaturidade à Agilidade.

Fev 5

Qualidade em Processo de Desenvolvimento de Software

Escrito por Edgard Davidson em 1, 2009, 6, Agile, api, AR, arte, AUG, auto, BI, busca, class, cliente, comunicação, conferência, control, cultura, Curso, Cursos, demo, Desenvolvimento, Desenvolvimento de Software, Documentação, empresas, event, Evento, exemplo, falha, for, Google, ide, IE, if, image, int, Liderança, LOB, Mercado, Mestrado, mg, Motivação, mudanças, NaN, O, on, Opinião, processo, produto, Projetos, pt, Qualidade de Software, RIA, Ria’s Geral, Software, Sun, TAT, Tecnologia, Treinamento, UI, yahoo @ 02 5th, 2011 | via http://edgarddavidson.com | Sem comentários
Edgard Davidson
? X
  • Bookmarks

Blinkbits BlinkLists BlogLines Blogmarks Buddymarks CiteULike Co.mments Del.icio.us Digg Diigo

Fark Feed Me Links Furl Google Linkagogo ma.gnolia Mister Wong Newsvine Propeller Rawsugar

Reddit Rojo Simpy Sphinn Spurl Squidoo StumbleUpon Tailrank Technorati Yahoo

More »

Chaus Report 2009 – Standish Group

Pesquisas como as realizadas pelo Standish Group apresentadas no Chaus Report 2009 demonstram que grande parte dos projetos de software falham ou são desafiados, seja porque não cumprem o orçamento, ou não cumprem o cronograma, ou as funcionalidades não atendem às necessidades dos usuários ou porque todos estes fatores estão presentes em conjunto. Para o Standish Group um projeto de software é considerado um Sucesso quando todas a funcionalidades do escopo inicial são entregues no orçamento e cronograma planejado. O projeto é Desafiado quando ele sofre com atrasos, não cumpre o orçamento inicial e/ou é entregue com menos recursos e funções do que o definido no escopo inicial. E finalmente, o projeto é considerado Falho quando ele é cancelado antes da conclusão ou o produto da sua entrega nunca é utilizado.

Há algumas décadas a indústria de software vem buscando técnicas de desenvolvimento que possam reduzir os riscos dos projetos de software e tornar essa atividade mais produtiva. A referida constatação não é recente. Já em em 1968 houve um evento denominado conferência de NATO, que, entre outras coisas, tentou entender e discutir o porquê que a maioria dos projetos de software falham ou são desafiados. De lá para cá, a indústria de software vem evoluindo e a partir dos anos 90 surgiram várias propostas como o desenvolvimento de processos formais como RUP, pautados sobre modelos de maturidade como CMMI e a evolução de autores consagrados como Coad & Yourdon, Pressman, Sommerville, Rumbaugh, Booch, Jacobson, etc.

Quando o assunto é desenvolvimento de software, existem basicamente duas grandes “escolas”: a tradicional e a ágil. Cada uma delas enxerga e trata o processo de desenvolvimento de software de maneiras bem peculiares, apesar dos objetivos finais serem os mesmos. Na escola tradicional o conceito de processo de desenvolvimento de software se assemelha ao usado em processos de produção industrial: um conjunto de passos parcialmente ordenados, constituídos por atividades, métodos, práticas e transformações usadas para atingir uma meta, centrado em documentação e controle operacional. Já os adeptos das metodologias ágeis não estão presos a processos rígidos; o que interessa é aquilo que de fato agrega valor ao usuário, não que a escola tradicional não pense assim, como entregas rápidas ou como já diria um dos princípios ágeis: “Nossa maior prioridade é satisfazer o cliente através da entrega rápida e contínua de software de valor.”

Não obstante, a indústria de software é bastante dinâmica, novas idéias, tendências e tecnologias surgem a todo instante e em todas as partes do mundo. Acompanhar essa dinâmica é fator crítico de sucesso para profissionais e empresas que pretendem adquirir um diferencial no mercado. Um ponto fundamental para acompanhar o dinamismo do mercado está na habilidade de lidar de forma mais eficiente com as mudanças de requisitos, aumentar a motivação da equipe e melhorar comunicação com o cliente do projeto, e, para isso, será necessário estar pronto para introduzir uma nova cultura de liderança que irá alterar os papeis e trará uma nova forma de trabalhar transferindo parte da responsabilidade do gerente do projeto para a equipe.

A adaptação às mudanças decorrentes de fatores externos são uns dos conceitos centrais dos métodos ágeis. Onde os métodos mais formalizados e centrados em planejamento e documentação são preditivos na tentativa de prever as necessidades futuras, em contrapartida, os métodos ágeis são adaptativos e rapidamente se adaptam às novas exigências, aderindo ao lema “abrace as mudanças!”. A única medida de sucesso é a de produto funcionando.

Outro princípio importante é a simplicidade e pensamento enxuto. De acordo com o conceito de pensamento ágil, projetos de grande escala, por exemplo, não são desejáveis. Pelo contrário, é preferível minimizar a quantidade de trabalho daquilo que não precisa ser feito. Isto inclui, por exemplo, não gastar tempo escrevendo documentação desnecessária.

Cada vez mais a abordagem ágil de desenvolvimento de software vem se popularizando entre grandes empresas de sucesso como: google, yahoo, amazom.com, globo.com entre outras. No entanto, nem sempre as empresas que tentam adotar a filosofia ágil têm obtido o mesmo sucesso. Várias discussões tem se formado para entender o motivo do referido insucesso, e as conclusões estão convergindo para fatores como: falta de treinamento dos colaboradores; equipes hierarquizadas, e, sobretudo, resistência de mudança cultural.

Desenvolver software é uma tarefa que exige técnicas de engenharia e arte. Se uma empresa ou profissional não absorver a filosofia ágil dificilmente se manterá competitiva no cenário atual do mercado de software por mais que se implemente uma metodologia.

Nesse sentido, cabe a nós profissionais críticos, formadores de opinião, termos a a clara consciência de adotar processos tradicionais ou processo ágeis, ou no melhor dos casos, como integrar os dois para tirar o maior proveito.

Dez 6

Como salvar “ SnapShots” de componentes do Flex na máquina do usuário.

Escrito por DClick Team em 1, 4, 6, action, Actionscript, ActionScript 3, api, Aplicativos, AR, arte, as3, back, BI, bitmap, blog, class, Componente, Componentes, Curso, Cursos, dados, desempenho, encode, encoder, event, exemplo, flash, Flash Player, Flex, for, function, game, git, handle, ide, IE, if, image, int, label, library, map, mg, Motivação, NaN, News, O, Office, on, Outros, padrão, Partilha, player, processo, pt, reference, referencia, RIA, Ria’s Geral, Sem categoria, servidor, TAT, Tutorial, Twitter, UI @ 12 6th, 2010 | via http://blog.dclick.com.br/pt/ | Sem comentários
DClick Team
? X
  • Bookmarks

Blinkbits BlinkLists BlogLines Blogmarks Buddymarks CiteULike Co.mments Del.icio.us Digg Diigo

Fark Feed Me Links Furl Google Linkagogo ma.gnolia Mister Wong Newsvine Propeller Rawsugar

Reddit Rojo Simpy Sphinn Spurl Squidoo StumbleUpon Tailrank Technorati Yahoo

More »

https://github.com/mikechambers/as3corelib .

Implementação

Então vamos ao que interessa. Esta pequena função abaixo é que faz toda a mágica, é ela que gera a imagem a partir do componente AgonNewsSnapShot e o salva na maquina do usuário:

PLAIN TEXT
ACTIONSCRIPT:

  1. protected function saveSnapshot_clickHandler(event:MouseEvent):void
  2. {
  3. var imageBitmapData:BitmapData = ImageSnapshot.captureBitmapData(birthDaySnapshot);
  4. var imgByteData:ByteArray = PNGEncoder.encode(imageBitmapData);
  5. var file:FileReference = new FileReference();
  6. file.save(imgByteData,“nomeDoArquivo.png”);
  7. }

O componente AgonNewsSnapShot nada mais é do que um Group no qual todos os seus filhos (Labels, Background, Images, etc.) serão desenhados na imagem a ser salva, veja abaixo o exemplo de uma instância deste componente:

Vamos dividir em partes:

Primeiro é capturada a imagem Bitmap do componente AgonNewsSnapShot, que no nosso caso é o componente que será salvo como imagem no computador do usuário:

PLAIN TEXT
ACTIONSCRIPT:

  1. var imageBitmapData:BitmapData = ImageSnapshot.captureBitmapData(agonNewsSnapshot);

Usamos o PNGEncoder para converter a imagem e retornar o ByteArray da mesma:

PLAIN TEXT
ACTIONSCRIPT:

  1. var imgByteData:ByteArray = PNGEncoder.encode(imageBitmapData);

É chamado o system dialog padrão do S.O, para salvar o ByteArray na maquina do usuário no diretório selecionado por ele.

PLAIN TEXT
ACTIONSCRIPT:

  1. var file:FileReference = new FileReference();
  2. file.save(imgByteData,“nomeDoArquivo.png”);

Pronto! Seu componente acaba de ser desenhado numa imagem e salvo no computador do usuário.

Bom galera esse é meu primeiro post, espero que tenham gostado, e virão mais por aí.

Abraços.

Referencias:

http://www.switchonthecode.com/tutorials/flex-tutorial-an-asynchronous-jpeg-encoder

http://ask.amoeba.co.in/save-images-from-flash-actionsctipt-3-filereference-save-jpgencoder/


Nov 19

Generics, como Scala trata o Problema de Generalização de Classes

Escrito por DClick Team em 1, 4, 6, AR, auto, back, bar, BI, blog, boolean, busca, case, class, classe, classes, codec, código, comparação, demo, err, erro, error, exemplo, explicação, for, function, Google, IE, if, image, int, Java, lista, mg, Motivação, NaN, O, on, operadores, Orientação, Orientação a Objetos, padrão, problema, pt, rest, RIA, Ria’s Geral, RoR, screen, Screencast, site, string, strings, Sun, TAT, Teste, Tutorial, Twitter, UI, uint, XP, zend @ 11 19th, 2010 | via http://blog.dclick.com.br/pt/ | Sem comentários
DClick Team
? X
  • Bookmarks

Blinkbits BlinkLists BlogLines Blogmarks Buddymarks CiteULike Co.mments Del.icio.us Digg Diigo

Fark Feed Me Links Furl Google Linkagogo ma.gnolia Mister Wong Newsvine Propeller Rawsugar

Reddit Rojo Simpy Sphinn Spurl Squidoo StumbleUpon Tailrank Technorati Yahoo

More »

Twitter!


Generics em Java = Type Parameters em Scala


A motivação para o uso de generics em Java é bem conhecida, e Scala resolve o mesmo problema, dando um nome diferente para a solução: Type Parameters. Podemos chamar também de Generic Types, o significado é o mesmo.

Criando uma lista de tipo específico




Vamos implementar uma lista ligada para valores String. Tente fazer você mesmo, implementando um classe para ser a célula da lista, e uma para ser a lista em si. A lista deve também conter métodos para adicionar, remover e buscar um elemento específico dado o índice.

Em um paradigma mais funcional por assim dizer, você pode acabar em uma implementação para a célula, parecida com a minha:

1
2
3
4
5
6
7
8
package br.com.dclick.typeparameters

abstract class StringListCell {
    def isEmpty: Boolean
    def next: StringListCell
    def setNext(n: StringListCell): Unit
    def value: String
}


1
2
3
4
5
6
7
8
package br.com.dclick.typeparameters

class StringEmptyCell extends StringListCell{
    def isEmpty = true
    def next: StringListCell = error(“empty”)
    def value: String = error(“empty”)
    def setNext(n: StringListCell) = error(“empty”)
}


1
2
3
4
5
6
7
8
9
package br.com.dclick.typeparameters

class StringValueCell(v: String) extends StringListCell{
    var nextElem: StringListCell = new StringEmptyCell
    def isEmpty = false
    def setNext(n: StringListCell) = nextElem = n
    def next: StringListCell =  nextElem
    def value: String = v   
}


Implementação diferente do usual, né? :)
Repare que criei dois tipos de célula: uma célula que está sempre vazia, e uma célula que contém de fato o valor a ser guardado. Fiz isso pois em Scala não existe (ou a idéia é não utilizar) null, assim a checagem é feita por células vazias e não por null. Como Scala utiliza código Java, é possível passar e receber valores nulos. Código puramente em Scala estão praticamente livres de NullPointerException, justamente por essa restrição com valores nulos. Vamos ver logo mais um caso em que é possível obter tal erro.
Em Scala uma das alternativas para execução de funções que devolvem null como resultado para certas circunstâncias, é o Option. Option, como o próprio nome sugere, se trata de um opção por devolver, ou não um valor. No caso de se devolver algum valor, deve-se devolver um Some contendo o valor. No caso de não se devolver o valor, deve-se devolver um None. Ambos são Case Classes, portanto não necessitam da palavra new, e possuem todas a propriedades que vimos em um post anterior.

Pensando em todas essas características da linguagem, cheguei nesta implementação para a lista, e usei uma abordagem recursiva. Vou mostrar o resultado:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package br.com.dclick.typeparameters

class StringList {
    var head: StringListCell = new StringEmptyCell
    var last = head
   
    def add(value: String): StringTypeList = {
        if (head.isEmpty) {
            head = new ValueCell(value)
            last = head
        }
        else {
            last setNext new ValueCell(value)
            last = last.next
        }
        this
    }
   
    def remove(index: Int, node: StringListCell): StringListCell = {
        if (node.isEmpty)
            new StringEmptyCell
        if (index == 0) {
            node.next
        }
        else {
            node.setNext(remove(index-1, node.next))
            node
        }
    }
   
    def get(index: Int, node: StringListCell): Option[String] = {
        if (node.isEmpty)
            None
        else
            if (index == 0)
                Some(node.value)
            else
                get(index-1, node.next)
    }
}


Outra implementação não muito convencional… mas mesmo assim não deixa de ser clara. Mesmo não send o foco do post, vou dar uma breve explicação: na lista guardo o último elemento, assim sei onde devo adicionar o novo elemento; na função add verifico se o início da lista está vazio para adicionar, ou se devo adicionar no final; na função remove se a célula passada estiver vazia devolvo uma nova célula vazia, se o índice atual for zero, ou seja, queremos remover o atual, devolvo o próximo, e como caso padrão seto o próximo item como sendo o resto da lista com o item correto removido (Repare que não funciona para remover o primeiro item, mas não é esse o intuito mesmo :p); na função get verificao se a célula está vazia, logo não devolvo nada, e itero no resto dos itens de maneira recursiva no caso padrão.

Para termos certeza que nossa lista está funcionando corretamente, criei o seguinte teste unitário usando JUnit4, que para utilizá-lo é muito fácil, como foi visto no post anterior.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package br.com.dclick
import br.com.dclick.typeparameters._
import org.junit._
import Assert._

class ListTest {

    @Test
    def testList = {
        val list = new StringList
       
        assertEquals(None, list.get(0, list.head))
       
        list add “1″ add “2″ add “3″ add “4″ add “5″ add “6″
       
        assertEquals(“1″, list.get(0, list.head).get)
        assertEquals(“2″, list.get(1, list.head).get)
        assertEquals(“3″, list.get(2, list.head).get)
        assertEquals(“4″, list.get(3, list.head).get)
        assertEquals(“5″, list.get(4, list.head).get)
        assertEquals(“6″, list.get(5, list.head).get)
        assertTrue(list.get(6, list.head).isEmpty)
       
        list.remove(1, list.head)
        list.remove(1, list.head)
        list.remove(1, list.head)
       
        assertEquals(“1″, list.get(0, list.head).get)
        assertEquals(“5″, list.get(1, list.head).get)
        assertEquals(“6″, list.get(2, list.head).get)
        assertTrue(list.get(3, list.head).isEmpty)
    }
}


Rode o teste para ter certeza de que está tudo rodando.

Generalizando nossa Lista


Agora imagine que queremos fazer uma lista de inteiros ao invés de Strings. O problema é o mesmo que temos em Java. Se generalizarmos nossa lista para guardar AnyRef do Scala ao invés de Strings (em Java faríamos o mesmo com Object), teremos o problema de ter que fazer cast do resultado em toda chamada para nossa lista. Para isso que existem os Generic Types.

Se você reparou como utilizamos Option, tivemos que passar um tipo de parâmetro para ele, que no nosso caso foi String, dessa forma quem utiliza o resultado do método, sabe que está lidando com Strings e portanto não precisa fazer o cast do resultado. Vamos implementar a mesma funcionalidade em nossa lista. Para isso temos que modificar nossas células e nossa lista, de maneira que recebam o tipo como parâmetro. Segue o código da lista modificada:

1
2
3
4
5
6
7
8
package br.com.dclick.typeparameters

abstract class ListCell[T] {
    def isEmpty: Boolean
    def next: ListCell[T]
    def setNext(n: ListCell[T]): Unit
    def value: T
}


1
2
3
4
5
6
7
8
9
package br.com.dclick.typeparameters

class ValueCell[T](v: T) extends ListCell[T]{
    var nextElem: ListCell[T] = new EmptyCell[T]
    def isEmpty = false
    def setNext(n: ListCell[T]) = nextElem = n
    def next: ListCell[T] = nextElem
    def value: T = v
}


1
2
3
4
5
6
7
8
package br.com.dclick.typeparameters

class EmptyCell[T] extends ListCell[T]{
    def isEmpty = true
    def next: ListCell[T] = error(“empty”)
    def value: T = error(“empty”)
    def setNext(n: ListCell[T]) = error(“empty”)
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package br.com.dclick.typeparameters

class TypeList[T] {
    var head: ListCell[T] = new EmptyCell[T]
    var last = head
   
    def add(value: T): TypeList[T] = {
        if (head.isEmpty) {
            head = new ValueCell(value)
            last = head
        }
        else {
            last setNext new ValueCell(value)
            last = last.next
        }
        this
    }
   
    def remove(index: Int, node: ListCell[T]): ListCell[T] = {
        if (node.isEmpty)
            new EmptyCell[T]
        if (index == 0) {
            node.next
        }
        else {
            node.setNext(remove(index-1, node.next))
            node
        }
    }
   
    def get(index: Int, node: ListCell[T]): Option[T] = {
        if (node.isEmpty)
            None
        else
            if (index == 0)
                Some(node.value)
            else
                get(index-1, node.next)
    }   
}


Note que a implementação é praticamente a mesma, a única coisa diferente é o tipo do valor passado para guardar na lista. Repare que para quem usa a lista, basta adicionar um tipo no momento de criação da mesma, por isso em nosso teste mude apenas a linha que instancia uma nova lista, e rode o teste.

1
val list = new TypeList[String]


Crie um outro teste com um tipo de valor diferente e veja que funciona da mesma maneira que no Java.

Restrições de Tipos Genéricos


Nosso tipo T pode ser qualquer coisa. Existe em Scala uma sintaxe própria inclusive para inicializar uma varável de um tipo genérico, basta utilizar um ‘_‘. Dessa forma você está explicitando que sua variável pode ou não ter um valor do tipo genérico, afinal não tem como saber se o tipo será um primitivo ou não. Este é o caso em que estamos sujeito ao NullPointerException que citei no começo do post: para definir uma variável em Scala é necessário iniciá-la, e no caso de tipos genéricos, como não possível iniciá-los, as variáveis possuem valor nulo (‘_‘), logo geram código que pode lançar NullPointerException.

Com nosso tipo genérico podendo ser qualquer coisa, não conseguiríamos, por exemplo, ordenar nossa lista, afinal nem tudo é ordenável. A solução em Java é a mesma, mas a sintaxe em Scala me parece bem mais amigável. O que é necessário fazer, é dizer que o seu tipo obrigatoriamente extende de alguma classe determinada. No caso de querermos uma lista ordenada, basta obrigarmos o tipo passado extender de Comparable (no Java), ou Ordered (em Scala). Ordered extende Comparable, sobrescrevendo os operadores de comparação básico (>, <, >=, <=) e utilizando o método de comparação disponível em Comparable (compareTo).

Vamos mudar o parâmetro de nossa lista para obter tal comportamento. Para isto, basta mudar a assinatura da classe com seguinte código:

1
class TypeList[T <: Comparable[T]] {


Estou usando Comparable, pois não teremos erros de compilação usando String como parâmetro. Porém em Scala é possível dizer que um parâmetro poder ser convertido para o tipo definido na restrição. Esse tipo de restrição é chamado de View Bound e Scala já implementa a conversão implícita para os tipos primitivos e String, portanto se mudarmos nossa classe para:

1
class TypeList[T <% Ordered[T]] {


nosso código ainda compila, e nossos testes funcionam, o que é o mais importante :) .

Invariância e Covariância


Pensando em termos de orientação a objetos, se definirmos um lista TypeList[String], esta lista deve ser subtipo de TypeList[AnyRef]? Parece uma pergunta simples de se responder, mas as respostas tem suas implicações. Se a resposta é não, então estamos dizendo que quando criarmos uma lista de Strings, só faremos referência a essa lista sabendo que é do tipo String, e que portanto só adicionamos valores String na lista. Se a resposta é não, então estamos dizendo que ao criarmos um lista de Strings, podemos referenciá-la como uma lista de AnyRef e portanto conseguimos adicionar qualquer valor em nossa lista. O primeiro caso é dito invariante, e o segundo caso é dito Covariante.

Em Scala os tipos são por padrão sempre invariantes. Diferente do Java que é covariante.

Quando os tipos são covariantes, temos o problema de lidar com tipos diferentes dos esperados. Java resolve esse problema fazendo a verificação em tempo de execução, no momento da atribuição de um tipo. Em Scala o problema é resolvido de maneira estática impedindo o código de compilar. Ainda assim é possível estabelecer tipo covariantes em Scala. Para nossa lista, basta mudar a assinatura, com o operador +:

1
class TypeList[+T] {


Fazendo isso, seremos obrigados a mudar em todas as classes que usem T, por exemplo, nossas células.

Mas com isso surge um problema: como que o compilador irá saber tratar o tipo T de maneira que este possa ser de algum supertipo do mesmo? Para isso podemos definir nosso tipo T, como um limitante inferior. Basta usarmos a sintaxe simétrica a de restrições de limitantes superiores:

1
A >: T


Assim estamos dizendo que A é supertipo de T, e portanto podemos usá-lo em nossas funções sem que o compilador reclame.

Também podemos definir um range para nossas restrições combinando os operadores, por exemplo:

1
A >: B <: C


Objects


Scala não permite que usemos parâmetros em objects, por isso mesmo nossa célula vazia teve que definir um tipo para o parâmetro.

Para definirmos um object como super classe de uma classe que necessite de parâmetros, precisamos que a classe pai seja cocariante, e em nosso object, basta extendermos tal classe com o tipo Nothing. O tipo Nothing é subclasse de todos os tipos em Scala, portanto é o menor limitante inferior. Com isso conseguimos definir um object que extende uma classe que precisa de parâmetros.

Antes de falarmos de listas em Scala, ainda falta falarmos de tuplas e Functions. Veremos isso em um screencast que será divulgado em breve.

Espero que a série tenha andado bem até aqui, e que as informações que estou publicando sejam úteis a muitas pessoas. Lembrando que todos os tipos de comentários são bem vindos: críticas, dúvidas e sugestôes.

Por @Gust4v0_H4xx0r

Nov 16

Case Classes com Scala

Escrito por DClick Team em 1, 4, 6, Access, app, AR, auto, back, BI, blog, boolean, case, catch, class, classe, classes, codec, código, Desenvolvimento, DRE, Eclipse, eval, exemplo, explicação, flash, for, FullScreen, fundo, Google, ide, IE, if, image, int, internet, Java, Livro, Mate, mg, Motivação, mudanças, NaN, Number, O, on, operadores, pattern, Plugin, polimorfismo, print, problema, pt, RIA, Ria’s Geral, screen, Screencast, string, Sun, TAT, Tema, Teste, Tree, try, Tutorial, tv, Twitter, UI, uint, Vídeo, wave, XP, zend @ 11 16th, 2010 | via http://blog.dclick.com.br/pt/ | Sem comentários
DClick Team
? X
  • Bookmarks

Blinkbits BlinkLists BlogLines Blogmarks Buddymarks CiteULike Co.mments Del.icio.us Digg Diigo

Fark Feed Me Links Furl Google Linkagogo ma.gnolia Mister Wong Newsvine Propeller Rawsugar

Reddit Rojo Simpy Sphinn Spurl Squidoo StumbleUpon Tailrank Technorati Yahoo

More »

Twitter!

Vimos que Scala na verdade é uma linguagem puramente orientada a objetos, com conceitos de classe, instância, heirarquia e polimorfismo como Java por exemplo. Mas Scala traz também alguns conceitos próprios muito interessantes, que é o caso de Case Classes.

Case Classes são um caso de classes com regras pré-definidas em tempo de compilação, de maneira que se permita executar algumas outras operações sobre tais classes facilitando algumas modelagens, e ajudando na aplicação de algumas boas práticas. Vamos estudar mais a fundo o conceito de Case Classes nesse post. Usei como referência o Scala By Example do Martin Odresky, o qual citei em posts anteriores.

Para acompanhar o post, é muito recomendado alguma IDE de desenvolvimento de scala. Estou usando o scala-ide plugin para o Eclipse, que pode ser encontrado em http://www.scala-ide.org/.

Motivação para Case Classes


Eu gostei bastante do exemplo disponível no livro, por isso vou seguir a mesma idéia nesse post só que com as minhas palavras do que eu consegui aprender sobre assunto pesquisando um pouco mais na internet, e citando também as dificuldades que enfrentei.

Imagine que queremos modelar um interpretador de expressões matemáticas que são descritas em objetos do nosso domínio. Por exemplo, queremos interpretar o resultado de 1 + (3 + 7), e representando em nosso modelo, queremos obter algo como:

1
new Sum(new Number(1), new Sum(new Number(3), new Number(7)))



Uma maneira orientada a objetos de se implemetar tal domínio poderia ser algo como:

1
2
3
4
5
6
7
8
9
trait Expr {
    def eval: Int
}
class Number(n: Int) extends Expr {
    def eval: Int = n
}
class Sum(e1: Expr, e2: Expr) extends Expr {
    def eval: Int = e1.eval + e2.eval
}



A implementação é bastante limpa e nosso interpretador seria mais simples ainda:

1
2
3
4
object Inter {
    def inter(e: Expr) =
        e.eval
}



Se você assistiu o screencast sobre integração com Java, e JUnit rodando testes de Scala, você pode fazer um teste para verificar que nosso interpretador está funcionando corretamente:

1
2
3
4
5
6
7
8
9
10
11
12
package br.com.dclick
import org.junit._
import Assert._

class InterTest {

  @Test
  def testInter = {
    var res = Inter.inter(new Sum(new Number(1), new Sum(new Number(3), new Number(7))))
    assertEquals(11, res)
  }
}



Para essa modelagem, quando quisermos adicionar uma nova operação que pode ser interpretada, basta criar uma nova classe que extends Expr e pronto! Nada mais precisa ser alterado em nosso código, e nosso interpretador continuará funcionando.
Agora imagine que antes de executar a expressão, queremos imprimir no console de um jeito amigável a expressão matemática que está sendo executada. Nesse caso, de acordo com nossa modelagem, teríamos que definir em nosso Expr uma função print, para que todas as suas implementações definam o comportamento de tal função. Para isso temos que alterar o código em todas as classes que já existem, o que pode ser ruim dependendo do nosso sistema.

Aplicando Case Classes


Em Scala existe a definição de Case Class. Para criar uma Case Class basta adicionar o modificador case antes da definição da classe. Em nosso exemplo faça as seguintes mudanças:

1
2
case class Number(n: Int) extends Expr
case class Sum(e1: Expr, e2: Expr) extends Expr



Case classes seguem as seguintes regras:

1 – Possuem um construtor definido exatamente com o mesmo nome definido na classe. Em nosso exemplo:

1
def Number(n: Int) = new Number(n)



Dessa forma é possível escrever nossa expressão 1 + (3 + 7) da seguinte forma:

1
Sum(Number(1), Sum(Number(3), Number(7)))



Substitua no teste para ter certeza do funcionamento.

2 – Os métodos toString, equals e hashCode já estão implementados seguindo a definição da classe com seus atributos. Para nosso exemplo com Number, esses métodos já levam em consideração o atributo n, deixando de comparar os objetos por endereço de memória. Os operadores == e != também já estão definidos em função do equals.

3 – Todos os atributos passados no construtor possuem os métodos de acesso público já definidos. Em nosso exemplo, Number e Sum já possuem os seguintes métodos:

1
def n: Int


1
def e1: Expr, e2: Expr



Fato importante é que tais classes se tornam imutáveis, ou seja, não existe um método para alterar o valor dos atributos, e nem é possível definí-los.

4 – Case Classes podem ser usadas para pattern matching, que é uma operação disponível em Scala e que veremos agora.

Match, não Switch


Vimos que a classe base do Scala é o Any, e que todos objetos podem ser tratados como tal. Any define uma função que permite verificar o tipo de classe que está sendo tratado e tomar a atitude correspondente. Vamos ao exemplo que explica melhor o comportamento. Em nosso object Inter, mude a função inter para o seguinte:

1
2
3
4
5
def inter(e: Expr): Int =
    e match {
        case Number(n) => n
        case Sum(a, b) => inter(a) + inter(b)
    }



Rode nosso teste novamente e verifique que está tudo correto.
Para entender o que está acontecendo: estamos dizendo que um dos casos esperados é o caso em que e é do tipo Number, que recebe um parâmetro que chamamos de n. Note que não precisamos definir o tipo de n, pois o compilador consegue inferir baseado na definição do construtor de Number. Feito isso, n está disponível no contexto do case atual. Para nosso caso com Number, precisamos apenas devolver o valor de n.
No segundo caso, estamos esperando uma Expr do tipo Sum, que recebe dois parâmetros e que baseado no construtor definido na classe, sabemos que é do tipo Expr. Nesse caso devolvemos o inter de a somado ao inter de b.
Simples não? :)

Nessa nossa nova modelagem fica fácil adicionar uma nova funcionalidade ao comportamento das expressões, como por exemplo imprimir de maneira legível. Basta adicionar mais um método ao nosso interpretador. Claro que agora temos o problema adicionar um novo caso quando criarmos uma nova operação, mas a quantidade de código a ser implementada é consideravelmente menor.

Match é definida como uma função como qualquer outra em Scala, portanto pode ser atribuída a variáveis, ser devolvida como resultado e ser passada como parâmetro para outras funções. Pode-se também criar um bloco como o seguinte:

1
{ case Number(n) => n case Sum(a, b) => a + b }



e usá-lo como uma função anônima. Dessa forma será criado uma função match para tratar com seus casos definidos no bloco.

Exceptions


Veremos Exceptions mais para frente, mas perceba como funciona o bloco try/catch em Scala, e veja se há alguma semelhança com o que acamos de ver:

1
2
3
4
5
6
7
try {
    println
} catch {
    case npe: NullPointerException => print(npe.getMessage)
    case ioe: IOException => print(ioe.getMessage)
    case e: Exception => print(e.getMessage)
}



Pois bem, catch possui o mesmo comportamento de match para execeções.

Exercício


Vou me basear no exercício disponível no livro do Martin.

Considere que queremos implementar uma árvore binária ordenada de inteiros. E tome a seguinte implementação como base:

1
abstract class IntTree


1
case object EmptyTree extends IntTree {}


1
case class Node(elem: Int, left: IntTree, right: IntTree) extends IntTree {}


Agora complete a seguinte implementação dentro de IntTree:

1
2
3
4
5
6
7
8
9
10
11
12
abstract class IntTree {

    def contains (t: IntTree, v: Int): Boolean =
        t match {
            …
        }
   
    def insert(t: IntTree, v: Int): IntTree =
        t match {
            …
        }
}


Lembre-se que Node é imutável, e que é obrigatório usar Case Classes. Boa sorte :) !

A reposta está no screencast a seguir, junto com a explicação:

Vídeo em alta resolução.

Set 29

Como foi o 1º #DevDay Curitiba

Escrito por Igor Musardo em .NET, 1, 4, 6, Adobe, Adobe Flex, Air, AR, Arquitetura, Asp.Net, Banco de Dados, BI, break, business, control, Controls, CRUD, css, Curitiba, dados, demo, Desenvolvedor, desenvolvedores, event, Evento, Excel, exemplo, Flex, for, geo, ide, IE, int, internet, JQuery, mg, Microsoft, Motivação, mvc, O, on, padrão, Palestra, Palestras, rest, RIA, Ria’s Geral, server, silverlight, Software, tag, TAT, Tech, TechEd, Tecnologia, UI, Vários, Ved, Visual Studio, WCF, web, window, windows, WPF, XP, zend @ 09 29th, 2010 | via http://www.igormusardo.com.br | Sem comentários
Igor Musardo
? X
  • Bookmarks

Blinkbits BlinkLists BlogLines Blogmarks Buddymarks CiteULike Co.mments Del.icio.us Digg Diigo

Fark Feed Me Links Furl Google Linkagogo ma.gnolia Mister Wong Newsvine Propeller Rawsugar

Reddit Rojo Simpy Sphinn Spurl Squidoo StumbleUpon Tailrank Technorati Yahoo

More »

Sensacional!

É o melhor adjetivo para descrever como foi o 1º DevDay Curitiba, neste último sábado (25/09), tivemos um dia intenso de imersão em tecnologia Microsoft com palestrantes de altíssimo nível. Quase todos os palestrantes são MVP’s e palestraram esse ano no TechEd, maior evento organizado pela Microsoft na América Latina.

O auditório estava cheio de desenvolvedores ávidos pelo conteúdo das palestras.

O Thiago Zavaschi começou a maratona de palestras falando sobre Business Inteligence com dados Geoespaciais. Uma excelente palestra, com várias demos claras e simples!

Depois foi a minha vez de dar continuidade à imersão, contei como comecei a minha caminhada na plataforma Flex, e como aconteceu o meu primeiro contato com o WPF e Silverlight e principalmente como foi que eu abri os olhos para o Silverlight como uma plataforma realmente interessante para aplicações ricas de internet. Ao final da palestra fiz a demo de um aplicativo CRUD em Silverlight com WCF RIA Services do zero, incluindo a criação do banco de dados que você.

Tivemos uma pausa para o Coffee-break e o bate-papo.

Depois foi a vez do Djonatas Tenfen explicar para todos o que é o MVVM e quais os benefícios de se utilizar esse padrão de arquitetura em aplicações Silverlight.

Pausa para o almoço! no Mexicano!

Na volta do almoço o Rodolpho Carmo mostrou para todos como será a plataforma do Windows Phone 7 e como desenvolver um aplicativo em pouquíssimo tempo para o WP7. No final da palestra o Windows Phone 7 dançou o Ah! Muleque…

Victor Cavalcante subiu no palco logo após a palestra do Rodo e quebrou cada um dos conceitos por trás do ASP.NET WebForms comparando-o com a Matrix, pois os conceitos do WebForms simplesmente não são conceitos de Web, como por exemplo, Web não tem Estado, Web não tem Server Side Controls, etc. E nos apresentou a pílula Vermelha para conhecermos a verdade através do ASP.NET MVC + CSS + JQuery em uma palestra muito dinâmica e divertida.

E para fechar com chave de ouro o DevDay, não tinha ninguém melhor que o Giovanni Bassi. Com uma palestra extremamente provocadora, apresentando a verdade nua e crua que mexeu com vários desenvolvedores presentes fazendo-os cair na real sobre o que realmente é ser um Desenvolvedor de Software Profissional, quais as responsabilidades e obrigações de se desenvolver software! Sem dúvida foi uma palestra para a reflexão de todos.

Ao final do DevDay fizemos vários sorteios de mouse sem-fio, pen drives e uma mochila para Notebook.

Sem dúvida foi um dia sensacional!

Aguarde, pois mais DevDays virão por aí! Até o próximo…

Set 10

Criando seu primeiro projeto Maven

Escrito por DClick Team em 1, 4, 6, apache, AR, arte, auto, back, bash, BI, blog, camp, carregar, class, classe, classes, codec, código, demo, Dica, Download, Eclipse, exemplo, explorer, for, Hibernate, html, IE, if, image, int, Java, Linux, mg, Motivação, NaN, O, on, padrão, Plugin, Projetos, pt, reference, relatório, Relatórios, rest, RIA, Ria’s Geral, site, tag, TAT, Tema, Teste, Tutorial, Twitter, UI, uint, UX, window, windows, XML, XP @ 09 10th, 2010 | via http://blog.dclick.com.br/pt/ | Sem comentários
DClick Team
? X
  • Bookmarks

Blinkbits BlinkLists BlogLines Blogmarks Buddymarks CiteULike Co.mments Del.icio.us Digg Diigo

Fark Feed Me Links Furl Google Linkagogo ma.gnolia Mister Wong Newsvine Propeller Rawsugar

Reddit Rojo Simpy Sphinn Spurl Squidoo StumbleUpon Tailrank Technorati Yahoo

More »

Twitter!


Começando com Maven 2

O objetivo desse post é ensinar como configurar um projeto para usar maven desde o início, deixando um pouco de lado a origem e a motivação por trás do maven. Também não será detalhado o funcionamento do maven, o que será feito em um outro post.

Instalando maven

Para instalar basta baixar a pasta compactada do próprio site (http://maven.apache.org/download.html). Existem várias tipos de arquivos compactados, mas todos contém a mesma pasta, escolha o de sua prefência. Como o maven é feito em Java, não existe restrição de SO.

Uma vez que a pasta foi descompactada no diretório de sua escolha, basta adicionar no PATH de seu SO o caminho para a pasta ‘bin‘ de onde o maven foi descompactado.

No Linux e no OSX, basta adicionar uma linha em seu arquivo ‘.bash_profile‘ na pasta do seu usuário:

export PATH=$PATH:<diretório do maven descompactado>/bin

No Windows vá em ‘Configurações Avançadas do Sistema‘ -> ‘Variáveis de Ambiente‘, na parte de ‘Variáveis de ambiente para o usuário‘ clique em ‘Novo‘.

No campo ‘Nome‘ coloque ‘PATH‘, e no valor o caminho até a pasta ‘bin‘ do diretório do maven. No caso da imagem ‘C:mavenbin‘.

Adicionando o Maven no PATH do Windows

Lembrando que o maven é feito em Java, portanto é obrigatório que o Java esteja instalado na máquina e que a pasta ‘bin‘ do java esteja definida também no ‘PATH‘ para usá-lo.

Para usar as dependências que ele irá vincular no projeto dentro do Eclipse, basta adicionar a variável de ambiente no Eclipse M2_REPO:

‘Windows‘ -> ‘Preferences‘ -> ‘Java‘ -> ‘Build Path‘ -> ‘Classpath Variables‘

Clique em ‘New‘ e crie uma varável que se chama ‘M2_REPO‘ com o valor apontando para o diretório do seu usuário seguido de ‘/.m2/repository‘:

Criando o projeto

Uma vez que o maven esteja instalado, rode em um terminal:

$ mvn --version

Para se certificar que o maven está instalado corretamente e que a versão é a que você fez o download.

Agora que o maven está rodando corretamente, basta escolher uma para pasta colocar seu novo projeto e rodar o seguinte comando dentro da mesma:

$ mvn archetype:generate

Feito isso:

  • Uma série de opções irá aparecer para você escolher, apenas aperte Enter para que seja escolhido o tipo padrão de projeto Java.
  • Agora o maven irá pedir uma versão do gerador de projetos, apenas escolha a opção ‘1‘ e aperte Enter;
  • Feito isso você deve especificar um ‘groupId‘ para seu novo projeto, no caso do exemplo ‘br.com.dclick‘, que é onde o maven irá armazenar todos os artefatos que conterem esse mesmo ‘groupId‘. No caso do Hibernate por exemplo, o ‘groupId‘ é ‘org.hibernate‘;
  • Agora especifique um ‘artifactId‘, que no caso é o nome do projeto. Seguindo o exemplo do hibernate, o ‘artifactId‘ é ‘hibernate-core‘;
  • Especifique uma versão que no caso de nosso exemplo a versão padrão atende bem (1.0-SNAPSHOT);
  • E por último escolha um nome para o pacote que já será criado dentro da pasta do seu projeto.

Confirme as informações e deixe o maven terminar de criar seu projeto. Certifique-se que tudo está configurado corretamente e rode dentro da pasta de seu projeto novo:

$ mvn clean install

Isso fará com que o maven compile seu código, rode os teste, e gere um artefato (jar) que estará disponível em seu repositório local. Para entender como o maven organiza os artefatos, entre na sua pasta de usuário e depois na pasta ‘.m2‘ e dentro ‘repository‘. Repare que existe uma pasta com o nome do seu ‘groupId‘ e sua respectiva hierarquia, e dentro dessa pasta existe uma outra com o nome do seu artefato e por último uma outra pasta com a versão do mesmo. Abra a pasta e veja que o jar do seu projeto está dentro junto com o pom do mesmo. Por exemplo os artefatos do JUnit:

Para importar seu projeto novo no Eclipse, basta rodar o comando no terminal:

$ mvn eclipse:eclipse

Com isto o projeto se tornará um projeto que o eclipse entende, e assim será possível importá-lo. Importe o projeto e veja como o maven organizou as pastas e pacotes:

Hierarquia de um projeto criado no Maven e importado no Eclipse

Abra na ‘View‘ ‘Package Explorer‘ do Eclipse e repare que existem duas pastas principais no projeto: ‘src/main/java‘ e ‘src/test/java‘. Em ambas as pastas existe o pacote ao qual tínhamos dado nome no momento em que criamos o projeto pelo maven. Também existe uma classe com um método ‘main‘ que apenas imprime “Hello World!”, e uma classe de teste que apenas possui um ‘assertTrue(true);‘.

Alguns detalhes importantes: o projeto que o maven cria por padrão usa o JUnit 3.8.1, e para mudar a versão basta alterar o ‘pom.xml‘ que o maven criou. Outro detalhe importante é que por padrão o maven compila o projeto usando Java 1.3, portanto é preciso adicionar o seguinte trecho de xml no ‘pom‘ do projeto para alterar a versão do compilador, dentro da tag ‘project‘:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <compilerVersion>1.6</compilerVersion>
                <source>1.6</source>
                <target>1.6</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

Note que foi adicionado uma tag ‘encoding’ com o valor ‘UTF-8‘, isso para dizer que as classes estão escritas em formato UTF-8 para padronizar o build.

Agora que o projeto está criado e configurado podemos começar a desenvolver em cima dele. Todas as suas classes da aplicação devem sempre estar dentro de ‘src/main/java‘, pois esta é a pasta que o maven irá exportar no jar que estará disponível no repositório.

Dica: rode o comando:

$ mvn clean install

Agora abra a pasta do projeto. Será criada uma pasta ‘target‘ que contém o ‘jar‘ do seu projeto além de alguns relatórios de teste e os arquivos compilados.

Na pasta ‘src/test/java‘ devem ir todas as classes de teste do seu projeto. Assim o maven se encarregará de rodá-los quando o jar for gerado, garantindo a integridade do projeto.

No próximo post será explicado melhor o funcionamento do maven, por isso tente seguir o exemplo e poste dúvidas a vontade.

Set 8

EXtreme Programming em Cinco Minutos

Escrito por Edgard Davidson em 1, 4, 6, Agile, api, AR, arte, auto, back, BI, busca, class, cliente, código, comunicação, control, dados, Desenvolvedor, desenvolvedores, Desenvolvimento, Dica, err, erro, event, falha, Flex, for, framework, Frameworks, Geral, ide, IE, if, image, int, jogo, lista, lógica, Mestrado, mg, Motivação, mudanças, O, on, Partilha, problema, problemas, processo, produto, programação, Projetos, protótipo, rest, RIA, Ria’s Geral, site, Software, tag, Tema, Teste, Testes Automatizados, UI, Vários, Ved, XP @ 09 8th, 2010 | via http://edgarddavidson.com | Sem comentários
Edgard Davidson
? X
  • Bookmarks

Blinkbits BlinkLists BlogLines Blogmarks Buddymarks CiteULike Co.mments Del.icio.us Digg Diigo

Fark Feed Me Links Furl Google Linkagogo ma.gnolia Mister Wong Newsvine Propeller Rawsugar

Reddit Rojo Simpy Sphinn Spurl Squidoo StumbleUpon Tailrank Technorati Yahoo

More »

A eXtreme Programmig (XP) proposta por Kent Beck [BECK, 2004] tem o objetivo de propor uma metodologia ágil para equipes de tamanho pequeno a médio, onde o desenvolvendo de software está inserido em um contexto de requerimentos vagos ou que mudam rapidamente.  O próprio autor descreve a Programação eXtrema como: “A XP é uma maneira leve, eficiente, de baixo risco, flexível, previsível, científica e divertida de desenvolver software”. [BECK, 2004].  Ainda segundo [BECK, 2004], a XP reconhece que os projetos precisam dedicar-se à obtenção da redução dos custos e tirar vantagem daquilo que foi economizado. Além disso, defende a não especialização dos membros do time, ou seja, todos participam de todas as atividades, em pares e com sistema de rodízio dos pares o desenvolvimento de infra-estrutura e frameworks durante o desenvolvimento da aplicação, e a comunicação face a face ou por meio de testes eficientes e código cuidadosamente escrito.

Segundo [BECK, 2004], a XP se distingue das outras metodologias por:

  • Seu feedback antecipado;
  • O planejamento incremental, que gera rapidamente um plano geral que evolui com o decorrer do projeto;
  • Sua habilidade de implementar as funcionalidades de forma flexível considerando as necessidades mutáveis do negócio;
  • Sua confiança nos testes automatizados;
  • Sua confiança em comunicação oral;
  • Sua confiança em um processo de projeto evolutivo que dura tanto quanto o sistema;

Risco: O Problema Básico

A principal motivação da Programação eXtrema parte do princípio que o desenvolvimento de software tem falhas na entrega e falhas nos produtos entregues caracterizando o problema básico – o risco, portanto, produz-se software de baixa qualidade. Segundo [BECK, 2004], existem vários riscos associados ao desenvolvimento do software, como: (i) cronograma irreal; (ii) cancelamento do projeto por vários atrasos no cronograma; (iii) o sistema é descontinuado pelo alto custo de se fazer modificações ou a taxa de erros cresce tanto que o sistema deve ser substituído; (iv) o negócio é mal compreendido e o software desenvolvido não resolve o problema original; (v) as regras de negócio mudam antes que o software seja finalizado; (vi) funcionalidades inúteis. A missão da XP é aceitar o risco como problema a ser resolvido, onde o objetivo é encontrar a solução. Nesse sentido, a necessidade é criar um modelo de desenvolvimento de software que trate desses riscos.

Além de mitigar ao máximo os riscos, a metodologia XP advoga que quatro variáveis têm de ser controladas no projeto – custo, tempo, qualidade e escopo. Dessa forma, o modelo desenvolvimento de software é dirigido sob a perspectiva de controlar as referidas variáveis. Em um projeto, as referidas variáveis são restrições inerentes ao produto final. Eventualmente se o custo e/ou o tempo forem escassos, é muito provável que a qualidade do produto entregue possa estar muito inferior àquela esperada no escopo do projeto.  A XP cria valores, princípios de atividades básicas e práticas para tentar conduzir bem os problemas correlacionados à efetivação dos riscos do projeto. Esses valores podem ser caracterizados em:

  1. Comunicação: deve ser extremamente aberta e franca. A XP dá uma ênfase especial à comunicação e é essencial para tudo o que acontece no contexto de um projeto. Segundo [BECK, 2004], “Os problemas nos projetos podem ser invariavelmente rastreados a alguém não ter conversado com alguém mais sobre alguma coisa importante”.
  2. Simplicidade: é representada na XP pela busca pela “coisa mais simples que possa funcionar” [BECK, 2004]. O propósito é construir algo simples e direto que solucione problemas de hoje e ter certeza de que isso seja suficientemente flexível para ser refinado e expandido de modo a solucionar os problemas de amanhã, mas fundamentalmente não se preocupa hoje com os problemas de amanhã.
  3. Feedback: seu objetivo é criar ciclos de realimentação que atuam em intervalos de tempos pequenos como dias e minutos, em relação aos testes de unidade, e, grandes semanas (dias, semanas) em associação a teste de aceitação de usuário, e,  planejamento e cronograma de projeto.
  4. Coragem: é o valor que permite aos participantes da XP se aventurarem em projetos de alto risco e alta recompensa nas tarefas de desenvolvimento. Isso muitas vezes se manifesta na forma de desenvolvedores que constroem protótipos descartáveis durante a codificação.

Princípios Fundamentais da XP

De acordo com [BECK, 2004] os princípios fundamentais da XP são:

  1. Feedback rápido: o princípio é obter o feedback, interpretá-lo e aplicar o que é aprendido no sistema o mais rápido possível, realimentando o que foi aprendido em dias ou semanas, em vez de meses ou de anos.
  2. Simplicidade presumida: este princípio dita que a equipe deve pressupor que todo problema tem uma solução razoavelmente simples. Como conseqüência, o tempo poupado na maioria dos problemas para os quais isso é válido pode ser usado para abordar problemas que realmente necessitem de soluções complexas.
  3. Mudanças incrementais: parte do princípio que grandes modificações feitas de uma só vez têm grandes chances de não dar certo. Assim, qualquer problema é resolvido por meio de uma série de mudanças menores.
  4. Aceitação das mudanças: este princípio se apóia na premissa da XP que de desenvolver software no contexto de requerimentos vagos ou que mudam rapidamente. As idéias é que os membros da equipe devem simplesmente aceitar as mudanças como algo natural, diário, em vez de algo que ocorre eventualmente.
  5. Alta qualidade: ninguém gosta de fazer um trabalho de baixa qualidade. Todos gostam de fazer um bom trabalho. A XP defende que se você não vai fazer algo bem, então não faça independentemente das restrições de cronograma e orçamento.

Atividades Básicas do Desenvolvimento

[BECK, 2004] define quatro atividades básicas associadas ao desenvolvimento de software utilizando XP, sendo elas:

  1. Codificar: as práticas da XP utilizam o código como um mecanismo para atingir objetivos secundários incluindo o aprendizado rápido e uma melhor comunicação. Algumas das práticas citadas no tópico a seguir estão ligadas à codificação: refatoração, programação em pares e integração continua.
  2. Testar: está fortemente relacionada à codificação. Os desenvolvedores devem escrever códigos de teste de unidade antes escrever o código e verificar se o código passa por todos esses testes antes de se tornar um sistema. O cliente também é envolvido nos testes funcionais, onde os mesmos devem confirmar se o sistema satisfaz as regras de negócio.
  3. Escutar: refere-se à necessidade de estruturar a comunicação de modo que as conversas, sempre que possível, envolvam os problemas de hoje, não os de amanha, em um nível de detalhe apropriado.
  4. Projetar: está associado a necessidade de criar uma estrutura que organiza a lógica dentro do sistema de modo a torná-lo robusto e possível de manter. Nesse contexto, a prática utilizada é projetar simples.

Práticas do XP

[BECK, 2004] lista algumas práticas que devem ser seguidas pela equipe de desenvolvimento para que os valores, princípios e atividades básicas da metodologia sejam alcançados, são elas:

  1. O jogo do planejamento: determinar o escopo da próxima versão de forma que os requisitos mais importantes sejam contemplados e a entrega possa ser um praza não muito longo. Quando o planejado fugir do realizado, então o plano deve ser reajustado.
  2. Entregas freqüentes: dividir o desenvolvimento em pequenos módulos de acordo com as funcionalidades de forma que possa ser rapidamente colocado em produção.
  3. Metáfora: conduzir o desenvolvimento por meio de histórias simples, compartilhada por todos os envolvidos, sobre como o sistema deverá funcionar.
  4. Projeto Simples: o sistema deve ser pensado e projetado de maneira simplista. Complexidades desnecessárias são removidas assim que descobertas.
  5. Testes: os programadores escrevem os testes de unidade durante todo o desenvolvimento, o qual deve ser executado sem falha para o desenvolvimento continue.
  6. Refatoração: os programadores se preocupam sempre em deixar o código estruturado removendo códigos redundantes, simplificando e aumentando a flexibilidade.
  7. Programação em pares: todo o desenvolvimento é realizado por programadores trabalhando em pares.
  8. Propriedade coletiva: todos podem alterar o código em qualquer trecho e em qualquer momento.
  9. Integração contínua: integre e atualize as versões do sistema várias vezes por dia, cada vez que uma tarefa fora terminada.
  10. Semana de 40 horas: como regra, trabalhe no máximo quarenta horas por semana, evitando fazer hora extra por duas semanas consecutivas.
  11. Cliente presente: mantenha o cliente o mais próximo possível para responder a questões.
  12. Padrões de codificação: os programadores escrevem código respeitando as regras que enfatizam comunicação através do código.

Referência:  BECK, Kent (2004). Programação eXtrema explicada: escolha as mudanças, Bookman, 2004.

« Entradas anteriores |

ACERCA

O que é o RedeRIA ?

O redeRIA não é nada mais que um agregador de feed's que disponibiliza o conteudo de varios blogs e autores ao redor do mundo RIA, actualmente agregamos mais de 2755 entradas vindas de 53 blogs especializados em ria’s, pelo que só fica a ganhar em assinar o feed ou seguir a comunidade no twitter.

Se acha que o seu blog ou um blog de um amigo é interessante e util para os leitores o redeRIA, faça a sua submissão aqui.

Feed: assine já
Twitter: siga-nos

GOOGLE

Votação


Deveria o RedeRia agregar conteúdo em inglês?
Ver Resultados

AUTORES


Eduardo KrausAlexandre TadashiBindableCognitiva SoluçõesDaniel LopesDaniel SchmitzDanielPedrinhaDClick TeamEbercomEdgard DavidsonElvis FernandesErko BrideeFabiel PrestesFábio Batista da SilvaFabio da SilvaFabriccio BernardesFelipe BorellaFlavia MoreiraGabriel VersalliniGabriela T. PerryIgor MusardoJanderson CardosoJoão AugustoJose Carlos FielKelps SousaLeonardo FrançaLucas MarçalLuis MessiasLuiz TarabalMario JuniorMário SantosMauro MartinsPablo SouzaPedro ClaudioreneRia BrazilriaPTRicardo CerqueiraRobson FernandesRodrigo Pereira FragaSaintBrSamuelFacchinelloSergio SouzaSilva DeveloperStefan HorochovecTech CaffeTecinforThiago BuenoVedVinícius SandimWillian ManoXAML Cast

PUBLICIDADE








Powered by Wordpress & msdevstudio.com