Code for Cloud

Venho compartilhar com vocês um novo projeto que estou iniciado, o blog Code for Cloud. Neste blog irei me dedicar a criar conteúdo voltado a desenvolvimento web, tanto back-end, como front-end e infraestrutura, portanto será muito comum posts sobre HTML5, CSS, JavaScript, JQuery, Python, Apache, Nginx, AWS, etc.
Não deixe de visitar, comentar e participar, a visita de todos é muito importante.

Code for Cloud

Publicado em Programação, Tecnologia | Marcado com , , , , , , , , | Deixe um comentário

Pratique, pratique, pratique!

O título deste post faz uma referencia ao livro O Programador Apaixonado de Chad Fowler, (um livro muito bom, recomendo). No capitulo que leva o mesmo nome deste post, o autor fala da necessidade do desenvolvedor em praticar, tanto para apreender coisas novas, como para não esquecer e fortalecer esse aprendizado, dentre outras coisas.

Algo que muito me chamou a atenção neste capitulo foi a última dica passada na sessão faça algo, a dica “Pratique com Code Kata”. Não entrarei em detalhes sobre Code Kata, porém, recomendo a leitura do artigo O que é o Coding Dojo do meu grande amigo Márcio Bonfim.

Voltando ao tema, esse capítulo me motivou a praticar mais com Python. Como eu estava sem ideias sobre o que atacar, resolvi procurar alguns desafios simples, em um formato muito semelhante a um code kata, nesta busca me deparei com o site DojoPuzzles que consiste em uma coleção desses pequenos desafios.

O primeiro desafio que escolhi foi o Analisando URLs, um desafio simples o suficiente para validar se essa ideia maluca pode ser divertida. O desafio desse puzzle basicamente seria validar e interpretar as partes de uma url, seja uma url do protocolo HTTP ou uma url do protocolo SSH. O resultado do estudo/desafio ficou desta forma:

import re

class UrlAnalyzing:
    def __init__(self, url=''):
        self.url = url

    def __get_protocol(self):
        m = re.match(r'\w+', self.url)
        if m:
            return m.group(0)
        else:
            raise Exception('Invalid url')

    def __get_http_information(self):
        m = re.match(r'(?P<protocol>\w+)://(?P<host>\w+)\.(?P<domain>[\w\.]+)/?(?P<path>\w*)/?(?P<parameter>[\w=]*)', self.url)
        if m:
            return {'url': self.url,
                    'protocol': m.group('protocol'),
                    'host': m.group('host'),
                    'domain': m.group('domain'),
                    'path': m.group('path'),
                    'parameter': m.group('parameter')}
        else:
            raise Exception('Invalid url')

    def __get_ssh_information(self):
        m = re.match(r'(?P<protocol>\w+)://(?P<user>\w+)%(?P<password>\w+)@(?P<domain>[^/]+)', self.url)
        if m:
            return {'url': self.url,
                    'protocol': m.group('protocol'),
                    'user': m.group('user'),
                    'password': m.group('password'),
                    'domain': m.group('domain')}

    def analyzing(self):
        protocol = self.__get_protocol().upper()
        if protocol == 'HTTP':
            return self.__get_http_information()
        elif protocol == 'SSH':
            return self.__get_ssh_information()
        else:
            raise Exception('Invalid url')

Basicamente fiz uma classe que realiza todas as validações e tratamentos utilizando RegEx (uma das coisas mais bacanas que eu apreendi no último ano). A utilização desta classe é algo muito simples, informe a url e execute o método analyzing(), veja os exemplos:

Chamada:

ua = UrlAnalyzing('http://www.google.com/mail/user=fulano')
print(ua.analyzing())

Saída:

{'host': 'www', 'path': 'mail', 'protocol': 'http', 'domain': 'google.com', 'parameter': 'user=fulano', 'url': 'http://www.google.com/mail/user=fulano'}

Chamada:

ua.url = 'ssh://fulano%senha@git.com/'
print(ua.analyzing())

Saída:

{'protocol': 'ssh', 'user': 'fulano', 'domain': 'git.com', 'password': 'senha', 'url': 'ssh://fulano%senha@git.com/'}

Chamada:

ua.url = 'htp://123@gmail.www&_.1'
print(ua.analyzing())

Exception gerada pela url ser inválida:

Exception: Invalid url

Apesar de eu não estar fazendo um dojo (por estar desenvolvendo sozinho), ainda sim a experiência até agora foi muito divertida. Recomendo para você que esteja aprendendo uma nova linguagem mas não tem abertura para usa-la profissionalmente, procure por grupos de CodingDojo em sua cidade, ou seja independente e procure alguns pequenos desafios para praticar e testar seus conhecimentos.

Estarei mantendo o repositório python-puzzles no GitHub com todos os katas que eu for resolvendo, sinta-se à vontade para colaborar com o repositório, seja sugerindo melhores resoluções ou até mesmo sugerindo novos desafios para serem resolvidos.

Publicado em Metodologias Ágeis, Programação, Tecnologia | Marcado com , , , , , | Deixe um comentário

Design Pattern Strategy com Delphi

O padrão de projetos Strategy (GoF) consiste em um padrão comportamental que se preocupa em encapsular um determinado comportamento dentro de um objeto, delegando a execução desse comportamento para outro objeto, de forma que, caso seja necessário, esse algoritmo pode ser alterado sem afetar o objeto principal. Com isso fica fácil especificar e alterar as estratégias de processamento de um objeto, independente do cliente que esteja lhe usando.

