English readers and other languages: Many posts are in portuguese, you can use the Translate button at left side.

Clique nas imagens dos artigos! Elas levam você para o site do artista que a criou e muitas
vezes tem assuntos relacionados ou outras imagens para expandir seus horizontes!
Mostrar mensagens com a etiqueta Programação. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta Programação. Mostrar todas as mensagens

quinta-feira, 17 de setembro de 2009

Converter String vazia para Long em Java

Referência:
Java Error in tMap

Java não converte uma string vazia para long de forma automática.
Para isto, pode-se usar um bloco try/catch como esse:

String stringValue = "";
long longValue = -1;
try {
longValue = Long.parseLong(stringValue);
} catch (NumberFormatException e) {
longValue = 0;
}
System.out.println(longValue);

sexta-feira, 11 de setembro de 2009

Programador também faz POG

The Duck Tape Programmer
Foto: Graeme - New Zealand


A POG, Programação Orientada a Gambiarra, possui diversas formas de implementação.

A escolha da abordagem mais adequada, é geralmente na base do que funcionar primeiro. Por incrível que pareça, na programação POG, o que vale nem sempre é o menor esforço, pois o que está em jogo é o resultado e não a capacidade do programador entender o que está fazendo. Isto inclui também, os misteriosos problemas no kernel ou nas ferramentas de desenvolvimento e softwares de terceiros, para os quais, nem sempre o fabricante fornece suporte adequado.

Vejamos alguns dos tipos de POG mais encontrados:

FORCEPS

De fácil compreensão, esse recurso é largamente utilizado, caso um valor não seja atribuído a sua variável durante a execução de um programa por algum problema desconhecido pelo programador POG. Assim em vez de perder horas e horas debugando um programa, através do altíssimo nível de programação orientada a gambiarra, o programador POG atribuiu um valor na base da porrada e o programa roda livre e sem bugs. É claro que de tempos em tempos esse pequeno ajuste deve ser mantido.

Programação Orientada a Estagiário

Consiste na capacidade do analista de sistemas sobrecarregar o estagiário ou o técnico mais próximo com todas as suas funções, desde interação com clientes até desenvolvimento de casos de uso e bancos de dados, aproveitando ao máximo toda a energia gambiarrizadora que essas categorias possuem. Sabendo que fica mais fácil para o programador entender e realizar a POGização do sistema se ele conversar diretamente com o usuário, o analista sabiamente permite que o programador realize os contatos com o cliente, permitindo assim que o analista realize funções que condizem mais ao seu cargo, como acessar a desciclopédia, ficar o dia inteiro na cantina ou ir puxar o saco do chefe, por exemplo. Além do mais, o contato do programador com o usuário economiza papel e tinta de impressora, pois a parte da documentação impressa é nula, já que o analista não participa do processo e assim não gera as toneladas de folhas com diagramas e especificações. O acoplamento do sistema é muito maior, pois foi desenvolvido por uma única pessoa, facilitando na manutenção, pois existem poucas classes para serem modificadas (no máximo cinco, para programas muito complexos).

Apellation Number Technic

É um método muito utilizado por MVP's (MOST VALUABLE POGrammer), que resolve 90% dos BUGs sem que precise queimar nenhum neurônio. POGramadores experientes sabem que: Deu um BUG no sistema? Digita -1 em algum lugar que funciona!!! Ainda não se sabe o motivo, e nem precisa saber. apenas funciona e pronto.

Static Spree

Um dos patterns mais utilizados da POG. O objetivo desse padrão é que tudo fique visível em qualquer canto, porque private é coisa de gente sem vergonha. Também conhecido por Public Static Spree, pois comumente tudo é feito "public static".

Imagem: Dom Herms
Public Global Access

Pattern que simplifica o desenvolvimento eliminando todos aqueles métodos de acesso inúteis, tornando todos os atributos acessíveis globalmente, diminuindo a quantidade de lixo no código. Apesar da semelhança com o Static Spree, os atributos não precisam ser static.

RCP Pattern

Significa Reuse by Copy-and-Paste (Reúso por Copiar e Colar). O RCP dita que, na pressa, quando não dá pra fazer a coisa por herança, basta copiar e colar, quantas vezes for necessário. Em geral se espera que futuras alterações sejam feitas por outros trouxas, digo programadores, perdão. Os trechos de código são copiados de todo e qualquer lugar possível, geralmente de outro programador (muitas vezes o estagiário) ou código da internet, para criar partes funcionais do programa. Utiliza-se a do "Ctrl+C" e "Ctrl+V" para juntar as partes e adaptá-las para funcionar, por tentativa e erro. Leva um considerável tempo para se adaptar o programa, e um número absurdo de compilações, mas pelo menos pode-se dizer que foi você quem fez o código. Este pattern também é conhecido como "Contra o C e Contra o V".

