Página 10 de 10

IntelliSense do SQL Server 2008

Se você já usou o SQL Server 2008, já deve ter visto que ele consegue auto-completar nomes de campos e tabelas, além de exibir erros de sintaxe. Este é o “novíssimo” IntelliSense.

O problema é que ele não funciona 100% e tem sérios problemas com cache, pois ao criar novas colunas e tabelas, é difícil fazer ele reconhecer essas alterações.

Vários colegas comentaram esse recurso acaba mais atrapalhando do que ajudando.

Se você compartilha da mesma opinião, fica a dica. Basta clicar no botão da imagem:

Além disso, no menu “Edit > IntelliSense”, você encontra várias opções, como “Refresh Local Cache”, o que significa que ele vai atualizar seu cache local com relação à estrutura da base de dados.

Porém, em alguns testes que fiz, o cache só atualizou mesmo reiniciando o programa… mas quem sabe você pode ter mais sorte!

Cuidado com o ADD_MONTHS do Oracle

Sabe aqueles erros esquisitos onde você olha o código é pensa: “não é possível, tá tudo certo…”?

O cenário

Há muito tempo, trabalhei na migração de diversas procedures de um sistema financeiro de SQL Server para Oracle. Eram procedure complexas com milhares de linhas, muitos cursores e algumas péssimas práticas.

A princípio, a ordem era para migrarmos tudo manualmente. Mas, depois de analisar algumas ferramentas de migração automática, descobri que se fizesse alguns ajustes nas procedures em SQL Server poderia migrá-las inteiramente para Oracle usando o SQL Developer, disponibilizado gratuitamente pela Oracle.

Ao migrar uma procedure, o  SQL Developer utiliza algumas rotinas de adaptação para o Oracle, que deve estar disponível num package chamado qlserver_utilites. Fiz um parser simples que substituía as chamadas a esse package por funções nativas do Oracle, evitando criar código desnecessário e que diminuiria a performance.

Escrevi um documento com os ajustes necessários e se tornou o padrão do projeto. Assim conseguimos manter o código-fonte único.

Entretanto, identificamos que algumas operações específicas do sistema geraram lançamentos com valores estranhos, mas a maioria estava correta. No caso, o cálculo envolvia períodos de datas e a primeira observação é que a data inicial do período era dia 30, o último do mês.

Cálculos daqui, cálculos dali, verificou-se que, apenas para esse tipo de período, a procedure estava calculando um dia a mais numa diferença entre as datas. Uma dessas datas era calculada somando-se um número X de meses.

A origem do problema

No Oracle, a rotina usada para somar datas é ADD_MONTHS. Seria o equivalente de DATEADD do SQL Server.

Entretanto, essa rotina segue um padrão ANSI muito esquisito:  se a data é o último dia do mês, ao somar X meses, o resultado será sempre no último dia do mês.

Vamos supor que a data fosse 28/02, ao somar um mês, o resultado seria 31/03, a não ser no ano bissexto. Para 30/04, por exemplo, somando-se um mês, o resultado seria 31/05.

Isso estava gerando a distorção nos cálculos.

Solução

Foi necessário criar uma function para somar meses e que mantivesse o dia fixo, a não ser quando o mês do resultado tinha menos dias  do que o mês original.

Conclusões

Não confiar na implementação de uma rotina somente pelo nome, principalmente entre softwares tão diferentes.

No caso de migração, analisar a fundo a equivalência de funções, métodos, classes, etc. Se possível, com testes unitários.

Data loading script generator (Oracle and SQL Server)

In software development, there’s a common scenario where we need to transport data between separated environments.

For instance, we routinely have to reproduce customer’s problems. In order to do that, we need the same data. Sometimes we just enter the production environment or request a backup, but in a few cases we aren’t allowed to do that! Some environments have security constraints that makes it impossible to obtain a backup, for example. We can request a query, but it isn’t proper because we want to work with the data.

How we can accomplish that?

Script that generates INSERTs

At first I developed an Oracle PL/SQL script to migrate data between different environments. It worked well so I did a SQL Server T-SQL version too.

Indeed, I’m talking about a procedure that generates INSERT commands from table data. Check out the following examples:

-- Generates INSERTS for all records from table TAB1
EXEC GET_INSERT_SCRIPT
    @TABELA = 'TAB1', -- table name
    @BANCO_ORIGEM = 'MY_DATABASE', -- source database
    @BANCO_DESTINO = DEFAULT, -- target database
    @OWNER = DEFAULT,
    @WHERE = DEFAULT,
    @GERAR_DELETE = 0 -- generate DELETE command?

-- Generates INSERTs for all records from table TAB2
EXEC GET_INSERT_SCRIPT
    @TABELA = 'TAB2', -- table name
    @GERAR_DELETE = 0 -- generate DELETE command?

-- Generates INSERTs for product table, but only when code is 'PROD' and company is 'COMP1'
EXEC GET_INSERT_SCRIPT
    @TABELA = 'PRODUCT', -- table name
    @WHERE = 'ID = ''PROD'' AND ID_COMPANY = ''COMP1'' '

--Generates INSERTs for client table when client code is 123
EXEC GET_INSERT_SCRIPT
    @TABELA = 'CLIENT', -- table name
    @BANCO_ORIGEM = 'MY_DATABASE', -- source database
    @BANCO_DESTINO = DEFAULT, -- target database
    @OWNER = DEFAULT,
    @WHERE = 'ID = 123'

Remarks

In the first example, we set the source database as MY_DATABASE. This parameter is optional if the database is already selected with USE command.

The parameters with DEFAULT value instructs SQL Server to use the default value defined in procedure signature. They could be omitted.

The parameter @GERAR_DELETE defines if the generated script will have a DELETE command to remove the table data before the insertions.

