Automatização utilizando Ant

Desenvolvedores que iniciaram seu aprendizado na linguagem Java utilizando alguma IDE, muitas vezes desconhecem como funcionam os processos responsáveis por transformar o código escrito, em software propriamente dito. Neste post irei mostrar um pouco sobre os conceitos por trás destes processos, como compilar e geração de arquivos .jar, e como automatizar estas tarefas utilizando o Ant.

Os arquivos .class

Quando desenvolvemos um software escrito em Java, não é nosso código em si que é utilizado para executar o programa. Antes de rodarmos o código que escrevemos, o mesmo deve ser compilado, etapa esta que a maioria das IDEs faz automaticamente. A compilação consiste em transformar o código fonte, legível para nós, em código de máquina ou bytecode, que é a forma que a JVM (Java Virtual Machine) compreende e sabe executar. Enquanto os arquivos que escrevemos possuem a extensão .java, este arquivos gerados, escritos em bytecode, são arquivos .class.

Os arquivos .jar e .war

A não ser que você esteja escrevendo seu primeiro Hello World, dificilmente seu programa em Java terá somente uma classe. O arquivo .jar é o executável do Java, nele se encontram os pacotes com todas as classes e arquivos do seu software. Os arquivos .war funcionam de forma semelhante, mas são criados para aplicações web, nele também se encontram todas as classes e arquivos do projeto. O arquivo .war é utilizado para instalar a aplicação no servidor web como Jboss ou TomCat.

Apache Ant

Apache Ant, ou somente Ant como é mais conhecido, é uma ferramenta que automatiza além dos processos mostrados anteriormente muitos outros. Você pode por exemplo criar e remover diretórios, mover arquivos entre eles, rodar seus testes unitários e gerar relatórios.

Instalação

Baixe o instalador do Ant aqui. Descompacte o arquivo no local de sua preferência. É necessário inserir o caminho da pasta “bin” do Ant às variáveis de ambiente do Windows. Copie o endereço da pasta bin que vai ser algo como “C:\Program Files\apache-ant-1.9.2\bin”. Vá nas propriedades do computador e acesse a opção variáveis de ambiente. Procure a variável Path e adicione no final de seu valor o caminho para o diretório copiado anteriormente. Isso é tudo que precisa ser feito, para conferir se a instalação ocorreu corretamente, apartir do prompt de comando digite: ant –version. Se tudo estiver certo, uma mensagem com a versão de seu Ant será exibida.

O arquivo build.xml

As operações do Ant, mais conhecidas como tasks, funcionam através de configurações escritas em um arquivo XML. Através de comandos simples as tarefas que vimos anteriormente podem ser automatizadas facilmente. Vou demonstrar isso através de um exemplo bem simples com o objetivo de demonstrar na prática como se monta um arquivo de build. Crie os arquivos build.xml e TesteAnt.java, e copie os trecho abaixo, ou baixe o exemplo pronto no meu GitHub.

public class TesteAnt {
public static void main(String[] args) {
System.out.println(“Hello Ant!”);
}
}

<project name=”teste” basedir=”.” default=”executar”>

<property name=”classes” location=”classes”/>
<property name=”arquivo” value=”TesteAnt” />

<target name=”diretorios”>
<mkdir dir=”classes” />
</target>

<target name=”apagar”>
<delete dir=”classes”/>
</target>

<target name=”compilar” depends=”diretorios”>
<javac srcdir=”${basedir}” classpath=”${classes}” destdir=”${classes}”/>
</target>

<target name=”empacotar” depends=”compilar”>
<mkdir dir=”build/jar”/>
<jar destfile=”build/jar/TestAnt.jar” basedir=”${basedir}/classes”>
<manifest>
<attribute name=”Main-Class” value=”main.TesteAnt”/>
</manifest>
</jar>
</target>

<target name=”executar” depends=”empacotar, apagar”>
<java jar=”build/jar/TestAnt.jar” fork=”true”/>
</target>

</project>

Por trás do exemplo

<project name=”teste” basedir=”.” default=”executar”>

Esta linha é o início do arquivo de build, onde é declarado o nome do projeto, o diretório base, e a task padrão que será executada pelo Ant.

<property name=”classes” location=”classes”/>
<property name=”arquivo” value=”TesteAnt” />

