sábado, 9 de outubro de 2010

O que é Anti-Pattern?

Este texto é uma tradução da Wikipedia

Em Engenharia de Software, um anti-pattern é um pattern que pode ser utilizado, mas é ineficiente e contraprodutivo na prática.

O termo foi cunhado em 1995 por Andrew Koening, inspirado no livro Design Patterns da Gang of Four, que desenvolveu o conceito de design patterns na área de software.
O termo foi popularizado três anos depois pelo livro AntiPatterns, que estendeu o uso do termo além das fronteiras do design de software para a interação social geral. De acordo com os autores, devem haver pelo menos dois elementos-chaves presentes para distinguir formalmente um anti-pattern de um simples mau hábito, má prática, ou má idéia:

- Alguns patterns repetidos de ação, processo ou estrutura que inicialmente parecem ser benéficos, mas acabam produzindo mais conseqüências ruins que que resultados benéficos;
- Uma solução refatorada é claramente documentada, comprovada na prática e repetível.

Muitas idéias anti-patterns são mais que erros, retórica, problemas sem solução ou práticas ruins que devem ser evitadas. O uso informal do termo, às vezes denominado "armadilhas" (pitfalls) ou "patterns negros" (dark patterns), refere-se a soluções ruins para os problemas. Desta forma, muitos anti-patterns colocados sob debate não seriam formalmente considerados anti-patterns.

Através da descrição formal de erros repetidos, podem-se reconhecer as forças que levam a esta repetição e aprender refatorar este pattern.

Anti-patterns Organizacionais:
- Paralisia na análise: colocar um esforço desproporcional na fase de análise de um projeto.
- Vaca leiteira: Um produto legado rentável que muitas vezes leva à complacência sobre os novos produtos.
- Design por commitê: resultado de muitos contribuintes para o design, mas sem uma visão unificada.
- Escalação de compromisso: falha em revogar uma decisão quando a mesma se revela errada.
- Gestão por perkele (sem tradução): estilo autoritário de gerenciamento, sem tolerância à dissidência.
- Gestão matricial: estrutura organizacional sem foco, que resulta em subordinação dividida e falta de direção.
- Risco moral: isentar um tomador de decisão das conseqüências de sua decisão.
- Gestão Cogumelo: manter funcionários sem informação ou mal informados.
- Stovepipe ou Silos (sem tradução): uma estrutura que suporta principalmente o fluxo vertical (de cima para baixo) de informação, mas inibe a comunicação organizacional.
- Vendedor bloqueado: tornar um sistema excessivamente dependente de um componente externo.

Anti-patterns de Gerenciamento de Projetos:
- Marcha para a morte: todos sabem que o projeto caminha para um desastre, exceto o presidente da empresa. Porém, a verdade permanece ocultada e a sobrevida do projeto é mantida artificialmente até que o "Dia D" chega. Definição alternativa de marcha para a morte: funcionários sofrem pressões para trabalharem dias, noites e fins de semana em um projeto com prazo irracional.
- Groupthink (pensamento em grupo): durante o groupthink, membros do grupo evitam mencionar pontos de vista que estejam fora da zona de conforto do pensamento consensual.
- Fumaça e espelhos: demonstrar como funções não implementadas irão surgir.
Software bloat (inchaço do software): permitir versões sucessivas de um sistema a fim de demandar cada vez mais recursos.

Anti-patterns de análise:
- Apatia do espectador: quando um requisito ou uma decisão de design está incorreta, mas as pessoas que notaram o problema não fazem nada a respeito, porque isto afeta um número maior de pessoas.

Anti-patterns do design de Software:
- Inversão da Abstração: não expor a funcionalidade implementada requisitada pelos usuários, para que eles a re-implementem usando funções de mais alto nível.
- Ponto de vista ambíguo: apresentar um modelo (normalmente análise e design orientados a objeto) sem especificar seu ponto de vista.
- Grande bola de lama: um sistema sem nenhuma estrutura reconhecida.
- Database-as-IPC: usar um banco de dados como message queue para comunicação de interprocessamento de rotina onde um mecanismo muito mais simples seria apropriado.
- Chapeamento a ouro: continuar a trabalhar em uma tarefa ou projeto bem além do ponto em que o esforço extra agrega valor.
- Efeito na plataforma interna: um sistema é tão customizável que se torna uma réplica pobre da plataforma de desenvolvimento de software.
- Input kludge (sem tradução): falha em especificar e implementar o tratamento de uma entrada possivelmente inválida.
- Interface bloat (inchaço da interface): construir uma interface tão poderosa que se torna extremamente difícil de implementá-la.
- Magic pushbutton (botão mágico): codificar a lógica de implementação diretamente no código da interface, sem usar abstração.
- Race hazard (perigo de corrida): falha na verificação da conseqüência de diferentes ordens de eventos.
- Stovepipe system: componentes mal-relacionados e difíceis de manter.

