Mostrando postagens com marcador desenvolvimento. Mostrar todas as postagens
Mostrando postagens com marcador desenvolvimento. Mostrar todas as postagens

Padrões e Linguagens de Padrões

Introdução

Devido a ineficiência no processo de desenvolvimento de software, a idéia inicialmente apresentada pelo arquiteto Christopher Alexander, na década de 70, ganhou força dentre os os projetistas. Christopher notou temas recorrentes na arquitetura e o agrupou em descrições e instruções chamadas Padrões.

Padrões

Pode-se entender como Padrão soluções para problemas específicos que ocorrem de forma recorrente em um determinado contexto que foram acumulados por projetistas no desenvolvimento de software. Um Padrão é uma regra que pode ser divida em:

  • Contexto: descreve a situação de uma problema no desenvolvimento.

  • Problema: fato recorrente que atua sobre um contexto.

  • Solução: descreve uma configuração ou estrutura de componentes e suas interconexões, obedecendo as forças(requisitos, restrições e propriedades) presentes no problema.

  • Forças: são requisitos, restrições e propriedades associadas ao problema. De uma maneira geral, segundo Alexander, a força consiste em requisitos que descrevem o problema proposto a qual a solução deve atender, as restrições devem ser aplicadas às soluções e propriedades desejáveis que a solução deve alcançar.

Atualmente, os padrões tem sido amplamente utilizados em todo o processo de desenvolvimento de software, desde a análise até a implementação do sistema

Vantagens

Existem várias vantagens na utilização de Padrões no processo de desenvolvimento de software, tais como:

  • Descreve abstração de software.

  • Formação de um vocabulário comum para comunicações entre projetistas em todas as fases de um projeto.

  • Reduz o término de aprendizado de uma tecnologia, visto que, quando um projetista aprende uma tecnologia pode utilizar-se dela como facilitar para aprender uma nova tecnologia.

  • Possibilita vasta reutilização.

Classificação de Padrões

Padrões de software podem ser classificados sobre domínios. Um Padrão pode ser genérico onde tem sua aplicabilidade em domínios diferentes ou específico quando fica associado a um único domínio.

Segundo Bushmann[1996], os padrões podem ser agrupados em três categorias:

  • Padrões de arquitetura.

  • Idiomas.

  • Padrões de análise e projeto.

Padrões de Arquiterura

Os Padrões de Arquitetura expressam o esquema de organização da estrutura de um sistema. Eles agrupam um conjunto de subsistemas, especificando os relacionamentos entre eles e as regras de comunicação entre os relacionamentos. Um exemplo deste padrão é o MVC(Model-View-Controller).

Idiomas

Os Idiomas são padrões de baixo nível, específicos para uma linguagem de programação que descrevem como implementar aspectos particulares de componentes, bem como, os relacionamentos entre eles. Além disso, agem como diretrizes de projetos, pois acabam ditando como será feito o modo de atribuição de nomes.

Padrões de Análise e Projeto

Os Padrões de Análise e Projeto fornecem um esquema para refinar os subsistemas ou componentes de um sistema de software. Estes padrões possuem um grau de granularidade considerado médio e são independentes de linguagem de programação. Em geral os Padrões de Projeto podem ser classificados em três diferentes tipos:

  • Padrões de criação: abstraem o processo de criação de objetos a partir da instanciação de classes.

  • Padrões estruturais: tratam da forma como a classe e o objeto estão organizados para formação de estruturas maiores.

  • Padrões comportamentais: preocupam-se com algoritmos e a atribuição de responsabilidade entre objetos.

Cada um desses padrões podem ser subdivididos em:

  • Padrões de classes: em geral estáticos, definidos em tempo de execução.

  • Padrões de objetos: em geral dinâmicos, definidos em tempo de execução.

O catálogo Gamma é o exemplo mais famoso para padronização de projetos baseando-se em experiências de diversos projetistas. Abaixo será apresentada uma tabela com a estrutura proposta por este catálogo.

Tabela 1. Estrutura proposta pelo catálogo


Finalidade

Criação

Estrutural

Comportamental

Escopo

Classe

Factory Method

Adapter

Interpreter

Objeto

Abstract Factory

Adapter

Chain of Responsability

Builder

Bridge

Command

Prototype

Composite

Iterator

Singleton

Decorator

Mediator


Facade

Memento


Flyweigth

Observer


Proxy

State



Strategy



Vistor

Umas séries de características podem ser realizados a cada item contido na tabela. Por critério de visualização será apresentado uma relação de tipos de padrões e sua referida funcionalidade.

Tabela 2. Especificação do catálogo Gamma


Descrição

Uso

Padrões de Criação

Abstract Factory

Fornece uma interface para criação de famílias de objetos relacionados ou dependentes sem especificar duas classes concretas.

