Saltar para o conteúdo
050 · Open Source Essentials

T01 — 051.1 Componentes de software

TópicoT01Objetivo051.1Peso2PáginasLPI Open Source Essentials (050) - Version 1.0

Resumo Conciso

O que é software

Software é a parte não-física, não-material, de qualquer tipo de computador. É o que permite que as partes físicas (hardware) interajam e que o computador aceite comandos e execute tarefas.

ConceitoDescrição
SoftwareSequências de comando codificadas que controlam os componentes do computador
AlgoritmoManeira de resolver um problema (ex.: calcular uma média)
Código-fonteTexto escrito numa linguagem de programação, legível por humanos
Código de máquinaPadrões de bits que a CPU executa diretamente
BytecodeFormato intermediário executado por uma máquina virtual em tempo de execução

Linguagens de programação

Linguagens artificiais altamente estruturadas que dizem a um computador o que ele deve fazer. Existem cerca de 400 linguagens reconhecidas.

TipoDescriçãoExemplos
CompiladasTraduzidas em código de máquina ou bytecode por um compiladorC, C++, Java, C#
InterpretadasExecutadas linha a linha por um interpretadorPython, Ruby, JavaScript
Orientadas a dadosOtimizadas para processamento de grandes quantidades de dadosSQL, R, MATLAB
AssemblyLinguagem de baixo nível com nomes para instruções de máquinaUsada em firmware, drivers, microcontroladores

Características das linguagens de programação

CaracterísticaDescrição
ConcorrênciaTratamento de diversas tarefas simultaneamente (processos, tarefas, threads)
Gestão de memóriaAlocação e liberação de memória num programa (manual ou automática)
Memória partilhadaMecanismo que permite vários processos ler e manipular a mesma região de memória
Passagem de mensagensComunicação entre processos via sockets, pipes ou filas de mensagens
Coleta de lixoTécnica de gestão automático de memória (garbage collection)
Tipos de dadosDeterminam que tipo de informação pode ser representada no programa
Entrada e saída (E/S)Mecanismos para ler e gravar dados de e para um programa
Tratamento de errosDetecção e resposta a erros durante a execução de um programa

Sintaxe das linguagens

ElementoDescrição
Procedimentos e funçõesBlocos de código reutilizáveis chamados várias vezes
VariáveisContêineres na memória que armazenam dados
OperadoresPalavras-chave ou símbolos que atribuem valores e realizam operações
Estrutura de controleDeclarações condicionais, loops e exceções que alteram o fluxo de execução

Bibliotecas e vinculação

ConceitoDescrição
BibliotecaColeção de procedimentos e funções combinados num único ficheiro
Vinculação (linking)Combinação de ficheiros binários e bibliotecas pré-compiladas num executável
Vinculação estáticaCódigo da biblioteca incluído no executável final
Vinculação dinâmicaBiblioteca partilhada por todas as aplicações que a utilizam
Versionamento semânticoTrês números separados por pontos (ex.: 2.39.16)

Paradigmas de programação

ParadigmaDescriçãoLinguagens-exemplo
Orientado a objetos (POO)Baseia-se em objetos que encapsulam dados e comportamentoJava, C#, Python
ProceduralExecuta tarefas por meio de procedimentos/blocos de códigoC, Pascal, Fortran
FuncionalEnfatiza funções, imutabilidade e avaliação de expressõesErlang, Haskell, Lisp, Scheme
ImperativaConcentra-se nas instruções para controlar o fluxo de transiçõesC, Assembly
DeclarativaDescreve quais ações tomar sem especificar a ordem de execuçãoSQL, Prolog
NaturalUtiliza linguagem natural para descrever o comportamento do programaScratch, Alice

Código de máquina vs. linguagem assembly

AspetoCódigo de máquinaLinguagem assembly
FormatoPadrões de bits (0s e 1s)Instruções com nomes legíveis
LegibilidadeMuito baixaMuito superior
Uso atualExecução direta pelo hardwareFirmware, drivers, microcontroladores
ConversãoConvertida por um assembler

Compiladores vs. interpretadores

AspetoCompiladorInterpretador
FuncãoTraduz todo o código-fonte para código de máquina ou bytecode antes de executarLê e executa cada linha de código imediatamente
Velocidade de execuçãoMais rápidaMais lenta
FlexibilidadeRequer recompilação após alteraçõesModificações imediatas sem recompilação
Uso típicoAplicações de desempenho (C, C++)Scripts, prototipagem rápida (Python, Ruby)

Bytecode vs. código de máquina

AspetoCódigo de máquinaBytecode
ExecuçãoExecutado diretamente pela CPUExecutado por uma máquina virtual
PortabilidadeDependente da plataformaIndependente da plataforma
DesempenhoMáximoInferior (tradução em tempo de execução)

Exercícios Guiados

Exercício Guiado 1 — Finalidade das funções

Enunciado: Qual a finalidade das funções?

Solução: As funções encapsulam certas atividades comuns, como a saída de uma string. Ao criar uma função, podemos permitir que aquele programa e outros programas executem a função de maneira conveniente e repetida, sem que precisem escrever o próprio código para ela. As funções são blocos de código reutilizáveis que podem ser chamados várias vezes, promovendo a reutilização e a manutenção do código.

Exercício Guiado 2 — Vantagem do bytecode sobre código de máquina

Enunciado: Qual a vantagem do bytecode sobre um ficheiro de código de máquina?

Solução: O ficheiro bytecode pode ser executado em vários computadores diferentes, nos quais uma máquina virtual transforma o código em código de máquina. Assim, por exemplo, o JavaScript é executado em muitos navegadores e em muitos tipos de computadores. O bytecode torna os programas independentes da plataforma, podendo ser executados em qualquer sistema com uma máquina virtual compatível.

Exercício Guiado 3 — Vantagem do código de máquina sobre bytecode

Enunciado: Qual a vantagem de um ficheiro de código de máquina sobre o bytecode?

Solução: O código de máquina é executado o mais rápido possível. O bytecode é executado mais lentamente porque a máquina virtual deve transformá-lo em código de máquina enquanto executa o bytecode. Para aplicações onde o desempenho é crítico, o código de máquina direto é preferível.

Exercício Guiado 4 — Função de um compilador

Enunciado: Qual a função de um compilador no processo de execução de software?

Solução: O compilador é responsável por traduzir o código-fonte escrito numa linguagem de programação de alto nível em código de máquina ou num formato intermediário chamado bytecode. Dentre as linguagens compiladas que produzem código de máquina diretamente estão o C e o C++. Já o Java e o C# produzem bytecode. A escolha entre código de máquina e bytecode depende dos requisitos do projeto, como desempenho, agnosticismo de plataforma e facilidade de desenvolvimento.

Exercícios Exploratórios

Exercício Exploratório 1 — Desvantagens de dividir um programa em processos

Enunciado: Quais as desvantagens de dividir um programa em um grande número de processos ou tarefas?

Quando um programa é dividido em processos, eles precisam se comunicar entre si. Se trabalharem com muitos dados em comum, os processos poderão gastar muita sobrecarga na troca de dados e na proteção contra alterações múltiplas e simultâneas (condições de corrida). Os processos também incorrem em sobrecarga quando são iniciados e finalizados. Quanto mais processos houver, mais complexos se tornam o programa e suas interações, tornando os erros mais difíceis de encontrar. O paradigma funcional tende a facilitar a divisão dos programas em muitos processos, devido à imutabilidade — dados imutáveis não sofrem com condições de corrida.

Exercício Exploratório 2 — Critérios para escolher um pacote de código aberto

Enunciado: Você encontrou vários pacotes de código aberto, oferecidos em diferentes versões, que fornecem os recursos necessários para o seu programa. Quais são os critérios para escolher um pacote?

  • Verifique relatórios de bugs e avisos de segurança dos pacotes, pois alguns apresentam muitos bugs e até são inseguros. Às vezes, a versão mais recente não é a melhor, porque uma falha de segurança pode ter sido introduzida nela.
  • Visite o fórum em que os desenvolvedores conversam sobre o pacote para ver se ele é mantido ativamente. O seu programa provavelmente será usado por bastante tempo e, por isso, o pacote também precisa estar disponível e se manter robusto ao longo do tempo.
  • Experimente diferentes pacotes para verificar o desempenho, bem como a correção.
  • A maioria dos pacotes depende de funções encontradas em outros pacotes (dependências), de modo que uma fraqueza numa das dependências pode afetar o seu programa.

Exercício Exploratório 3 — Outros paradigmas de programação além de POO e procedural

Enunciado: Além dos paradigmas de POO e de desenvolvimento procedural, que outras abordagens de desenvolvimento de software existem? Dê exemplos das linguagens de programação que melhor suportam cada abordagem.

  • Programação funcional: Enfatiza o uso de funções e conceitos matemáticos (lambdas, closures), tratando funções como cidadãs de primeira classe e enfatizando a imutabilidade. Linguagens: Erlang, Haskell, Lisp e Scheme.
  • Linguagens imperativas: Concentram-se nas instruções necessárias para controlar o fluxo das transições do programa de e para diferentes estados.
  • Linguagens declarativas: Descrevem quais ações tomar e a lógica por trás das instruções, sem especificar a ordem de execução. Podem ser reordenadas e otimizadas por compiladores.
  • Programação natural: Utiliza a linguagem natural para descrever o comportamento desejado do programa, tornando a programação acessível a pessoas sem educação formal em ciência da computação. Linguagens: Scratch e Alice.

Exercício Exploratório 4 — Vinculação estática vs. dinâmica

Enunciado: Explique as diferenças entre vinculação estática e vinculação dinâmica, indicando as vantagens e desvantagens de cada uma.

Vinculação estática: O código da biblioteca necessária é incluído diretamente no ficheiro executável do aplicativo final. O executável é maior mas não depende da presença das bibliotecas no sistema em tempo de execução. Pode causar duplicação de código se múltiplos programas usam a mesma biblioteca.

Vinculação dinâmica: Uma biblioteca instalada no sistema é partilhada por todas as aplicações que a utilizam. Atualmente é a abordagem mais usada, caracterizada por ficheiros executáveis menores e menos uso de memória em tempo de execução. No entanto, depende da presença correta das bibliotecas no sistema, podendo causar problemas de compatibilidade entre versões.