segunda-feira, 16 de novembro de 2009

Refatorar ou reescrever?

Uma situação que já presenciei algumas vezes é alguém dizendo: “devemos reescrever essa aplicação do zero”. Mas, realmente vale a pena? E quais as situações que levam a isso?

Nas situações que presenciei, normalmente haviam dois possíveis motivos: o código era muito ruim ou houve uma grande evolução tecnológica desde que a aplicação foi escrita.

Repare que ambos os motivos são de ordem tecnológica, não tendo nada a ver com o negócio em si.

Vamos reescrever!!!

Todo o desenvolvedor gosta de criar algo novo, dificilmente alguém gosta de manter um código existente e, principalmente, escrito por outros. Quando vemos um código ruim, sempre pensamos “eu poderia fazer muito melhor” e “é melhor jogar todo esse código fora e começar do zero”.

O mesmo ocorre quando uma tecnologia antiga é utilizada em um software.

Sempre temos algumas desculpas para reescrever:
  • A tecnologia atual é muito melhor;
  • Dessa vez vamos fazer bem feito, deixaremos o código correto;
  • Entendemos melhor o produto, não vamos cometer os mesmos erros;
  • Reescrever o produto vai ser rápido, afinal, todos os requisitos já foram levantados.

Mas, nem sempre é como esperamos

Certo, decidimos reescrever toda a aplicação. Vamos deixa o antigo código de lado. Utilizamos a antiga aplicação para olhar os requisitos e copiamos o funcionamento dela em uma aplicação novinha em folha.

Aos poucos alguns problemas vão surgindo. Alguns percebemos de imediato, outros só aparecem quando já é muito tarde:
  • Os requisitos estão embutidos no código fonte: mesmo que a aplicação tenha uma ótima documentação, não podemos confiar totalmente nela. Sempre há detalhes que só estão presentes na aplicação em si. Pequenas correções, algumas features e outros pequenos detalhes. Se olhamos apenas para a documentação, deixamos passar esses detalhes, e mesmo ao se basear no código fonte, certamente muitos detalhes passarão despercebidos;
  • O mundo não para de girar: enquanto a nova aplicação é escrita, a antiga continua sendo utilizada. Sempre será necessário incluir um novo recurso ou corrigir um bug. Nesse meio tempo, enquanto reescrevemos a aplicação, toda o desenvolvimento tem que ser duplicado, é feito na versão antiga e na nova. Além disso, evitamos adicionar qualquer recurso na versão antiga, afinal, o cliente que espere a versão nova e nela fazemos isso. Infelizmente, não é bem assim que funciona na prática;
  • Vai demorar tanto quanto a primeira versão ou ainda mais: a ilusão de que o desenvolvimento será rápido logo cai por terra. Criar uma aplicação baseando-se em outra é uma tarefa difícil, além disso, temos que manter as duas versões até que a nova esteja pronta;
  • A nova versão só poderá ser utilizada quando estiver pronta: para tirar proveito da nova aplicação precisamos esperar que ela esteja 100% concluída. Nesse meio tempo, ela não adiciona nenhum valor aos desenvolvedores e nem ao cliente. Imagine se, por algum motivo, o projeto é cancelado. Todo o código desenvolvido é perdido sem nunca ter tido nenhum valor.

Então, como fazer?

A melhor tática é refatorar a aplicação existente, fazendo ajustes de forma gradual até que todo o sistema esteja da forma que desejamos. Já escrevi a respeito de como utilizar a orientação a objetos para nos ajudar nessa refatoração (veja Parte 1, Parte 2 e Final).

Podemos alterar pequenas partes do sistema ou até mesmo jogar toda uma parte fora, porém, não o sistema inteiro.

Ao fazer ajustes graduais na aplicação evitamos toda a dor de cabeça gerada pela reescrita da aplicação inteira. É claro que normalmente é mais difícil ajustar uma aplicação do que reescrevê-la, mas no final das contas, vale a pena.

Quando reescrever?