Imagine no cenário de um ponto de vendas (PDV) o processamento de uma venda. Esse processo pode ser executado de diversas formas (ou se preferir, estratégias), por exemplo: itens concomitantes ou não, emissão de cupom fiscal, impressão não fiscal, envio para um webservice, gravação local, etc. Muito provavelmente, uma solução sem uso de padrões de projetos resultaria em uma série de blocos condicionais (IF’s) encadeados. O que significa código sujo, de difícil compreensão, difícil manutenibilidade e altamente destrutivo. O pattern Strategy foi criado para evitar esse tipo de problema.

Das diversas motivações para aplicar o pattern Strategy, eu destaco as seguintes:

  • Evitar a construção de diversas classes semelhantes que diferem somente em alguns comportamentos.
  • Possibilitar a variação dinâmica de um determinado algoritmo dentro de uma classe.
  • Deixar de usar operadores condicionais para realizar operações que podem variar.
  • Novos comportamentos podem ser implementados sem afetar o comportamento atual.

Para nos localizarmos melhor, vamos conhecer os participantes do pattern Strategy e suas atribuições:

  • Contexto (contexto): O objeto que possui o comportamento que será encapsulado em uma estratégia. O contexto recebe uma estratégia concreta e interage com ela.
  • Estratégia (strategy): A interface abstrata comum de todas as estratégias. Graças a essa interface é possível que o contexto se comunique com diferentes estratégias sem alterar o seu funcionamento.
  • Estratégia concreta (concrete strategy): O objeto concreto que implementa a interface da estratégia. O objeto de estratégia concreta é o objeto que efetivamente executa os algoritmos da estratégia.
  • Cliente (client): Responsável por criar o contexto e determinar qual será a estratégia concreta utilizada.

O contexto precisa conhecer a interface das estratégias para poder aplica-las, assim como as estratégias precisam conhecer o contexto para coletar as informações necessárias para a execução do algoritmo de estratégia ou até mesmo manipular o estado do contexto. Você pode optar por passar todas informações necessárias para a estratégia via parâmetro, mas dependendo da complexidade da solução, isso se torna inviável.

Um lema muito difundido entre os entusiastas do eXtreme Programming (os desenvolvedores que adotam o XP utilizam largamente os Design Patterns) é:

Programe para uma interface e não para uma implementação

Entenda interface como algo abstrato e não concreto (no Delphi pode ser tanto uma classe com métodos virtuais e abstratos como uma interface propriamente dita), por essa razão, o pattern Strategy pode ser implementado de duas formas, através de herança e polimorfismos ou através de interfaces. Neste post estarei mesclando um pouco as duas abordagens, porém dando mais ênfase para o uso de interfaces.

Para demonstrar o diagrama do pattern Strategy, vamos voltar ao exemplo de processamento de vendas em um PDV e definir quais serão nossas entidades e seus respectivos papeis na solução:

A classe TVenda será nosso contexto. Uma venda pode ter vários tipos de comportamentos, portanto, o tipo da venda será nossa estratégia e será representado pela interface ITipo. As estratégias concretas implementam a interface de ITipo. A classe TVenda não conhece a implementação da estratégia contida nas classes concretas de ITipo, assim como as classes concretas de tipo de venda, só devem conhecer a abstração de TVenda. Lembre-se, “programe para uma interface e não para uma implementação”.

Vale ressaltar que esse é um exemplo didático, onde o intuito é apresentar o conceito e não propor uma solução final para um problema que imagino que muitas softwares houses sofrem. Sendo assim, não faremos nada de muito prático, apenas uma aplicação do tipo console para validar a proposta do pattern Strategy.

Antes de partirmos para a solução elegante, vamos fazer um exercício e tentar imaginar como seria o método “Finalizar()” da classe TVenda, sem o uso do pattern Strategy. Talvez algo como:

function TVenda.Finalizar: Boolean;
begin
  if Self.Tipo = 0 then //não fiscal
  begin
    Writeln('imprimir itens');
  end
  else if Self.Tipo = 1 then //fiscal
  begin
    Writeln('Enviar itens para o ECF');
    Writeln('Imprimir o cupom fiscal');
  end
  else if Self.Tipo = 2 then //concomitante
  begin
    Writeln('Imprimir o cupom fiscal');
  end;
  Writeln('finalizar venda');
end;

Já posso imaginar o seu desespero, “IF’s”, “números mágicos”, “comentários”, “duplicidade”, etc. Outros devem estar pensando “esse código me lembra tanto um código que sofro para dar manutenção”. Vamos ver agora como podemos melhorar esse cenário, implementado o pattern Strategy. Vamos começar pelas interfaces e abstrações do nosso problema, TVenda e ITipo:

type
  TVenda = class;

  ITipo = interface
    procedure ProcessarItem(AVenda : TVenda);
    procedure ProcessarVenda(AVenda : TVenda);
  end

  TVenda= class
  private
    FTipo : ITipo;
    FItens : TStringList;
  public
    constructor Create(ATipo : ITipo);
    destructor Free();
    procedure AdicionarItem(const AItem : string);
    function Finalizar():Boolean;
    property Itens : TStringList read FItens;
  end;