A tag property serve para declarar variáveis que podem ser utilizadas dentro do arquivo de build.

<target name=”diretorios”>
<mkdir dir=”classes” />
</target>

A tag target serve para definir um alvo para o Ant. Uma vez definido, você pode chamar o alvo dentro do arquivo, ou até de fora através do comando “ant nomeDoAlvo”. Mkdir cria um diretório com o nome recebido por parâmetro.

<target name=”apagar”>
<delete dir=”classes”/>
</target>

Delete apaga o diretório com o nome recebido. Não se preocupe não estamos criando e apagando em seguida o diretório, você já irá entender.

<target name=”compilar” depends=”diretorios”>
<javac srcdir=”${basedir}” classpath=”${classes}” destdir=”${classes}”/>
</target>

A tag javac, assim como o comando de mesmo nome, compila os arquivos .java gerando como saída os .class escritos em bytecode

<target name=”empacotar” depends=”compilar”>
<mkdir dir=”build/jar”/>
<jar destfile=”build/jar/TestAnt.jar” basedir=”${basedir}/classes”>
<manifest>
<attribute name=”Main-Class” value=”main.TesteAnt”/>
</manifest>
</jar>
</target>

A tag jar empacota os arquivos indicados gerando como saída um arquivo jar. Já a tag manifest cria o arquivo manifest necessário para criação do pacote jar.

<target name=”executar” depends=”empacotar, apagar”>
<java jar=”build/jar/TestAnt.jar” fork=”true”/>
</target>

E a tag java  executa um arquivo .jar. A tag depends indica que a iniciação do target depende da finalização de outro, por isso no exemplo anterior o alvo “apagar” não será executado após o “diretorios”, e sim antes do alvo “executar”. Cuidado ao montar seu arquivo, se um target não for dependência de outro, ele só será executado caso seja declarado como default na tag project.

Executando

Para executar o arquivo é simples, basta abrir o prompt de comando, navegar até a pasta onde se encontra o arquivo “build.xml”, e digitar o comando ant, se tudo ocorrer bem, você terá uma pasta com o arquivo .jar e a mensagem “Hello Ant!” será exibida no console. Também é possível executar um target específico executando o comando ant nomeTarget.

Como disse anteriormente, este foi apenas um exemplo didático, o Ant possibilita automatizar muitas outras tarefas de seu projeto. Abaixo seguem alguns links interessantes para se aprofundar no assunto.

Links

Ant: http://ant.apache.org/

Documentação: http://ant.apache.org/manual/index.html

Lista de tasks: http://ant.apache.org/manual/Tasks/ 

Qual a sua causa?

O relógio chama. Hora de acordar. Vale a pena? Você tem um motivo para acordar. Algo para fazer? Algo para realizar?

Como conseguir manter este foco. Como manter um propósito vivo? Nesta apresentação de pouco mais de 2mins, apresento alguns conceitos de caras famosos, como Daniel Pink e Chip Conley. Podemos ainda falar na famosa pirâmide de Maslow, que acabei pulando nesta apresentação (a pirâmide aparece quase como uma mensagem subliminar).

O dinheiro não é suficiente. Ser reconhecido pode não ser suficiente. Fazer parte de uma causa, que nos ajuda a manter o foco e aceitar as realizações que conseguimos alcançar, pode ser uma opção.

Esta palestra foi realizada em um uMov.me Labs Summit, evento de palestras usado para compartilhar e criar conhecimento.

Link para o vídeo no youtube. Ou mande um play aí na apresentação:

How to com experiências em JUnit 4

JUnit é um framework simples, baseado na arquitetura xUnit para a implementação de testes unitários na linguagem Java. O JUnit geralmente vem integrado em IDE’s como Eclipse e NetBeans, mas pode ser obtido através da seguinte url https://github.com/junit-team/junit/wiki/Download-and-Install. Para começar a trabalhar com JUnit é preciso identificar junto à IDE como criar suites de testes. Geralmente uma suite de testes implementada no JUnit estará vinculada a uma determinada classe a ser testada. Cada suite de testes é formada por um conjunto de testes unitários que farão afirmações específicas sobre comportamentos do código, gerando resultados positivos se as afirmações forem verdadeiras, e resultados negativos se as afirmações forem falsas.

