SlideShare uma empresa Scribd logo
1 de 12
Baixar para ler offline
UNA – PÓS GRADUAÇÃO EM
ENGENHARIA DE SOFTWARES COM
  ÊNFASE EM MÉTODOS ÁGEIS.




              Cláudio Xavier
                    e
              Samuel Lopes




SAP - Stablility and Abstract Principle
       Princípio da Abstração e Estabilidade.




                  Belo Horizonte
                   17-06-2011
Introdução

Este princípio é mais apropriado para aplicações que excedem 50.000 linhas de código e exige uma equipe
de engenheiros para escrever. Este artigo descreve um conjunto de princípios e métricas que podem ser
usados para medir a qualidade de um design (projeto) orientado a objeto em termos de interdependência
entre os pacotes.

Projetos que são altamente interdependentes tendem a ser rígidos, difícil de manter e sem reusabilidade.
No entanto, a interdependência é necessária se os pacotes do projeto estão colaborativos. Logo, algumas
formas de dependência são desejáveis, e outras indesejáveis.

Os princípios e os parâmetros analisados no presente artigo tem a ver com estabilidade.

Resumindo estabilidade é o núcleo de todo projeto de software, devemos trabalhar para tornar um projeto
estável na presença de mudanças. Esse objetivo tem a ver com o princípio Aberto (para espanção) e
Fechado (para modificação) (OCP).

Nesse artigo veremos o conceito de impácto da estabilidade das relações entre os pacotes em larga escala
de um aplicativo.

Exemplo de mudança no cliente com sóftware interdependente.

Usuários e gerentes são incapazes de prever quando vai haver uma mudança. Uma simples mudança em
uma parte do pedido pode provocar falhas em outras partes que parecem ser completamente
independentes. Corrigindo esses problemas podem surgir ainda mais problemas, e o processo de
manutenção começa a se assemelhar a um cachorro correndo atrás do rabo.

É difícil reutilizar um projeto que é altamente interdependente. Por isso os desenvolvedores se assustam
com a quantidade de trabalho para separar uma parte indesejável do projeto, da parte desejável se um
projeto possui essa característica.

Muitas vezes para fazer a separação de uma parte do sistema que não será mais utilizada, o custo é maior
do que refazer o projeto do zero. Por isso é comum essa ação em algumas empresas.

Para ilustrar essa situação, vamos utilizar um programa simples que é carregado com a tarefa de copiar
caracteres digitados em um teclado e enviar para uma impressora, e que a plataforma de implementação
não dá suporte a independência dos dispositivos.




Há três módulos. O módulo "Copy" chama os outros dois. Imagine um loop dentro do módulo "Copy". O
corpo do loop que chama o módulo "Read Keybord” (leitura do teclado) para buscar um caracter do teclado,
que envia um caracter para o
módulo "Write Printer” (Escrever impressora) que imprime o caráter.
Os dois módulos de baixo nível são bem reutilizáveis. Eles podem ser usados em muitos outros programas
para ter acesso ao teclado e a impressora. Este é o mesmo tipo de reutilização que ganhamos com
bibliotecas de rotinas.

Veja um exemplo de código parecido com o módulo “Copy”:

using   System;
using   System.Collections.Generic;
using   System.Linq;
using   System.Text;
using   BR.POO.LeitorCaracteres;
using   BR.POO.ImpressoraCaracteres;
using   BR.POO.ImpressorTXT;


namespace BR.POO.Copiador
{
    class Copiador
    {
        //Copia caracteres e imprime para impressora.
        public static void CapturaCaracterParaImpressora()
        {
          char[] caracter = LeitorCaracteres.LeitorCaracteres.obterCaracteres();

              for (int i = 0; i < caracter.Length; i++)
              {
                ImpressoraCaracteres.ImpressoraCaracteres.ImprimeCaracteres(caracter[i]);
              }
          }
    }
}

Note que o módulo "Copy" é dependente do módulo "Write Printer", e portanto, não pode ser reutilizado em
um novo contexto, apesar da funcionalidade desse módulo ser muito interessante, ele não é reutilizável em
qualquer contexto que não envolva um teclado ou uma impressora.

Por exemplo, considere esse contexo: um programa que copia os caracteres digitados em um teclado para
um arquivo em disco.

Certamente poderíamos modificar o módulo "Copiar" para dar-lhe a nova funcionalidade desejada.

Poderíamos acrescentar um “if” para que possamos escolher entre o módulo "Write Printer" e o "Write Disk”,
dependendo somete de algum tipo de comando. No entanto, isso acrescenta novas interdependências, para
o sistema, e conforme o passar do tempo, cada vez mais dispositivos
podem participar do programa, então o módulo "Copy" estará repleto de declarações “if” e “else”
e será dependente de vários módulos de nível inferior. Ele se tornará rígido e frágil.

Veja o código do módulo que lê o teclado:

using   System;
using   System.Collections.Generic;
using   System.Linq;
using   System.Text;

namespace BR.POO.LeitorCaracteres
{
    public class LeitorCaracteres
    {
        public static char[] obterCaracteres()
        {
            char[] caracteres = { 'S', 'A', 'P'};
            return caracteres;
        }
    }
}
Veja o código do módulo que imprime o que foi escrito:

using   System;
using   System.Collections.Generic;
using   System.Linq;
using   System.Text;


namespace BR.POO.ImpressoraCaracteres
{
    public class ImpressoraCaracteres
    {

          public static void ImprimeCaracteres(char caracter)
          {
              string caracteres = caracter.ToString();

              System.Console.WriteLine(caracteres);
          }
    }
}

Veja um exemplo do BR.POO.Copiador modificado para imprimir para arquivo:

using   System;
using   System.Collections.Generic;
using   System.Linq;
using   System.Text;
using   BR.POO.LeitorCaracteres;
using   BR.POO.ImpressoraCaracteres;
using   BR.POO.ImpressorTXT;