Transportabilidade entre diferentes bibliotecas de interfaces gráficas.

Builder

Separa a construção de um objeto complexo da sua representação, de modo que o mesmo processo de construção possa criar diferentes representações.

Conversão de formatos de texto em editores.

Factory Method

Define uma interface para criar um objeto, mas deixa as subclasses decidirem qual a classe que será instanciada. Permite a uma classe postergar a instanciação de subclasses.

Bastante usado em toolkits e frameworks para a instanciação de objetos.

Prototype

Especifica os tipos de objetos a serem criados usando uma instância prototípica e cria novos objetos copiando este protótipo.

Depurador Etgdb.

Singleton

Garante que uma classe tenha somente uma instância e fornece um ponto global de acesso para ela.

Programas que só podem ter uma instância sendo executada em um dado momento.

Padrões Estruturais

Adapter

Converte a interface de uma classe em uma outra interface esperada pelo clientes. Permite que certas classes trabalhem em conjunto, pois de outra forma seria impossível por causa de suas interfaces incompatíveis.

Popularmente conhecido como wrapper, usado para adaptar a interface de classes.

Bridge

Separa uma abstração de sua implementação, de modo que as duas possam varias independentemente.

Para evitar o vínculo entre abstração e implementação quando de mudanças na implementação em tempo de execução.

Composite

Compõe objetos em estrutura de árvores para representar hierarquias do tipo partes-todo. Permite que os clientes da estrutura tratem objetos individuais e composições de objetos de maneira uniforme.

Para representar hierarquias parte-todo.

Decorator

Atribui responsabilidades adicionais a um objeto dinamicamente. Fornece uma alternativa flexível à utilização de subclasses para a extensão de funcionalidades.

Para a atribuição de enfeitos gráficos e outras funcionalidades acessórias a widgets.

Façade

Fornece uma interface unificada para um conjunto de interfaces em um subsistema. Define uma interface de nível mais alto que torna o subsistema mais fácil de usar.

Interface única em sistema complexos.

Flyweigth

Usa compartilhamento para suportar grandes quantidades de objetos, de granularidade fina, de maneira eficiente.

Sistemas com grandes números de objetos.

Proxy

Fornece um objeto representante ou um marcador de outro objeto para controlar acesso ao mesmo.

Algumas implementações corbas.

Padrões Comportamentais

Chain of Responsibility

Evita o acoplamento entre o remetente de uma solicitação e o destinatário da solicitação, dando a mais de um objeto a chance de tratar a solução. Encadeia os objetos receptores e passa a solicitação ao longo da cadeia até que um objeto trate.

Tratamento de eventos do usuário.

Command

Encapsula uma solicitação como um objeto, permitindo a parametrização de clientes com diferentes solicitações, o enfileiramento e o registro de solicitações e o suporte a operações que possam ser, por exemplo, desfeitas.

Suporte a desfazer.

Interpreter

Dada uma linguagem, define uma representação para uma gramática juntamente com um interpretador que usa a representação para interpretar sentenças nessa linguagem.

Interpretar uma linguagem com uma árvore sintática abstrata, como em compiladores de linguagens orientadas à objetos.

Iterator

Fornece uma maneira de acessar sequencialmente os elementos de um objeto agregado sem expor sua representação subjacente.

C++ Standard Template Library

Mediador

Define um objeto que encapsula a interação entre um conjunto de objetos. Promove o acoplamento fraco ao evitar que os objetos se refiram explicitamente uns aos outros, permitindo a variação das interações independentemente.

Arquitetura de aplicações Smalltalk.

Memento

Sem violar a encapsulação, captura e externaliza um estado interno de um objeto, de modo que o mesmo possa posteriormente ser restaurado para esse estado.

Armazenar um instantâneo do estado do objeto sem romper o encapsulamento.

Observer

Define uma dependência um-para-muitos entre objetos, de modo que, quando um objeto muda de estado, todos os seus dependentes são automaticamente notificados e atualizados.

Propagação de mudanças e atualizações com acoplamento fraco entre objetos.

State

Permite que um objeto altere seu comportamento quando seu estado interno muda. O objeto parecerá ter mudado sua classe.

Em algumas implementações da pilha TCP/IP.

Template Method

Define o esqueleto de um algoritmo em uma operação, postergando a definição em alguns passos para a subclasses. Permite que as subclasses redefinam certos passos de um algoritmo sem mudar sua estrutura.

Arquiteturas Application/Document/View.

Visitor

Representa uma operação a ser executada sobre os elementos de uma estrutura de objetos. Permite a definição de uma nova operação sem mudar as classes dos elementos sobre os quais opera.

Para executar uma série de operações sobre os objetos que possuem interfaces diferentes, sem poluir a interface dos mesmos.

Linguagens de Padrões