Anti-patterns do design orientado a objeto:
- Anemic Domain Model: uso do modelo de domínio sem qualquer lógica de negócio. Os objetos do modelo de domínio não podem garantir sua correção, porque sua lógica de validação e mutação está armazenada externamente (muito provavelmente em múltiplos locais).
- BaseBean (sem tradução): herdar a funcionalidade de uma classe utilitária em vez de delegar a ela.
- Call super (sem tradução): requisitar às subclasses a chamarem um método overriden de uma superclasse.
- Problema círculo-elipse: subtipar tipos-variável com base dos subtipos de valor.
- Dependência circular: introduzir dependências mútuas diretas ou indiretas entre objetos ou módulos do software.
- Constant interface (sem tradução): usar interfaces para definir constantes.
- God object (Objeto Deus): concentrar muitas funções em uma única parte do design (classe).
- Object cesspool (fossa de objetos): reutilizar objetos cujo estado não está em conformidade com o contrato (possivelmente implícito) para reúso.
- Orgia de objetos: falha para encapsular propriamente os objetos, permitindo acesso irrestrito ao seu interior.
- Poltergeists: objetos cujo único propósito é passar informação para outro objeto.
- Acoplamento seqüencial: uma classe que exige que seus métodos sejam chamados em uma ordem particular.
- Problema Iô-Iô: uma estrutura (por exemplo, de herança) que é difícil de entender devido à sua fragmentação excessiva.

Anti-patterns de programação:
- Complexidade acidental: introduzir uma complexidade desnecessária a uma solução.
- Ação a distância: interação inesperada entre partes amplamente separadas de um sistema.
- Fé cega: falta de verificação da correção realizada em um bug, ou do resultado de uma subrotina.
- Âncora de barco: manter uma parte do sistema que não possui mais qualquer uso.
- Busy spin (sem tradução): consumir CPU enquanto aguarda algo ocorrer, normalmente pela verificação repetida em vez de mensagem.
- Caching failure (sem tradução): esquecer de resetar uma flag de erro quando o mesmo foi corrigido.
- Cargo cult programming (sem tradução): usar patterns e métodos sem entender por quê.
- Codificar por exceção: adicionar novo código para tratar cada caso especial reconhecido.
- Esconder o erro: fazer um catch da mensagem de erro antes que a mesma seja mostrada ao usuário e não mostrar nada ou uma mensagem sem significado algum.
- Hard code: incorporar pressupostos do ambiente de um sistema em sua implementação.
- Fluxo de lava: manter código indesejável (redundante ou de baixa qualidade) porque removê-lo é muito caro ou trará conseqüências imprevisíveis.
- Seqüência Loop-switch: codificar um conjunto de etapas seqüenciais usando switch dentro de um loop.
- Números mágicos: incluir números inexplicáveis em algorítmos.
- Strings mágicos: incluir strings literais no código, para comparações, como tipos de eventos etc.
- Soft code (código leve): não armazenar a lógica de negócio no código fonte, mas em arquivos de configuração.
- Código macarrônico: programas cuja estrutura é difícil de compreender, especialmente por causa da mistura de estruturas de código.

Anti-patterns metodológicos:
- Copiar e colar um programa: copiar e modificar um código existente em vez de criar soluções genéricas.
- Golden hammer (martelo de ouro): presumir que uma solução favorita é universalmente aplicável.
- Fator de improbalidade: presumir que seja improvável que um erro conhecido possa ocorrer.
- Otimização prematura: codificar pensando somente na eficiência, sacrificando o bom design, manutenibilidade e, muitas vezes, a própria eficiência.
- Programar por acidente: tentar chegar a uma solução através de modificações sucessivas no código para ver se funciona.
- Reinventar a roda: não adotar uma solução existente e adequada.
- Reiventar a roda quadrada: não adotar uma solução existente. Em vez disso, adotar uma solução customizada com um desempenho muito pior que a existente.
- Silver bullet (bala de prata): presumir que uma solução técnica favorita pode resolver um processo ou problema maior.
- Tester Driven Development (Desenvolvimento Orientado ao Testador): projetos de software onde novos requisitos são especificados em relatórios de erros.

