30 de junho de 2010

Automatizando tarefas que envolvem arquivos através de scripts

O tempo passa, as tecnologias evoluem, novos paradigmas são introduzidos e passam a ser dominantes. Mas ainda não inventaram nada que seja tão efetivo e rápido para integrar sistemas do que a boa e velha troca de arquivos. Mesmo com a popularização dos Web Services e outros mecanismos, a troca de informações entre sistemas de fabricantes diferentes ou que exijam acesso a um sistema legado ainda têm no uso de arquivos texto uma solução prática.

Embora obviamente não se restrinjam ao cenário descrito acima, a Microsoft disponibiliza em seus sistemas operacionais ferramentas que permitem aos desenvolvedores ter acesso a toda a estrutura de pastas e arquivos e realizar operações básicas nessa estrutura.

O ponto de entrada para ter acesso a esta estrutura é o objeto FileSystemObject, disponível como uma interface COM. Com uma instância desse objeto você pode listar as subpastas e arquivos existentes numa pasta específica. Pode também copiar, mover e criar tanto pastas quanto arquivos, além de listar os drives conectados no computador e obter informações a respeito deles - como o espaço livre remanescente.

O código VBScript abaixo pesquisa os arquivos e subpastas contidos na pasta Processo, detecta os que são arquivos compactados (ZIP) e os move para a pasta Historico. Usei o VBScript porque ele pode ser agendado como se fosse um executável, completando a automatização das tarefas.
Dim fso
Dim gArqLog, caminho
Dim gPasta, gArqs, arquivo

Set fso = CreateObject("Scripting.FileSystemObject")
Set gArqLog = fso.CreateTextFile ("carga.log")

' Lê o conteúdo da pasta Processo
caminho = "c:\Processo\"
Set gPasta = fso.GetFolder (caminho)
Set gArqs = gPasta.Files

' Processa os arquivos que são do tipo ZIP
for each arquivo in gArqs
if fso.GetExtensionName (arquivo) = "zip" then
' Armazena no log o nome do arquivo processado
gArqLog.WriteLine (arquivo.Name)

' incluir aqui algum processamento com o arquivo
fso.MoveFile caminho + arquivo.Name, "c:\Historico\" + arquivo.Name
end if
Next

gArqLog.Close ()
Set fso = Nothing
O exemplo apenas ilustra como funciona uma pesquisa básica numa pasta - para a tarefa proposta, poderíamos simplesmente usar o MoveFile com uma máscara *.zip de uma pasta para a outra.

Algumas observações sobre o que acontece no código acima. Para começar, a função CreateObject cria o objeto principal - uma instância do Scripting.FileSystemObject. A princípio, uso esse objeto para criar um arquivo texto onde são gravados os nomes dos arquivos que forem processados - uma espécie de log.

Em seguida, a função GetFolder recupera um objeto que representa a pasta com a qual queremos trabalhar; dessa pasta, obtemos uma "coleção" com os arquivos contidos nela, coleção esta representada pela proprieda Files. Tal coleção implementa a interface IEnumerator, o que nos permite navegar pela lista usando o laço For Each, mais direto que o For convencional nesses casos.

Para terminar, o comando MoveFile move o arquivo processado da pasta original para outro local, de modo que se, o script for executado de novo, serão processados somente arquivos novos colocados na pasta de origem.

Note que eu a função GetExtensionName para determinar se o arquivo deve ou não ser considerado. Poderia ter usado a propriedade Type do arquivo. No entanto, o valor retornado por Type é afetado pela língua do sistema operacional (português, inglês, etc.), sendo um problema quando se precisa ter tal script em outras máquinas.

O script poderia ainda incluir outras tarefas com o ZIP, incluindo a chamada de rotinas para descompactá-lo e processar o conteúdo. Neste caso, um outro objeto seria necessário para executar um programa externo (como o unzip): o WshShellObject.

25 de junho de 2010

Certificados de Qualidade em TI

por Bianca Machado Branco*

O mercado consumidor está começando a exigir dos fornecedores de software e de serviços garantias de desempenho e do nível de serviço na forma de certificações de qualidade como CMMI (Capability Maturity Model Integration), MPS-BR (Melhoria de Processos do Software Brasileiro) e ISO 20000. Essas certificações atestam que o fornecedor utiliza as melhores práticas do mercado.