Linguagens Padrões consiste em uma coleção estruturada de padrões que são construídos a partir de outros padrões para transformar necessidades e restrições em uma arquitetura[Coplien].

Conclusão

Os Padrões e Linguagens Padrões têm como objetivo profissionalizar o processo de desenvolvimento de software, ainda que, os Padrões não apresentem uma solução exata.

José Mauro da Silva Sandy


Referências

Leia Também

Entendendo como é formada a linha digitável nos boletos bancários

Introdução


Todo boleto bancário exige uma série de especificações que devem ser seguidas com o intuito de estabelecer uma padronização de conteúdo. A pouco tempo adquiri uma documentação da CEF - Caixa Econômica Federal, onde constava as principais características que um boleto deveria ter para poder entrar em circulação. Esta postagem levará em conta a formação da linha digitável dos boletos para a CEF.


Descrição

Uma linha digitável segue a seguinte estrutura:

Figura 1. Layout Linha Digitável

Onde:

B = banco
M = moeda(real = 9)
L = campo livre
d = dígito verificador de campo
D = dígito verificador geral
V = valor e vencimento


A linha digitável de qualquer boleto bancário é composto por 5 campos. Abaixo segue as respectivas descrições:
  • Campo 1: as posições de 1 a 3 refere-se ao código da agência, neste exemplo 104, a quarta posição refere-se a moeda(9 para o real) as próximas cinco posições são os primeiros dígitos do campo livre, mais um dígito verificador de campo.
  • Campo 2: é composto pelas posições de 6 a 15 do campo livre e um dígito verificador de campo.
  • Campo 3: composto pelas posições de 16 a 25 do campo livre e um dígito verificador de campo.
  • Campo 4: dígito verificador geral da linha digitável.
  • Campo 5: composto pelo "fator de vencimento" com quatro posições e o valor nominal do boleto, sem vígulas. Torna-se necessário a inclusão de zeros entre os dois, afim de, compor as quatorze posições.
Campo livre


O Campo Livre é formado pelo nosso número(número gerado a cada boleto) com 10 dígitos e mais 15 dígitos contendo o código do cedente fornecido pela agência.

Observe que nos três primeiros campos é colocado um ponto após a 5ª posição, afim de, facilitar a digitação caso necessário. No 5º campo, preenche-se com zero as posições restantes entre o fator de vencimento e o valor do documento.

Nota: O fator de vencimento é obtido pela diferença entre a Data Base(07/10/1997) e a data de vencimento do título. O mesmo aparece nas 4 primeiras posições do último campo.
Utiliza-se o MÓDULO 10 para cálculo do dígito verificador de campo. Para realizar o cálculo execute os seguintes passos:
  1. Inverta os valores do campo e inicialize um fator multiplicativo com 2. Tal fator irá alternar entre os valores 1 e 2.
  2. Multiplique do dígito atual do campo pelo fator multiplicativo.
  3. Caso o valor multiplicado for maior que 10, aplique a regra dos noves fora. Por exemplo 12, 12 - 9 = 3.
  4. Soma-se o valor obtido a um totalizador. Repita os passos 2, 3 e 4 até percorrer todo a extensão numérica.
  5. Faça a divisão do totalizador obtido por 10.
  6. Subtraia o resto valor obtido no passo anterior, de 10.
Abaixo segue uma função em Python que realiza o cálculo desse dígito para exemplificação.
def verifier_digit(field):        
 mult = 2
 sum = 0

 for i in range(len(field)-1, -1, -1):
     x = (int(field[i]) * mult)

     if(x > 10):
         x = (x % 10) + 1
  
     sum += x

     if(mult == 2):
         mult = 1
  
     else:
         mult = 2

 if(not (sum % 10)):
     sum = 0

 else:
     sum = 10 - (sum % 10)

 return sum
O cálculo do fator de vencimento é mais simples, basta subtrair a data de vencimento do título pela Data Base(07/10/1997).
def diff_date(date_comp):
 date_def = date(1997,10,7)

 return (str(date_comp - date_def))[0:4]
O nosso número segue o MÓDULO 11, com pesos entre 2 a 9. Segue os passos:
  1. Inverta os valores do campo e inicialize um fator multiplicativo com 2.
  2. Multiplique o valor do dígito do campo pelo fator multiplicativo.
  3. Caso o fator multiplicativo for maior que 9, inicialize-o com 2.
  4. Soma-se o valor obtido a um totalizador. Repita os passos 2, 3 e 4 até percorrer todo a extensão numérica.
  5. Faça a divisão do totalizador obtido por 11.
  6. Subtraia o resto valor obtido no passo anterior, de 11.
Abaixo segue a implementação em Python do nosso número.
def calc_our_number(our_number):
 mult = 2
 sum = 0

 for i in range(len(our_number) - 1, -1, -1):
     sum += (int(our_number[i]) * mult)

     if(mult >= 9):
         mult = 2

     else:
         mult += 1

 sum = 11 - (sum % 11)

 if(sum > 9):
     sum = 0

 return our_number + '-' + str(sum)
Os passos para cálculo do dígito verificador geral segue os mesmos do nosso número. No entanto, deve ser passado para função uma sequência seguindo a ordem:

BANCO + MOEDA + CAMPO 5 + NOSSO NÚMERO + CÓDIGO CEDENTE

Para exemplificação seguem os códigos abaixo:

Dígito verificador geral.
def general_digit(line):
 mult = 2
 sum = 0

 for i in range(len(line) - 1, -1, -1):
     sum += (int(line[i]) * mult)

     if(mult >= 9):
         mult = 2

     else:
         mult += 1

 sum = 11 - (sum % 11)

 if(sum > 9 or sum or not sum):
     sum = 1

 return sum
Montagem linha digitável

E por fim a implentação da montagem com da linha digitável.
def mount_line(bank, currency, code_transf, our_number, factor, value):
 diff = 10 - len(str(value))

 field_1 = str(verifier_digit(bank + currency + our_number[0:5]))
 field_2 = str(verifier_digit(our_number[5:10] + code_transf[0:5]))
 field_3 = str(verifier_digit(code_transf[5:15]))
 field_4 = factor + ('0' * diff) + value

 g_digit = general_digit(bank + currency + field_4 + our_number + code_transf)

 return  bank + currency + our_number[0] + '.' + our_number[1:5]+ field_1\
         + ' ' + our_number[5:10] + '.' + code_transf[0:5] + field_2\
         + ' ' + code_transf[5:10] + '.' + code_transf[10:15] + field_3\
         + ' ' + str(g_digit) + ' ' + field_4
Pode-se incorporar as funções apresentadas em um arquivo de módulo para uso posterior.

José Mauro da Silva Sandy


Leia Também

Detalhes sobre a criação de Módulos em Python

Introdução

A príncipio foram omitidos alguns detalhes sobre a utilização de módulos em Python. Esta última postagem sobre a série Módulos em Python irá cubrir tais detalhes.

Ocultação de dados

Os módulos em Python exportam todas suas declarações de nível superior. Porém, existe a possibilidade de ocultar algumas exportações quando usa-se a claúsula from *. Vale ressaltar que isto não é um encapsulamento e as notações a seguir são contornadas utilizando as demais instruções, import e from.

Pode-se utilizar a notação _VARIAVEL ou a lista __all__ para definir quais serão os nomes exportados. Uma é exatamente o inversa da outra, na primeira situação é definido quais variáveis, funções, etc., que não serão exportadas, já na segunda, é definida uma lista no início do arquivo de módulo com todos os nomes de nível superior para exportação.

Na postagem, Importação de Módulos em Python, foi apresentado o arquivo de módulo employee.py. Para exemplificar a conceituação acima citada será utilizado tal arquivo.

_VARIAVEL

def salary_inc(perc=0, salary=0):
   return (salary + ((salary / 100) * perc))

def _sum_emp(list_emp=[]):
   return len(list_emp)
__all__
__all__=["salary_inc", "sum_emp"]

def salary_inc(perc=0, salary=0):
   return (salary + ((salary / 100) * perc))

def sum_emp(list_emp=[]):
   return len(list_emp)
Utilizando: __main__ e __name__

Uma das grande vantagens de Python é que o mesmo possibilita utilizar um arquivo de módulo tanto como um arquivo de nível superior(executável) ou como um arquivo de módulo propriamente dito, ao contrário de outras linguagens, e.g., C e Pascal.

Para isso, cada módulo tem um atributo interno chamado __name__, que de acordo com a utilização do arquivo, o interpretador atribui seu valor. Quando utilizado como arquivo de nível superior, __name__ recebe a string "__main__" e caso contrário recebe o nome do módulo importado.

Claúsula as

Como visto na postagem, Pacotes de Módulos em Python, pode-se ter caminho grandes a serem percorridos até chegar ao objetivo final. Para facilitar este percurso existe a claúsula as. Esta serve como uma alias de todo o caminho, conforme segue:
import diretorio1.diretorio2.employee as employee
Dessa maneira, todo caminho pode ser omitido e a utilização fica da forma mais simples. É claro que pode-se atribuir o objeto retornado a uma nova variável, de fato é isso que acontece com a claúsula as.

Abaixo segue uma conceituação sobre o ambiente de módulos em Python.

Figura 1. Ambiente de Módulos


José Mauro da Silva Sandy


Referências

  • MARK, Lutz. ASCHER, David. Aprendendo Python. Tradução João Tortello. 2. ed. Porto Alegre : Bookman, 2007.
Série Módulos em Python
Leia Também

Pacotes de Módulos em Python