The parameters @OWNER, @BANCO_ORIGEM, @BANCO_DESTINO can also be omitted and only need to be informed if you execute the script from master or from a different database owner. The default owner is dbo.

If these parameters are informed, the “path” to the database objects will be like this:

TARGET_DATABASE.dbo.TABLE

In the second example, the parameter @WHERE adds a filter clause to the generated data and DELETE command. This way we can load data selectively.

We only need be cautious with the output. Management Studio limits the text output size, so my advice is to change the configuration Tools > Options > Query Results > SQL Server > Results to Text > Maximum number of characters... to 4000 (maximum characters per line) or just output to file.

Advantages

  • Store and migrate data in a clear and simple way.
  • Easily see and change all data.
  • Select exactly the data needed. Many tools don’t give you the option to export data selectively.
  • It ins’t necessary deploy any tool. The person who will generate the scripts just need to run a single script.

Potential problems

  • Tables with data types that cannot be represented as text cannot be generated.
  • Large tables will generate huge scripts hard to open in an editor.

Oracle version

The Oracle version haven’t all features I implemented in SQL Server, but as I told you in the beginning, it was successfully used to migrate data between different environments.

Available in

https://github.com/utluiz/database-insert-script-generator

Questions, suggestions, and bug fixes are welcome!

Script de Geração de Carga de Dados (Oracle e SQL Server)

No dia-a-dia do desenvolvimento, é comum precisarmos reproduzir uma determinada situação ocorrida no cliente. Só que precisamos dos dados exatos para isso!

Geralmente solicitamos SELECTs ou backups. Mas e quando não dá?

Em ambientes com restrições onde não é possível solicitar um backup e um SELECT não é suficiente, pois precisamos trabalhar com os dados e não apenas visualizá-los, existe uma alternativa prática para recuperar os dados do ambiente.

Script que gera INSERTs

Inicialmente desenvolvi um script para Oracle em PL/SQL para migração de dados entre ambientes. O resultado foi bom e fizemos também uma versão para SQL Server.

No caso do SQL Server trata-se de uma procedure que, quando executada, gera INSERTS a partir dos dados de uma tabela. Veja os exemplos abaixo:

-- Gera INSERTS para todos os registros da tabela TAB1
EXEC GET_INSERT_SCRIPT
    @TABELA = 'TAB1',
    @BANCO_ORIGEM = 'MINHA_BASE',
    @BANCO_DESTINO = DEFAULT,
    @OWNER = DEFAULT,
    @WHERE = DEFAULT,
    @GERAR_DELETE = 0

-- Gera INSERTs para todos os registros da tabela TAB2
EXEC GET_INSERT_SCRIPT
    @TABELA = 'TAB2',
    @GERAR_DELETE = 0

-- Gera INSERT para a tabela de produtos somente para o produto 'PROD' da empresa 'EMP1'
EXEC GET_INSERT_SCRIPT
    @TABELA = 'PRODUTOS',
    @WHERE = 'CODPRODUTO = ''PROD'' AND LECOLCOD = ''EMP1'' '

-- Gera INSERT da tabela BOLETOS somente para o boleto '123'
EXEC GET_INSERT_SCRIPT
    @TABELA = 'BOLETOS',
    @BANCO_ORIGEM = 'MINHA_BASE',
    @BANCO_DESTINO = DEFAULT,
    @OWNER = DEFAULT,
    @WHERE = 'CODBOLETO = 123'

Observações

No primeiro exemplo, é definido o banco de origem como  “MINHA_BASE”. Esse parâmetro é opcional, se o banco de dados já estiver selecionado (“USE”).

Os parâmetros com valor “DEFAULT” indicam que o SQL deve usar o valor padrão definido pela procedure. Eles poderiam ser simplesmente omitidos.

O parâmetro @GERAR_DELETE define se o script gerado vai conter também um comando “DELETE” para apagar os dados da tabela.

Os parâmetros @OWNER, @BANCO_ORIGEM e @BANCO_DESTINO podem ser omitidos e somente precisam ser usados se houver necessidade de executar os scripts a partir do master ou com um usuário cujo owner é diferente do owner  do banco de dados. O padrão para o @OWNER é “dbo”.

Caso esses parâmetros sejam informados, o caminho para os objetos será escrito como no exemplo:

AB_BANCO_DESTINO.dbo.TABELA

No segundo exemplo, o parâmetro @WHERE faz com que os dados gerados e o DELETE (se houver) contenham o filtro passado. Então também é possível criar uma carga parcial com o filtro desejado.

Somente é preciso tomar cuidado com a saída. O Management Studio limita a quantidade de texto retornado, então é recomendável alterar a configuração  Tools > Options > Query Results > SQL Server > Results to Text > Maximum number of characters... para o valor de “4000” ou simplesmente jogar a saída para um arquivo.

Vantagens

Armazenamento e migração de dados de forma transparente, sendo possível analisar e alterar os dados.

O desenvolvedor pode selecionar exatamente os registros que deseja. São poucas as ferramentas que permitem geração de scripts com filtro por registros.

Não é necessário que a pessoa que vai executá-lo saiba usar uma ferramenta de geração de scripts e tenha que selecionar as tabelas ou até registros manualmente.

Problemas

Tabelas com tipos de dados que não podem ser representados em texto.

Tabelas muitos grandes vão gerar scripts impossíveis de editar.

Versão para Oracle

A versão Oracle atual não tem todas as opções da versão SQL Server, mas já foi utilizada para migração de dados entre ambientes com sucesso.

Disponível em

https://github.com/utluiz/database-insert-script-generator

Dúvidas, sugestões, correções ou apontamento de erros são bem-vindos!

Uma avaliação do play! framework