Segundo o Standish Group, empresa que realiza desde 1994 um levantamento sobre projetos de software, há uma taxa de 77% de fracasso em projetos de desenvolvimento de software. De acordo com a pesquisa, um projeto de software custará em média 45% mais caro do que o contratado, terá um atraso de 63% sobre o prazo previsto para entrega e não terá 33% das funcionalidades encomendadas.

Nesse contexto, surgiram as certificações, uma espécie de selo de qualidade, com o objetivo de descrever as melhores práticas no desenvolvimento de software e também em serviços. Porém, de acordo com o Standish Group, cerca de 2/3 das implementações de certificações não atingem os objetivos, o que explica o ceticismo de muitos diretores de TI, que não acreditam na certificação como modalidade que agrega valor ao produto.

As empresas com CMMI, uma das principais certificações para desenvolvimento de software, são de 30% a 70% mais caras, dependendo do nível da certificação. Porém, muitos clientes não enxergam os benefícios que a certificação traz para suas respectivas instituições, acreditando tratar-se de um modismo de mercado ou um argumento para criar demanda.

Entretanto, já existe um movimento no sentido de exigir que os fornecedores de TI atestem sua competência através dos certificados. Empresas como Coca-Cola, Tetra Pack e Volkswagen já estão exigindo pelo menos o nível 3 do CMMI, que pode chegar até o patamar 5.

O selo CMMI parece estar se consolidando como a principal certificação para as empresas de TI, tendo ganhado popularidade entre os gerentes e diretores de TI das empresas clientes, os principais influenciadores na compra de software.

Outra tendência recente é a ISO 20000, primeiro padrão reconhecido internacionalmente para gerenciamento de serviços de TI. Até o momento, cerca de 100 companhias ao redor do mundo já têm essa certificação, que agora começa a surgir no Brasil. Acredita-se que o conceito vá se popularizar em médio prazo e será considerado um diferencial. Futuramente, acredita-se que a ISO 20000 poderá se tornar um pré-requisito para as empresas de tecnologia.

Além dessas, a MPS-BR, a versão brasileira da CMMI, vem crescendo cada vez mais no mercado e já tem sido exigida pelo governo federal em licitações públicas. O ponto positivo dessa certificação é que ela é mais fácil de ser obtida em virtude do custo ser bem menor que o da CMMI, além de ser menos complexa que esta última. Trata-se de uma boa alternativa para empresas de pequeno e médio porte.

Por fim, as empresas devem pesquisar constantemente quais certificações são mais reconhecidas no mundo corporativo e optar por aquela que seja mais aderente aos processos da empresa e que traga visibilidade junto aos clientes atuais e potenciais. Opções não faltam.

*Bianca Machado Branco possui MBA em Gestão Empresarial e formação em Análise de Sistemas. Trabalha com tecnologia da informação desde 1998. Atualmente é coordenadora de projetos na ABC71.

Mais Informações
CMMI, MPS-BR, ISO 20000

24 de junho de 2010

Trabalhando com as funções de agregação do SQL

O SQL - Structured Query Language (Linguagem de Consulta Estruturada) é uma linguagem usada para dar manutenção nos dados em um bancos de dados. Oracle, Sybase e MS SQL Server são alguns exemplos de servidores de bancos de dados que se valem dessa linguagem tanto para permitir a extração dos dados armazenados como para inserir novos dados ou atualizar aqueles já existentes. A primeira versão da sintaxe foi padronizada em 1986 e a última revisão foi aprovada pelo ISO em 2008.

Desde a primeira versão, o padrão incorpora funções classificadas como "agregação". São funções nativas de consulta que servem para agrupar informações, agregando numa única linha o conteúdo de vários registros. Dessa forma, os detalhes da informação original são postos de lado e as informações são tratadas em conjunto.

Atualmente, as funções de agregação disponíveis no SQL são as seguintes: AVG (calcula a média dos valores de um campo determinado), COUNT (retorna a quantidade de registros existentes), SUM (calcula a soma dos valores de um determinado campo), MAX (retorna o maior valor existente para um campo especificado) e MIN (retorna o menor valor existente para um campo especificado). Todas essas funções são aplicadas apenas aos registros que atenderem os critérios estabelecidos na cláusula WHERE da query onde estiverem sendo usadas.

