Não represento de nenhuma maneira a Microsoft, mas gostaria de falar um pouco aqui sobre Windows Azure e Nuvens Privadas.
As vezes quando converso com colegas sobre Windows Azure, ouço os clássicos questionamentos: Nuvem não é segura. Trabalhamos para governo, não podemos colocar software em servidores de uma empresa estadunidense. Para quê vou aprender algo que quase ninguém quer usar e só funciona na nuvem?
O fato é que aplicações implantadas em nuvem podem trazer vantagens que não podem ser ignoradas apenas com base em questionamentos como esses. A plataforma Windows Azure por exemplo tem crescido a cada dia, e cada vez novos recursos são acrescentados. Para um desenvolvedor, ou empresa, que tem o .NET Framework como sua principal plataforma de desenvolvimento, abdicar dessas vantagens pode significar abrir mão de uma grande vantagem competitiva.
Mas e os questionamentos acima? Como ter as vantagens da computação em nuvem sem ter que hospedar as aplicações num ambiente público e controlado por empresas de fora do país?
A alternativa são as nuvens privadas. No caso das plataformas Microsoft, ambientes baseados em Windows System Center 2012 ou Windows Server 2012, bastante semelhantes ao Windows Azure e que tem o modelo de desenvolver de aplicações bastante semelhante, se não idêntico, em muitos casos.
Na próxima vez que estiver considerando alternativas para aplicações robustas e escaláveis em plataforma Microsoft, não deixe de considerar essa opção.
E como desenvolvedor, não ignore o Windows Azure apenas por que a empresa onde trabalha se mostra resistente a ele. Conheça seus benefícios, as alternativas, e quem sabe até os convença a investir na plataforma.
Mais informações: http://msdn.microsoft.com/en-us/library/windowsazure/jj136831.aspx
Rafael Romão
Estratégias em Arquitetura de Software
sexta-feira, 3 de maio de 2013
domingo, 28 de abril de 2013
Dynamic Method Binding
Já não é novidade que a partir da versão 4 do .NET Framework e da linguagem C# é possível declarar objetos com tipagem dinâmica. Veja este link para mais detalhes.
Em C#, quando um objeto é declarado como dynamic, o compilador nos permite invocar qualquer método a partir desse objeto, sem checar em tempo de compilação se este método existe ou não. Esse recurso é conhecido como Dynamic Method Binding e apenas em tempo de execução o Framework irá informar, através de uma exceção, que o método invocado não existe.
Exemplo:
Imagine escrever um conjunto de métodos privados sobrecarregados, cada um tratando um tipo específico de entrada e delegar a um único método público a função de decidir qual dos métodos privados deve ser executado.
O exemplo abaixo faz isso:
Veja como esse mesmo código ficaria se utilizássemos tipagem dinâmica para deixar que o .NET Framework decida em tempo de execução qual a versão do método GenusFor deve ser executada:
Usando ((dynamic)this), informamos ao compilador que queremos que o this seja tratado como um tipo dinâmico, assim a existência de um método GenusFor com os parâmetros informados não será verificada em tempo de compilação.
Em tempo de execução, o CLR irá procurar por um método chamado GenusFor no objeto this e encontrará 4 sobrecargas, 1 pública e 3 privadas. Nesses casos, o comportamento do CLR é utilizar o método cujos tipos dos parâmetros esperados sejam o mais próximos possíveis dos parâmetros passados. Isso faz com que o método correto seja invocado, conforme o tipo de IAnimal recebido como parâmetro.
Interessante, não? No entanto lembre-se que recursos poderosos como esse devem ser usados com muita cautela. Brinque um pouco com o código disponível no GitHub e veja o impacto positivo e negativo que esse tipo de abordagem pode trazer.
Confira também o uso desse recurso em um dos exemplos citados no livro Implementing Domain-Driven Design, de Vaugh Vernon.
Abraços.
Em C#, quando um objeto é declarado como dynamic, o compilador nos permite invocar qualquer método a partir desse objeto, sem checar em tempo de compilação se este método existe ou não. Esse recurso é conhecido como Dynamic Method Binding e apenas em tempo de execução o Framework irá informar, através de uma exceção, que o método invocado não existe.
Exemplo:
dynamic objetoDesconhecido = ObtemObjetoDesconhecidoDeAlgumLugar(); objetoDesconhecido.MetodoQueNaoExiste(); // Compila mas não executaNão quero discutir aqui o propósito dessa inclusão à linguagem, quero apenas apresentar uma construção bastante interessante permitida com o uso desse recurso.
Imagine escrever um conjunto de métodos privados sobrecarregados, cada um tratando um tipo específico de entrada e delegar a um único método público a função de decidir qual dos métodos privados deve ser executado.
O exemplo abaixo faz isso:
public class Taxonomy
{
public string GenusFor(IAnimal animal) {
if (animal is Lion)
return GenusFor((Lion)animal);
if (animal is Zebra)
return GenusFor((Zebra)animal);
if (animal is Elephant)
return GenusFor((Elephant)animal);
return null;
}
private string GenusFor(Lion lion) {
return "Lion";
}
private string GenusFor(Zebra zebra) {
return "Zebra";
}
private string GenusFor(Elephant elephant) {
return "Elephant";
}
}
O código acima pode parecer desnecessário se considerarmos que o genero do animal poderia ser uma simples propriedade da interface IAnimal, no entanto serve bem para ilustrar a ideia.
Veja como esse mesmo código ficaria se utilizássemos tipagem dinâmica para deixar que o .NET Framework decida em tempo de execução qual a versão do método GenusFor deve ser executada:
public class Taxonomy
{
public string GenusFor(IAnimal animal) {
return ((dynamic)this).GenusFor((dynamic)animal);
}
private string GenusFor(Lion lion) {
return "Lion";
}
private string GenusFor(Zebra zebra) {
return "Zebra";
}
private string GenusFor(Elephant elephant) {
return "Elephant";
}
}
Usando ((dynamic)this), informamos ao compilador que queremos que o this seja tratado como um tipo dinâmico, assim a existência de um método GenusFor com os parâmetros informados não será verificada em tempo de compilação.
Em tempo de execução, o CLR irá procurar por um método chamado GenusFor no objeto this e encontrará 4 sobrecargas, 1 pública e 3 privadas. Nesses casos, o comportamento do CLR é utilizar o método cujos tipos dos parâmetros esperados sejam o mais próximos possíveis dos parâmetros passados. Isso faz com que o método correto seja invocado, conforme o tipo de IAnimal recebido como parâmetro.
Interessante, não? No entanto lembre-se que recursos poderosos como esse devem ser usados com muita cautela. Brinque um pouco com o código disponível no GitHub e veja o impacto positivo e negativo que esse tipo de abordagem pode trazer.
Confira também o uso desse recurso em um dos exemplos citados no livro Implementing Domain-Driven Design, de Vaugh Vernon.
Abraços.
sexta-feira, 26 de abril de 2013
Não posso resolver o seu problema se você só me informa a sua solução.
Imagino que todo desenvolvedor um pouco mais experiente já tenha passado por esse tipo de situação. Seu 'chefe' lhe apresenta um 'problema' e diz que você precisa resolvê-lo urgente. "Precisamos disso para a próxima versão." Algo do tipo:
Normalmente isso não costuma ser verdade. Questões técnicas quase sempre passam despercebidas no momento da elaboração da solução, em maior ou menor grau, e muitas vezes o desenvolvedor não se sente a vontade, ou se quer tem a opção de criticar a solução apresentada pelo 'chefe'. Ou pior, ele implementa tal solução sem perceber que haverá um impacto indesejado, que causará problemas futuros.
O grande problema nisso é o fato de o 'chefe' ter comunicado uma solução para um problema que ele se quer expôs ao desenvolvedor. Duas cabeças pensam melhor que uma. Quanto melhor a equipe conhecer o verdadeiro problema a ser resolvido, maior será a chance de alguém visualizar com antecedência os impactos negativos de se implantar uma ou outra solução.
Não é a toa que metodologias como o Scrum determinam que decisões técnicas ("soluções") sejam tomadas pelos desenvolvedores, cabendo ao Product Owner apenas a tarefa de especificar e priorizar os requisitos ("problemas").
Infelizmente essa é uma realidade que nem sempre podemos mudar. Mas em todo caso, na próxima vez que você receber uma tarefa ("solução") para implementar, pense se você tem total entendimento de qual é o problema que aquela solução se destina a resolver. Se não tiver esse entendimento, tente esclarecer os objetivos com os demais membros do time, com seu 'chefe', e quem mais puder ajudar. Não se acanhe. Quanto melhor você entender o problema, melhor capacitado estará para implementar uma solução, ainda que não seja você quem a defina.
Seja pragmático.
Referência: http://www.acceptancetesting.info/the-book/
"Preciso que crie essa tabela no banco, armazene tais valores e altere tal e tal tela para o usuário fazer o cadastro dos dados."Nesses cenários o 'chefe' sabe bem o que está fazendo, domina a arquitetura do sistema, sabe que basta inserir a tabela no banco e alterar as telas de cadastro, certo?
Normalmente isso não costuma ser verdade. Questões técnicas quase sempre passam despercebidas no momento da elaboração da solução, em maior ou menor grau, e muitas vezes o desenvolvedor não se sente a vontade, ou se quer tem a opção de criticar a solução apresentada pelo 'chefe'. Ou pior, ele implementa tal solução sem perceber que haverá um impacto indesejado, que causará problemas futuros.
O grande problema nisso é o fato de o 'chefe' ter comunicado uma solução para um problema que ele se quer expôs ao desenvolvedor. Duas cabeças pensam melhor que uma. Quanto melhor a equipe conhecer o verdadeiro problema a ser resolvido, maior será a chance de alguém visualizar com antecedência os impactos negativos de se implantar uma ou outra solução.
Não é a toa que metodologias como o Scrum determinam que decisões técnicas ("soluções") sejam tomadas pelos desenvolvedores, cabendo ao Product Owner apenas a tarefa de especificar e priorizar os requisitos ("problemas").
Infelizmente essa é uma realidade que nem sempre podemos mudar. Mas em todo caso, na próxima vez que você receber uma tarefa ("solução") para implementar, pense se você tem total entendimento de qual é o problema que aquela solução se destina a resolver. Se não tiver esse entendimento, tente esclarecer os objetivos com os demais membros do time, com seu 'chefe', e quem mais puder ajudar. Não se acanhe. Quanto melhor você entender o problema, melhor capacitado estará para implementar uma solução, ainda que não seja você quem a defina.
Seja pragmático.
Referência: http://www.acceptancetesting.info/the-book/
segunda-feira, 15 de abril de 2013
O papel do testador no futuro do desenvolvimento de software.
O papel do testador no futuro do desenvolvimento de software é um tema que já havia planejado tratar aqui. No entanto, Igor Abade já o fez com maestria e portanto não vejo nada mais adequado que referenciar o seu texto aqui, ao invés de reescrever a roda.
O testador de software deve ser visto como mais um membro da equipe de desenvolvedores, tão importante quanto os demais, sejam eles programadores, analistas de negócio ou gerentes. Seu trabalho deve ser integrado ao processo e jamais menosprezado.
Aproveito para indicar o livro Specification By Example, do Gojko Adzic, que apresenta entre outros aspectos um ponto de vista semelhante a respeito do papel do testador de software.
Confiram o texto do Igor Abade.
O testador de software deve ser visto como mais um membro da equipe de desenvolvedores, tão importante quanto os demais, sejam eles programadores, analistas de negócio ou gerentes. Seu trabalho deve ser integrado ao processo e jamais menosprezado.
Aproveito para indicar o livro Specification By Example, do Gojko Adzic, que apresenta entre outros aspectos um ponto de vista semelhante a respeito do papel do testador de software.
Confiram o texto do Igor Abade.
sexta-feira, 5 de abril de 2013
O que constitui um programador pragmático?
Todo desenvolvedor é único, com pontos fortes e fracos, preferências e aversões. Com o tempo, cada um irá criar seu próprio ambiente. Esse ambiente irá refletir a individualidade do programador, assim como seus hobbies, roupas, corte de cabelo. No entanto, se você for um programador pragmático, você irá compartilhar muitas das seguintes características:
- Adotar cedo e adaptar-se rápido: Você tem um instinto por tecnologias e técnicas, e ama testar coisas novas. Quando diante de uma novidade, você será capaz de compreende-la rápido e integrá-la com o restante de seu conhecimento. Sua confiança nasce de sua experiência.
- Ser curioso: Você tende a fazer perguntas. Isso é bacana, como você fez? Você teve problemas com essa biblioteca? O que é esse BeOS do qual ouvi falar? Como links simbólicos são implementados? Você é um acumulador de detalhes, cada um podendo afetar alguma decisão anos a frente.
- Ser um pensador crítico: Você raramente aceita as coisas como dadas sem primeiro entender os fatos. Quando um colega diz "porque é assim que funciona," ou um fornecedor promete a solução para todos os seus problemas, você sente o cheiro de um desafio.
- Ser realista: Você tenta entender a real natureza de cada problema que enfrenta. Esse realismo lhe dá uma boa ideia de quão diferente as coisas são, e quanto tempo tomarão. Entender pro si próprio que um processo deve ser difícil ou vai tomar um tempo para ser concluído lhe dá estímulo para continuar.
- Atirar para todos os lados: Você se esforça para se familiarizar com todo tipo de tecnologia e ambiente, e trabalha para se manter atualizado. Embora seu trabalho atual exija que você seja um especialista, você sempre será capaz de seguir para novas áreas e novos desafios.
Deixamos a mais básica característica para o final. Todo programador pragmático a possui:
- Cuidar da sua criação.
Nós entendemos que não há sentido em desenvolver software a menos que você se preocupe em fazer isso bem feito.
- Pense! Sobre seu trabalho.
De modo a ser um programador pragmático, nós o desafiamos a pensar sobre o que faz enquanto faz. Isso não é uma análise única de suas práticas atuais, mas sim uma avaliação contínua de toda decisão tomada, a cada dia, em cada desenvolvimento. Nunca entre no piloto automático. Pense constantemente, criticando seu trabalho em tempo real. O velho lema da IBM, PENSE!, é o mantra do programador pragmático.
Se isso soa difícil pra você, então você está exibindo a característica de ser realista. Isso irá tomar boa parte do seu valioso tempo, tempo que provavelmente já está sobre tremenda pressão. A recompensa é um envolvimento mais ativo com o trabalho que você ama, um sentimento de domínio sobre um crescente conjunto de assuntos, e prazer em sentir um crescimento contínuo. Ao longo do tempo, seu investimento será pago à medida em que você e sua equipe se tornam mais eficientes, escrevem códigos mais fáceis de manter, e gastam menos tempo em reuniões.
Andrew Hunt e David Thomas, The Pragmatic Programmer: From journeyman to master, Addison Wesley 1999. Pág. xviii
terça-feira, 2 de abril de 2013
Engenheiro de Software ou Arquiteto de Software?
Há alguns dias me perguntaram a diferença entre um Arquiteto de Software e um Engenheiro de Software.
Após uma definição do papel de cada um, para quem é do ramo, pode até não ser difícil entender, mas para quem não é, pode parecer que são apenas duas formas de descrever a mesma função.
À época pedi um tempo para pensar numa forma simples de explicar, e minha resposta veio através de uma analogia com um jogo bem conhecido, um quebra-cabeças, daqueles de encaixar peças para formar uma imagem.
Nessa analogia dizemos que o Engenheiro de Software é aquele que desenha a imagem a ser montada, o que será visto quando o jogo for concluído, enquanto o Arquiteto de Software é aquele que divide a imagem em peças pequenas e encaixáveis, que juntas formam a imagem desejada.
Um Engenheiro de Software tem como objetivo transformar um conjunto de processos de negócio em software; modelar o domínio do negócio de modo que um software possa ser produzido.
Já o Arquiteto de Software tem como objetivo organizar os artefatos modelados pelo Engenheiro de Software de modo a conseguir o melhor encaixe possível entre eles, dados os objetivos do negócio.
E ai? Será que consegui explicar? Ou complicar ainda mais? rs
Após uma definição do papel de cada um, para quem é do ramo, pode até não ser difícil entender, mas para quem não é, pode parecer que são apenas duas formas de descrever a mesma função.
À época pedi um tempo para pensar numa forma simples de explicar, e minha resposta veio através de uma analogia com um jogo bem conhecido, um quebra-cabeças, daqueles de encaixar peças para formar uma imagem.
Nessa analogia dizemos que o Engenheiro de Software é aquele que desenha a imagem a ser montada, o que será visto quando o jogo for concluído, enquanto o Arquiteto de Software é aquele que divide a imagem em peças pequenas e encaixáveis, que juntas formam a imagem desejada.
Um Engenheiro de Software tem como objetivo transformar um conjunto de processos de negócio em software; modelar o domínio do negócio de modo que um software possa ser produzido.
Já o Arquiteto de Software tem como objetivo organizar os artefatos modelados pelo Engenheiro de Software de modo a conseguir o melhor encaixe possível entre eles, dados os objetivos do negócio.
E ai? Será que consegui explicar? Ou complicar ainda mais? rs
quinta-feira, 7 de março de 2013
Pragmatismo e TDD
Anteontem, 05 de Março de 2013, Uncle Bob Martin, um dos principais defensores do desenvolvimento guiado por testes (TDD), fez uma crítica ao modo como são vistas as startups, jovens empresas que se aventuram, ousam, e se arriscam na busca do sucesso através da criação de softwares inovadores.
Como resposta, alguns leitores tacharam o autor de ser muito dogmático a respeito da prática de TDD. E quem o conhece sabe que há alguma verdade nisso.
No dia seguinte, Uncle Bob publicou uma resposta onde apresentou o seu ponto de vista com relação ao pragmatismo vs dogmatismo no que se refere à prática de TDD, apontando situações em que ele é pragmático e não utiliza a técnica.
Segue abaixo, traduzido para nosso idioma:
Então, quando eu não pratico TDD?
- Não escrevo testes para getters e setters. Fazer isso normalmente é besteira. Tais getters e setters serão indiretamente testados por testes de outros métodos; então não há porquê testá-los diretamente.
- Não escrevo testes para variáveis membros. Elas também serão testadas indiretamente.
- Não escrevo testes para funções de uma só linha ou funções que são obviamente triviais. Novamente, elas serão testadas indiretamente.
- Não escrevo testes para GUIs. GUIs necessitam ajustes. Você tem que acertá-las no lugar alterando tamanho de fonte aqui, valores RGB ali, uma posição XY aqui, a largura de um campo ali. Fazer isso com testes primeiro é estupidez e perda de tempo.
- No entanto, me certifico que qualquer processamento relevante no código da GUI seja removido para módulos que sejam testáveis. Não permito que código relevante passe sem testes. Portanto meus códigos de GUI são pouco mais que colas e fios que enfiam os dados no seu lugar na tela (Veja artigos sobre MVVM e Model View Presenter).
- Em geral não escrevo testes para nenhum código que eu tenha que ajustar no lugar por tentativa e erro. Mas separo o código "ajustável" do código que estou mais certo de que escreverei testes.
- Ocasionalmente, ajusto código no lugar e então escrevo os testes posteriormente.
- Também ocasionalmente removo código "ajustado" e o reescrevo com testes primeiro.
- Qual abordagem escolher é uma questão de julgamento.
- Alguns meses atrás escrevi um programa inteiro de 100 linhas sem nenhum teste.
- O programa era para uma única execução. Seria usado uma vez e então descartado. (Era para um efeito especial em um de meus vídeos).
- O programa era todo relacionado à tela. Em essência, era um aplicativo GUI puro. Sendo assim eu tive que ajustar a coisa toda no lugar.
- Escrevi em Clojure, e portanto tinha REPL! Pude executar o programa à medida em que crescia a partir da REPL, e pude ver os resultados de cada linha de código que escrevia instantaneamente. Isso não era TDD, isso era EDD (Eye Driven Development).
- Normalmente não escrevo testes para frameworks, bancos de dados, web-servers, ou outra ferramenta de terceiros que supõe-se funciona. Crio mocks para essas coisas e testo o meu código, não o deles.
- Claro que as vezes testo códigos de terceiros se:
- Acredito que tenha defeitos.
- Os resultados são rápidos e previsíveis o bastante a ponto de criar um mock ser um exagero.
Não é tudo dogma.
Essa lista não está completa. Estou certo de que pensarei em outras vezes que não escrevi testes; mas o espirito dessa lista deve estar evidente. Pragmatismo entra em jogo quando fazemos TDD. Não é apenas dogma.
Entretanto, respeito o dogma; há uma razão para isso. Pragmatismo pode as vezes se sobresair; mas: Não escreverei nenhum código de produção relevante sem fazer todo esforço para usar TDD.
Uncle Bob Martin
Assinar:
Postagens (Atom)
