Arquitetura em prática

por Fabio Margarito Martins de Barros

Law of Demeter

A lei de Demeter é um conjunto de regras para construir sistemas visando baixo acoplamento, também conhecida como Princípio do menor Conhecimento e Fale somente com os amigos. Apesar do nome, Demeter não foi o autor, Demeter é o nome do projeto conduzido pela universidade Northeasterns University em 1987 liderado pelo Dr. Karl Lieberherr. Foi projeto Demeter que as leis foram criadas e por isto o nome.

Em linhas gerais, as regras são:

  • Cada unidade deveria somente utilizar um conjunto limitado de unidades de outras unidades: somente unidades fortemente relacionadas com a unidade corrente.
  • Cada unidade deveria falar somente com seus amigos e não com estrangeiros.

Em orientação a objetos, definido que uma unidade=método de um objeto, a lei é traduzida da seguinte forma:

Um método M de um objeto O somente poderia acessar métodos de outros objetos que sigam as diretrizes:

  • Seja parâmetro de M
  • Um objeto que M criou
  • Um método do próprio objeto O
  • Objeto diretamente relacionado com o objeto O
  • Uma variável global acessível pelo objeto O

Para não ficar muito abstrato, vamos aos exemplos:

Seja parâmetro de M: 

public class A{    
	public void FazAlgumaCoisa(B parametro){       
           parametro.FazOutraCoisa();}
}

Um objeto que M criou:

public class A{       
        public void FazAlgumaCoisa(){
           B objetoB = new B();
           B.FazOutraCoisa();}
        }

Um método do próprio objeto O

public class A{
    private void FazOutraCoisa(){
       //faz algo}        
    public void FazAlgumaCoisa(){
       FazOutraCoisa();}
}

Objeto diretamente relacionados com o objeto O

public class B{ 
        public void FazOutraCoisa(){
           //Faz algo}
}
public class A{      
            private B _objetoB;
            A(){_objetoB = new B();}
            public void FazAlgumaCoisa(){
               _objetoB.FazOutraCoisa();}
}

Um dos grandes problemas que temos na manutenção de sistemas OO é o alto acoplamento, ou seja, nossos objetos “falam” com muitos objetos, e quando isto acontece, se eu alterar um objeto no sistema, posso ter efeitos colaterais nos chamadores. A lei de Demeter como vimos, ajuda a diminuir este acoplamento. Algo do tipo

public class C{
        public void FazMaisOutraCoisa(){
          //Faz algo}
}

public class B{
        public C FazOutraCoisa(){
         return new C();}
}
public class A{
        private B _objetoB;
        A(){_objetoB = new B();}
        public void FazAlgumaCoisa(){
          _objetoB.FazOutraCoisa().FazMaisOutraCoisa();}
}

fere a lei de Demeter, pois não estou mais falando com um “amigo” e sim com o método de C que é o objeto de retorno de B, o “estrangeiro”. Agora nossa classe A tem acoplamento com B e C. Se alterar algo em C, tenho efeitos em A.  Sacaram ao que leva a lei de Demeter?

Um dos princípios de orientação a objetos que leva a concordância com a lei de Demeter, é o princípio da responsabilidade exclusiva do S.O.L.I.D. Porque digo isto? Simples, quando meu método começa a usar muitos recursos de outro objeto, em vez do próprio objeto ao qual pertence, provavelmente este método está no local errado, resumindo, não faz parte das responsabilidades do objeto que está. Outro princípio interessante de OO que ajuda a atingir a lei é o Tell don’t ask, mas este deixo para vocês lerem nas referências deste post.

Concordam com Lei, o que acham?

Referências: Law of Demeter, S.O.L.I.D, Tell don’t ask, Artigo do Giovanni Bassi sobre Tell don’t Ask

[]’s Fábio Margarito

Posted: Feb 18 2010, 01:26 by fabiomargarito | Comments (1) RSS comment feed |
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under:

Dynamic Dispatcher e Dynamic Binding

Com certeza se desconhece estes termos, já os usou sem saber. Vamos ver em C# como isto rola.

Dynamic Dispatch: A Wikipedia define como "...processo de mapear uma mensagem para uma sequência de código em tempo de execução", simplificando, é o recurso que a plataforma de desenvolvimento oferece, onde você consegue executar um método sem saber detalhes do tipo em tempo de compilação. Se houver algum erro, como nome de método incorreto, falta de parâmetros ou tipo incorreto de parâmetro, só será possível saber em tempo de execução. Linguagem dinâmicas que não são tipadas(ex. JavaScript), utilizam o recurso de dynamic dispatch o tempo todo. Quando precisamos executar algum componente COM em .Net, também utilizamos dynamic dispatch. Para exemplificar, utilizando C# 3.5 vou executar o método Soma dinamicamente.

using System;
using System.Reflection;
namespace DynamicDispatchDynamicBinding
{
class Calculo
{
public int Soma(int a, int b){
return a + b;
}
}
class Program
{
static void Main(string[] args)
{
var tipo = typeof(Calculo);
var objeto = new Calculo();
var retorno = tipo.InvokeMember("Soma",BindingFlags.InvokeMethod,null,objeto ,new object[] { 10, 20 });
Console.Write(retorno);
}
}
}
Com a nova DLR(Dynamic Language Runtime) incluída no .Net 4.0, ficou bem mais fácil
using System;
namespace DynamicDispatcherDynamicBinding40
{
class Calculo
{
public int Soma(int a, int b)
{
return a + b;
}
}
class Program
{
static void Main(string[] args)
{
var tipo = typeof(Calculo);
dynamic objeto = new Calculo();
var retorno = objeto.Soma(10, 20);
Console.Write(retorno);
}
}
}

Dynamic Binding: É a forma de determinar a partir do objeto recebido, qual a implementação do método deverá ser executada em tempo de execução. Com exemplo fica mais fácil

using System;
using System.Reflection;
namespace DynamicDispatchDynamicBinding
{
class Calculo
{
public virtual int Soma(int a, int b)
{
return a + b;
}
}
/*Cálculo incorreto propositalmente*/
class CalculoFilho1:Calculo
{
public override int Soma(int a, int b)
{
return a + a + b;
}
}
class Program
{
static void Main(string[] args)
{
/*Dynamic Binding*/
Calculo calculo = new CalculoFilho1(); 
Console.Write(calculo.Soma(10, 20));
}
}
}
Nossa variável é do tipo Calculo, entretanto, o método executado foi da subclasse que é o tipo instanciado. Entenderam?

Referências: Dynamic Dispatch, Dynamic Binding, DLR
[]'s
Fabio Margarito
Posted: Feb 08 2010, 12:39 by fabiomargarito | Comments (3) RSS comment feed |
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under:

Quer aprender TDD?

A galera do grupo Coding Dojo Floripa, postou aqui um excelente post com um apanhado de tutorias, vídeos entre outros recursos sobre TDD. Vale a pena dar uma olhada!

[]'s

Posted: Feb 05 2010, 20:10 by fabiomargarito | Comments (1) RSS comment feed |
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under:

Não confunda testes unitários com testes de sistema

Na prática, um percentual muito pequeno de desenvolvedores realiza algum tipo de teste nas aplicações, é triste, mas é a realidade. Sem testes(criados antes, ou depois da implementação de um código), torna-se impossível qualquer melhoria futura(Refactoring).

Ao observar equipes trabalhando, é perceptível que boa parte do tempo é gasto no Debug do Visual Studio(Ou ferramentas similares). A mecânica atual do trabalho de muitos desenvolvedores é a seguinte:

