Aplicações Práticas para Computação
Prezados e prezadas, estamos chegando ao final de nosso curso. Alguns dos assuntos citados pela ementa foram cobertos pelo curso de Lógica e alguns pela disciplina de Matemática Discreta. Faltando mesmo para encerra todo o conteúdo o título dessa aula de hoje “Aplicações Práticas para a Computação”, claro que as aplicações práticas são de lógica.
Banco de Dados
Abaixo trago um excelente texto de Marceliz Mayer do site “https://www.devmedia.com.br/por-que-construir-um-modelo-de-dados-logico-parte-i/368” acessado em 14/06/2021. Vou transcrever o texto para nosso site para poder inserir comentários para nosso assunto. Não deixe de acessar e ler o original.
Modelos de Dados
Há três tipos de modelos de dados: o conceitual, o lógico e o físico. Todos concordam que uma estrutura de dados com qualidade é imprescindível para garantir a legitimidade do banco de dados facilitando a manutenção do sistema de aplicação.
Isto se aplica ao modelo de dados físico. Considerando que há poucos administradores de banco de dados que partem do seguinte princípio: “É mais fácil criar uma tabela e incluir todos os dados nela”. Muitos profissionais estão cientes da importância das regras de normalização de dados e seus benefícios. O arquiteto de dados deve familiarizar-se com as principais razões de se implementar um banco de dados normalizado.
Uma vez entendida as técnicas e justificativas, é difícil não concordar com elas. O propósito deste artigo não é discutir design e implementação de banco de dados, mas demonstrar a importância do modelo de dados lógico MDL como sendo o nível mais alto dos dados de negócios. Uma vez identificado os requisitos de negócios poderemos normalizar e implementar os dados. Entretanto, se não tivermos um conhecimento transparente do trabalho de design e implementação de todos os requisitos de negócios, não teremos uma aplicação com qualidade.
Dado é a parte mais importante de um sistema de aplicação. Uma estrutura de dados acurado, permite ao analista de sistema da aplicação desenhar os processos, a interface de usuário, relatórios e análise estatística sempre que precisar. Requisitos de negócio são mais importantes do que a própria estrutura de dados. Pode ser o sistema da mais alta tecnologia, mas se ele não possuir os requisitos de negócios documentados estará fadado ao fracasso. Portanto o modelo de dados lógico combina dois importantes componentes do desenvolvimento de aplicações: requisitos de negócios e qualidade da estrutura de dados.
O que é um modelo de dados lógico?
Um modelo de dados lógico é uma representação lógica das informações da área de negócios, não é um banco de dados, é independente do modelo físico. Este é o conceito chave da modelagem de dados lógica. Ele deve ser independente da tecnologia implementada devido a constante mudança dos produtos tecnológicos. Os desenvolvedores de sistemas não devem se apegar a uma determinada tecnologia, precisam desenvolver sistemas independentes de tecnologia. Mas como isso seria possível? Há componentes de sistemas que estão intimamente ligados a tecnologia como os programas, sistemas gerenciadores de banco de dados, componentes de tela, mas há também os componentes de sistema que podem ser criados independentes da tecnologia que será implementado como acontece com o modelo de dados lógico e as regras de negócios. Estes componentes estão intimamente ligados aos negócios, não a tecnologia.
A área de negócios não muda tão rapidamente como os produtos tecnológicos. Pense na indústria como uma área de negócios centenária em que seu objetivo é a fabricação de produtos dos mais diversos tipos e que os processos de negócios vão desde a compra da matéria-prima, sua transformação, empacotamento e distribuição do produto acabado. Ela tem feito isso ao longo de toda a sua história. Eles sempre realizaram seus processos de trabalho sem os computadores, depois tiveram o apoio dos mainframes, da rede de computadores e agora da internet. O que os negócios fazem não mudou ao longo do tempo, mas como eles são feitos sim. A diferença entre “O que” são os requisitos de negócios e “Como” eles são executados descreve a diferença entre o modelo de dados lógico e banco de dados físico.
Quando surge uma nova tecnologia o responsável pelo modelo de dados lógico não necessita questionar os profissionais da área de negócios de novo pois as regras de negócios continuam sendo as mesmas, ele precisa apenas revisar o modelo lógico, entender os requisitos de negócios e oferecer sugestões para a implementação de mudanças perante a nova tecnologia ou sugerir “Como” a nova tecnologia poderia mudar a maneira dos requisitos de negócios serem feitos. Desta forma, desenvolver e fazer manutenção utilizando modelo de dados lógico permite prover um serviço diferenciado para a área de negócios com maior rapidez e menor custo. O modelo de dados lógico é o retrato de todas as informações necessárias para a realização dos negócios. Ele é representado de diversas maneiras diferentes, utilizando metodologias e ferramentas diferentes para implementações diferenciadas. O modelo entidade-relacionamento (MER) é uma técnica de modelagem amplamente utilizada pelos administradores de dados. O diagrama entidade-relacionamento é um desenho estruturado utilizado como uma ferramenta de comunicação entre os profissionais de negócios e os desenvolvedores de sistemas de aplicação. Ele representa a diagramação dos dados necessários para as regras de negócios. Os componentes do MER são representados pelas entidades, os relacionamentos e os atributos. Cada entidade representa um conjunto de pessoas, coisas ou conceitos sobre os quais o negócio precisa de informações. Cada relacionamento representa a associação entre duas entidades. Cada atributo é a característica ou parte da informação de uma entidade. Um nome e uma definição textual descreve cada um desses componentes. Estes nomes e definições proveem da documentação das regras de negócio e informações as quais são armazenadas e mantidas num repositório de dados garantindo assim a padronização conceitual dos dados. O MER utiliza a simbologia do IDEF1x (Integration Definition for Information Modeling) e IE (Information Engineering) (Figura 1).
Quem cria o modelo de dados lógico?
O arquiteto de dados com a ajuda do analista de requisitos de negócios cria o modelo de dados lógico e se utiliza dele para avaliar possíveis impactos nos requisitos de negócios numa provável mudança tecnológica. O arquiteto de dados também é responsável por trabalhar com o administrador de banco de dados – DBA – para garantir a implementação do modelo de dados lógico para o modelo de dados físico de acordo com o sistema gerenciador de banco de dados – SGBD – que será aplicado. O DBA revisa o modelo de dados lógico e define o SGBD mais apropriado, cria índices, detalha os tipos de dados e cria a integridade referencial para proteger o valor dos dados. O administrador de banco de dados pode des-normalizar a base de dados, criar stored procedures, triggers além de monitorar a performance do banco de dados físico.
Veja o exemplo do MER completo na Figura 2.
Importância dos Modelos de Dados
Estes modelos podem ajudar na comunicação entre o projetista, programadores e o usuário final, dando uma compreensão mais aprimorada da organização para a qual está sendo desenvolvida.
As aplicações são criadas para gerenciar os dados e transformá-las em informações. Daí a importância de não ignorar esta etapa fundamental, principalmente que cada um dos envolvidos (projetistas, programadores e usuários finais) tem visões diferentes sobre o sistema como um todo.
Caso tenha um bom projeto em mãos para trabalhar, esses pontos de vista diferentes não importarão. Se você não tiver algo bom, você pode sofrer com prejuízos futuros. Imagina um software que faz conflito de dados, mostrando valores de produtos de forma trocada, algo como uma caneta simples mostrando o valor de R$ 1.200,00, que seria o valor de um outro produto que poderia ser um computador, por exemplo.
O modelo de dados é uma abstração que não será possível obter dados a partir dele, mas você irá precisar para começar seu projeto de banco de dados, dando mais segurança para o seu projeto dar certo, atendendo as necessidades do usuário final.
Graus de Abstração de Dados
Modelagem Conceitual
O objetivo aqui é criar um modelo conceitual de forma gráfica, sendo este chamado de Diagrama Entidade e Relacionamento (DER), que identificará todas as entidades e relacionamentos de uma forma global. Aqui é evitado qualquer detalhamento específico do modelo de BD.
O modelo conceitual mais utilizado é o de ER, que é ajudado pelo DER, que na prática, constitui o modelo básico do BD. Este é utilizado para representar graficamente o esquema conceitual.
Através deste modelo, teremos uma visão de cima (macro) compreendida de modo relativamente fácil sobre o ambiente de dados. Também é independente de hardware ou software, ou seja, não depende de nenhum SGBD utilizado para implantá-lo. Por tanto, qualquer alteração no software ou hardware, não terão efeito no nível conceitual.
Modelagem Lógica
Depois que selecionamos um SGBD, iremos mapear o modelo conceitual para ele. O projetista relaciona as características e restrições do modelo conceitual com as do modelo selecionado para implementação. O modelo lógico constitui uma representação específica de um modelo interno, utilizando as estruturas de BD suportada pelo banco escolhido. Em um Banco de Dados Relacional (BDR), o esquema interno é expresso utilizando linguagem SQL, por padrão.
Neste nível, o modelo lógico depende do software. Por tanto, qualquer alteração feita no SGBD exigem que o modelo interno seja alterado para adequar-se às características e exigências de implementação do modelo de BD. Quando conseguimos alterar o modelo lógico sem afetar o modelo conceitual, teremos o que é chamado de independência lógica. No entanto, o modelo lógico continua independente de hardware, ou seja, qualquer alteração (escolha de um computador, sistema operacional diferente, etc) não afetará no modelo lógico.
É nesta modelagem que serão definidas os padrões e nomenclaturas, chaves primárias e estrangeiras, sempre levando em conta o modelo conceitual criado anteriormente.
Modelagem Física
Aqui é trabalhado no nível mais baixo de abstração, descrevendo o modo como os dados são salvos em meios de armazenamentos, como discos e fitas, sendo exigido a definição tanto dos dispositivos de armazenamento físico como dos métodos de acesso (físico) necessários para se chegar aos dados nesse dispositivos, o que o torna dependente tanto de software como de hardware. Os projetistas precisam de um conhecimento detalhado do hardware e do software utilizado para implementar o projeto de BD.
Não é necessário que o projetista se preocupe com as características do armazenamento físico dos dados, mas a implementação de um modelo relacional pode exigir sintonização refinada no nível físico para melhorar o desempenho, principalmente em BD muito grandes em ambientes mainframes.
Compiladores
A construção de compiladores abrange diversas áreas de estudo em Ciências da Computação, como por exemplo conceitos de Linguagens de Programação, Arquitetura de Máquina, Algoritmos, Teoria da Computação, Lógica e Engenharia de Software.
As linguagens de programação e a arquitetura de computadores evoluem e estão cada vez mais sofisticados. O desafio dos projetistas de compiladores é criar algoritmos mais eficientes que visem obter um melhor desempenho no uso de memória e processamento.
Conhecer como um compilador funciona é essencial para entender a ligação entre Linguagens de Programação, Arquitetura de Máquina, Algoritmos, Teoria da Computação, Lógica e Engenharia de Software.
Definição
O compilador é um software complexo que converte uma linguagem fonte, ou linguagem origem, em uma linguagem destino, ou linguagem-objeto, ou seja, converte um programa originado de uma linguagem de programação para uma linguagem que possa ser entendida e executada por um computador. Durante a compilação são executadas tarefas que fazem a tradução de uma linguagem em outra.
Existem dois princípios fundamentais na construção de compiladores:
- O compilador deve preservar o significado do programa a ser compilado; e
- O compilador deve melhorar o programa de entrada de alguma forma perceptível.
As etapas de compilação são complexas e exigiam um esforço significativo, sendo que os primeiros compiladores eram escritos em código binário e salvos na memória ROM. Hoje nós temos um conjunto de ferramentas que facilitam a criação e manutenção de compiladores, muitas dessas ferramentas são escritas em linguagem como Java, C e C++ e já automatizam boa parte da construção de um compilador.
Essas ferramentas geram códigos que podem ser incluídos no projeto do compilador. Um exemplo são os geradores de analisadores léxicos, que com base em expressões regulares geram um algoritmo capaz de identificar os elementos léxicos de uma linguagem de programação.
O compilador precisa traduzir um conjunto infinito de programas escritos em uma linguagem de programação e o resultado desse processo deve ser um código eficiente que deve ser executado em diversas arquiteturas de processadores.
Um conceito muito importante no estudo de compiladores é a otimização, que se refere as atentivas de produzir um compilador que gere um código mais eficiente. Essa é uma etapa cada vez mais importante e complexa devido à grande variedade de arquiteturas de processadores. O tempo de compilação é outro fator muito importante que deve ser levado em consideração durante o desenvolvimento de um compilador.
Características
Normalmente, o código fonte é escrito em uma linguagem de programação de alto nível, com grande capacidade de abstração, e o código objeto é escrito em uma linguagem de baixo nível, como uma sequência de instruções a ser executada pelo microprocessador.
O processo de compilação é composto de análise e síntese. A análise tem como objetivo entender o código fonte e representá-lo em uma estrutura intermediária. A síntese constrói o código objeto a partir desta representação intermediária.
A análise pode ser subdividida ainda em análise léxica, análise sintática, análise semântica e geração de código intermediário. É também conhecida como front end. A síntese pode ter mais variações de um compilador a outro, podendo ser composta pelas etapas de optimização de código e geração de código final (ou código de máquina), sendo somente esta última etapa é obrigatória. É também conhecida como back end.
Em linguagens híbridas, o compilador tem o papel de converter o código fonte em um código chamado de byte code, que é uma linguagem de baixo nível. Um exemplo deste comportamento é o do compilador da linguagem Java que, em vez de gerar código da máquina hospedeira (onde se está executando o compilador), gera código chamado Java Bytecode.
Um compilador é chamado de Just-in-time compiler (JIT) quando seu processo de compilação acontece apenas quando o código é chamado. Um JIT pode fazer otimizações às instruções à medida que as compila.
Muitos compiladores incluem um pré-processador. Que é um programa separado, ativado pelo compilador antes do início do processo de tradução.[19] Normalmente é responsável por mudanças no código fonte destinadas de acordo com decisões tomadas em tempo de compilação. Por exemplo, um programa em C permite instruções condicionais para o pré-processador que podem incluir ou não parte do código caso uma assertiva lógica seja verdadeira ou falsa, ou simplesmente um termo esteja definido ou não. Tecnicamente, pré-processadores são muito mais simples que compiladores e são vistos, pelos desenvolvedores, como programas à parte, apesar dessa visão não ser necessariamente compartilhada pelo usuário.
Outra parte separada do compilador que muitos usuários veem como integrada é o linker, cuja função é unir vários programas já compilados de uma forma independente e unificá-los em um programa executável. Isso inclui colocar o programa final em um formato compatível com as necessidades do sistema operacional para carregá-lo em memória e colocá-lo em execução.
Fases da compilação
Análise léxica – A análise léxica é a primeira fase do compilador. A função do analisador léxico, também denominado scanner, é ler o código-fonte, caractere a caractere, buscando a separação e identificação dos elementos componentes do programa-fonte, denominados símbolos léxicos ou tokens. É também de responsabilidade desta fase a eliminação de elementos “decorativos” do programa, tais como espaços em branco, marcas de formatação de texto e comentários. Existem disponíveis uma série de geradores automáticos de analisadores léxicos, como por exemplo, o lex. O objetivo dos geradores automáticos é limitar o esforço de programação de um analisador léxico especificando-se apenas os tokens a ser reconhecidos.
Análise sintática – A análise sintática, ou análise gramatical é o processo de se determinar se uma cadeia de símbolos léxicos pode ser gerada por uma gramática. O analisador sintático é o cerne do compilador, responsável por verificar se os símbolos contidos no programa fonte formam um programa válido, ou não. No caso de analisadores sintáticos top-down, temos a opção de escrevê-los à mão ou gerá-los de forma automática, mas os analisadores bottom-up só podem ser gerados automaticamente. A maioria dos métodos de análise sintática, cai em uma dessas duas classes denominadas top-down e bottom-up. Entre os métodos top-down os mais importantes são a análise sintática descendente recursiva e a análise sintática preditiva não-recursiva. Entre os métodos de análise sintática bottom-up os mais importantes são a análise sintática de precedência de operadores, análise sintática LR canônico, análise sintática LALR e análise sintática SLR. Existem disponíveis uma série de geradores automáticos de analisadores sintáticos, como por exemplo, o Yacc, o Bison e o JavaCC.
Análise semântica – As análises léxica e sintática não estão preocupadas com o significado ou semântica dos programas que elas processam. O papel do analisador semântico é prover métodos pelos quais as estruturas construídas pelo analisador sintático possam ser avaliadas ou executadas. As gramáticas livres de contexto não são suficientemente poderosas para descrever uma série de construções das linguagens de programação, como por exemplo regras de escopo, regras de visibilidade e consistência de tipos. É papel do analisador semântico assegurar que todas as regras sensíveis ao contexto da linguagem estejam analisadas e verificadas quanto à sua validade. Um exemplo de tarefa própria do analisador semântico é a checagem de tipos de variáveis em expressões. Um dos mecanismos comumente utilizados por implementadores de compiladores é a Gramática de Atributos, que consiste em uma gramática livre de contexto acrescentada de um conjunto finito de atributos e um conjunto finito de predicados sobre estes atributos.
Geração de código intermediário – Na fase de geração de código intermediário, ocorre a transformação da árvore sintática em uma representação intermediária do código fonte. Esta linguagem intermediária é mais próxima da linguagem objeto do que o código fonte, mas ainda permite uma manipulação mais fácil do que se código assembly ou código de máquina fosse utilizado. Um tipo popular de linguagem intermediária é conhecido como código de três endereços. Neste tipo de código uma sentença típica tem a forma X := A op B, onde X, A e B são operandos e op uma operação qualquer. Uma forma prática de representar sentenças de três endereços é através do uso de quádruplas (operador, argumento 1, argumento 2 e, resultado). Este esquema de representação de código intermediário é preferido por diversos compiladores, principalmente aqueles que executam extensivas otimizações de código, uma vez que o código intermediário pode ser rearranjado de uma maneira conveniente com facilidade. Outras representações de código intermediário comumente usadas são as triplas, (similares as quádruplas exceto pelo fato de que os resultados não são nomeados explicitamente) as árvores, os grafos acíclicos dirigidos (DAG) e a notação polonesa.
Otimização de código – A otimização de código é a estratégia de examinar o código intermediário, produzido durante a fase de geração de código com objetivo de produzir, através de algumas técnicas, um código que execute com bastante eficiência. O nome otimizador deve sempre ser encarado com cuidado, pois não se pode criar um programa que leia um programa P e gere um programa P´ equivalente sendo melhor possível segundo o critério adotado. Várias técnicas e várias tarefas se reúnem sob o nome de Optimização. Estas técnicas consistem em detectar padrões dentro do código produzido e substituí-los por códigos mais eficientes. Entre as técnicas usadas estão a substituição de expressões que podem ser avaliadas durante o tempo de compilação pelos seus valores calculados, eliminação de subexpressões redundantes, desmembramento de laços, substituição de operações (multiplicação por shifts), entre outras. Uma das técnicas de optimização mais eficazes e independente de máquina é a otimização de laços, pois laços internos são bons candidatos para melhorias. Por exemplo, em caso de computações fixas dentro de laços, é possível mover estas computações para fora dos mesmos reduzindo processamento.
Geração de código final – A fase de geração de código final é a última fase da compilação. A geração de um bom código objeto é difícil devido aos detalhes particulares das máquinas para os quais o código é gerado. Contudo, é uma fase importante, pois uma boa geração de código pode ser, por exemplo, duas vezes mais rápida que um algoritmo de geração de código ineficiente. Nem todas as técnicas de optimização são independentes da arquitetura da máquina-alvo. Optimizações dependentes da máquina necessitam de informações tais como os limites e os recursos especiais da máquina-alvo a fim de produzir um código mais compacto e eficiente. O código produzido pelo compilador deve se aproveitar dos recursos especiais de cada máquina-alvo. Segundo Aho, o código objeto pode ser uma sequência de instruções absolutas de máquina, uma sequência de instruções de máquina relocáveis, um programa em linguagem assembly ou um programa em outra linguagem.
Conclusão
Não esgotamos o assunto, apenas introduzimos algumas aplicações/assuntos importantes da computação que são fortemente dependentes de lógica. Veremos na próxima aula uma linguagem que usa a lógica para resolver problemas computacionais.