O verdadeiro custo do Paliativo

07:58 Vinicius Knob 2 Comments



Quem nunca ouviu uma frase semelhante a essa: "Faz aí uma correção que resolve esse problema rapidamente, pois precisamos entregar isso para o cliente e tem que funcionar. Outra hora revisamos esse código com mais calma".

E assim iniciou-se um ciclo viciante (sim, viciante, essa é realmente a palavra) de pequenas inserções de código que visam boas intenções, obviamente, porém com consequências destrutivas no longo prazo. Se você já passou por isso sabe do que estou falando. São essas pequenas atitudes que fazem com que um projeto comece a ter pequenas amostras de código que poderão futuramente nunca ser substituídas.

Afinal, para que serve um paliativo?

Você já se perguntou? Bom eu vou lhe explicar. Um paliativo segue a ideia de um MVP praticamente, desenvolver o mínimo de valor entregável que gere um retorno e que atenda às expectativas do cliente. Só que um paliativo não pode ser chamado de MVP, ele apenas segue a ideia, aí você adiciona um pouco mais de velocidade ao processo (nesse momento você já deve estar no meio do fogo), e também algumas palavras mágicas devem ser proferidas: "Isso será temporário!".

Ei pera aí! Temporário? Eu acho que tem algo errado aí. Algo que deveria ser temporário acaba permanecendo por muito tempo no sistema. Na maioria das vezes esse paliativo recebe correções e até melhorias. Nesse ponto, significa praticamente dar uma armadura a um monstro que já existia. Você agora está fortalecendo esse monstro.

"O cliente não se importa com o código", muito se ouve falar isso. A única pessoa que se importa com ele é você, pois nem o seu gestor está interessado se aquilo é um paliativo, se é de fato uma implementação permanente, se é a melhor aplicação dos padrões de projeto que existe, ninguém se importa, somente você e agora você tem um monstro com uma armadura em seu sistema. Sabe por quanto tempo ele vai viver?

Por que paliativos são um problema?

Simples, pois eles funcionam. E somente por esse atrativo é que são tão requisitados e aceitos. E então esquecidos. Mas então qual é o problema com eles? Especificamente, o problema não está no paliativo. Se um sistema fosse apenas um paliativo, ele em si seria o sistema, logo não seria um paliativo, nem poderia ser chamado disso. O que estou tentando dizer é que nesse contexto o "paliativo" não é um problema, ele é um sistema. 

Quando o problema é o paliativo, você tem um problema no sistema. Um pequenino e indefeso código lá nos confins daquele bolo de classes e arquivos de configuração, no futuro pode resultar em um comportamento que precise de correção ou melhoria. Nesse contexto, nós temos um problema, mas o que é o problema: o paliativo inocente ou a situação do futuro que precisa mexer nesse paliativo? Perceba que aqui estamos falando de questões como planejamento e segurança: quanto estou disposto a me defender de possíveis anomalias conhecidas do meu sistema?

Bom, você tem um problema quando esse paliativo está em um local incomum, não rastreável, nem por olhos humanos, durante a rotina do dia-a-dia, e nem por sistemas de versionamento. Você também tem um problema com paliativos quando eles não seguem boas práticas como escalabilidade, legibilidade, manutenibilidade, responsabilidade, baixo acomplamento, e tantas outras mais. Aliás, um paliativo que segue essas práticas não pode ser chamado de paliativo.

Não sei se ficou claro, mas o fato de um sistema ser algo dinâmico faz com que você tenha que pensar no futuro. Já falei sobre o futuro logo acima. O paliativo somente será um problema se existir um futuro, e ele existe para a maioria dos sistemas. Partindo dessa premissa, talvez o problema realmente não seja o paliativo, mas sim você que chegou ao ponto de precisar de um paliativo.

Algumas táticas para contornar isso

Fugir dos paliativos é um pouco difícil. Você precisa deles e isso é inevitável por diversas razões: um paliativo de curto prazo é a melhor solução para que um projeto seja entregue, uma demanda seja finalizada ou uma correção em ambiente produtivo mantenha o sistema online. Então nesse caso o que fazer? 

