Segue a palestra feita em BH pro evento de inauguracão do DevIsland:

Links relacionados:


Postado na(s) categoria(s) Arquitetura , Eventos pelo Giovanni Bassi em 25 de junho de 2010 às 16:44 | Tags: ,

Um cupinzeiro demonstra emergência

Nos lugares onde os aspectos arquiteturais são levadas a sério como imprecindíveis para o sucesso de qualquer projeto é cada vez mais consenso de que a maneira tradicional de arquitetar sistemas não está provendo todo o valor que deveria.

Por maneira tradicional entenda:

  • Um arquiteto ou um time deles planeja a arquitetura de um sistema, mas não atua desenvolvendo ou não está ao lado dos desenvolvedores full-time.
  • A arquitetura de um sistema é planejada totalmente no começo do desenvolvimento, com definições sobre diversos aspectos da aplicação, como as camadas físicas e lógicas, a forma de acesso a dados, e as tecnologias em geral.
  • Uma mistura dos dois também é muito comum.

É comum também a criação de documentos que pré-restringem as opções de tecnologias, padrões, metodologias, etc, muitas vezes feitos pelos próprios arquitetos. Tais restrições se justificariam em nome da padronização, e raramente levam em conta cenários. Um exemplo é: “aplicações devem utilizar o Entity Framework para acessar dados” ou “ASP.Net Webforms sempre deve ser usado quando o desenvolvimento for web”.

Ainda é assim que a maioria dos times de arquitetura trabalha. Temos obtido ganhos? Sem dúvida! Pensar na arquitetura é melhor do que não pensar. Mas quais os problemas?

Alguns dos problemas são código jogado fora, código criado e nunca utilizado (inútil), código que não faz o que indica (enganando o desenvolvedor), soluções com alta fricção, que congelam o código e/ou a criatividade do desenvolvedor, entre diversos outros (comente sua lista de problemas lá embaixo).

Viva a padronização, matando a produtividade. O interessante é que o maior argumento para a padronização é justamente a produtividade. Será que é possível ser produtivo sem padrões? Será que é possível ter padrões e ainda assim permitir a criatividade? Vamos ver.

Já tem quase 10 anos que umas pessoas declararam que responder a mudanças é mais importante do que seguir um plano, e que indivíduos e interações são mais importantes do que processos e ferramentas. Isso significa que podemos ter um plano, mas devemos mudá-lo sempre que as premissas sobre as quais eles se fundaram mudarem, ou quando eles não fizerem mais sentido. E que podemos ter ferramentas, processos, e padrões, mas que as interações entre as pessoas, e o que sai delas são mais importantes. Interessante, não? Parece que aplica ao que estamos discutindo.

De lá pra cá esses valores, além de mais alguns, tomaram o mundo. Chegou a hora de falarmos não só sobre o que é uma boa arquitetura, mas também como chegar lá. O processo tradicional, baseado em algumas pessoas determinando como outras vão trabalhar, e em documentos antigos e não focados no projeto, não promovem a interação entre o time que realmente cria os detalhes de um software (e é nos detalhes que está o perigo). Como eles não interagem entre eles, com o negócio e com TI, a solução arquitetural proposta pelos arquitetos (externos ao time) é a solução aceita e aplicada. Uma solução concebida desta forma é linear. As variáveis são analizadas, um catálogo é avaliado, as melhores soluções são propostas, comparadas com outras candidatas, e uma é escolhida. Parece bastante linear, não parece? Sabe qual o problema de ser linear?

O problema é que uma solução linear não reflete as necessidades do negócio, a criatividade do time, os problemas da empresa, o ambiente (físico e humano) onde o software vai rodar, as regras e regulamanentos, e outras influências não lineares que moldam um software além do momento em que foram concebidas. São, por definição, míopes. Todos essas características juntas formam um sistema complexo, e quando interagem começam a criar resultados não lineares. Eles começam a emergir. As necessidades e as soluções que emergem são tão profundamente ricas que nenhum time de arquitetos, por melhor que seja, conseguiria alcançar sozinho, por que estão presos a sua linearidade.

O risco em usar uma solução linear, que presume um comportamento previsível, em um sistema complexo, é que as previsões não vão se confirmar. Em arquitetura isso vai gerar os problemas que já conhecemos. O mais interessante é que, como o sistema é assumido como linear, muitas das variáveis não são sequer analisadas (ou até conhecidas), porque só aparecem muito mais tarde. E como influenciam o resultado de forma não prevista, o desenvolvimento do software começa a parecer ser caótico, aleatório, absolutamente imprevisível. E ele não é imprevisível, só não é previsível além de um período muito curto.

Como resolver esse problema? Pra começar devemos aceitar o fato de que desenvolver software é um sistema complexo, e isso inclui sua arquitetura. Por isso teorias que pregam previsibilidade podem ser abandonadas, já que somos incapazes de prever o estado em que o desenvolvimento do sistema estará em um curto período de tempo, geralmente alguns meses.

Em seguida precisamos saber lidar com um sistema complexo. Uma excelente maneira, é a utilização de um modelo de controle de processo que seja empírico. O Scrum é um deles. O Scrum diz que trabalha com um processo iterativo e incremental, e se baseia em 3 pilares. Segundo o Scrum Guide (em português e gratuito):

    • O primeiro pilar é a transparência
      A transparência garante que aspectos do processo que afetam o resultado devem ser visíveis para aqueles que gerenciam os resultados. (…)
    • O segundo pilar é a inspeção
      Os diversos aspectos do processo devem ser inspecionados com uma frequência suficiente para que variações inaceitáveis no processo possam ser detectadas. (…)
    • O terceiro pilar é a adaptação
      Se (…) um ou mais aspectos do processo estão fora dos limites aceitáveis e o produto resultante será inaceitável, ele deverá ajustar o processo ou o material sendo processado. Esse ajuste deve ser feito o mais rápido possível para minimizar desvios posteriores.

O Scrum também diz que um pedaço de funcionalidade deve ser entregue a cada iteração, e que só o time pode tocar e influenciar o código. O time é seu próprio gerente, e é auto-organizado.

E como surge a arquitetura? Assim como todo o resto, ela emerge. Ela é desenvolvida incrementalmente a cada iteração, conforme é necessária. É claro para o time que alguma funcionalidade deve ser entregue, e as entregas funcionais são mais importantes que as não funcionais, como as arquiteturais.

Também é comum que, dentro de uma iteração, um time Scrum faça uma rápida prova de conceito e avalie arquiteturas candidatas. Muitas vezes, também durante uma iteração (geralmente nas primeiras), o time desenvolve uma visão geral da arquitetura do sistema, mas sempre lembrando que o foco é atender o cliente e maximizar a entrega de forma sustentável.

Quando um time se preocupa com arquitetura ele está claramente preocupando com o custo total de propriedade (TCO), além do seu próprio prazer em codificar, e o desenvolvimento iterativo e incremental, que habilita uma arquitetura emergente, facilita o alcance destes objetivos.

Concluo resumindo alguns pontos chave. Para habilitar uma arquitetura emergente o processo de desenvolvimento precisa:

  • ser decentralizado;
  • possuir um time auto-organizado;
  • ser transparente;
  • promover inspeção e adaptação constantes;
  • ser evolutivo;
  • promover a presença da língua do negócio;

Uma arquitetura bem feita serve ao time, não é o time que trabalha para satisfazê-la. Isso se reflete no TCO, na felicidade do time e no sucesso do projeto.