Há alguns meses, alguém levantou a possibilidade de melhorar o gerenciamento das visitas a clientes na empresa em que trabalho, utilizando um sistema específico.

Consultaram-me sobre a possibilidade de utilizar um sistema opensource, entretanto não encontrei nada nessa linha. Como estava estudando algumas novidades e queria desenvolver algum sistema com elas, no caso o play! framework, vi que a oportunidade era perfeita, pois tratava-se de um sistema de uso interno e de baixíssimo risco, então respondi que em pouco tempo poderia criar um protótipo.

Utilizei o Twitter Bootstrap (que também estava aprendendo) na camada de apresentação e o Hibernate para persistência (depois de desistir do Ebeans, padrão do framework).

O desenvolvimento do protótipo totalmente funcional ocorreu em uma semana. Trata-se de um sistema pequeno, porém como estava usando o play! e o bootstrap pela primeira vez, acredito que foi bem rápido.

Depois das rotineiras mudanças de requisitos e solicitações de melhorias após a apresentação para os usuários, mais dois ou três dias e estava tudo pronto.

O que tem de mais esse tal de play!?

  • Instantâneo: Todas as alterações em telas ou no código java são recompiladas e executadas sem reiniciar o servidor, só é necessário um “refresh”;
  • Depuração: é possível conectar o debugger do Eclipse com a aplicação executando em modo de desenvolvimento, mas nem é tão necessário, pois quando há algum erro no Java ou na tela, a mensagem do framework é tão amigável que mostra, além da pilha, o próprio código fonte e qual o comando ou erro de sintaxe que causou a falha;
  • Sessão: não existe uma session, os únicos valores que são armazenados entre as requisições ficam em cookies criptografados. Isso faz com que a aplicação seja altamente escalável com múltiplas instâncias, embora seja confuso para quem está acostumado com as tecnologias JEE padrão;
  • Threads: não há criação de threads por requisição como nos Servlets, os métodos dos controladores são static e processamentos “demorados” devem ser assíncronos;
  • Totalmente REST: todas as entradas de url são configuradas no arquivo “routes”, como no rails;
GET     /sobre                      controllers.App.sobre()
  • CoC (Convensão sobre Configuração / Convention over Configuration): a ideia é não reinventar a roda, basta executar um comando “play new [nome sistema]” e sair programando, obviamente se você seguir o padrão adotado pelo framework. Já se quiser fazer diferente aí vai ter tanto ou mais trabalho do que num framework tradicional;
  • Builders para as views: as telas, por exemplo, possuem parâmetros e você “invoca” uma tela a partir do código chamando um método de uma classe gerada dinamicamente que recebe os devidos parâmetros, então se você mudar uma tela para receber algo novo, não tem como esquecer de atualizar o código, já que isso vai gerar erros de compilação;
  • Servidor de aplicação: esqueça Tomcat, Glassfish, Weblogic ou Websphere, ele já vem com um servidor leve embutido, o comando “run” inicia a aplicação em modo desenvolvimento e o comando “start” em modo de produção;
  • Ciclo de vida: o framework gerencia o ciclo de vida através de uma ferramenta de build chamada SBT (uma espécie de ANT), gerencia as dependências através do IVY e também é compatível com Maven;
  • Integração com Eclipse: o comando “eclipsify” gera os arquivos necessários para importar o projeto no Eclipse, quando incluir uma nova dependências, basta executar o comando novamente para atualizar o classpath e demais configurações;
  • Banco de dados: integração nativa com JPA, inclusive gerenciando as evoluções da estrutura do banco e gerando a DDL necessária a partir das classes
  • Telas: templates feitos numa mistura de HTML com a liguagem Scala. É simples e rápido para implementar, porém lento demais para compilar.
<select id="cliente" name="cliente">
  @for(opcao <- options(Cliente.options)) {
    <option value="@opcao._1"
      @if(opcao._1 == filtro.cliente) { selected }>@opcao._2</option>
  }
</select>

Pontos negativos

No Eclipse, várias vezes as classes geradas pelos builders não são reconhecidas mesmo dando refresh no projeto e erros em views, por exemplo, são listados mesmo que já estejam corrigidos. Às vezes, só fechando e reabrindo o projeto (usando “Close Project”). Isso não afeta a execução mas fica “feio” ver o projeto com erros que não existem.

A versão 2.x mudou muito em relação à primeira e a maioria dos tópicos encontrados fala da versão 1. Além diso, ela não é uma simples evolução da primeira, mas uma reformulação total, tornando a migração muito difícil. Por exemplo, alguns recursos, tal como a geração de WAR para deploy num container, foram removidos e atualmente só é possível executar a aplicação no servidor embutido.

Apesar do framework suportar Java ou Scala como linguagem de programação, os templates da versão 2 são feitos em Scala por padrão, portanto é necessário aprender um pouco da sintaxe e a curva de aprendizagem aumenta. A linguagem Scala executa na JVM e é eficiente, mas a compilação pode ser bem mais demorada que uma classe comum.

O gerenciamento automático da evolução da DDL pode ser confuso à primeira vista e causar alguns efeitos colaterais se mal utilizada.

Update: Como comentei num post mais recente, uma biblioteca foi removida do repositório, tornando impossível compilar uma versão do sistema com o play 2.0 e obrigando os desenvolvedores a migrar para a versão 2.1. 

Resumo

No geral as implementações dos diversos aspectos do play! framework usam outras ferramentas já bem conhecidos, tal como o Hibernate, a linguagem Scala, o gerenciador de dependências IVY, etc. O uso dessas e outras tecnologias já consagradas é uma ótima base para se desenvolver, aumentando a confiança nos resultados.