Pode parecer confuso a princípio mas o conceito de agregação é, na verdade, bastante simples. Considere o seguinte conjunto de registros existente numa tabela no banco de dados:
NF Produto Cliente Qtde Valor Dia
1 P001 C1 8 R$ 160,00 5
1 P002 C1 2 R$ 34,00 5
1 P003 C1 1 R$ 58,00 5
2 P002 C3 20 R$ 340,00 7
3 P001 C2 12 R$ 240,00 8
3 P002 C2 5 R$ 85,00 8
4 P001 C1 2 R$ 40,00 10
5 P003 C3 4 R$ 232,00 15

Um exemplo simples de agregação com esses registros seria somar a coluna Valor deles todos. Supondo que a tabela se chame TABELA, a query e seu retorno seriam:
SELECT SUM (Valor) FROM TABELA

------------------
1189,00
Repare que apenas um registro é retornado. É por isso que eu disse que as agregações escondem os detalhes dos registros envolvidos. O uso de agregações não impede que se aplique a cláusula WHERE na query, isto é, ainda posso restringir quais registros eu quero incluir na agregação. O exemplo da soma considerando apenas as notas do cliente C1 ficaria:
SELECT SUM (Valor) FROM TABELA
WHERE Cliente = 'C1'

------------------
292,00
Na maioria dos casos, restringir tanto os registros afetados e o retorno não é desejável. Numa aplicação real, quase sempre as informações terão que vir um pouco mais detalhadas. Pode ser necessário, por exemplo, trazer as somas de cada cliente separadamente, sem que se tenha que especificar um cliente em particular. Esse efeito é obtido agrupando-se os registros através da cláusula GROUP BY.
SELECT Cliente, SUM (Valor), COUNT(*) AS QtdeReg
FROM TABELA
GROUP BY Cliente

Cliente QtdeReg
------------------ ------------------ ------------------
C1 292,00 4
C2 325,00 2
C3 572,00 2
Acrescentei no quadro anterior também uma coluna que mostra quantos registros da tabela foram considerados em cada linha trazida, isto é, quantos registros estão agregados em cada linha. Isso exemplifica o uso da função COUNT.

Se for preciso, é permitido detalhar ainda mais as informações adicionando novos agrupamentos - o produto ou o dia da movimentação, por exemplo. Além disso, todos os elementos de uma query comum podem ser usados, tais como o WHERE (já mostrado) e o ORDER BY (para que as linhas retornadas estejam classificadas numa determinada ordem).

A cláusula WHERE determina quais registros da tabela devem ser incluídos na agregação. E se você quiser restringir as linhas retornadas, trazendo apenas aquelas que atingirem determinado valor agregado ? Suponha, por exemplo, que na query do quadro anterior você queria exibir apenas os clientes cuja soma de valor seja superior a 300. Para esta situação, o padrão SQL define a cláusula HAVING que nada mais é que um WHERE aplicado ao resultado da agregação. Veja a implementação do exemplo:
SELECT Cliente, SUM (Valor), COUNT(*) AS QtdeReg
FROM TABELA
GROUP BY Cliente
HAVING (SUM (Valor) > 300) AND (COUNT(*) >= 1)

Cliente QtdeReg
------------------ ------------------ ------------------
C2 325,00 2
C3 572,00 2
Repare que o HAVING é aplicado após o agrupamento (GROUP BY) enquanto o WHERE é aplicado ao SELECT. O exemplo também mostra que é possível combinar mais de um valor de agregação no HAVING para obter filtros mais complexos.

18 de junho de 2010

Registrando automaticamente uma fonte de dados para acesso ODBC

Muitas aplicações que trabalham com banco de dados ainda fazem o acesso através de uma fonte de dados ODBC. Isso normalmente exige que se faça uma configuração através das Ferramentas Administrativas do Painel de Controle do Windows em cada estação que fará uso da aplicação em questão.

A ABC71 usa o ADO com OleDB na maioria de suas aplicações para acessar banco de dados. Os poucos módulos que necessitam ter uma configuração ODBC externa são os relacionados à Qualidade (Metrologia e Inspeção da Qualidade), que já estão sendo revistos e também deverão adotar o ADO em breve.