Pra saber mais:

  1. eu já havia falado rapidamente sobre isso quando mencionei a criação de frameworks corporativos;
  2. o assunto também faz parte do curso de Professional Scrum Developer;
  3. este post do Brad Appleton traz diversos links sobre o assunto;
  4. o Fábio Akita falou bastante sobre sistemas complexos e agilidade no RailsSummit do ano passado.

Bom estudo e divirta-se. O assunto é muito interessante.


Postado na(s) categoria(s) Arquitetura , Agilidade pelo Giovanni Bassi em 23 de março de 2010 às 03:28 | Tags: , ,

image

Dia 26 de janeiro fiz um webcast sobre design patterns. Expliquei um pouco o que são, onde devem ser utilizados, apresentei alguns padrões, mostrei alguns dos problemas no seu uso, e falei também sobre padrões de arquitetura. Abordei os seguintes padrões:

  1. Strategy
  2. Template Method
  3. Factory method
  4. Abstract factory
  5. Singleton

A gravação já está disponível no media center do MSDN. Acesse aqui.

A apresentação:

Os links:

Design Patterns:
http://dofactory.com/Patterns/Patterns.aspx
http://en.wikipedia.org/wiki/Design_Patterns

Padrões de Arquitetura (Fowler):
http://martinfowler.com/eaaCatalog

Na MSDN Magazine:
http://tinyurl.com/msdnmagdp1
http://tinyurl.com/msdnmagdp2

 

Na página de livros indicados há o livro de padrões que recomendo, e o do GoF.


Postado na(s) categoria(s) Eventos , Arquitetura pelo Giovanni Bassi em 9 de fevereiro de 2010 às 08:05 | Tags: , ,

280px-Penrose_triangle_svg Eu uso o termo “engenharia de software”. Quem já viu uma palestra minha, leu um artigo, ou frequenta este blog sabe disso. Só que já tem um tempo que tenho um certo problema com o termo. Principalmente porque o termo “engenharia” parece carregar práticas que não se aplicam em sua totalidade à criação de algo tão etéreo como software. Nas palestras que dou sobre engenharia de software ou processos logo no começo eu deixo claro que há uma grande diferença entre o que fazemos e o que um engenheiro civil faz. Comparo a criação de software com a construção de uma ponte e também com o litigar de um caso na justiça, e ressalto que há elementos de um, como de outro, mas que ainda assim não é um, como não é o outro.

Eu mudei de idéia. Não me incomodo mais com o termo. Quem me fez mudar de idéia foi a segunda edição do livro “Agile Software Development – The Cooperative Game” do Alistair Cockburn. Estou gostando muito do livro, e ele entra nesta discussão, perguntando se desenvolvimento de software é ou não engenharia. A resposta é: sim, é; e faz sentido.

A questão é que normalmente vemos engenharia de software como “ciências aplicadas”. O engenheiro é alguém com profundo conhecimento de matemática, física, química, e talvez outras ciências naturais, que faz uso deste conhecimento para criar coisas materiais. Ele utiliza seu conhecimento de física e de determinado material para determinar o tamanho de uma viga, dada a carga que ela vai ter que suportar, por exemplo. Só que o engenheiro não é só isso.

É verdade que o engenheiro deve aplicar o conhecimento das ciências naturais para resolver os problemas que encontra. Mas isso não significa que as perguntas que ele deve fazer para resolver os problemas com o qual ele se depara vêem tão matematicamente quanto as respostas para tais perguntas, ou ainda que ele as formule sozinho.

O que normalmente acontece é que um engenheiro, independentemente da área, terá que buscar de maneira criativa a pergunta correta para resolver um problema. Somente depois de fazer a pergunta certa – e pode haver mais de uma, cada uma resolvendo o problema com diferentes graus de exatidão – é que ele vai poder aplicar seus conhecimentos das ciências exatas. Até então ele está trabalhando criativamente, utilizando o conhecimento das ciências exatas em conjunto com diversos outros, combinando-os de maneiras aleatórias, ou utilizando técnicas de análise, para chegar em perguntas candidatas, que podem ser testadas, ou não, até que uma seja escolhida como a mais apropriada. E depois de resolver a pergunta escolhida, ela pode acabar não atendendo o problema de maneira satisfatória, e o processo começa de novo, só que desta vez após um grande processo de aprendizado ter acontecido, com um engenheiro agora mais preparado, e que vai olhar suas opções com mais abrangência e profundidade do que aconteceu na primeira iteração. O conhecimento gerado com a primeira iteração, tenha ela tido sucesso ou não, não tem preço, e só pode ser ganho desta forma, e não lendo um documento com as experiências de outra pessoa, por exemplo. Experiência não se compra.

Esse processo ocorre também em grupos, onde um time de engenheiros, e possivelmente alguns não-engenheiros, se reune para discutir um problema, e como vão resolvê-lo. Nesse caso, além de todo o processo de criatividade e invenção já citado, há ainda todo o processo de comunicação, que nada tem a ver com uma ciência natural como a física ou a matemática. O problema é sempre formulado por alguém, que não é o engenheiro. Isso significa que o engenheiro nunca está só, e o processo de comunicação sempre existe. E se há comunicação estamos abrindo as portas para atividades que nada tem a ver com matemática ou física. Assuntos como negociação, persuação, hierarquia, relacionamento interpessoal, entre outros, passam a preocupar o engenheiro, que não deve mais se restringir a números, vigas, ou a resistência de materiais.

Diante desta visão, fica mais fácil dizer que engenharia de software existe, sim. Da mesma forma, temos atividades mais exatas, como a aplicação de algum padrão de projeto, ou de polimorfismo, por exemplo, mas temos também atividades relacionadas a comunicação, como reuniões diárias, e o pareamento. Nesses momentos estamos trabalhando nossa capacidade inventiva e comunicativa para buscar as perguntas corretas para atender determinado caso de uso história. Nesse cenário o engenheiro civil é mais parecido com o engenheiro de software do que pensávamos; temos os processos mais exatos, mas eles são somente parte da prática, já que temos também os processos inventivos e comunicativos.

Você, como desenvolvedor de software que me lê agora, deve à sua profissão se aprimorar em ambos os lados da sua prática, o humano, e o exato. E então poderá se qualificar como um engenheiro.

(Quantas faculdades de engenheria será que expõe os alunos a processos que não tocam somente as ciências exatas, mas tocam também em assuntos como liderança, criatividade, negociação, entre outros? Será que podemos qualificá-las como verdadeiros cursos de engenharia?)


Postado na(s) categoria(s) Arquitetura pelo Giovanni Bassi em 21 de janeiro de 2010 às 15:17 | Tags:

Saí agora a pouco de uma sessão remota com um cliente do Sul do Brasil. Alguns problemas de performance atrasavam a aplicação, feita com ASP.Net Webforms e SQL Server. Em dois dias descobrimos algumas fontes do problema: uso incorreto do Microsoft Ajax, falta de compressão no IIS, e um problema chato de memory leak que demandou uma análise profunda dos dumps de memória, originado de uma única palavra em um único arquivo de código, que todos imaginavam inofensiva. (Aliás, cuidado com ela: “static”.)

