Category Archives: Desenvolvimento de Software

100% de Code Coverage?

De forma simplificada,  o code coverage é uma métrica usada em testes automatizados que aponta o percentual de linhas de código que estão sendo cobertas pela suite de teste. Ter 100% de coverage significa que toda linha do seu código de produção está sendo executada pelo menos uma vez.

Sabendo disto, lhe pergunto, o que você ganha ao atingir 100%?

Ter um software com 100% de cobertura de testes não significa que seu software é bug-free e muito menos que ele é melhor que um software que possui apenas 80%. Além disso, eu poderia até dizer que 100% de cobertura é quase impossível. Nos projetos em que eu tentei cobertura total, geralmente eu conseguia no máximo 95% usando testes um tanto quanto inúteis, apenas para aumentar o percentual. O maior problema ao estabelecer uma meta de 100% é que seu foco ao escrever um teste acaba se voltando para atender esta meta, e não mais para testar um requisito.

Um adepto de TDD geralmente terá perto de 90% de coverage. Porquê? Porque se você escreve o teste antes, ao codificar o código de produção você fará apenas o necessário para o teste passar, nem uma linha de código a mais, nem a menos, ou seja, 100%. Em todo caso, por algum motivo de seu framework ou linguagem, você é obrigado a escrever algumas linhas não esperadas no seu teste, e isso vai fazer seu coverage baixar, por isso o 90%.

Eu não tenho o costume de verificar o coverage constantemente, executo apenas uma vez ou outra para ter uma idéia de como está a situação. Se está muito baixo, e eu considero baixo até 80%, eu busco encontrar o que está baixando tanto assim minha coberturda. As vezes é porque um método que foi criado e que não é mais utilizado ainda está dentro de uma classe, ou então uma classe que por algum motivo eu esqueci de testar. Enfim, para mim, 80% ~ 100% é um valor aceitável.

Para quem nunca usou code coverage em C#, eu recomendo baixar o plugin TestDriven.Net que já vem com diversos frameworks de teste como MbUnit e NUnit além do NCover.

Veja abaixo uma imagem das informações mostradas pelo NCover. Aquele percentual vermelho ali mostra que apenas X% das linhas daquela classe estão sendo executadas no teste. Por exemplo a classe CodeUtil (0%), não possui teste nenhum.

Model Binding de enumeration no Struts2

Depois de perder 1 dia inteiro pesquisando e de inúmeras tentativas falhas de como usar o model binding do struts2 com enumerations do Java5, eu finalmente encontrei a solução em um site Japonês. Sim, Japonês. Não entendi nada do que estavam falando, mas consegui entender parte do código, o que foi suficiente.

Resolvi registrar para ajudar quem estiver passando pelo mesmo problema. Infelizmente não tenho o link da onde tirei a solução, se eu achar novamente, eu coloca aqui a fonte.

Usando a seguinte enum e entidade:

public enum Sexo {
    Masculino, Feminino
}

public class Cliente {
    private Sexo sexo;
    public void setSexo(Sexo sexo) {
        this.sexo = sexo;
    }
    public void setSexo(String sexo) {
        this.sexo = Sexo.valueOf(sexo);
    }
    public Sexo getSexo() {
        return this.sexo;
    }
}

A view ficaria assim:

<select name="cliente.sexo">
	<option <s:if test="%{cliente.sexo == @com.pacote.Sexo@Masculino}">selected="selected"</s:if> value="Masculino">Masculino</option>
	<option <s:if test="%{cliente.sexo == @com.pacote.Sexo@Feminino}">selected="selected"</s:if> value="Feminino">Feminino</option>
</select>

Neste caso, estou considerando que a action tenha uma propriedade do tipo Cliente com nome cliente.
Eu havia tentado de tudo ali nos atributos values da tag option, principalmente 0 e 1 por estar acostumado com o ASP.NET MVC. Mas acabei descobrindo que nas values o correto é ir o nome dos valores da enumeração e a entidade precisa ter um método set que receba uma string. Veja na classe Cliente o método setSexo(String), dentro dele, apenas converto para a enumeração.

Até a próxima!

CSharpista falando Javanês, minha opinião sobre o Java


Até duas semanas atrás, meu conhecimento de Java beirava o nulo. Eu já conhecia a sintaxe, afinal, é parecida com C#. Conhecia alguns frameworks famosos também, como o Hibernate e log4j, mas colocar a mão na massa, nunca.

O projeto em que eu iria iniciar tinha como pré-requisito ser escrito em Java, com isso, tive que aprender linguagem e alguns de seus frameworks. Foi e está sendo uma experiência bem legal, e por isso resolvi compartilhar ela, bem como falar um pouco da minha opinião sobre o Java.

Sintaxe e Padrões

Preciso adminir que sou fã da forma como é implementado o get/set em C#, acho o resultado muito mais legível e de fácil compreensão. Um pequeno comparativo:

Em C#:

//definição
public class Cliente
{
    public string Nome { get; set; }
    public int Idade { get; set; }
}

//uso
public class ClienteController
{
    public void Adicionar()
    {
        Cliente cliente = new Cliente();
        cliente.Nome = "João Salsa";
        cliente.Idade = 23;

        if (cliente.Idade > 20)
        {
            //stuff
        }
    }
}

Em Java:

//definição
public class Cliente {
    private String nome;
    private Integer idade;

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getNome() {
        return this.nome;
    }

    public void setIdade(Integer idade) {
        this.idade = idade;
    }

    public String getIdade() {
        return this.idade;
    }
}

//uso
public class ClienteController {
    public void adicionar() {
        Cliente cliente = new Cliente();
        cliente.setNome("João Salsa");
        cliente.setIdade(23);

        if (cliente.getIdade() > 20) {
            //stuff
        }
    }
}

Self-explanatory, além de menor, fica mais fluente, não?

A questão das chaves também me chamou a atenção. Tanto no PHP quanto no Java, o padrão é utilizar as chaves na mesma linha da instrução, já no C#, na linha abaixo. Neste ponto eu fico com o padrão do Java. Compare o if dos dois códigos acima, se no lugar do comentário “//stuff” tivesse realmente uma única instrução, no Java ficaria mais junto e fácil de ler. Eu sei que não há necessidade de se usar chaves nestes casos, mas eu gosto.

IDE (eclipse)

Algumas hotkeys do eclipse são interessantes, por exemplo, o CTRL+SHIFT+T. Este atalho abre uma janela para pesquisar classes pelo nome usando wildcards, * e ?. Vejam a imagem abaixo:


Imagem retirada de Java Place Blog

Existe isso no Visual Studio? Eu quero :D

Outro recurso do eclipse que gostei bastante foi o do highlight que ele faz quando você clica em alguma variável ou método, vejam só:


Imagem retirada de satukubik

Ah, outro detalhe importante. Levei menos de 2 minutos para “instalar” o eclipse contra as quase 1 hora que leva o Visual Studio. Copy and Paste definitivamente é melhor que Next, Next, Finish. E isso ocorreu com tudo o que eu precisei instalar de Java na máquina: Tomcat, Eclipse e JBoss. Apenas a JDK foi no instalador. Kick ass, definitivamente.

Frameworks

Até o momento tive pouco contato com os frameworks Java, mas é impossível não falar do maven. Caramba, que fantástico, é muito útil mesmo, e até o momento não tive nenhum problema com ele. De forma simplificada, é um framework onde você define quais são as dependências do seu projeto e ele se encarrega de montar seu projeto com todas as dependências definidas, fazendo download e adicionando as referências necessárias.

Outros frameworks que tive contato foram Struts2 e JSF. Pelo o que pudi perceber, o JSF é para o ASP.NET WebForms o que o Struts2 é para o ASP.NET MVC. Eu, sendo fã de ASP.NET MVC, optei por usar Struts2. De modo geral, eu estou gostando, alguns itens como model binding e configuração deixam a desejar. A configuração é toda feita em arquivos *.xml e cada dia que passa os xml estão ficando maiores. Saudade do ASP.NET MVC onde eu configurava as rotas via C# e com sintaxe fluente…

Tirando essa parte da configuração, achei bem fácil de customizar os filters, results e interceptor, não tive que ir em nenhum tutorial, descobri sozinho, e isso só mostra o quanto é fácil.

Quanto ao JSF, um dia foi suficiente para eu largá-lo. Muita semelhança com o ASP.NET WebForms me deixou com medo, a falta de controle no HTML foi um dos motivos maiores, além disso a curva de aprendizado do JSF foi maior que o Struts2. Não fui muito a fundo no JSF, posso ter me enganado, mas a primeira impressão não agradou.

Comunidade

Aqui é que geralmente a maior partes das intrigas são geradas. Conforme este meu post, acho o GUJ um excelente fórum de discussão de alto nível. Vejo que falta isso na comunidade .NET, as dúvidas que surgem em alguns fórum são geralmente relacionados às funções de wizard e drag and drop do Visual Studio. É mais fácil achar uma discussão de algum design pattern ou arquitetura em um grupo de Java do que em um de C#.

Felizmente as coisas estão mudando, a grande movimentação que há no grupo de discussão .Net Architects prova que existe muita gente interessada em aprender e discutir este tipo de assunto.

Conclusão

Cada linguagem/plataforma tem seu espaço e momento, nunca vi uma discussão entre duas linguagens que tivesse um fim. Além disso, cada pessoa tem sua preferência e sua opinião, e devemos saber respeitá-las. Eu, por exemplo, não me dou bem com Ruby, já tentei, mas não consigo, eu prefico ficar com PHP e Python. Não digo que Ruby é ruim ou qualquer coisa do tipo, apenas não gosto. Eu não gostava de Java até então, achava tudo muito complicado, agora já estou mudando de opinião, conforme eu fui aprendendo, fui vendo que não é um bixo de 7 cabeças.

Gostei de Java, adorei a oportunidade que estou tendo de aprender, consegui sair um pouco do meu mundinho csharpista e abriu algumas portas em minha mente, porém, minha preferência continua sendo C#, I love it <3 :D

Dica #5: Escondendo teclado no Windows Mobile com C#

Olá a todos,

Neste post vou explicar como remover o teclado dos smartphones que possuem windows mobile. Além disso, vou repassar uma dica de como utilizar esse recurso com maior eficiência, prontos?

Porque eu deveria esconder o teclado?

Talvez você esteja se perguntando isso neste momento, é simples, imagine uma tela onde há apenas botões e nenhum campo para digitar, faz sentido dar ao usuário um teclado que ele não vai usar? É muito mais prático remover o teclado e evitar que ele aperte acidentalmente e deixar apenas o que importa na tela.

Como fazer?

Essas funções que envolvem alterações no core são feitas através de P/Invoke. Basicamente, são chamadas feitas à DLLs do próprio sistema operacional através do C#.

Sem mais delongas, vou colocar aqui uma classe com um método para remover o teclado, e é claro, outro para fazer o teclado aparecer novamente.

public static class Keyboard
{
    [DllImport("coredll.dll")]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("coredll.dll")]
    private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);

    [DllImport("coredll.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    private static void SetSipButton(bool show)
    {
        IntPtr hSipWindow = FindWindow("MS_SIPBUTTON", "MS_SIPBUTTON");
        if (hSipWindow != IntPtr.Zero)
        {
            IntPtr hSipButton = GetWindow(hSipWindow, 5);
            if (hSipButton != IntPtr.Zero)
                ShowWindow(hSipButton, (show) ? 1 : 0);
        }
    }

    public static void Hide()
    {
        SetSipButton(false);
    }

    public static void Show()
    {
        SetSipButton(true);
    }
}

Para usar é muito fácil. Quer esconder o teclado? Basta escrever:

Keyboard.Hide();

E agora você quer fazer o teclado voltar ao normal?

Keyboard.Show();

Difícil? :}

Agora há um problema, se você colocar isso em todo formulário que você for fazer, você vai repetir este código x vezes, onde x é a quantidade de formulários que você possui.
No coméco eu disse que eu daria uma dica, e a dica é para resolver isso.

Dica

Crie dois formulários que servirão de base. Chame um de KeyboardForm e outro de NoKeyboardForm, faça com que ambos formulários herdem de Form.

No formulário KeyboardForm coloque o código para MOSTRAR o teclado, no formulário NoKeyboardForm coloque o código para ESCONDER o teclado.

Toda novo formulário que você criar, ao invés de herdar de Form (padrão), faça ele herdar de KeyboardForm caso sua tela tenha necessidade de um teclado, caso contrário, herde de NoKeyboardForm.

Simples, elegante, eficiente, e como diria o Steve Jobs, “amazing”, “incredible”, “awesome”, “great”.

Abaixo estou deixando um pacote com uma solução que eu fiz no Visual Studio 2008 com exemplos de uso. É só baixar, abrir e executar.

Clique aqui para fazer o download de 'Removendo teclado no Windows Mobile' (40.28 kB)

Espero ter ajudado.

Configurar NHibernate em um projeto Web

Neste tutorial vou explicar como dar o primeiro passo com o NHibernate. A configuração não é nada trivial e por isso gera bastante dúvidas.

Vou estar usando a versão mais recente do NHibernate até o momento, se você quiser usar a mesma versão, utilize este link para fazer o download.

Primero passo, criando a estrutura de projetos

Abra o Visual Studio, crie um projeto Web Application e uma Class Library na mesma solução. Vai ficar assim:

Obs.: Eu tenho o costume de deletar a pasta App_Data e a classe Class1 porque não vou utilizar.

Segundo passo, criando o arquivo de configuração

Dentro do projeto Class Library, crie um xml e chame-o de hibernate.cfg.xml. Atenção, é hibernate e não nhibernate!

Dentro deste arquivo ficam as configurações do banco de dados que iremos usar. Aqui será informado qual o provider (sqlserver, mysql, oracle etc), qual a string de conexão, dialeto etc.

Estou usando MSSQL Server e meu arquivo de configuração ficou assim:


<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
 <session-factory name="NHibernate">
 <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
 <property name="connection.connection_string">Server=(local);initial catalog=MinhaBase;Integrated Security=SSPI</property>
 <property name="show_sql">false</property>
 <property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
 <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
 <property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
 <mapping assembly="MercadoVader.NHibernateModule" />
 </session-factory>
</hibernate-configuration>

Obs.: A única configuração que muda entre meu arquivo e o seu será a string de conexão. No meu caso estou usando localhost com um banco de dados chamado e usando windows authentication.

Clique com o botão direito no arquivo hibernate.cfg.xml e vá em suas propriedades, na opção Copy to Output Directory escolha o valor Copy Always.

Terceiro passo, banco de dados

Não há muito segredo aqui, apenas crie uma base de dados e rode este script para criar uma tabela de produtos.