Regra nº 1: Rastreabilidade

Primeiro passo é tornar esse paliativo rastreável, ou seja, você quer que esse paliativo dentro de algum tempo vire algo que seja revisado, e feito de forma correta e permanente. Estamos falando agora de código limpo, performático e fácil de entender. Um código que siga os padrões do Projeto e de Projeto (perceba a diferença entre "de projeto" e "do projeto", um papo para outro post). 

Se a sua empresa utiliza algum controle de issue, o melhor é neste exato momento que você está criando o paliativo também criar uma issue explicando como encontrar o paliativo e o que deve ser feito para que posteriormente alguém atenda a esta solicitação, ou mesmo você, e a correção deste paliativo resulte em uma implementação correta do mesmo. Se um Kanban é utilizado em seu projeto, essa é a hora de fazer um ticket ou story aparecer nele, provavelmente em backlog, o local não importa, mas alguma coisa deve aparecer.

Regra nº 2: Código Sujo

Sim, sujo, é isso mesmo que você leu, uma denominação que indica o oposto de código limpo. Uma importante atitude é não fazer com que esse paliativo seja algo excepcionalmente bom, ou seja, se você é um expert em código não utilize das melhores práticas, o palitivo não pode ser considerado um código fantástico que alguém vai olhar e pensar "Meu Deus, eu não vou conseguir fazer melhor que isso". Se esse código envolve telas faça uma tela com HTML puro as pessoas não devem gostar disto, a própria implementação deve ser um alerta para que as coisas sejam melhoradas.

Outra motivação para que esse paliativo seja sujo, é que fazer um código limpo geralmente demanda mais tempo, pois atender as boas práticas na maioria das vezes requer tempo, análise, uma relembrada dos padrões de código, conduta e convenções utilizadas. Se você está utilizando um paliativo, muito provavelmente esteja em um mal momento, algo está pegando fogo, então por que perder tempo com coisas bonitas?

Se você não tem saída e este paliativo deve ser uma implementação muito boa tanto em front quanto em back, performática e fácil de ler, então você ainda deve lembrar que tem a possibilidade de criar uma issue no sistema para rastreamento futuro. Se tempo não for o problema para você, por que está chamado sua implementação de paliativo?

Regra nº 3: Conhecimento

Eu não poderia deixar de falar sobre isso, pois esse com certeza é o assunto-chave para reduzir drasticamente a capacidade de você gerar um paliativo no sistema. Deixei ele por último, pois quero que esse seja o foco. As regras 1 e 2 são contingências, mas a regra 3 é o que realmente fará a diferença na sua vida.

Você já se perguntou por que chegou ao ponto de precisar de um paliativo? Bom, vou tentar listar alguns pensamentos, ou mesmo afirmações, que podem estar passando pela sua cabeça agora:

A plataforma/framework/lib que estou utilizando possui um bug, e agora preciso de um paliativo. Bom, você identificou um bug, será que consegue documentar esse bug e passar para a equipe de suporte desse recurso de terceiro que você precisa? Esse recurso está encapsulado e é acessível através de uma interface do seu sistema, e pode facilmente ser implementado um novo encapsulamento oferencendo a possibilidade de troca ou alternância de recurso? O ideal aqui é reportar o bug, mas também ter o sistema muito bem protegido para que uma troca de lib, por exemplo, não seja um problema. O acoplamento dessa lib no sistema deveria ser uma interface ou classe do sistema, e só. O nome desse padrão de projeto é Facade, mas nada impede você de utilizar o padrão Adapter, também conhecido como Wrapper, caso o recurso seja minúsculo e precise de adaptações para conexão com o seu sistema.