Pode-se entender como pacote de módulo um diretório onde contenha os arquivos de módulos necessários para utilização de um sistema em Python. Um pacote de módulo tem como principal característica a organização do código em um sistema.

Para importação de pacotes utiliza-se o caminho dos arquivos separados por "pontos" e por fim o arquivo a ser importado. O diretório contêiner é omitido e deve ser obtido pela localização dos arquivos de módulo como apresentado anteriormente.

Tem-se a seguinte hierarquia:

Instrução: import


import diretorio1.diretorio2.modulo
Instrução: from
from diretorio1.diretorio2.modulo 
import atributo
A grande sacada da utilização dos pontos da notação é a portabilidade entre plataformas de desenvolvimento. Como o diretório contêiner é omitido e este é encontrado pelo caminho de pesquisa em Python, arquivos .pth e PYTHONPATH, o interpretador realiza a busca e concatena os diretórios importados em seu caminho de pesquisa.

Um detalhe importante na utilização de pacotes consiste em ter um arquivo __init__.py em todos os diretórios informados nas instruções de importação. Vale ressaltar que não é preciso existir esse arquivo no caminho que é buscado pelo PYTHONPATH ou .pth, o interpretador desconsidera o arquivo para estes diretórios.

Os arquivos __init__.py contém códigos Python, assim como os demais arquivos de módulo. Não é necessário que exista alguma instrução nestes arquivos, os mesmos podem estar vazios. Sempre ao passar pela primeira vez por um diretório de uma importação de pacote todo o conteúdo presente nos arquivos são executados. Uma forma útil de utilização destes arquivos poderia ser para abrir conexão com banco de dados, por exemplo.

Abaixo será apresentado graficamente este esquema.


Figura 1. Hierarquia de pacote

Observe que para todos os diretórios presentes na importação, exceto o contêiner, tem um arquivo __init__.py e no diretório 2 está o arquivo que realmente será importado. Neste exemplo a importação seria da seguinte forma:

Instrução: import

import diretorio1.diretorio2.employee
Instrução: from
from diretorio.diretorio2.employee 
import salary_inc
Nota: o módulo employee.py é o mesmo utilizado na postagem anterior.
Sem a presença dos arquivos __init__.py suas importações falharão e existem com a finalidade de impedir que diretórios sejam ocultos pela pesquisa impossibilitando a busca correta do arquivo desejado.

Alguns detalhes avançados, assim como da postagem Importação de Módulos em Python, serão discutidos na próxima postagem.

José Mauro da Silva Sandy


Referências

  • MARK, Lutz. ASCHER, David. Aprendendo Python. Tradução João Tortello. 2. ed. Porto Alegre : Bookman, 2007.
Série Módulos em Python
Leia Também


Importação de Módulos em Python

Pode-se utilizar duas maneiras distintas para importação de módulos em Python, são elas: import e from. Basicamente, provêem as mesmas funcionalidades, só que, com algumas pequenas diferenças:

  • import: a instrução import traz o módulo como um todo. Tal característica faz com que seja preciso qualificar um atributo em sua busca.
  • from: a instrução from realiza uma cópia de nomes de um módulo não necessitando de qualificar um atributo.

Nota: Tome o módulo employee.py como parâmetro para o restante da postagem. Tal módulo contém apenas duas funções sem nenhuma funcionalidade real.

# !/usr/bin/env python

# MODULE: employee -> file module reponsible for tasks to employees
# AUTHOR: Jose Mauro da Silva Sandy - http://informacaocomdiversao.blogspot.com
#
# CONTACT: jmsandy_at_gmail_dot_com
#
# DATE: 2008-12-26
#
# This is a fictitious example.
# The correct way to implement this module would be using class.
###############################################################################

# Arguments 1. percentage increase
#           2. salary
# result    wage hike
#
def salary_inc(perc=0, salary=0):
   return (salary + ((salary / 100) * perc))

# Arguments 1. list employee
# result    sum of number of employee
#
def sum_emp(list_emp=[]):
   return len(list_emp)
Instruções: import vs. from

Import

Quando importado, o módulo employee.py, passa a ser uma variável no script que o importa. Como apresentado, a instrução import traz um módulo como um todo, logo precisa-se utilizar o módulo importado para qualificar seus atributos.

import employee
print employee.salary_inc(10, 1500), " - ", employee.sum_emp()
Note que foi necessário fornecer o nome do módulo importado para se obter acesso as funções(atributos) e que com essa simples importação obteve-se ingresso a TODOS os seus atributos.

from e from *

Ao contrário do import, a instrução from copia nomes de um arquivo de módulo. Devido a isso não é necessário informar o nome do módulo que foi importado.

from employee import salary_inc
print salary_inc(10, 1500)
Observe que o único atributo importado pela instrução from, foi salary_inc, logo não será possível ter acesso a nenhum outro atributo do módulo. Para conseguir ingresso aos demais atributos torna-se indispensável utilizar a instrução from *, como abaixo:
from employee import *
print salary_inc(10, 1500), " - ", sum_emp()

Nota: Caso haja a curiosidade de executar o print usado no primeiro exemplo(import) em from omitindo o objeto importado, verá que acontecerá um erro em tempo de execução, pois o interpretador não encontrará a variável sum_emp().
Detalhes importantes na construção de módulos

Antes que qualquer atributo presente em um módulo possa ser acessado, o mesmo deve ter sido importado por uma das instruções acima citadas. É importante ressaltar, que para um arquivo ser importado é preciso que o módulo esteje no caminho de pesquisa e também possua a extensão .py, pois todos os arquivos com extensão diferente ou ausente são desconsiderados, causando assim erro de execução.

Uma vez carregado, os módulos em execução não sofrem nenhum mudança a menos que sejam recarregados. Tal episódio não reflete muito a realidade e fica apenas a termo de conceituação. Para recarregar um módulo é preciso que este tenha sido carregado previamente com sucesso, usa-se a função interna reload(module) para realizar esse processo. Este recarregamento trabalha de forma diferente para as instruções import e from. Em import, todas as mudanças alteradas são refletidas imediatamente em todos os clientes que importem o módulo, já na instrução from, os clientes não serão atingidos pois tal instrução trabalha com cópias para os atributos do módulo.

José Mauro da Silva Sandy


Referências

  • MARK, Lutz. ASCHER, David. Aprendendo Python. Tradução João Tortello. 2. ed. Porto Alegre : Bookman, 2007.
Série Módulos em Python
Leia Também


Visão Geral de Módulos em Python

Esta será a primeira postagem de uma série que visa apresentar as principais funcionalidades da estruturação de um programa em Python, o módulo. O módulo pode ser entendido como o nível mais alto dos programas em Python, onde as instruções são fornecidas para tratamento de qualquer problema.

A principal empregabilidade de módulo é no empacotamento de componentes de um sistema. Pode-se citar como suas principais funcionalidades: reutilização de código, particionamento do espaço de memória e dados compartilhados.

Arquitetura de um programa em Python

Normalmente, tem-se mais de um arquivo em um programa em Python, mesmo que, se tenha apenas um arquivo, geralmente, estará sendo utilizado módulos de terceiros e/ou internos do sistema.

Basicamente, um programa em Python consiste em um arquivo de nível superior que contém o fluxo inicial do programa e uma série de módulos que são importados pelo arquivo de nível superior e por outros módulos.

Abaixo será mostrado um esquema com 3 arquivos de módulo: a.py, b.py e c.py. Por notação o arquivo a.py será o usado como nível superior e os demais como módulos. Imagine que no arquivo b.py tenha a seguinte instruções:
def module_b(parameter):
    print "The value in parameter received is: %s." % parameter

if(__name__ == "__main__"):
    module_b("This is a teste: level higher!!!")


Na primeira linha tem-se a definição de uma função que recebe como parâmetro um valor qualquer para ser impresso pela mesma, logo depois(linha 3), uma instrução print para apresentar o valor recebido pelo parâmetro. As linhas 5 e 7 é um tratamento especial que existe na linguagem será abordado em postagens posteriores.

Agora será definido no arquivo a.py uma importação do módulo b.py e uma chamada a função module_b. Ambos nas linhas 1 e 3, respectivamente.
import b
b.module_b("Module a.py")

Note que para utilização da função module_b torna-se necessário o uso da importação do módulo b.py, sem esta claúsula não é possível acessar nenhum componente presente neste arquivo. Feito a importação utiliza-se a notação objeto.atributo que é vista em todos os códigos em Python. A instrução import será mostrada com mais detalhes posteriormente. Na figura 1, o esquema é apresentado graficamente.

Figura 1. Esquema em Python




Está presente na figura 1 uma parte referente aos módulos internos do sistema. Existem mais de 200 módulos para diversas funcionalidades em Python, para maiores informações acesse: http://www.python.org.

Funcionamento das importações

Quando algum módulo é importado são realizadas três etapas em tempo de execução:

  1. Localizar arquivo de módulo
  2. Compilá-lo em código de byte(se necessário)
  3. Executar o código afim de construir o objeto que ele define
Localização

