metodologia

CruiseControl com SVN – Parte 01

February 20th, 2010  |  Published in metodologia, programação

Esse ano estamos tentando fazer algumas mundanças na Informant. Percebemos que usar quadros magnéticos, pregar post-it’s por toda empresa e fazer reuniões diárias não estavam nos fazendo mais “ágeis”, e na prática… pouca coisa era aplicada. Agora estamos buscando realmente implementar algo ágil nos nossos projetos. Estamos dandos os primeiros passos, mas muita coisa boa está sendo planejada para este ano.

Uma das coisas que precisamos melhorar é a forma como trabalhamos com nosso repositório de fontes. Estamos modificando nossos procedimentos e nosso trabalho diário para manter nosso respositório mais confiável: A Integração Contínua é uma prática essencial do XP, que não se resume apenas a utilização de uma ferramenta, mas a automatização de build’s e deploy’s pode economizar muito tempo de desenvolvimento. Deixando o programador disponível para realizar o seu trabalho mais importante: programar.

Estamos começando a utilizar o CruiseControl, ferramenta que ainda não conhecia de perto. Apesar de já ter trabalhado com algumas ferramentas do gênero (ex.: Bamboo), o CC me impressionou bastante com relação a flexibilidade de configuração e implementação de planos de build. Para quem está perdendo muito tempo com liberação de versões, builds, deploys de aplicativos, e está pensando em utilizar o CC, vou repassar aqui os meus passos iniciais de configuração da ferramenta em ambiente Windows:

  1. Faça o download da última release do CC, que atualmente é a 2.8.3 e descompacte vvocê achar melhor, por exemplo em C:\java\cruisecontrol-bin-2.8.3
  2. O ideal é criar um diretório de trabalho configuração de seus projetos. (ex.: C:\java\work\cruise). Achei mais fácil iniciar o CC desta mesma workspace, por isso também copiei os arquivos cruisecontrol.bat, config.xml e dashboard-config.xml para o diretório /cruise. Bastando apenas fazer alguns acertos no cruisecontrol.bat, apontando o launcher do CC para o caminho correto (C:/java/cruisecontrol-bin-2.8.3/lib/cruisecontrol-launcher.jar). Nesse momento, você já poderá iniciar o CC. Apontando o seu navegador para http://localhost:8080/dashboard/tab/dashboard já será possível acessar a ferramenta. Se tudo der certo, você deverá ver o Dashboard Server, que por enquanto, não terá nenhum projeto disponível.Você deverá ter a variável JAVA_HOME também já configurada no seu Path.
  3. Agora precisamos configurar um projeto. No CC, todos os projetos são configurados a partir do arquivo config.xml. Quando trabalhamos com múltiplos projetos, é interessante manter a configuração de cada um deles em arquivos separados, para isso podemos alterar o config.xml para que fique da seguinte forma:
    <!-- config.xml -->
    <!DOCTYPE cruisecontrol [
       <!ENTITY build-informantUtils SYSTEM "projects/informantUtils-config.xml">
       <!ENTITY build-informantEJB SYSTEM "projects/informantEJB-config.xml">
    ]>
    <cruisecontrol>
        <property file="config.properties"/>
        <plugin name="svn" classname="net.sourceforge.cruisecontrol.sourcecontrols.SVN"/>
        <plugin name="svnbootstrapper" classname="net.sourceforge.cruisecontrol.bootstrappers.SVNBootstrapper"/>
        <system>
           <configuration>
               <threads count="2"/>
           </configuration>
        </system>
        &build-informantLibs;
        &build-informantEJB;
    </cruisecontrol>
    
  4. O meu objetivo inicial com a utilização do CC, era fazer o build automático das aplicações no nosso ambiente de testes sempre que alterações fosse efetivadas (commit), garantindo que nosso repositório esteja sempre compilando, e que a qualquer momento, tivéssemos uma versão disponível para liberação. Para isso, utilizamos o elemento <modificationset>, que determina como o CC procura por alterações no repositório e quando vai executar o build do projeto.
    <!-- informantEJB-config.xml -->
    <plugin name="svn" classname="net.sourceforge.cruisecontrol.sourcecontrols.SVN"/>;
    <plugin name="svnbootstrapper" classname="net.sourceforge.cruisecontrol.bootstrappers.SVNBootstrapper"/>
        <modificationset quietperiod="10">
            <svn localWorkingCopy="checkout/agil/${project.name}"
                 repositoryLocation="${svn.repository}/${svn.trunk}/InformantEJB"
                 username="${svn.user}"
                 password="${svn.passwd}">
            </svn>
        </modificationset>
    

    Assim monitoramos alterações do projeto no SVN e quando o CC deverá fazer o build do projeto. Veja que é preciso indicar o respositório local do projeto (localWorkingCopy), para onde os fontes do projetos serão copiados e compilados no momento do build. Por isso é necessário criar um diretório de checkout local para os projetos no seu diretório de trabalho (ex.: /work/cruise/checkout)
    Para tudo dar certo, ainda iremos precisar incluir os plugins do svn, conforme acima. Também será necessária instalar e garantir que o SVN esteja no seu Path.

  5. Então utlizamos o elemento <schedule> com interval=”300″, para fazer com que o CC verifique o respositório do SVN a cada 5 minutos por novas modificações.  Além disso utilizamos o atributo time=”2300″, forçando com que um build seja executado diariamente as 23:00 horas. Nestes casos, o CC irá executar o script de build do projeto:  build-file=”checkout\agil\build-${project.name.xml}”
    <!-- informantEJB-config.xml -->
    <schedule  interval="500" showProgress="true">
         <ant  antscript="${ant.home}\bin\ant.bat"
               buildfile="checkout\agil\build-${project.name}.xml"
               target="build-informantEJB"
               uselogger="true"
               usedebug="true"
               time="2300"/>
    </schedule>
    

    Será necessário ter o ant instalado. O próprio CC  já vem com a versão 1.7.0 do ant, disponível no diretório de instalação do CC (C:/java/cruisecontrol-bin-2.8.3/apache-ant-1.7.0).

  6. Precisamos agora definir o diretório de logs do projeto. Crie um diretório de logs no seu diretório de trabalho (ex.: C:/java/work/cruise/logs). Isso é importante, porque o CC controla todo o histórico de builds e status (buildstatus) dos projetos em execução, através deste diretório de logs. Dentro do diretório de logs serão criados outros vários subdiretórios, um para cada projeto.
    E acrescente a configuração de log ao projeto:
    <!-- informantEJB-config.xml -->
    <log dir="logs/${project.name}"/>
    
  7. Após cada build do projeto, geralmente um artefato é gerado. Um arquivo war, ear ou zip por exemplo. Neste caso, um arquivo .jar. Por isso é preciso definir uma diretório onde todos esses artefatos serão armazenados após um build realizado com sucesso. Crie um diretório para os artefatos gerados no seu diretório de trabalho (ex.: C:/java/work/cruise/artifacts).  Dentro do diretório de artefatos serão criados outros vários subdiretórios, um para cada projeto.
    Para dizer ao CC, onde e quais artefatos serão publicados, utilizamos o elemento <artifactpublisher>:
    <!-- informantEJB-config.xml -->
    <publishers>
        <artifactspublisher dir="checkout/agil/${project.name}/output" dest="artifacts/${project.name}"/>
    </publishers>
    
  8. Com o arquivo de configuração do projeto concluído (projects/informantEJB-config.xml), precisamos apenas do script de build do projeto, que será chamado pelo CC. No meu caso, ficou mais ou menos assim:
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <project basedir="." default="build-informantEJB" name="informantEJB">
        <echo message="Project:informantEJB: Executando..."/>
    
        <property file="build.properties"/>
        <property name="svnant.latest.url" value="${agil.svn.repository}/${agil.svn.trunk}/informantEJB"/>
        <property name="local.repository" value="informantEJB"/>
    
        <path id="informant.libs">
            <fileset dir="libs/jars">
      	   <include name="**/*.jar"/>
    	</fileset>
        </path>
    
        <path id="jboss-runtime.libs">
    	<fileset dir="../../dependencies/jboss-runtime/client">
        	    <include name="**/*.jar"/>
    	</fileset>
    	<fileset dir="../../dependencies/jboss-runtime/lib">
     	    <include name="**/*.jar"/>
    	</fileset>
        </path>
    
        <path id="ejb.libs">
            <path refid="informant.libs"/>
            <path refid="jboss-runtime.libs"/>
        </path>
    
        <taskdef  resource="svntask.properties"/>
        <target name="checkout">
    	<echo message="${ant.project.name}: Fazendo checkout do respositorio ${svnant.latest.url}..."/>
    	<svn username="${agil.svn.user}" password="${agil.svn.passwd}">
      	    <checkout url="${svnant.latest.url}" revision="HEAD" destPath="${local.repository}" />
    	</svn>
        </target>
    
        <target name="mkdir">
            <mkdir dir="informantEJB/build/classes"/>
    		<mkdir dir="informantEJB/output"/>
            <copy includeemptydirs="false" todir="informantEJB/build/classes">
                <fileset dir="informantEJB/ejbModule">
                    <exclude name="**/*.launch"/>
                    <exclude name="**/*.java"/>
                </fileset>
            </copy>
        </target>
    
        <target depends="checkout,mkdir" name="compile">
            <echo message="${ant.project.name}: ${ant.file}"/>
            <javac debug="true"
    	       debuglevel="${debug.level}"
    	       destdir="informantEJB/build/classes"
    	       source="${compile.source}"
    	       target="${compile.target}"
    	       classpathref="ejb.libs">
                <src path="informantEJB/ejbModule"/>
            </javac>
        </target>
    
        <target depends="compile" name="build-informantEJB">
    	<echo message="${ant.project.name}: Gerando informantEJB.jar..."/>
    	<jar 	destfile="informantEJB/output/informantEJB.jar"
    		basedir="informantEJB/build/classes"
    		includes="**/*.class,**/*.xml">
    		<manifest>
          		    <attribute name="Created-By" value="Agil ERP"/>
    		    <attribute name="Manifest-Version" value="1.0"/>
    		    <attribute name="Implementation-Vendor" value="Informant"/>
    		    <attribute name="Implementation-Title" value="Informant"/>
    		    <attribute name="Implementation-Version" value="1.0"/>
    		</manifest>
    	</jar>
        </target>
    </project>
    

    O plano de build do projeto agora está OK: configuramos o informantEJB-config.xml para que execute o script de build (build-informantEJB.xml) quando alguma alteração for realizada no repositório. Além disso o CC irá executar também um build diário, as 23:00 horas.

  9. Tudo certo agora?! NÃO.
    Mesmo que você faça um build manual do projeto através do CC ( http://localhost:8080/dashboard/tab/dashboard), o status do projeto continuará inativo. Isso acontece porque criamos um diretório de trabalho em C:/java/work/cruise, onde serão armazenados os logs e artefatos do projeto. Mas o CC ainda não sabe disso.Crie um arquivo override.properties em C:/java/cruisecontrol-bin-2.8.3/reporting/jsp dessa forma:
    # This should be the full path to your CruiseControl log directory.
    # If you are in multi-project mode, there will be multiple sub-directories
    # inside this log directory, one for each project.
    user.log.dir=C:/java/work/cruise/logs
    
    # This should be the path to your current build status file, # expressed relative to the project's log directory.
    user.build.status.file=C:/java/work/cruise/logs/buildstatus.txt
    
    # This should be the absolute path to the directory where # additional build artifacts are stored.
    cruise.build.artifacts.dir=C:/java/work/cruise/artifacts
    

Essa é uma configuração bem básica. Mas já dá pra ter uma idéia do que pode ser feito. O CC foi implementado para ser extensível e flexível o suficiente para que você possa customizar quase tudo. Além disso, existem vários plugins e outros add-ons que podem ser utilizados pafa aumentar ainda mais as possibilidades de uso do framework.

<!DOCTYPE cruisecontrol [
<!ENTITY build-informant SYSTEM "projects/informant-config.xml">
<!ENTITY build-informantLibs SYSTEM "projects/informantLibs-config.xml">
<!ENTITY build-informantUtils SYSTEM "projects/informantUtils-config.xml">
<!ENTITY build-displayTags SYSTEM "projects/struts2-displatTag-config.xml">
<!ENTITY build-informantWeb SYSTEM "projects/informantWeb-config.xml">
<!ENTITY build-informantEJB SYSTEM "projects/informantEJB-config.xml">
<!ENTITY build-informantEAR SYSTEM "projects/informantEAR-config.xml">
<!ENTITY deploy-informantEAR SYSTEM "projects/informantEAR-deploy-config.xml">
]>
<cruisecontrol><property file=”config.properties”/>
<plugin name=”svn” classname=”net.sourceforge.cruisecontrol.sourcecontrols.SVN”/>
<plugin name=”svnbootstrapper” classname=”net.sourceforge.cruisecontrol.bootstrappers.SVNBootstrapper”/>
<system>
<configuration>
<threads count=”2″/>
</configuration>
</system>
&build-informantLibs;
&build-informantUtils;
&build-displayTags;
&build-informantWeb;
&build-informantEJB;
&build-informantEAR;
&build-informant;
&deploy-informantEAR;
</cruisecontrol>

Analistas de Sistemas. Quem ainda acredita neles ?

October 28th, 2008  |  Published in metodologia

Alguns dias atrás, me vi numa discussão com alguns colegas, sobre funções, atividades e cargos dentro de uma empresa. Apensar desse assunto ainda ser bem confuso em TI, a maioria soube descrever suas atividades diárias como programadores. Porém, essa descrição não foi obtida tão facilmente quando nos perguntamos: Afinal de contas, o que um “Analista de Sistemas” faz ?

Alguns me falaram que o analista de sistemas é um profissional com mais experiência, com perfil investigativo, que deve fazer a análise dos requisitos e modelar uma solução. Outros disseram que analista de sistema não devem “perder”  tempo com detalhes sobre linguagem ou tecnologia, porque “análise” de sistemas deve ser feita em alto nível, a.k.a UML. Escutei também alguns comentários clássicos: analista de sistemas necessariamente não precisa saber programar, precisa apenas conhecer UML e algum editor de texto. ( “analistas de sitemas não precisam saber programar…”. Com certeza essa merece estar nas próximas falácias da programação, parte ll … hehe )

Sobre esse assunto, tenho que dizer que concordo com Barry Hawkins: a super divisão de trabalho no desenvolvimento de software, foi umas das piores experiências da indústria de software nos últimos anos.

One of the most widespread tragedies in the practice of software development has been the tendency of corporate culture to over-compartmentalize the activities of software development. In the upper echelon of the artificial hierarchy of task separation sits the software architect. Sequestered away from the disturbing din of real life within the company, these persons are liberated from the mundane, in order that they may orchestrate plans that set in motion the work of many, unfettered by such things as domain knowledge and implementation constraints.
Know this; the only people who belong in white towers are the captured princesses of fairy tales, and even then it was not of their volition. Partitioning the activity of design away from implementation destroys the call-and-response cycle between design and implementation. The relevance of your work is directly related to how engaged you are in the domain.
- Barry Hawkins.

Estou convencido, que a separação das atividades de design e programação deveria ser qualificada como um anti-pattern do desenvolvimento de software. O waterfall já vem mostrando por anos, que essa abordagem é um erro.

Porque é necessário criar um cargo especial para atividades, que deveriam ser de responsabilidade do programador ?! Análise, design, programação e arquitetura são atividades e não cargos. Nós, como programadores, precisamos vestir “chapéus” diferentes dentro de um projeto.

Quando questionamos requisitos, buscamos informações de nossos usuários, organizamos e priorizamos tarefas, estamos vestindo nosso chapéu de analista e gerente de projetos. Quando estamos codificando, nos preocupando com manutenabilidade, performance e com a correta aplicação de patterns, estamos vestindo nosso chapéu de programador e projetista. Ao escolhermos por um framework, por uma API, estamos com certeza tomando decisões de arquitetura.
Não quero dizer aqui, que todo programador dever ser um  Macgyver em TI. Mas tenho certeza, que se você é programador, é bem provável que você precise colocar à prova diariamente suas habilidades como programador, analista, arquiteto ou gerente.

A maioria dos programadores passam anos querendo se tornar analista de sistemas, e quando conseguem, descobrem que como programadores, já desempenhavam atividades de análise a muito tempo. Além do mais, achar que um monte de diagramas UML podem modelar um sistema inteiro sem programar uma linha de código, não é algo muito inteligente. Analistas, arquitetos, projetistas, seja lá como for o nome que deram para ele, mas esse cara precisa saber programar -  If you design it, you should be able to code it - Mike Brown:

When designing the architecture for your project, you need to have a feel for what amount of effort is necessary to implement the various elements of your design. The easiest way to have the knowledge of the effort that a specific design element will take is to have developed it before.

Don’t use a pattern in your design that you haven’t personally implemented before. Don’t rely on a framework that you haven’t coded against before. Don’t use a server that you haven’t configured before. If your architecture depends on design elements that you haven’t personally used, there are a number of negative side effects. Mike Brown

Muitas empresas de TI estão procurando “achatar” hierarquias, procurando manter profissionais mais qualificados, com conhecimentos multidisciplinares e que possam atuar em diversos papéis diferentes. Que possam programar, tomar decisões de arquitetura ou conversar com usuários se for necessário. Por mais que muita gente ainda pense o contrário: Profissionais competentes e equipes motivadas são fundamentais em qualquer empresa.

E mesmo que os “Analistas de Sistemas” ainda existam para enfeitar alguns crachás corporativos ou anúncios de RH, eu já deixei de acreditar neles já faz algum tempo …

Pense antes de imprimir

August 7th, 2008  |  Published in metodologia

Desde que trabalho com desenvolvimento de software, venho observado a necessidade das empresas em gerar documentação. Esforços são feitos e muito tempo é investido na tentativa de criar e manter documentos de arquitetura (SAD – Software Architecture Document) em projetos de todos os tipos e tamanhos. E ao mesmo tempo, não é incomum que arquitetos de software, não saibam justificar por que a maioria das suas atividades diárias, acabam se resumindo na atualização de diagramas. E nem saibam dizer quem é o maior interessado em toda essa documentação.
Mas enfim, qual é a relação entre a documentação e o sucesso de um projeto ? Segundo Scott Ambler, nenhuma.

There is no solid relationship between project success and writing comprehensive documentation, and in fact it is more likely that the more documentation that you write the greater the chance of project failure.  Have you ever seen a project team write a comprehensive requirements document, get it signed off by your stakeholders, only to have the developers build something else?  Or the team actually builds to spec, only to have your stakeholders say that’s not really what they wanted?  Or the team delivers late or over budget, even though everything looked good most of the way through the project?  Have you ever seen a team create a comprehensive architecture model, have it reviewed and accepted by really smart people, only to see the architecture fail in practice anyway?  Or the developers simply ignore the model and then go off and build it the way that they want to?  Have you seen all this happen under the guise of management oversight, without management realizing what was happening until long after it occurred?
Scott W. Ambler

Na minha opnião, o que mais influenciou este comportamento, é um antigo conceito herdado da indústria de software e do waterfall model: o BRUF approach. Essa técnica é comprovadamente inviável e de fato não conheço nenhuma bibliografia séria, que recomende essa prática. A idéia de que seria possível levantar todos os requisitos de um sistema antes de gerar qualquer código executável, fez com que muitas empresas
ficassem por anos gerando documentos de todos os tipos e formatos.
Penso que documentar pontos fundamentais e use cases essenciais de um sistema não é um problema. O problema ocorre quando a documentação se torna o foco principal do projeto e as pessoas envolvidas tornam-se prisioneiras dos templates e da burocracia.
Muitos gerentes de TI, quando colocados em discussões como estas, refutam de formas diferentes, mas mas maioria se baseia no mesmo paradigma:

“Então vamos sair programando, sem nenhuma análise prévia ?!?!”

Não. A UML2 é uma ótima forma para investigar pontos críticos de um sistema, fazer avaliações de viabilidade de uma arquitetura ou comparar soluções para um determinado problema. E principalmente, a UML é uma fantástica linguagem de comunicação entre as equipes quando à utilizamos como UmlAsSktech. Alguns diagramas de iteração são muito úteis para expor idéias mais detalhadas numa reunião e para troca de informações entre arquitetos e programadores. Um diagrama mais simples, como de caso de uso, pode ser utilizado para demonstrar à stackholders e outros interessados no projeto, uma visão geral dos requisitos básicos de um sistema. Nestes casos, a abstração da UML é aceitável, já que preciso apenas de um overview sobre alguns pontos do meu sistema.

Na sua essência, a UML está relacionada com comunicação. E apesar de terem sido criadas várias ferramentas para geração de código fonte a partir de diagramas, acredito que a indústria de software ainda não conseguiu resultados satisfatórios com MDA e qualquer outra técnica de forward engineering. Ainda não vi nenhuma ferramenta que pudesse gerar código fonte aceitável em termos de qualidade a partir da UML. E acho que estamos bem longe disso por enquanto. Bons programadores, SEMPRE serão fundamentais.
Mas por que ? Porque a UML, apesar de ter evoluído muito desde a sua primeira versão, não está preparada para modelar TODOS os detalhes, comportamentos e funcionalidades que podem ser escritas no código fonte.

Além disso, outro ponto crítico sobre a supervalorização a UML, reside no simples fato de que ainda não  existe uma forma de validar UML. Como posso validar se um requisito está detalhado em um diagrama de sequência ? Como posso testar se uma regra de negócio do meu domínio foi corretamente “modelada” ?
UML não é executável e por isso não tenho como validar se um design é bom ou ruim. Todas as regras de negócio estarão implementadas no codigo fonte, e é código fonte, executável, que pode ser validado. É o código fonte executável, que poderei submeter a testes em TDD. Então por que não modelar em código ?

That, yes, but more. The source code is also the ONLY document in whatever collection you may have that is guaranteed to reflect reality exactly. As such, it is the only design document that is known to be true. The thoughts, dreams, and fantasies of the designer are only real insofar as they are in the code. The pictures in the reams of UML are only veridical insofar as they are in the code. The source code is the design in a way that no other document can claim. One other thought: maybe gloss isn’t in the writing, maybe it’s in the reading.
Ron Jeffries

Código fonte bem escrito é o melhor design e documentação que um programador pode fornecer, bem mais rico em detalhes do que qualquer diagrama UML. O problema é que a maioria dos desenvolvedores não encaram código fonte com uma forma de documentação e nem sequer levam em consideração que programação também é uma atividade de design. A preocupação com a clareza e simplicidade do código, a correta aplicação de patterns e a prática de refactoring também são atividades de design sob responsabilidade do programador. Estas práticas provavelmente produzirão a documentação mais atualizada e precisa do sistema. É claro, que muito código fonte que se encontra por aí, não é legível, e sequer pode ser encarado como documentação. Mas tenho certeza que isso esteja mais relacionado com a competência do programador, do que com o fato de que código fonte não possa servir de documentação. E de qualquer forma, digitadores de luxo nunca foram a melhor opção.

Vejo que na maioria dos casos, o simples é a melhor opção. Muitas vezes, papel, caneta e alguns rabiscos podem representar da melhor forma possível o comportamento de uma funcionalidade ou regra negocial. Geralmente uma boa conversa entre a equipe, pode economizar muitas horas de trabalho em ferramentas de modelagem e ganhar muito tempo de programação no projeto.
A UML é uma boa pedida, para promover comunição entre equipes, na validação de arquiteturas ou na verificação de algum ponto mais complexo do sistema. Mas o faça, quando a equipe sentir essa necessidade ou quando a complexidade do projeto exigir isso.
Modele em código fonte quando possível e cuide dele, faça do refactoring um hábito.
Não torne a geração de diagramas obrigatória para todos os projetos. Documente o necessário e corte as “gorduras”. Não burocratize demais. Não crie checklists demais. Não formalize em excesso.

E se ainda assim você optar em continuar documentando tudo. Pelo menos, economize papel e pense antes de imprimir. Porque afinal de contas, toda essa papelada vai servir pra que ?