A classe TVendas recebe a sua estratégia concreta em seu método construtor (Create()) e armazena no atributo FTipo que é do tipo ITipo (aproveito esse método também para criar a instancia da listagem de itens da venda):

constructor TVenda.Create(ATipo: ITipo);
begin
  Self.FTipo := ATipo;
  Self.FItens := TStringList.Create;
end;

Vamos partir do ponto que, a cada item adicionado (AdicionarItem()), será executado o método ProcessarItem() da estratégia e quando for solicitada a finalização da venda (Finalizar()), será executado o método ProcessarVenda() da estratégia. Desta forma:

procedure TVenda.AdicionarItem(const AItem: string);
begin
  Self.FItens.Add(AItem);
  Self.FTipo.ProcessarItem(Self);
end;

function TVenda.Finalizar: Boolean;
begin
  Self.FTipo.ProcessarVenda(Self);
  Result := true;
end;

Pronto, agora basta implementar as diversas estratégias necessárias (respeitando a interface de ITipo) e passar a interagir com a classe TVenda. Vamos começar pela estratégia concreta TTIpoNaoFiscal, que representa uma estratégia de venda não fiscal:

type
  TTipoNaoFiscal = class(TInterfacedObject, ITipo)
  public
    procedure ProcessarItem(AVenda: TVenda);
    procedure ProcessarVenda(AVenda: TVenda);
  end

Como a classe TTipoNaoFiscal implementa a interface ITipo, ela já está “credenciada” para ser uma estratégia para a classe TVenda. Em nosso cenário fictício, a estratégia de venda não fiscal não necessita realizar nenhum processamento ao adicionar itens a venda, mas, deve realizar a impressão em tela de todos os itens da venda no momento da finalização desta.

procedure TTipoNaoFiscal.ProcessarItem(AVenda: TVenda);
begin
end;

procedure TTipoNaoFiscal.ProcessarVenda(AVenda: TVenda);
var
  I: Integer;
begin
  writeln('#################################');
  Writeln('# Impressão de venda não fiscal #');
  writeln('#################################');
  Writeln(EmptyStr);

  for I := 0 to AVenda.Itens.Count - 1 do
    Writeln(Format('Item %d: %s',[I+1, AVenda.Itens.Strings[i]]));

  Writeln(EmptyStr);
  writeln('#################################');
  Writeln('#              FIM              #');
  writeln('#################################');
end;

Antes de implementarmos novas estratégias, vamos validar a estratégia TTipoNaoFiscal com o seguinte código no próprio arquivo dpr do projeto (levando em consideração que esta é uma aplicação console):

var
  oVenda : TVenda;
begin
  oVenda := TVenda.Create(TTipoNaoFiscal.Create());
  try
    try
      oVenda.AdicionarItem('Banana');
      oVenda.AdicionarItem('Maça');
      oVenda.Finalizar();
      Readln;
    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    oVenda.Free;
  end;
end.

Ao executar a aplicação acima, a saída de console será a seguinte:

#################################
# Impressão de venda não fiscal #
#################################

Item 1: Banana
Item 2: Maça

#################################
#              FIM              #
#################################

Excelente, já estamos fazendo vendas não fiscais 🙂 . Vamos implementar agora a estratégia de venda fiscal, criando a classe concreta TTipoFiscal.

type
  TTipoFiscal = class(TInterfacedObject, ITipo)
  public
    procedure ProcessarItem(AVenda: TVenda);virtual;
    procedure ProcessarVenda(AVenda: TVenda);
  end;

(Não se preocupe, a diretiva virtual, fará sentido mais a frente 🙂 ).
Assim como a classe TTipoNaoFiscal, a classe TTipoFiscal não fará tratamentos ao adicionar itens a venda, porém, no momento de fechamento, a venda será “enviada para o ECF”:

procedure TTipoFiscal.ProcessarItem(AVenda: TVenda);
begin
end;

procedure TTipoFiscal.ProcessarVenda(AVenda: TVenda);
begin
  writeln('################################');
  Writeln('# Impressão enviada para o ECF #');
  writeln('################################');
end;

Para testar nossa nova estratégia, vamos mudar a linha:

oVenda := TVenda.Create(TTipoNaoFiscal.Create());

Para:

oVenda := TVenda.Create(TTipoFiscal.Create());

Veja que não foi necessária nenhuma alteração na classe TVenda. Ao executar o teste da nova estratégia, teremos a seguinte saída no console:

################################
# Impressão enviada para o ECF #
################################

Implementaremos agora nossa ultima estratégia concreta, a que irá realizar vendas fiscais, porém, com impressão de itens concomitantes (simultâneo ao lançamento). Essa estratégia será representada na classe concreta TTipoFiscalConcomitante. A estratégia de venda fiscal concomitante só difere da estratégia de venda fiscal no que diz respeito a impressão concomitante dos itens, sendo assim, iremos aproveitar o rotina de “enviar a venda para o ecf” da nossa classe TTipoFiscal através de herança:

type
  TTipoFiscalConcomitante = class(TTipoFiscal)
  public
    procedure ProcessarItem(AVenda: TVenda);override;
  end;

Repare que, diretamente não estou especificando que minha classe TTipoFiscalConcomitante implementa a interface ITipo, porém, por ela ser uma herança da classe TTipoFiscal, implicitamente a minha classe TTipoFiscalConcomitante implementa a interface ITipo. Como dito anteriormente, nossa estratégia de venda fiscal concomitante somente irá se diferenciar da estratégia de venda fiscal no que diz respeito a tratamento de itens lançados na venda, sendo assim, como herdamos da classe TTipoFiscal, só precisamos sobrescrever o método ProcessarItem():

procedure TTipoFiscalConcomitante.ProcessarItem(AVenda: TVenda);
var
  I : integer;
begin
  inherited;
  I := AVenda.Itens.Count;
  Writeln(Format('Item [%d-%s] enviado para o ECF',[I, AVenda.Itens.Strings[I-1]]));
end;

Eu sei que seria possível resolver todo esse cenário apenar usando heranças da classe TVenda, porém, o pattern Strategy é uma forma de fugir das heranças. Repetindo o nosso teste agora para a classe TTipoFiscalConcomitante, vamos mudar a linha:

oVenda := TVenda.Create(TTipoFiscal.Create());

Para:

oVenda := TVenda.Create(TTipoFiscalConcomitante.Create());

Mais uma vez, repare que somente alteramos a estratégia e não o contexto, a saída desse novo teste será a seguinte:

Item [1-Banana] enviado para o E
Item [2-Maça] enviado para o ECF
################################
# Impressão enviada para o ECF #
################################

Para fechar, poderíamos criar um método que de forma dinâmica nos retorne uma instancia da estratégia concreta, que por algum motivo, será a estratégia que deverá ser usada no momento. Em nosso exemplo, essa decisão será tomada através de um parâmetro de linha de comando:

function GetTipoVenda():ITipo;
var
  sParam : string;
begin
  sParam := ParamStr(1);
  if sParam = 'fiscal' then
    Result := TTipoFiscal.Create()
  else if sParam = 'concomitante' then
    Result := TTipoFiscalConcomitante.Create
  else
    Result := TTipoNaoFiscal.Create();
end;

E finalmente, nossa estratégia de venda passa a ser dinâmica:

oVenda := TVenda.Create(GetTipoVenda());

O cenário de processamento de venda foi um exemplo de uso em uma situação real do pattern Strategy. A ideia é entender os conceitos por trás desse pattern. Você pode encontrar os fontes dos exemplos desse post e outros exemplos de design patterns neste repositório do GitHub.

Publicado em Metodologias Ágeis, Programação | Marcado com , , , , | 3 Comentários

E como fica o Singleton no Python?

Ultimamente tenho passado a dar mais atenção ao Python e tenho gostado muito da experiência. Obviamente que, para qualquer desenvolvedor, a transição de uma linguagem para outra pode ocasionar alguns choques. Vejo isso como algo positivo, simplesmente por que, você não pode codificar em um linguagem como codificaria em outra. Em outras palavras, você não pode desenvolver em python da mesma forma que desenvolve em delphi. Desenvolver desta forma é um erro muito comum e que pode atrapalhar bastante no processo de aprendizado.

O mais recente choque desses que tive foi com relação ao pattern Sigleton (GoF). Isso porque, aparentemente em python existe outro pattern semelhante, que na prática funciona da mesma maneira, o pattern Borg.

Se no pattern Singleton, garantimos somente uma instancia de um determinado objeto, no Borg podemos ter N instancias do mesmo objeto, porém, todas essas instancias compartilham o mesmo estado. O que isso significa? Significa que, em um objeto de uma classe Borg, se você atribuir 10 para o atributo x, você está alterando o estado de todos os objetos instanciados dessa classe.

Para descomplicar, vamos ver os dois padrões na prática, começando pelo Borg:

class Borg:
    __shared_state = {}

    @property
    def x(self):
        return self.__x

    @x.setter
    def x(self, value):
        self.__x = value

    def __init__(self):
        self.__dict__ = self.__shared_state

O atributo __shared_state é um atributo de classe e o Self.__dict__ consiste em uma estrutura interna do Python que armazena o estado do objeto. Em uma forma simplista de dizer, o código acima faz com que a cada nova instancia da classe Borg (__init__), o estado do objeto passe a ser controlado pelo atributo __shared_state.

Já o Singleton não possui nenhuma novidade, a inteligência toda fica por conta do método instance().

class Singleton:
    __instance = None

    @property
    def x(self):
        return self.__x

    @x.setter
    def x(self, value):
        self.__x = value

    @staticmethod
    def instance():
        if not Singleton.__instance:
            Singleton.__instance = Singleton()
        return Singleton.__instance

Em termos de uso, como mencionei no começo do post, não temos muitas diferenças, veja um exemplo:

s1 = Singleton.instance()
s2 = Singleton.instance()
s1.x = 10

b1 = Borg()
b2 = Borg()
b1.x = 20

print('Singleton')
print('s1.x={} | s2.x={}'.format(s1.x, s2.x))
print('id(s1)={} | id(s2)={}'.format(id(s1), id(s2)))
print('-------------------')
print('Borg')
print('b1.x={} | b2.x={}'.format(b1.x, b2.x))
print('id(b1)={} | id(b2)={}'.format(id(b1), id(b2)))

A saída do código acima será a seguinte:

Singleton
s1.x=10 | s2.x=10
id(s1)=30928456 | id(s2)=30928456
-------------------
Borg
b1.x=20 | b2.x=20
id(b1)=30928512 | id(b2)=30928624

Veja que nos objetos Borg, o id retornado é diferente, o que significa que estamos lidando com instancias distintas, porém, o valor do atributo X é o mesmo para as duas instancias.

Uma vantagem do Borg é que o seu funcionamento se estende para as suas subclasses, porém, as vezes o que realmente queremos é somente uma instancia de uma determinada classe.

Independente de qual é o melhor, conhecer os dois e estar pronto para usá-los ou interpretá-los no momento certo é com certeza a melhor opção.

Publicado em Programação | Marcado com , , , | Deixe um comentário

Singleton Pattern no Delphi com uma nova abordagem

Recentemente tive a felicidade de ver meu artigo Padrão Singleton com Delphi publicado na edição 110 da revista Active Delphi. Neste artigo explico as características do Design Pattern Singleton (GoF) e mostro algumas maneiras de implementar ele no Delphi.

Simplificando a questão, uma classe Singleton só deve possuir uma instancia em todo contexto da aplicação. A maneira mais básica de implementar o pattern Singleton no Delphi é seguindo o seguinte esqueleto:

type
  TMyClass = class
  strict private
    class var FInstance : TMyClass;
  private
    class procedure ReleaseInstance();
  public
    class function GetInstance(): TMyClass;
  end;

O segredo está no uso do atributo de classe FInstance, que armazena uma instancia da classe em questão. Os métodos GetInstance() e ReleaseInstance() por sua vez são responsáveis por trabalhar com apenas uma instancia da classe, ou seja, a instancia armazenada no atributo FInstance. A implementação desses métodos, garante essa segurança:

class function TMyClass.GetInstance: TMyClass;
begin
  if not Assigned(Self.FInstance) then
    self.FInstance := TMyClass.Create;
  Result := Self.FInstance;
end;

class procedure TMyClass.ReleaseInstance;
begin
  if Assigned(Self.FInstance) then
    Self.FInstance.Free;
end;

initialization
finalization
  TMyClass.ReleaseInstance();

Para utilizar uma classe singleton basta substituir o Create() pelo GetInstance() e não executar o método Free().

var
  oMyClass : TMyClass;
begin
  oMyClass := TMyClass.GetInstance();
  oMyClass.ExecutarAlgo();
  {...}

Ai vem a pergunta, como fica o memory leek? Bem, repare que na implementação da classe singleton o método ReleaseInstance() é executado no finalization da unit, ou seja, quando aquela unit sair do contexto da aplicação, a instancia da nossa classe singleton será liberada da memória.

Pesquisando sobre design patterns em Delphi, me deparei com uma abordagem muito interessante relacionada ao pattern Singleton. Da maneira anterior, a inteligência que faz com que uma classe seja singleton deve ser replicada em toda classe que deve funcionar como singleton. Isso não é tão ruim, visto que estamos lidando com uma implementação simples, porém, não seria interessante poder transformar qualquer classe comum em uma classe singleton? Isso é possível, basta utilizar Generics. Criaremos uma classe genérica chamada TSingleton e ela será o nosso coringa para transformar outras classes comuns em classes singleton.

type
  TSingleton<T: class, constructor> = class
  strict private
    class var FInstance : T;
  public
    class function GetInstance(): T;
    class procedure ReleaseInstance();
  end;

Veja que, desconsiderando o uso de generics, em quase nada a interface da classe é diferente do modelo anterior, assim como também, não há grandes diferenças de implementação.

class function TSingleton<T>.GetInstance: T;
begin
  if not Assigned(Self.FInstance) then
    Self.FInstance := T.Create();
  Result := Self.FInstance;
end;

class procedure TSingleton<T>.ReleaseInstance;
begin
  if Assigned(Self.FInstance) then
    Self.FInstance.Free;
end;

O diferencial aqui fica por conta da flexibilidade. Com essa classe genérica podemos transformar qualquer classe comum em uma classe singleton sem alterar em nada a classe original. Vamos ver na prática, recriando nossa classe TMyClass. Faremos essa classe sem os controles de uma classe singleton e logo em seguida, criaremos uma classe que seja uma opção singleton da classe TMyClass.

type
  TMyClass = class
  strict private
    FValue : integer;
  public
    property Value : Integer read FValue write FValue;
  end;

  TMyClassSingleton = TSingleton<TMyClass>;

Pronto, agora nossa classe TMyClass pode funcionar tanto como uma classe normal, como uma classe singleton, graças a classe TMyClassSingleton. Para garantir que não teremos memory leek, é recomendado liberar a instancia no finalization da unit, assim como feito anteriormente:

initialization
finalization
  TMyClassSingleton.ReleaseInstance();

Em termos de utilização da classe, em nada difere os dois modelos, em ambos utilizamos o GetInstance() no lugar do Create() e dispensamos o uso do Free(). Em um teste simples de uma aplicação console, podemos validar se nossa abordagem está realmente correta:

var
  oSingleton1  : TMyClass;
  oSingleton2  : TMyClass;
begin
  oSingleton1  := TMyClassSingleton.GetInstance();
  oSingleton2  := TMyClassSingleton.GetInstance();
  try
    oSingleton1.Value  := 2;
    oSingleton2.Value  := 3;

    Writeln(Format('Singleton1: %d | Singleton2: %d',[oSingleton1.Value,
                                                      oSingleton2.Value]));
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

A saída do código acima será:

Singleton1: 3 | Singleton2: 3

Ou seja, tanto o objeto oSingleton1 quando o objeto oSingleton2 estão apontando para a mesma instancia da classe TMyClass. São duas abordagens de implementação distintas, com um resultado semelhante, qual você prefere?

Publicado em Programação | Marcado com , , , , | 4 Comentários

Recuperando o XML de uma requisição SOAP em Delphi

Talvez a maneira mais popular de se fazer uma integração entre diferentes aplicações é através de Webservices SOAP. Inúmeras aplicações governamentais trabalham com webservices, como é o caso do projeto Farmácia Popular, Nota Fiscal Eletrônica (NFe), Conhecimento de Transporte Eletrônico (CTe), etc.

Para ajudar nesse processo, existem as definições WSDL que consiste numa espécie de documentação do webservice. Para ficar ainda melhor, o Delphi está preparado para importar as definições WSDL de um webservice e já criar toda uma interface de comunicação entre a sua aplicação e o webservice, sendo necessário somente consumir os métodos já criados. Obviamente existe um mundo de definições e pequenos detalhes que não irei me aprofundar.

Para mostrar o quanto tudo isso é tranquilo, faremos o processo completo para o consumo de um webservice simples. O site WebserviceX.NET possui uma série de webservices livres para testes. Usaremos o webservice Currency Convertor, um webservice responsável por obter taxa de conversão de uma moeda para outra.

Importando o WSDL
Primeiramente (após criar um novo projeto obviamente) iremos importar o arquivo WSDL do webservice Currency Convertor. Esse está disponível no endereço: http://www.webservicex.net/CurrencyConvertor.asmx?WSDL.
Baixe esse arquivo na sua máquina e vamos ao processo de importação no Delphi.
Com o projeto criado, vá em File -> New Other e depois vá em Webservices -> WSDL Importer

wsdl

O processo de importar o WSDL é extremamente simples, next -> next -> finish (não se preocupe com as opções, faça a importação com a parametrização default).  Após a importação, será criada a unit CurrencyConvertor.pas e essa já será adicionada ao projeto.

Consumindo o Webservice
Com isso seu aplicativo já está praticamente pronto para consumir o webservice, bastando apenas incluir um código extremamente simples (obviamente, pelo fato do webservice ser simples).

uses
  CurrencyConvertor

procedure TfrmWebserviceCliente.Converter();
var
  oCCSoap : CurrencyConvertorSoap;
begin
  oCCSoap := GetCurrencyConvertorSoap();
  try
    ShowMessageFmt('USD -> BRL = $%f',[oCCSoap.ConversionRate(Currency.USD,Currency.BRL)]);
  finally
    oCCSoap := nil;
  end;
end;

Se você nunca consumiu um webservice antes e está acompanhando esse post, parabens, você acaba de consumir o seu primeiro webservice 🙂 . No código acima foi convertido o valor de 1 dolar para real.

Para saber qual método você deve executar para criar uma instancia do objeto que representa o webservice, na unit que foi gerada pela importação do WSDL, basta conferir os métodos da sessão implementation, o Delphi sempre disponibilizar um método com a assinatura Get[NomeDoWebservice].

Recuperando o conteúdo das mensagens.
O grande problema de tudo isso é que essa negociação HTTP toda, fica muito camuflada dentro das implementações do Delphi e por algumas vezes, tive a necessidade de validar o conteúdo XML puro da requisição assim como o XML puro de resposta. Para resolver esse problema, basta utilizar um componente THttpRIO e interceptar o conteúdo da negociação HTTP. Calma, não se assuste, isso é bem simples.

O componente THttpRio, dentre outras coisas, possui os métodos OnBeforeExecute e OnAfterExecute, o primeiro é executado antes da requisição e o segundo após momento da resposta. Em nosso exemplo, adicione esse componente e mais dois TMemo em seu projeto (mmRequest e mmResponse) e defina os métodos OnBeforeExecute e OnAfterExecute do componente THttpRio da seguinte maneira.

procedure TfrmWebserviceCliente.httpRioBeforeExecute(const MethodName: string;
  SOAPRequest: TStream);
begin
  SOAPRequest.Position := 0;
  mmRequest.Lines.LoadFromStream(SOAPRequest);
  SOAPRequest.Position := 0;
end;

procedure TfrmWebserviceCliente.httpRioAfterExecute(const MethodName: string;
  SOAPResponse: TStream);
begin
  SOAPResponse.Position := 0;
  mmResponse.Lines.LoadFromStream(SOAPResponse);
  SOAPResponse.Position := 0;
end;

Esse foi apenas um exemplo simplório, mas como você pode ver, tanto o conteúdo do request (SOAPRequest), quanto o conteúdo do response (SOAPResponse) são objetos do tipo TStream, sendo assim, você pode manipular essa informação da maneira que for necessária, inclusive, se necessário, é possível manipular o request para que o conteúdo enviado não seja o gerado pelo Delphi e sim, um conteúdo gerado em outra rotina. Para realizarmos o teste, vamos mudar a criação da instancia do objeto que representa o webservice, para que ele tenha conhecimento do nosso componente THttpRio.

procedure TfrmWebserviceCliente.Converter;
var
  oCCSoap : CurrencyConvertorSoap;
begin
  oCCSoap := GetCurrencyConvertorSoap(false, EmptyStr, httpRio);
  try
    ShowMessageFmt('USD -> BRL = $%f',[oCCSoap.ConversionRate(Currency.USD,Currency.BRL)]);
  finally
    oCCSoap := nil;
  end;
end;