BCDR Pattern

Black Cat in a Dark Room (Gato Preto em um Quarto Escuro). Consiste em criar métodos que recebem apenas um parâmetro (um Map em Java ou um params em .NET). O argumento que você precisa está lá dentro, mas você não sabe exatamente onde. Esse padrão permite passar quantos argumentos forem necessários a um método, sem poluir o código. Permite criar métodos cujas assinaturas seriam, de outra forma, extremamente longas . Evita a alteração de assinaturas de métodos no momento da manutenção do código, fazendo desnecessário qualquer tipo de refactoring.

Há registro de programadores de Black Cat in a Dark Room. Um exemplo complementar é o parâmetro String[]:

Um exemplo prático é o sistema de gerência de Mensagens do Windows.

User Friendly Exception

Consiste na padronização de todas as mensagens de erro do sistema para uma única mensagem amigável ao usuário. Um sistema 100% compatível com esse padrão, nunca trava nem encerra de forma inesperada, mas apenas não atende ao usuário exibindo uma mensagem do tipo "Caro usuário, tente novamente observando as regras de uso do sistema". Observação: Trata-se da evolução de um padrão amplamente utilizado em sistemas Microsoft com mensagens "Catastrophic Failure" e "Unexpected Error".

Exemplo de implementação em Java:
public static void main(String[] args){
while (true) {
  try {
  ...
       } catch (Throwable ex) { // qualquer erro do sistema cai aqui
      // só pode ser culpa da besta ignorante do usuário
      System.out.println("Caro usuário, tente novamente observando as regras de uso do sistema");
      // após a mensagem, o while(true) garante a robustez do sistema que nunca aborta!
      }
   }
}


Chaotic Experimentation

Padronização de construção de funções para continuar a executar o programa mesmo que dê pau em alguma rotina. Exemplo clássico: On Error Resume Next (Visual Basic).

Controller Confusion

Tática que permite uma menor escrita de classes no sistema. Consiste simplesmente em eliminar o M do padrão MVC, ficando um padrão muito mais legal - o VCC ("View/Controller Confusion", ou "Vai catar coquinho"). Alguns tem sugerido inclusive a eliminação do V - ou seja, ficando apenas o CC (Codigo coco para os usuarios mais intimos) - a lógica, o modelo, os templates, o HTML, tudo e mais um pouco dentro do controller confusion. Como você pode ver, o padrão cêcê faz jus ao nome.

N.M.L. Combat Action POG Pattern

É um Design Pattern POG ousado, moderno, revolucionário e NÃO-EMO. Os arquitetos emos e POGuistas ADORAM, junto com seus miguxus, incrementar suas frameworks utilizando MUITAS camadas, geralmente desnecessárias. A N.M.L. (No More Layers) aborda uma estrutura onde todas as regras de negócio, validação (client e server side) e acesso à dados estão na tela! Para que Facades, Commands, Bussines Delegate e outras viadagens EMO detonando a performance da aplicação? Manutenção? Não é necessário, pois quem domina e faz uso dessa técnica modesta e humilde produz códigos Chuck Norris Style, ou seja: PERFEITOS. Esse paradigma está amplamente difundido por programadores VB e Delphi, e tem migrado com sucesso para a plataforma .NET, porque o que importa é a beleza da tela, e não a tecnologia que está por trás!

UFB -Uso de Força Bruta

Método muito famoso no meio dos programadores POG.

O método se aplica para solucionar problemas sem perder tempo voltando no código para procurar onde deu errado.
...


if (var==20)
   ChamaMetodoSolucao(var);
else

   {
   var=20;
   ChamaMetodoSolucao(var);
   }


Strombolic Bridge (ou, DRIBLE DA VACA)

O Paradigma Strombolic Bridge (Ponte Estrombólica) ou mais conhecido no Brasil pelo Pseudonome de "Drible da Vaca" é uma evolução do já consagrado BRUTE FORCE. Consiste em alimentar uma variável global que será utilizada dentro de algum método, mas certificando-se de que seu valor inicial será retornado ao original após o uso dela pelo método. Por exemplo:
varTemporaria = varOriginal;
varOriginal = "NovoValor";
Executa(varOriginal);
varOriginal = varTemporaria;