namespace BR.POO.Copiador
{
    class Copiador
    {
        //Copia caracteres e imprime para impressora.
        public static void CapturaCaracterParaImpressora()
        {
            char[] caracter = LeitorCaracteres.LeitorCaracteres.obterCaracteres();

              for (int i = 0; i < caracter.Length; i++)
              {
                  ImpressoraCaracteres.ImpressoraCaracteres.ImprimeCaracteres(caracter[i]);
              }
              //Copia caracteres e imprime para arquivo.
              ImpressorTXT.ImpressorTXT.ImprimeParaArquivoTXT(caracter);
          }
    }
}
Veja o código do módulo que imprime para arquivo:

using   System;
using   System.Collections.Generic;
using   System.Linq;
using   System.Text;

namespace BR.POO.ImpressorTXT
{
    public class ImpressorTXT
    {
        public static void ImprimeParaArquivoTXT(char[] caracteres)
        {
            string texto = string.Empty;

              for (int i = 0; i < caracteres.Length; i++)
              {
                  texto = texto + caracteres[i].ToString();
              }
              texto = texto + " - Exemplo de aplicação com alta interdependêcia";

              System.IO.File.WriteAllText(@"C:ArquivoSAP.txt", texto);

          }
    }
}

Invertendo dependências com OOD

Uma forma de caracterizar o problema acima é de notar que o módulo que contém
um alto nível de acoplamento, ou seja, o módulo "Copy", é dependente de seus detalhes.

Se pudéssemos controlar os outros módulos a partir de qualquer dispositivo de entrada para qualquer
dispositivo de saída, poderíamos reutilizar livrimente o “Copy”. O OOD nos dá mecanismos para a
realização dessa inversão de dependência.

Considere o diagrama de classe simples:




Acima nós temos uma classe "Copy" que contém uma classe "Reader" e "Writer" abstract. Pode-se
facilmente imaginar um loop dentro da classe "Copy" que recebe caracteres de "Reader" e envia-los para
"Writer".
No entanto, essa classe "Copy" de não depende em tudo da "Keyboard Reader", nem da "Printer Writer".
Assim, as dependências foram invertidas. Agora, a classe "Copy" depende
somente das abstracts, e o “Read” e o “Writer”.

Agora podemos reutilizar a classe "Copy", independentemente do "Keyboard Reader" e do
"Printe Writer". Podemos inventar novos tipos de "Reader" e "Writer" que podem dar suporte à classe
"Copy". Além disso, não importa quantos tipos de "Reader e
"Writer" são criados, "Copy" não dependerá de nenhum deles.
Não haverá interdependências para deixar o programa frágil ou rígido. Esta é a essência do DIP.

O que torna a versão do programa OO de Copy robusto, sustentável e reutilizável?

É a sua falta de interdependências. Mas ele tem algumas dependências e as dependências
não interferem na qualidade desejável. Por que não? Porque é extremamente improvável que mude o
objetivo das dependências, com as classes “Reader” e “Writer” pois elas são do tipo não-volátil.

O que fazer quando existem forças que provocam a mudança?

Certamente poderíamos imaginar algumas mudanças se estendecemos um pouco o nosso pensamento.
Mas no curso dos acontecimentos normal, essas classes têm baixa volatilidade.

Desde "Copy" dependa de módulos que são do tipo não-volátil, é muito pouco provável que a “Copy” sofra
alterações. "Copy" também é um exemplo do princípio "Open/Closed". "Copy" está aberta a ser expanção,
uma vez que podem criar novas versões de "Reader"
e "Writer". No entanto, "Copy" está fechada para a modificação, já que não tem que modificá-lo para
alcançar essas extensões. Assim, podemos dizer que uma dependência boa é uma dependência de algo
com baixa volatilidade. Quanto menos volátil o objetivo da dependência, melhor a dependência. Da mesma
forma uma "Má Dependência" é uma dependência de algo que é volátil. Quanto mais volátil o objetivo da
dependência, pior é a dependência.

Estabilidade e Independência

A definição clássica da estabilidade palavra é: "Não é facilmente abalado."

Esta é a definição que iremos utilizar neste artigo. Ou seja, a estabilidade não é uma medida da
probabilidade que um módulo vai mudar, e sim é uma medida da dificuldade de um módulo em mudar.

Como se alcançar a estabilidade? Por que, por exemplo "Reader" e "Writer", são tão estáveis?

Considere novamente as forças que poderiam fazê-los mudar. Eles não dependem de nada
em tudo, então a mudança de uma dependencia não podem estender-se até eles e levá-los a mudar.

Essa característica é chamda de "Independência".

Classes Independente são classes que não dependem de qualquer outra coisa.

Outra razão que "Reader" e "Writer" são estáveis é que eles são dependencias de outras classes. Entre
"Copy", "KeyboardReader" e "KeyboardWriter".

O fato é que, podem existir alterações de "Reader" e "Writer", mas, quanto mais dependencias essas
classes tiverem, mais difícil será alteralas.
Se alterarmos "Reader" ou "writer" que teria que mudar todas as outras classes
que dependem delas. Assim, essa mudança daria muito trabalho o que nos impede de mudar
essas classes, e aumentando a sua estabilidade.
Classes responsável tendem a ser estáveis porque qualquer mudança tem grande um impacto.

As classes mais estáveis, são classes que são independentes e responsáveis. Essas classes não têm
nenhuma razão para mudar, e muitas razões para não mudar.

O Princípio dependências Estável (SDP)

As dependências entre pacotes em um projeto devem ser no sentido da estabilidade dos PACOTES.
Os PACOTES devem depender apenas de pacotes que são MAIS ESTÁVEL que ele.

Projetos não podem ser completamente estáticos. Alguma volatilidade é necessário ser mantida no projeto.

Nós conseguimos isso em conformidade com o Princípio Encerramento Comum (PCC).

Usando este princípio, criamos pacotes que estão sensíveis a certos tipos de alterações.
Estes pacotes são destinados a serem voláteis.
Nós esperamos que eles mudem. Qualquer pacote que nós esperamos ser voláteis não devem depender de
um pacote que é difícil mudar! Caso contrário, o pacote voláiíl também será difícil de mudar.

Conformando-se à SDP, podemos garantir que os módulos que são projetados para ser instáveis
(Isto é fácil de mudar), não são considerados pelos módulos que são mais estáveis (isto é mais difícil
mudar) do que eles.