Testes unitários no JUnit são caracterizados por métodos de classe que implementam comportamentos da ferramenta. Cada teste unitário pode ser mapeado através de uma anotação @Test, declarada junto com o método de teste para sinalizar ao JUnit que este método deve ser invocado quando executar a(s) suite(s) de testes. Cada teste deve mapear exatamente um cenário a ser testado na aplicação, exigindo que determinados comportamentos sejam testados várias vezes para os diferentes cenários identificados.

Existem afirmações básicas que podem ser utilizadas ao implementar um teste unitário. Dependendo das necessidades e objetivos do teste, afirmações diferentes podem ser melhor aplicadas ao contexto. O teste mais simples pode ser construído usando o comando assertEquals(expected, obtained), que serve para comparar dois valores (objetos), e verificar se eles são iguais (um valor esperado e um valor obtido).

Outros testes podem ser construídos usando comandos como assertTrue(booleanValue). assertFalse(booleanValue), assertNull(valueObject), assertNotNull(valueObject), assertArrayEquals(expectedArray[], obtainedArray[]), e alguns matchers que fazem comparações específicas entre os valores esperados e os valores obtidos. Exceções podem ser esperadas em determinados cenários de teste, sendo verificadas através da anotação @Test presente no cabeçalho, inserindo a Exception.class no atributo ‘expected’. Ex.: @Test(expected=’Exception.class’)

É possível também criar critérios próprios de teste, implementando classes de Assertions especializadas nas abordagens adotadas pelo desenvolvedor. Para isso basta construir comparações e comportamentos que verifiquem as condições desejadas do código. Caso as verificações falhem, o resultado deve ser transmitido através do comando fail(message). Dessa maneira o teste irá falhar e exibir a respectiva justificativa para a falha.

O tutorial apresentado nos slides pode ser consultado através do link https://github.com/rmuchoa/JunitExperience com os códigos armazenados no github. Ps.: O acesso a banco não foi implementado de verdade, foi apenas uma prova de conceito inicial.

Análise de Código utilizando SonarQube

No meu último post falei sobre métricas de código e os benefícios que eles podem trazer para a boa saúde do código. Hoje irei apresentar uma ótima ferramenta para gerar automaticamente estas métricas, SonarQube.

SonarQube é um software open-source que se propõe a ser a central de qualidade do seu código-fonte, lhe possibilitando o controle sobre um grande número de métricas de software, e ainda apontando uma série de possíveis bugs. Tudo isso é gerado através de uma análise completa do código, e após isso os resultados obtidos são mostrados através de uma interface web, em forma de dashboards, e gráficos. Um exemplo do resultado disto pode ser visualizado nesta página.

Iniciando o SonarQube

Vejamos então como configurar o SonarQube. Para este exemplo irei utilizar um projeto Java do jogo FizzBuzz. Além de Java, mais de 25 linguagens são suportadas como C# e Python por exemplo. Uma lista completa pode ser conferida aqui.

Baixe o SonarQube 3.6.3. Descompacte o arquivo em uma pasta de sua escolha. Abra a pasta “sonar-3.6/bin” e entre na versão relativa ao seu sistema operacional. Execute o arquivo StartSonar.bat (no caso do Windows). Um console irá aparecer e executar o serviço do Sonar. Para verificar se tudo ocorreu corretamente acesse o seguinte endereço em seu navegador: http://localhost:9000/. A tela abaixo deve aparecer.

exemplo

Tela de apresentação do SonarQube

Configurando o projeto

O próximo passo será criar o arquivo de configuração. Crie um arquivo com o nome “sonar-project.properties” na raiz de seu projeto. Abaixo segue o arquivo com a configuração para o projeto exemplo, copie para o seu arquivo e faça as adaptações necessárias para o seu projeto.

# metadados requeridos

sonar.projectKey=FizzBuzzSonarExample

sonar.projectName=FizzBuzzSonarExample

sonar.projectVersion=0.1

# caminhos para os códigos fontes

# caminhos podem ser separados por vírgula

sonar.sources=src/main/java

sonar.tests=src/main/test

# A linguagem do projeto

sonar.language=java

# Formato

sonar.sourceEncoding=UTF-8

Analisando o código