Desde que seguidos os padrões do framework e depois que se pega o jeito dele, fica muito fácil sair implementando novos requisitos. O maior problema no começo é se despender do conceito de JSP/Sevlet que está tão arraigado no mundo Java.

Enfim, o play! framework é muito bom para projetos pequenos e rápidos. Para algo maior, com uma vida útil mais longa, maior risco ou com uma equipe que não conheça a tecnologia, não recomendaria no momento, por dois motivos: a documentação não é muito completa e os desenvolvedores não tem um compromisso em manter compatibilidade, corrigir bugs críticos ou implementar funcionalidades que eles não considerem importantes.

Por outro lado, com o estudo de frameworks como este, é possível extrair algumas boas práticas e conceitos importantes, aplicando de outras maneiras mesmo em tecnologias mais tradicionais.

Bootstrap, uma biblioteca CSS

O desafio

Implementar sistemas baseados na web pode se tornar uma tarefa difícil se for necessário sempre começar sem um layout bem definido.

O grande problema em criar um interface “do zero” é que ela provavelmente terá que passar por muitas iterações até ficar estável e o escopo dela será limitado. Sem falar nas diferenças entre navegadores que exigem hacks nos estilos e no javascript para funcionar de forma semelhante em todos eles.

Criar um layout reaproveitável e que se adapte a muitas situações é um grande desafio e muitas tentativas já foram feitas, muitas das quais vinculadas a uma tecnologia específica.

Uma solução

Há algum tempo descobri que os desenvolvedores do Twitter, pensando em todos esses desafios, criaram uma biblioteca usando CSS e um pouco de javascript para facilitar a vida dos desenvolvedores. Ela chama-se bootstrap, ou seja, a ideia é dar um ponta-pé inicial e evitar que se reinvente a roda a todo momento.

Esta biblioteca traz componentes web reaproveitáveis, muito flexíveis, fáceis de usar e desvinculados de qualquer tecnologia específica do lado do servidor.

O layout gerado por essa biblioteca é muito bem pensado e consegue se adaptar a todo tipo de dispositivo, desde monitores grandes até tablets e celulares em retrato ou paisagem. E o melhor de tudo é que ela é compatível com a grande maioria dos navegadores atuais:

  • Internet Explorer 7 ou superior
  • Google Chrome
  • Mozilla Firefox
  • Opera
  • Safari

Exemplificando tudo isso, basta conferir o visual de uma das telas de um sistema que fiz usando o bootstrap. O CSS específico do sistema possui apenas 150 linhas. Todo o restante foi reutilizado do bootstrap: barras fixas de navegação, botões, submenus, hints, cores, tabelas, campos e ícones.

sistema-bootstrap

Tecnologias envolvidas

bootstrap faz uso da tecnologia LESS (dynamic stylesheet language), que é uma linguagem que gera folhas de estilo CSS, mas possui variáveis e funções, permitindo personalizar o CSS final com suas cores prediletas e outras customizações de forma automática.

É impressionante a capacidade atual do CSS 3 em gerar interfaces bonitas e “responsivas”, o que significa que com um único CSS a página web adapta-se a diferentes orientações e tamanhos de telas dinamicamente, sem necessidade de código.

A parte de javascript que complementa a biblioteca baseia-se no jQuery e dá suporte ao dinamismo que foge ao escopo do CSS, por exemplo, ao capturar eventos e posicionar os “Pop Overs” (uma espécie de hint mais elaborado, com título) sobre os elementos.

Quer testar?

Acesse o link http://twitter.github.com/bootstrap/ para ver toda a documentação auto-exemplificada que utiliza a própria bibliteca.

Para usar é preciso apenas saber html e um pouco de CSS.

Conclusão

bootstrap é ótimo para criar sistemas rapidamente e vai evitar que muitos programadores criem sistemas em amarelo com bolinhas marrons ou fiquem “amarrados” com um determinado tipo de layout da tecnologia utilizada.

Entretanto é uma biblioteca generalista e não substitui os designers que  produzem layouts para necessidades específicas.

Na verdade, designers podem conviver muito bem e até utilizar bibliotecas desse tipo a fim de evitar retrabalho, personalizando aquilo que for necessário.

Reflexões sobre a natureza do software e das estimativas de software

Ao escrever minha monografia sobre técnicas de estimativas de software ágeis e “tradicionais”, comecei achando que conseguiria definir o melhor método de todos, pelo menos para determinados casos.

Entretanto, após orientação e pesquisa, enquanto escrevia sobre o assunto, acabei chegando a uma das “piores” e óbvias conclusões: isso é impossível.

O motivo é simples (pelo menos após a devida reflexão): o software é abstrato, complexo, mutante e intangível.

O que isso significa? Resumindo:

  • Você não pode medir objetivamente um software;
  • Você não pode simplificar (abstrair) um software sem perda de informação;
  • Você não pode definir estaticamente um software.

Anteriormente, pensava que as já conhecidas métricas de software eram confiáveis. Mas quem pode medir o tamanho de um software? Linhas de código realmente refletem o “tamanho” do sistema? Como afirmar que um sistema é mais confiável que outro? Ou, como medir a usabilidade?

A verdade é que, dado um mesmo requisito, há uma implementação para cada programador que já viveu, que vive e que surgirá na terra!

Um autor afirmou que os requisitos de software mudam, em média, 25% desde que os requisitos foram levantados até a primeira versão. O software é mutante! Não que ele tenha caído num tambor de lixo tóxico ou teve seu DNA alterado por radiação, mas porque os negócios e suas necessidades mudam.

Infelizmente, estimativas de software sofrem do mesmo mal. É impossível afirmar categoricamente que uma determinada estimativa é melhor que qualquer outra.

No fim, como tudo que envolve software, o que conta é o talento das pessoas envolvidas. Algumas pessoas estimam melhor que outras, mas não são o estudo, a experiência e o método científico que tornam isso possível. É simplesmente algum tipo de intuição subjetiva, que pode ser melhor ou pior aproveitada ao se utilizar uma determinada técnica.

Estimar é simplesmente “chutar”. É um erro acreditar que qualquer estimativa é um número matemático que você pode jogar numa fórmula e obter um resultado qualquer, por mais tentador que isso pareça. Fazemos por necessidade, mas isso consiste apenas como um chute em cima de outros.

Se você estivesse indo apostar que seu time ganharia de dois a zero contra outro e, no meio do caminho, lesse uma matéria no jornal que algumas contratações deixaram seu time duas vezes melhor, você aumentaria a aposta para quatro a zero?

O único meio de fazer comparações significativas e objetivas entre softwares, estimativas e técnicas de estimativa é utilizando critérios específicos.

Por exemplo, o software S1 pode processar uma quantidade Q de informação num tempo T, enquanto S2 processa Q em T+1. Especificamente no quesito eficiência, S1 é superior a S2, mas essa informação não agrega nada nos demais aspectos de um sistema de software.

Da mesma forma, uma determinada estimativa pode se mostrar melhor que outra por se aproximar mais da realidade concretizada, mas isso em nada prova que ela é superior, pois existem fatores demasiadamente complexos para que alguém possa fazer tal afirmação.

Quanto às técnicas de estimativa, escreverei em breve.

Conclusão

Estimativas são… estimativas.

É errado pensar em estimativas como medidas numéricas absolutas.

É errado considerar estimativas como a palavra final para o planejamento e o cronograma.

É errado acreditar que quanto mais detalhadas as estimativas melhor ou mesmo que é possível garantir uma determinada precisão.

McConnell, em seu livro “Estimativas de Software: Desmistificando a Magia Negra” (Software Estimation: Demystifying the Black Art) afirma que é preciso definir e diferenciar conceitos, tais como:

  • Estimativas são estimativas, não um compromisso;
  • Compromisso é quando a equipe se dispõe a cumprir um determinado cronograma;
  • Cronograma é o planejamento no tempo, o qual pode ou não ser baseado em estimativas.

Nota: repare no título sugestivo do livro de McConnell. Estimar não é quase como tentar prever o futuro?

DRY + HTML 5 Boilerplate + Initializr

Você já ouviu falar sobre o conceito DRY? Don´t repeat yourself!

Segundo a Wikipedia:

Don’t repeat yourself (em português: Não repita a si mesmo) ou também conhecido pelo acrônimo DRY é um conceito de programação de computadores o qual propõe que cada porção de conhecimento em um sistema deve possuir uma representação única, de autoridade e livre de ambiguidades em todo o sistema. Esta expressão foi cunhada por Andy Hunt e Dave Thomas em seu livro The Pragmatic Programmer. Se este conceito for aplicado, a modificação de uma parte do sistema não leva a modificações em outras partes não relacionadas.

In another words: do not reinvent the wheel!


Em se tratando de HTML, não sei quantos já tentaram fazer um site usando Notepad, Front Page, Word, Dreamweaver ou algum outro editor de HTML. Mas uma coisa é editar HTML, outra é fazer uma página se mostrar correta e funcional em toda a gama de navegadores e dispositivos. É muuuito difícil. Você precisa caçar todas as boas práticas e dicas de como estruturar HTML, associar CSS e programar em Javascript.

Além disso, é raro conseguir reaproveitar código, estilos e imagens de forma modular e as soluções acabam sendo restritas e específicas. Muitas soluções incluem código específico para navegadores diferentes e diversos hacks para navegadores antigos. Com tantas novidades no HTML 5, muita gente ainda está deixando de aproveitar o seu potencial.

Porém, se já existem pessoas que se preocupam só com isso e possuem muita experiência nessa área, por que reinventar a roda?

O desenvolvimento de páginas parecia esquecido e abandonado num mundo movido a classes, interfaces, instâncias, bibliotecas, componentes, frameworks, etc. Até agora!

Frameworks Web

Para resolver esse problema foram criadas algumas soluções modulares que trazem reuso, compatibilidade, padrões e boas práticas para o desenvolvimento web. Por falta de um termo melhor, vamos chamá-las de frameworks web.

Além de normalizar a aparência de uma página, os frameworks usam os recursos mais modernos no que se refere a HTML. Mas não é só isso, se bem utilizados é possível conseguir compatibilidade com navegadores do século passado! É isso mesmo, alguns deles oferecem a possibilidade de usar recursos do HTML 5 e, de brinde, ser compatível com Internet Explorer 6!

Um deles é o Twitter Boostrap que apresentei num outro post. O problema dele é que você ainda fica por conta para estruturar o site ou sistema web, embora você possa usar um dos exemplos para isso.

Mas então surgiram algumas iniciativas de prover uma estrutura básica sólida mais completa para a estruturação de HTML. Uma delas é o Boilerplate. Ele provê algo como um molde, ou seja, uma estrutura básica de HTML bem estruturado, incluindo as bibliotecas jQuery e Modernizr, arquivos de configuração para o servidor (.htaccess para Apache, robots.txt, etc.).

O site http://www.initializr.com/ vai um passo a frente e permite a você decidir qual será a estrutura básica do site! O interessante é que tudo é feito reutilizando outras tecnologias, nesse caso, o Initializr usa o Boilerplate e o Bootstrap, além de outras.

Veja as opções:

Após selecionar as tecnologias desejadas, você clica num botão de download e pronto! Para conferir um exemplo, clique aqui e faça o download.

Suposições

Obviamente, toda solução pré-fabricada faz suposições sobre boas práticas e tecnologias utilizadas. No entanto, algumas pessoas, por exemplo, não usam jQuery.

Dependendo do resultado desejado, utilizar uma estrutura básica pré-definida pode não ser a melhor ideia.

No entanto, seguir padrões gerais usados na web traz benefícios, principalmente em produtividade.

Alternativas

Além dos frameworks apresentados, existem outros que podem se adaptar melhor em determinados casos ou que suprem necessidades específicas.

Eis alguns:

Alguns deles poderiam ser classificados como Frameworks de Script ou Frameworks CSS.

Benefícios

Resumindo, usar um framework web…

  • Acelera o desenvolvimento;
  • Evita muitos problemas comuns e conhecidos;
  • Facilita a compatibilidade com o universo de dispositivos e navegadores;
  • Aumenta o desacoplamento da camada de apresentação com as demais camadas e com tecnologias específicas;
  • Permite a reutilização de componentes web independentes sem necessidade de implementar componentes numa determinada tecnologia;
  • Fácil integração com qualquer tecnologia que gere HTML;
  • Desacopla o HTML dos javascripts utilizados, evitando a implementação de trechos hard-coded.

E você? Vai entrar na onda dos boilerplates?

Da anarquia à otimização: maturidades do processo de desenvolvimento de software

Em seu artigo From Anarchy to Optimization, McConnell analisa um estudo do Instituto de Engenharia de Software (SEI, em Inglês) do Departamento de Defesa norte americano, a respeito da efetividade do processos de desenvolvimento de software praticados.

Veja a seguir como o autor descreve os cinco níveis de maturidade.

Os níveis de maturidade do SEI

I. Anarquia

Não há planejamento nem gerenciamento. O desenvolvedor faz o que pode e espera que tudo dê certo.

II. Folclore

Nessa altura o desenvolvedor ganhou experiência num tipo específico de sistema. Ele realiza alguma espécie de planejamento, estimativa e gerenciamento, acreditando que desenvolveu um processo de trabalho efetivo. A empresa depende fortemente dos desenvolvedores que, se deixam o emprego, levam embora todo seu conhecimento. O sucesso depende dos novos projetos serem semelhantes aos anteriores e geralmente há problemas com novas ferramentas e domínios diferentes.

III. Padrões

A mitologia da empresa é documentada em forma de padrões, assim o processo não é mais dependente de indivíduos. Porém não há dados e métricas para análise e comparação da eficácia do processo. O fato de haver documentação não significa que o processo é bom, então os programadores geralmente discutem o valor do processo em geral.

IV. Medidas

Dados brutos do processo são coletados para medir sua eficiência e possibilitam a comparação e o julgamento com outros processos de forma objetiva. Isso acaba com a discussão subjetiva do nível anterior.

V. Otimização

Com a documentação e as métricas, a empresa começa a melhorar o processo. Ferramentas automatizadas de coleta de métricas são usadas para acelerar ainda mais o processo.

Suponha que a empresa mediu o número de defeitos por linhas de código. Ela então cria uma variação do processo original e mede o resultado. Se este for positivo, a variação se torna o novo padrão de processo.

Benefícios

Você pode estar se perguntando se investir na melhoria dos processos vela realmente a pena. Para responder a isso, o autor utiliza dados obtidos por Alfred Pietrasanta.

Alfred acompanhou uma empresa chamada Lockheed num programa de melhoria do processo de desenvolvimento de software por cinco anos. Nesse tempo, eles partiram do nível 1 e chegaram até o nível 3, obtendo resultados substanciais e tangíveis. A tabela abaixo representa numericamente os benefícios de um projeto típico de 500 mil linhas de código:

Nível Custo de desenv. (milhões) Tempo de desenv.
(meses)
Qualidade
(defeitos / KLOC)
Produtividade
(LOC/Hora)
Produtividade
($/LOC)
1 33 40 9 1 66
2 15 32 3 3 30
3 7 25 1 5 14
4* 3 19 0.3 8 6
5* 1 16 0.1 12 2

* Os resultados desses níveis são apenas projeções, já que a empresa chegou apenas até o nível 3.

Nos cinco anos, a Lockheed melhorou a produtividade em 5 vezes e reduziu a quantidade de defeitos em quase 10 vezes. Resultados semelhantes foram obtidos em projetos da IBM, Motorola e Xerox. A empresa Hughes Aircraft relatou que um investimento único de $ 400 mil na melhoria do processo para 500 empregados está agora dando um retorno de $ 2 milhões ao ano.

Conclusão

Embora o artigo seja relativamente antigo, a verdade é que o cenário de TI pouco mudou no que se refere à maturidade das empresas, o que prova que realmente não existem “balas de prata” (soluções mágicas) quando se fala em desenvolvimento de software.

Portanto, a receita continua a mesma: é necessário investir constantemente para colher melhores resultados no desenvolvimento de software.

Estudo de caso: experiência com arquitetura RESTful

Trabalhei recentemente num projeto de desenvolvimento de um sistema interno para a empresa, no qual os analistas de suporte, desenvolvimento ou negócios deverão registrar com antecedência as visitas aos clientes e incluir anexos como documentos e e-mails relacionados às visitas.

Tratando-se de um projeto de baixo risco, encontrei uma ótima oportunidade de realizar experimentos arquiteturais e conferir na prática algumas tecnologias que nunca foram usadas por aqui, principalmente relacionadas à arquitetura REST.

O sistema de Agenda de Visitas

O sistema contém uma tela inicial que lista as entradas da agenda, incluindo filtro e ordenação. Os filtros são persistidos em cookies que expiram após alguns dias, então o usuário vê a tela inicial do sistema da mesma forma que havia deixado na última visita.

