Programação Estruturada

No "começo" do uso de computadores o principal custo da computação era o equipamento eletrônico (hardware). Atualmente a situação se modificou, os computadores estão cada vez mais rápidos e baratos e em contrapartida a tecnologia de software não apresentou um desenvolvimento comparável.

A noção da "crise do software" surgiu já no final dos anos 60 e uma das primeiras e mais conhecidas referências ao termo foi feita por Edsger W. Dijkstra, em 1972 no Prêmio Turing da Association for Computing Machinery, no manuscrito intitulado "The Humble Programmer".

Os problemas encontrados nas etapas do processo de desenvolvimento de software começaram a ser observados no final da década de 60 e continuam atormentando a vida dos projetistas até hoje. A crise se manifesta de várias formas, citando: a baixa produtividade dos programadores (projetos ultrapassando os prazos e orçamentos), a falta de uma "metodologia formal" para o desenvolvimento de software e os códigos de baixa qualidade (programas literalmente sem a possibilidade de serem mantidos). As soluções para a crise de software passam principalmente pelo uso de melhores técnicas, métodos e ferramentas.

O histórico com o surgimento das linguagens de programação está intensamente ligado a evolução das tecnologias de hardware e de software. Foi com o aumento da tecnologia e da capacidade dos computadores que problemas mais complexos puderam ser resolvidos pela máquina.

  • Década de 40, programação física em linguagem de máquina (conhecimento total do hardare).
  • Década de 50, linguagens de 1ª geração, programação lógica (abstração do hardware), linguagens montadoras como assembler (ainda exigiam conhecimentos do hardware), ênfase em cálculos matemáticos. Linguagens: Fortran, List e Algol 58.
  • Década de 60, linguagens de 2ª geração, ênfase no processamento de dados (sistemas bancários). Linguagens: Fortran, Algol 60, Lisp, Basic e Cobol.
  • Década de 70, linguagens de 3ª geração, ênfase na estruturação do código (programação estruturada). Linguagens: PL/1, Fortran, Algol 68, Cobol, Linguagem C, Pascal (ferramenta de aprendizagem de programação) e Simula (primeira linguagem a suportar o conceito de classes).

Como o próposito deste artigo é abordar os elementos chaves da programação estruturada destacou-se aqui a evolução das linguagens de programação até a década de 70.

Em 1968, Edsger W. Dijkstra, através do artigo "A Case against the GO TO Statement" critica o uso excessivo do comando de desvio incondicional GOTO nos programas desenvolvidos na época. Já em 1972 , novamente Dijkstra, escreve sobre os conceitos da Programação Estruturada no "Capítulo I- Notes on Structured Programming" do livro "Structured Programming" publicado juntamente com outros dois autores: Charles Antony Richard Hoare e Ole-Johan Dahl.

Elementos Chaves da Programação Estruturada

A programação estruturada é uma forma de programação de computadores que estabelece uma disciplina de desenvolvimento de algoritmos, independentemente da sua complexidade e da linguagem de programação na qual será codificado, que facilita a compreensão da solução através de um número restrito de mecanismos de codificação.

1) Estruturas básicas de controle: sequência, condição e repetição.

São formas de raciocínio intuitivamente óbvias. A legibilidade e compreensão de cada bloco de código na solução é enormemente incrementada, proibindo o uso irrestrito de comandos de desvio incondicional (GOTO).

2) Subprogramação (ou modularização).

À medida que os programas vão se tornando maiores e mais complexos, é possível simplificar e melhorar a clareza dividindo o programa em partes menores, chamadas subprogramas.

Um subprograma, é um nome dado a um trecho de um programa mais complexo e que, em geral, encerra em si próprio um pedaço da solução de um problema maior (o programa a que ele está subordinado). São sinônimos usados na engenharia de software para o conceito de subprograma: procedimento, função, módulo (estrutura modular), métodos (orientação a objetos) e subrotina.