Anti-patterns de gerenciamento de configuração:
- Dependency hell: problemas com as versões dos produtos exigidos.
- DLL hell: gerenciamento inadequado das dynamic-link libraries (DLLs).
- Conflito de extensão: problemas com diferentes extensões para as versões do pre-Mac OS da MC OS, na tentativa de corrigir as mesmas partes do sistema operacional.
- JAR hell: superutilização de múltiplos arquivos JAR, normalmente causando problemas de versionamento e localização, devido ao não entendimento do Java class loading model.

Tester Driven Development: Não Confundir com Test Driven Development

Este texto é uma tradução do Wikipedia

Tester driven development é um anti-pattern no desenvolvimento de software. Não pode ser confundido com Test Driven Development (TDD). Este anti-pattern diz respeito a qualquer projeto de desenvolvimento de software onde a fase de teste é tão longa que os requisitos podem mudar radicalmente durante o teste do software. Requisitos novos ou alterados acabam surgindo como relatórios de bugs. Um software de rastreamento de bugs normalmente não oferece suporte para lidar com requisitos. Como resultado, ninguém sabe de fato quais são os requisitos do sistema.

Projetos que são desenvolvidos utilizando este anti-pattern sempre sofrem grandes atrasos. Outro problema freqüente é a queda na qualidade do código.

As causas mais comuns para projetos que acabam sendo executados dessa maneira, são:

A fase de teste começa muito cedo;
Requisitos incompletos;
Testadores inexperientes;
Desenvolvedores inexperientes;
Má gerência de projetos.

As coisas pioram quando os testadores percebem que não sabem quais são os requisitos e, portanto, não sabem como testar uma mudança particular no código. Desta forma, o ônus recai sobre os desenvolvedores de alterações para escreverem seus próprios casos de teste.

sexta-feira, 8 de outubro de 2010

Anemic Domain Model

Este post é uma tradução do Wikipedia.

O Anemic Domain Model é um termo usado para descrever o uso de um software domain model, onde a lógica de negócio é implementada fora dos objetos de domínio.

Resumo
Este pattern foi descrito primeiramente por Martin Fowler, que considera a prática um anti-pattern. Com este pattern, a lógica é tipicamente implementada em classes separadas que transformam o estado dos objetos de domínio. Fowler denomina estas classes externas como transaction scripts (scripts de transação). Este pattern é uma abordagem comum em Enterprise Java Applications, possivelmente encorajado por tecnologias como as versões iniciais do EJB Entity Beans, assim como aplicações .Net que seguem a arquitetura de aplicação de serviços em três camadas, onde tais objetos se enquadram na categoria de "Entidades de Negócios" (embora Entidades de Negócio possam conter comportamento).

Benefícios:
Separação clara entre lógica e dados (programação procedural).


Deficiências:
- Lógica não pode ser implementada de forma verdadeiramente orientada a objeto a não ser que wrappers sejam usados para esconder a estrutura anêmica de dados.
- Violação do encapsulamento e dos princípios de ocultação de informação.
- Necessita de uma camada de negócios separada para conter a lógica localizada em um modelo de domínio. Isto também significa que objetos do modelo de domínio não podem garantir sua correção, porque sua lógica de validação e mutação é colocada em algum local externo (muito provavelmente em múltiplos locais).
- Necessita de um acesso global aos internos das entidades de negócio compartilhadas, aumentando acoplamento e fragilidade.
- Facilita a duplicação de código entre scripts transacionais e casos de uso similares, além de reduzir o reúso de código.
- Necessita de uma camada de serviço quando for compartilhar a lógica de domínio entre diferentes consumidores de um modelo de objeto.
- Torna um modelo menos expressivo e mais difícil de entender.

God objects: em geral, uma má prática

Este post é composto de trechos extraídos da Wikipedia.

Em programação orientada a objeto, um God Object (Objeto Deus) é um objeto que sabe muito e faz muito. God Object é um exemplo de anti-pattern.

A idéia básica por trás da programação estruturada é que um problema grande seja quebrado em muitos problemas menores (estratégia dividir e conquistar) e soluções são criadas para cada um destes problemas. Assim que os problemas pequenos são resolvidos, o problema como um todo também será. Portanto, há somente um objeto de quem um objeto precisa saber tudo: ele mesmo. Além disso, há somente um objeto de quem um objeto deve resolver um conjunto de problemas: ele mesmo.