Outra pessoa da minha equipe gerou esse problema, e agora preciso de um paliativo. Ótimo, você identificou um problema no sistema, identificou o gerador, fez o paliativo. Hora de respirar? Não. Tente entender os motivos que levaram essa pessoa do seu time a criar esse problema para você. Muito provavelmente será falta de conhecimento, e agora você tem uma missão em suas mão: melhorar o processo de desenvolvimento do seu time. Você tem o conhecimento necessário para propagar de maneira controlada a informação de ações ou boas práticas para evitar problemas que geram paliativos no sistema. Um time é tão forte quanto seu integrante mais fraco.

Eu gerei esse problema, e agora preciso de um paliativo. Perfeito, você tem nas mãos um feedback perfeito para tomar uma atitude de mudança em sua vida. Melhore suas práticas de desenvolvimento de software, utilize testes unitários, crie anotações para não esquecer de configurações complexas de plataformas mal documentadas, utilize testes automatizados, explore mais as lógicas do seu código, teste em múltiplos ambientes, converse com outras pessoas do time, peça para alguém mais validar o seu código, peça por sugestões de melhorias, peça por sugestões de testes que podem ser feitos, explore mais as plataformas online como StackOverflow, teste como se sua vida dependesse desse código, teste, Teste, TESTE.

Para você desenvolvedor...

Se você leu até aqui acredito que seja alguém como eu, que deseja insamente melhorar, que seja curioso, que seja inquieto com o código fonte. Espero que meu objetivo tenha sido alcançado com você. Minha visão sobre o paliativo, o motivo de eu considerar isso um problema, como atacar o problema, mas principalmente o que fazer pró-ativamente para que um paliativo nunca seja necessário em seu sistema. 

2 comentários:

ATG: RqlStatement com Cache interno

03:59 Vinicius Knob 0 Comments


Resolvi por curiosidade estudar o método estático RqlStatement.parseRqlStatement. No Javadoc da classe, pude observar que existem duas formas de utilizar o método com passagem de String para representar o RQL, algo muito comum quando estamos no mundo ATG e seus infindáveis properties de configuração. As duas formas podem ser vistas abaixo:

RqlStatement.parseRqlStatement(rql);

e

RqlStatement.parseRqlStatement(rql, cacheRqlStatement);

Quero focar meus esforços em apresentar a diferença entre esses dois métodos. Quando utilizado RqlStatement.parseRqlStatement(rql), o que realmente acontece é a execução do parse sem manter o objeto convertido em cache. Para deixar claro, esse cache é interno a classe.

Já no segundo método, o Javadoc descreve o processo da seguinte maneira:

"Parses an RqlStatement from the given String. If pCacheRqlStatement is true, then the RqlStatement that is created from this operation will be saved in an internal cache with the String pStatement as the key. The next time this same string is passed to parseRqlStatement, the cached RqlStatement will be returned, so we don't have to re-parse the same string over and over again. Only use this method for statements that you'll definitely be re-using over again, and if the code you're using does NOT cache the statement already".

Isso quer dizer que ao utilizar o segundo método ganha-se a possibilidade de armazenar no cache interno do RqlStatement uma referência do objeto convertido, não sendo necessário efetuar novamente a conversão do mesmo pela própria classe.

Para se ter uma ideia do impacto disso, montei 2 testes com JUnit: 1 sem cache e 1 com cache (informando o segundo parâmetro como true). Na imagem abaixo, pode-se ver como é alarmante a diferença entre ambos os processos quando temos 1 milhão de iterações. Sem cache o processo leva 62 segundos, mas com cache leva apenas 0,843 segundos.



Sendo assim, o melhor caminho seria utilizar RqlStatement.parseRqlStatement(rql, true), favorecendo a performance dos processos, otimizando o tempo em novas chamadas ao parse que possuam o mesmo parâmetro de RQL, não sendo necessário armazenar referências convertidas em atributos de classe, pois a classe RqlStatement faz isso.