Reparem que, tal como o "Drible da Vaca":
- A varOriginal dá um 'totózinho' lateral do seu valor para a variável temporária,
- Recebe o novo valor que será utilizado pelo método,
- (corre) e recebe de volta seu valor la na frente...
Não tem erro.... assim você sempre terá certeza que o valor original será sempre o mesmo !!!

Space Kick Pattern

Consiste em ir chutando pro espaço, até acertar e a coisa dar certo!

Abstract Observer Pattern

Método para dar manutenção em código POG. Você observa um monte de gambiarra, mas abstrai e considera a coisa como funcional.

------------------------------------------------------------------------------------------------------

O texto acima está com algumas pequenas modificações e acréscimos feitos por mim. O original foi encontrado no  Blog Mundo .Net do Constantine

.'.

quarta-feira, 2 de setembro de 2009

Performance: Quando A Culpa Não é do Banco de Dados

The IBM Stretch supercomputer.
Photo: IBM

Performance: Quando A Culpa Não é do Banco de Dados
02/09/2009

Otizimizando a performance em SQL com Join e Subquerys


Com frequência temos casos em que uma determinada seleção de registros, apesar de parecer atender as necessidades iniciais, não é satisfatória devido a demora do processamento.

Uma das causas, é pela utilização apenas de dados de teste, em tabelas pequenas. Com isto, o tempo real de execução deixa de ser avaliado e, como resultado, o coitado do DBA vai ter que ouvir mais uma vez que “minha Select funcionou, então é o banco de dados é que tem problema”. Ou então, será alegado culpa do usuário...

Mas existem muitas diferenças entre simplesmente “funcionar”, e funcionar de forma eficiente.

A complexidade de uma seleção de dados, vai levar em conta, o tempo de que dispomos para sua codificação é claro, mas também, é preciso ponderar no ganho de tempo, mesmo na fase de testes com dados reais, e os recursos utilizados em produção. Na maior parte das vezes, o tempo ganho estudando a otimização compensa largamente e geralmente diminui o tempo de programação e testes.

Outra falha, é confiar excessivamente nos recursos de otimização automática dos gerenciadores de banco de dados. Nem sempre estes farão a melhor escolha. Como por exemplo, ao avaliar a disponibilidade de outros índices, neste caso, mudando as chaves de seleção de alguma forma, que poderá ter um impacto significante. Também a hierarquia como serão processadas as condições de seleção e até mesmo, transferir parte dos recursos para outra tabela, ainda assim de forma mais eficiente no resultado geral, pelo aproveitamento de dados em cache.

Tomei para este exemplo, uma seleção de dados numa tabela real, mudando é claro os nomes para o exemplo, com cerca de 60 milhões de registros de movimentos relativos a um conjunto de setores, relacionadas noutra tabela.

Esta transação era utilizada diariamente numa consulta pelo usuário final, os diretores da empresa para decisões de mudanças estratégicas em tempo real para ofertas nas suas lojas, mas demorava até absurdamente 2 horas! Imagine alguém da diretoria precisando tomar decisões de enorme valor financeiro a nível nacional, literalmente milhões de $ e tendo que esperar este tempo todo! Certamente era desejável obter uma boa performance.

É importante observar, que mesmo que fosse o caso de um programa de execução única ou eventual, a enorme perda de tempo durante a fase de testes compensa largamente que se faça um código melhor.
Veja bem: como é que vou trabalhar se entre um teste e outro preciso esperar horas? Estamos no Século XXI, é hora das coisas funcionarem melhor e serem melhor feitas. 
Desta forma, teremos nosso trabalho pronto mais rápido, e também, estaremos economizando os recursos do sistema e da empresa que também são utilizados pelos demais usuários.
E também muito importante, é lembrar que geralmente, não teremos exclusividade de uso do servidor. Existem outros programas disputando recursos. No caso do exemplo atual, eram mais de 5000 estações fazendo todo tipo de transação acessando exatamente a tabela principal desta pesquisa, além de uma grande quantidade de processamento batch realmente volumosos.

O sistema gerenciador de banco de dados (SGBD) neste caso, era o Sybase AES (Adaptative Server Enterprise) 12.5. Usei os comandos sp_showplan e sp_statistics para listar resumos das execuções.
Os conceitos aqui mostrados servem para qualquer outro SGBD Relacional, como Oracle, Sql Server, etc.