Pouco antes estava em outro cliente, trabalhando um modelo de factories de entidades, baseado em Abstract Factory, criado para solucionar um problema de regras dinâmicas de entidades obtidas via NHibernate. Usamos o modelo de interceptação para, em conjunto com o Unity, resolver as dependências dinâmicas, injetá-las nas factories, que eram singletons (graças ao modelo de lifetime managers do Unity), que depois as passariam para as entidades correspondentes quando criadas pelas factories concretas, utilizando as regras como políticas (no padrão strategy). Parece complicado? E foi.

Deixei o cliente analisando o modelo de headers do WCF para implementar uma solução customizada. Estávamos estudando um modelo de extensão com Endpoint Behaviors customizados, algo formidável permitido pelo WCF, mas nada simples.

Porque tão complicado? Afinal, porque arquitetamos, senão para permitir uma melhor sobrevida da aplicação, mais barata, enquanto ela atende todos os requisitos operacionais e de negócio. Oras, se ficou muito complexo vai ficar mais difícil de manter, e portanto mais caro.

No primeiro caso, cuidávamos de um código sem uma linha de testes automatizado ou requisitos de performance escritos, feitos por um desenvolvedor desatento a questões que só apareceriam quando a aplicação atingisse um tamanho muito maior, ou seja, código que não escalava. No segundo caso estávamos cuidando de código de infra-estrutura.  O código de negócio em si está altamente desacoplado, e as classes de infra que fizemos foram desenvolvidas com TDD, todas extensivamente testadas, e por isso, funcionando de forma 100% garantida. O cliente seguiu para continuar implementando aquele código que o cliente dele está pagando ele pra fazer. Eu, que arquitetetei o modelo e auxiliei (ou realizei) as implementações mais complexas, trabalhei para fazer o código que o meu cliente me pagou, aquele que o habilitaria a ser mais produtivo.

A função do arquiteto acaba sendo essa mesmo. Não consigo conceber uma equipe sem um arquiteto e um bom sênior para dar prosseguimento no código. E ele tem que acompanhar o projeto para ajudar a equipe. Para entregar soluções completas profissionalmente precisamos de profissionais capacitados. Fazer software, concretizar sonhos, não é simples, mesmo que fosse no papel. Há uma complexidade inerente ao processo, e quando transportamos esses sonhos para o computador, há técnicas de engenharia precisas para ajudar a resolver os problemas do mundo real. Qualquer outra opção, sem engenharia especializada, levaria a uma solução que atenderia apenas parcialmente.

Não desenvolvemos foguetes com amadores. Não operamos corações com enfermeiros. Por mais que possamos argumentar que podemos simplificar, simplesmente não se opera um coração de maneira simples. Há muitas camadas até chegar o coração, tem que trabalhar com ele funcionando, e depois fechar tudo. De maneira equivalente, software tem suas próprias complicações.

Esse é um dos principais motivo da existência deste blog. Apresentar algumas das idéias que tenho pra ajudar nesse processo tão difícil. É por isso que falo de DDD, TDD, Scrum, Domain Events, ASP.Net MVC, DI, SOLID, etc, etc… É também a idéia por trás da criação do grupo .Net Architects.

Diante disso tudo, a cada dia acredito menos em soluções simples, pra não dizer simplórias, baseadas em arrasta e solta, baseadas muito fortemente em geradores de código, ou qualquer coisa que elimine um bom engenheiro. Usuário não programa. Alguém com certeza vai comentar que há cenários e cenários, e que há aplicações em que o arrasta e solta resolve. Que alto acoplamento é ok. Que testes são desnecessários. Que há sistemas simples. Já adianto: você está enganado. Não há. Não há nada disso. O que há é um desrepeitoso desperdício de recursos, que deveria ultrajar tanto quem fez o software, quanto quem paga por ele.


Postado na(s) categoria(s) Arquitetura pelo Giovanni Bassi em 2 de dezembro de 2009 às 02:08 | Tags:

Eu tinha ficado de falar de Domain Events por aqui, já que deixei um exemplo rápido no post de princípio aberto fechado. Chegou a hora.

Entrei em contato com a idéia no blog do Udi Dahan, que é um forte defensor do DDD. Lá ele fez uma série de três posts (um, dois, três). De lá pra cá, tive a chance de implementá-lo algumas vezes com alguns clientes, e os resultados foram muito interessantes. Em alguns casos os eventos eram parte do processo de atualização do domínio, em outros toda comunicação da camada de aplicação com o domínio se passava com eventos de domínio.

Os posts do Udi são muito bons, e recomendo que você os leia. Ainda assim, acho que eles ficaram muito extensos, então vou pegar mais leve, e mostrar um exemplo mais direto.

A idéia é que você tenha eventos que façam sentido para o domínio, os eventos são coisas interessantes que aconteceram no seu domínio. Vamos supor que você esteja fazendo um sistema de locadora, alguns eventos poderiam ser “filme locado”, “filme devolvido”, “cliente cadastrado”, e coisas do tipo.

O conceito de eventos de domínio ajuda a aplicar a idéia de Command and Query Separation (CQS). Com eventos de domínio, suas operações de escrita ficam todas encapsuladas em comandos, na forma de eventos (fugindo do conceito do Command Pattern, e entendendo um comando como uma mensagem).

E como funciona? Muito simples. Vou usar aqui Domain Events em conjunto com um contêiner de injeção de dependência (mais sobre DI neste blog aqui, quando discuto DI x Service Locator, e aqui, um webcast sobre o assunto). Mr. Dahan faz também com um modelo de registro, que é uma opção interessante e menos “mágica”.

O básico de tudo é uma classe abstrata/interface que abstraia a idéia de evento:

public interface IDomainEvent
{
}

A partir daí você cria classes que representam eventos reais. Aqui vocês vêem o evento de filme alugado:

public class FilmeAlugado : IDomainEvent
{
    public FilmeAlugado()
    {
        Quando = DateTime.Now;
    }
    public int IdFilme { get; set; }
    public int IdCliente { get; set; }
    public DateTime Quando { get; set; }
}

Estas classes são objetos de valor, são representadas pelos seus atributos, e não tem nenhum id. Poderiam ser structs numa boa.

Para lançar um evento, você utiliza uma classe estática que representa um ponto comum de lançamento de eventos:

public static class DomainEvents
{
    public static void Raise<T>(T evento) where T : IDomainEvent
    {
        var registry = ConfiguracaoRegistry.RegistryConfigurado;
        var enderecadoresDeEvento = registry.ResolverTodas<IEnderecadorDeEvento<T>>();

        foreach (var enderecadorDeEvento in enderecadoresDeEvento)
        {
            enderecadorDeEvento.EnderecarEvento(evento);
        }
    }
}

Essa classe chama os endereçadores de eventos interessados no evento lançado, e chama-os, um a um. Cada um faz o que precisar, de acordo com as necessidades da aplicação.

Notem que esta classe está puxando os endereçadores de eventos de um registry, que no meu caso utiliza um contêiner de DI – geralmente o Unity, para obter todos os endereçadores de eventos. Meu contêiner geralmente observa alguns assemblies, puxa todas as classes, descobre suas interfaces, e as registra automaticamente. Assim, basta criar uma classe que representa um endereçador de evento que tudo já funciona automaticamente, ligado automaticamente quando a aplicação inicia.

Tenho uma interface ou classe abstrata que representa um endereçador de eventos. Algo assim:

public interface IEnderecadorDeEvento<T> where T : IDomainEvent 
{
    void EnderecarEvento(T args);
}