Para fazer a análise do código iremos utilizar o SonarQube Runner. Baixe o arquivo SonarRunner 2.2.2, e extraia o conteúdo em uma pasta de sua escolha. Agora é necessário adicionar o caminho onde se encontra o arquivo “sonar-runner.bat” às variáveis de ambiente (no caso do Windows). Clique com o botão direito em Computador e escolha propriedades. Vá em Configurações avançadas do sistema e entre em variáveis de ambiente. Edite a variável Path, adicionando no final o caminho para o SonarQube Runner, que irá ser algo como: “suaPasta\sonar-runner-2.2.2\bin”

variaveis

Adicionando o SonarQube Runner às variáveis de ambiente

Feita a configuração, é hora de análisar o projeto. Se certifique que o SonarQube foi iniciado e que seu projeto tenha o arquivo “sonar-project.properties”. Através do Prompt de Comando, navegue até a pasta raiz de seu projeto e digite o comando: “sonar-runner”. Se tudo ocorrer bem a análise deve iniciar e o resto do trabalho é feito automaticamente. O tempo de duração irá variar de acordo com o tamanho de seu código, e no final uma mensagem de sucesso é exibida.

prompt

Mensagem de sucesso na execução do Sonar Runner

Agora você pode acessar novamente o endereço http://localhost:9000/ para conferir o resultado. Os dashboards com as métricas padrões serão exibidos. Você pode configurar os dashboards, efetuando login com usuário: admin, e senha: admin. 

Por fim acesse a documentação oficial para conhecer as diversas opções de métricas disponíveis, e escolha as que atenderem o seu projeto.

Clean code good! Spaghetti code bad!

Desculpem pelo título em inglês, era para poder fazer a piada. O ponto é que ler um código espaguete é diferente de comer espaguete. O código neste “formato” provoca dores de cabeça e muitas vezes gera sentimentos como ódio, fúria, principalmente se você é chamado para corrigir algo em um código assim perto das 18h da sexta-feira.

O ideal é poder iniciar novos sistemas com boas práticas, de padrões de projetos e facilidade de leitura. Mas nem sempre é assim. E aí vem a importância do estudo contínuo de orientação a objetos, padrões de projetos, e tópicos de engenharia de software em geral.

excelencia-tecnica.032

Uma das referências neste aspecto é Bob Martin, o Uncle Bob.

Usei o Uncle Bob como motivação em alguns time que trabalhei, usando a regra da banda verde.  Selecionava pessoas que acreditava que tinham potencial de disseminar a cultura de TDD e Clean Code pela equipe, e doava uma banda verde para que aquele desenvolvedor sempre que fosse tocar no código se lembrasse de manter o código limpo e desenvolver como um desenvolvedor profissional.

Praticar código limpo. Se eu posso dar um conselho para você, esse é o meu conselho. E dentro da prática, está em transformar código. E transformar com paciência. Baby steps. Saber que débito técnico é uma realidade em qualquer código de produção. Mesmo times ágeis focados em refactoring, testes e qualidade no código sempre, encontrarão oportunidades de melhoria, para ganhar mais desempenho e estabilidade em algum pedaço de código fonte.

Pensando nisto trouxe um dojo diferente para a equipe. Coloquei um código Java ruim, com vários pequenos problemas que passam desapercebidos pelos desenvolvedores muitas vezes, para que durante o espaço do dojo o time fosse trabalhando criando testes básicos para garantir o comportamento do fonte e a partir daí focassem na refatoração da estrutura. Dá para ver o resultado depois de 40mins programando em um repositório do github. Lá tem o código original para quem quiser brincar.

Os Coding Dojos são excelentes oportunidades para a prática do código limpo. Seja de um problema do zero como de um problema “pronto” para ser transformado, como é o caso deste “bad code dojo”. Estudar ferramentas de apoio no processo do TDD, como ferramentas de auditoria de código fonte e cobertura de testes, também são ótimas possibilidades. No meu post sobre TDD tem algumas dicas.

E essa prática dever ser igual a do seu esporte favorito. Deve fazer parte da sua rotina praticar código e resolver problemas. Escolha um kata, e pratique código limpo! Comecei o post em inglês e vou terminar com uma tagline para vocês sobre qualidade de código e testes. Só quem faz teste automatizado vai entender:

Keep the bar green to keep the code clean!

Android & Lua

Neste post, vou apresentar um pequeno projeto de exemplo que mostra uma integração de Lua com uma aplicação Android.


O que é Lua?

Lua é uma “embed language”, ou seja, tem como objetivo ser usada dentro de uma aplicação escrita com outra linguagem (para estender a app, configurar, etc.). Quando foi criada na PUC-Rio, por exemplo, era usada por engenheiros da Petrobras (que nem mesmo eram programadores) para configurar o funcionamento de alguns softwares usados nas plataformas de petróleo.

Mais detalhes na página oficial: http://www.lua.org


Como um programa escrito em Lua roda dentro de uma aplicação?

Lua nada mais é que uma biblioteca escrita em C. É multiplataforma, pois usa apenas as funções e tipos da biblioteca padrão do C. É possível executar programas escritos em Lua (scripts) através da linha de comando, mas isso nada mais é que um pequeno executável que tem a biblioteca Lua dentro.

Então, para incluir Lua na sua aplicação, basta incluir essa biblioteca no seu programa e usar suas funções. É possível carregar arquivos com os scripts, executá-los e integrar funções e dados; por exemplo, funções escritas em C que podem ser chamadas pelo script Lua, e funções do script podem ser chamadas pelo código em C.


Lua e Android

No link https://github.com/marciodrosa/LuaAndAndroidSample há um sample que mostra como integrar Lua em uma aplicação mobile. No caso, Android. Teoricamente, deve ser possível também em outras plataformas, como iOS e Windows Phone 8 (o Windows Phone 7 não tem suporte a programação com C, logo, só é possível executar Lua caso exista alguma implementação não oficial da biblioteca em C#).

O objetivo é mostrar como uma aplicação poderia ser estendida com um plug-in escrito pelo usuário.

Ao executar a app, são exibidos três caixas de texto. Ao alterar valores das duas primeiras, a soma destes valores aparece na terceira. Essa lógica e manipulação do terceiro campo é feita por um script Lua.

postimg1 - screenshot


Mas as aplicações Android são escritas em Java, não em C!