Talvez você se sinta inclinado a querer a possibilidade de limpar esse cache quando quizer. Esse geralmente é um controle que Desenvolvedores do mundo ATG gostam de ter. Entretanto, lhe afirmo que esse não é um cache perigoso, daqueles que você realmente precisa limpar, pois algo foi atualizado em banco e agora a aplicação precisa refletir. Não! Esse é um cache interno a classe RqlStatement. Se o RQL for alterado por um properties dinâmico, tudo que a classe irá fazer na próxima iteração é armazenar o novo RQL convertido, sendo que o anterior não será mais utilizado.

Gostou? Compartilhe esse post =)

0 comentários:

JavaScript: Notifications API

13:34 Vinicius Knob 0 Comments

A API de Notificações permite que páginas web controlem a apresentação de notificações do sistema para o usuário final. Essas notificações estão em um nível acima da janela atual da página web, isso permite que elas sejam apresentadas mesmo que a guia não esteja selecionada, ou que você esteja utilizando um programa/aplicativo diferente. A API foi projetada para possui total compatibilidade com sistemas de notificação existentes nas diferentes plataformas.

Modo de Uso


Em plataformas compatíveis, existem dois passos muito simples para lançar notificações:

1. Solicitar permissão ao usuário;
2. Lançar a notificação.

Solicitando permissão ao usuário

A solicitação de permissão para envio de notificações é um passo muito interessante. Que mundo seria esse se as notificações estivessem livres para uso desenfrado por todos os sites? Seria o carnaval eterno na web (acho que de qualquer forma isso já está acontecendo com alguns sites). Para evitar o problema clássico do uso sem limites, a API foi criada com uma premissa básica: notificações precisam ser ativadas pelo usuário final.

O seguinte código lança a solicitação de permissão, que nada mais é do que um popup, parecido com um tooptip ou popover, onde existe uma pergunta e as opções de resposta: permitir ou bloquear.




Exemplo de solicitação emitida pelo navegador após executar o código citado.


Quando solicitar?

Depende. Gosto de pensar que essa decisão tem a ver com "se colocar no lugar do usuário". A maioria dos sistemas solicita a permissão ao carregar a página, mas tudo vai depender do tipo de conteúdo e do público alvo. Pense comigo, o conteúdo pode chamar mais atenção do usuário que a solicitação e ela acabar sendo ignorada. Quando uma solicitação é ignorada ela mantém o status default, ou seja, notificações não serão lançadas. O público alvo pode resultar no mesmo problema, pois se o seu sistema atinge pessoas que tem pouco ou nenhum conhecimento do que seria uma notificação elas podem simplesmente ignorar ou até bloquear (status "denied") a solicitação. Por padrão, os browsers não efetuam múltiplas solicitações de permissão se o usuário já bloqueou a primeira.

Lançando notificações

Após obter a permissão do usuário, seu sistema está apto a lançar notificações. O status da API está "granted" e criar uma notificação é muito simples:


title: Na notificação, o title fica na parte superior, com mais destaque;
options: Existem diversas opções de configuração, porém as que você realmente precisa conhecer são body e icon. O body recebe um texto mais descritivo, mais longo que o title, e que será apresentado no centro da notificação. Já o icon é uma url de uma imagem para ser apresentada na esquerda da notificação.


Exemplo de Notificação do Queiroz


Isso é o suficiente para sua notificação ser apresentada ao usuário =)

Queiroz: um exemplo real


Na imagem demonstrada acima você pode observar um exemplo de notificação existente no Queiroz.js. Já falei do Queiroz.js aqui no blog. No Queiroz.js, utilizo as notificações para avisar aos usuários de que alguns determinados horários do dia estão próximos de chegar. Isso ajuda consideravelmente o usuário que pode estar efetuando atividades em outras janelas, mas mesmo assim verá a notificação. Esse é um exemplo real, e foi utilizado exatamente da mesma forma que explico acima.

Para refletir


Você deseja que o usuário aceite a permissão, pois ele entende aquilo e sabe do que se trata, ou você simplesmente quer que ele aceite e viva com uma notificação que pode se tornar algo muito estressante e gerar críticas ruins? A maioria dos sites não se importa com a resposta para essa pergunta. Não seja mais um nesse grupo.

0 comentários: