segunda-feira, 24 de outubro de 2011

Formatando datas no SQL e no C#

Muitas vezes é necessário exibir datas em um determinado formato no GridView. Muitos programadores convertem a data para o formato desejado já na consulta SQL ou procedure. Isso não está correto por uma série de motivos, entre os quais podemos citar:

1) A responsabilidade de formatar a data deve ser totalmente da view, ou seja, da camada de apresentação.
2) Datas formatadas pelo SQL não são mais datas, são varchars, e não podem ser ordenados como datas.
3) Trazendo sempre a data integral do banco de dados pode-se fazer qualquer operação desejada com ela.

Veja o link abaixo para tirar qualquer dúvida que você possa ter a respeito.
http://weblogs.sqlteam.com/jeffs/archive/2007/04/13/format-date-sql-server.aspx

Dito isso, algumas considerações interessantes:

Para formatar strings diretamente em uma GridView adicione a coluna (bound column) e defina um valor para a propriedade DataFormatString:


<asp:BoundField DataField="Data" DataFormatString="{0:dd/MM/yyyy}" HeaderText="Data" />
<asp:BoundField DataField="Hora" DataFormatString="{0:HH:mm:ss}" HeaderText="Hora" />

dd - Dia com dois dígitos
MM - Mês com dois dígitos, deve ser maiúsculo
yyyy - Ano com quatro dígitos

hh - Hora no formato de 12 horas (necessário AM e PM)
HH - Hora no formato de 24 horas
mm - Minuto
ss - Segundo

Função para extrair a data de um datetime, com hora 0:00:00


CREATE  function [dbo].[sudf_Common_DateOnly]
(
@dtDateTime DateTime
)
returns datetime
as
begin
    return dateadd(dd, 0, datediff(dd, 0, @dtDateTime))
end

Função para extrair a hora de um datetime, com data 01/01/1900


CREATE function [dbo].[sudf_Common_TimeOnly]
(
      @dtDateTime datetime
)
returns datetime
as
begin
    return dateadd(day, -datediff(day, 0, @dtDateTime), @dtDateTime)
end
Fonte:
http://www.lazerwire.com/2011/10/ms-sql-date-only.html
http://www.lazerwire.com/2011/10/ms-sql-time-from-datetime.html

Melhor fonte de informação sobre esses formatos:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.boundfield.dataformatstring.aspx

Funções para lidar com datas:
http://msdn.microsoft.com/en-us/library/aa258863(v=sql.80).aspx

Conversão de datas com Convert no SQL Server:
http://www.sql-server-helper.com/tips/date-formats.aspx


Have fun ;)

segunda-feira, 12 de setembro de 2011

Factory Reset do Samsung Galaxy S

Neste endereço http://www.clangsm.com.br/vb/android-os/9802-aparelhos-android-hard-reset.html também há um procedimento para resetar o Galaxy S e apagar tudo, servindo para desbloqueá-lo.

Reproduzindo:
Para hard reset seu Samsung I9000 Galaxy S:

1. Desligue o aparelho. Se o seu celular Samsung Galaxy S está congelado, retire a bateria e recoloque-a.
2. Segure o botão Diminuir Volume.
3. Pressione e solte o botão Power.
4. Você está agora confrontado com um menu que permite Fastbook, recuperação Clear Storage, e Simlock.
5. Selecione Clear Storage, pressionando o botão Diminuir Volume.
6. Pressione e solte o botão Power.
7. Agora, basta confirmar a sua decisão: Volume para cima para confirmar e Volume para baixo para negar a ação.

Se SIM for selecionada, todos os dados, incluindo aplicações de terceiros serão apagados do seu Samsung I9000 Galaxy S. Uma vez que a limpeza for concluída, o telefone irá reiniciar a suas configurações de fábrica.

ou

-Botão do volume para cima+botão home+power
-Espere piscar I9000, solte o power (continue segurando home +volume)
-Com o botão do e volume selecione wipe data/factory.reset
-Home para confirmar
-Com o botão do volume vá até : yes - delete all user data
-Home para confirmar novamente
-Espere voltar e reboot system now
-Home para confirmar


É isso. Usei esse menu para outras coisas, como acesso de root, mas não para resetar. É por sua conta e risco.

segunda-feira, 15 de agosto de 2011

Criando um lookup que chame uma de suas forms

Um leitor deu a dica de fazer um lookup que chame uma das forms do projeto. Há várias maneiras de se fazer isso, mas uma que encontrei foi usar formulários registrados com RegisterClass. Depois é só usar FindClass para encontrar o formulário, e FindComponent para encontrar o componente onde reside o valor a ser trazido. Se o componente for um TPersistentField, melhor ainda. Ele pode ser achado, e com um typecast para TField seu valor (o valor encontrado e escolhido no formulario de procura/cadastro padrão) pode ser trazido para o keyvalue.

Abaixo um exemplo de como isso pode ser feito. Primeiro o registro do formulario:
initialization

  RegisterClass(TfrmConsulta);

Depois a chamada dele. Repare que ele é desconhecido para o formulário principal: não está no uses.
procedure TfrmPrincipal.Button1Click(Sender: TObject);
var
  NewFormClass: TFormClass;
  NewForm: TForm;
begin
  NewFormClass := TFormClass(FindClass( 'TFrmConsulta' ));
  //detalhe: esse  string 'TFrmConsulta' pode vir de um campo, edit, banco de dados, arquivo de configuração etc
  try
    NewForm := NewFormClass.Create(nil);
    NewForm.ShowModal;
  finally
    FreeAndNil(NewForm);
  end;
end;

Esse exemplo mostra como registrar formularios e chamá-los sem colocar no uses e sem que o "cliente" saiba da sua existencia.
Assim que tiver um tempo coloco isso encapsulado em um lookup.

quinta-feira, 11 de agosto de 2011

Bancos de dados gratuitos parte 2

Saiu na Clube Delphi 132 a parte 2 do artigo sobre bancos de dados gratuitos. Espero que todos gostem.

Esta edição ainda traz um artigo sobre Nota Fiscal Eletrônica 2.0, muito útil.

Não se esqueça que agora os códigos GTIN (códigos de barra a serem preenchidos nos campos cEAN e cEANTrib) agora são obrigatórios.

Um artigo que eu lerei com bastante curiosidade é o artigo sobre Morfik, que permite desenvolvimento par Web com Object Pascal, semelhante ao Delphi. Mas com o Morfik você também desenvolve código "client-side".

Espero que todos tenham boa leitura!

Artigos sobre bancos de dados gratuitos e lookups

Saiu na revista Clube Delphi 131 dois artigos meus: um sobre bancos de dados gratuitos e outro sobre a criação de um componente lookup genérico.

Lokups são campos utilizados para fazer a ligação entre duas entidades, duas tabelas. Em uma tabela de venda, por exemplo, há informações sobre o código do cliente para quem a venda está sendo feita, o código da forma de pagamento, e assim por diante. Um formulário não deve ter campos para se digitar os códigos diretamente, e sim campos lookup, que possam ser usados para procurar a forma de pagamento, o cliente e as outras informações em questão pelo nome e não pelo código. Neste artigo fizemos um lookup, usando um ButtonedEdit e um formulário com grid,  que pode funcionar em múltiplos bancos de dados e que traz os registros filtrando-os, usando para isso uma instrução SQL montada sob demanda. Isso ajuda a diminuir o tempo de abertura dos formulários e o tempo de carregamento dos lookups, bem como a quantidade de registros trazida nesses tipos de campo.

O outro artigo publicado fará parte de uma série de 3 artigos sobre bancos de dados gratuitos e ferramentas de acesso. Além do postgre, mysql e firebird ainda existem as versões gratuitas do DB2, Oracle, SQL Server entre outros. Além disso o artigo abordará como criar bancos SQLite e se conectar a eles.

Você sabia que além do DBXpress também há outras formas de se conectar a múltiplos bancos de dados? Existe o AnyDac, Zeos, Unidac, dezenas de drivers OLEDB ou ODBC, a possibilidade de usar ODBC com o DBXpress (que será recurso nativo do Delphi XE2) entre outros. Mas a suite de componentes de conexão mais rápida que eu já via é a Unidac.

Ambos os artigos terão uma continuação extra-oficial neste blog. O artigo sobre bancos de dados gratuitos terá um teste de performance mais profundo, fazendo também inserts e updates e usando clientdatasets em conjunto com outros tipos de datasets que não sejam o SQLDataset do DBX. Esse servirá como um catálogo definitivo de conexão com qualquer banco de dados.

Um leitor da Clube Delphi me deu uma dica interessante de colocar uma propriedade do tipo string no lookup e fazer com que ele chame um formulário de consulta ou cadastro que tenha o mesmo nome preenchido nessa propriedade. Isso faria com que o lookup pudesse "chamar" qualquer formulário do sistema sem que ele conhecesse suas units ou sequer soubesse que elas existem. Funcionalidade extra sem acoplamentos desnecessários.

Espero que tenham uma boa leitura.

sexta-feira, 15 de julho de 2011

erro "ora-12154: tns: não foi possível resolver o identificador de conexão especificado"

Para se conectar uma aplicação Delphi no Oracle é necessário editar o arquivo tsnames.ora, geralmente na pasta C:\oraclexe\app\oracle\product\10.2.0\server\NETWORK\ADMIN caso seu oracle seja o XE.
Esse erro pode acontecer tanto em runtime como em design-time, com qualquer tipo de componente: DBX, ADO e assim por diante. É mais comum que aconteça em tempo de design em um windows de 64 bit. 
Em alguns casos onde essa mensagem de erro aparece é porque o arquivo não existe ou está em uma pasta que o Delphi ou o seu aplicativo não tem permissão de acesso. 
Na grande maioria dos casos o erro ocorre apenas em design-time e nunca em runtime. Se esse é o seu caso  então provavelmente a culpa é do windows de 64 bit, mais especificamente o fato de o Delphi estar instalado na pasta "Arquivos de Programas (x86)". Explicando, o driver de conexão ao oracle não suporta caminhos contendo parênteses "()", esses que tem no "(x86)". Ele não consegue encontrar nem o driver de conexão nem o arquivo tsnames.ora por causa desses parênteses. Instale o Delphi em uma pasta tipo "Arquivos de Programas" "normal" ou até mesmo em uma pasta direto na raiz, como c:\Delphi.
Se o Delphi já está instalado nesta pasta problemática ainda assim é possível copiar toda a pasta do RAD STUDIO (geralmente C:\Arquivos de programas (x86)\Embarcadero\RAD Studio) para uma pasta qualquer, tipo c:\rad studio, e execute o Delphi dali. (ele se encontra na pasta 7.0\bin se for o 2010 ou 8.0\bin se for o XE, é o arquivo bds.exe).
Ele vai executar normalmente, mesmo no local "errado", já que tudo que ele precisa em matéria de bibliotecas está no registro e ele consegue encontrar no diretório original, e isso não impedirá de que uma conexão DBX com o oracle funcione normalmente. Vai funcionar mesmo em design-time, e compilar sua aplicação normalmente.

Have fun ;)

quinta-feira, 30 de junho de 2011

Key Violation em nested datasets

Resolva de uma vez por todas o problema de "key violation" em datasets "detail" ligados a datasetfileds através de providers.

Cenário: você tem duas tabelas num relacionamento 1:n tipo mestre-detalhe no seu banco de dados, por exemplo Pedidos e ItensDoPedido.
A chave primária de ambas as tabelas é auto-numerada, por exemplo com ajuda de um generator do firebird. A Tabela itens tem uma chave estrangeira PedCodigo, que é o código do pedido, mas para controle interno também tem uma chave primária CodItem, autonumerada.
Você colocou no formulário dois SQLDatasets, um fazendo o select em Pedidos e outro fazendo o select em ItensDoPedido, com um "where CodPedido = :CodPedido" para fazer a "ligação". Você ligou o SQLDataset detalhe (ItensDoPedido) a um datasource ligado ao SQLDataset mestre. Você ligou também um DatasetProvider ao SQLDataset de Pedidos e ligou um ClientDataset cdsPedidos a esse provider, criando um dataset field (campo do tipo dataset), talvez chamado sqlItens, e ligando o ClientDataset cdsItem a este dataset field, criando assim o cdsDetahle.

Você talvêz tenha recebido alguma mensagem de que o campo CodItem é requerido e não pode ser deixado null, então tomou providências para deixar a propriedade required do campo = false ou atribuido algum valor randômico a ele. Se fez isso é sinal de um design fraco. Há maneiras mais elegantes de se resolver isso, veja as soluções 2 e 3.

Problema: Quando você insere o segundo item no ClientDataSet cdsItem recebe a exception "Key Violation".

Causa: O cdsItem (detalhe) também possui uma chave primária, CodItem. Quando você dá o post no segundo item ele é gravado com o mesmo valor do registro anterior: null ou zero se você definiu para atribuir zero no evento "onNewRecord" ou "beforepost". Como chave primária ele não pode se repetir no cdsItem, mesmo sabendo que os códigos serão criados no banco de dados automaticamente depois do applyupdates e do commit da transação. Antes disso não há valor definido para a chave primária do item.

Há 3 maneiras de solucionar:

1) Atribua um número randômico (pode até ser negativo) ou GetTickCount à chave primária no evento OnNewRecord.
Desvantagens: essa é a gambiarra mais feia e porca que existe. Além de poluir o código, caso o número randômico se repita, o que estatisticamente pode acontecer, ocorrerá o key violation. Caso use GetTickCount este pode trazer um número maior do que o suportado pelo integer field, já que retorna um cardinal sem sinal, podendo causar o erro de integer overflow. Portanto a solução 1 está aqui para fins "didáticos" (ou não). Nunca a use.

2) Para que você precisa trazer o campo da chave primária do item? Na maioria das vezes isso não é necessário. Você pode incluir todos os campos no select exceto a PK, já que ela ainda não está definida. E você não precisa exibi-la caso ela esteja null. Isso resolve o problema de uma maneira performática e elegante.

3) Metadados: Como o ClientDataset sabe que tal campo é chave primária se ele não é conectado diretamente ao banco de dados? Ele "sabe" isso porque provavelmente a propriedade GetMetadata do SQLDataset deve estar true. Colocando essa propriedade para false  o ClientDataset não "saberá" que esse campo não pode se repetir, muito menos que ele é requerido. Além disso o ClientDataset abre muito mais rápido caso essa propriedade esteja false, pois não tem que fuçar nos metadados da tabela. Essa técnica é ideal para quando você precisa mostrar o número da PK logo depois da inserção e persistência. Como por exemplo mostrar um número de comanda num sistema de restaurante ou mostrar o número da "carteirinha" de um cliente recém inserido.
Desvantagem: se por algum motivo, como campo requerido, not null ou qualquer outro você precisa que os metadados sejam trazidos para que sejam tratados no client e não no server esta técnica não deve ser usada, recorra à 2.

Mencionei o problema ocorrendo em nested datasets mas ele pode ocorrer em ClientDatasets "normais" ligados a uma única tabela.

Uma mistura das soluções 2 e 3 quando aplicável é a melhor e mais performática solução. Quando nenhuma das duas pode ser usada, ou seja, você precisa dos metadados por algum motivo e ainda precisa exibir a chave primária criada logo depois do registro salvo, considere usar um outro tipo de arquitetura, ou usar chaves primárias definidas via programação em vez de generators.

Happy Coding  \(^.^)/

segunda-feira, 27 de junho de 2011

O que você melhoraria no Delphi? - parte 2

Na parte 1 desse post, há muito tempo, fiz uma pequena descrição do que eu acho que poderia ser melhorado no Delphi.

Resumindo:
1) Alguns componentes e bibliotecas mais comuns "nativos" em vez de "incorporados".
2) Literatura orientada mais a POO e a boas práticas da Engenharia de Software do que a RAD. A literatura disponível nos helps, exemplos, snippets e consequentemente nos blogs e fóruns é toda voltada a RAD, arrastar e  soltar componentes. E como todos sabemos RAD é bom para protótipos e projetos pequenos, ou com requisitos fixos, com baixa frequencia de manutenção.
3) O aspecto que eu acho mais importante é (a falta de) um framework de persistência nativo da Embarcadero, para se fazer o mapeamento objeto relacional de maneira padronizada e ao mesmo tempo rápida.


Continuando, uma coisa que eu acho muito importante são as ações de marketing. No Brasil parece que o Delphi está queimado justamente com quem mais deveria acreditar nele: os professores.
Digo isso por experiência própria, pois meu projeto de conclusão de curso da pós graduação passou por esse problema.
Minha monografia era para ser "frameworks de mapeamento objeto relacional em Delphi". Meu orientador, professor de engenharia de software e outras matérias. Delpheiro de carteirinha e especialista em Delphi me perguntou "Por Que Delphi?". Ele questionou que meu trabalho, focado em Delphi, seria para um público muito restrito e que o Delphi está fadado a cair no desuso (nas palavras dele).
Não concordo com o ponto de vista dele sobre o Delphi, mas concordei que eu teria que expandir meus horizontes se quisesse fazer um trabalho academicamente mais amplo. Por isso meu tema foi trocado para "Processo de criação de frameworks de mapeamento objeto relacional em ambientes open-source".

O ponto em questão é que os professores, em vez de recomendar Delphi, estão "des-recomendando" (se é que esse termo existe). E agora como convencê-los do contrário?

Outro ponto é quanto ao preço do Delphi, mais caro que a concorrência. Quando saiu a edição "starter" do Delphi realmente o preço saiu bastante tentador. Mais barato que uma licença do windows 7 ultimate. Mas meu interesse na versão starter despencou quando eu soube que esta verão não possui dbexpress. Qual a utilidade do Delphi, para se fazer sistemas de informação, sem o dbExpress? Se conectar com MySql através de ADO+ODBC? BDE? Não, obrigado. Terei que comprar a suíte de componentes Unidac (que eu recomendo, muito boa).

Conversando com uns amigos no evento de lançamento da Embarcadero no Brasil chegamos a seguinte conclusão: por que não vender o Delphi "pelado", apenas IDE e compilador, por um preço simbólico e vender os componentes e add-ons sob demanda? Pense nisso:
Hoje em dia estão na moda as AppStores, onde você compra uma aplicação a um preço justo, e esta aplicação é sua, sendo sincronizada em seus dispositivos com o mesmo sistema operacional. Se você formata / reseta seu sistema, suas aplicações já pagas/compradas da appStore são baixadas e instaladas novamente. Tudo é re-sincronizado automaticamente. O mundo da Apple funciona assim, com o iPhone, iPad, iPod  e com o iMac. O mundo do Google Android também funciona assim, e até a Intel entrou na brincadeira.
Qual é o maior problema quando um desenvolvedor Delphi tem que formatar sua máquina? Ele perde um dia inteiro, ou dias, reinstalando, além do Delphi, todos os componentes, open-source ou não, bibliotecas e adds que precisa para trabalhar produtivamente. Muitos tentam exportar chaves de registro, e copiar diretórios de bpl's e dcp's a fim de criar uma instalação do Delphi personalizada para poder instalar depois, ou fazem ghost da máquina. A situação se torna pior se a empresa tem vários programadores Delphi, com várias máquinas diferentes e várias licenças pra instalar. Pior ainda se lida com versões diferentes do Delphi.
Solução: por que não criar um instalador mínimo do Delphi e um appStore de componentes e bibliotecas? Assim, bastaria instalar o Delphi e logar-se com a sua conta na Embarcadero para re-instalar e sincronizar todos os componentes. E isso serviria quem sabe para você publicar um componente seu e ganhar com ele, porque não? Até mesmo para se fazer "Component Contests".
Isso poderia ajudar a garantir o controle de qualidade, testes etc de um componente, além da procedência, e garantir, principalmente para os não-open-source, uma sobrevida e um tempo de suporte maior, além de tornar a instalação do Delphi muito mais fácil e a busca, aquisição e instalação de componentes muito mais fácil.
Quando eu digo componentes me refiro à bibliotecas "normais" também, daquelas que você precisa instanciar uma classe, ou usar uma função, mas que não tem um componente em uma paleta pra colocar na form.
A maioria dos componentes precisam que arquivos sejam colocados em certos diretórios, e que certos caminhos sejam adicionados ao library path e browsing path do windows. Além disso os instaladores dos componentes são todos diferentes, quando há instalador, pois a maioria você deve compilar a partir dos dpk's.
Agora imagine um ambiente com um gerenciador de componente que encontra o componente que você precisa, faz as devidas inclusões dos paths, compila e instala se for open-source ou simplesmente instala se não  for, e te livra de todos os passos chatos, demorados ou complicados.

Essas são algumas coisinhas que eu acho que poderiam ser melhoradas. E vocês, o que acham?

quarta-feira, 22 de junho de 2011

Grande verdade sobre developers


Além de encarar qualquer problema de frente, assumimos a responsabilidade pelos bugs, sejam eles nossos, de "estimação", ou não.

quinta-feira, 26 de maio de 2011

Que saudade das férias

Estava limpando a bagunça do meu PC e encontrei uma foto que me deu saudade das férias.


Tudo ok com vocês peixinhos? Oh wait, isso não foi um gesto obsceno, aaaaargh.

segunda-feira, 23 de maio de 2011

Easter Egg de Fringe no site da Bardahl

Entre no site da Bardahl, clique em história da Bardahl ==> Museu Bardahl 3d em flash, quando carregar um "mural" com vários anos clique em próximo para ver o próximo "mural/parede" e clique em 1962.

Veja quem está observando ...

Biblioteca MadCollection

Saiu na edição 129 da Revista Clube Delphi meu artigo sobre a madCollection.
Francamente não sei como não é distribuída juntamente com o Delphi, ou com qualquer outra linguagem / IDE, uma biblioteca tão útil. Explico: ela te permite fazer o que as vezes nem a API do windows permite. Neste artigo dei algumas pinceladas, mas a biblioteca é muito maior do que eu demonstrei.

Mencionando os artigos que estou lendo AGORA: o artigo dbExpress 4 do Fabrício Kawata e o Padrões Criacionais do Rafael Stavarengo chamaram muito minha atenção.

Boa leitura.

quarta-feira, 13 de abril de 2011

Para descontrair hoje








Uma boa tarde a todos!

Sobre livros

Eu gosto de ler. Não sou um rato de biblioteca, não tenho leitura dinâmica e não leio tão rápido ou com tanta frequência (sem trema desta vez), mas gosto de ler.
Gosto de comparar uma boa leitura com uma boa refeição. Já percebeu que às vezes um prato simples, em um restaurante pequeno de um bairro não muito movimentado pode te surpreender? Pode ser exatamente igual ao que sua mãe fazia, por exemplo.
O mesmo acontece com livros. Às vezes não damos muita atenção para um livro, e ele nos surpreende. Não apenas pela história envolvente, mas pelas "notas". Sim, notas. Para quem degusta vinhos, café ou perfumes está acostumado a ouvir essa palavra, "notas", fora de um contexto musical. Nos vinhos, pratos e perfumes notas são características, que não são plenamente fixas ou mensuráveis, mas são nebulosas. Não têm extremos, mas têm infinitas gradações.
Quantas gradações de sabor podem existir entre o amargo do café e o doce do chocolate? Entre um perfume e outro?
Essas "notas" podem ser encontradas em livros. E não apenas em romances ou ficções, mas em livros técnicos, enciclopédias, trabalhos científicos, quadrinhos, livros religiosos etc... Elas atingem sua mente, ressoam no seu intelecto, reverberam no seu íntimo, retinem em sua alma, misturam-se a todas as suas crenças, filosofias, conhecimentos tácitos e personalidade. Por fim são incorporadas e tornam parte do seu próprio acervo, de você. Essas notas também são chamadas de memes, mas memes hoje ganharam um significado marqueteiro interneteiro muito aquém do seu real significado.
Se comparados à refeições uma revista é como um lanche em um fast-food americano. Um livro técnico é como um prato-feito de buteco: quantidade grande, comida demasiadamente comum (ou até ordinária), muita gordura e carboidrato, em frente ao seu trabalho, te preparando para o trabalho, pronto para o trabalho. Sim, da mesma forma que você só come o "pf" no buteco em frente à empresa quando está trabalhando, livros técnicos só servem para trabalho. Eles SÃO trabalho. Mas, da mesma forma que o pf, nem tudo será comido, e nem tudo será digerido. Ou você vai me dizer que devora com prazer os livros técnicos de capa a capa, mesmo as partes que você já está "saciado", mesmo sem fome desse conhecimento, e ainda assim fica mais "saudável"? Dirá que a cada livro técnico devorado seu salário aumenta 1%, 0,1%?
Livros técnicos são importantes, como o arroz, feijão, bife e salada. Mas não deveriam ser os únicos livros da  sua vida.
Recentemente eu li um livro desses, baratinho, de bolso, comprado em banca de jornal, que não valorizei muito quando vi, mas que ele se mostrou uma macarronada de domingo, com direito a frango à passarinho.
O diário do chaves vai além do que é mostrado nos episódios do seriado e, sem perder o tom de comédia, mostra um lado mais dramático, triste e até lúgubre da história.
Não vou falar mais nada, porque irá estragar sua refeição. Apenas recomendo: experimente.







Atualização:
Meio esfomeado estou hoje não? É que minha inspiração para o texto acima foi esse livro-mangá aqui:
Sentimentos se misturam num belo prato, marcados por um ritmo, um passo, intenso como a correria da vida, onde apenas nos momentos de saciar o vazio em seu estômago é que o personagem se apercebe do seu vazio existencial.
Eu gostei.

quinta-feira, 7 de abril de 2011

Uma grande verdade sobre tecnologia



Vai dizer que não é verdade.

quarta-feira, 6 de abril de 2011

Clube Delphi 128

Saiu a Clube Delphi 128, e dessa vez o meu artigo é capa! Agradeço ao Guinther Pauli, editor da revista, pela paciência que tem com meus atrasos :p

Meu artigo sobre interoperabilidade explica como integrar sistemas Delphi Win32, .Net e talvez outros através de DLLs, COM, WebServices e troca de mensagens pela API do windows.

Mostro nesse artigo como consumir uma DLL feita em Delphi através do .Net, como consumir pelo Delphi uma DLL .Net através da integração COM, como consumir pelo Delphi um webservice feito em .Net e como fazer as aplicações se comunicarem via API do windows.

Lógico, sobre interoperabilidade fiquei devendo, por questões de tempo e espaço, algumas coisinhas que pretendo mencionar em artigos futuros, na revista e/ou neste blog:



  1. .Net consumindo webservice em Delphi
  2.  Introdução do Lazarus na brincadeira
  3.  Integração por sockets
  4.  Integração por xml, json e txt

Por enquanto não vejo a hora de ler os artigos sobre programação Android com freepascal e o artigo sobreXML Data Binding.

Espero que todos tenham uma boa leitura ;)

Verdades sobre programação

Esse blog, do @luisdalmolin, contém um excelente texto sobre verdades não tão conhecidas sobre programação. Não tão conhecidas talvez pelos nossos chefes / stakeholders, mas muito bem conhecidas por nós. O post foi traduzido desse aqui  em inglês.

Basicamente, o texto fala sobre o que já sabemos:
1) Dez programadores não farão o programa em um décimo do tempo assim como nove mulheres não fazem um bebê em um mês. (apenas uma grande suruba lésbica).
2) Bons programadores passam muito mais tempo lendo, estudando, pensando, refatorando do que escrevendo, codificando e debugando. É fato! Scrum e XP pregam isso. O resto é XGH (eXtreme Go Horse).
3) Programadores (e hoje analistas de sistemas também) são tratados como peões, na rabeira do organograma da empresa, muitas vezes mesmo se destacando em sua área, possuindo graduação, pós graduação e certificações, o que significa que um programador é tratado como um operário mesmo tendo estudado tanto quanto (em alguns casos muito mais) um médico ou advogado, e continuar estudando ao longo de TODA sua carreira.
4) Planejamento é fundamental antes, durante e depois.
5) Mesmo os requisitos sendo flexíveis, isso não significa "festa do caqui" com os requisitos. E os prazos e escopo deveriam ser flexíveis proporcionalmente à flexibilidade dos requisitos.
6) Mudanças de requisitos geram entropia, ok, mas mudanças sem planejamento, sem levantamento de requisitos, direto no código, por meio de tentativa e erro até funcionar geram mais entropia ainda, tendendo ao caos, e inevitavelmente vão falhar. FALHARÃO MISERAVELMENTE.

Alguns quadrinhos humorísticos tirados do site Vida de Programador ilustram isso:



Essa outra ilustra bem a situação.


Não podemos esquecer do vídeo hug a developer! Ele ilustra de maneira bem humorada os problemas, desafios e DORES pelas quais um programador passa nas mãos e chefes porcos, cães sarnentos ignorantes ...


terça-feira, 5 de abril de 2011

Enquanto isso, em algum lugar da internet

Para descontrair...






E para quem trabalha com suporte:

IPS VIZINHOS
  • QA:
    Oi, usuário tá conectando com o IP 189.21.22.23 e não tá funcionando
  • DBA:
    Mas o IP aqui no banco de dados é o 189.22.23.25... Tem algo errado aí
  • QA:
    Ah, não são iguais, mas são bem próximos né?


fonte: http://fuckyeahdementia.com/ e http://fuckyeahitbullshit.tumblr.com/

segunda-feira, 4 de abril de 2011

A API GetuserNameEx

Primeiro de tudo, a função GetUserNameEx se encontra na dll Secur32.dll e, como outras funções da API do windows, possui duas versões, uma ANSI (GetUserNameExA) e uma WIDE (GetUserNameExW).

Abaixo segue o cabeçalho para importação dessas duas funções.

function GetUserNameExA(NameFormat: TEXTENDED_NAME_FORMAT; lpBuffer: PAnsiChar; var nSize: DWORD): BOOL; stdcall external 'Secur32.dll' name 'GetUserNameExA';
function GetUserNameExW(NameFormat: TEXTENDED_NAME_FORMAT; lpBuffer: PWideChar; var nSize: DWORD): BOOL; stdcall external 'Secur32.dll' name 'GetUserNameExW';


Atenção especial para o parâmetro NameFormat do tipo TEXTENDED_NAME_FORMAT. Ele é na verdade um Enum com alguns valores fixos. (no C também é um enum, e usa-se um ponteiro para ele)

  TEXTENDED_NAME_FORMAT  =
  (
    NameUnknown            = 0,
    NameFullyQualifiedDN   = 1,
    NameSamCompatible      = 2,
    NameDisplay            = 3,
    NameUniqueId           = 6,
    NameCanonical          = 7,
    NameUserPrincipal      = 8,
    NameCanonicalEx        = 9,
    NameServicePrincipal   = 10,
    NameDnsDomain          = 12
  );

Criei essas duas funções que me retornam uma string (UnicodeString no Delphi 2010) ou AnsiString para testar e facilitar o uso da GetUserNameEx (A ou W).

function TForm1.VtrGetUserNameExW(NameFormat: TEXTENDED_NAME_FORMAT): string;
var
  I: DWord;
begin
  I := 1000;
  SetLength(Result, I);
  GetUserNameExW(NameFormat, PChar(Result), I);
  Result := string(PChar(Result));
end;

function TForm1.VtrGetUserNameExA(NameFormat: TEXTENDED_NAME_FORMAT): AnsiString;
var
  I: DWord;
begin
  I := 1000;
  SetLength(Result, I);
  GetUserNameExA(NameFormat, PAnsiChar(Result), I);
  Result := AnsiString(PAnsiChar(Result));
end;



Estou alocando um espaço de 1000 caracteres para o resultado. É arbitrário. Quem souber uma maneira melhor de fazer isso, talvez usando outra api para saber o tamanho do nome do usuário de antemão, por favor me avise.

para testar chamo todas as funções, GetUserNameEx (A e W) passando todos os parâmetros possíveis de NameUnknown (0) a NameDnsDomain (12) e vejo o resultado.

procedure TForm1.Button2Click(Sender: TObject);
var
  enf: TEXTENDED_NAME_FORMAT;
begin
    Memo1.Lines.Add('Versão Wide -----------------------------------');
    enf := NameUnknown;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExW(enf));

    enf := NameFullyQualifiedDN;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExW(enf));

    enf := NameSamCompatible;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExW(enf));

    enf := NameDisplay;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExW(enf));

    enf := NameUniqueId;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExW(enf));

    enf := NameCanonical;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExW(enf));

    enf := NameUserPrincipal;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExW(enf));

    enf := NameCanonicalEx;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExW(enf));

    enf := NameServicePrincipal;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExW(enf));

    enf := NameDnsDomain;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExW(enf));


    Memo1.Lines.Add('Versão Ansi -----------------------------------');
    enf := NameUnknown;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExA(enf));

    enf := NameFullyQualifiedDN;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExA(enf));

    enf := NameSamCompatible;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExA(enf));

    enf := NameDisplay;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExA(enf));

    enf := NameUniqueId;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExA(enf));

    enf := NameCanonical;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExA(enf));

    enf := NameUserPrincipal;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExA(enf));

    enf := NameCanonicalEx;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExA(enf));

    enf := NameServicePrincipal;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExA(enf));

    enf := NameDnsDomain;
    Memo1.Lines.Add(inttostr(integer(enf)) +' ' + VtrGetUserNameExA(enf));

end;


Api hooking para mudar o usuário logado

Já está nas bancas a revista Clube Delphi 127 com meu primeiro artigo sobre a madShi Collection. Neste artigo eu explico o básico sobre API Hooking.

Neste post falarei sobre um exemplo que não se encontra no artigo, que é o hooking da API GetUserName.
Os motivos que levam a hookar essa API podem ser variados, e todos eles nada éticos a meu ver. Você pode desde tentar enganar um produto registrado para um usuário acessando-o como outro usuário ou simplesmente para tapear um usuário administrador, que quando olhar quem está logado verá um nome diferente (supondo que isso funcione, não testei).

A idéia é que dá para mudar a resposta que outros programas recebem quando perguntam quem é o usuário logado. Para isso é necessário conhecer quais são as api's que fazem isso e como interceptá-las.

O código dessa postagem mostra como usar a madCodeHook para interceptar a api GetUserName da api do windows.

Primeiro de tudo criei um programa que mostra o nome do usuário corrente:


function NomeUsuario: string;
var
  I: DWord;
begin
  I := 255;
  SetLength(Result, I);
  Windows.GetUserName(PChar(Result), I);
  Result := string(PChar(Result));
end;



procedure TForm2.btTestarClick(Sender: TObject);

begin
  Edit1.Text := NomeUsuario;
end;



Esse programa simplesmente mostra o usuário logado. Depois de injetada a DLL que faz o hook a chamada a GetUserName terá seu resultado mudado.
É preciso salientar que existe outra api chamada GetUserNameEx que não está mapeada na unit windows.pas e que aceita mais parâmetros, e devolve mais resultados.

Interceptar essas duas API's é certeza de que mudará os resultados às suas relativas chamadas. Não é garantia nenhuma de que será possível abrir um arquivo para o qual seu usuário atual não tem autorização, mas não custa nada tentar.

Como pôde ser visto nos artigos que escrevi para a Revista Clube Delphi, eis o código da dll a ser injetada.

Essa dll intercepta apenas a função GetUserName, deixo a cargo do leitor a GetUserNamneEx, que é mais complexa. Num post futuro trataremos da GetUserNameEx. Deixo apenas o esqueleto para quem quiser se aventurar.

Lembre-se de que se estiver usando a versão trial/demo da madCollectionHook deverá manter mchEvaluation rodando para que o hooking funcione.

library hook;

uses
  SysUtils,
  windows,
  Classes,
  madcodehook;

{$R *.res}


const
  USUORIGINAL =  'vitorrubio';    //       vitorrubio --> meu user
  USUTROCA = 'Administrador';       //       Administrador--> quem quero ser




var
  GetUserNameWNext:  function (lpBuffer: PWideChar; var nSize: DWORD): BOOL; stdcall;
  GetUserNameANext:  function (lpBuffer: PAnsiChar; var nSize: DWORD): BOOL; stdcall;


function GetUserNameWCallback (lpBuffer: PWideChar; var nSize: DWORD): BOOL; stdcall;
begin

  Result := GetUserNameWNext(lpBuffer, nSize);
  if (trim(string(lpBuffer)) = USUORIGINAL) then
  begin
    StrCopy(lpBuffer, USUTROCA);
    nSize := Length(USUTROCA);
  end;

end;

function GetUserNameACallback (lpBuffer: PAnsiChar; var nSize: DWORD): BOOL; stdcall;
begin

  Result := GetUserNameANext(lpBuffer, nSize);
  if (trim(AnsiString(lpBuffer)) = AnsiString(USUORIGINAL)) then
  begin
    StrCopy(lpBuffer, USUTROCA);
    nSize := Length(USUTROCA);
  end;

end;

begin
  HookAPI('advapi32.dll', 'GetUserNameW',  @GetUserNameWCallback, @GetUserNameWNext);
  HookAPI('advapi32.dll', 'GetUserNameA',  @GetUserNameACallback, @GetUserNameANext);
end.


Agora o código para injetar, desinjetar e testar a dll:

procedure TForm1.btInjetarClick(Sender: TObject);
begin
  InjectLibrary(ALL_SESSIONS or SYSTEM_PROCESSES, 'hook.dll');
end;

procedure TForm1.btTestarClick(Sender: TObject);
begin
  Edit1.Text := NomeUsuario;
end;

procedure TForm1.btDesinjetarClick(Sender: TObject);
begin
  UninjectLibrary(ALL_SESSIONS or SYSTEM_PROCESSES, 'hook.dll');
end;

Crie uma form com 3 botões e um edit e teste. Lembre-se de todas as medidas de segurança necessárias para se trabalhar com API hooking e lembre-se que toda a api do windows se invoca com stdcall.

Coloque a dll e o testador em um mesmo project group para facilitar.

É importante salientar que qualquer processo que use a GetUserNameEx para identificar o usuário não sofrerá nenhum efeito desse hooking. Além disso o windows tem outras formas, de baixo nível, para descobrir o usuário logado.

Have fun :)

sexta-feira, 1 de abril de 2011

Primeiro de Abril dos programadores

Quem é do ramo de TI sabe o que são as normas RFC. São conjuntos de convenções onde são estabelecidos padrões para que computadores possam se comunicar e trocar dados entre si, e para que esses dados sejam reconhecidos por todos. Se não fossem essas normas o mundo da TI seria um caos (e já não é).

É insteressante o fato de que a norma RFC 2550 foi criada em 1° de abril de 1999, e tratava do bug y2k, o bug do milênio. Desde que a convenção de dadas expressa em 2 dígitos para o ano foi criada sabia-se que em 2000 isso ia dar merda parar de funcionar, mas mesmo assim a solução foi deixada para 1999, a véspera.

Lendo a norma, é possível encontrar o seguinte texto, bem - humorado apesar da seriedade e sobriedade das normas RFC:


" Nearly everyone now regrets the
   short-sightedness of the programmers of yore who wrote programs
   designed to fail in the year 2000.  Unfortunately, the current fixes
   for Y2K lead inevitably to a crisis in the year 10,000 when the
   programs are again designed to fail."


Numa tradução livre:

"Quase todo mundo lamenta a falta de visão dos programadores de antigamente, que criaram os programas já designados para falhar em 2000. Infelizmente, as correções correntes para o Y2K conduzirão inevitavelmente a uma crise no ano 10.000, quando os programas falharão novamente"

Sei lá, eu nunca esperaria encontrar esse tipo de ironia sutil numa norma RFC mas é a mais pura realidade: prepare-se porque todos os programas falharão no ano 10.000, o que fizemos foi uma gambiarra que tem 8000 anos de duração.

Há também na norma um padrão de nomenclatura para o bug do ano 10.000, chamado de YXK, em algarismos romanos (X) ou YAK, em hexadecimal (A = 10).

Seja pró-ativo, não espere o pior acontecer, antecipe-se, corrija agora mesmo o bug do ano 10.000 no seu software :)

Isso poderá gerar royalties e patentes para os seus tatatatatatatatatatatatatatatata (são 14 ou mais tatas?) ranetos.

segunda-feira, 28 de março de 2011

O analista de sistemas

Um homem anda por uma estrada próxima a uma cidade, quando percebe, a pouca distância, um balão voando baixo. O balonista lhe acena desesperadamente, consegue fazer o balão baixar o máximo possível e lhe grita:

- Ei você, poderia ajudar-me? Prometi a um amigo que me encontraria com ele às duas da tarde, porém já são duas e meia e nem sei onde estou. Poderia me dizer onde me encontro?

O outro homem, com muita cortesia, respondeu:

- Mas claro que posso ajudá-lo! Você se encontra em um balão de ar quente, flutuando a uns vinte metros acima da estrada. Está a quarenta graus de latitude norte e a cinqüenta e oito graus de longitude oeste.

O balonista escuta com atenção e depois pergunta-lhe com um sorriso:

- Amigo, você trabalha como analista de sistemas?

- Sim, senhor, ao seu dispor! Como conseguiu adivinhar?

- Porque tudo o que você me disse está perfeito e tecnicamente correto, porém esta informação me é Totalmente inútil, pois continuo perdido.

Será que você não tem uma resposta mais satisfatória?

O analista fica calado por alguns segundos e finalmente pergunta ao balonista:

- E você, não seria por acaso um Gerente?

- Sim, por um acaso sou um gerente. Porque?

- Ah, foi muito fácil! Veja só: Você não sabe onde está e nem para onde vai. Fez uma promessa da qual não tem a mínima idéia de como irá cumprir e ainda por cima espera que outra pessoa resolva o seu problema. Continua exatamente tão perdido quanto antes de me perguntar. Porém, agora, por um estranho motivo, a culpa passou a ser minha...

sexta-feira, 25 de março de 2011

Laço for in no lazarus

Já faz um tempinho que saiu esse feature, mas eu nem fazia idéia. Talvez mais pessoas não saibam.

Agora já é possível usar o laço for... in no free pascal. Outras alterações previstas para a versão 2.5.x e muito bem vindas é a adição de generics e a nova sintaxe para classes, permitindo class vars e class properties.

Segue abaixo um exemplo do operador for...in usando TStringList e Arrays Dinâmicos.

procedure TForm1.Button1Click(Sender: TObject);
var
   lista: TStringList;
   vetor: array of string;
   s: string;
begin
     lista := TStringList.Create;
     lista.Add('Delphi');
     lista.Add('Lazarus');
     lista.Add('C#');
     lista.Add('Java');
     lista.Add('PHP');

     for s in lista do
         Memo1.Lines.Add(s); //ou showmessage(s)

     SetLength(vetor, 5);
     vetor[0] := 'Laranja';
     vetor[1] := 'Maçã';
     vetor[2] := 'Pera';
     vetor[3] := 'Uva';
     vetor[4] := 'Cajá';

     for s in vetor do
         Memo1.Lines.Add(s); //ou showmessage(s)


end;   

Have fun ;)

quarta-feira, 23 de março de 2011

Leitura obrigatória sobre strings

A maior facilidade das strings do Delphi em relação ao C e C++ é que elas não são baseadas em operações de "baixo nível" com ponteiros. Elas são facilmente quebradas, concatenadas ou copiadas. No caso das cópias, elas podem ser copiadas com performance pois mantém um contador de referências.

Em comparação com as linguagens interpretadas, gerenciadas e com "coletores de lixo" as strings nessas linguagens não são tão performáticas. Cópias de strings não são cópias de referências, mas da string completa mesmo, sem reference counting. Tratando - se de concatenação de strings então, o .Net Framework, até a versão 2.0, que eu saiba, encorajava o uso de StringBuilder em vez de strings dentro de um loop para montar um relatório ou tabela na web, por exemplo. Isso porque ao se concatenar duas strings o .Net Framework cria uma nova string com o conteúdo das duas, destruindo as outras duas, gerando um overhead.

Imagine quantas operações dentro de um loop não acontecem quando você faz um:

tabela += "<tr><td>" + col1 + "</td> <td>"+ col2+ "</td></tr>";

Só nesse trecho, bobinho e trivial, mas apenas um exemplo, foram concatenados 5 strings. Isso quer dizer que 5 "resultados" foram criados até chegar ao final, e que, duas a duas, de 5 a 10 strings foram marcadas para ser destruídas, pelo menos as constantes, excetuando-se as variáveis col1 e col2.

O simples fato de trocar o conteúdo de uma string gera a destruição da string atual e a criação de outra no .Net. O programador final não percebe isso porque a sintaxe é bastante "amigável" e para strings e loops pequenos realmente parece que o .Net é performático. Isso não acontece no Delphi.

Algumas leituras obrigatórias sobre strings:

Marco Cantu compara as strings do Delphi com outras linguagens, tanto no que tange à sintaxe como à performance. -->  http://blog.marcocantu.com/blog/delphi_super_duper_strings.html

Meu artigo sobre strings --> http://blog.vitorrubio.com.br/2010/08/strings-e-delphi-2010-na-clube-delphi.html

Paper na Embarcadero sobre Unicode --> http://www.embarcadero.com/images/dm/technical-papers/delphi-unicode-migration.pdf

Artigo DrBob sobre strings --> http://www.drbob42.com/examines/examinA7.htm

Artigo na Embarcadero --> http://edn.embarcadero.com/article/38437

O que eu mais gosto é este: breve história sobre as strings no Delphi --> http://www.codexterity.com/delphistrings.htm


Have Fun ;)

quinta-feira, 17 de março de 2011

A linguagem de programação do futuro

         O empenho em analisar a execução dos pontos do programa desafia a capacidade de equalização das condições inegavelmente apropriadas. Podemos já vislumbrar o modo pelo qual a constante divulgação das informações oferece uma interessante oportunidade para verificação das formas de ação. Assim mesmo, o acompanhamento das preferências de consumo cumpre um papel essencial na formulação do fluxo de informações. O que temos que ter sempre em mente é que o comprometimento entre as equipes promove a alavancagem das diversas correntes de pensamento. Pensando mais a longo prazo, a determinação clara de objetivos faz parte de um processo de gerenciamento das novas proposições. 

          Por conseguinte, a expansão dos mercados mundiais obstaculiza a apreciação da importância das condições financeiras e administrativas exigidas. Nunca é demais lembrar o peso e o significado destes problemas, uma vez que a crescente influência da mídia maximiza as possibilidades por conta dos conhecimentos estratégicos para atingir a excelência. Gostaria de enfatizar que a hegemonia do ambiente político representa uma abertura para a melhoria do investimento em reciclagem técnica. Não obstante, o consenso sobre a necessidade de qualificação afeta positivamente a correta previsão das direções preferenciais no sentido do progresso. 

          A prática cotidiana prova que a percepção das dificuldades aponta para a melhoria dos relacionamentos verticais entre as hierarquias.


Fonte: http://padrelevedo.hpg.ig.com.br/lerolero/lerolero.html


























sim, é um post troll ...  

Nunca confie no TIOBE

Em vários posts meus eu mencionei o índice TIOBE para relacionar a popularidade das linguagens. Mas eu não sabia como o índice TIOBE funcionava, achei que ele era sério, baseado em projetos, mas ele é mais furado que o IBOPE, muito mais.

O TIOBE classifica popularidade como número de resultados nos buscadores. Ele parte de vários pressupostos errados.

1) Assume que popularidade é o número de resultados de buscas de uma linguagem em um mecanismo de busca.
2) Assume que todos os buscadores tem o mesmo peso, embora os resultados sejam muito diferentes e o algoritmo também.
3) Não elimina ruidos. Se você pesquisar por java programming encontrará resultados relacionados com uma programação qualquer na ilha de Java, por exemplo.

Além do ruido ser problema, a pesquisa é sempre feita com os termos <linguagem> programming, mas termos diferentes relacionados a uma mesma linguagem podem trazer resultados várias ordens de grandeza maiores ou menores do que <linguagem> programming. Além disso certas linguagens como javascript ou perl as pessoas costumam definir seu trabalho como scripting em vez de programming.

Por favor leia esses artigos: (o derivado e a fonte) http://akitaonrails.com/2008/04/13/off-topic-nunca-confie-no-tiobe

Parei de acreditar que o Java está sempre no topo. Embora muito utilizado e muito bom acredito que tenha outras linguagens que quase empatam com ele, em uma ordem totalmente diferente da TIOBE.

Comecei a ver as estatísticas de linguagens dos projetos do GIT hub. Se o kernel do linux está lá e muitos projetos GPL estão lá também isso torna as medidas um tanto quanto confiáveis. Os resultados são bem diferentes do TIOBE. Mesmo assim ainda posso dizer que não são completamente confiaveis porque essa estatística é baseada em uma amostra viciada: a maioria dos amantes de Ruby também é fã de Git e os amantes do Git, em sua maioria, programam em Ruby, então existem muitos projetos em Ruby no Git Hub, mas existem muitos projetos em outras linguagens que não estão no Git Hub. Com o tempo e o crescimento da popularidade do Git Hub é possível que o índice fique mais apurado. Outro modo de se chegar a esse resultado seria considerar o número de projetos em cada linguagem do sourceforge e do google code também.

Mas como eu sempre digo, REPITO:
1 - a popularidade de uma linguagem nada tem a ver com sua utilidade
2 - a popularidade de uma linguagem não tem nada a ver com a empregabilidade de seu programador
3 - Mesmo Java, Ruby, Delphi ou C# sendo populares ou "modinhas" isso não vai te impedir de estudá-los ou estudar PROLOG caso a necessidade apareça

Uma coisa é certa, um amigo meu me indicou Ruby e eu estou bastante curioso para ver como ele funciona. Por outro lado a vontade de programar para Android está me guiando ao Java.  Conclusão: JRuby :)

Qualquer que seja a linguagem, não vou mais conficar no índice da TIOBE

terça-feira, 15 de março de 2011

GEBRASA nunca mais - sobre e-commerce

Trabalho com e-commerce, mas não farei aqui um post sobre desenvolvimento de e-commerce e sim sobre gerência de e-commerce.

Qual é a principal preocupação do cliente, e a principal dúvida ao comprar em uma loja "online"? A dúvida é sempre a mesma: "será que a empresa vai entregar?"

O pagamento se dá de maneira muito fácil, via cartão de crédito. Mas caso haja algum problema o cliente sabe que o estorno é um inferno. Se o pagamento é intermediado por uma dessas MOIP ou PagSeguro da vida é pior, pois existe mais uma camada intermediária para atravancar o estorno, que pode demorar até 45 dias e fazer com que a empresa simplesmente tome posse de dinheiro seu emprestado, sem juros.

Algumas empresas se confundem ou se enganam na hora de entregar um produto, o que é até aceitável, e entregam o produto errado. Depois demoram muito para devolver o dinheiro ou trocar o produto (Submarino, por exemplo). Mas talvez a demora seja causada pela massa: um volume muito grande de clientes, pedidos, produtos.

Outras empresas fazem a chamada venda de cauda longa: elas vendem um produto mesmo não tendo no estoque, mas É CERTEZA que o produto existe no estoque dos fornecedores, e não está esgotado. Com isso a  empresa pode solicitar o produto do fornecedor sob demanda e mandar despachar para o cliente. É como "just in time".

Um e-commerce nunca, NUNCA deveria fazer venda de cauda longa de algo que depende de fabricante e não de distribuidor, ou seja, de um produto que deva ser FABRICADO. Tampouco deveria fazer venda de cauda longa de um produto sazonal .

Bom, essa bronca é para a GEBRASA, empresa na qual eu NUNCA MAIS COMPRAREI e DESACONSELHO FORTEMENTE.

Comprei um simples hack, um quadrado de madeira (ou coisa que o valha) para colocar meu pc, monitor e impressora, paguei, e não vi a cor até hoje, dois meses depois. Coisa que se eu tivesse comprado numa loja qualquer estaria levando pra casa no mesmo dia.

Se a empresa me mandasse periodicamente um e-mail me posicionando sobre o status do meu pedido, ou ligasse ou mandasse um e-mail se desculpando e mandando um prazo ou oferecendo a devolução do meu dinheiro eu não ficaria nervoso, pois sei que essas coisas acontecem.  Mas a GEBRASA, além de não dar prazo e dizer que não tem previsão de entrega foi estupidamente mal educada no atendimento por e-mail, dizendo simplesmente: "você não leu no site? lá está escrito que há um prazo de 10 dias para verificar a disponibilidade do produto no estoque.". É verdade, mas não se passaram 10 dias, se passaram 58, para ser mais exato.

Como o pagamento foi feito via MOIP, teria que aguardar a MOIP entrar em "disputa" com eles. Não tenho paciência para isso, ficar ouvindo musiquinha em ura...

Perdoem-me meus leitores, eu nunca pronuncio palavras vulgares, de baixo calão e profanidades no meu blog técnico, mas .... pra puta que o pariu com essa merda.

Depois de 4 trocas de e-mails com muita desconsideração e descaso com o cliente entrei no reclame aqui, procon e entrei em contato com a VISA para estorno do meu pagamento, tudo de uma vez. Para a VISA ainda tive que mandar um FAX (o que é isso meu Deus? Falando a verdade, nunca tinha usado um desses antes....) enorme cheio de firulas e burocracias.

Espero sinceramente que a GEBRASA feche as portas da maneira mais humilhante possível. No mais, desculpem-me pelo desabafo, prometo que o próximo post será tech, com certeza.

segunda-feira, 14 de março de 2011

madShi collection


Saiu na revista Clube Delphi 127 meu artigo sobre a madShi Collection, uma coleção de bibliotecas muito úteis e interessante. Elas vão além do basicão fornecendo aos programadores funcionalidades bastante inusitadas, como api hooking, e funcionalidades que são uma mão na roda na hora de distribuir seu software ou na hora de encontrar bugs persistentes. O madExcept é um gerenciador de exceções que automaticamente gera um log com nome da unit e até a linha do código que disparou o erro. Seu usuário pode simplesmente clicar em um botão para te enviar o relatório de erros.

Espero que gostem do artigo. Boa leitura :)

quarta-feira, 9 de março de 2011

Dicas de Inglês

O inglês é essencial para programadores. Ponto. Não importa o pais em que você esteja, o inglês é o esperanto que deu certo, pelo menos nessa nossa era.

O site Tecla Sap tem muitas dicas interessantes para quem já cursa inglês mas quer sanar dúvidas, pegar dicas ou aprimorar seus conhecimentos.

Peguei essa dica hoje no site: Palavras com "L" mudo. Acontece também com outras letras, por isso muita atenção à pronúncia. Ensaie a pronúncia em diálogos reais.


  • ALMS /aams/
  • Esmola
  • BALM /baam/
  • Bálsamo
  • CALM /kaam/
  • Calmo
  • COULD /kud/
  • Passado do verbo auxiliar “CAN” (poder)
  • HALF /héf/
  • Metade
  • PALM /paam/
  • Palma; palmeira; palm
  • PSALM /saam/
  • Salmo
  • SALMON /SÉ m@n/
  • Salmão
  • SHOULD /shud/
  • Deveria (verbo auxiliar)
  • SOLDER /SÓ d@r/
  • Solda
  • TALK /tók/
  • Conversar
  • WALK /wók/
  • Andar
  • WOULD /wud/
  • Verbo auxiliar usado no condicional
  • I’ll have the salmon, please.
  • Vou querer o salmão, por favor.
  • Aluminum is also very difficult to solder. (Chicago Tribune)
  • É muito difícil soldar alumínio também.

Postagens populares

Marcadores

delphi (60) C# (31) poo (21) Lazarus (19) Site aos Pedaços (15) sql (13) Reflexões (10) .Net (9) Humor (9) javascript (9) ASp.Net (8) api (8) Básico (6) Programação (6) ms sql server (5) Web (4) banco de dados (4) HTML (3) PHP (3) Python (3) design patterns (3) jQuery (3) livros (3) metaprogramação (3) Ajax (2) Debug (2) Dicas Básicas Windows (2) Pascal (2) games (2) linguagem (2) música (2) singleton (2) tecnologia (2) Anime (1) Api do Windows (1) Assembly (1) Eventos (1) Experts (1) GNU (1) Inglês (1) JSON (1) SO (1) datas (1) developers (1) dicas (1) easter egg (1) firebird (1) interfaces (1) introspecção (1) memo (1) oracle (1) reflexão (1)