Utilizando a linha de comandos numa aplicação Windows

Depois de ver o Ubiquity, creio que se torna claro o poder de uma linha de comandos numa interface aplicacional, especialmente quando os comandos estão bem construídos. Se bem que muitos há muito terão anunciado a morte da linha de comandos em detrimento de interfaces gráficas, a verdade é que ainda não morreu e encontra-se frequentemente novas aplicações para ela. Repare que o Linux continua a ser fortemente dependente da linha de comandos, existe uma versão do Windows – Windows Server Core – que é completamente dependente da linha de comandos, o motores de busca geralmente aceitam parametros de uma forma similar a uma linha de comandos e agora temos o Ubiquity que facilita tarefas através de uma linha de comandos com uma linguagem natural e facilmente adaptável.

Associamos a linha de comandos a tarefas de sistema operativo, normalmente, mas é possível associá-lo a uma aplicação concreta. E não refiro os comandos de inicialização da aplicação; estou a falar de inserir uma linha de comandos dentro de uma aplicação, de modo a desenvolver tarefas aplicacionais e que tipicamente exigiria meia dúzia de cliques. Porque há tarefas que se tornam fatídicas com uma interface gráfica – para uma tarefa por vezes é necessário deslocar o rato constantemente de um ponto para outro, aceder a um menu, seleccionar um elemento, preencher uma caixa e clicar. E se poder simplesmente escrever uma linha de texto que descreve completamente a tarefa?

Imaginei que para o gerador de código, esse elemento poderia ser uma mais valia. Há tarefas que acredito que poderão ficar simplificadas através de uma comandos texto. Por exemplo, para criar um objecto, poder escrever algo do género:

add bo NomeDoObjecto

em vez de ter que seleccionar um módulo, clicar com o botão direito, clicar na opção do menu de contexto, preencher o campo do formulário e clicar em OK. É possível, e creio que será mais rápido – menos movimento de rato, menso cliques, menos transição entre teclado e rato.

Algo que reparei é que informação sobre estratégias de implementação de linhas de comandos são relativamente escaças na web (ou então segui o caminho errado em termos de palavras de pesquisa), em especial a inclusão de uma consola de comandos num formulário windows. Encontrei depois de algum tempo um componente muito interessante no Code Project desenvolvido por um indiano – o Command Prompt Control do vikashparida.