Na programação estruturada o "método dos refinamentos sucessivos" é uma "sistemática" de abordagem útil no projeto detalhado e na implementação de softwares. Partindo-se de um dado problema, para qual se deseja encontrar um programa de solução, deve-se procurar subdividi-lo em problemas menores e consequentemente de solução mais simples (dividir para conquistar). Alguns destes problemas menores (subproblemas) terão solução imediata (na forma de um subprograma) e outros não. Os subproblemas para os quais não for possível encontrar uma solução direta devem ser novamente subdivididos. Assim, o processo é repetido até que se consiga encontrar um subprograma para solucionar cada um dos subproblemas definidos. Então, o programa de solução do problema original será composto pela justaposição dos subprogramas usados para solucionar cada um dos subproblemas em que o problema original foi decomposto.

Com a subdivisão de programas complexos algumas vantagens são conquistadas: a) cada parte menor tem um código mais simples; b) facilita o entendimento uma vez que os subprogramas podem ser analisados como partes independentes (legibilidade); c) códigos menores são mais facilmente modificáveis para satisfazer novos requisitos do usuário e para correção de erros (manutenibilidade); d) simplificação da documentação de sistemas; e) desenvolvimento de software por equipes de programadores; e, f) reutilização de subprogramas através de bibliotecas de subprogramas, na linguagem C, sob a forma dos arquivos de cabeçalhos (.h).

A principal questão é a "reutilização de software" objetivando a economia de tempo e trabalho (benefícios técnicos que trazem vantagens financeiras). Um conjunto de subprogramas destinado a solucionar uma série de tarefas bastante corriqueiras é desenvolvido e vai sendo aumentado com o passar do tempo, com o acréscimo de novos subprogramas. A este conjunto dá-se o nome de biblioteca. No desenvolvimento de novos sistemas, procura-se ao máximo basear sua concepção em subprogramas já existentes na biblioteca, de modo que a quantidade de software realmente novo que deve ser desenvolvido é minimizada.

3) Tipos Abstratos de Dados.

Segundo o Prof. Nivio Ziviani, um Tipo Abstrato de Dados (TAD) pode ser visto como um modelo matemático, acompanhado das operações definidas sobre o modelo. O conjunto dos inteiros acompanhado das operações de adição, subtração e multiplicação forma um exemplo de um TAD.

Ainda segundo Ziviani, os TAD podem ser considerados generalizações de tipos primitivos de dados, da mesma forma que procedimentos são generalizações de operações primitivas tais como adição, subtração e multiplicação. Assim como um procedimento é usado para encapsular partes de um programa, o tipo abstrato de dados pode ser usado para encapsular tipos de dados.

Neste caso a definição do tipo de dados e todas as operações definidas sobre ele podem ser localizadas em uma única seção do programa (na Linguagem C, por exemplo, em um arquivo de cabeçalhos).

Em resumo as principais características da Programação Estruturada são:

  • decomposição gradativa dos programas ao nível fundamental (método dos refinamentos sucessivos, desenvolvimento top-down).
  • programação orientada a procedimentos: subprogramas = blocos estruturados de códigos (procedimentos, funções ou módulos); a comunicação entre os blocos se faz utilizando variáveis globais e pela passagem de dados através de parâmetros; os dados são processados nos blocos e migram de um bloco para outro, como mostra a Figura 1, através de variáveis globais, parâmetros passados por referência e expressão retornada pela função (através do comando return na linguagem C); a execução de um programa é caracterizada pelo acionamento de um bloco de código. Obs.: a utilização de variáveis globais não constitui uma boa prática de programação (escopo muito grande).
  • tipo abstrato de dados = modelo matemático + operações.
Programação Estruturada (programação orientada a procedimentos)
Figura 1: Programação Estruturada (programação orientada a procedimentos).

Nota: Os códigos, apresentados nas Listagens 1 e 2, abordando os elementos chave da programação estruturada foram implementados em Linguagem C usando o ambiente de programação" Code::Blocks 8.02".

A Listagem 1 apresenta o arquivo de cabeçalhos, salvo com o nome data.h, com a implementação de um tipo abstrato de dados para operações com valores do tipo data (data de nascimento, por exemplo). Inicialmente foi declarado um tipo de dados registro (struct) denominado de rgData com os campos dia, mes e ano. A seguir foram codificadas as operações através de três subprogramas: a) dataNova: retorna uma data criada a partir dos valores recebidos através dos parâmetros "d", "m" e "a"; b) dataHoje: retorna a data do sistema operacional; e, c) calculaIdade: calcula e retorna a idade de uma pessoa usando a data de nascimento recebida pelo parâmetro dt.