CREATE TABLE [dbo].[PRODUTO](
 [ID] [int] IDENTITY(1,1) NOT NULL,
 [NOME] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
 [PRECO] [decimal](18, 2) NOT NULL,
 [DATA_CADASTRO] [datetime] NOT NULL,
 CONSTRAINT [PK_PRODUTO] PRIMARY KEY CLUSTERED
(
 [ID] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

Terceiro passo, banco de dados

Não há muito segredo aqui, apenas crie uma base de dados e rode este script para criar uma tabela de produtos.


CREATE TABLE [dbo].[PRODUTO](
 [ID] [int] IDENTITY(1,1) NOT NULL,
 [NOME] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
 [PRECO] [decimal](18, 2) NOT NULL,
 [DATA_CADASTRO] [datetime] NOT NULL,
 CONSTRAINT [PK_PRODUTO] PRIMARY KEY CLUSTERED
(
 [ID] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

Quarto passo, criando um HttpModule pro NHibernate

Essa parte é mais chata, primeiro de tudo, selecione o projeto Class Library e adicione referência à NHibernate.dll que está na pasta Required_Bin dentro do arquivo zip que foi baixado no início do tutorial. Adicione também uma referência à NHibernate.ByteCode.Castle que também veio no arquivo zip. Por último, adicione referência à System.Web, será necessário para poder criar uma classe que herde da System.Web.IHttpModule.

Crie uma classe chamada NHibernateSessionModule dentro da Class Library e coloque este conteúdo nela:

public class NHibernateSessionModule : IHttpModule
{
    public static readonly string KEY = "NHibernateSession";
    private static ISession _session;

    public void Dispose()
    {
    }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(context_BeginRequest);
        context.EndRequest += new EventHandler(context_EndRequest);
    }

    private void context_EndRequest(object sender, EventArgs e)
    {
        HttpApplication application = (HttpApplication)sender;
        HttpContext context = application.Context;

        ISession session = context.Items[KEY] as ISession;
        if (session != null)
        {
            try
            {
                session.Flush();
                session.Close();
            }
            catch { }
        }
        context.Items[KEY] = null;
    }

    private static ISessionFactory factory = null;

    private static ISessionFactory GetFactory()
    {
        if (factory == null)
        {
            Configuration config = new Configuration();
            if (config == null)
                throw new InvalidOperationException("NHibernate configuration is null.");

            config.Configure();

            factory = config.BuildSessionFactory();
            if (factory == null)
                throw new InvalidOperationException("Call to Configuration.BuildSessionFactory() returned null.");
        }
        return factory;

    }

    public static ISession OpenSession()
    {
        ISession session;
        session = GetFactory().OpenSession();
        if (session == null)
            throw new InvalidOperationException("Call to factory.OpenSession() returned null.");
        return session;
    }

    public static ISession CurrentSession
    {
        get
        {
            if (HttpContext.Current == null)
            {
                if (_session != null)
                {
                    return _session;
                }
                else
                {
                    _session = OpenSession();
                    return _session;
                }
            }
            else
            {
                HttpContext currentContext = HttpContext.Current;
                ISession session = currentContext.Items[KEY] as ISession;
                if (session == null)
                {
                    session = OpenSession();
                    currentContext.Items[KEY] = session;
                }
                return session;
            }
        }
    }

    private void context_BeginRequest(object sender, EventArgs e)
    {
        HttpApplication application = (HttpApplication)sender;
        HttpContext context = application.Context;
        context.Items[KEY] = OpenSession();
    }
}

Pelo fato de esta classe herdar de IHttpModule, ela será chamada toda vez que um HttpRequest for feito para sua aplicação Web. Esta classe cria uma objeto do tipo Session para cada request e só destroi ele no final.Isso garante que teremos apenas uma Sessão aberta para cada request.

Essa parte não é necessária fazer, mas é considerado uma boa prática trabalhar com apenas uma Sessão ao invés de sair criando várias.

Abra o arquivo web.config e procure pela tag httpModules, dentro desta tag adicione mais um valor, que será referência ao módulo que acabamos de criar. Fica assim:

<httpModules>
 <add name="NHibernateSessionModule" type="MercadoVader.NHibernateModule.NHibernateSessionModule, MercadoVader.NHibernateModule"/>
 <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</httpModules>

Quinto passo, o mapeamento

Ufa, quase acabando :)

Dentro da Class Library crie uma classe chamada Produto. Crie também uma pasta chamada Mapping e dentro dela crie o arquivo Produto.hbm.xml.

A classe produto fica assim:

public class Produto
{
    public int Id { get; set; }
    public string Nome { get; set; }
    public DateTime DataCadastro { get; set; }
    public decimal Preco { get; set; }
}

O arquivo Produto.hbm.xml fica assim:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="MercadoVader.NHibernateModule" assembly="MercadoVader.NHibernateModule">

  <class name="Produto" table="PRODUTO">

    <id name="Id">
      <column name="ID" sql-type="int" not-null="true"/>
      <generator class="identity" />
    </id>

    <property name="Nome" type="String">
      <column name="NOME" length="100" not-null="true" />
    </property>

    <property name="Preco" type="Decimal">
      <column name="PRECO" precision="18" scale="2" not-null="true" />
    </property>

    <property name="DataCadastro" type="DateTime">
      <column name="DATA_CADASTRO" not-null="true" />
    </property>
  </class>

</hibernate-mapping>

O que estamos fazendo aqui é criar uma classe que é espelho da nossa tabela no banco de dados e também criando um arquivo de mapeamento que liga a classe com a tabela, nada muito complexo.

Clique com o botão direito no arquivo Produto.hbm.xml e vá em suas propriedades. Na opção Build Action selecione o valor “Embedded Resource”, isso fará com que o arquivo seja compilado dentro de uma DLL.

Sexto passo, será que funciona funciona?

Para testar, você deve selecionar o projeto Web e adicionar referência ao projeto Class Library e também à NHibernate.dll.

Feito isso, entre no Default.aspx.cs e coloque isso no Page_Load:

protected void Page_Load(object sender, EventArgs e)
{
    Produto produto = new Produto();
    produto.Nome = "Biscoito Trakinas";
    produto.Preco = 1.10M;
    produto.DataCadastro = DateTime.Now;
    NHibernateSessionModule.CurrentSession.Save(produto);
}

Se tudo der certo, deverá haver um registro salvo no banco de dados agora.
Deu certo? Parabéns, o NHibernate está configurando e funcionando.
Não deu? Faça um comentário descrevendo o erro e verei se consigo ajudar.

Documentação do NHibernate está aqui: https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/

Utilize a documentação para aprender sobre HQL e como buscar dados do banco de dados.
Conforme eu havia comentado neste post, o site summer of nhibernate é muito bom para aprender.
Se eu escrevi algo errado, por favor, me corrijam, já é meio tarde e o sono já está batendo.

Aqui está o projeto que eu criei para download.

Clique aqui para fazer o download de 'MercadorVader, NH + ASP.NET' (1.09 MB)

Até a próxima!

Buscando o preço de e-commerces brasileiros usando PHP

Infelizmente nenhum e-commerce brasileiro possui uma API para integração. Imagine as possibilidades de mashup que poderiam ser criados se o Submarino e/ou Americanas liberassem uma API para consulta de produtos e de preços.

Porém existem outras formas de fazer isso, possuem N desvantagens quando comparada com uma API, mas funciona. A maneira mais fácil é fazer um httpRequest para a site do e-commerce e buscar o preço dentro do HTML que vem no httpResponse.

Quer ver um exemplo em PHP? Estou fazendo o uso de uma biblioteca FANTÁSTICA escrita em PHP, ela se chama simplehtmldom e é usada para fazer o parser de um HTML. Veja como ficou:


<?php
include('simple_html_dom.php');

//URL do produto
$url = "http://www.submarino.com.br/produto/6/21619508";

//Nome da loja
//Valores possíveis: Americanas, Submarino
$loja = "Submarino";

$html = file_get_html($url);
if ($loja == "Americanas") {
 $pattern = "dd.acomPrice";
} else if ($loja == "Submarino") {
 $pattern = "strong.for span";
}

foreach($html->find($pattern) as $element) {
 echo $element->innertext . "<br/>";
}
?>

Funciona de uma forma bem simples, a função file_get_html faz um request para o endereço que está na variável $url, método find você passa uma expressão para buscar algum conteúdo dentro do resultado HTML que da $url. Para quem conhece jQuery vai perceber que a sintaxe do “pattern” é o mesmo, extremamente simples e fácil de usar.

No caso do Americanas, estamos procurando todos os elementos dd que possuem a classe css acomPrice, dentro desta tag é que está o preço. No submarino o preço está dentro de um span que, por sua vez, está dentro de um strong com a classe css for.

Se você precisa buscar o preço de um produto em alguma loja que não seja essas duas, basta aninhar mais um if ali na verificação da loja e jogar na variável $pattern o caminho do preço no e-commerce que você precisa.

Se você está pensando em fazer uma busca de preço em massa, ou seja, buscar o preço de 100 ou mais  produtos, eu recomendo que você faça uma pausa de 5~10 segundos para não sobrecarregar o servidor do e-commerce. Use com moderação.

Clique aqui para fazer o download de 'Buscador preço PHP' (7.44 kB)

Este é o arquivo de exemplo que coloquei no post e também a biblioteca simplehtmldom.

UPDATE 30/04/2011: Como este script se baseia na estrutura da página HTML dos e-commerces, ele pode parar de funcionar a qualquer momento caso alguma alteração na página do e-commerce seja feita. É necessário alterar este script para atender a nova estrutura.

A teoria da janela quebrada e o desenvolvimento de software

Teoria da Janela Quebrada

Teoria da Janela Quebrada

EDIT: Este post foi criado dia 22/10/2009 e alterado dia 31/01/2010.

A teoria da janela quebrada foi formulada em Nova Iorque após algumas experiências feitas em bairros nobres da cidade. Em um dos testes realizados, um carro foi deixado  parado em uma rua e durante uma semana inteira ninguém tocou no carro. Os responsáveis pela experiência então quebraram propositalmente uma das janelas do carro e deixaram por mais uma semana exatamente no mesmo lugar. Qual foi o resultado? O carro foi completamente destruído, janelas quebradas, peças roubadas dentre outras degradações.

Esta teoria é aplicada em uma Política de Tolerância Zero nos estados unidos onde cada crime, por mais pequeno que seja, passa por uma punição. Uma simples pixação já é suficiente para que o delinquente seja levado pela polícia e a parede pixada é rapidamente limpada. Com o tempo percebeu-se que havia diminuido a quantidade de pixação já que era sabido que havia punição e que a polícia estava sempre de olho. Esta teoria foi assunto de um livro chamado Fixing Broken Windows: Restoring Order And Reducing Crime In Our Communities sobre a sua utilização no combate à crimanilidade.

Vejo que isto também acontece bastante com os aparelhos eletrônicos. Nos primeiros dias após a compra está tudo em perfeito estado, todo o cuidado é pouco para não danificá-lo. Todo esse cuidado acaba quando ele cai pela primeira vez. Na hora da até um aperto no coração, porém, a partir da segunda ou terceira queda ninguém se importa mais.

O que isso tem a ver com desenvolvimento de software? Tudo. O primeiro dia de um projeto é o paraíso, existem poucas classes no sistema, complexidade do código está baixa e o prazo de entrega está bem longe. O tempo vai passando, a complexidade aumentando e o prazo apertando, a tendência é que a qualidade do código baixe, pois você precisa se preocupar mais com a entrega do que com o design do código. Você adquire o famoso Technical Debt. Nesses momentos surge frases como: “Cara, faz assim mesmo, depois da entrega do produto eu te dou mais uma semana para arrumar isso”. Esse dia nunca chega.

Tendo um produto com design ruim ninguém vai se importar de fazer uma manutenção e continuar errando, o que vai contra a regra dos escoteiros, que diz: “Deixe o acampamento mais limpo do que você encontrou” e também se aplica à software.

O que fazer nestes casos? Refactore, refatore e refatore um pouco mais. Deixe o código o mais limpo possível. Se as donas de casa limpam TODA a casa uma vez (ou duas) por semana, porque também não fazemos o mesmo com nosso software?

E ai, você atua em um projeto com janelas quebradas? Cuidado.

Dica #3: Olá SGMLReader; Adeus Regex;

Eu tenho uma lista das próximas dicas que pretendo escrever sobre, essa não estava prevista, mais depois de um certo esforço para fazer isso funcionar, resolvi registrar.

Durante meu aprendizado de python conheci a htmllib, é uma biblioteca para fazer parse de documentos HTML. Antigamente eu usava regex para fazer buscas em documentos HTML, sim regex! Acredito que pior do que regex é usar o IndexOf da classe string. O problema é que regex é algo bem complicado, precisava ter um guia rápido aberto, além do mais os patterns tendem a ficar cada vez maior e mais difícil de entender. Como diria o Ramon Durães, não tem que ser difícil. De fato, não tem, a htmllib resolveu o problema, consegui de forma simples procurar tags e seus atributos usando essa super biblioteca.

De volta ao C#, me deparei com exatamente o mesmo problema. Mas dessa vez fui atrás de algo parecido e achei o SGMLReader. Pelo que andei lendo o propósito dele é converter documentos HTML em XHTML, de qualquer forma consegui novamente resolver o problema. Essa biblioteca gera uma documento XML formatado de forma perfeita, facilitando o uso do XPATH. Apenas um detalhe, ela é mais lenta que a htmlib do python, mas é bem mais flexível, você tem acesso ao XmlDocument contendo todo o código da página.

Vou deixar aqui um exemplo funcional usando essa biblioteca para resgatar todos os títulos dos posts do meu blog.

Clique aqui para fazer o download de 'SGMLReader' (92.96 kB)

Exemplo da saída do programa acima.

SGMLReader

Convite para grupo de discussão sobre arquitetura .net

Há um ano atrás a minha maior fonte para tirar dúvidas sobre arquitetura era o fórum de Arquitetura do GUJ. Apesar de ser em Java você consegue aproveitar 99% das discussões abertas, esse assunto é do tipo que você aprende uma vez e usa em qualquer lugar. Domain Model, IoC, DI, TDD, Design Patterns em geral é algo que pode ser feito qualquer linguagem, sendo ela dinâmica ou estática (não posso falar de funcional pois não sei :)). Inclusive dentro meus livros de arquitetura, a maioria deles é em Java, o Clean Code (fantástico, merece um review mais tarde) e o Code Complete (na fila…).

Para a felicidade de mais de 400 pessoas (número atual de participantes), ano passado foi criado uma lista de discussão de arquitetura focado em .Net, a idéia veio de um dos MVPs da Microsoft, o Giovanni Bassi. Aqui está a lista e aqui está o site.

Apesar do foco em .Net, temos a participação do Rafael Rosa da comunidade Ruby on Rails, o Phillip Calçado aparece de vez em quando nas threads mais quentes, e já houve a presença do Fábio Akita falando de Ruby on Rails (Vídeo).

Aproveitando o assunto, vou deixar mais alguns blogs que eu recomendo.

  1. O do Scott Hanselman, segundo esta lista com o top 200, este é o melhor blog sobre desenvolvimento desoftware;
  2. O CodeBetter, que é uma compilação de assuntos variados escritos por várias pessoas;
  3. O Bliki do Martin Fowler, preciso dizer algo? next!;
  4. Fábio Akita sobre Ruby on Rails e
  5. Phillip Calçado sobre Softwares e Batatas
http://www.hanselman.com/blog/

Dica #2: Formatando datas em formato e língua específica

Neste post do C# Brasil você consegue ver alguns dos formatos de datas possível da classe DateTime. Muitas vezes você precisa de um formato mais específico, como por exemplo, ‘Agosto, 2009′ ou ‘sábado, 29 de janeiro de 2009′.

Na lista abaixo você confere os possíveis valores de se obter usando o método ToString da classe DateTime.

Código Resultado Exemplo
HH Hora (de 0 até 23)
hh Hora (de 0 até 12)
mm Minutos
MM Mês 08, 02, 12
MMM Mês jun, ago, jan, dez
MMMM Mês agosto, setembro, outubro
dd Dia 21,10,20
ddd Dia da semana sáb, seg, ter
dddd Dia da semana sábado, segunda, terça
yy Ano 09,08,89,90
yyyy Ano 2009,2008,1989,2010

Veja alguns exemplos de como usar, e também qual o resultado.

DateTime.Now.ToString("dddd, dd 'de' MMMM 'de' yyyy"); // sábado, 22 de agostro de 2009
DateTime.Now.ToString("MMMM, yyyy"); // agostro, 2009
DateTime.Now.ToString("'dia' dd 'de' MMMM 'de' yyyy"); // dia 22 de agostro de 2009
DateTime.Now.ToString("HH:mm 'do dia' dd"); // 18:17 do dia 22
DateTime.Now.ToString("hh:mm 'do dia' dd"); // 06:17 do dia 22

Eu particularmente gosto de usar esses formatos ao invés de apenas uma letra como foi mostrado no C# Brasil, fica mais explícito e outra pessoa vai conseguir ler com mais clareza.

Por default o resultado sairá na língua atual do sistema operacional que está executando o programa, se você quer executar em uma língua específica, você pode fazer assim:

Thread.CurrentThread.CurrentCulture = new CultureInfo("nl-NL");
Console.WriteLine(DateTime.Now.ToString("dddd, MMMM")); //zaterdag, augustus

Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Console.WriteLine(DateTime.Now.ToString("dddd, dd 'de' MMMM 'de' yyyy")); //Saturday, August

Thread.CurrentThread.CurrentCulture = new CultureInfo("pt-BR");
Console.WriteLine(DateTime.Now.ToString("dddd, dd 'de' MMMM 'de' yyyy")); //sábado, agosto

Esqueci de algo?

Sharing Buttons by Linksku