Basta implementar então os endereçadores. Vamos supor que eu queira mandar um e-mail sempre que um filme é alugado, e também gravar essa locação no banco de dados. Basta implementar dois endereçadores:

public class GravaNoBancoQuandoUmFilmeEhAlugado : IEnderecadorDeEvento<FilmeAlugado>
{
    public void EnderecarEvento(FilmeAlugado filmeAlugado)
    {
        Console.WriteLine(
            "Aluguel gravado no banco para o filme id {0} e cliente id {1}!", 
            filmeAlugado.IdFilme, 
            filmeAlugado.IdCliente);
    }
}

public class MandaUmaMensagemParaOClienteAgradecendoAPreferencia : IEnderecadorDeEvento<FilmeAlugado>
{
    public void EnderecarEvento(FilmeAlugado filmeAlugado)
    {
        Console.WriteLine("Email enviado!");
    }
}

Eles vão ser pegos automaticamente no registro do contêiner de DI, e ao chamar o código da classe DomainEvents, eles vão ser executados. Eles poderiam ter dependências complexas, que seriam automaticamente resolvidas pelo Unity, tudo com inversão de controle, claro, pra facilitar um possível polimorfismo, principalmente na hora de testar.

Para usar você cria um evento, e manda ele pro ponto de contato comum, a classe DomainEvents. Aqui está um exemplo simples:

class Program
{
    static void Main(string[] args)
    {

        //setup app
        ConfiguracaoRegistry.RegistryConfigurado = new Registry();

        //preparando o evento
        const int idCliente = 1;
        const int idFilme = 1;
        var alugaramUmFilme = new FilmeAlugado
                                  {
                                      IdCliente = idCliente,
                                      IdFilme = idFilme,
                                      Quando = DateTime.Now
                                  };
        //lançando o evento
        DomainEvents.Raise(alugaramUmFilme);

        Console.ReadLine();
    }
}

O resultado é simples:

Pra testar isso tudo seria extremamente simples. A classe Domain Events não dá para mockar, já que é estática, mas como ela depende do meu IRegistry, tudo fica simples. Além disso, meu maior ponto de manutenção seriam os eventos e seus endereçadores, muito fáceis de testar, por serem simples, objetivos e pequenos. Nada como atender ao princípio da responsabilidade única, não é? Esse tipo de arquitetura é simples de testar e evoluir também por privilegiar o desacoplamento.

Uma aplicação muito comum para esse tipo de modelo é o log. Se você precisar incluir log em todas as operações da sua aplicação é só criar um endereçador de log para cada evento, dá pra fazer de maneira muito simples, com reflexão e um pouquinho de magia negra.

Outro que usa muito esse tipo de modelo é o Greg Young, MVP canadense. Ele grava diretamente os eventos no banco de dados, em um banco de dados de documentos, e condensa os dados de tempo em tempo para o contexto de leitura. Radical, mas muito interessante para cenários com muitas escritas, e alta necessidade de performance, onde você pode ter os dados eventualmente consistentes.

E é isso. Simples assim. É óbvio que no mundo real questões como eventos que devem ser tratados transacionalmente, processamento assíncrono dos eventos, entre outros, seriam tratadas. O maior ponto de alteração seria a classe DomainEvents, sendo que as outras teriam pequenas mudanças. Em dois clientes os eventos foram serializados com WCF e eram criados no Silverlight, em outra camada física. Funcionou perfeitamente.

Além disso, essa estrutura pode ser usada também para outros tipos de eventos, que não sejam de domínio, obviamente separada da estrutura de eventos de domínio.

Espero que gostem da idéia. Não é pra ser usada em todo lugar, mas sem dúvida é muito útil tê-la na caixa de ferramentas.


Postado na(s) categoria(s) Arquitetura pelo Giovanni Bassi em 30 de novembro de 2009 às 00:57 | Tags: , , ,

O desenvolver RAD?Ferramentas RAD, ou Rapid Application Development (desenvolvimento rápido de aplicação), é o termo usado para definir ferramentas que estimulam o design visual da interface gráfica, e alta reutilização de componentes, de forma a produzir uma aplicação no menor tempo possível. Lembro, por exemplo, que quando estávamos no tempo do Visual Basic clássico, muitos diziam que o VB era RAD, e o C++ não era (mesmo possuindo também sua suite de componentes visuais – mas que nem de longe chegavam à simplicidade e produtividade do VB). Na época era comum fazer a regra de negócio em C++ e só a apresentação em VB. As empresas mantinham equipes distintas pra isso.

Os componentes visuais RAD costumam ser data driven, ou seja, o foco é exibição e manipulação de dados, e até mesmo ligados aos registros de banco de dados. Alguns componentes tinham ainda uma forte ligação com o banco de dados.

Aí fico pensando… Rapid Application Development. Rapid. Veloz. Penso em veloz e logo penso ágil. E quando penso ágil, não penso em controles data driven, no estilo drag and drop, que ligam a tela ao banco de dados, para fazer aplicações. Não penso em “forms over data”.

Tanto que, ao pesquizar o que era RAD para colocar aqui, encontrei uma definição da Wikipedia coloca RAD com os pés no desenvolvimento ágil. Fala que RAD é iterativo, coloca que XP e Scrum são formas de RAD.

É assim que entendo RAD: desenvolvimento rápido só pode ser feito quando você trabalha direito, com boas práticas, com uma boa arquitetura. Nas minhas palestras sobre boas práticas (como a última) falo que sempre que o desenvolvedor ignora alguma boa prática de desenvolvimento, e fica só arrastando e soltando coisas na tela, ele se vê como o The Flash, que coloquei aqui no começo do post, quando na verdade, quanto mais ele trabalha “RAD”, mais ele se parece mais com isso:

O desenvolver RAD!

Quanto mais rápido você tenta ir, ignorando as boas práticas de desenvolvimento, mais débito técnico você adquire, e mais devagar você vai. Em pouco tempo a produtividade do projeto cai, e você está preso no código legado que você mesmo escreveu, um mês atrás.

Isso porque uma aplicação feita com “forms over data”, com componentes ligados ao banco de dados, é acoplada demais, difícil de testar, possui regras de negócios duplicadas em vários lugares, e código macarrônico, impossível de entender (entre outros inúmeros problemas).

Portanto, rápido mesmo é fazer direito, limpo, com boas práticas, com arquitetura adequada. Ferramentas RAD são muito úteis sim, desde que você saiba usá-las. Desenvolver telas com código dá muito mais trabalho, e você precisa dominar a tecnologia que está trabalhando (daí tanta crítica ao ASP.Net MVC) e por isso não sou contra designers visuais, sou contra aplicações feitas somente com eles, ou abusando deles. Não faça data binding com seu banco de dados, faça com seus objetos de domínio. Use OO, DDD, TDD. Use padrões de arquitetura da interface gráfica, como os citados pelo Fowler aqui (e aqui, do lado direito tem os presentation patterns). Vai lá ler, é grátis, e a leitura é obrigatória.

Com frequência os clientes me chamam para ajudar a definir o backend das aplicações, definimos o método de acesso a dados, aplicamos DDD, usamos WCF, fica tudo lindo, escalável, fácil de entender, etc. Quando vamos entrar na interface gráfica, o cliente diz que já sabe fazer, ele usa ferramentas RAD. Faz sem boas práticas, e o resultado é uma aplicação limpa, mas só de uma camada pra frente. Aí acabo tendo que voltar pra explicar onde está errado, e o cliente acaba tendo que refazer um pedaço da aplicação.

Pense nisso.


Postado na(s) categoria(s) Arquitetura pelo Giovanni Bassi em 10 de novembro de 2009 às 08:46 | Tags:

image Amanhã vou palestrar sobre o caminho do desenvolvedor amador para o profissional, no Microsoft Techday, evento organizado pelas comunidades MCPBrasil, Canal SystemCenter, Codificando e Winsec.

Vai ser a única palestra que não será 100% foca em uma tecnologia, vou falar muito sobre arquitetura, processo, design de software, padrões, e, principalmente, atitude. Na verdade, vou passar a noite puxando a orelha de todo mundo, e vou começar com a conhecida “Não sabemos fazer software” e “Tudo que você acha que sabe está errado”. A palestra vai ter um tom parecido com o keynote que fiz na 2ª semana de tecnologia da Univem, onde falei sobre práticas de um engenheiro de software eficiente. O foco da palestra de amanhã é falar o que um desenvolvedor deveria estar fazendo para se tornar um desenvolvedor profissional, e sair do amadorismo.

Minha palestra começa as 21, ao contrário do que está escrito no site. Troquei o horário com o Andrey, que vai falar antes de mim sobre ASP.Net. Ainda dá tempo de se inscrever, e as palestras são gratuitas. O evento começou ontem e vai até sexta.

Depois posto aqui os links da palestra e o ppt no Slideshare, como sempre.

Vejo vocês lá.


Postado na(s) categoria(s) Eventos pelo Giovanni Bassi em 4 de novembro de 2009 às 12:20 | Tags: ,

Nesta terça abri 2ª semana de tecnologia da informação da Univem em Marília, com uma palestra sobre práticas de um engenheiro de software eficiente. Falei sobre o status atual da industria de software, dos problemas que enfrentamos, do mercado de trabalho, e apresentei algumas soluções para estes problemas. Falei muito de desenvolvimento iterativo, de tdd, pareamento, práticas ágeis, práticas que todo desenvolvedor deveria realizar, entre outros assuntos. Chamei-os à comunidade de desenvolvimento, à interagirem nas diversas comunidades que temos (incluindo, claro, o .Net Architects), à participarem dos eventos (mostrei e falei bastante do TechEd deste ano). Vierei a cabeça de muitos de ponta cabeça, mas eles gostaram, e deram um feedback positivo tanto no evento quanto depois via twitter.

Foi uma palestra muito boa, fui bem recebido por todos, o auditório estava cheio, e até encontrei uns membros do .Net Architects por lá.

Agradeço o convite do Elvis Fusco para o evento.

Abaixo estão os slides da palestra.

Logo depois eu fui pro Rails Summit 2009, mas depois eu conto essa em outro post.


Postado na(s) categoria(s) Eventos pelo Giovanni Bassi em 15 de outubro de 2009 às 15:05 | Tags: , , , ,

O princípio aberto fechado, em inglês Open Closed Principle, ou somente OCP, é um dos princípios mais interessantes da OOP. Ele diz que:

“Entidades de software (classes, módulos, funções, etc) devem ser abertas para extensão mas fechadas para modificações” – Bertrand Meyer (1988)

Parece meio contraditório… Mas na prática isso significa que você deve ser capaz de estender uma classe sem modificá-la. Isso acontece com herança, quando você utiliza uma class abstrata, ou até uma não abstrata mas com métodos virtuais. Você estendende a classe base, sem modificá-la, mas completando seu comportamento.

O OCP é sugerido porque, uma vez concluída uma classe, ela é uma unidade funcional que, se alterada, fica sob risco de efeitos colaterais não esperados na aplicação (bugs). Você pode resolver boa parte do problema com testes, mas ainda assim está introduzindo um risco. Nada é mais sólido do que código testado em ambiente de desenvolvimento e produção.

Para aplicar o padrão, tudo começa com a identificação do que não deve mudar e do que pode mudar. As partes que podem mudar você deixa abstratas ou virtuais, ou separa com, por exemplo, uma associação, via padrão Strategy.

Por exemplo, suponha que, em um blog, eu tenha uma ação de postar um comentário. E quero que alguém seja notificado quando um comentário acontecer. No meu controller teria um método assim:

public ActionResult PostarComentario(int id, FormCollection collection)
{
    //algum código
    new NotificadorSMTP().AvisarDoComentario(comentario);
    //mais algum código
}

Só que, se eu quiser mudar o NotificadorSMTP por um NotificadorExchange, vou ter que alterar a classe de controller. Isso não é bom, porque, primeiro, em nada tem a ver com o controller, que é responsável pelo fluxo da interface gráfica, e segundo, o controller já está funcionando e testado. Se eu identifiquei que isso é uma mudança possível, não posso trabalhar com o notificador desta forma. Uma opção seria trabalhar com um Strategy com injeção de dependência e inversão de controle. Ficaria assim:

public class PostsController
{
    private Notificador _notificador;
    public PostsController(Notificador notificador)
    {
        _notificador = notificador;
    }
    public ActionResult PostarComentario(int id, FormCollection collection)
    {
        //algum código
        _notificador.AvisarDoComentario(comentario);
        //mais algum código
    }
}

Agora já posso trabalhar com o controlador sem depender do NotificadorSMTP, ou do NotificadorExchange. A classe apropriada, derivada da classe “Notificador” será passada.

Uma opção mais elegante seria trabalhar com Domain Events. Na hora de adicionar um comentário ao post este levantaria um evento de domínio:

public class Post : Entidade
{
    //outros métodos, campos, propriedades, etc...
    public virtual void AdicionarComentario(string corpo, Comentarista comentarista)
    {
        var comentario = new Comentario(this, corpo, comentarista);
        DomainEvents.Raise(new ComentarioAdicionado(this, comentario));
        //outras ações...
    }
}

E eu teria então uma classe que assinaria o evento de domínio:

public class NotificadorPorEmailEmCasoDeComentarios : IEnderecadorDeEvento<ComentarioAdicionado>
{
    public void EnderecarEvento(ComentarioAdicionado args)
    {
        var textoNotificacao = ...;//formatação
        _notificadorEmail.Notificar(args.Post.Autor.Email, textoNotificacao);
    }
    //outros métodos, etc...
}

É uma opção bastante interessante, onde eu removo a responsabilidade de notificação do controller, já que ela não deveria estar lá desde o começo. Outro dia eu falo mais de eventos de domínios. É um tema que está na minha pauta faz tempo.

Pra completar, sugiro vocês darem uma olhada no artigo do Uncle Bob sobre o assunto, listado na página que deu origem também ao nome SOLID. O livro que deu origem ao termo, Object-Oriented Software Construction, do Bertrand Meyer, também vale a pena dar uma olhada.


Postado na(s) categoria(s) Arquitetura pelo Giovanni Bassi em 30 de setembro de 2009 às 08:41 | Tags: , , ,

entlib_accelerator Amanhã, terça-feira, 29/09, ao meio-dia, farei um webcast sobre DI (dependency injection ou injeção de dependência) com Unity, do Enterprise Library.

Vejo vocês lá.


Postado na(s) categoria(s) Eventos , Arquitetura pelo Giovanni Bassi em 28 de setembro de 2009 às 04:25 | Tags: ,