Enquanto isso não acontece, incluimos no projeto desses módulos código para criar automaticamente as configurações, de modo que o usuário não precisa se preocupar com essa criação. Basicamente, configurar uma fonte de dados ODBC é criar algumas entradas no registry do Windows - a localização das chaves variará, dependendo se você quer disponibilizar a fonte só para o usuário atual do Windows ou para todos. Qualquer que seja o caso, a hierarquia de chaves é \\SOFTWARE\\ODBC\\ODBC.INI. Esta chave é onde são armazenados os drivers ODBC instalados no computador. Ai também fica a chave "ODBC Data Sources", que, como diz o nome, é onde o Windows armazena as fontes de dados para conexões ODBC. Veja abaixo um exemplo em C++ Builder para acessar essa chave. Para usar em Delphi, basta adaptar a sintaxe para Pascal.
void TWRegConfig::ConfigODBC (AnsiString ServerName)
{
AnsiString metrologia ("mt305w");
AnsiString sqlServer ("SQL Server");
AnsiString _OdbcIni = "\\SOFTWARE\\ODBC\\ODBC.INI\\";

TRegistry *_Reg = new TRegistry ();
_Reg->RootKey = HKEY_LOCAL_MACHINE;

_Reg->OpenKey (_OdbcIni + "ODBC Data Sources", true);
/* ... */
No código acima, é criada uma instância da classe TRegistry que encapsula o acesso ao registry do Windows. A raiz para o acesso (RootKey) no exemplo é o HKEY_LOCAL_MACHINE, indicando que acessaremos o local de armazenamento das fonte de dados disponíveis para todos os usuários do computador. Use HKEY_CURRENT_USER como RootKey para acessar apenas as fontes do usuário atual do Windows.

O comando OpenKey abre a chave especificada, preparando-a para manutenções (leitura e gravação). O segundo parâmetro da função OpenKey indica se a chave deve ser criada caso ainda não exista. Agora, podemos criar as entradas que configuram a fonte de dados ODBC:
/* ... */
if ( _Reg->KeyExists(_OdbcIni + metrologia) == false)
{
/* cria o nome da fonte de dados, indicando o tipo de banco de dados que será acessado */
_Reg->WriteString (metrologia, sqlServer);

/* efetivamente faz a configuração da fonte de dados */
_Reg->OpenKey (_OdbcIni + metrologia, true);
_Reg->WriteString ("driver", "C:\\WINDOWS\\System32\\SQLSRV32.dll");
_Reg->WriteString ("Description", metrologia);
_Reg->WriteString ("Server", ServerName);
_Reg->WriteString ("LastUser", metrologia);
}
delete _Reg;
Pelo exemplo acima, nota-se que há duas informações distintas a serem gravadas. A primeira é o nome da fonte de dados, isto é, o nome pelo qual referenciaremos a fonte de dados quando formos conectar via ODBC. Veja que é gravado o nome da fonte (Metrologia) e o tipo de banco de dados que desejamos (Sql Server). Os valores válidos para tipo de banco depende do que você tem instalado no computador. Este valor tem que corresponder a uma das entradas existentes na chave ODBCINST.INI.

A segunda informação é uma chave do Registry que deve ser criada como sub-chave do ODBC.INI com o mesmo nome da fonte de dados - no exemplo, este nome é Metrologia. A configuração propriamente dita é feita criando-se entradas dentro dessa nova sub-chave. Algumas informações são comuns a todos os tipos de banco de dados, como é o caso de driver e Description; outras, são específicas de cada tipo de banco. No exemplo aparecem as entradas necessárias para configurar um banco MS SQL Server.

A informação menos óbvia do exemplo é o driver. Essa entrada deve indicar o caminho da biblioteca do próprio fabricante; biblioteca esta que fará, em última análise, todo o acesso ao banco de dados. O valor correto pode ser facilmente encontrado dentro da chave ODBCINST.INI. Como dentro dela há uma chave para cada driver instalado, basta procurar o nome do driver desejado (SQL Server, por exemplo) e copiar o valor da entrada cujo nome é "Driver".

Uma forma de descobrir quais entradas devem ser criadas é criando uma fonte de dados manualmente através do painel de controle do Windows e depois analisar o resultado na hierarquia do ODBC.INI dentro do registry.