Como deve ter sido observado na linha 1 do arquivo a.py, a extensão do arquivo de módulo importado .py é omitida e também seu caminho. Isto é feito de forma proposital para manter a portabilidade entre plataformas. O caminho de pesquisa em Python segue a seguinte hierarquia:

  1. Diretório base do arquivo de nível superior
  2. Diretórios do PYTHONPATH
  3. Diretórios da biblioteca padrão
  4. Todo conteúdo dos arquivos .pth(quando presentes)
  • Diretório base de nível superior: são todos os arquivos de módulos presentes no diretório onde está o arquivo de nível superior.
  • PYTHONPATH: variável de ambiente onde o Python busca os módulos a serem carregados, para maiores detalhes, clique aqui.
  • Diretório a biblioteca padrão: localização dos módulos padrões do Python.
  • Arquivos .pth: Este é um recurso avançado da linguagem. Pode-se ter um ou mais arquivos .pth com informações sobre localizações do módulos. Este recurso pode ser utilizado no lugar do PYTHONPATH, que como descrito no link acima, não deve ser alterado sem plena certeza. Neste arquivo tem-se uma lista de diretórios que contém arquivos de módulos necessários, e sempre, deve ser informado um caminho por linha.
Este é um arquivo chamado myconfig.pth, e serve como exemplo:
/home/jmsandy/src/
/home/jmsandy/src/modules

Compilação

Uma vez encontrado o arquivo de módulo, o Python, compila o arquivo .py para um código de byte .pyc para maior desempenho na execução. Note que esta etapa pode ser pulada quando é encontrado um arquivo .pyc para o módulo requerido. Porém, mesmo quando este arquivo é encontrado pode ocorrer compilação para manter a sincronia entre o arquivo .py e o .pyc, o Python verifica se o arquivo .py foi atualizado e reverte suas atualizações para o arquivo .pyc.

Execução

Após gerado o código de byte é realizada a execução do mesmo. O interpretador faz uma varredura de todas as instruções contida no arquivo de módulo de baixo para cima carregando os atributos para a memória.

José Mauro da Silva Sandy




Referência

  • MARK, Lutz. ASCHER, David. Aprendendo Python. Tradução João Tortello. 2. ed. Porto Alegre: Bookman, 2007.
Leia Também

CEP - Código de Endereçamento Postal

Introdução

O CEP - Código de Endereçamento Postal, foi criado em maio de 1971 pela Empresa Brasileira de Correios e Telégrafos. Inicialmente era formado por 5 dígitos e cerca de 20 anos depois, em maio de 1992, sua estrutura foi alterada para 8 dígitos, a mesma dos dias atuais.

O mesmo tem por objetivo otimizar a distribuição das encomendas entregues pelos Correios. Com tal endereçamento, torna-se possível uma melhor filtragem das remessas por parte da empresazada junto ao público em geral, com a publicação do Guia Postal Brasileiro, Edição 1992.
.

Estrutura

O CEP está configurando segundo o sistema decimal, sendo composto por: região, sub-região, setor, sub-setor, divisor de subsetor e identificadores de distribuição. Abaixo será apresentado graficamente a conceituação anterior:
Figura 1. Estrutura do CEP

O Brasil foi dividido em 10 regiões postais de acordo com parâmetros sócio-econômicos e fatos de densidade demográfica de cada região ou conjunto delas. A distribuição ocorre em sentido anti-horário a partir do estado de São Paulo que recebe o primeiro dígito.

Cada região está dividida em 10 sub-regiões e as sub-regiões em outros 10 setores. Tal esquema funciona até o divisor de subsetor, cada grupo é subdividido em 10 subgrupos, restando apenas os três últimos dígitos para identificação de distribuição, conhecido como SUFIXO. Os sufixos se classificam da seguinte forma:
Localidades não codificadas por logradouros (possuem um único CEP):
  • Faixa de Sufixos utilizada: 000 a 999
  • Caixas Postais Comunitárias: 990 a 998
Localidades codificadas por logradouros:
  • Logradouros: Faixa de Sufixos utilizada: 000 a 899
  • Códigos Especiais: Faixa de Sufixos utilizada: 900 a 959
  • CEPs Promocionais: Faixa de Sufixos utilizada: 960 a 969
  • Unidades dos Correios: Faixa de Sufixos utilizada: 970 a 989 e 999.
  • Caixas Postais Comunitárias: Faixa de Sufixos utilizada: 990 a 998
Implentação

Abaixo segue um código feito em Python, que leva em conta um arquivo texto onde contém todos os CEP's existentes no país para sua respectiva validação.
#!/usr/bin/env python

# ZIP CODE
# AUTHOR: Jose Mauro da Silva Sandy - http://informacaocomdiversao.blogspot.com
#
# CONTACT: jmsandy _at_ gmail _dot_ com
#
# DATE: 2008-12-08
#
# More information about ZIP CODE, visit:
# http://www.correios.com.br/servicos/cep/cep_estrutura.cfm
################################################################################

import easygui

def verify_zip(zip_code):
""" Receiving one zip-code for validate.
   Return one list with adress of zip-code or -1, otherwise.

"""

# Opening the file responsible to save information the CEP
file_cep = open(r'/home/jmsandy/Desktop/cep.txt', 'r')