Para incluir ou alterar uma entrada o usuário deve autenticar-se. Ele somente poderá editar entradas em seu próprio nome a não ser que seja um líder de equipe. Aqui estão requisitos de autenticação e autorização.

Ao incluir ou alterar uma entrada, é possível incluir ou remover anexos, além de alterar sua descrição a qualquer momento.

Um relatório (PDF ou XLS) com as entradas de um período pode ser emitido por qualquer usuário.

O sistema possui log para todas as ações e é possível emitir um relatório de “quem fez o que e aonde” num período de sistema.

sistema-bootstrap

Iniciando com o play! framework

Na primeira iteração do projeto, após a reunião inicial de levantamento de requisitos, adotei o play! framework para criar o primeiro protótipo, o qual fornece uma pilha de tecnologias pré-definidas e promete um desenvolvimento ágil e agradável.

Em geral, gostei bastante do play!. Embora eu acredite ele carece de amadurecimento em muitos aspectos, a codificação e os resultados obtidos são bastante satisfatórios. Depois que se "pega o jeito", novas funcionalidades são agregadas muito rapidamente ao sistema. O framework segue a linha do Rails e utiliza adota fortemente o conceito de CoC (Convention over Configuration – Convenção antes de Configuração), então as aplicações funcionam sem necessidade de criar XML’s ou qualquer configuração complicada. O ponto fraco desse conceito é que se você quiser “fugir” do padrão poderá ter grandes dores de cabeça. A documentação é simples e bem-feita, mas não completa. Precisei andar bastante nos fóruns.

Para as classes de domínio e a persistência das mesmas adotei o padrão DAO com JPA (Hibernate). No mais, os controladores foram feitos no estilo play! e as views em templates Scala (na verdade, um misto de HTML com expressões em linguagem Scala), que são o padrão da versão 2.0 do framework.

A camada de apresentação, renderizada no navegador do usuário, foi implementada em HTML 5 com toques de jQuery. Usei a “estilosa” biblioteca Bootstrap, que fornece componentes visuais muito bons e altamente portáveis entre os diversos navegadores. Nunca me arrependi de tê-la usado.

O desenvolvimento e depuração com o play! merecem destaque, pois o mesmo exibe mensagens muito amigáveis sempre que há problemas em código Java ou nos templates Scala. O resultado nem sempre é perfeito, houve um momento ou outro em que foi difícil achar a causa, mas em geral foi muito mais fácil depurar do que outros frameworks conhecidos.

Os problemas

Após o primeiro ciclo de implementação dos requisitos iniciais, o sistema precisava ser entregue para homologação. Aqui as restrições do play! começaram a surgir. Como toda empresa que trabalha com JEE, usamos como padrão servidores de aplicação como Tomcat, Weblogic e Websphere. Porém, o play! 2.0 não suportava deploy para o formato WAR, embora fosse possível na versão 1.x. As aplicações do play! são distribuídas em pacotes standalone que rodam uma versão do Jetty e escutam por padrão a porta 9000. Para contornar essa limitação criei um manual de instalação exclusivo para essa tecnologia, mas ainda assim houve dificuldade por parte dos analistas de suporte que estão acostumados com servidores de aplicação tradicionais. Além disso, depois de desfeita a confusão, tive que ajudar a configurar a inicialização automática da aplicação num servidor Windows utilizando parâmetros específicos do play! de acesso a banco de dados, porta, etc. Tudo isso poderia ser evitado com a opção de deploy em formato WAR, mas os desenvolvedores optaram por mudar o framework de tal forma que a versão 2 não é compatível com a anterior de forma alguma, nem há um processo natural de migração (upgrade ou downgrade), então descartei essa possibilidade logo de início.

Outra dificuldade foi a falta de uma configuração do path base da aplicação, ou seja, ela só funciona na “raiz” do servidor. O play! gera sempre URLs absolutas. O problema é que a aplicação seria disponibilizada para os diferentes setores da empresa através de um proxy reverso, logo todos os links da aplicação precisariam ser reescritos como http://servidor/aplicacao/. Resolvi a questão usando uma branch do core do framework que permitia alterar a raiz da aplicação através de uma nova configuração e assim os links seriam gerados corretamente. Feito isso, tudo funcionou perfeitamente… pelo menos por um tempo.

A última gota foi quando recebi o retorno da homologação solicitando alterações no sistema (alguns requisitos novos e outros modificados). Parti para a segunda iteração, fiz algumas modificações, mas o play! simplesmente não conseguia mais compilar as classes e views. Depois de algumas horas tentando entender o motivo, descobri que algumas bibliotecas da versão 2.0 foram removidas do repositório Ivy pela própria equipe responsável pelo framework com a justificativa de estarem com problemas. A solução foi migrar para a versão 2.1, porém os problemas com o path base da URL voltaram, pois esta funcionalidade não havia sido incluída na HEAD e não havia uma branch da versão 2.1 com a nova configuração que eu necessitava. O único caminho seria aplicar manualmente as modificações necessárias na versão 2.1 e recompilar o framework… ou mudar de tecnologia.

Brincando com JAX-RS

Em paralelo a essas experiências, também vinha estudando o JAX-RS (Java API for RESTful Web Services) e realizado alguns testes com o framework Jersey. Além de ser uma API bastante fácil de usar, achei promissora em vários sentidos. De certa forma a codificação de controladores em JAX-RS é semelhante ao play! (que também usa REST), o código fica conciso e a assinatura dos métodos é ainda mais flexível.

Decidi apostar numa mudança e, embora ainda enfrentasse o início da curva de aprendizado da API, a migração para JAX-RS com Jersey foi concluída em menos de uma semana. É claro que nem tudo foi um mar de rosas, houveram várias dificuldades. A documentação oficial do Jersey deixa muitos pontos em aberto e a internet está cheia de exemplos defasados pelos fóruns.

