051.1 Lição 1
Certificação: |
Open Source Essentials |
---|---|
Versão: |
1.0 |
Tópico: |
051 Os fundamentos do software |
Objetivo: |
051.1 Componentes de software |
Lição: |
1 de 1 |
Introdução
O software live e o software open source — também abreviados como FOSS — já são parte integrante de nossas vidas, mesmo que nem sempre a gente perceba. O FOSS, por exemplo, está presente, de uma maneira ou de outra, por trás de todas as nossas atividades na internet: no computador que usamos para visitar sites no navegador ou nos servidores que armazenam esses sites e os exibem no momento em que digitamos o endereço.
O que é software?
Porém, antes de entrar nos aspectos específicos do software livre e de código aberto, precisamos esclarecer o significado de software. Vamos começar com uma descrição geral: software é a parte não-física, não-material, de qualquer tipo de computador. O software é o que permite que as partes físicas (o hardware) do computador interajam e que o computador possa aceitar comandos e executar tarefas.
Um smartphone, um laptop ou um servidor em um data center são apenas máquinas feitas de metal e plástico quando estão desligadas. Logo que as ativamos, o software é iniciado na forma de sequências de comando codificadas que controlam os componentes individuais daquela máquina, permitem a interação do usuário com ela e realizam tarefas extremamente específicas empregando para isso determinados aplicativos.
Os desenvolvedores de software têm a missão de analisar as tarefas que o computador precisa realizar e especificá-las de forma a permitir que o computador as implemente. As ferramentas usadas pelos desenvolvedores são tão numerosas e variadas quanto as tarefas realizadas pelo software.
Algumas tarefas de software estão intimamente vinculadas ao hardware e à arquitetura do computador, como por exemplo o endereçamento e gerenciamento da memória ou a coordenação dos diferentes processos. Assim, os programadores de sistema trabalham próximos ao hardware.
Por sua vez, os desenvolvedores de aplicativos concentram-se principalmente no usuário, programando soluções que lhe permitam realizar tarefas de maneira eficiente e intuitiva. Um exemplo de aplicativo complexo é um programa de processamento de texto que inclui todas as funções de formatação em menus e botões, além de exibir o texto na forma como ele ficará ao ser impresso.
Em geral, um algoritmo é uma maneira de resolver um problema. Por exemplo, para calcular uma média, o algoritmo normal soma uma série de valores e divide o resultado pelo número total de valores. Embora tradicionalmente os algoritmos sejam projetados e escritos por programadores, hoje em dia eles também podem ser gerados por inteligência artificial.
Os conceitos deste capítulo vão ajudar você a entender os pontos fortes e os riscos associados ao FOSS, tomar decisões informadas e até mesmo definir se deseja se tornar um desenvolvedor de software.
Linguagens de programação
Linguagens de programação são linguagens artificiais altamente estruturadas que dizem a um computador o que deve fazer. Os programas são geralmente escritos em formato texto, mas certas linguagens são escritas em uma forma gráfica. Os desenvolvedores de software escrevem instruções (chamadas de código) para os computadores nessa linguagem artificial. Porém, o hardware do computador não executa esse código diretamente. O hardware só é capaz de executar diretamente uma série de padrões de bits armazenados na memória, chamados de código de máquina ou linguagem de máquina. Todas as linguagens de programação são convertidas em código de máquina por um compilador ou interpretada por outro programa em código de máquina chamado interpretador para fazer com que o hardware execute essas instruções.
Dentre as linguagens de programação mais utilizadas atualmente, podemos mencionar Python, JavaScript, C, C++, Java, C#, Swift e PHP. Cada uma dessas linguagens tem seus pontos fortes e fracos. A escolha da linguagem depende do projeto e das necessidades do desenvolvedor. Assim, o Java é uma escolha comum para o desenvolvimento de aplicativos empresariais em larga escala, enquanto o Python é frequentemente usado para computação científica e análise de dados.
A criatividade dos desenvolvedores no design das linguagens de programação impressiona. Originalmente, tratava-se de linguagens de baixo nível, semelhantes às instruções do computador. Mas essas linguagens foram se tornando cada vez mais de alto nível, ou seja, elas buscam representar combinações de instruções poderosas em termos breves. Algumas linguagens refletem a maneira como os humanos pensam naturalmente, sem deixar de lado o rigor necessário para funcionar corretamente.
Existem atualmente cerca de 400 linguagens de programação reconhecidas, embora muitas sejam usadas apenas em aplicações de nicho ou ambientes legados. Cada uma delas foi desenvolvida para solucionar problemas específicos.
Características, sintaxe e estrutura das linguagens de programação
A escolha da linguagem de programação pode ter um impacto significativo no desempenho, na escalabilidade e na facilidade de desenvolvimento de um projeto de software. As seções a seguir apresentam elementos importantes das linguagens.
Características das linguagens de programação
Estas são algumas características e qualidades comuns das linguagens de programação:
- Concorrência
-
A concorrência denota o tratamento de diversas tarefas simultaneamente, seja executando-as em diferentes processadores de hardware ou alternando as tarefas em um único processador. O grau de concorrência suportado por uma linguagem de programação pode afetar bastante seu desempenho e escalabilidade, especialmente para aplicativos que requerem processamento em tempo real ou grandes quantidades de dados. Cada parte separada do trabalho pode ser chamada de processo, tarefa ou thread.
- Gerenciamento de memória
-
O gerenciamento de memória é a alocação e liberação de memória em um programa. Dependendo da linguagem ou do ambiente de execução, o gerenciamento de memória pode ser feito manualmente pelo programador ou de forma automática. O gerenciamento adequado da memória é essencial para garantir que um programa use a memória de maneira eficaz, evitando o esgotamento da memória e outros problemas. Se um programa não for capaz de liberar a memória não utilizada, ele causará um vazamento de memória, aumentando gradualmente o uso da memória até que o programa trave ou causando efeitos negativos perceptíveis no desempenho.
- Memória compartilhada
-
A memória compartilhada é um tipo de mecanismo de comunicação entre processos que permite que vários processos leiam e manipulem uma mesma região da memória. A memória compartilhada é comum em dispositivos de hardware como as unidades de disco. Ela também pode ser uma forma eficiente de compartilhar dados entre processos. Mas esse mecanismo requer uma sincronização e um gerenciamento cuidadosos para evitar a corrupção de dados. Um erro conhecido como condição de corrida (race condition) ocorre quando um processo faz uma alteração imprevista nos dados enquanto outro processo os utiliza.
- Passagem de mensagens
-
A passagem de mensagens é um mecanismo de comunicação entre processos que lhes permite trocar dados e coordenar suas atividades. Ela é comumente usada em programação simultânea para estabelecer a comunicação entre processos e pode ser implementada por meio de diferentes mecanismos, como sockets, pipes ou filas de mensagens.
- Coleta de lixo
-
A coleta de lixo (garbage collection) é uma técnica de gerenciamento automático de memória empregada por algumas linguagens de programação para recuperar a memória que não está mais sendo usada enquanto um processo está em execução. Isso ajuda a evitar vazamentos de memória e facilita a criação de código correto e eficiente, mas também pode levar a uma sobrecarga de desempenho e dificultar o controle fino sobre o comportamento do programa.
- Tipos de dados
-
Os tipos de dados determinam que tipo de informação pode ser representado no programa. Os tipos de dados podem ser predefinidos na linguagem ou definidos pelo usuário e podem incluir números inteiros, números de ponto flutuante (ou seja, aproximações de números reais), cadeias de caracteres, matrizes e outros.
- Entrada e saída (E/S)
-
Entrada e saída são mecanismos para ler e gravar dados de e para um programa. A entrada pode vir de diversas fontes, como cliques do usuário e entrada do teclado, um arquivo ou uma conexão de rede, ao passo que a saída pode ser enviada para uma variedade de destinos, como um monitor, um arquivo ou uma conexão de rede. A E/S permite que os programas interajam com o mundo exterior e troquem informações com outros sistemas.
- Tratamento de erros
-
O tratamento de erros detecta e responde aos erros que ocorrem durante a execução de um programa. Isso inclui erros como divisão por zero e um arquivo solicitado que não tenha sido encontrado. O tratamento de erros permite que os programas continuem em execução mesmo quando ocorrem erros, aprimorando sua confiabilidade e robustez.
Os conceitos listados acima são fundamentais para entender como as linguagens de programação funcionam e como escrever código eficiente e de fácil manutenção.
A sintaxe das linguagens de programação
A sintaxe de uma linguagem de programação refere-se às regras para escrever instruções e expressões de programas. É importante que a sintaxe seja bem definida e consistente, para que o programador possa escrever e compreender efetivamente seu código. Eis os blocos de construção usados na maioria das linguagens de programação:
- Procedimentos e funções
-
Procedimentos e funções são usados para definir blocos de código reutilizáveis que podem ser chamados várias vezes.
- Variáveis
-
As variáveis representam contêiners na memória. Elas armazenam dados que podem ser manipulados e repassados entre procedimentos e funções.
- Operadores
-
Operadores são palavras-chave ou símbolos (como
+
e-
) que atribuem valores às variáveis e realizam operações aritméticas. - Estrutura de controle
-
Geralmente, o código do programa é executado na ordem em que foi escrito, mas declarações condicionais alteram o fluxo de execução. O código executado a seguir depende de diversas condições, como o conteúdo da memória, o estado do teclado, os pacotes que chegam da rede e assim por diante. A declaração loop, uma forma especial de declaração condicional, é útil para executar as mesmas operações em uma série de conjuntos de dados. Uma exceção, que invoca um código especial quando ocorre um erro, é outra estrutura de controle.
A sintaxe e o comportamento dessas construções podem variar de acordo com a linguagem de programação. A escolha da linguagem tem um grande impacto na legibilidade e na manutenção do código.
Bibliotecas
Uma boa linguagem de programação deve facilitar o desenvolvimento de programas e a reutilização do código existente. Muitas linguagens de programação incluem um mecanismo para organizar procedimentos e funções em peças que podem ser reutilizadas em outros programas.
Uma biblioteca é uma coleção de procedimentos e funções que suportam um recurso ou objetivo específico, combinados em um único arquivo. A disponibilidade de muitas bibliotecas fáceis de usar é outro requisito muito importante de uma boa linguagem de programação. Por exemplo, o Python é amplamente reconhecido como uma boa linguagem para o desenvolvimento de programas relacionados à IA porque possui uma série de bibliotecas adequadas para processamento de IA.
Com o aumento do tamanho e da complexidade dos programas, a importância das bibliotecas como blocos de construção prontos para usar é cada vez maior. Isso vale principalmente para o mundo do código aberto, onde as pessoas se sentem confortáveis em pegar códigos criados por outros e reutilizá-los. Assim, um ecossistema de bibliotecas foi desenvolvido para cada linguagem de programação. Gerenciadores de pacotes como o composer
para PHP, o pip
para Python e o gems
para Ruby facilitam a instalação de bibliotecas.
As bibliotecas também são importantes nas linguagens compiladas. A combinação de diversos arquivos binários e bibliotecas pré-compiladas para obter um único arquivo executável é chamada de vinculação, e a ferramenta que executa essa operação é chamada de vinculador. Existem dois tipos de vinculação: a vinculação estática, em que apenas o código da biblioteca necessária é incluído no arquivo executável do aplicativo final, e a vinculação dinâmica, em que uma biblioteca instalada no sistema é compartilhada por todos os aplicativos que a utilizam. Atualmente, a vinculação dinâmica é a abordagem mais usada. Ela se caracteriza por arquivos executáveis menores e menos uso de memória em tempo de execução.
Uma vez que as mesmas bibliotecas podem ser usadas por diversos programas, as diferenças entre as versões de uma biblioteca podem causar um problema ainda maior do que com os aplicativos. Vamos relembrar como interpretar os números de versão. Usamos geralmente o versionamento semântico. Ele designa as versões com três números separados por pontos. Uma versão típica poderia ser 2.39.16
, o que indica que estamos na versão principal 2 (um número que provavelmente só será alterado após alguns anos), sendo a versão secundária dentro da principal a 39 (podendo ser atualizada a cada poucos meses, com alterações importantes de recursos) e uma revisão rápida com o número 16 (que pode mudar após a correção de um único bug). As versões e revisões posteriores terão números mais altos.
Um exemplo bem simples
Vejamos um exemplo bem simples de um programa de computador na linguagem Python para termos uma ideia aproximada de alguns dos elementos mencionados.
Traduzindo em linguagem natural, o programa deverá fazer o seguinte: “Peça ao usuário para inserir um número e verifique se esse número é par ou ímpar. Por fim, mostre o resultado.”
E aqui está o código que podemos salvar no arquivo simpleprogram.py
:
num = int(input("Digite um número: ")) if (num % 2) == 0:
print("O número fornecido é PAR.")
else:
print("O número fornecido é ÍMPAR.")
Mesmo nessas poucas linhas de código, podemos encontrar muitas das características e elementos de sintaxe mencionados acima:
-
Na linha 1, definimos a variável
num
e atribuímos a ela um valor com o operador=
. -
O valor atribuído corresponde à entrada do usuário (por meio da função
input()
). Além disso, a funçãoint()
garante que essa entrada seja convertida para o número inteiro tipo de dados, se possível. A expressão passada para uma função entre parênteses é chamada de parâmetro ou argumento. -
Se o usuário inserir uma sequência de letras, o Python imprimirá um erro como parte de seu tratamento de erros. Se um número decimal for inserido, a função
int()
o converterá para o número base, por exemplo,5.73
será convertido para5
. -
Nas linhas a seguir, a estrutura de controle que indica uma condição, com as palavras-chave
if
eelse
, controla o que acontece em cada um dos dois casos possíveis (o número é par ou é ímpar). -
Primeiro, o operador modulo
%
testa se (if
) a divisão do número inserido por 2 produz o valor 0 (ou seja, sem resto) — neste caso, o número é par. O==
duplo é o operador de comparação “é igual a”, que é diferente do operador de atribuição=
na linha 1. -
No outro caso (
else
), ou seja, quando a divisão por 2 produzir um resultado diferente de 0, o número digitado deve ser ímpar. -
Em ambos os casos, a função
print()
retorna o resultado como saída em formato de texto.
E é assim que fica quando executamos o programa na linha de comando:
$ python simpleprogram.py Digite um número: 5 O número fornecido é ÍMPAR.
Quando consideramos quanta lógica de linguagem já está contida neste pequeno exemplo, dá pra ter uma ideia do que um software complexo, distribuído em milhares de arquivos, é capaz; por exemplo, sistemas operacionais como Microsoft Windows, macOS ou Linux, que permitem o acesso a todo o hardware de um computador e, ao mesmo tempo, garantem que os usuários possam instalar todos os aplicativos desejados e utilizá-los para trabalho ou diversão.
Código de máquina, linguagem assembly e assemblers
Como já dissemos, o hardware pode executar diretamente apenas uma série de padrões de bits chamados de código de máquina. A CPU lê um padrão de bits da memória em unidades de uma palavra (8 a 64 bits) e executa a instrução respectiva. As instruções individuais são bem simples; por exemplo, “copiar o conteúdo do local de memória A para o local de memória B”, “multiplicar o conteúdo do local de memória C pelo conteúdo do local de memória D” ou “ler os dados que chegaram ao dispositivo no endereço X”. Na era das CPUs de 8 bits, algumas pessoas eram capazes de memorizar todos os padrões de bits usados no código de máquina e escrever programas diretamente. Hoje em dia, o número de padrões de instrução aumentou em uma ordem de grandeza — assim, tentar decorar todos esses padrões seria impraticável.
O código de máquina é uma sequência de padrões de bits, ou 0s e 1s, o que não é nem um pouco intuitivo para nós humanos. Para tornar a programação mais intuitiva, foi criada a linguagem assembly, na qual as instruções recebiam nomes e podiam ser especificadas por strings (conjuntos de caracteres). Na linguagem assembly, as instruções que correspondem individualmente ao código de máquina são escritas uma a uma. As instruções ficam assim:
move [B], [A] copiar o conteúdo da memória A para a memória B multi R1, [C], [D] multiplicar o conteúdo da memória C pelo conteúdo da memória D input R1, [X] ler os dados que chegaram ao dispositivo no endereço X
Uma instrução em linguagem assembly corresponde a uma instrução em código de máquina, a qual corresponde à instrução exata que o hardware pode compreender e executar. Eis algumas vantagens da linguagem assembly sobre a linguagem de máquina:
- Melhor legibilidade e facilidade de manutenção
-
A linguagem assembly é muito mais fácil de ler e escrever do que o código de máquina. Ou seja, fica mais fácil para os programadores entender, depurar e manter o código.
- Automação da computação de endereços
-
A programação em código de máquina também pode usar o conceito de variáveis e funções, mas tudo deve ser expresso em termos de endereços de memória. A linguagem assembly também atribui nomes aos endereços de memória, o que facilita a expressão da lógica de um programa.
Como a linguagem assembly tem acesso a todas as funcionalidades do hardware, ela é comumente usada nas seguintes situações:
- Parte dependente da arquitetura do sistema operacional
-
O uso de instruções dedicadas específicas a uma arquitetura de CPU, para acesso aos recursos de inicialização e segurança, pode ser feito somente em linguagem assembly.
- Desenvolvimento de componentes de sistema de baixo nível
-
A linguagem assembly é usada para desenvolver componentes de sistema que precisam interagir diretamente com o hardware do computador, como drivers de dispositivo, firmware e o sistema básico de entrada/saída (BIOS). Em particular, dispositivos de alta velocidade que exigem levar o desempenho do hardware ao seu limite geralmente necessitam de drivers e firmware programados em linguagem assembly.
- Programar microcontroladores
-
O código de máquina também é usado para programar microcontroladores, que são computadores pequenos e de baixa potência usados em uma ampla gama de sistemas embarcados, de brinquedos a controle industrial. Certos microcontroladores têm capacidades de memória de somente algumas centenas de bytes e são comumente programados em linguagem assembly.
O código da linguagem assembly é convertido em código de máquina antes de ser executado por um aplicativo chamado assembler. O assembler é a ferramenta de programação mais antiga; ele trouxe uma série de vantagens que seriam impensáveis na programação em código de máquina. Para confundir as coisas, às vezes as pessoas se referem à linguagem assembly como assembler.
O código de máquina e a linguagem assembly diferem de um processador para outro. Elas são chamadas de “linguagens de baixo nível”, pois operam diretamente no hardware. No entanto, os conceitos de computação e entrada/saída são os mesmos em todos os processadores. Se os conceitos comuns forem expressos de uma forma mais fácil de ser compreendida pelos humanos, a eficiência da programação é drasticamente aprimorada. É aqui que entram as “linguagens de alto nível”.
Linguagens compiladas
Linguagens compiladas são linguagens de programação traduzidas em código de máquina ou em um formato intermediário chamado bytecode. O bytecode é executado no computador de destino por uma máquina virtual em tempo de execução. A máquina virtual traduz o bytecode para o código de máquina adequado para cada computador. Graças ao bytecode, os programas se tornam independentes da plataforma, podendo ser executados em qualquer sistema com uma máquina virtual compatível.
A tradução do código-fonte escrito em uma linguagem de programação de alto nível em código de máquina ou bytecode é feita por um compilador. 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.
Linguagens interpretadas
Linguagens interpretadas são linguagens de programação executadas por um interpretador, em vez de serem compiladas em código de máquina. O interpretador lê o código-fonte e executa as instruções nele contidas. Um interpretador é capaz de processar diretamente o código-fonte sem transformá-lo em outro formato de arquivo. Assim, ao contrário de um compilador, que traduz todo o programa em código de máquina antes de executá-lo, um interpretador lê cada linha de código e a executa imediatamente, permitindo ao programador ver os resultados de cada linha conforme são executadas.
As linguagens interpretadas costumam ser usadas para criar scripts, ou seja, programas curtos que automatizam tarefas, além de interfaces de linha de comando e controle de lotes (batches) e tarefas. Os scripts escritos em linguagens interpretadas podem ser facilmente modificados e executados sem a necessidade de recompilação, sendo assim adequados para tarefas que requerem prototipagem rápida ou iteração rápida e flexível. Essa conveniência traz algumas desvantagens em potencial. Por exemplo, um programa interpretado é executado mais lentamente do que um equivalente compilado.
Dentre as linguagens interpretadas podemos citar o Python, o Ruby e o JavaScript. O Python é amplamente utilizado em computação científica, análise de dados e aprendizado de máquina, enquanto o Ruby é frequentemente empregado em desenvolvimento web e para criar scripts de automação. O JavaScript é uma linguagem de script do lado do cliente incorporada em navegadores web para criar páginas web dinâmicas e interativas.
Linguagens orientadas a dados
Linguagens orientadas a dados são linguagens de programação otimizadas para processamento e manipulação de grandes quantidades de dados. Elas são projetadas para lidar de forma eficiente com grandes conjuntos de dados, estruturados ou não, e fornecem um conjunto de ferramentas para trabalhar com bancos de dados, estruturas de dados e algoritmos para processamento e análise de dados.
As linguagens orientadas a dados são usadas em uma diversidade de aplicações, incluindo ciência de dados, análise de big data, aprendizado de máquina e programação de bancos de dados. Elas são perfeitas para tarefas que envolvem processamento e análise de grandes quantidades de dados, como limpeza e transformação de dados, visualização de dados e modelagem estatística.
As linguagens orientadas a dados mais famosas são o SQL (abreviação de Structured Query Language), o R e o MATLAB. O SQL é uma linguagem padrão usada para gerenciar bancos de dados relacionais, amplamente utilizada no mundo empresarial e na indústria. O R é uma linguagem de programação e um ambiente para computação estatística e gráfica, muito usada em ciência de dados e aprendizado de máquina. O MATLAB é um ambiente de computação numérica e uma linguagem de programação usada em uma ampla gama de aplicações, incluindo processamento de sinais, processamento de imagens e finanças computacionais.
Paradigmas de programação
Além das especificidades das linguagens de programação, os paradigmas de programação determinam a abordagem específica da solução. Podemos pensar num paradigma como uma estratégia básica com a qual abordamos uma tarefa, dependendo dos requisitos e condições específicas.
Um exemplo comparável é a construção de uma casa: os pedreiros podem erguer as paredes tijolo por tijolo ou usar componentes de concreto pré-fabricados montados no local. Essa é uma decisão fundamental que depende dos requisitos e das circunstâncias. Quais características desejamos para a casa? Onde ela está localizada? Ela estará conectada a outras casas?
Os paradigmas definem a direção da programação de um jeito parecido: por exemplo, um projeto de software será dividido em partes menores e separadas? E de que forma? Cada linguagem de programação será mais adequada a um paradigma específico. Portanto, a escolha do paradigma está intimamente relacionada à escolha da linguagem de programação.
Os seguintes paradigmas são comuns em programação:
- Programação orientada a objetos (POO)
-
a POO baseia-se no conceito de objetos, que são instâncias de classes que encapsulam dados e comportamento. Por exemplo, uma linguagem pode oferecer um retângulo como classe para ajudar o programador a exibir uma caixa na tela.
A POO se concentra na manipulação de dados em nível de objeto. Com a POO, é mais fácil escrever código de fácil manutenção, reutilizável e extensível. Ela é amplamente utilizada em programas para desktop, videogames e aplicativos web. Dentre as linguagens de programação orientadas a objetos temos Java, C# e Python.
- Programação procedural
-
A programação procedural executa tarefas por meio de procedimentos, ou blocos de código que podem ser executados em uma ordem específica. Isso facilita a escrita de código estruturado e fácil de seguir, mas pode levar a um código menos flexível e mais difícil de manter à medida que o tamanho e a complexidade do projeto aumentam. Como exemplos de linguagens de programação procedurais, temos C, Pascal e Fortran.
Atualmente, existem outras abordagens para o desenvolvimento de software. Certas linguagens são mais adequadas a elas do que outras. Além disso, as interfaces de arrastar e soltar permitem que não-programadores escrevam programas, e muitos serviços online começaram recentemente a gerar código por meio de inteligência artificial quando recebem instruções em linguagem simples.
Em conclusão, cada paradigma de programação tem seus próprios pontos fortes e fracos. A escolha do paradigma geralmente depende das necessidades do projeto, da experiência e preferências do desenvolvedor e das restrições da plataforma e do ambiente de desenvolvimento. Compreender os diferentes tipos de paradigmas pode ajudar você a escolher o paradigma certo para suas necessidades e também a escrever um código melhor e mais eficiente.
Exercícios Guiados
-
Qual a finalidade das funções?
-
Qual a vantagem do bytecode sobre um arquivo de código de máquina?
-
Qual a vantagem de um arquivo de código de máquina sobre o bytecode?
Exercícios Exploratórios
-
Quais as desvantagens de dividir um programa em um grande número de processos ou tarefas?
-
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?
-
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.
Resumo
Nesta lição, você aprendeu o que é software e como ele é desenvolvido com a ajuda de linguagens de programação. As diversas linguagens de programação não diferem apenas na sintaxe, mas também, por exemplo, no gerenciamento de recursos de hardware ou no manuseio de estruturas de dados.
As linguagens de programação também diferem na forma como o código-fonte, legível por humanos, é convertido por um interpretador ou compilador para o código de máquina final a ser processado pelo computador.
Os paradigmas de programação determinam a estratégia dos projetos de software e, portanto, também a escolha das linguagens de programação adequadas, dependendo dos requisitos e da dimensão do projeto específico.
Respostas aos Exercícios Guiados
-
Qual é a finalidade das funções?
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 seu próprio código para ela.
-
Qual é a vantagem do bytecode sobre um arquivo de código de máquina?
O arquivo 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.
-
Qual é a vantagem de um arquivo de código de máquina sobre o bytecode?
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.
Respostas aos Exercícios Exploratórios
-
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. Os dados imutáveis não sofrem de condições de corrida.
-
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é mesmo 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. 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 seu desempenho, bem como sua correção.
A maioria dos pacotes depende de funções encontradas em outros pacotes (dependências), de modo que uma fraqueza em uma das dependências pode afetar seu programa.
-
Além dos paradigmas de POO e de desenvolvimento procedural, que outras abordagens de desenvolvimento de software existem? Dê exemplos de linguagens de programação que melhor suportam cada abordagem.
Além do POO e dos paradigmas de desenvolvimento procedural, também podemos citar:
A programação funcional enfatiza o uso de funções e conceitos matemáticos, como lambdas e closures, para escrever código baseado na avaliação de expressões em vez da execução de instruções. A programação funcional trata as funções como cidadãs de primeira classe — para que possam ser manipuladas pelo programa — e enfatiza a imutabilidade, ou o trabalho com variáveis que não podem mudar depois de serem inicialmente definidas. Dessa forma é mais fácil refletir a respeito do código e testá-lo, bem como escrever aplicativos simultâneos e paralelos. Dentre as linguagens de programação funcionais estão Erlang, Haskell, Lisp e Scheme.
As linguagens imperativas concentram-se nas instruções necessárias para controlar o fluxo das transições do programa de e para diferentes estados.
As linguagens declarativas descrevem quais ações tomar e a lógica por trás das instruções. A ordem em que as instruções são executadas não é especificada. Essas instruções, as chamadas de função e outros comandos podem ser reordenados e otimizados por compiladores, desde que a lógica subjacente seja mantida.
A programação natural é um paradigma de programação que utiliza a linguagem natural ou outras representações amigáveis para descrever o comportamento desejado de um programa. A ideia é tornar a programação acessível a pessoas que talvez não tenham uma educação formal em ciência da computação. Como exemplos de linguagens de programação naturais, podemos citar Scratch e Alice.