O código baseado em God Object não segue esta abordagem. Em vez disso, a maioria da funcionalidade global é codificada em um único objeto "sabe-tudo", que mantém a maioria das informações do programa inteiro e fornece a maioria dos métodos para manipular os dados. Devido ao fato que este objeto mantém muitos dados e requisita muitos métodos, seu papel no programa se torna como se fosse um "Deus". Em vez de objetos se comunicando diretamente, os outros objetos dentro do programa confiam a um God Object a maioria de suas informações e interações. Uma vez que o God Object é referenciado por muitos outros códigos, a manutenção se torna mais difícil do que em um design dividido de forma mais equilibrada.

God Object é um análogo orientado a objeto de não usar subrotinas em linguagens procedurais, ou em usar muitas variáveis globais para armazenar informação de estado.

Enquanto a criação de um God Object é normalmente considerada uma má prática de programação, esta técnica é ocasionalmente utilizada em certos ambientes de programação (como microcontrollers), onde há um ligeiro aumento de desempenho e a centralização do controle é mais importante que a manutenibilidade e o código elegante.

O que é Code Smell?

Este post é um conjunto de trechos extraídos da Wikipedia.

Em programação, code smell é qualquer sintoma no código fonte que indica um problema mais profundo.

O problema sugerido por um code smell sempre ser descoberto quando o código está sujeito a um pequeno ciclo de feedback, onde é refatorado em etapas pequenas e controladas, e o design resultante é examinado para verificar se há mais code smells que indiquem a necessidade de mais refatoração.

Do ponto de vista de um programador encarregado de realizar a refatoração, code smells são heurísticas que indicam quando refatorar, e quais técnicas específicas de refatoração devem ser usadas.

Determinar o que é ou não um code smell é sempre um julgamento subjetivo, e sempre irá variar de acordo com a linguagem de programação, o desenvolvedor e a metodologia de desenvolvimento.

Existem ferramentas que detectam certos tipos de code smells, como:
Java: Checkstyle, PMD e FindBugs.
Dot Net: ReSharper.

Code smells comuns:

Código duplicado: código idêntico ou muito similar existe em mais de um local.
Método longo: um método, função ou procedure muito extenso.
Classe extensa: uma classe que acabou ficando muito extensa (God Object).
Feature envy (sem tradução): uma classe que utiliza em excesso métodos de outra classe.
Intimidade inapropriada: uma classe que possui dependência de detalhes de implementação de outra classe.
Legado recusado: uma classe que sobrepõe (override) o método da classe genérica de forma que o contrato da classe genérica não é cumprido pela classe derivada.
Classe preguiçosa: classe que faz muito pouco.
Complexidade artificial: uso forçado de design patterns extremamente complicados, onde um design simples seria suficiente.
Identificadores excessivamente longos: em particular, o uso de convenções de nomes para evitar ambigüidades, o que deveria estar implicito na arquitetura do software.

Princípios SOLID: O que são?

SOLID são cinco princípios básicos de programação e design orientados a objeto, introduzidos por Robert C. Martin no início dos anos 2000:

SRP: Single Responsibility Principle (Princípio da Responsabilidade Única). Noção de que um objeto deve possuir uma única responsabilidade.

OCP: Open/Closed Principle (Princípio Aberto / Fechado). Noção de que o software deve ser aberto para extensão, mas fechado para modificação.

LSP: Liskov Substitution Principle (Princípio da Substituição de Liskov). Noção de que objetos devem ser substituídos por instâncias de seus subtipos, sem afetar a correção do programa.

ISP: Interface Segregation Principle (Princípio de Segregação da Interface). Muitas interfaces específicas são melhores do que uma interface de uso geral.

DIP: Dependency Inversion Principle (Princípio de Inversão da Dependência). Noção de que se deve depender de interfaces abstratas e não de classes concretas, uma vez que implementações concretas são mais propensas a mudanças.

Princípios SOLID podem ser aplicados no desenvolvimento de software:

- A fim de remover Code Smells. Desta forma, o desenvolvedor refatora o código fonte do software até que esteja legível e extensível.
- Em conjunto com TDD (Test-Driven Development: desenvolvimento orientado a testes).
- É parte de uma estratégia global de programação ágil e adaptativa.
- Quando os princípios são aplicados em conjunto, aumentam bastante as chances de que o sistema criado seja simples de manter e estender.

Esta foi uma introdução a SOLID. Nos próximos posts farei uma explicação simples de cada um dos princípios aqui mencionados.