  • cria-se uma funcionalidade completa(Tela,Código, Banco)
  • roda-se a aplicação
  • o sistema falha(raramente roda da primeira vez sem nenhum bug)
  • inicia-se a epopéia no debugger para adivinhar onde ocorre o erro
  • corrige-se o bug
  • repete-se o ciclo até que todos os bugs foram corrigidos


Para mim é desperdício de tempo, e já justifica por si só, o tempo gasto na criação de um teste unitário. Eu Queria entender melhor, o motivo pelo qual eles trabalham da forma que relatei e questionei a  alguns desenvolvedores. Por quê vocês não fazem testes unitários? . As respostas foram bacanas:

  • "Testes unitários demoraram muito para serem criados, pois tenho que criar tela para testar o código, etc..."
  • "Você está enganado, já fazemos testes unitários, o responsável pelo teste pega a aplicação pronta e reproduz na UI os passos previstos em algum caso de testes"
  • "Testes unitários são complicados, tenho que colocar n referências no código fora a dificuldade de configurar o ambiente para os meus testes"

Na realidade, o problema não são os testes,  e sim a falta de conceitos, preparo dos profissionais e ausência de métricas que comprovem o desperdício de tempo e o real custo de um sistema(construção + manutenção).

Para não fugir do título do post e argumentar os motivos da não execução de testes unitários, vamos alinhar e entender a real diferença entre teste unitário e de sistema:

Testes unitários: São testes isolados que o desenvolvedor realiza em unidades de código isoladas, por exemplo, testar o método de uma classe. O teste unitário deve ser isolado e sem efeitos colaterais aos demais testes. Dependências externas(outros objetos, banco de dados,etc..), devem ser substituídas por mocks e stubs, pois a finalidade é testar aquele trecho de código em específico, e de presente você ainda cria aplicações menos acopladas. É ideal que os testes sejam automatizados, assim você os roda quantas vezes quiser a cada alteração de código. Se após a inclusão de uma melhoria, ou, adição de uma nova funcionalidade algum teste do conjunto falhar, é fácil identificar o bug, pois sei exatamente o que foi alterado, portanto, ganhamos produtividade. Existem n vantagem em utilizar testes, pontuei apenas algumas.

Testes de sistemas: São testes realizados na aplicação de modo integrado e pouco importa como a aplicação foi codificada. O teste é baseado nas funcionalidades solicitadas e requisitos não funcionais(usabilidade, desempenho, etc.). Existem vários tipos de testes de sistemas e estes devem ser executados conforme necessidade, tais como: Testes de usabilidade, de estresse, de carga de segurança entre outros. Para mais informações, consulte os links em saiba mais.

Saiba mais

Espero que tenha ficado clara a diferença e que as definições e material de apoio os ajudem a colocar os testes unitários no seu dia a dia, com certeza vocês não se arrependerão.


[]'s

Fabio Margarito

Posted: Feb 04 2010, 17:58 by fabiomargarito | Comments (1) RSS comment feed |
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under:
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); var pageTracker = _gat._getTracker("UA-6166990-1"); pageTracker._trackPageview();