Um ponto complicado foram os uploads, pois como já comentei, havia uma funcionalidade de envio de múltiplos arquivos usando o plugin jquery-file-upload e foi difícil encontrar o parâmetro necessário (que é FormDataMultiPart) que funcionasse na versão mais recente do Jersey.

Além disso, tive que estender a classe de tratamento de cookies, mas o culpado (e quase sempre é ele) é o Internet Explorer por não respeitar o cabeçalho MAX-AGE. Outro problema que envolveu o IE e uploads foi relacionado aos nomes dos arquivos enviados para o servidor. O IE envia o caminho absoluto dos arquivos de upload sem “escapar” as barras de diretórios. O resultado obtido pela API do Jersey é algo como c:\diretorio\arquivo.txt. Tanto no caso do cookie quanto do upload, os desenvolvedores do Jersey se negaram a contornar essas situações (leia-se: fazer gambiarras específicas para o IE), logo cabe ao desenvolvedor da aplicação contornar manualmente esses problemas. Pelo menos existem pontos de extensão suficientes para isso, embora carentes de documentação.

No geral fiquei muito satisfeito com o Jersey, principalmente com a possibilidade de estender as classes que permitem transformar o corpo da requisição em objetos Java e vice-versa (usando as interfaces MessageBodyWriter e MessageBodyReader), assim o mapeamento do request para objeto e de objeto para o response fica completamente transparente.

Abandonando JPSs

Outra escolha marcante da segunda iteração foi o uso da biblioteca FreeMarker para escrever a saída em HTML. Encontrei nela uma linguagem de marcação de templates simples, poderosa e extremamente eficiente.

Havia feito algumas pesquisas sobre benchmarks de template engines porque, após conviver bastante tempo com JSP e JSF eu já estava cansado da limitação, da lentidão e das dificuldades encontradas nessas APIs para criar lógicas simples de apresentação. O FreeMarker se mostrou uma das melhores opções, não possuindo dependências, sendo extensível e compacto.

O fato é que o JSF, principalmente nas versões mais novas, até pode já trazer componentes prontos e fáceis de usar, mas na maioria das vezes isso inclui alto grau de acoplamento com a implementação escolhida e com o visual da aplicação. O desenvolvedor que gosta de liberdade e flexibilidade, sem abrir mão da performance, irá preferir uma biblioteca como o FreeMarker ou Grails, que não agregam uma pilha enorme às tecnologias do projeto.

Substituir as marcações Scala pela sintaxe do FreeMarker não foi muito dispendioso depois de ter feito a configuração básica dos templates. A performance é excelente e a maior parte da sintaxe é simples e agradável.

Conclusões

Primeiramente, achei o play! framework promissor, mas em ambientes já dominados por tecnologias JEE ou com determinadas restrições, dificuldades oriundas da imaturidade do projeto podem surgir e acabar com a “mágica” de soluções inovadoras como esta.

A arquitetura REST é excelente para se trabalhar, pois facilita ao desenvolvedor pensar no sistema em termos de serviços. Este é uma das razões que tornaram a migração do play! para o Jersey fácil, pois não foi preciso alterar nenhum URL.

A API JAX-RS, na minha opinião, é uma escolha certeira para a web. Porém, não estou me referindo apenas a enviar e receber dados em JSON ou XML, mas também HTML sobre HTTP.

Não acoplar as diferentes camadas da arquitetura permitiu a troca de tecnologia de forma razoavelmente rápida e com introdução de poucos bugs. Mais um ponto positivo para bibliotecas como o Bootstrap e mais um motivo pelo qual eu não recomendo tecnologias que “amarrem” diferentes as camadas. O planejamento da arquitetura deve levar em consideração o acoplamento entre os componentes utilizados. Se tivesse adotado inicialmente o JSF ou Vaadin, por exemplo, e tentasse trocar de tecnologia, teria que reescrever praticamente a aplicação inteira.

Há frameworks que prometem uma solução completa, uma pilha tecnológica que vai da persistência à visão. Embora sejam bons para desenvolvedores menos experientes ou que simplesmente não querem lidar com decisões arquiteturais, eles não trarão a longo prazo todos os benefícios de uma arquitetura bem pensada e, pelo contrário, poderão se tornar barreiras à evolução do software. A tendência é que a tecnologia estacione no tempo, como é o caso do framework Demoiselle, iniciativa da SERPRO que pretendia criar um modelo completo para o desenvolvimento de aplicações para o governo.

Por outro lado, usar componentes arquiteturais independentes, conectando-os para formar a arquitetura do sistema, apesar de inicialmente ser mais trabalhoso, compensa ao longo do tempo. Uma vez definida uma boa arquitetura básica (por exemplo: persistência, modelo, controle, visão e apresentação) é possível atingir um alto grau de flexibilidade e baixo acoplamento, além de extrair o melhor de cada camada usando a tecnologia adequada e não aquela que vem de “brinde” com o framework. Aliás, essa é a tendência de muitos frameworks modernos. Os desenvolvedores os dividem em módulos e permitem o uso das componentes independentemente uns dos outros. Outra tendência, como no caso do Jersey, que faz mapeamento nativo de e para JSON, XML e JAXB, é o aumento da interoperabilidade e extensibilidade dos frameworks através de APIs e configurações específicas.

Finalmente já é de senso comum que, por melhor que seja um framework, ele não vai atender todos os diferentes requisitos arquiteturais do mercado.

Página 10 de 10

Creative Commons O blog State of the Art de Luiz Ricardo é licenciado sob uma Licença Creative Commons. Copie, compartihe e modifique, apenas cite a fonte.