Em algumas situações realmente vale a pena reescrever totalmente a aplicação. Uma aplicação desktop que precisa ser reescrita para web por exemplo, envolve uma mudança grande de tecnologia, nesse caso vale a pena reescreve-la totalmente.

Mesmo quando decidimos reescrever uma aplicação é recomendável ter uma estratégia de como fazer isso de forma gradual. Implementando as partes mais importantes na nova versão e deixando as duas versões viverem em conjunto enquanto essa migração é feita.

Um artigo bastante interessante escrito pelo Joel Spolsky também fala a respeito disso. Recomendo a leitura: Things You Should Never Do

terça-feira, 3 de novembro de 2009

Criando um protótipo rapidamente com Balsamiq Mockups

Frequentemente precisamos criar um protótipo de tela, seja simplesmente para mostrar uma idéia ou para mostrar para o cliente e verificar se é isso mesmo que ele deseja.

Nesse momento temos duas opções:
  • Criar o protótipo real, exatamente da maneira como será o resultado final;
  • Criar um esboço, destacando apenas aquilo que nos interessa;
login
Eu evito ao máximo ter que criar um protótipo fiel a realidade, primeiramente pelo trabalho, mas principalmente porquê isso acaba virando um compromisso. Na hora de implementar somos obrigados a seguir a risca aquele protótipo, e como bem sabemos, na hora de implementar nem sempre podemos seguir a risca o que desenhamos.

Minha primeira opção ao criar um esboço é o bom e velho papel e caneta, ou um quadro branco se disponível. Porém, na maioria das vezes isso não é suficiente, precisamos enviar a imagem por e-mail a outras pessoas, anexá-la a documentos, etc. Nesse caso, como não tenho habilidades artísticas e tampouco sei trabalhar muito bem com ferramentas de edição gráfica acabo optando pelo Paint. Bem, o Paint até que é rápido pra se desenhar, fácil, mas deus queira que eu não tenha que refazer algo!!

Descobri agora um software muito bom para isso, é o Balsamiq Mockups. Simplesmente ótimo! É exatamente aquilo que eu procuro ao criar um esboço. As principais características que posso destacar são:
  • Bastante intuitivo – em poucos minutos usando a ferramenta já sabemos como tudo funciona;
  • Rápido de criar;
  • Facilmente alterável – cada elemento na tela é um “componente", podemos modificá-los a qualquer momento;
  • Não requer habilidades artísticas;
  • E principalmente, tem cara de esboço. Não precisamos nos ater a detalhes. Nos focamos no fundamental apenas.
tela
O mais legal é que já criaram até um site com vários componentes e layouts comuns, como por exemplo a figura abaixo:
mytube

A única coisa que talvez esteja faltando é a possibilidade de criar nossas próprias bibliotecas de componentes. Porém, pelo visto, isso já está sendo desenvolvido.

No site do fabricante você encontra maiores informações do produto: Balsamiq.

quarta-feira, 28 de outubro de 2009

A teoria e prática caminham juntas

Frequentemente ouço alguém pedir: "devo aprender primeiro a tecnologia X ou Y?" ou, "o que é melhor eu conhecer, Java ou C# ?". Normalmente minha resposta vai ser: não importa qual você aprenda, desde que aprenda primeiro os conceitos por trás delas.

A importância da teoria

As formas de ensino as quais estamos acostumados normalmente separam a teoria da prática, nunca mostrando como aplicar toda a teoria no mundo real. A teoria e prática são separadas de tal modo que somos levados a crer que uma não tem relação com a outra.

Certamente você já ouvir frases do tipo "Isso é coisa de acadêmico", "No mundo real uma coisa dessas não se aplica" ou então "Eu sou uma pessoa pragmática não ligo pra essas teorias".

Essas frases são exemplos claros de como a teoria e prática são vistas como duas coisas distintas. Uma pessoa se diz pragmática e se afasta de qualquer teoria. A verdade é que a teoria está pros traz de tudo que fazemos, querendo ou não, ela é o fundamento.

O foco excessivo na tecnologia

Uma tendência que vemos atualmente é um foco excessivo na tecnologia em si e não nas motivações por traz dela. Todos querem estudar a nova ferramenta da moda.  As soluções são baseadas apenas em ferramentas.