A Select original que está abaixo, vai retornar a soma para quatro condições diferentes em cada setor existente.
Para nosso exemplo temos duas tabelas: Setores e Movimentos. Precisamos selecionar os Setores de Tipo = 'X', e os movimentos dentro de um periodo de datas, que tenham um determinado CodigoTeste igual ou diferente de zero e, que poderá ter uma segunda condição a ser testada. Ainda, precisamos o total geral de registros.

Neste modelo, em que a tabela de setores é a principal, simplesmente fizeram quatro varreduras na tabela de movimentos para cada um dos setores dentro do período selecionado. Uma leitura para cada um dos campos a ser somado! O tempo de execução foi obviamente bastante longo.

Logo abaixo estão as estatísticas de execução.

Select Original:

select Setores.codigoSetor,
       (select count(*) from Movimentos b
               where Setores.codigoSetor = b.codigoSetor and
                     dataOperacao between '04/01/2009' and '04/30/2009'),
       (select count(*) from Movimentos c
               where Setores.codigoSetor = c.codigoSetor and
                     dataOperacao between '04/01/2009' and '04/30/2009' and
                     codigoFlagTeste 0),
       (select count(*) from Movimentos d
               where Setores.codigoSetor = d.codigoSetor and
                     dataOperacao between '04/01/2009' and '04/30/2009' and
                     codigoFlagTeste = 0 and tipoABCDE in (1, 2, 3, 4)),
       (select count(*) from Movimentos e
               where Setores.codigoSetor = e.codigoSetor and
                     dataOperacao between '04/01/2009' and '04/30/2009' and
                     codigoFlagTeste = 0 and tipoABCDE not in (1, 2, 3, 4))
  from Setores (index indiceSetores01)
  where (tipoSetor = 'X' or Setores.codigoSetor = 999)
  order by Setores.codigoSetor


Estatística da Execução:
----------------------------------
Table: Movimentos scan count 121, logical reads: (regular=124152 apf=0 total=124152), physical reads: (regular=1129 apf=123023 total=124152), apf IOs used=123023

Table: Movimentos scan count 121, logical reads: (regular=6949399 apf=10100 total=6959499), physical reads: (regular=843310 apf=5103725 total=5947035), apf IOs used=5090713

Table: Movimentos scan count 121, logical reads: (regular=1003943 apf=2237 total=1006180), physical reads: (regular=37563 apf=261910 total=299473), apf IOs used=262198

Table: Movimentos scan count 121, logical reads: (regular=1003943 apf=0 total=1003943), physical reads: (regular=0 apf=0 total=0), apf IOs used=0

Table: Setores scan count 1, logical reads: (regular=51 apf=0 total=51), physical reads: (regular=47 apf=16 total=63), apf IOs used=1


===> Total actual I/O cost for this command: 132.860.664... !!!
Total writes for this command: 125

Execution Time 749.
SQL Server cpu time: 74900 ms. SQL Server elapsed time: 1.471.296 ms.

(121 rows affected)
----------------------------------


Vemos que houve um processamento bastante repetitivo e bem pesado. Para cada linha selecionada na tabela Setores, são feitos quatro leituras na tabela de Movimentos, que neste caso, pelo menos tinha um Indice por data. Mas ainda assim, é demais.

Podemos melhorar isto em duas partes principais.
  1. Fazer apenas um ciclo de leitura na tabela de Movimentos eliminando as subconsultas. 
  2. Otimizar a forma como vamos validar quais código de setor serão validados.

Para aproveitar melhor o ciclo de leitura, fazendo a contagem das condições que precisamos verificar, utilizamos o comando CASE WHEN, que é semelhante a do SQL Server. A maioria dos SGBDs possui uma condição de critério.
A tabela de Movimentos passa a ser o principal e não mais o de Setores, também temos no mesmo um índice por setor e data.
E usamos o Join que não era usado!

Assim teremos:

  select codigoSetor, count(*),
        sum ( case
                when b.codigoFlagTeste 0 then 1 else 0 end ),
        sum ( case
                when b.codigoFlagTeste = 0 and
                     tipoABCDE in (1, 2, 3, 4) then 1 else 0 end ),
        sum ( case
                when b.codigoFlagTeste = 0 and
                     tipoABCDE not in (1, 2, 3, 4) then 1 else 0 end )
   from Movimentos b
   join Setores (index indiceSetores01)
     on Setores.codigoSetor = b.codigoSetor
   where dataOperacao between '04/01/2009' and '04/30/2009' and
        (tipoSetor = 'X' or Setores.codigoSetor = 999)
   group by codigoSetor
  

Estatística da Execução:
----------------------------------
Table: Movimentos scan count 1, logical reads: (regular=60523 apf=53 total=60576), physical reads: (regular=48421 apf=6249 total=54670), apf IOs used=6173

Table: Setores scan count 95560, logical reads: (regular=99289 apf=0 total=99289), physical reads: (regular=10 apf=0 total=10), apf IOs used=0

Table: Worktable1 scan count 1, logical reads: (regular=6545 apf=0 total=6545), physical reads: (regular=0 apf=0 total=0), apf IOs used=0


===> Total actual I/O cost for this command: 1.317.060... (apenas 1% do anterior)


Execution Time 15.
SQL Server cpu time: 1500 ms. SQL Server elapsed time: 83.800 ms.


Basta uma rápida olhada para perceber imediatamente que a diferença na quantidade de I/Os e no tempo de processamento é impressionante, próximo de apenas 1% da select original!

Mas ainda podemos mudar um pouco isto para explorar alternativas.

Observem que utilizamos um Join para validar a tabela de setores. Mas neste caso, poderemos ter várias releituras da mesma.

Também seria possível a condição 'where... IN' para validar o setor, ao invés de Join. Mas neste caso, pode ocorrer um aumento no número de I/Os, que é pequeno em relação ao problema original, mas que deverá ser estudado se for noutra implementação

Assim teremos:

select codigoSetor, count(*),
       sum ( case
               when b.codigoFlagTeste 0 then 1 else 0 end ) ,
       sum ( case
               when b.codigoFlagTeste = 0 and tipoABCDE in (1, 2, 3, 4) then 1 else 0 end ) ,
       sum ( case
               when b.codigoFlagTeste = 0 and tipoABCDE not in (1, 2, 3, 4) then 1 else 0 end )
  from Movimentos b
  where dataOperacao between '04/01/2009' and '04/30/2009' and
        codigoSetor in (select codigoSetor
                          from Setores (index indiceSetores01)
                          where tipoSetor = 'X' or Setores.codigoSetor = 999)
  group by codigoSetor  

Estatística da Execução:
----------------------------------
Table: Movimentos scan count 1, logical reads: (regular=60523 apf=26 total=60549), physical reads: (regular=51955 apf=4993 total=56948), apf IOs used=4822

Table: Setores scan count 95560, logical reads: (regular=99627 apf=0 total=99627), physical reads: (regular=27 apf=0 total=27), apf IOs used=0

Table: Worktable1 scan count 1, logical reads: (regular=6545 apf=0 total=6545), physical reads: (regular=0 apf=0 total=0), apf IOs used=0


===> Total actual I/O cost for this command: 1.358.992.
Total writes for this command: 6884

Execution Time 18.
SQL Server cpu time: 1800 ms. SQL Server elapsed time: 107.326 ms.

(113 rows affected)
----------------------------------


Portanto vemos que a Alternativa A ainda foi uma melhor modificação.

Uma observação adicional, é que ao mudarmos a select original, também foram eliminados alguns resultados desnecessários, que precisariam processamento posterior, daí a diferença na quantidade de registros resultante ter baixado de 121 para 113.


Comparativo


Custo Total
I/O
Tempo Execução
Tempo CPU
SQL Server elapsed time
Original
132.860.664
749
74900 ms
1.471.296 ms
Alternativa A
1.317.060
15
1500 ms
83.800 ms
Alternativa B
1.358.992
18
1800 ms
107.326 ms



Conclusão:

Obtive para a empresa uma redução aproximada de 99% na quantidade de I/Os necessários e de 98% no tempo de execução.

Alguns pontos podem ser melhorados, mas em face do ganho obtido, já ficou num nível mais satisfatório, especialmente considerando a cultura local da empresa. 

Assim, passaram a tomar decisões mais rápidas, negócios de milhões $ que puderam agilizar de maneira melhor e certamente maiores lucros. 


Resultados:

  • Enorme economia de recursos.
  • Maior disponibilidade do servidor para atender outras transações.
  • Maior satisfação do usuário final que passou a ter muito mais agilidade.
  • Ciclo de desenvolvimento e testes do programa foram reduzidos a uma fração do previsto.
  • Ganhos de milhões de $ para a empresa diariamente. 


Gostaram do exemplo? 

Apenas para citar, que tal outro caso de uma aplicação chave para a empresa, novamente envolvendo muitos milhões de $ e demorava 16-18h. Só podiam executar no fim de semana e tinham que cortar os servidores da rede. Consegui reduzir para menos de 2h e sem afetar a rede. Neste caso, além de otimizar o SQL também foram utilizadas soluções de lógica complexa necessarios para melhor uso da CPU e obter melhores resultados. 

Quanto sua empresa ganha com serviço bem feito


Se precisam de um profissional de longa experiência que sabe o que fazer, aceito convites que sejam realmente sérios. Só falo diretamente com o responsável pela contratação, não entro em fila e nem preencho ficha em site.  




Leia também:



..

terça-feira, 25 de agosto de 2009

Levando Legados ao Ideal

Uma coisa que me ocorre quando se trata de sistemas legados, e até por ter que lidar tanto com eles nestes anos todos, entre uma conversão e outra, é que temos um mundo real e um ideal.

O mundo ideal, é aquele em que estamos longe do legado. Usamos outras ferramentas mais atuais, espiamos pela janela do vizinho para ver como são lindas as interfaces gráficas (que ele j-u-r-a que funcionam), conexões entre as mais diversas plataformas...

Enfim, o mundo ideal é aquele que muitas vezes sonhamos em alcançar, mantendo tudo de bom que o sistema atual tem e agregando tudo que gostariamos que tivesse.



Sabem, depois de mais de quinze anos usando Clipper e participando de fóruns, principalmente na Usenet onde encontramos caras como o Dave Pearson e outras feras que participaram na criação destas linguagens, podemos observar que as alternativas podem estar muito mais próximas do que pensamos.

Claro que eu gostaria de converter tudo direto para algo "topo de linha", do dia para a noite, sem nunca mais me preocupar em ter que manter dois sistemas em paralelo durante o desenvolvimento, muito menos ouvir a choradeira de alguém com saudade dos velhos programas... (AAAARGGGGG!!!!....)

Mas e se dizermos por partes? Agregando algo aqui e ali. Fazendo, por exemplo no Clipper, um super tunning simplesmente com a adoção do ADS, que ajuda a resolver a vasta maioria dos problemas de limitação dos arquivos DBF, aumenta estupidamente a performance, com segurança e integridade e, sem limitação de tamanhos de arquivo? E de quebra, fica pronto para você migrar para DB relacional... Claro que corrupção de dados pode ser por erro de programação ou projeto, mas aí já entra o nosso trabalho.

Fazendo um tunning destes, claro que você não deve contar o milagre todo para seu usuário, que poderia automaticamente pensar que você ficou desocupado e vai atropelar o resto do trabalho.

Continuando, sobre coisas que se vê por aí. Na usenet conversavamos com uns caras de uma rede de lojas norte-americana. Eles já usavam algo tipo VPN (no início dos anos 2000), conectando todas as lojas, num enorme sistema integrado que cobria todo o país. Tamanho da coisa? Mais de MIL lojas. Tudo em Clipper 5.2e, um pouco de sabedoria, muita experiência e aquela paciência necessária para fazer algo bem feito.

Posteriormente estavam começando a colocar uma interface gráfica para Windows, creio que era o FiveWin, e na época, não cogitavam ainda usar o Harbour que recém estava engatinhando.

Fazendo uma revisão aqui, na época, o sistema deles tinha integração com e-mail, planilhas, diversos outros sistemas de arquitetura diferentes, etc. A parte de relatórios a muito já estava sendo migrada para utilização de ferramentas produtividade, como Crystal Reports, o próprio Ms-Access e outras tantas.

Mas o que importa, é que essa idéia funciona: ir aos poucos colocando coisas novas. Sabe que as vezes o Frankenstein pode funcionar melhor numa migração tranquila do que arriscar uma fortuna numa migração maciça?
.'.

segunda-feira, 10 de agosto de 2009

O Guia de Referencia para o Programador Pragmatico

Para quem pretende ser um bom programador, no link abaixo tem um ótimo resumo do livro.
Material excelente de condutas a serem, no mínimo, pensadas.

Só alguns pontos:

# Care About Your Craft.
Cuide do que faz. Porque gastar sua vida desenvolvendo software a menos que você se importe em fazer isto bem feito?

# Think! About Your Work.
Pense. Sobre seu trabalho. Desligue o piloto automático e assuma o controle. Constantemente critique ou aprecie seu trabalho.

# Provide Options, Don't Make Lame Excuses.
Forneça opções. Não desculpas esfarrapadas.
Ao invés de desculpas, provenha opções.Não diga que não pode ser feito. Explique o que pode ser feito.

# Don't Live with Broken Windows.
Não viva com janelas quebradas.
Fixe mau design, decisões erradas e código ruim quando os ver.

# Evite repetições.

# Faça-o fácil de ser reusado.

# Faça o design e codificação na linguagem do usuário.

# Finish What You Start.
Termine o que começa.
Sempre que possível, a rotina ou objeto que alocar um recurso deveria ser responsável por desalocar.

# Fixe o problema, não a culpa.

# E por último: "Sign Your Work"
Assine seu trabalho.
Desde os tempos antigos, os artesões tem orgulho de assinar seu trabalho bem feito. Você deveria também.



"The Pragmatic Programmer Quick Reference Guide"
http://www.codinghorror.com/blog/files/Pragmatic%20Quick%20Reference.htm

quinta-feira, 6 de agosto de 2009

Citações de TI

A internet é o Viagra de grandes negócios.
Jack Welch


"O problema com os programadores é que você nunca pode dizer o que  
um programador está fazendo até que seja tarde demais."
Seymoure Cray  

"Só existem duas indústrias que referenciam seus clientes como usuários."
Edward Tufte

(Para quem não sabe, são: Informática e Tráfico de drogas entorpecentes)
            
"Software é como sexo: é melhor quando é livre."
Linus Torvalds

"Existem duas maneiras de escrever programas livres de erro. Só a terceira funciona."
Alan Perlis

"Homens são de Marte, mulheres são de Vênus e computadores são do inferno."

"Depois da linguagem de programação,
a linguagem mais usadas pelos programadores
é a linguagem obscena."


Buddha with Bird Nest
Escultura de Edward Tufte
.'.

Leia outros artigos relacionados clicando nas tags abaixo:

quarta-feira, 29 de julho de 2009

As lições dolorosas do Outsourcing.

Outsourcing pode tornar-se um verdadeiro show de horrores. Principalmente quando a comunicação interna é falha e houver enfoque apenas em custos.

Confiram alguns casos (muito) mal sucedidos:

http://www.infoworld.com/d/adventures-in-it/painful-lessons-it-outsourcing-gone-bad-032

Em tempo: Ao contrário do que os céticos pensam, santo de casa faz milagre sim.

sexta-feira, 12 de junho de 2009

Corrigindo Corrupção de Dados em arquivos DBF - Clipper, xHarbour, xBase, etc

Clipper - Corrupção de Dados

Desenvolvedores que utilizam a linguagem Clipper frequentemente vão se deparar com problema de corrupção de dados em arquivos DBF e/ou nos índices.
Descartando os problemas que possam ser eventualmente causados por falhas de equipamento, cabos, placas, HD com defeito, etc, na ampla maioria das vezes, estes problemas são totalmente contornáveis, bastando ao programador, adotar medidas preventivas no seu programa.
Tratamento de erros é algo que todo bom programador deve adotar se quiser apresentar sistemas confiáveis para o usuário.
A solução abordada também é válida para Foxpro, xBase++, xHarbour, etc
A lógica aqui apresentada, serve também como modelo para linguagens de outras categorias, pois trata-se de princípios universais a serem observados.
Em tempo, também podem ocorrer problemas de perdas de dados por causa do tamanho dos arquivos. O DBF possui limitações de tamanho, que varia um pouco, mas geralmente ao redor máximo de 1Gb. Neste caso, você terá que adotar um gerenciador diferente para seus dados.
Para os usuários de DBF, que não queiram, ou não precisam reprojetar imediatamente seus dados para outro formato, como SQL, recomendo o ADS Advantage Database Server, excelente gerenciador client/server da Sybase. É altamente performante, agrega muita segurança ao processamento e é uma boa opção para grandes volumes de dados. E também, já é uma porta para quem estiver pensando em migrar para SQL.

Vamos lá então:

-----------------------------------------------------------
Impedindo Erros de Gravação em Clipper

Principais Erros:
* Corruption Detect
* Internal Error 19
Uma das principais causas de corrupção de dados ocorre ocorre porque nem sempre o LOCK é bem sucedido, devido a demora na rede, ou porque o registro está bloqueado noutra estação.
Este código testa se o lock foi bem sucedido, senão, faz um loop padrão de N-vezes ou até o limite solicitado.
Se ainda não conseguir, vai apresentar uma mensagem na tela avisando que está a espera de liberação, a qual o usuário pode interromper por ESC.
A rotina aceita um parâmetro para especificar quanto tempo aguardar.
Adaptem o código ao seu caso:
Desenvolvido em Clipper 5.2e
Cabeçalho:
#command default <variable1> to <value1> [, <variableN> to <valueN> ] => ;
if <variable1> == nil; <variable1> := <value1>; endif;
[; if <variableN> == nil; <variableN> := <valueN>; endif ]
// Código desenvolvido por Gilberto Strapazon
//
Function Exemplo
//
// Exemplo de uso da função NET_REG
if .not. Arquivo->(dbseek(chave))
Arquivo->(dbappend())

...(seu código aqui) gerar chave, etc...
endif
if .not. net_reg()
mensagem("Nao foi possivel incluir registro no arquivo",, 0)
return false
endif
Replace Arquivo->campo1 with OutroArquivo->campo1,;
Arquivo->campo2 with OutroArquivo->campo2
Arquivo->(dbunlock())
Arquivo->(dbcommit())
Return true
Function NET_REG(limite)
local savtela
local xvezes
local msgaviso
local windx
local wcontador
default limite to 0 // se limite > 0, aguarda N segundos e volta
// se limite == 0 fica aguardando
CLEAR TYPEAHEAD
savtela := savescreen(0, 0, maxrow(), maxcol())
savcolor := setcolor()
xvezes := 0
wcontador := 0
msgaviso := "Aguardando para gravar registro no arquivo " +
alltrim(alias(select()))
do while true
if Rlock() // Se conseguir bloquear o registro
restscreen(0, 0, maxrow(), maxcol(), savtela)
return true // Retornar...
endif
//
if (xvezes < 6)
xvezes++
inkey(0.5)
loop
endif
aguarde(msgaviso) \\ janela padrão de Aguarde
mensagem(msgaviso) \\ rotina padrão de mensagem rodapé
@ maxrow()-1,00 say padc(msgaviso + ". Tecle ESC para interromper")
if inkey(0.5) = K_ESC // aguarda 0.5 segundo
setcolor(savcolor)
restscreen(0, 0, maxrow(), maxcol(), savtela)
return false
endif
wContador++
if limite > 0 .and. ; // se for informado limite
wContador > limite // aguarda o tempo especificado
restscreen(0, 0, maxrow(), maxcol(), savtela)
return false // aviso de erro. Nao bloqueou
endif
//
enddo
restscreen(0, 0, maxrow(), maxcol(), savtela)
return(true)
Function mensagem(vMsg, vJust, vtempo, vLinha, vTom)
// Apresenta mensagem padrao no rodape da tela ou na linha informada
// Se for informado TEMPO, faz pausa pelo tempo especificado
// Se for informado TOM, soa um sinal.
local savcolor
public cRealce := "W+/R,N/W,,,W+/R"
default vMsg to ""
default vJust to "E"
default vTempo to nil
default vLinha to maxrow()
default vTom to false
savcolor := setcolor()
vJust := upper(vJust) // padroniza parametro
if empty(vMsg)
setcolor("GR+/B")
else
setcolor(m->cRealce)
endif
do case
case vJust = "E"
@ vLinha, 0 say padr(vMsg, maxcol()+1)
case vJust = "C"
@ vLinha, 0 say padc(vMsg, maxcol()+1)
case vJust = "D"
@ vLinha, 0 say padl(vMsg, maxcol()+1)
endcase
if vTom
tone(440,1)
endif
if vTempo <> NIL
inkey(vTempo)
endif
setcolor(savcolor)
return
Function Aguarde(mensagem, linha, cor)
// Mostra mensagem hh:mm:ss aguarde...
//
local wcoli
local wlinf
local wcolf
local tammsg := 0
local savcolor
public cRealce := "W+/R,N/W,,,W+/R"
default linha to (maxrow()/2)-3
default cor to m->cRealce
savcolor := setcolor()
setcolor(m->cRealce)
mensagem := time() + " " + alltrim(mensagem)
tammsg := (maxcol() - (len(alltrim(mensagem)))) / 2
wlinf := linha + 3
wcoli := tammsg - 2
wcolf := (maxcol() - tammsg) + 1
janela(linha, wcoli, wlinf, wcolf, mensagem,, false, cor)
@ linha +2, wcoli+ 2 say mensagem
setcolor(savcolor)
return(NIL)
==================================================================