Métricas de Estabilidade
Como podemos medir a estabilidade de um pacote?
   • Uma maneira é contar o número de dependências que entram e saem desse pacote. Estas
       contagens nos permitirá calcular a posição estabilidade do pacote.
   • Ca: Acoplamentos Aferentes: O número de classes de fora deste pacote, que dependem
       em classes dentro deste pacote.
   • Ce: Acoplamentos eferente: O número de classes dentro desse pacote que depende de
       classes de fora deste pacote.
   • I: Instabilidade: (Ce/(Ca + Ce)): Esta métrica tem no intervalo [0,1].

                        I = 0 (indica ser um pacote maximamente estável).
                        I = 1 (indica um pacote máximamente instável).

As métricas de Ca e Ce são calculados pela contagem do número de classes fora do
pacote em questão que têm dependências com as classes dentro do pacote em questão.

O PSD diz que a métrica de um pacote que deve ser maior do que as métricas I do
pacotes que ele depende. ou seja, eu métricas devem diminuir na direção de dependência.
Nem todos os pacotes devem ser estáveis. Se todos os pacotes em um sistema foram maximamente
estável, o sistema seria imutável.
Esta não é uma situação desejável. Na verdade, queremos projetar a nossa estrutura de pacotes, de modo
que alguns pacotes são instáveis, e alguns são estáveis. A figura a seguir mostra o ideal
configuração de um sistema com três pacotes.




O Princípio da Abstração Estável (SAP)

Pacotes que são maximamente ESTÁVEIS devem ser maximamente ABSTRATOS.
PACOTES instáveis DEVEM SER CONCRETOS.
A abstração de um pacote deve ser PROPORCIONAL a sua estabilidade.

Este princípio estabelece uma relação entre a estabilidade e a abstração. Ela diz que um
pacote estável deve também ser abstrato de modo que sua estabilidade não impeça que ele seja
modificado. Por outro lado, ele diz que um pacote instável deve ser de concreto, uma vez que a sua
instabilidade permita que o código de concreto dentro dele seja facilmente alterado.

Veja um exemplo do BR.POO.Copiador aplicando o princício SAP. Note que o copiador agora pode
receber qualquer tipo de leitor de caracteres e impressoras, sem sofrer nenhuma modificacão:

using    System;
using    System.Collections.Generic;
using    System.Linq;
using    System.Text;
using    BR.POO.Ler;
using    BR.POO.Imprimir;

namespace BR.POO.Copiador.SAP
{
    class Copiador
    {
        /*Exemplo de aplicação estável e abstrata.
        (Aberta a espanção e fechada para modificação*/

           public static void LerImprimir()
           {
               char[] leituraEntrada = Ler.Ler.Leitura();
               Imprimir.Imprimir.Imprime(leituraEntrada);

           }
     }
}
Veja o código do módulo ler:

using   System;
using   System.Collections.Generic;
using   System.Linq;
using   System.Text;
using   BR.POO.LeitorCaracteres;

namespace BR.POO.Ler
{
    public class Ler
    {
        public static char[] Leitura()
        {
            char[] leitura = LeitorCaracteres.LeitorCaracteres.obterCaracteres();
            return leitura;
        }
    }
}

Veja o código do módulo Imprimir:

using   System;
using   System.Collections.Generic;
using   System.Linq;
using   System.Text;
using   BR.POO.ImpressorTXT;
using   BR.POO.ImpressoraCaracteres;

namespace BR.POO.Imprimir
{
    public class Imprimir
    {
        public static void Imprime(char[] leitura)
        {
            ImpressorTXT.ImpressorTXT.ImprimeParaArquivoTXT(leitura);

              for (int i = 0; i < leitura.Length; i++)
              {
                  ImpressoraCaracteres.ImpressoraCaracteres.ImprimeCaracteres(leitura[i]);
              }

          }
    }
}

Código do módulo que lê o teclado:

using   System;
using   System.Collections.Generic;
using   System.Linq;
using   System.Text;

namespace BR.POO.LeitorCaracteres
{
    public class LeitorCaracteres
    {
        public static char[] obterCaracteres()
        {
            char[] caracteres = { 'S', 'A', 'P'};
            return caracteres;
        }
    }
}
Código do módulo que imprime o que foi escrito:

using   System;
using   System.Collections.Generic;
using   System.Linq;
using   System.Text;


namespace BR.POO.ImpressoraCaracteres
{
    public class ImpressoraCaracteres
    {

          public static void ImprimeCaracteres(char caracter)
          {
              string caracteres = caracter.ToString();

              System.Console.WriteLine(caracteres);
          }
    }
}

Código do módulo que imprime para arquivo:

using   System;
using   System.Collections.Generic;
using   System.Linq;
using   System.Text;

namespace BR.POO.ImpressorTXT
{
    public class ImpressorTXT
    {
        public static void ImprimeParaArquivoTXT(char[] caracteres)
        {
            string texto = string.Empty;

              for (int i = 0; i < caracteres.Length; i++)
              {
                  texto = texto + caracteres[i].ToString();
              }
              texto = texto + " - Exemplo de aplicação com alta interdependêcia";

              System.IO.File.WriteAllText(@"C:ArquivoSAP.txt", texto);

          }
    }
}
Como mensurar?

       (NC): O número de classes do pacote
       (Na): O número de classes abstratas no
       pacote
       (Abstração): A = Na / Nc
       Um A tem o intervalo [0,1]
       A = 0 (implica que o pacote não tem classes abstratas)
       A = 1 (implica que o pacote possui somente classes abstratas)




Distância da Sequência Principal


       (Distância D): D = | A + I - 1 | / √ 2
       O pacote deve estar ligado ou próximo da seqüência principal

       Intervalos D’ a partir de [0, 0,707 ~]
       (Distância normalizada D ‘): D’ = | I + A - 1 |
       Intervalos D 'a partir de [0, 1]
       D = 0 indica que o pacote está diretamente ligado
       a seqüência principal
       D = 1 indica que o pacote está tão longe
       longe possível a partir da seqüência principal

Gráfico de Métrica de Variância de Todas as Métricas D
SAP- Plotando a métrica D’ de cada pacote ao longo do tempo