O que adianta conhecer o framework de desenvolvimento web XYZ se a pessoa não sabe os conceitos básicos de desenvolvimento web? Ou aprender o lindo e maravilhoso framework de persistência recém lançado, sem saber quais seus objetivos e razões de existir.

Esse foco excessivo leva as pessoas a serem especialistas em uma determinada ferramenta, sendo incapazes de utilizar outras ferramentas de mesmo propósito ou até mesmo de fazer qualquer julgamento a respeito delas.

A teoria faz parte da prática

Sempre que preciso utilizar uma ferramenta procuro entender os problemas que motivaram o desenvolvimento dela e a forma que ela visa resolver esses problemas. Com isso em mente, fica fácil comparar diversas ferramentas e adotar outra se necessário.

Um exemplo prático é o desenvolvimento Web. Comecei a desenvolver sistemas web utilizando ASP.Net, e como todos devem saber, o conceito de WebForms adotado pelo ASP.Net tenta abstrair a complexidade da web e simular o desenvolvimento desktop. Nunca gostei muito dessa idéia de abstrair a web, por isso acabava estudando o funcionamento por traz daquela abstração. É importante saber como mostrar os dados em um Grid ou como utilizar um Repeater com dados aninhados, mas tem coisas muito mais importantes que isso.

Com o conhecimento de desenvolvimento web em geral que adquiri, e não apenas o conhecimento da abstração criada pelo ASP.Net, fui capaz de utilizar outros frameworks sem problemas. É só uma questão de traduzir a teoria para os comandos do novo framework.

Orientação a objetos na teoria e na prática

A orientação a objetos não é nova, porém somente na última década ela passou a ser amplamente utilizada.

Em qualquer projeto desenvolvido hoje, se alguém cogitar utilizar o desenvolvimento estruturado, certamente será motivo de piadas. Afinal, programação orientada a objetos (POO) é um paradigma muito superior a programação estruturada. Há apenas um problema: grande parte dos projetos que atualmente são desenvolvidos utilizando POO não utilizam os conceitos de POO, são apenas programas estruturados utilizando classes.

POO não se resume a conhecer o que é classe, objeto, método e herança. Há muitos outros princípios que se aplicados ajudam no bom desenvolvimento. Os princípios mais difundidos são os que conhecemos pelo acrônimo SOLID. São eles:
  • SRP - Single Responsibility Principle;
  • OCP - Open Closed Principle;
  • LSP - Liskov Substitution Principle;
  • ISP - Interface Segregation Principle;
  • DIP - Dependency Inversion Principle.
Apenas com estes princípios é que podemos realmente alcançar todo o potencial da POO e não apenas desenvolver programas estruturados utilizando classes. Em futuros posts devo falar mais sobre eles.
Mais uma vez, é um questão de mudar o foco da tecnologia para a teoria.

Em resumo

Para ter sucesso no desenvolvimento de software devemos tirar um pouco o foco da tecnologia e aprender os conceitos por traz dela. É uma pena que a cada dia as instituições de ensino estão focando menos nessa teoria e mesmo quando o fazem, é de forma distante da realidade, ficando difícil fazer uma ligação entre teoria e prática.

quinta-feira, 22 de outubro de 2009

Valores nulos em chave única no SQL Server

O Microsoft SQL Server tem uma característica que eu não gosto nem um pouco: em uma chave única dois valores nulos são considerados iguais.

Imagine uma tabela com os campos abaixo, tendo uma chave única com o campo CPF.
ID Nome CPF
1 João 123.456.789-00
2 Pedro NULL
3 Bino NULL

No SQL Server, ao contrário de outros bancos como o PostgreSQL, esses dados não seriam válidos. Ao tentar inserir o terceiro registro seria gerado um erro de chave duplicada.

Para contornar esse problema existe um truque denominado Nullbuster. Descobri essa técnica por acaso ao ler um post do Karl Seguin. Pesquisando na internet descobri que os créditos são dados ao Steve Kass, porém não encontrei nenhum link onde pudesse confirmar isso.

O truque é bastante simples, veja o SQL abaixo:
CREATE TABLE dupNulls (
  pk int identity(1,1) primary key,
  X  int NULL,
  nullbuster as (case when X is null then pk else 0 end),
  CONSTRAINT dupNulls_uqX UNIQUE (X,nullbuster)
)
Repare que foi criado um campo adicional denominado “nullbuster” onde o valor será igual a PK se o valor for NULO ou 0 se o valor estiver preenchido. A chave única então é composta dos dois campos.

A tabela exibida acima ficaria com os valores:
ID Nome CPF Nullbuster
1 João 123.456.789-00 0
2 Pedro NULL 2
3 Bino NULL 3

Um truque bastante simples que resolve alguns problemas.

segunda-feira, 19 de outubro de 2009

Influências de Domain-Driven Design

Nos últimos anos a prática de Domain-Driven Design vêm ganhando popularidade. Mesmo não sendo amplamente aplicada, muitas de suas abordagens influenciam o desenvolvimento de softwares como um todo.

Para quem não está familiarizado com o tema, DDD é uma abordagem para desenvolvimento de software. Esse termo for criado por Eric Evans no livro Domain-driven design: tackling complexity in the heart of software.

De uma maneira super resumida, DDD visa eliminar as diferenças entre negócio e software, o software deve espelhar exatamente o domínio sendo tratado. Para tanto, são adotadas diversas práticas no desenvolvimento, como por exemplo: colaboração mais próxima do especialista no negócio, uso de uma linguagem única pelos desenvolvedores e especialistas, e deixar os conceitos envolvidos na aplicação explícitos.

Como o próprio Eric Evans deixa claro, DDD não é uma abordagem a ser adotada no desenvolvimento de qualquer software, ela deve ser adotada apenas em sistemas complexos.

Mesmo não adotando a abordagem como um todo, podemos tirar proveito de diversas práticas no desenvolvimento de qualquer software.

Deixando os conceitos explícitos

Uma das práticas de DDD é deixar os conceitos explícitos. Ou seja, deixar clara a intenção deles. Isso deve ser feito tanto no nível de código como na própria interface.

Um exemplo que me deparei recentemente onde os conceitos não estão muito claros é no Blogger. Ao editar uma postagem vemos uma tela semelhante a figura abaixo:
blogger
A questão nessa tela são os botões “Publicar postagem” e “Salvar”. As ações deles não ficam muito claras ao usuário. Enquanto criamos uma postagem eles tem as funções de:
  • Publicar postagem – tira a mensagem dos rascunhos e publica oficialmente a mensagem;
  • Salvar – simplesmente atualiza os dados da postagem;
Se a mensagem já foi publicada, as funções são:
  • Publicar postagem – simplesmente atualiza os dados da postagem;
  • Salvar – move para os rascunhos a mensagem já publicada;
Ficaria muito mais claro para o usuário se as funções de Publicar, Mover para rascunhos e Salvar fossem distintas. Na minha opinião, ficaria muito mais claro com as seguintes opções:
  • Salvar – simplesmente atualiza os dados. Não move para rascunhos e não publica, atualiza os dados independente do estado da postagem;
  • Publicar postagem – aparece apenas se a postagem ainda não foi publicada;
  • Mover para rascunhos – cancela a publicação e coloca novamente a mensagem nos rascunhos.
É uma alteração simples e que envolve basicamente renomear os botões. Pode ser que eu seja chato, mas acho que dessa forma fica muito mais claro para o usuário qual o efeito de cada comando.

Utilizando técnicas de DDD no dia-a-dia

Como já mencionei antes, DDD não é uma abordagem a ser adotada em todo e qualquer software, porém podemos tirar lições dela e adotar algumas partes no desenvolvimento do dia-a-dia. Sempre que possível podemos deixar os conceitos mais explícitos e usar nomenclaturas padronizadas. Ou seja, deixar claro tanto para o desenvolvedor como para o usuário o efeito de cada ação e sua relação com o negócio.