Veja que agora estamos especificando 3 parâmetros, o primeiro é se nossa instancia do webservice irá utilizar o endereço do WSDL como endereço do serviço, o segundo parâmetro define qual será o endereço final da requisição (note que o segundo parâmetro anula o primeiro) e por fim, o terceiro parâmetro é o componente THttpRio.

Feita a alteração, repita o teste e veja que em nossos componentes memos, estão os conteúdos de request e response da requisição, conforme a especificado a baixo.

Request:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <SOAP-ENV:Body>
      <ConversionRate xmlns="http://www.webserviceX.NET/">
         <FromCurrency>USD</FromCurrency>
         <ToCurrency>BRL</ToCurrency>
      </ConversionRate>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Response:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soap:Body>
      <ConversionRateResponse xmlns="http://www.webserviceX.NET/">
         <ConversionRateResult>2.349</ConversionRateResult>
      </ConversionRateResponse>
   </soap:Body>
</soap:Envelope>

Acredite, é realmente muito útil ter em mãos o conteúdo da requisição, pois é comum que em um cenário de integração entre aplicações, o fornecedor do serviço, solicite o payload da requisição, ou seja, o conteúdo desta, para validar possíveis inconsistência.

Disponibilizei no Gist os fontes completos de um projeto utilizando esses códigos de exemplo, com algumas pequenas modificações (crio o THttpRio de forma dinâmica, fiz combos com as possíveis moedas, etc.), quem tiver interesse é só baixar e montar o projeto.

Publicado em Programação | Marcado com , , , | 1 Comentário

Padrão Singleton com Delphi – Revista Active Delphi 110

Olá amigos, como estão? Sei que estou meio distante desse blog, mas estou me esforçando para continuar perto da comunidade Delphi.

Prova disso que estou falando é essa excelente noticia que venho compartilhar com vocês. Esse mês foi publicado o meu artigo Padrão Singleton com Delphi na edição 110 da revista Active Delphi.

Este artigo fala sobre o Design Pattern Singleton (GoF) no Delphi, tanto em termos de implementação como de funcionamento e faz algumas sugestões de uso.

Estou torcendo para que gostem do artigo e estou aguardando ansiosamente pelo feedback de todos.

Grande abraço e até a próxima.

Publicado em Programação, Publicações | Marcado com , , , , , , | 1 Comentário

Use Class/Record Helpers no Delphi

Você sabe o que vem a ser um Class Helper?
Class Helper é uma técnica da programação orientada a objetos que tem o intuito de estender as funcionalidades de uma classe, sem que seja necessário utilizar herança e sem que seja necessário alterar a classe original.

Imagine o seguinte cenário. Em sua aplicação existe a classe TPessoa, que por algum motivo você não pode alterar a sua implementação, mas, necessita de um determinado método nesta classe, como por exemplo retornar a idade da pessoa a partir de sua data de nascimento.

Em situações normais, seria feito um método CalcularIdade() por exemplo e seria usado da seguinte forma:

{...}
  EdtIdade.Text := IntToStr(CalcularIdade(oPessoa.DataNasc));
{...}

Agora imagine se fosse desta forma:

{...}
  EdtIdade.Text := oPessoa.Idade.ToString;
{...}

Muito mais claro e limpo. Mas como fazer isso sem ter acesso a implementação da classe TPessoa? Simples, fazendo um Class Helper para a classe TPessoa.
Faremos um exemplo bem simples para mostrar o uso prático do recurso. Vamos começar pela interface da classe TPessoa:

type
  TPessoa = class
  private
    FDataNasc: TDate;
  public
    property DataNasc : TDate read FDataNasc write FDataNasc;
  end;

Usaremos somente o campo referente a data de nascimento, pois ele está no foco do nosso exemplo. Agora faremos o nosso Class Helper para a classe TPessoa:

type
  TPessoaHelper = class helper for TPessoa
  private
    function GetIdade: integer;
  public
    property Idade : integer read GetIdade;
  end;

implementation
uses
  DateUtils,
  System.SysUtils;

{ TPessoaHelper }

function TPessoaHelper.GetIdade: integer;
begin
  Result := YearsBetween(Self.DataNasc,Now);
end;

Note que para determinar que uma classe é um class helper de outra é necessário utilizar a diretiva helper e indicar a classe principal com a palavra reservada for.
Outro ponto que merece atenção é o fato de que, na classe helper, nós temos acesso a todos os atributos públicos da classe principal a partir da própria instância do helper, por esse motivo que foi possível acessar a propriedade DataNasc.

Pronto, agora a propriedade Idade já está disponível para todos os objetos do tipo TPessoa em units que fizerem referência a unit do class helper (caso o class helper TPessoaHelper tenha sido feito em uma unit diferente da unit da classe TPessoa).

Por exemplo:

uses
  unt_pessoa,
  unt_pessoa_helper;

procedure TForm1.Button1Click(Sender: TObject);
var
  oPessoa : TPessoa;
begin
  oPessoa := TPessoa.Create;
  try
    oPessoa.DataNasc := StrToDate('26/11/1986');
    EdtIdade.Text := IntToStr(oPessoa.Idade);
  finally
    oPessoa.Free;
  end;
end;

Mas nosso exemplo ainda não terminou. Note que ainda estou fazendo um type casting explícito na idade, como resolver isso? Utilizando Record Helper :). A partir do Delphi XE3, é possível criar helpers para tipos primitivos, como por exemplo o tipo integer.

