Este artigo vai abordar os algoritmos, que são sequências de instruções para resolver problemas, e as linguagens de programação, que são as ferramentas que usamos para implementar (construir) esses algoritmos.
Apresentação
Programar, ou desenvolver um software, é basicamente criar um passo a passo para o computador seguir. Para isso, a gente escreve instruções usando uma linguagem específica, chamada linguagem de programação, que o computador consegue entender.
Assim, conseguimos fazer o computador realizar tarefas do jeito que queremos. Claro, essas tarefas estão limitadas as capacidades do computador, seu hardware e software.
Não adianta pedir para o PC da sua casa levantar voo, por exemplo, que (sem os recursos adequados para isso) ele não vai conseguir.
Essas instruções são chamadas de algoritmos. É como se você estivesse mostrando para o computador, passo a passo, o que ele precisa fazer para cumprir uma tarefa. O algoritmo nada mais é do que uma explicação simples do caminho que o computador deve seguir para chegar ao resultado que você quer.
Ao longo deste texto, vamos explorar mais sobre algoritmos e como eles são fundamentais na programação. Vamos também discutir as diferentes linguagens de programação que podemos usar para implementar esses algoritmos.
Algoritmos
Esses algoritmos citados antes, que são sequências de instruções para resolver problemas adequados as limitações (restrições ou condições) do computador, são chamados de algoritmos computacionais. Esses algoritmos são construídos pensando em como o computador vai entender e executar as instruções, levando em conta sua arquitetura e capacidade de processamento.
Mas não pense que só existem algoritmos na computação! Podemos criar uma lista de passos para quase tudo na vida: atravessar a rua, fazer um bolo ou dar banho no cachorro, por exemplo.
Algoritmo é só isso, uma sequência de instruções para chegar ao resultado que queremos.
Como construir um algoritmo?
Para fazer um algoritmo, primeiro é preciso entender bem o problema que queremos resolver. Depois, é só dividir a solução em passos simples, pensando em cada etapa como uma parte do caminho até chegar ao resultado que procuramos.
Esses passos não podem ser genéricos (muito amplos, com poucos detalhes e que dependem de entrelinhas e dedução) ou confusos; eles precisam ser bem explicados, simples e seguir uma ordem. Assim, fica fácil entender e acompanhar cada etapa.
Na hora de criar um algoritmo, pense nessas coisas:
- O que você quer resolver?
- Explique qual é o problema ou objetivo, de um jeito simples.
- O que precisa para começar?
- Liste o que vai ser usado ou o que tem que estar pronto antes de começar.
- O que deve acontecer no final?
- Diga o que espera que aconteça quando terminar.
- Tem algo especial que precisa?
- Fale se tem alguma condição especial antes de começar.
- Quais são os passos?
- Escreva o passo a passo, de forma clara e simples.
- E se der erro?
- Conte o que fazer se algo não sair como esperado.
- Quando parar?
- Mostre em que momento o algoritmo termina.
A seguir vamos exercitar (praticar) a construção de algoritmos, aplicando este passo a passo (conjunto de etapas) a situações do dia a dia.
Exemplo de algoritmo: como fazer café
- Objetivo:
- Fazer 300 ml de café coado.
- O que você vai precisar:
- água,
- pó de café,
- filtro,
- coador,
- chaleira,
- xícara ou jarra
- e algo para esquentar a água pode ser um fogão ou micro-ondas.
- O que vai sair:
- 300 ml de café pronto.
- Antes de começar:
- Verifique se tudo está limpo e se tem água potável.
- Passo a passo:
- Coloque cerca de 18 gramas de pó de café (mais ou menos 3 colheres de sopa rasas) no filtro.
- Esquente 300 ml de água até quase ferver (quando começam a aparecer bolhinhas).
- Se o filtro for de papel:
- Molhe o filtro com um pouco de água quente para tirar o gosto de papel e já aproveite para esquentar a xícara; depois, jogue fora essa água.
- Despeje um pouco de água quente (uns 40 ml) por cima do pó, só para molhar tudo. Espere uns 30 a 45 segundos, isso ajuda a soltar bem o sabor do café.
- Depois vá despejando o resto da água quente devagar, até terminar.
- Espere toda a água passar pelo pó para cair na xícara ou jarra.
- Se o filtro NÃO for de papel:
- Não precisa molhar o filtro
- Siga os mesmos passos sem molhar o filtro.
- Pronto, é só servir!
- Se tiver algum problema:
- Se não conseguir esquentar a água porque, por exemplo, o fogão não funciona, pare e tente resolver antes de continuar.
- Se a água não estiver passando pelo pó (talvez porque o pó está muito fino e entupiu), mexa devagar com uma colher para destravar e seguir.
- Quando termina:
- Quando toda a água tiver passado pelo pó e você tiver os 300 ml de café pronto.
Isso mostra como um algoritmo pode ser aplicado a uma tarefa do dia a dia, como fazer café. Ele ajuda a organizar o pensamento e a garantir que todos os passos necessários sejam seguidos para alcançar o resultado desejado.
Vamos fazer mais um exemplo a seguir…
Exemplo de algoritmo: como dar banho em um cachorro
- Objetivo:
- Lavar e deixar o cachorro limpinho.
- O que você vai precisar:
- água,
- shampoo para cachorro,
- toalha,
- secador (opcional),
- coleira ou guia,
- lugar apropriado para o banho.
- O que vai sair:
- Um cachorro limpo e seco.
- Antes de começar:
- Verifique se tudo está à mão e se o cachorro está calmo.
- Passo a passo:
- Coloque a coleira ou guia no cachorro.
- Molhe bem todo o pelo do cachorro com água morna.
- Aplique o shampoo e esfregue bem, por cerca de 2 a 3 minutos.
- Enxágue completamente até sair toda a espuma.
- Seque o cachorro com uma toalha, removendo o excesso de água.
- Se o dia estiver frio, use um secador na temperatura morna e à distância para secar o pelo.
- Se não estiver frio, use só a toalha para secar o pelo do cachorro.
- Certifique-se de que o pelo está completamente seco antes de soltar o cachorro.
- Pronto!
- Se tiver algum problema:
- Se o cachorro ficar muito agitado, pare e espere ele se acalmar antes de continuar.
- Se o shampoo causar irritação, enxágue imediatamente e consulte um veterinário.
- Se o cachorro não quiser entrar no banho, tente atraí-lo com um brinquedo ou petisco.
- Quando termina:
- Quando o cachorro estiver limpo e seco.
Esses exemplos servem para mostrar como um algoritmo pode ajudar a organizar o pensamento e a garantir que todos os passos necessários sejam seguidos para alcançar o resultado desejado. Claro que, os exemplos que foram usados aqui podem ser ainda mais refinados (detalhados), o ideal é refinar (detalhar) o algoritmo conforme a necessidade e complexidade (nível de dificuldade) da tarefa.
Não é bom tentar resolver um problema muito complexo de uma vez só, é melhor dividir em partes menores e ir resolvendo uma de cada vez. Ou seja, dividir para conquistar, “quebrar” (cortar) o problema em pedaços menores e mais fáceis de trabalhar até que, no final, o problema todo esteja solucionado.
Linguagens de Programação
Agora que já conhecemos o que são os algoritmos, inclusive com a criação de exemplos, vamos falar sobre as linguagens de programação.
Uma linguagem de programação é um jeito de conversar com o computador. Por meio dela, pessoas escrevem comandos que o computador entende e faz o que foi pedido. Assim, a linguagem de programação serve como uma ponte entre quem usa o computador e o que ele realmente faz.
Como foi explicado com detalhes em: Computação para Iniciantes: Programas ou Softwares - Linguagens de Programação.
Código-fonte
Quando alguém escreve comandos numa linguagem de programação, está criando um código-fonte. Esse código é como uma receita, mostrando passo a passo o que o programa deve fazer.
Ele tem dois grandes objetivos:
- facilitar a vida de quem lê o programa (outras pessoas programadoras),
- permitir que o computador execute o que foi pedido.
Para o computador entender esse código, ele pode ser transformado de duas formas principais:
- Compilação:
- Um programa chamado compilador pega todo o código-fonte de uma vez e traduz para uma linguagem de máquina, que o computador entende.
- Depois que vira esse “arquivo traduzido” (chamado binário), o computador só precisa ler esse arquivo sempre que rodar (executar) o programa, sem precisar traduzir de novo, só se o programa mudar aí precisa compilar de novo.
- Interpretação:
- Nesse caso, um programa chamado interpretador lê e executa o código-fonte linha por linha, cada vez que o programa for usado.
- Ele traduz e executa ao mesmo tempo, toda vez que você roda (executa) o programa.
Linguagens compiladas e linguagens interpretadas
Quando a gente fala que uma linguagem é “interpretada” ou “compilada”, isso quer dizer só como o código dela é rodado (executado), não o tipo de linguagem. Na verdade, várias linguagens podem ser usadas dos dois jeitos, dependendo de como são feitas.
Dá para usar jeitos (técnicas) diferentes para executar o código, como:
- JIT (compilação na hora),
- AOT (compilação antes de executar),
- bytecode (um código intermediário),
- máquinas virtuais (que são ambientes que simulam um computador para executar programas).
Mesmo assim, vale a pena saber a diferença entre cada jeito (técnica ou abordagem) de executar um código.
Linguagens compiladas
Nas linguagens compiladas (AOT), o código que você escreve passa por várias etapas:
- Primeiro, é analisado e transformado em uma estrutura que o computador entende.
- Depois, recebe melhorias e vira uma versão intermediária.
- Por fim, esse código é convertido para uma linguagem que a máquina entende direto, como x86 ou ARM, e vira um programa pronto para ser executado.
Observação: x86 e ARM são tipos de arquiteturas de processadores, e cada uma tem seu próprio conjunto de instruções que o computador entende. O que se compila para x86 não funciona em ARM e vice-versa, a menos que seja feito um trabalho extra para adaptar o código.
Desse jeito, o programa já está pronto para executar, sem precisar de passos extras. Ele funciona direto e costuma ser rápido, além de poder ser enviado como um arquivo que é só abrir para usar. Por outro lado, leva mais tempo para “compilar” e você precisa repetir esse processo para cada tipo de computador (arquitetura de processador como x86 ou ARM) ou sistema operacional diferente.
Linguagens interpretadas
Nas linguagens interpretadas, funciona de outro jeito. Normalmente, o código vira um tipo de “meio termo”, chamado bytecode
(como os arquivos .pyc
do Python), e aí uma máquina virtual lê e executa esse bytecode. Em alguns casos, o interpretador pode executar o código direto, sem precisar transformar antes.
Algumas linguagens usam JIT (Just-In-Time em português “compilação em tempo real”), que transforma partes do código em instruções nativas enquanto estão sendo usadas. A vantagem é que dá para escrever e executar o código quase na hora, e é fácil usar em diferentes computadores, desde que tenha a máquina virtual.
Por outro lado, o programa geralmente demora mais para começar e pode precisar de um “aquecimento” (warm-up que é um período inicial de execução onde o desempenho melhora gradualmente, ou seja, o programa se torna mais rápido à medida que é executado) para chegar ao desempenho das compiladas.
Comparando as duas abordagens (compilação vs interpretação)
Fazendo uma comparação entre as duas modalidades de execução de código é possível dizer que: linguagens compiladas costumam ser mais rápidas logo de cara, enquanto as interpretadas com JIT podem ficar tão rápidas quanto, ou até mais, depois de um tempo de uso.
A portabilidade também muda: interpretadas são mais fáceis de usar em diferentes máquinas, porque só dependem da máquina virtual, enquanto compiladas precisam ser feitas de novo para cada sistema. Compiladas entregam programas prontos, enquanto interpretadas normalmente distribuem código que dependem de um ambiente virtual para serem executados.
As ferramentas para depurar (que significam encontrar e corrigir erros no código) e observar o código (para entender seu funcionamento) também mudam:
- compiladas usam arquivos de símbolos, que são dados extras, gerados enquanto o código é compilado, para ajudar no futuro em tarefas como depuração (encontrar e corrigir erros) e análise de desempenho.
- interpretadas costumam ter ambientes interativos (REPL - Read-Eval-Print Loop em português significa “Leia-Avalie-Imprima”), esses ambientes são ferramentas que permitem escrever e testar código rapidamente, linha por linha, facilitando a experimentação (verificar o que o código faz).
Na segurança, compiladas usam medidas como proteção de memória, enquanto interpretadas ou JIT fazem verificações durante a execução. Isso quer dizer que as compiladas podem oferecer mais segurança em alguns casos, mas as interpretadas podem ser mais flexíveis e adaptáveis.
Explicando de um outro jeito: as linguagens compiladas geralmente são mais rígidas e exigem que o código esteja completo e correto antes da execução, enquanto as interpretadas permitem ajustes e testes mais dinâmicos (em tempo real) durante a execução.
Exemplos de linguagens compiladas são:
- C
- C++
- Rust
- Go
- Ada
- Fortran
- Pascal
- Objective-C
- Swift
Enquanto as linguagens interpretadas incluem:
- Python
- Ruby
- JavaScript
- PHP
- Perl
- Lua
- R
Existem ainda linguagens que usam uma mistura de bytecode e JIT. Isso quer dizer que elas compilam o código para um formato intermediário (bytecode) e depois usam JIT (Just-In-Time ou compilação em tempo real) para transformar partes desse bytecode em código nativo enquanto o programa está sendo executado. Exemplos dessas linguagens são:
- Java
- Kotlin
- C# e .NET
- Clojure
- Scala
- Elixir
- Erlang
No fim das contas, o que define se uma linguagem é interpretada ou compilada é a implementação. Por exemplo, Python é chamado de interpretado, mas existem ferramentas que permitem transformar o código em executável compilado, como PyPy, Cython e Nuitka (que são compiladores alternativos para Python).
Na prática, as compiladas são melhores para sistemas que precisam de rapidez, pouco gasto de memória e desempenho alto, como programas de linha de comando, serviços críticos e sistemas embarcados.
As interpretadas ou híbridas são ótimas para desenvolvimento rápido, protótipos, ciência de dados e aplicações que precisam funcionar em vários sistemas diferentes. Em situações em que o tempo de início tem que ser muito rápido, como em serviços serverless, muitas linguagens passam a usar compilação antecipada, mesmo que normalmente dependam de máquinas virtuais.
Paradigmas de programação
As linguagens de programação podem funcionar de maneiras diferentes, chamadas de paradigmas. Tem linguagem que segue só um jeito, e tem linguagem que permite misturar vários. Cada forma tem suas próprias regras e jeitos de pensar, facilitando ou complicando dependendo do que você quer fazer.
Você pode imaginar os paradigmas de programação como tipos ou estilos diferentes que organizam as linguagens de programação. Algumas linguagens se encaixam em um único tipo, enquanto outras podem combinar vários estilos ao mesmo tempo.
É como se fosse uma filosofia que ensina a pensar e resolver problemas com a programação, influenciando o passo a passo, desde criar as ideias até colocar o sistema em funcionamento e cuidar dele depois.
Os paradigmas são importantes porque mostram diferentes formas de resolver um mesmo problema usando programação, dependendo do estilo escolhido, você pode encontrar caminhos diferentes para chegar na solução.
Eles também influenciam em como o código vai ficar para quem precisar ler, arrumar ou aumentar o programa depois. Por isso, escolher um paradigma pode facilitar (ou complicar) o trabalho em equipe e a manutenção do sistema.
Os paradigmas de programação mais comuns serão apresentados a seguir:
- Imperativo / Procedural:
- No jeito imperativo ou procedural de programar, você escreve o que o computador tem que fazer, passo a passo, como se fosse uma lista de tarefas. Dá para mudar valores, criar listas, repetir comandos e escolher caminhos usando “se” ou “enquanto”.
- Esse estilo é bem direto, igual seguir instruções. Linguagens como C, Go, Python e Rust usam bastante esse jeito de programar.
- Orientado a Objetos (OO):
- A ideia principal é que, nesse jeito de programar, você organiza o código em “objetos”, que são como caixinhas onde ficam guardados os dados e as ações que podem ser feitas com eles.
- Esses objetos ajudam a deixar tudo mais arrumado: você pode esconder detalhes que não precisa ou não quer mostrar (isso se chama encapsulamento), criar coisas novas aproveitando o que já existe (herança) e mudar o comportamento de acordo com a situação (polimorfismo).
- Esse estilo é muito usado para criar programas que imitam situações do dia a dia ou aplicativos com telas (interfaces gráficas).
- Funcional:
- No jeito funcional de programar, tudo gira em torno de funções, que são como pequenas máquinas: você coloca um valor e ela te devolve outro, fazendo uma conta ou tarefa.
- Normalmente, não ficamos mudando o que já existe, ou seja, evitamos mexer em variáveis (que são como caixas que guardam valores), o que ajuda a evitar erros difíceis de achar.
- As funções são “puras” (o que quer dizer que elas não têm efeitos colaterais como mudar alguma coisa fora do seu controle), então sempre dão o mesmo resultado se você entregar o mesmo valor, sem surpresas.
- Declarativo (consultas/consultável):
- No paradigma declarativo, a gente diz para o computador o que quer que aconteça, mas não explica o passo a passo de como fazer.
- Um exemplo famoso é o SQL, usado para fazer perguntas e buscar informações em bancos de dados.
- Nele, só precisamos dizer quais dados queremos encontrar, e o sistema se vira para descobrir como pegar tudo.
- Outros exemplos são ferramentas que usam regras ou instruções para montar projetos ou configurar servidores sem precisar explicar cada detalhe do processo. Assim, o foco está em falar o resultado que queremos, não o caminho para chegar lá.
- Lógico:
- No jeito lógico de programar, o programa funciona como uma lista de fatos e regras.
- Para executar, você faz uma pergunta (consulta) e o computador tenta achar uma resposta, testando combinações e voltando atrás quando necessário.
- Esse método é muito usado em inteligência artificial, sistemas que checam regras ou protótipos (modelos de teste).
Qual paradigma escolher?
Na realidade, você não precisa escolher um desses jeitos de programar agora! Aqui, a gente vai usar o paradigma (modelo) orientado a objetos, mas não se preocupe com isso neste começo. O importante é saber que existem diferentes estilos de programação, entender um pouco como cada um funciona, e conhecer seus nomes. O resto vem com o tempo e com a prática.
Se você quiser uma dica para o futuro, vale a pena aprender mais sobre os estilos orientado a objetos e funcional. Esses dois jeitos de programar são muito procurados no mercado de trabalho e ajudam bastante na hora de conseguir um emprego na área.
Resumo
Ao longo deste artigo, vimos que programar é basicamente criar instruções que o computador deve seguir, e que essas instruções são chamadas de algoritmos. Descobrimos que algoritmos não estão presentes apenas na tecnologia, mas também em situações do dia a dia, eles ajudam a organizar os passos de forma clara para chegar ao resultado desejado.
Também entendemos que, para transformar esses algoritmos em algo que o computador consiga executar, usamos linguagens de programação, elas funcionam como uma ponte entre a pessoa programadora e a máquina. Vimos que existem diferentes formas de executar o código, compilação e interpretação, cada uma com suas vantagens e desvantagens.
Além disso, exploramos os paradigmas de programação, que são diferentes jeitos de pensar e estruturar um programa, como o imperativo, orientado a objetos, funcional, declarativo e lógico.
No fim das contas, a programação é uma forma de transformar ideias em soluções práticas, quanto mais conhecemos sobre algoritmos, linguagens e paradigmas, mais preparados ficamos para criar sistemas úteis e eficientes. O segredo é praticar, experimentar e, aos poucos, ir se familiarizando com os diferentes estilos e ferramentas.
É assim que se constrói uma boa base para seguir aprendendo e evoluindo na área de programação.