Mais conteúdo relacionado

Mais procurados

Introdução à Programação de Computadores com Python
Introdução à Programação de Computadores com PythonIntrodução à Programação de Computadores com Python
Introdução à Programação de Computadores com PythonSidney Roberto
 
Apostila - Linguagem de Programação I
Apostila - Linguagem de Programação IApostila - Linguagem de Programação I
Apostila - Linguagem de Programação ISidney Roberto
 
Java memory model primary ref. - faq
Java memory model   primary ref. - faqJava memory model   primary ref. - faq
Java memory model primary ref. - faqPedro De Almeida
 
Apostila php
Apostila phpApostila php
Apostila phpfelgamer
 
C# 6.0 - Novos Recursos (Agosto/2015)
C# 6.0 - Novos Recursos (Agosto/2015)C# 6.0 - Novos Recursos (Agosto/2015)
C# 6.0 - Novos Recursos (Agosto/2015)Renato Groff
 
CURSO DE PHP PARA INICIANTES - AULA 1
CURSO DE PHP PARA INICIANTES - AULA 1CURSO DE PHP PARA INICIANTES - AULA 1
CURSO DE PHP PARA INICIANTES - AULA 1Norivan Oliveira
 
Slide curso metasploit
Slide curso metasploitSlide curso metasploit
Slide curso metasploitRoberto Soares
 
Curso de PHP Básico ao Avançado
Curso de PHP Básico ao AvançadoCurso de PHP Básico ao Avançado
Curso de PHP Básico ao AvançadoLuiz Junior
 
Apresentação php
Apresentação phpApresentação php
Apresentação phpwilliameier
 
Minicurso PHP básico
Minicurso PHP básicoMinicurso PHP básico
Minicurso PHP básicoCezar Souza
 
Aula 01 introdução ao php
Aula 01   introdução ao phpAula 01   introdução ao php
Aula 01 introdução ao phpAdriano Castro
 
Apostila linguagem c
Apostila linguagem cApostila linguagem c
Apostila linguagem corvel
 
Aula 02 - Introdução ao PHP
Aula 02 - Introdução ao PHPAula 02 - Introdução ao PHP
Aula 02 - Introdução ao PHPDaniel Brandão
 

Mais procurados (17)

Introdução à Programação de Computadores com Python
Introdução à Programação de Computadores com PythonIntrodução à Programação de Computadores com Python
Introdução à Programação de Computadores com Python
 
Apostila - Linguagem de Programação I
Apostila - Linguagem de Programação IApostila - Linguagem de Programação I
Apostila - Linguagem de Programação I
 
Java memory model primary ref. - faq
Java memory model   primary ref. - faqJava memory model   primary ref. - faq
Java memory model primary ref. - faq
 
Pesl latex
Pesl latexPesl latex
Pesl latex
 
Shell scripts
Shell scriptsShell scripts
Shell scripts
 
Introdução a php
Introdução a phpIntrodução a php
Introdução a php
 
Apostila php
Apostila phpApostila php
Apostila php
 
C# 6.0 - Novos Recursos (Agosto/2015)
C# 6.0 - Novos Recursos (Agosto/2015)C# 6.0 - Novos Recursos (Agosto/2015)
C# 6.0 - Novos Recursos (Agosto/2015)
 
OpenMP Day1
OpenMP Day1OpenMP Day1
OpenMP Day1
 
CURSO DE PHP PARA INICIANTES - AULA 1
CURSO DE PHP PARA INICIANTES - AULA 1CURSO DE PHP PARA INICIANTES - AULA 1
CURSO DE PHP PARA INICIANTES - AULA 1
 
Slide curso metasploit
Slide curso metasploitSlide curso metasploit
Slide curso metasploit
 
Curso de PHP Básico ao Avançado
Curso de PHP Básico ao AvançadoCurso de PHP Básico ao Avançado
Curso de PHP Básico ao Avançado
 
Apresentação php
Apresentação phpApresentação php
Apresentação php
 
Minicurso PHP básico
Minicurso PHP básicoMinicurso PHP básico
Minicurso PHP básico
 
Aula 01 introdução ao php
Aula 01   introdução ao phpAula 01   introdução ao php
Aula 01 introdução ao php
 
Apostila linguagem c
Apostila linguagem cApostila linguagem c
Apostila linguagem c
 
Aula 02 - Introdução ao PHP
Aula 02 - Introdução ao PHPAula 02 - Introdução ao PHP
Aula 02 - Introdução ao PHP
 

Semelhante a PÓS-GRADUAÇÃO EM ENGENHARIA DE SOFTWARES COM ÊNFASE EM MÉTODOS ÁGEIS

Spring & Struts
Spring & StrutsSpring & Struts
Spring & Strutseduan
 
Módulo 5 Arquitetura de Computadores
Módulo 5 Arquitetura de ComputadoresMódulo 5 Arquitetura de Computadores
Módulo 5 Arquitetura de ComputadoresLuis Ferreira
 
Lista exercicios algoritmos
Lista exercicios algoritmosLista exercicios algoritmos
Lista exercicios algoritmosslashmelhor
 
Aula 8 - Modularização e Funções.pptx
Aula 8 - Modularização e Funções.pptxAula 8 - Modularização e Funções.pptx
Aula 8 - Modularização e Funções.pptxItamarGoncalves2
 
Entendendo Frameworks web com Python
Entendendo Frameworks web com PythonEntendendo Frameworks web com Python
Entendendo Frameworks web com PythonLuiz Aldabalde
 
Multithreaded tecnologia
Multithreaded tecnologia Multithreaded tecnologia
Multithreaded tecnologia J Chaves Silva
 
Introdução à Linguagem de Programação C
Introdução à Linguagem de Programação CIntrodução à Linguagem de Programação C
Introdução à Linguagem de Programação CJose Augusto Cintra
 
Apresentação final
Apresentação finalApresentação final
Apresentação finalvalmon
 
Algoritmia para o site do 10gi marcelo e ricardo
Algoritmia para o site do 10gi marcelo e ricardoAlgoritmia para o site do 10gi marcelo e ricardo
Algoritmia para o site do 10gi marcelo e ricardozedaesquina98
 