# Receive and format the zip-code for validation
find_cep = '"' + str(zip_code) + '"'
lines = file_cep.readlines()

# Receiving the line to line the file
for line in lines:
 line_dic = line.split(',')

 # Comparing the zip-code
 if(line_dic[2] == find_cep):
   file_cep.close()

   return line_dic

else:
 file_cep.close()

 return "-1"

# Verifying if the module is been executed like principal code or module
if("__main__" == __name__):
zip_chosen = easygui.integerbox(msg="Enter the Zip-Code(Only Digits)", \
title="ZIP-CODE",default="", argLowerBound=0, argUpperBound=99999999)

# Verify if the desire's user is validate zip-code
if(zip_chosen):
 adress = verify_zip(zip_chosen)

 if(adress!="-1"):
   answer = 'RUA:    ', adress[5].replace('"',''), '\n', 'BAIRRO: ', \
   adress[1].replace('"',''), '\n', 'CIDADE: ', adress[3].replace('"',''),\
   '-', adress[9].replace('"','')

   easygui.codebox(msg="Information", title="Adress", text=answer)

 else:
   easygui.msgbox("Zip code invalid.")

José Mauro da Silva Sandy

Leitura Recomendada

Leia Também

Fábrica de Software

Atualmente com o crescente aumento do mercado consumidor de TI, torna-se necessário um maior profissinalismo envolvendo os processos de criação de software por empresas desenvolvedoras, tais como: custo e qualidade.

Com isso nos deparamos cada vez mais frequentemente com o termo Fábrica de Software(Software Factory). Este termo vem evoluíndo deste a década de 60, onde foi empregado pela primeira vez pela japonesa Hitach, mas acabou ganhando força no início dos anos 90 com o surgimento das linguagens de orientação a objeto. Juntamente com a OO(Orientação a Objetos) pode-se então ter uma maior reutilização de código e componentes, algo imprescindível para uma Fábrica de Software.

Como na área de informática é difícil uma clara definição dos processos empregados para o desenvolvimento de software, o termo Fábrica de Software, ganha basicamente três tipos de definições de acordo com a metodologia da empresa envolvida:
  • apenas a codificação;
  • apenas o modelo físico;
  • o projeto como um todo(lógico, físico, implementação, teste, implantação).
Os processos envolvidos em um projeto deve ser claramente definidos de acordo com o PMBOK(Project Management Body of Knowledge). Em software a iniciativa de definição e padronização dos processos surgiu através do SEI(Software Enginnering Institute), e também, com a brasileira MPS-BR(Melhoria dos processos de Software), ambas baseadas no PMBOK.

Embora tenha-se citado três definições de Fábrica de Software, a que melhor abrange o conceito de fábrica é a terceira, um projeto como um todo. Onde podemos subdividi-la em dois tipos de projeto: contínuo e discontínuo.
  • Contínuo: quando há necessidade de maior demanda por parte da empresa contrante, a fábrica de software fica em contato de forma contínua com o cliente aprendendo seus processos para uma maior produtividade.
  • Descontínuo: pode-se trabalhar uma única vez com a contratante e não ter mais envolvimento com seu negócio após o término do projeto.
É altamente recomendado que os profissionais que trabalharão em cada processo empregado por uma Fábrica de Software tenha suas atividades bem definidas e coordenada por um Gerente de Projeto. Ficará a cargo do Gerente de Projeto realizar uma interface entre a contratante e a contratada, definindo prazos, planejamento, monitoramento e controle. Basicamente, em uma Fábrica de Software têm-se a seguinte estrutura funcional:
  • Gerente de Negócios: prospecção do mercado e venda dos serviços;
  • Gerente de Projeto: gerenciamento dos riscos das atividades em desenvolvimento, dimensionamento e alocação de recursos, interação com o cliente e o gerente de negócios;
  • Analista de Sistemas: Levantamento de requisitos, análise, definição da arquitetura e documentação do sistema a ser desenvolvido;
  • Analista de Qualidade: revisão dos artefatos gerados, controle de mudanças, definição e validação da qualidade e precisão do processo utilizado;
  • Engenheiro de Software: Implementação do sistema conforme as especificações e documentação, seguindo o processo de desenvolvimento definido, desenvolvimento, validação e execução de testes de software visando assegurar a qualidade e precisão do software produzido;
  • Líder de Equipe: Coordenação e atribuição de tarefas dentro de um grupo específico, relatando periodicamente ao gerente de projetos o andamento das atividades.
Abaixo segue um esquema da empregabilidade dos processos envolvidos em uma Fábrica de Software:

Fig. 1

Vale lembrar que a maioria das empresas que se denominam Fábrica de Software precisam melhorar, consideravelmente, sua metodologia para que realmente possa se enquadrar neste termo.

José Mauro da Silva Sandy

Leia Também