Tratamento de erros é algo que não é visto com o suficiente cuidado pela maioria dos desenvolvedores de software. Com frequência, quando estou dando consultorias, encontro software sem tratamento de erro, com um tratamento de erro inútil ou ruim. Infelizmente a maioria dos desenvolvedores assume que o software deve funcionar e acabou. Acham-se os melhores desenvolvedores do planeta, já que não criam bugs, e esquecem que há problemas que acontecem mesmo com um software sem bugs. A memória acaba, a conexão com o banco de dados ou com um serviço cai, uma permissão é negada, o ambiente de instalação não é suportado, o navegador onde roda a aplicação não suporta a versão de Javascript que você está usando, e por aí vai. Outros não sabem como fazer o tratamento de erro, só sabem que devem tratar erro de alguma forma, e fazem tratamentos de erros inúteis, que mais atrapalham do que ajudam.

Vamos começar primeiro entendendo o que é um erro. O .Net já usa um nome para definir erros que não deixa margens à duplicidade: Exception, ou “exceção” no português. Exceção, segundo o dicionário Aulete Digital é:

  1. Não correspondência a uma regra.
  2. O que não confirma uma regra ou generalização.

Ou seja, exceções são coisas que acontecem e que não fazem parte de uma regra. A palavra regra ajuda bem a entender o significado. Não é uma regra que seu código tenha bugs (eu espero), assim como não é uma regra que a conexão do banco de dados caia, e não é uma regra que o IIS seja reiniciado enquanto a aplicação está rodando. Todos esses casos são exceções. Quando essas exceções acontecem nosso código precisa saber lidar com elas.

Agora que já está claro o que é um erro, temos que entender quando lançar uma exceção. Devemos ter claro o seguinte: se algo que aconteceu no software não for uma exceção, mas uma regra, como uma regra de negócios, por exemplo, isso não deve ser tratado como um erro, com uma Exception sendo lançada. Assim, por exemplo, quando o usuário digitar um CPF inválido, em vez de lançar uma CPFInvalidoException, você devolve algum objeto que informe que o CPF é inválido. Afinal, digitar um CPF inválido é uma regra de negócio que deve ser tratada, não é um bug ou condição excepcional.

 

Exceções no .Net são objetos perigosos, eles podem derrubar a aplicação se não forem tratados, e além disso têm um custo altíssimo de performance. Sempre que for lançar uma exceção avalie se está fazendo isso para deixar claro que há um bug ou condição inesperada.

Há uma regra muito clara para saber se você deve lançar uma exceção ou não: lance erros quando seu método não conseguir fazer o que tem que fazer. Se seu método deve abrir uma conexão e não conseguir, lance um erro. Se o seu método deve dar um desconto a um cliente, e o cliente não existir e portanto o desconto não puder ser dado, lance um erro. Mas não lance um erro se estiver buscando um cliente e ele não existir, afinal em buscas o objeto buscado pode realmente não ser encontrado, e isso é legal.

E como tratar as exceções de verdade? Certamente não é assim:

static void Main(string[] args)
{
    try
    {
        var minhaClasse = new MinhaClasse();
        minhaClasse.FazAlgo();
    }
    catch (Exception)
    {
        throw;
    }
}

Esse código tem diversos problemas:

  1. Todo o código do método Main está envolto em um blog de Try Catch Finally (TCF). Será que instanciar a classe “MinhaClasse” pode gerar um erro? Talvez não, e então essa linha tinha que estar fora do TCF. Já vi empresas onde todos os métodos estão envoltos em TCF, como se tudo pudesse causar erro. Isso causa uma tremenda confusão no código, além de uma queda na performance. Problema: preguiça de checar onde podem acontecer exceções.
  2. No catch a exceção sendo tratada é a System.Exception. Isso significa que qualquer exceção que aconteça vai ser tratada. Mas será que a classe “MinhaClasse”, que está dentro do try, não gera uma exceção mais específica? Se sim, então esta exceção deveria ser tratada. Problema: preguiça de checar quais exceções são lançadas pelo método FazAlgo, ou talvez o método seja tão complicado, tenha tantas dependências, e não tenha tratamento de erros, que isso não seja claro.
  3. Se realmente for o caso de tratar qualquer exceção, então um simples “catch {}” resolveria, não precisava de um “catch (Exception) {}”.
  4. A exceção não é efetivamente tratada, já que o código simplesmente lança a exceção de volta no throw.

Mas dá para ficar pior. Esse código é pior:

static void Main(string[] args)
{
    try
    {
        var minhaClasse = new MinhaClasse();
        minhaClasse.FazAlgo();
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

Esse código é pior porque ele esconde a exceção. Vejam minha janela de edição Visual Studio:

O erro acontece na linha 15, ao chamar FazAlgo. Se eu rodar o primeiro código, da primeira listagem, tenho o seguinte Stack Trace:

at ConsoleApplication1.MinhaClasse.FazAlgo() in F:\ConsoleApplication1\Program.cs:line 50
at ConsoleApplication1.Program.Main(String[] args) in F:\ConsoleApplication1\Program.cs:line 21
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

Rodando da segunda maneira, o Stack Trace é esse:

at ConsoleApplication1.Program.Main(String[] args) in F:\ConsoleApplication1\Program.cs:line 21
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

Deixei em destaque a diferença. Note que na segunda maneira de trabalhar, fazendo “throw ex”, o erro, que aconteceu na minha linha 50, no método “FazAlgo” da classe “MinhaClasse”, é escondido. Temos somente o erro na linha 21, que é a linha de saída do método Main. Ou seja, em vez de ajudar, atrapalhamos, porque sem tratamento nenhum de erro o resultado seria parecido com o primeiro caso, teríamos claro onde o erro realmente ocorreu: no método “FazAlgo”.

Vamos arrumar então? Arrumando todos os problemas o código fica assim:

static void Main(string[] args)
{
    var minhaClasse = new MinhaClasse();
    try
    {
        minhaClasse.FazAlgo();
    }
    catch (MinhaException ex)
    {
        Console.WriteLine("A MinhaException aconteceu./nDetalhes:{0}/nTentar de novo?", ex.Message);
        if (Console.ReadLine() == "s")
            Main(args);
    }
}

Agora realmente temos a exceção sendo tratada. Se acontecer uma System.Exception a aplicação cai, mas talvez seja exatamente o que eu espero que aconteça. Uma System.Exception significa que aconteceu uma exceção, algo não esperado, e a aplicação pode conter um estado inválido, e não deve mais continuar. Talvez cair seja a opção correta. De qualquer forma, isso deve ser analisado, e não simplesmente tratar System.Exception sempre.

Há mais uma coisa faltando: log dos erros. Uma aplicação profissional que se presa loga suas exceções. Aplicação sem log de erros não é uma aplicação profissional, é amadora. Não fazer um log de erros é falta de profissionalismo. Quando a aplicação falhar em produção, como você vai saber se não tiver um log? Vai pedir um dump e analisar no WinDBG, aquela ferramenta super fácil de usar? Facilite sua vida, logue seus erros.

Mais uma dica: é uma boa prática tratar as exceções no mínimo nas fronteiras da aplicação. Isso significa tratar na interface gráfica, tratar nas camadas de serviço, e em qualquer outra onde exista uma fronteira entre sua aplicação e outra. Se você não fizer isso, vai ter desagradáveis surpresas. Aplicação caindo toda hora, yellow screen of death no ASP.Net, e por aí vai. Com Silverlight, se você devolve um erro da camada de serviço WCF para a camada Silverlight vai receber um belo erro “Not Found” de volta no Silverlight, independentemente do erro. Tudo o que você precisa para uma boa depuração, não é?

A politica de tratamento de erros é algo que deve ser definido logo no começo do desenvolvimento de uma aplicação. Definir onde os erros serão tratados, como serão tratados, onde serão logados, que exceções serão definidas, entre outros assuntos devem ser avaliados o quanto antes, preparando uma estrutura mínima de tratamento de erros. Uma boa opção é usar o Enterprise Library, que já possui o Exception Handling Application Block para ajudar na tarefa. Este bloco de aplicação já me poupou centenas (talvez milhares) de linhas de código (baixe a versão 4.1 da EntLib aqui), sem falar na dor de cabeça. Se você não conhece este bloco sugiro avaliá-lo o quanto antes. Mais ou menos… assim que terminar de ler este post.

Resumindo:

  • Se você não vai tratar a exceção, ou seja, fazer alguma coisa com ela, não coloque TCF no método.
  • Use um framework para te ajudar, como o EntLib.
  • Trate erros nas camadas de fronteira.
  • Logue seus erros.
  • Nunca, nunca, nunca faça “throw ex”.

Boa caçada às exceptions!


Postado na(s) categoria(s) Arquitetura pelo Giovanni Bassi em 14 de setembro de 2009 às 08:35 | Tags:

“We want to make these really elaborate architectures, because we believe that we are solving world hunger when we do so. We are going to build structures that will solve every software problem forever. These tend to go on, and on, and on forever. They are hard to work with, they actually impede the flow of most development. Avoid making the grand architecture in the sky. Anybody here have an enterprise architecture, nailed down by some people that don’t code? This is probably an error in judgment. Not that you don’t want to make enterprise wide decisions but you don’t want to have some massive enterprise architecture created by people who do not have the responsibility to deliver. The people that have the responsibility to deliver are the ones that should be deciding what their architectures ought to be.”

Traduzido:

“Nós queremos fazer essas arquiteturas realmente elaboradas, porque acreditamos que estamos resolvendo a fome mundial quando o fazemos. Nós iremos constuir grandes estruturas que vão resolver os problemas de software para sempre. Estas tendem a sobreviver para sempre. Elas são difíceis de trabalhar, e na verdade impedem o fluxo da maioria dos desenvolvimentos. Evite criar uma grande arquitetura nos céus. Alguém aqui tem uma arquitetura corporativa, criada por algumas pessoas que não codificam? Este é provavelmente um erro de julgamento. Não que você não queira fazer decisões corporativas, mas você não quer ter uma arquitetura corporativa massiva criada por pessoas que não tem responsabilidade sobre a entrega. As pessoas que tem a responsabilidade da entrega são as que deviam estar decidindo como suas arquiteturas devem ser.”

O vídeo da conferência pode ser baixado aqui, junto a inúmeras palestras, em um total de 30 GB de videos. Você pode baixar só o que quiser.

Eu já havia falado o que o uncle Bob está dizendo em outro post. Para não ficar reescrevendo, vejam o que eu disse:

“E onde ficam os frameworks corporativos, os padrões, a reusabilidade no nível da corporação? Muitas empresas fazem esse tipo de framework para ganhar tempo, diminuir a quantidade de código que escrevem, e agora? Este tipo de framework deve surgir quando necessário, e deve ter uma amplitude muito limitada. Acredito que é possível ter um framework corporativo, desde que ele emerja das necessidades reais dos projetos, ou seja, sejam abstraídos a partir de algo real que precisou ser implementado, e que pode ser reutilizado. (…) Estes podem emergir quando necessários, e devem ser feitos seguindo boas práticas, como o open closed principle, para que não se tornem um peso no processo de desenvolvimento, mas sejam uma solução real.”

Então, como criar frameworks corporativos? Ao lado dos desenvolvedores, com o olho pras necessidades reais de desenvolvimento.


Postado na(s) categoria(s) Arquitetura pelo Giovanni Bassi em 3 de setembro de 2009 às 04:07 | Tags:

Na minha palestra do TechEd falei bastante de arquitetura, e citei que há um teste para o qual não conseguimos escrever testes unitários. Você adivinha qual?

O teste do tempo.

Não há testes unitários para testar quanto tempo uma aplicação vai sobreviver. Uma das principais responsabilidades de um arquiteto de software é fazer com que a aplicação sobreviva o tempo esperado. E ele tem que fazer isso com as restrições impostas pelos outros requerimentos, como os requerimentos de negócio, e também os técnicos, como escalabilidade, extensibilidade, confiabilidade, e por aí vai. Não é tarefa fácil.

Sobreviver ao teste do tempo significa fazer uma aplicação que é útil ao longo de todo o seu tempo de vida, e que paga seu investimento ao longo de todo seu ciclo de vida, ou seja, que dá ROI. De nada adianta fazer uma aplicação que atende todos os requisitos de negócio, se ela custa mais do que o usuário quer pagar (ou usuários). Temos que conseguir nos equilibrar nesta relação de custo benefício. A palavra chave para isso é produtividade. Temos que ter produtividade durante todo o ciclo de vida da aplicação. Como conseguir isso?

Vamos analizar o que acontece no modelo mais difundido no mercado: o famoso "sair fazendo". Nesse modelo a equipe "sai fazendo" o código, sem se preocupar com boas práticas de desenvolvimento ou arquitetura.

Lembro bem daquelas demos no começo do ASP.Net, em que o palestrante arrastava uma tabela do Server Explorer para a página ASPX, e aparecia o datagrid, com os objetos de acesso a dados, todos já funcionando, paginando o grid, etc. Todo mundo ficava embasbacado, e o palestrante, propositalmente ou não, não contava que aquilo era demoware, ou seja, não era para ser usado em uma aplicação de verdade (e séria, e profissional). E muita gente usou. Qual o resultado? Uma altíssima produtividade, não é verdade? Claro que é, desde que você olhe para o curto prazo. No Teched usei um gráfico para representar essa atitude de trabalhar de qualquer jeito, sem boas práticas. Vamos olhar ele, só que só o seu começo:

Sem boas práticas, só o começo

Ele está cruzando produtividade com tempo. Temos então uma produtividade de 15, logo de início.

Esse é o gráfico com boas práticas:

Com boas práticas, só o começo

Temos uma produtividade de seis, ou seja, menos da metade da produtividade do gráfico anterior, que trabalha sem boas práticas.

Observação: antes que você me pergunte "Seis o quê?", respondo: seis qualquer coisa. Imagine que este número está na sua métrica, ou seja, se você trabalha com pontos de caso de uso, então são 6 dias para um UCP (ou horas, ou sei lá), se você trabalha com análise de ponto de função, então são 6 dias para um ponto de função (ou meses, sei lá), se você trabalha com user stories, então são 6 horas por story point (ou dias, sei lá). Imagine que o número é uma medidade de entrega versus tempo, ok? Na prática não estou exibindo produtividade, mas taxa de entrega, mas a maioria das pessoas prefere o nome produtividade.

Os mais atentos já perceberam a essa altura uma pequena diferença nos gráficos. O primeiro está decrescendo, o segundo está estável. Vamos ver o primeiro gráfico completo:

Sem boas práticas

A produtividade cai devagar por algum tempo. No meio do projeto ela cai vertiginosamente para 3, e fica por lá. E três é menos do que seis, certo? Quem nunca viveu isso? O projeto começa, tudo anda rápido, os prazos do nosso belo cronograma waterfall no MS Project são todos batidos, a previsão de entrega do projeto é até antecipada. Até chegarmos a uns 30% ou 40% do projeto, e tudo se enrola. O gerente do projeto volta o prazo original, de repente o prazo orignal é ultrapassado um pouco, e em pouco tempo o projeto está atrasado vários meses. Acontece o tempo todo, acontece em todo lugar.

Agora vejam o gráfico com boas práticas, completo:

Com boas práticas

Ele se mantém estável ao longo de todo o projeto. Qual a minha entrega? É a área debaixo do gráfico. Basta somar os valores para entender a entrega com uma abordagem e com a outra. 
No primeiro temos:  15+14.5+13.5+12.5+3+3+3+3+3 = 70.5
No segundo temos: 6*9 = 54

A primeira vista, temos uma produtividade maior no primeiro caso. Essa primeira vista é responsável por essa ilusão de que sair fazendo é uma boa idéia, e de que não temos tempo para sermos profissionais e trabalhar como engenheiros de verdade.

Vamos continuar nossos cálculos. Suponhamos que estas sejam semanas de desenvolvimento, e que o projeto se prolongue por 6 meses (24 semanas). Qual o resultado?
No primeiro temos: 15+14.5+13.5+12.5+3*20=115.5
No segundo temos: 24*6=144

A entrega nesse caso é 25% maior. Se o projeto se estender por um ano esse percentual dobra. O que isso significa?

Significa que temos um processo que entrega mais valor que o outro. Após os primeiros quatro períodos, entrega o dobro do valor. Por quanto tempo você quer valor? Por um pequeno e ilusório começo, ou por todo o tempo?

Esses números são apenas exemplos. Os números reais você vai ter que medir na sua equipe. Quando for fazer isso, além de somar o tempo do desenvolvedor fazendo o sistema, some também o tempo gasto em resolução de bugs que ninguém consegue resolver, problemas encontrados em produção, horas das equipes de DBAs, servidores, conectividade, segurança, horas de gestão, e por aí vai. Isso sem nem falar do stress. É possível você encontrar números ainda mais expressívos do que os que estou propondo por aqui. Mediu isso? Volta aqui e me conta, quero saber.

É claro que não é fácil para uma equipe realizar uma taxa de entrega estável. A equipe precisa estar entrosada, precisa ser um time de verdade, comprometido com a entrega final. Precisa ser uma equipe com bons conhecimentos de arquitetura e engenharia, e precisa ser suportada pela gestão da empresa. Poderia dizer que um deles é programar iterações curtas, mas não vou entrar nisso agora. Há muitos requisitos para alcançar essa linha estável, e posso garantir uma coisa: nenhum deles passa por "sair fazendo".

Da próxima vez que pensar em sair fazendo, lembre-se disso. Você está criando o que chamamos de débito técnico. Você está tomando emprestada um produtividade que você vai ter que pagar no futuro. E é você quem vai ter que explicar porque aquele designer mágico do Visual Studio parou de entregar, se antes tudo funcionava. Você está desenvolvendo de maneira não sustentável, e não vai passar no teste do tempo.

Pense nisso.


Postado na(s) categoria(s) Arquitetura pelo giovanni bassi em 2 de setembro de 2009 às 03:47 | Tags:

Acabo de responder um questionário de um aluno do Mackenzie sobre design patterns, que será utilizado em seu trabalho de conclusão de curso. Era curto (e isso é pré-requisito, ou eu não responderia), composto de apenas sete perguntas rápidas. Ele entrou em contato com alguns dos artigos que ando publicando sobre o assunto, e pediu meu feedback.

E porque estou contando isso pra vocês? Porque a terceira pergunta era essa:

Em algum projeto, durante a fase de análise, já foi detectado que a melhor solução era a não utilização de Design Patterns?

Fase de análise? Alguém ainda acredita em fase de análise? Parafraseando um twit meu, eu acredito em duendes, mas não acredito em fases de análise.

Minha resposta ao universitário:

Não entendo que exista uma "fase de análise". Isso leva a um modelo de desenvolvimento em cascata, que é prejudicial. E a analise arquitetural, que é feita um pouco antes do código, não deve chegar ao ponto de definição de padrões de codificação, mas sim a padrões arquiteturais. E mesmo essa, deve ser feita de forma incremental.

Não me estendi demais no comentário porque a pergunta já foi feita errada. Não é a primeira vez que entro em contato com conteúdo acadêmico fundamentado em práticas waterfall. As universidades, em sua grande maioria, estão presas à idéia de que construir software é igual a construir carros em uma fábrica, ou a construir uma ponte. Não é.

Temos que parar de "analisar o negócio" e voltar a escrever código. Milhões se gastam em papel, e proporcionalmente muito pouco em código funcionando. O overhead gasto em arquitetura, análise de negócio, análise de sistemas, documentação, gestão de projetos é grande demais. Tudo isso devia acontecer apenas como suporte do produto final funcionando. Temos que fazer análises arquiteturais, de sistemas, de negócio? Claro! Temos que ter uma fase para elas? Não, de forma alguma.

As universidades ensinam pouco aos estudantes, e quando dão para ensinar, ensinam isso: técnicas anacrônicas, despreparadas para a realidade. Os alunos chegam ao mercado de trabalho com a cabeça enviesada a favor de técnicas que não funcionam, e, dependendo da faculdade, ideológicamente estragados (principalmente se forem faculdades públicas).

Posso falar com autoridade sobre o assunto. Tenho aplicado, em paralelo à consultoria de arquitetura, também consultoria em agilidade. É comum o cliente entender a arquitetura, mas ainda ter problemas com processo, e acaba me perguntando como resolver, e aí aparece a consultoria de processo. Os resultados são impressionantes, e sempre muito positivos. E garanto: não existe fase de análise em projeto focado na entrega, ágil, produtivo.

Há muito o que caminhar ainda para que tenhamos uma profissão, para que possamos chamar nossa prática de desenvolvimento de software pelo nome de "profissão". Por enquanto, o que temos são discussões dispersas, práticas sem comprovação, e, sem dúvida alguma, ego demais.


Postado na(s) categoria(s) Gestão de projeto , Arquitetura pelo giovanni bassi em 1 de setembro de 2009 às 15:55 | Tags: , ,

Quem é Giovanni Bassi

Giovanni Bassi Sou uma pessoa apaixonada por tecnologia e especificamente por .Net. Sou consultor independente especialista em .Net, focado em arquitetura e melhores práticas. Tenho dezenas de artigos publicados na .Net Magazine, revista da qual sou editor técnico. Ministro palestras e cursos de vez em quando, e quando dá tempo eu respiro um pouco. Mais detalhes nesta página.

Busca

Selos

Eu vou ao TechEd Brasil 2010, e você?

MVP

MCPD

MCSD

.Net Magazine

Abaixo ao if!

Calendário

«  setembro 2010  »
seteququsedo
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910
Ver detalhamento de posts no calendário

Blogs interessantes

    OPMLDownload OPML file

    Postagens recentes

    Comentários recentes

    Disclaimer / Aviso
    As opiniões colocadas neste blog são minhas e pessoais e não expressam necessariamente as opiniões de meus empregadores, pareceiros e amigos. Da mesma forma, os comentários feitos por leitores do blog não expressam a minha opinião.

    © Copyright 2010 .Net Unplugged
    Log in