Construção de Frameworks com Annotation e Reflection API em Java
Construção de Frameworks com Annotation e Reflection API em JavaConstrução de Frameworks com Annotation e Reflection API em Java
Construção de Frameworks com Annotation e Reflection API em JavaFernando Camargo
 
Tópicos - Computacao Paralela Programação (Visão geral)
Tópicos - Computacao Paralela Programação (Visão geral)Tópicos - Computacao Paralela Programação (Visão geral)
Tópicos - Computacao Paralela Programação (Visão geral)Luiz Arthur
 
Emacs - Arquitetura E Design Com Foco No Desenv De Plugins
Emacs - Arquitetura E Design Com Foco No Desenv De PluginsEmacs - Arquitetura E Design Com Foco No Desenv De Plugins
Emacs - Arquitetura E Design Com Foco No Desenv De PluginsJosé Martins da Nobrega Filho
 
Linguagem de programação
Linguagem de programaçãoLinguagem de programação
Linguagem de programaçãoSandro Lopes
 
Palestra - Symfony Framework MVC PHP 5
Palestra - Symfony Framework MVC PHP 5Palestra - Symfony Framework MVC PHP 5
Palestra - Symfony Framework MVC PHP 5Lucas Augusto Carvalho
 
Apostila básica de PHP
Apostila básica de PHPApostila básica de PHP
Apostila básica de PHPKratos879
 

Semelhante a PÓS-GRADUAÇÃO EM ENGENHARIA DE SOFTWARES COM ÊNFASE EM MÉTODOS ÁGEIS (20)

Spring & Struts
Spring & StrutsSpring & Struts
Spring & Struts
 
Módulo 5 Arquitetura de Computadores
Módulo 5 Arquitetura de ComputadoresMódulo 5 Arquitetura de Computadores
Módulo 5 Arquitetura de Computadores
 
Lista exercicios algoritmos
Lista exercicios algoritmosLista exercicios algoritmos
Lista exercicios algoritmos
 
Aula 8 - Modularização e Funções.pptx
Aula 8 - Modularização e Funções.pptxAula 8 - Modularização e Funções.pptx
Aula 8 - Modularização e Funções.pptx
 
Escalando apps com React e Type Script e SOLID
Escalando apps com React e Type Script e SOLIDEscalando apps com React e Type Script e SOLID
Escalando apps com React e Type Script e SOLID
 
poster
posterposter
poster
 
Entendendo Frameworks web com Python
Entendendo Frameworks web com PythonEntendendo Frameworks web com Python
Entendendo Frameworks web com Python
 
Sap – stablility and abstract principle
Sap – stablility and abstract principleSap – stablility and abstract principle
Sap – stablility and abstract principle
 
Processador de texto
Processador de textoProcessador de texto
Processador de texto
 
Multithreaded tecnologia
Multithreaded tecnologia Multithreaded tecnologia
Multithreaded tecnologia
 
Introdução à Linguagem de Programação C
Introdução à Linguagem de Programação CIntrodução à Linguagem de Programação C
Introdução à Linguagem de Programação C
 
Apresentação final
Apresentação finalApresentação final
Apresentação final
 
Linguagem c
Linguagem cLinguagem c
Linguagem c
 
Algoritmia para o site do 10gi marcelo e ricardo
Algoritmia para o site do 10gi marcelo e ricardoAlgoritmia para o site do 10gi marcelo e ricardo
Algoritmia para o site do 10gi marcelo e ricardo
 
Construção de Frameworks com Annotation e Reflection API em Java
Construção de Frameworks com Annotation e Reflection API em JavaConstrução de Frameworks com Annotation e Reflection API em Java
Construção de Frameworks com Annotation e Reflection API em Java
 
Tópicos - Computacao Paralela Programação (Visão geral)
Tópicos - Computacao Paralela Programação (Visão geral)Tópicos - Computacao Paralela Programação (Visão geral)
Tópicos - Computacao Paralela Programação (Visão geral)
 
Emacs - Arquitetura E Design Com Foco No Desenv De Plugins
Emacs - Arquitetura E Design Com Foco No Desenv De PluginsEmacs - Arquitetura E Design Com Foco No Desenv De Plugins
Emacs - Arquitetura E Design Com Foco No Desenv De Plugins
 
Linguagem de programação
Linguagem de programaçãoLinguagem de programação
Linguagem de programação
 
Palestra - Symfony Framework MVC PHP 5
Palestra - Symfony Framework MVC PHP 5Palestra - Symfony Framework MVC PHP 5
Palestra - Symfony Framework MVC PHP 5
 
Apostila básica de PHP
Apostila básica de PHPApostila básica de PHP
Apostila básica de PHP
 

Mais de Engenharia de Software Ágil

OCP - The Open Close Principle - Princípio aberto/fechado
OCP - The Open Close Principle - Princípio aberto/fechadoOCP - The Open Close Principle - Princípio aberto/fechado
OCP - The Open Close Principle - Princípio aberto/fechadoEngenharia de Software Ágil
 

Mais de Engenharia de Software Ágil (20)

Common closure principle
Common closure principleCommon closure principle
Common closure principle
 
Common closure principle
Common closure principle Common closure principle
Common closure principle
 
Acyclic dependencies principle
Acyclic dependencies principleAcyclic dependencies principle
Acyclic dependencies principle
 
Acyclic dependencies principle (adp)
Acyclic dependencies principle  (adp)Acyclic dependencies principle  (adp)
Acyclic dependencies principle (adp)
 
Reuse release equivalence principle
Reuse release equivalence principleReuse release equivalence principle
Reuse release equivalence principle
 
Rep reuse release equivalence principle
Rep reuse release equivalence principleRep reuse release equivalence principle
Rep reuse release equivalence principle
 
OCP - The Open Close Principle - Princípio aberto/fechado
OCP - The Open Close Principle - Princípio aberto/fechadoOCP - The Open Close Principle - Princípio aberto/fechado
OCP - The Open Close Principle - Princípio aberto/fechado
 
Sdp – stable dependencies principles
Sdp – stable dependencies principlesSdp – stable dependencies principles
Sdp – stable dependencies principles
 
principio de reutilização comum
principio de reutilização comumprincipio de reutilização comum
principio de reutilização comum
 
Princípio law of demeter
Princípio law of demeterPrincípio law of demeter
Princípio law of demeter
 
Lod law of demeter
Lod law of demeterLod law of demeter
Lod law of demeter
 
Dip the dependency inversion principle
Dip   the dependency inversion principleDip   the dependency inversion principle
Dip the dependency inversion principle
 
Dip the dependency inversion principle
Dip   the dependency inversion principleDip   the dependency inversion principle
Dip the dependency inversion principle
 
Dip the dependency inversion principle
Dip   the dependency inversion principleDip   the dependency inversion principle
Dip the dependency inversion principle
 
(ISP) - Interface Segregation Principle
(ISP)  - Interface Segregation Principle(ISP)  - Interface Segregation Principle
(ISP) - Interface Segregation Principle
 
LSP – The Liskov Substitution Principle
LSP – The Liskov Substitution PrincipleLSP – The Liskov Substitution Principle
LSP – The Liskov Substitution Principle
 
SRP - Single Responsability Principle
SRP - Single Responsability PrincipleSRP - Single Responsability Principle
SRP - Single Responsability Principle
 
Princípio Law Of Demeter (LOD)
Princípio Law Of Demeter (LOD)Princípio Law Of Demeter (LOD)
Princípio Law Of Demeter (LOD)
 
TDD - Test Driven Development
TDD - Test Driven DevelopmentTDD - Test Driven Development
TDD - Test Driven Development
 
FDD
FDDFDD
FDD
 