Java permite integração com código escrito em C, a chamada Java Native Interface (JNI). O código escrito em C precisa ser compilado em uma lib, e por isso existem as ferramentas do Android para isso: o Android NDK (http://developer.android.com/tools/sdk/ndk/index.html). Além do compilador, há algumas bibliotecas disponíveis no NDK.

Assim, no Android, ocorre uma conversa entre três linguagens: Java <—> C <—> Lua.


Como funciona a app de exemplo LuaAndAndroidSample

Dentro do projeto há um arquivo “myscript.lua”, que é empacotado junto com a aplicação. Essa foi a maneira utilizada por este projeto de exemplo, mas é claro que poderia ser feito de outras maneiras, afinal, o script é apenas um texto; poderia ser recebido pela rede, lido de um arquivo, ou até mesmo criado dentro da app, em uma caixa de texto. O conteúdo do script é o seguinte:

 return {
   onfieldvaluechangedbyuser = function(context)
     local op1 = tonumber(context.fields["Field one"].value) or 0
     local op2 = tonumber(context.fields["Field two"].value) or 0
     return {
       newfieldvalue = {
         field = "Field three",
         value = op1 + op2,
       }
     }
   end
 }

Este script é como um plugin, ele altera o comportamento da aplicação para mostrar uma nova informação na terceira caixa de texto. Quando a app é iniciada, ela carrega e executa o script, que apenas retorna uma tabela (objeto) com as funções de callback para serem chamadas em determinados eventos. No exemplo, esta tabela tem uma função chamada “onfieldvaluechangedbyuser”, que é chamada pela app quando uma caixa de texto tem o valor alterado pelo usuário.

A função onfieldvaluechangedbyuser recebe um objeto de contexto, que possui os dados da aplicação (como os valores das três caixas de texto). Na implementação, ela retorna um outro objeto (result), que é então processado pela app. Este outro objeto pode possuir um novo valor para algum campo. No myscript.lua, o script retorna um novo valor para ser setado na terceira caixa de texto.

Resumidamente, este é o fluxo do que ocorre:

Usuário altera um valor na caixa de texto –> app chama o callback do script, passando o contexto –> script retorna um resultado –> app processa o resultado.

A idéia dessa arquitetura é isolar a execução do script em uma sandbox: não há interação entre a app e o script (por exemplo, o script não altera o valor da terceira caixa de texto; ao invés disso, ele retorna um objeto solicitando que a app faça isso). Esse isolamento é feito para deixar a execução do script mais unitária, facilitar os testes e simplificar o fluxo.

Além disso, usei um pouco da idéia dos plugins do Blender (blender.org), que também são executados assim que a aplicação é iniciada, e que possui funções de callback para serem chamadas mais tarde, quando ocorrem eventos (também recebendo um objeto de contexto como parâmetro).

postimg2 - flow


Como foi feita a integração na app (a “engine” de plug-ins)

A arquitetura básica da “engine” é exemplificada na seguinte imagem:

postimg3 - languageflow

  • A biblioteca em C foi nomeada de “Bridge”, já que é uma ponte entre a app e os scripts.
  • A aplicação Java e o “Bridge” em C conversam entre si (Java solicita para a Bridge que o plugin execute; a Bridge retorna resultados para a aplicação Java).
  • A Bridge e uma engine Lua conversam entre si. Essa engine não é o plugin em si. Ela é usada para fazer a lógica de chamada do plugin, processar erros, resultados, etc. Isso mostra como Lua pode ser usado não apenas para estender a aplicação: neste caso, foi usada para implementar uma lógica que pertence nativamente à aplicação. Isso pode ser muito útil para aplicações multiplataforma. Por exemplo, se a mesma app for implementada para outro sistema, como iOS, o código dessa engine em Lua pode ser reaproveitado.
  • Por fim, a engine em Lua faz o plugin executar. O plugin não se comunica com ninguém, ele executa em uma sandbox isolada, evitando que a lógica implementada por um usuário possa agir de maneira inesperada na aplicação. Toda a comunicação é feita entre a engine Lua e a Brigde C.

Algumas informações adicionais

  • Embora Lua utilize ANSI C (apenas as bibliotecas padrão), nem tudo são flores: o NDK, por exemplo, não possui a API de internacionalização do C (utilizada pelo Lua para saber se um número decimal usa ponto ou vírgula). Então, pequenos ajustes são necessários. O código fonte do Lua 5.2 pronto para ser compilado para Android pode ser pego no meu repositório do Github: https://github.com/marciodrosa/LuaAndroid. Além dos ajustes necessários, ele também direciona as mensagens de erro e log para o logcat.
  • Para fazer o build de uma lib para Android usando código-fonte C, os arquivos de código devem ser colocados dentro de uma pasta chamada “jni” e o comando “ndk-build” deve ser executado. Dentro da pasta “jni” também há alguns arquivos de configuração, como “Android.mk” e “Application.mk”, e outras libs pré-compiladas, caso sejam usadas pelo projeto. O NDK automaticamente move os binários gerados para dentro da pasta “lib”. No projeto Java do Android, as libs que serão usadas devem ser carregadas usando System.loadLibrary (ver a classe StartActivity do projeto LuaAndAndroidSample). O build pode parecer um pouco difícil de entender no começo. Para mais detalhes, é necessário ler a documentação do NDK. A maior parte da documentação não está disponível online; ao invés disso, vem junto com o projeto do Android NDK, quando ele é baixado.
  • No projeto AndroidAndLuaSample, há um método que gera o objeto “context”, que é passado para o callback do script. Ele gera o context concatenando scripts. Obviamente, isso não é uma boa prática, não estamos lidando com linguagens orientadas a string! Que fique claro que isso foi feito apenas para demonstração. O correto seria criar o objeto de contexto usando a API C do Lua.
  • Este sample funciona apenas em dispositivos com processador ARM. É necessário fazer outro build das bibliotecas C para que elas funcionem com outros processadores, como Intel.

Links

Página oficial do Lua:
http://www.lua.org/

Documentação do Lua (manual, referência da API e referência da API C):
http://www.lua.org/manual/5.2/

Livro online gratuito sobre Lua (mas é de uma versão antiga do Lua, com algumas features desatualizadas):
http://www.lua.org/pil/contents.html

Android NDK:
http://developer.android.com/tools/sdk/ndk/index.html

Lua 5.2 para Android:
https://github.com/marciodrosa/LuaAndroid

Código-fonte do projeto de exemplo “LuaAndAndroid”:
https://github.com/marciodrosa/LuaAndAndroidSample

Design Patterns: Como descobrir aonde queremos chegar

Padrões sempre existiram nas práticas de codificação de software. Eles eram idealizados e implantados em cada equipe de desenvolvimento, sempre que algum caso de sucesso era identificado e reproduzido em outros projetos. Porém existem alguns padrões específicos que tem sido identificados ao longo do tempo e que foram catalogados e amplamente disseminados e consagrados na comunidade de software, como os célebres Padrões de Projeto.

Image

Um dos mais famosos catálogos de Design Patterns é o catálogo de padrões do GoF (Gang of Four), grupo com os quatro autores do livro “Design Patterns: Elements of Reusable Object-Oriented Software” (1995), que atribuiu popularidade aos conceitos de padrões de projeto. Outro catálogo denominado GRASP (General Responsibility Assignment Software Patterns), foi proposto por Larman em seu livro “Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development” (2005), e também foi muito importante para a comunidade de software, levando também em conta princípios de desenvolvimento como SOLID.

Um padrão de projeto pode ser identificado sempre que alguma prática de solução de problemas é resolvida de maneira semelhante em diferentes ambientes e equipes de desenvolvimento. Para propor algum padrão de projeto, é necessário identificar 3 critérios muito importantes: o nome do padrão, o problema que o padrão se propõe a resolver, e a forma com que o padrão se propõe a resolver o problema. Alguns autores também se preocupam em definir quando usar e consequencias de usar um determinado padrão de projeto, mas em linhas gerais um padrão de projeto deve ser específico o suficiente para responder ao problema independente de linguagem ou arquitetura.

Os padrões de projeto se tornaram tão relevantes para a comunidade de software, que começaram a orientar a construção de inúmeros projetos ao redor do mundo, inclusive a construção de algumas linguagens de programação, componentes e frameworks de desenvolvimento que temos hoje. A definição de conceitos como padrões de arquitetura, também contribuiu muito para isso, visto que ofereceram a grandes projetos, modelos de arquitetura compostos por diferentes padrões de desenvolvimento reunidos e combinados.

Image

Um problema porém ainda permanece, desenvolver software preocupado com os padrões de projeto ainda é uma tarefa extremamente desafiadora, e que exige um alto grau de experiência e conhecimento de Orientação a Objetos. Como adotar os diversos princípios e leis da Orientação a Objetos, juntamente com os diversos padrões de desenvolvimento? Esta é uma pergunta difícil de se responder, principalmente porque os padrões, diferente das leis e princípios, não vem como uma simples cartilha de como programar, mas vem como uma proposta específica para um problema específico.

Nesse contexto, ressaltamos que conhecer os problemas e aprender a identifica-los ao longo do processo de desenvolvimento, é a chave para começar a demonstrar o real interesse em trabalhar com padrões de projeto. Quando um problema no projeto é identificado e compreendido de forma clara, propor uma solução ideal se torna uma tarefa bem mais objetiva. Se para cada problema de implementação encontrado for possível encontrar um padrão de projeto que solucione o problema, será necessário apenas adaptar a proposta ao projeto, e implementar a solução para resolver o problema.

Image

Martin Fowler catalogou alguns dos principais problemas de implementação de código, chamando-os de code smells ou bad smells (maus cheiros), por servirem como sintomas para as necessidades de refatoração no código e no projeto. Não existe uma relação exata entre um padrão de projeto e um bad smell específico. Mas os padrões de projeto podem ser utilizados de diferentes maneiras, para resolver problemas específicos e contribuir para eliminar alguns dos maus cheiros do código. Isso acontece porque os padrões de projeto possuem foco em problemas específicos, mas apesar disso eles possuem uma base muito forte em leis e princípios de Orientação de Objetos que apontam soluções claras de implementação e como evitar problemas de código.

Cabe a cada equipe de software escolher e desenvolver práticas que agucem a percepção dos desenvolvedores a fim de identificar os problemas mais acertivamente, e nada como a prática diária de desenvolvimento para adquirir esse tipo de experiência.