Listagem 1: Tipo Abstrato de Dados (arquivo data.h).


// TIPO ABSTRATO DE DADOS = MODELO MATEMÁTICO + OPERAÇÕES

#include "time.h"

// Modelo matemático (tipo de dados)
struct rgData {
  int dia;
  int mes;
  int ano;
};

// Conjunto de operações
// retorna uma data criada com os valores dos parâmetros
struct rgData dataNova(int d, int m, int a) {
  struct rgData dt;

  dt.dia = d;
  dt.mes = m;
  dt.ano = a;

  return(dt);
}

// retorna uma data criada a partir da data do sistema operacional
struct rgData dataHoje(void) {
  struct rgData dt;

  time_t tempo;
  struct tm *hj;
  tempo = time(NULL); // obtem o tempo corrente
  hj = localtime(&tempo); // obtem a data do sistema operacional
  dt.dia = hj->tm_mday;
  dt.mes = hj->tm_mon + 1;
  dt.ano = hj->tm_year + 1900;

  return(dt);
}

int calculaIdade(struct rgData dt) {
  struct rgData hj = dataHoje();

  int id = hj.ano - dt.ano;
  if ((hj.mes < dt.mes) || ((hj.mes == dt.mes) && (hj.dia < dt.dia))) {
     id = id - 1; // ainda não fez aniversário no ano
  }

  return(id);
}

O programa principal (main) apresentado na Listagem 2 utiliza o tipo abstrado de dados descrito na Listagem 1 incluindo o arquivo de cabeçalhos "data.h" através da instrução #include data.h. As variáveis dt e hj declaradas a partir do tipo de dados rgData são utilizadas para receber a data de nascimento de uma pessoa na entrada de dados (scanf("%d/%d/%d", &dt.dia, &dt.mes, &dt.ano);) e a data do sistema operacional (hj = dataHoje();), respectivamente. Finalizando o programa, através de comandos de saída (printf) são exibidos para o usuário final a data atual e a idade, valor definido pela chamada da função calculaIdade(dt).

Listagem 2: Utilizando o Tipo Abstrato de Dados definido no arquivo data.h


#include "stdio.h"
#include "data.h" // inclui o Tipo Abstrato de Dados

int main() {
  struct rgData dt, hj;

  printf("Informe a sua data de nascimento (dd/mm/aaaa):\n");
  scanf("%d/%d/%d", &dt.dia, &dt.mes, &dt.ano);

  hj = dataHoje(); // recebe a data do sistema operacional

  printf("\nHoje eh dia %.2d/%.2d/%d.\n", hj.dia, hj.mes, hj.ano);

  printf("\nSua idade eh igual a %d anos.\n", calculaIdade(dt));
}

Ao executar a aplicação o resultado apresentado na Figura 2 poderá ser exibido.

Executando a aplicação
Figura 2: Executando a aplicação

Saiu na DevMedia!

  • Principais atividades para administração do Oracle RAC:
    Neste artigo serão apresentados os principais conceitos sobre o Oracle Real Application Cluster (RAC) e os principais comandos para administração e manutenção destes ambientes.
  • Inno Setup: Instalando e distribuindo o SQL Server Express:
    Veremos neste artigo como é possível distribuir e instalar aplicativos que utilizam como base de dados o SQL Server Express utilizando o Inno Setup.
  • Conheça o MySQL Fabric:
    Neste artigo iremos conhecer e entender o que é o MySQL Fabric e em qual situações podemos utilizá-lo. Também falaremos sobre as melhores práticas na configuração, instalação e monitoramento do MySQL com o MySQL Fabric.

Referênciais:

  • Prof. Omero Francisco Bertol
  • Programando em Linguagem C:
    Neste guia de consulta você encontrará diversos conteúdos que podem ser usados ao longo dos seus estudos sobre a linguagem de programação C#. Consulte este guia para aprender mais sobre certos recursos da linguagem.
  • Aplicações Java:
    Com o objetivo de apresentar algumas das plataformas Java, este artigo aborda os conceitos de cada uma delas, são elas: Java SE, Java EE e Java FX, onde podem ser utilizadas e quais os tipos de aplicação que podem ser desenvolvidas.