PÓS-GRADUAÇÃO EM ENGENHARIA DE SOFTWARES COM ÊNFASE EM MÉTODOS ÁGEIS

  • 1. UNA – PÓS GRADUAÇÃO EM ENGENHARIA DE SOFTWARES COM ÊNFASE EM MÉTODOS ÁGEIS. Cláudio Xavier e Samuel Lopes SAP - Stablility and Abstract Principle Princípio da Abstração e Estabilidade. Belo Horizonte 17-06-2011
  • 2. Introdução Este princípio é mais apropriado para aplicações que excedem 50.000 linhas de código e exige uma equipe de engenheiros para escrever. Este artigo descreve um conjunto de princípios e métricas que podem ser usados para medir a qualidade de um design (projeto) orientado a objeto em termos de interdependência entre os pacotes. Projetos que são altamente interdependentes tendem a ser rígidos, difícil de manter e sem reusabilidade. No entanto, a interdependência é necessária se os pacotes do projeto estão colaborativos. Logo, algumas formas de dependência são desejáveis, e outras indesejáveis. Os princípios e os parâmetros analisados no presente artigo tem a ver com estabilidade. Resumindo estabilidade é o núcleo de todo projeto de software, devemos trabalhar para tornar um projeto estável na presença de mudanças. Esse objetivo tem a ver com o princípio Aberto (para espanção) e Fechado (para modificação) (OCP). Nesse artigo veremos o conceito de impácto da estabilidade das relações entre os pacotes em larga escala de um aplicativo. Exemplo de mudança no cliente com sóftware interdependente. Usuários e gerentes são incapazes de prever quando vai haver uma mudança. Uma simples mudança em uma parte do pedido pode provocar falhas em outras partes que parecem ser completamente independentes. Corrigindo esses problemas podem surgir ainda mais problemas, e o processo de manutenção começa a se assemelhar a um cachorro correndo atrás do rabo. É difícil reutilizar um projeto que é altamente interdependente. Por isso os desenvolvedores se assustam com a quantidade de trabalho para separar uma parte indesejável do projeto, da parte desejável se um projeto possui essa característica. Muitas vezes para fazer a separação de uma parte do sistema que não será mais utilizada, o custo é maior do que refazer o projeto do zero. Por isso é comum essa ação em algumas empresas. Para ilustrar essa situação, vamos utilizar um programa simples que é carregado com a tarefa de copiar caracteres digitados em um teclado e enviar para uma impressora, e que a plataforma de implementação não dá suporte a independência dos dispositivos. Há três módulos. O módulo "Copy" chama os outros dois. Imagine um loop dentro do módulo "Copy". O corpo do loop que chama o módulo "Read Keybord” (leitura do teclado) para buscar um caracter do teclado, que envia um caracter para o módulo "Write Printer” (Escrever impressora) que imprime o caráter.
  • 3. Os dois módulos de baixo nível são bem reutilizáveis. Eles podem ser usados em muitos outros programas para ter acesso ao teclado e a impressora. Este é o mesmo tipo de reutilização que ganhamos com bibliotecas de rotinas. Veja um exemplo de código parecido com o módulo “Copy”: using System; using System.Collections.Generic; using System.Linq; using System.Text; using BR.POO.LeitorCaracteres; using BR.POO.ImpressoraCaracteres; using BR.POO.ImpressorTXT; namespace BR.POO.Copiador { class Copiador { //Copia caracteres e imprime para impressora. public static void CapturaCaracterParaImpressora() { char[] caracter = LeitorCaracteres.LeitorCaracteres.obterCaracteres(); for (int i = 0; i < caracter.Length; i++) { ImpressoraCaracteres.ImpressoraCaracteres.ImprimeCaracteres(caracter[i]); } } } } Note que o módulo "Copy" é dependente do módulo "Write Printer", e portanto, não pode ser reutilizado em um novo contexto, apesar da funcionalidade desse módulo ser muito interessante, ele não é reutilizável em qualquer contexto que não envolva um teclado ou uma impressora. Por exemplo, considere esse contexo: um programa que copia os caracteres digitados em um teclado para um arquivo em disco. Certamente poderíamos modificar o módulo "Copiar" para dar-lhe a nova funcionalidade desejada. Poderíamos acrescentar um “if” para que possamos escolher entre o módulo "Write Printer" e o "Write Disk”, dependendo somete de algum tipo de comando. No entanto, isso acrescenta novas interdependências, para o sistema, e conforme o passar do tempo, cada vez mais dispositivos podem participar do programa, então o módulo "Copy" estará repleto de declarações “if” e “else” e será dependente de vários módulos de nível inferior. Ele se tornará rígido e frágil. Veja o código do módulo que lê o teclado: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BR.POO.LeitorCaracteres { public class LeitorCaracteres { public static char[] obterCaracteres() { char[] caracteres = { 'S', 'A', 'P'}; return caracteres; } } }
  • 4. Veja o código do módulo que imprime o que foi escrito: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BR.POO.ImpressoraCaracteres { public class ImpressoraCaracteres { public static void ImprimeCaracteres(char caracter) { string caracteres = caracter.ToString(); System.Console.WriteLine(caracteres); } } } Veja um exemplo do BR.POO.Copiador modificado para imprimir para arquivo: using System; using System.Collections.Generic; using System.Linq; using System.Text; using BR.POO.LeitorCaracteres; using BR.POO.ImpressoraCaracteres; using BR.POO.ImpressorTXT; namespace BR.POO.Copiador { class Copiador { //Copia caracteres e imprime para impressora. public static void CapturaCaracterParaImpressora() { char[] caracter = LeitorCaracteres.LeitorCaracteres.obterCaracteres(); for (int i = 0; i < caracter.Length; i++) { ImpressoraCaracteres.ImpressoraCaracteres.ImprimeCaracteres(caracter[i]); } //Copia caracteres e imprime para arquivo. ImpressorTXT.ImpressorTXT.ImprimeParaArquivoTXT(caracter); } } }
  • 5. Veja o código do módulo que imprime para arquivo: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BR.POO.ImpressorTXT { public class ImpressorTXT { public static void ImprimeParaArquivoTXT(char[] caracteres) { string texto = string.Empty; for (int i = 0; i < caracteres.Length; i++) { texto = texto + caracteres[i].ToString(); } texto = texto + " - Exemplo de aplicação com alta interdependêcia"; System.IO.File.WriteAllText(@"C:ArquivoSAP.txt", texto); } } } Invertendo dependências com OOD Uma forma de caracterizar o problema acima é de notar que o módulo que contém um alto nível de acoplamento, ou seja, o módulo "Copy", é dependente de seus detalhes. Se pudéssemos controlar os outros módulos a partir de qualquer dispositivo de entrada para qualquer dispositivo de saída, poderíamos reutilizar livrimente o “Copy”. O OOD nos dá mecanismos para a realização dessa inversão de dependência. Considere o diagrama de classe simples: Acima nós temos uma classe "Copy" que contém uma classe "Reader" e "Writer" abstract. Pode-se facilmente imaginar um loop dentro da classe "Copy" que recebe caracteres de "Reader" e envia-los para "Writer".
  • 6. No entanto, essa classe "Copy" de não depende em tudo da "Keyboard Reader", nem da "Printer Writer". Assim, as dependências foram invertidas. Agora, a classe "Copy" depende somente das abstracts, e o “Read” e o “Writer”. Agora podemos reutilizar a classe "Copy", independentemente do "Keyboard Reader" e do "Printe Writer". Podemos inventar novos tipos de "Reader" e "Writer" que podem dar suporte à classe "Copy". Além disso, não importa quantos tipos de "Reader e "Writer" são criados, "Copy" não dependerá de nenhum deles. Não haverá interdependências para deixar o programa frágil ou rígido. Esta é a essência do DIP. O que torna a versão do programa OO de Copy robusto, sustentável e reutilizável? É a sua falta de interdependências. Mas ele tem algumas dependências e as dependências não interferem na qualidade desejável. Por que não? Porque é extremamente improvável que mude o objetivo das dependências, com as classes “Reader” e “Writer” pois elas são do tipo não-volátil. O que fazer quando existem forças que provocam a mudança? Certamente poderíamos imaginar algumas mudanças se estendecemos um pouco o nosso pensamento. Mas no curso dos acontecimentos normal, essas classes têm baixa volatilidade. Desde "Copy" dependa de módulos que são do tipo não-volátil, é muito pouco provável que a “Copy” sofra alterações. "Copy" também é um exemplo do princípio "Open/Closed". "Copy" está aberta a ser expanção, uma vez que podem criar novas versões de "Reader" e "Writer". No entanto, "Copy" está fechada para a modificação, já que não tem que modificá-lo para alcançar essas extensões. Assim, podemos dizer que uma dependência boa é uma dependência de algo com baixa volatilidade. Quanto menos volátil o objetivo da dependência, melhor a dependência. Da mesma forma uma "Má Dependência" é uma dependência de algo que é volátil. Quanto mais volátil o objetivo da dependência, pior é a dependência. Estabilidade e Independência A definição clássica da estabilidade palavra é: "Não é facilmente abalado." Esta é a definição que iremos utilizar neste artigo. Ou seja, a estabilidade não é uma medida da probabilidade que um módulo vai mudar, e sim é uma medida da dificuldade de um módulo em mudar. Como se alcançar a estabilidade? Por que, por exemplo "Reader" e "Writer", são tão estáveis? Considere novamente as forças que poderiam fazê-los mudar. Eles não dependem de nada em tudo, então a mudança de uma dependencia não podem estender-se até eles e levá-los a mudar. Essa característica é chamda de "Independência". Classes Independente são classes que não dependem de qualquer outra coisa. Outra razão que "Reader" e "Writer" são estáveis é que eles são dependencias de outras classes. Entre "Copy", "KeyboardReader" e "KeyboardWriter". O fato é que, podem existir alterações de "Reader" e "Writer", mas, quanto mais dependencias essas classes tiverem, mais difícil será alteralas. Se alterarmos "Reader" ou "writer" que teria que mudar todas as outras classes que dependem delas. Assim, essa mudança daria muito trabalho o que nos impede de mudar essas classes, e aumentando a sua estabilidade.
  • 7. Classes responsável tendem a ser estáveis porque qualquer mudança tem grande um impacto. As classes mais estáveis, são classes que são independentes e responsáveis. Essas classes não têm nenhuma razão para mudar, e muitas razões para não mudar. O Princípio dependências Estável (SDP) As dependências entre pacotes em um projeto devem ser no sentido da estabilidade dos PACOTES. Os PACOTES devem depender apenas de pacotes que são MAIS ESTÁVEL que ele. Projetos não podem ser completamente estáticos. Alguma volatilidade é necessário ser mantida no projeto. Nós conseguimos isso em conformidade com o Princípio Encerramento Comum (PCC). Usando este princípio, criamos pacotes que estão sensíveis a certos tipos de alterações. Estes pacotes são destinados a serem voláteis. Nós esperamos que eles mudem. Qualquer pacote que nós esperamos ser voláteis não devem depender de um pacote que é difícil mudar! Caso contrário, o pacote voláiíl também será difícil de mudar. Conformando-se à SDP, podemos garantir que os módulos que são projetados para ser instáveis (Isto é fácil de mudar), não são considerados pelos módulos que são mais estáveis (isto é mais difícil mudar) do que eles. Métricas de Estabilidade Como podemos medir a estabilidade de um pacote? • Uma maneira é contar o número de dependências que entram e saem desse pacote. Estas contagens nos permitirá calcular a posição estabilidade do pacote. • Ca: Acoplamentos Aferentes: O número de classes de fora deste pacote, que dependem em classes dentro deste pacote. • Ce: Acoplamentos eferente: O número de classes dentro desse pacote que depende de classes de fora deste pacote. • I: Instabilidade: (Ce/(Ca + Ce)): Esta métrica tem no intervalo [0,1]. I = 0 (indica ser um pacote maximamente estável). I = 1 (indica um pacote máximamente instável). As métricas de Ca e Ce são calculados pela contagem do número de classes fora do pacote em questão que têm dependências com as classes dentro do pacote em questão. O PSD diz que a métrica de um pacote que deve ser maior do que as métricas I do pacotes que ele depende. ou seja, eu métricas devem diminuir na direção de dependência. Nem todos os pacotes devem ser estáveis. Se todos os pacotes em um sistema foram maximamente estável, o sistema seria imutável.
  • 8. Esta não é uma situação desejável. Na verdade, queremos projetar a nossa estrutura de pacotes, de modo que alguns pacotes são instáveis, e alguns são estáveis. A figura a seguir mostra o ideal configuração de um sistema com três pacotes. O Princípio da Abstração Estável (SAP) Pacotes que são maximamente ESTÁVEIS devem ser maximamente ABSTRATOS. PACOTES instáveis DEVEM SER CONCRETOS. A abstração de um pacote deve ser PROPORCIONAL a sua estabilidade. Este princípio estabelece uma relação entre a estabilidade e a abstração. Ela diz que um pacote estável deve também ser abstrato de modo que sua estabilidade não impeça que ele seja modificado. Por outro lado, ele diz que um pacote instável deve ser de concreto, uma vez que a sua instabilidade permita que o código de concreto dentro dele seja facilmente alterado. Veja um exemplo do BR.POO.Copiador aplicando o princício SAP. Note que o copiador agora pode receber qualquer tipo de leitor de caracteres e impressoras, sem sofrer nenhuma modificacão: using System; using System.Collections.Generic; using System.Linq; using System.Text; using BR.POO.Ler; using BR.POO.Imprimir; namespace BR.POO.Copiador.SAP { class Copiador { /*Exemplo de aplicação estável e abstrata. (Aberta a espanção e fechada para modificação*/ public static void LerImprimir() { char[] leituraEntrada = Ler.Ler.Leitura(); Imprimir.Imprimir.Imprime(leituraEntrada); } } }
  • 9. Veja o código do módulo ler: using System; using System.Collections.Generic; using System.Linq; using System.Text; using BR.POO.LeitorCaracteres; namespace BR.POO.Ler { public class Ler { public static char[] Leitura() { char[] leitura = LeitorCaracteres.LeitorCaracteres.obterCaracteres(); return leitura; } } } Veja o código do módulo Imprimir: using System; using System.Collections.Generic; using System.Linq; using System.Text; using BR.POO.ImpressorTXT; using BR.POO.ImpressoraCaracteres; namespace BR.POO.Imprimir { public class Imprimir { public static void Imprime(char[] leitura) { ImpressorTXT.ImpressorTXT.ImprimeParaArquivoTXT(leitura); for (int i = 0; i < leitura.Length; i++) { ImpressoraCaracteres.ImpressoraCaracteres.ImprimeCaracteres(leitura[i]); } } } } Código do módulo que lê o teclado: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BR.POO.LeitorCaracteres { public class LeitorCaracteres { public static char[] obterCaracteres() { char[] caracteres = { 'S', 'A', 'P'}; return caracteres; } } }
  • 10. Código do módulo que imprime o que foi escrito: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BR.POO.ImpressoraCaracteres { public class ImpressoraCaracteres { public static void ImprimeCaracteres(char caracter) { string caracteres = caracter.ToString(); System.Console.WriteLine(caracteres); } } } Código do módulo que imprime para arquivo: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BR.POO.ImpressorTXT { public class ImpressorTXT { public static void ImprimeParaArquivoTXT(char[] caracteres) { string texto = string.Empty; for (int i = 0; i < caracteres.Length; i++) { texto = texto + caracteres[i].ToString(); } texto = texto + " - Exemplo de aplicação com alta interdependêcia"; System.IO.File.WriteAllText(@"C:ArquivoSAP.txt", texto); } } }
  • 11. Como mensurar? (NC): O número de classes do pacote (Na): O número de classes abstratas no pacote (Abstração): A = Na / Nc Um A tem o intervalo [0,1] A = 0 (implica que o pacote não tem classes abstratas) A = 1 (implica que o pacote possui somente classes abstratas) Distância da Sequência Principal (Distância D): D = | A + I - 1 | / √ 2 O pacote deve estar ligado ou próximo da seqüência principal Intervalos D’ a partir de [0, 0,707 ~] (Distância normalizada D ‘): D’ = | I + A - 1 | Intervalos D 'a partir de [0, 1] D = 0 indica que o pacote está diretamente ligado a seqüência principal D = 1 indica que o pacote está tão longe longe possível a partir da seqüência principal Gráfico de Métrica de Variância de Todas as Métricas D
  • 12. SAP- Plotando a métrica D’ de cada pacote ao longo do tempo