Faremos um record helper para o tipo integer com o simples intuito de converter o inteiro para uma string:

TIntHelper = record helper for integer
public
  function ToString():String;
end;

implementation

function TIntHelper.ToString: String;
begin
  Result := IntToStr(Self);
end;

Agora sim, nosso exemplo está completo:

procedure TForm1.Button1Click(Sender: TObject);
var
  oPessoa : TPessoa;
begin
  oPessoa := TPessoa.Create;
  try
    oPessoa.DataNasc := StrToDate('26/11/1986');
    EdtIdade.Text := oPessoa.Idade.ToString;
  finally
    oPessoa.Free;
  end;
end;

Vale lembrar que utilizando o helper TIntHelper que criamos, abrimos margem para substituir a clássica conversão StrToInt para simplesmente utilizar a  nossa função ToString():

var
  iNumero : integer;
  sTexto  : string;
begin
  sTexto := 1.ToString; //sTexto = '1'
  iNumero := 2;
  sTexto := iNumero.ToString; //sTexto = '2'
end;

Mas antes de sair criando helpers para tipos conhecidos, verifique se o próprio Delphi já não disponibiliza um helper para o mesmo intuito. A unit SysUtils possui uma série de helpers para os tipos mais comumente utilizados.

Uma dúvida que sempre aparece quando se começa a utilizar class helpers é com relação a criação de mais de um helper para uma determinada classe. Por exemplo, o seguinte código não funciona da maneira que intuitivamente se espera:

  TPessoaHelper = class helper for TPessoa
  private
    function GetIdade: integer;
  public
    property Idade : integer read GetIdade;
  end;

  TPessoaFisicaHelper = class helper for TPessoa //esse passa a ser o Helper "ativo"
  public
    function isValidCPF():Boolean;
  end;

Não ocorre um erro de compilação, porém, a propriedade Idade, não estará mais disponível, pois um helper se sobrepõe ao outro. Para que isso não ocorra, é necessário indicar o class helper antecessor, desta forma:

  TPessoaHelper = class helper for TPessoa
  private
    function GetIdade: integer;
  public
    property Idade : integer read GetIdade;
  end;

  TPessoaFisicaHelper = class helper (TPessoaHelper) for TPessoa
  public
    function isValidCPF():Boolean;
  end;

  TPessoaJuridicaHelper = class helper (TPessoaFisicaHelper) for TPessoa
  public
    function isValidCNPJ():Boolean;
  end;

Devido a evoluções que a arquitetura do Delphi vem sofrendo, principalmente pelas inovações relacionadas a mobilidade, a própria Embarcadero recomenda que se use classe/record helpers para determinados fins, fazendo com que o seu código esteja protegido de eventuais mudanças mais trágicas, como por exemplo a promessa de extinção da concatenação de strings através do simbolo de adição (Ex: Str1 := ‘Texto ‘ + IntToStr(3));

Publicado em Programação | Marcado com , , | 1 Comentário

SCUTUM

scutumSCUTUM palavra em latim que significa escudo. Esse foi o nome sugerido pelo meu amigo Márcio Bonfim para essa iniciativa que ensaiei durante muito tempo para começar.

A ideia é simples, compartilhar com a comunidade soluções simples que facilitam o nosso dia a dia, mas de uma forma que fosse possível que outros desenvolvedores também colaborassem para a evolução das mesmas.

Porém, diferentemente de outros projetos Open Source, a proposta aqui é mais compartilhar boas práticas do que compartilhar soluções prontas.

A prova disso é a primeira solução proposta, o SCUTUMConnection.

O SCUTUM Connection é uma solução do tipo Abstract Factory (GoF) idealizada para permitir que o desenvolvedor desenhe suas soluções voltadas a uma interface única para acesso ao banco de dados e não se preocupe com particularidades de um SGBD ou um framework de acesso. Fazendo assim com que uma possível mudança de SGBD ou até mesmo no framework de acesso, seja transparente para a aplicação.

Hoje o framework já está encapsulando as seguintes classes concretas:

  • Firebird com DBExpress
  • Firebird com FireDac
  • SQL Server com FireDac

Farei alguns posts explicando o conceito aplicado na criação dessa solução e alguns exemplos de como usá-la.

O repositório do SCUTUM está disponível no GitHub e está passando por evoluções continuas. Conto com a participação de todos interessados, tanto para ajudar como para dar sugestões e críticas construtivas.

Publicado em Produtividade, Programação, SCUTUM, Tecnologia | Marcado com , , , , , , | Deixe um comentário

Aplicando a RTTI para serializar informações – Revista ClubeDelphi 152

Por mais essa vez venho compartilhar com vocês a alegria de ver um artigo escrito por mim sendo publicado em uma revista técnica especializada.

Meu artigo Aplicando a RTTI para serializar informações foi publicado na revista ClubeDelphi 152.

Esse artigo fala sobre conceitos de reflexão computacional, sobre o framework RTTI do Delphi e sobre conceitos e praticas de serialização de dados em Delphi usando a RTTI.

Na maior parte deste artigo a serialização é feita em notação JSON, porém, o conceito pode ser aplicado para qualquer tipo de notação.

Espero sinceramente que gostem e caso haja alguma dúvida, estou a disposição.

Publicado em Programação, Publicações | Marcado com , , , | 1 Comentário