O control é algo simples e tem bastante funcionalidade. Apresenta a listagem de comandos inseridos (e resultados) como na consola tradicional, permite modificar o texto do prompt, e automáticamente divide o texto do comando pelos delimitadores que ele define (e que podem ser alterados). Tem três eventos associados, sendo o principal a manipular é o Command que representa a inserção de um comando completo, mas tem outros que permitem controlar a aparição de tooltips e afins. A implemantação do handler acaba por ser algo do género (por exemplo para um comando “date” que apresenta a data actual:

private void prompt1_Command(object sender, CommandEventArgs e)
{    
   if (e.Command == "date")    
   {         
	e.Message = "  The current date is : " + DateTime.Now.ToLongDateString();
	return;    
   }    

   // Show error message    
   e.Message = "'" + e.Command + "' is an unrecognized command";    
   // Don't store the command    
   e.Record = false;
}

como demonstra o autor. A assemblagem está completa, e pode ser incorporado na toolbox do Visual Studio para inclusão em projectos.

A morte do UML…?

O título pode ser, vá, “controverso”, mas vêm no seguimento da leitura de dois artigos que encontrei hoje, e por acaso sobre uma matéria sobre a qual ponderei hoje. O primeiro é o “13 reasons for UML’s descent into darkness” e o “Uh-Éme-Éle” do blog Fragmental, que descobri hoje e considero muito bem escrito e interessante. Ambos apresentam argumentos muito válidos. E eu nunca imaginei que tanto pessoal (basta ler os comentários) sentisse a inutilizade do UML.

A ideia de criar o gerador de código tem levado a pensar um pouco sobre as ferramentas em uso. Eu uso o Visual Studio Express Editions, para programar, mas tenho muita vontade de passar para a versão profissional. Vejo nas opções extras oferecidas pelo IDE vantagens e validade para efectuar o investimento, em especial a integração de ferramentas externas, o gerador de classes, e a integração de tipos de projectos diferentes na mesma solução, que o Express não permite. Outra ferramenta que pondero é o Sparx EA, uma ferramenta de analise e modelação. Este, em particular, é uma ferramenta que utilizei num projecto e serviu para modelar um sistema bastante complexo. Gostei muito da aplicação e facilidades de documentação e geração de código oferecidos. A aplicação até nem é muito cara e com uma componente extra (que custa tanto como a aplicação) a integração no Visual Studio é completo. A pergunta principal é.. justifica-se?

Continue reading

Interfaces e Generics numa generalização de uma DAL

Nas ultimas semanas tenho ponderado e escrito algum código relativo ao gerador de código. Até agora consegui uma interface básica com uma treeview para navegar pelos objectos e um painel de propriedades para editar as propriedades dos objectos que defini. Muito arcaico mas ainda é só uma base. Pelo menos já gera o código dos business objects como utilizo, e escreve a configuração para um ficheiro XML, usando uma classe de serialização que eu já tinha.

Agora ando a pensar e preparar a DAL, que é talvez a parte mais complexa em termos de estrutura. É mais complexo, em especial, devido à modulariedade que desejo que tenha. Em especial, o conjunto de requisitos que desejo para a DAL são:

  • possibilitar trabalhar com um conjunto de sistemas de bases de dados (SQLite, SQLServer, MySQL, Access, …) para poder facilmente gerar o código necessário para qualquer um destes sistemas.
  • permitir loggar as operações efectuadas, também para um conjunto de repositórios diferentes (bases de dados, ficheiros texto, ficheiros XML, etc..)
  • permitir gerar o código base para manipular os dados (GetItem, GetList, Save, Delete…) para os diversos sistemas de armazenamento.
  • permitir extender as classes, adicionando-lhes funcionalidade ou sobrepondo a existente na base sem afectar a geração de novo código.
  • aproveitar código já criado e as opções que o .NET oferece.

Basicamente, necessito de um género de framework para a DAL. Modelei o conceito no papel e verifiquei que iria ter que prototipar alguns conceitos para garantir o funcionamento e aperfeiçoar o método. Em especial, necessitei de testar e verificar as limitações dos generics e interfaces no C#.

Continue reading

Snippet Compiler

O Snippet Compiler é uma pequena aplicação Windows gratuita que permite escrever pequenos conjuntos de código de C# (ou VB.Net) e compilar e correr, sem ter de criar um projecto ou solução completa, que é sempre um pouco chato quando é necessário fazer. Já me aconteceu inúmeras vezes ter que criar um projecto no Visual Studio só para poder executar meia dúzia de linhas de código de teste.

Pensando bem, esta ferramenta, além de servir pode ser uma óptima ferramenta para ensinar o C# (ou VB) ou uma optima ferramneta de prototipagem de conceitos um pouco ao estilo do IDE do Processing. Quem trabalha com estas linguagens certamente irá agradecer. Actualmente suporta .NET 2.0 e anteriores com versões próprias, ou o 3.5 numa versão ainda alpha.

http://www.sliver.com/dotnet/SnippetCompiler/

Caching em WebMethods

O objecto Cache do System.Web.Caching é muito funcional e poderoso na gestão de dados aplicacionais no ASP.Net. Uso-o frequentemente em aplicações, como modo de persistir dados nas camadas superiores permitindo acelerar alguns processos, especialmente quando os dados vão ser usados continuamente durante um curto período de tempo e em diversas páginas ou com operações de paginação e exportação de dados de uma GridView.

Há naturalmente vantagens e desvantagens em usar a Cache do .Net para armazenar dados. A Cache é efectivamente rápida. Muito mais rápida que o ViewState, por exemplo, e faz uma melhor gestão de grandes quantidades de dados que a objecto de Session. Permite também gerir o tempo de vida e modo de remoção dos dados. No entanto, a cache está disponível a todos os utilizadores, pelo que é necessário ter algum cuidado a gerir as chaves usada para armazenar os valores, se bem que esta característica até é vantajosa em muitas situações.

Enquanto que em páginas (ou melhor, classes herdadas da classe Page) o objecto Cache está imediatamente disponível, o mesmo não é tão verdade para WebServices. WebServices permite algumas estratégias de Caching, sendo a principal a cache de saída (output caching), em que a resposta do WebMethod é armazenado em cache durante um determinado período. Por exemplo:

[WebMethod(CacheDuration=60)]
public string DevolveString()
{
   string palavra
   //processamento (...)
   return palavra;
}

Irá devolver a mesma string durante os 60 segundos posterior à chamada, e determinado pelo uso de “CacheDuration=60” no atributo do WebMethod.

Mas e se quisermos utilizar a cache da mesma forma que é usada nas páginas, com recurso a métodos (estáticos?) para inserir e obter valores? Enquanto que escrever:

Cache.Insert("objectoAinserir", obj); //insere a instância obj na cache 

é válida nas classes das páginas, o mesmo não é verdade num WebMethod. Aliás, no VS, para que o IDE reconheça o objecto Cache, é necessário inserir a referencia ao System.Web.Caching, e mesmo assim os métodos não são disponibilizados pelo IDE. Instanciar a cache com algo do género

System.Web.Caching.Cache cache = new System.Web.Caching.Cache();

é válido quer no IDE, quer em runtime, qualquer tentativa de atribuir ou obter um valor usando cache.Get(…) ou cache.Insert(…) levantam excepções.

A solução passa emtão por ir buscar o objecto de Cache a outro local, nomeadamente ao HttpRuntime. Deste modo, no WebMethod, já é possivel inserir e obter valores dentro de um método (que não é necessáriamente a resposta do método) e persisti-lo para utilizar com outros métodos ou até outros utilizadores.

[WebMethod]
public void TestMethod()
{
   int a = 1;
   HttpRuntime.Cache.Insert("A", a);
}

[WebMethod]
public int TestMethod2()
{
   return (int)HttpRuntime.Cache.Get("A");
}

O código anterior é exemplo de como utilizar a Cache do HttpRuntime. No TestMethod() é armazenado um valor na cache, e considerando que este é executado antes do TestMethod2(), ao chamar o TestMethod2() o valor presente na cache será recuperada e retornada, permitindo persistir dados entre métodos, especialmente quando volumosos, e que pode evitar trocas de dados lentos entre camadas aplicacionais ou serviços.

O Cais do Bico em PhotoSynth

Ok, tive que o experimentar naturalmente. Depois de ver o que era possível e de ter lido o guia para melhor resultados e o vídeo, saí após o almoço para disparar algumas imagens.

A máquina compacta é a melhor opção para esta tarefa, na minha opinião, dada a quantidade de imagens que devem ser produzidas (menos desgaste). Infelizmente, nesta primeira tentativa, estive limitado a um cartão de 128MB e uma Canon G5, o que me permitiu produzir 92 fotografias de 5 MP.

Iniciei com uma panorâmica de 360º a partir da ponta do paredão sul, captei alguns planos mais apertados sobre os barcos pelo paredão, e segui até ao primeiro dos pontos de atracagem.

A capacidade de processamento do PhotoSynth é fabuloso. Apesar da reduzida percentagem de sintetização considerada (a cena é bastante complexa, em especial devido a ondulação/agua, diria), o PhotoSynth construiu correctamente a cena. no entanto não a deixou completa num só bloco 3D – acabou por dividir o espaço em alguns blocos 3D (é possível saltar entre os blocos a partir dos controlos na tela do visualizador). Além do mais, não tive o cuidado de gerar as imagens com os horizontes correctos nem controlo de exposição. Mesmo assim a combinação de imagens está muito bem conseguido.

É sem duvidas uma alternativa interessante à clássica panorâmica ou panorâmica esférica, mas sem as substituir. A experimentar!

PhotoSynth do Cais do Bico:
http://photosynth.net/view.aspx?cid=7AD3B30B-D989-4709-A3D3-2EFF901B196F

Conservação de baterias de portáteis

O Pplware tem um artigo interessante sobre a conservação de baterias de portáteis. Há um erro típico do pessoal que é pensar que a bateria de um portátil funciona da mesma forma que os dos telemóveis, e portanto que tenham o mesmo problema de “memória” ou viciação. A bateria do portátil é de iões de Lítio (Li.Ion) e não de Níquel-Cádmio (Ni-Cad) ou Níquel e Hidrato Metálico (Ni-MH). O problema deles é principalmente o do calor.

Importante, por vezes julgamos que quando está ligado à corrente, devemos retirar a bateria. De facto, a bateria fora do portátil fica menos exposta a calor. Mas na verdade, todo o portátil fica sujeito a picos de corrente que podem afectar os circuitos internos, ou mesmo falhas de corrente que desliga o portátil por completo. Com a bateria no lugar, este acaba por funcionar quase como um filtro e/ou UPS (e sabemos que a EDP não é lá muito fiável, infelizmente…). Considerando a diferença de custo entre uma bateria de portátil e uma motherboard ou o tempo perdido a desenvolver qualquer trabalho, prefiro “desgraçar” a bateria…

http://www.pplware.com/2008/08/20/conserve-a-bateria-do-seu-computador-portatil/

O snippet “prop” no Visual Studio 2008

Um dos snippets mais usados em C# é o “prop”, que escreve o código base de uma propriedade de uma classe, com a declaração do campo privado, a propriedade publica e a definição dos métodos de get e set. No Visual Studio 2005  e para o C#2.0, o snippet tinha a aparência do tipo:

private $type$ $field$;

public $type$ $property$
{
   get { return $field$;}
   set { $field$ = value;}
}

Este até é o do snippet usado pelo Visual Studio 2005. escrevendo “prop” e carregando em Tab duas vezes, o IDE automaticamente geava este código, onde era necessário mudar apenas o tipo, o nome do atributo e o da propriedade.

No Visual Studio 2008, este código mudou. O 2008 aproveita a auto-implementação das propriedades, definida no C# 3.0, em que o a definição necessita de ser:

public $type$ $property$ { get; set; }

Muito mais reduzido e muito mais simplificado – basta definir o tipo e o nome da propriedade; a parte privada e a lógica de atribuição é criada pelo compilador. Este código é agradável, quando a implementação pretendida é simples. O código tb ocupa muito menos espaço, o que pode ajudar à leitura da estrutura da classe. Infelizmente, não é perfeito, visto que é por vezes útil trabalhar a lógica de atribuição, ou se o tipo é nullável, a lógica de atribuição tem de ser obrigatoriamente trabalhada.

A solução? Definir novos snippets :D. Essencialmente basta definir um (ou vários novos snippets) para suportar as variantes, e o assunto fica resolvido. Eu aproveitei a oportunidade para implementar o do 2.0 em duas formas. A primeira é a clássica, com a definição do atributo e dos métodos de get e set. Também, habitualmente defino o elemento privado com o prefixo “_” e o mesmo nome da propriedade; Também costumo incluir um valor predefinido, o que era chato de inserir com o snippet original (obrigava a sair do bloco para poder retornar, senão incluía o valor no nome do atributo…); Também tenho interesse em inserir a informação de serialização. Por fim, fiz igual, mas considerando o tipo nullável.

O resultado:



  
    
prop 2.0 propc Code snippet for property and backing field Miguel Alho Expansion
type Property type int field The variable backing this property myVar defVal The default value -1 xmlType The XML serialization attribute XmlAttribute
prop null propn Code snippet for property and backing field of nullable types Miguel Alho Expansion
type Property type int field The variable backing this property myVar defVal The default value null xmlType The XML serialization attribute XmlAttribute

Basta criar um ficheiro, tipo props.snippet, e no Visual Studio importar o ficheiro para os snippets de C#. A partir daí, as declarações “propc” e “propn” ficam disponíveis, sendo o primeiro para o tipos “normais” e o “propn” para propriedades baseados em tipos anulláveis. Também podem descarregar o ficheiro daqui. Customize at will!

Também podem ver mais algumas notas em http://blogs.msdn.com/wriju/archive/2007/10/04/visual-studio-2008-automatic-property-is-the-default-snippet.aspx

Gerador de Classes em C#

Das funcionalidade mais eficientes que pode haver é a possibilidade de autogerar código. Especialmente durante a fase inicial do coding da aplicação, gerar código das classes é uma seca. Mais se for multi-camada. Interfaces constantemente criadas, nomes repetidos constantemente e código que, de aplicação em aplicação, mantém-se sempre igual…

Os últimos projectos que desenvolvi permitiu observar muitos padrões em uso – o uso de objectos anuláveis frequentemente, o tipo de código de acesso aos dados constante, os métodos base existentes nas classes, etc. Algumas classes que desenvolvi já permitem a reutilização projecto a projecto, o que é óptimo. Por exemplo o de acesso a dados da BD SQLServer e SQLite (que ainda têm margem para melhorias), ou de escrita de dados em Excel, ou o de serialização para XML.

Mas para geração do código base é que ainda não tenho nada, e até agora tenho estado dependente do Visual Studio e algumas funcionalidades existentes. As versões Express ainda não tem esse tipo de funcionalidade implementada, mas tem pequenos truques que ajudam. O Sparx, que utilizei num projecto, é completo e resulta bem, mas pelo menos a versão que utilizei não resolveu todos os problemas.

O que preciso é de uma aplicação que gere os meus BO (business objects), a DAL (Data Acces Layer) e que aproveite correctamente os métodos de acesso que já gerei, o BLL (Business Logic Layer) caso o projecto necessite, e que me gere o SQL também, já agora. Preferencialmente, tudo adaptado ao meu workflow e padrão de código, similar e adaptado do esquema que o Imar Spaanjaars apresenta no site dele.

Há um tempo que imaginava tentar construir algo, que aproveitasse bem o que já desenvolvi até agora, para gerar código base para qualquer aplicação que eu venha a desnvolver. Algo do género do C# Classe Generator apresentados no CSharpFriends.com, que permite a inserção do Namespace, do classe, das propriedades, e que gere o código dos objectos e da DAL. Mas ao pesquisar para este post, encontrei algo interessante no site do Spaanjaars – um link para o MyGeneration. O MyGeneration é um gerador de código muito completo, e que permite introduzir templates; Suporta várias linguagens de programação (C#, VB.NET, JScript…), vários sistemas de BD (SQL Server, Oracle, Acces, SQLite, Firebird,..), conceito de projecto, e suporte a diversas arquitecturas ORM. O IDE parece bastante completo. E complexo.

Portanto surge o probelma normal de “Usar o que existe e poupar tempo (ou não)” vs. “Construir algo costumizado, e talvez mais simples (ou não)”. Vou ter de estudar melhor o MyGeneration a ver se encaixa.

BackupPC

Em tempos, neste blog, inclui uma série de posts dedicados a backups. Uma das soluções que mencionei foi o BackupPC, uma aplicação Linux que permite efectuar backups de maquinas em Linux, Windows e até MAC, via a rede.

Durante o último ano tive uma máquina recuperada a funcionar na Misericórdia local com a aplicação, a efectuar backups dos dados das várias estações de trabalho e servidores. Infelizmente a minha primeira configuração não resultou completamente. Parte do problema foi a configuração efectuada ao nível dos discos no Linux – o mount point do disco para os backups não deveria estar bem configurado, e com qualquer reboot da máquina, o disco não era montado e o serviço de backup não arrancava. Parte do problema deveria ser do próprio BackupPC a funcionar com o samba (um serviço do Linux que permite comunicar/partilhar com o Windows) – não conseguia copiar os dados das pastas Document and Settings correctamente. Decidi actualizar o Linux e refazer a configuração, desta vez utilizando o rsync para efectuar a comunicação.

Como disse, a máquina é um PC recuperado – um Pentium 4 a 1.6Ghz com 512MB de RAM, um disco de 20GB + 500GB, e uma placa de rede 1GB. Funciona bem com o Ubuntu (desktop) em cima (escolhi a versão desktop pela interface gráfica). Desta vez, na instalação, decidi acertar os pontos de montagem. O disco de 20GB foi divido em três – 10GB montado em / em ext3, 5GB montado em /home, também em ext3 e os restantes 5GB como swap. Para finalizar, montei o disco de 500Gb em /var/lib/backuppc (a pasta onde o BackupPC armazena os dados) no sistema de ficheiros ReiserFS, que tem journaling e aparenta ser bom com ficheiros pequenos. Finalmente, um dos problemas originais ficou resolvido – tendo configurado os pontos de montagem logo na instalação, o segundo disco é montado correctamente no arranque, e o serviço do BackupPC pode arrancar no arranque, correctamente, também.

Com o Ubuntu a funcionar e actualizado (8.04 + actualizações), instalei o BackupPC via o Synaptics. Surgiu um problema com a configuração do BackupPC no Apache, que foi facilmente resolvido – tive de trocar a configuração de Apache para Apache2. Um tutorial simples pode ser visto no How To Forge.

Nota 20090206- Caso surgam problemas no acesso à página (ou seja se o apache n encontrar a página do backuppc, pode ser necessário executar mais um passo: copie e execute as seguintes linhas, como referido por “Girya” nos foruns do Ubuntu:

sudo chmod 777 /etc/apache2/apache2.conf
sudo cat /etc/backuppc/apache.conf >> /etc/apache2/apache2.conf
sudo chmod 644 /etc/apache2/apache2.conf
sudo /etc/init.d/apache2 stop
sudo /etc/init.d/apache2 start

I was having the same problem as you. I don’t why backuppc won’t auto configure apache2 but I found this in a post by searching backuppc. it was posted by bgearig. It adds the required lines to the apache config file so apache can find backuppc.

A segunda parte é (ou era) a mais complexa – a da configuração do BackupPC. Felizmente o BackupPC cresceu a nível de funcionalidade e já não é necessário editar os ficheiros de configuração à mão – o backoffice web agora incluí formulários de configuração onde podemos indicar os valores dos parâmetros gerais (como o modo de transferência – rsync/rsyncd/samba), a partilha base de backup, o user e pass para o backup, periodicidade de backups, etc. Também existe formulários para efectuar a configuração de parâmetros para máquinas individuais (fazendo o overide dos gerais).

Desta vez, na configuração decidi utilizar o rsync como método de transferência. O rsync é nativo ao Linux para transferência de ficheiros, mas existe um projecto chamado cygwin que inclui o rsync a funcionar em Windows. E pelos vistos o rysnc é melhor e mais eficiente que o samba na transferência de ficheiros. O cygwin-rsync pode ser obtido no Sourceforge do BackupPC, já quase quase configurado. O único “mal” de o rsync é que é necessário instalar/configurar em cada máquina. Mas correctamente gerido, é até um processo rápido.

Um óptimo tutorial para a configuração está em http://gerwick.ucsd.edu/backuppc_manual/backuppc_winxp.html. Ele indica uma forma correcta de instalar o rsync, que fica a trabalhar como serviço no Windows. Basta copiar os ficheiros para a pasta C:\rsyncd , editar o ficheiro .secrets com o user/pass e o .conf com a informação da máquina host permitida e as pastas (ou drives) a transferir, e iniciar o serviço. Por defeito, o ficheiro indica a pasta c:\Document and Settings como uma das configurações (“docs”)e o C:\ como a outra (“cDrive”). Nas maquinas onde havia mais que um disco, adicionei um “dDrive”. Criei tb um ficheio .bat na pasta com o conjunto de comandos para adicionar os serviços:

cd \rsyncd
 cygrunsrv.exe -I rsyncd -e CYGWIN=nontsec -p c:/rsyncd/rsync.exe -a "--config=c:/rsyncd/rsyncd.conf --daemon --no-detach"
sc start rsyncd

Assim, bastava copiar a pasta para cada máquina, adicionar info aos .conf, caso necessário, e executar o .bat para iniciar o serviço. Caso houvesse firewall a funcionar, tinha de abrir uma excepção para o rsync que utiliza a porta 873. Simples!

A minha tarefa ficou bem mais simples desta forma. No BackupPC, adicionei cada uma das máquinas (à medida que ia instalando o rsync) na lista de Hosts. A parte do Xfer geral tem – rsyncd como método de transferência; “cDrive” e “docs” como partilhas base, o user e pass de acesso e a definição do porto de acesso. Caso a máquina necessitasse, adicionava a partilha “dDrive” como override para a máquina. Tudo no backoffice web. 😀

E agora sim, tenho o os documentos a serem copiados correctamente, podendo preservar correctamente os ficheiros de trabalho.

NOTA: Em máquinas Vista, convém correr o .bat na linha de comandos iniciado como Administrador…