sábado, 3 de agosto de 2019

Começando com CGI em linguagem C

Introdução

Normalmente, quando se trata de programação web, muito se fala sobre linguagens como  PHP, Java, Node e Python, mas também é possível desenvolver em C ou Assembly, por exemplo.
Embora seja possível desenvolver páginas dinâmicas em praticamente qualquer linguagem, em algumas delas não é tão prático desenvolver tal dinamismo.  Usar a linguagem C traz algumas vantagens e desvantagens.

Vantagens

  • Desempenho: Linguagens compiladas são mais rápidas do que linguagens interpretadas (já que não precisam de uma máquina virtual).
  • Consumo de memória:  Por ser compilada consome menos memória, mas além disso, sem usar alocações dinâmicas e conhecendo bem o fluxo de execução, é possível determinar a quantidade de memória que será usada pelo programa.

Desvantagens

  •  Produtividade: Mais especificamente em C, como esta linguagem não foi pensada para o desenvolvimento de sistemas web, não possui algumas facilidades que trazem maior produtividade, como o tipo String; ter de interpretar strings para pegar os valores (esta parte ficará mais clara ao decorrer deste artigo).

Mas antes entender o que é e como funciona o CGI, é necessário aprender um pouco sobre como funciona a web (protocolo HTTP).

Sobre páginas na Internet

O Hypertext Transfer Protocol (HTTP) é o protocolo pelo qual a internet funciona. De modo simplificado o cliente (usuário / navegador) faz requisição a uma página e o servidores responde devolvendo a página requisitada.

Ilustração simplificada do que ocorre quando acessamos um site

Para criar uma simples página estática basta criar um arquivo com extensão .html (por exemplo minha_pagina.html) - caso queira aprender a criar páginas mais elaboradas o W3 Schools é altamente indicado, possui dicas sobre HTML, CSS e Javascript, por exemplo.


Abrindo o arquivo minha_pagina.html no navegador.

Um pouco mais sobre o protocolo HTTP

Ao acessar (fazer requisição) uma página na internet, algumas informações do lado cliente são enviadas ao lado servidor, como por exemplo, qual o navegador, sistema operacional, idioma, página requisitada e tipo de requisição. Para ver as informações estão sendo enviadas quando você acessa uma página, basta aperta a tecla F12 ou clicar com o botão direito do mouse e clicar em inspecionar elemento, em seguida acessar a aba Rede (network).

Estrutura de uma mensagem HTTP

Informações que são enviadas quando acessamos a página do Google
Observe que a mensagem é dividida em header (cabeçalho) e body (corpo) - isso será importante lá na frente.

Uma das formas para trazer dinamismo para uma página é utilizando formulários. Os formulários utilizam utilizam dois métodos para enviar os dados.

Método GET

Ao enviar dados usando o método GET, os valores dos campos são adicionados à URL, ou seja, os dados ficam visíveis no campo de endereço da página. Este método geralmente é usado em filtro de pesquisas.


Exibindo o formulário com método GET

Informações que são enviadas quando utilizado o método GET. Observe que aparece na URL o dado que digitei (1234), que fica no cabeçalho da requisição

Método POST

Ao enviar dados usando o método POST, os valores dos campos são colocados no corpo da mensagem. Este método geralmente é usando para enviar dados sensíveis, já que não fica exposto que nem o método GET.



Exibindo o formulário com método POST

Informações que são enviadas quando utilizado o método POST. Observe os dados não aparecem mais na URL, mas sim no Form Data, que fica no corpo da requisição

Sobre CGI

CGI (Common Gateway Interface) é um programa no lado servidor que envia ao cliente uma página HTML. É comumente usado para receber dados de formulários, mas pode ser usado para criar qualquer tipo de página dinâmica ou não.
Ilustração da comunicação do cliente com o servidor. Em seguida o servidor colocar as informações passadas pelo cliente em variáveis de ambiente. O programa pega os dados das variáveis de ambiente, processa e retorna algo (pode ser uma página ou não). O servidor pega o retorno do programa e repassa para o cliente


Antes de lidar com o dinamismo, vamos criar uma página estática.


Observe que colocamos a informação do cabeçalho de que tipo de mensagem estamos enviando e em seguida o HTML da página. É importante que após o cabeçalho haja a quebra de linha com dois \n. Podemos fazer um simples teste de executar o programa.

Saída no terminal do que é exibido pelo programa

Para transmitir informações do servidor ao programa, as informações são colocadas em variáveis de ambiente e o programa (a partir deste ponto irei me referir apenas por cgi). Algumas das variáveis de ambiente são:


Variável de AmbienteDescrição
CONTENT_TYPETipo de mídia
CONTENT_LENGTHTamanho do corpo
da mensagem
QUERY_STRINGParâmetros que estão sendo
enviados via URL
REQUEST_METHODTipo de método que está
sendo requisitado

Note que o que muda de um simples programa em C é que você também irá receber dados de variáveis de ambiente.

Para pegar dados das variáveis de ambiente é necessário usar a função getenv.


Para testar vamos ter de criar a variável de ambiente QUERY_STRING.



Criando variável de ambiente e logo em seguida executando o programa noWindows

Criando variável de ambiente e logo em seguida executando o programa no Linux


Note que você acabou de aprender como receber dados que são enviados pela URL, ou seja, acaba de aprender como receber dados que foram enviados usando o método GET.

Agora para receber dados que são enviados no corpo da mensagem, usaremos a variável de ambiente CONTENT_LENGTH para saber o tamanho do corpo da mensagem e faremos uma simples leitura do stdin (ou como comumente conhecido, leitura do teclado).

Criando variável de ambiente e logo em seguida executando o programa e por fim fazendo a leitura do teclado no Windows

Criando variável de ambiente e logo em seguida executando o programa e por fim fazendo a leitura do teclado no Linux


Note que você acabou de aprender como receber dados que foram enviados usando o método POST, pois o neste método coloca no CONTENT_LENGTH contém o tamanho do corpo da mensagem e o corpo da mensagem é enviado pelo stdin. Só lembre de colocar os dois \n antes de exibir devido ao fato já citade de servir para separar o cabeçalho do corpo da mensagem.

Usando o método POST e vendo o que é exibido
 



Agora, basta criar uma página com formulário, determinar o método de envio e a url de ação; e um CGI para lidar com os dados.


Formulário enviando dados ao CGI

CGI exibindo os dados recebidos via POST


Dados da requisição feita pelo formulário ao CGI

Observe que não foi necessária a instalação de nenhuma ferramenta (usamos apenas um compilador C) adicional para fazer nossos testes, mas para exibir o CGI no navegador é necessária a instalação de um servidor Web como Apache, não expliquei esse assunto por não ser o foco do artigo.

Caso queira ver um projeto usando CGI, tem um jogo da velha que criei um tempo atrás. E se quiser algo mais elaborado, como lidar com cookies e sessões veja as dúvidas frequentes.

Dúvidas frequentes


Pra que servem os as duas quebras de linhas (\n\n) no código? 
São essas quebras de linhas que separam o cabeçalho do corpo da mensagem e são de uso obrigatório. Para mais detalhes acesse a referência [4].

Para que serve o charset? 
Isso indica a codificação de caracteres. É indicado utilizar UTF-8 para que não haja nenhum problema.

O método GET é seguro?
"Não", pensando em passar dados sensíveis, como por exemplo senha ou tipo de previlégio, não é recomendado usar esse método, já que qualquer pessoa pode ver (também pessoas mal intencionadas que estejam monitorando a rede) e alterar os dados.

O método POST é seguro?
"Não", apesar de ser melhor que o GET, por não ficar tão escancarado, ainda não garante total segurança. Os dados só não estão mais visíveis, eles estão no corpo da mensagem. Para maior segurança, seria necessário usar o protocolo HTTPS, mas para estudar CGI não recomendo se preocupar com HTTPS de imediato.

O que muda de um programa qualquer escrito em C para os que utilizam CGI? 
A mudança é que você também irá receber dados de variáveis de ambiente.

Ao usar o método GET no envio de um formulário alguns caracteres estão estranhos, por que isso acontece?
Como os dados são colocados na URL, esses dados são codificados (URL encoding). Isso não acontece quando se usa o método POST.

Como posso criar sessão?
Você pode criar um arquivo no servidor com as credenciais dos usuários ( pode ser a identificação de do computador ou usuário) e as demais informações necessárias; e no lado cliente armazenar num cookie a credencial apenas, assim toda vez que o usuário acessar a página os cookies são enviados. Recomendo a leitura das referências [6] e [7].

Como testo o CGI no navegador?
Pra isso é necessário instalar um servidor web como o Apache e colocar os arquivos numa pasta específica. Assim você pode testar na sua própria máquina. Recomendo a leitura do artigo Habilitando CGI e .sh no Apache do Debian Jessie.



Referências:

[1] Programação WEB em C : Entendendo CGI
[2] O que é CGI e qual é sua finalidade?
[3] The Common Gateway Interface (CGI) Version 1.1
[4] Mensagens HTTP
[5] Getting Started with CGI Programming in C
[6] HOW-TO Write a CGI Program in C/C++
[7] How to handle session in CGI using c as same as we do in PHP

quinta-feira, 21 de dezembro de 2017

8 dicas para melhorar seus códigos


Depois que a gente já tem uma certa experiência com programação, nos perguntamos:
Será que sou um bom programador? Como ser um bom programador? Como posso melhorar meus códigos? Será que produzo bons códigos?

A resposta para estas questões é simples. ESCREVA CÓDIGOS LEGÍVEIS! FAÇA UM CÓDIGO LIMPO!

Antes de aprender a como escrever códigos mais legíveis, é necessário entender o motivo de interessar-se por este assunto.

No meio da computação diversos códigos são produzidos diariamente, mas nem todos possuem uma qualidade aceitável/boa. Além disso, muitas vezes será necessário fazer manutenção de algum código e se a leitura deste código for dificultosa, como você irá fazer a manutenção deste? Você pode acreditar  que um código ser bom ou não varia de programador para programador, mas com esta publicação espero mudar seu pensamento.

Obs: Tudo aqui dito teve como base experiências passadas e guiado pelo livro Código Limpo (nome original Clean Code), de Robert C. Martin.

O interessante para determinar se um código é limpo ou não, é analisá-lo de maneira científica, verificando quantos caracteres deve haver por linha, quantas linhas cada módulo deve ter, duplicação de código, etc. E se você ler o Clean Code, verá que o autor faz isso, trazendo diversos dados.

Pode-se verificar se o código é / está limpo a partir dos seguintes pontos:
  • Nomes descritivos;
  • Módulos pequenos;
  • Comentários;
  • Código repetido;
  • Quantidade de parâmetros;
  • Padronização;
  • Testes unitários;
  • Separação em arquivos;

  1. Nomes descritivos:

    A escolha de nomes descritivos é muito importante para facilitar a leitura. Bem... Quem nunca viu uma função que recebe como parâmetros a, b e c. Daí você se pergunta: Mas que diabos é esse a, b e c? Este é exatamente o problema, ao ler o nome destas variáveis, você não sabe o que elas representam, somente lendo o restante do código é que elas exprimem algum significado. O mesmo se aplica a nome de funções, arquivos, etc. Como deve ter notado, a escolha de nome dificulta a leitura, pois é necessário ficar "cavucando" o funcionamento e a regra do negócio para se ter uma compreensão mínima do que aquilo descrito representa. Sendo assim, também não abrevie para reduzir caracteres. Veja o seguinte exemplo:

    Você deve ter percebido que somente lendo o nome da função não é possível determinar o que ela faz, assim sendo necessário olhar sua implementação, só que ao vê-la, não há como dizer o que ela faz (seu significado) além de multiplicar dois números, assim sendo necessário conhecer "a regra de negócio". Obs: Esta função tem como objetivo calcular a área de um retângulo.

  2. Módulos pequenos:

    Ao criar módulos grandes, a leitura é dificultosa (por fazerem mais de uma coisa), assim, é provável que existam bugs nestes trechos, pois vários detalhes de implementação estão numa mesma parte. Agora em uma função pequena, a ideia é que ela faça apenas uma coisa, assim criando funções especializadas no que fazem e de fácil leitura, o que por sua vez diminui a probabilidade de bugs. Ou seja, o escopo é mais claro, o que faz com que o tempo gasto para encontrar as falhas sejam bem menores.
    Exemplo de problemas com funções que fazem mais de uma coisa. Um amigo meu estava fazendo um programa em que precisava descobrir o número de linhas um arquivo, sortear uma linha e fazer a leitura desta linha. O problema está no fato de que ao descobrir o número de linhas do arquivo, o ponteiro era movido para o final do arquivo, assim ao tentar fazer a leitura do conteúdo do arquivo, não devolvia nada. Este problema só ocorreu pelo fato do meu colega não ter criado um módulo para apenas pegar o número de linhas do arquivo, outro para sortear uma linha e outro para ler cada uma das linhas.

    A solução mais simples encontrada foi mandar o pArquivo para a posição inicial novamente, como mostra o código abaixo:
    Existem soluções melhores, mas seguindo a mesma lógica, o código com módulos pequenos ficaria:
  3. Comentários:

    "Se precisa comentar, obviamente não está legível."
    Muitos programadores utilizam-se de comentários para explicar o que o código faz, e isso é uma péssima prática, pois você acaba tendo dois trabalhos, o de escrever os códigos e o de escrever os comentários dos mesmos, como mostra o exemplo abaixo (atente-se da linha 1 à linha 6):

    Sendo que era possível escrever um código descritivo (deixando de lado a necessidade de comentários). Além disso, os comentários podem ser altamente destrutivos já que existe a possibilidade de lermos um comentário achando que a função faz X, quando na verdade faz Y, o que pode gerar diversas falhas e com a modificação da função ao longo do tempo, sem saber o que ela faz por completo, pode tornar-se um monstro que ninguém entende o funcionamento, como o seguinte:

    Note que lendo os comentários da linha 3 à 9, espera-se que a função somente conte o tamanho da string, mas além de "contar" ela retina o espaço e coloca um '\0', que indica o final da string, em outras palavras, a função que somente deveria contar está modificando a string. Este código é pequeno, mas se estivesse no meio de um código maior provavelmente você não enxergaria tal problema.

    Também existem os comentários que são extremamente desnecessários, onde o próprio código já é autoexplicativo, como o exemplo a seguir:

    Note que as linhas 8 e 9 já dizem o que elas fazem, não é necessário um comentário para explicá-las.

    Além disso, existem trechos de códigos que foram comentados, e, ao se ter isso num projeto grande em equipe, não se sabe se o motivo daquele trecho comentado e se pode removê-lo, veja abaixo:

    Nota: A linha 8 é equivalente as linhas 9 à 12. Assim você pode utilizar comentários para explicar o motivo de utilizar determinada solução e não outra. Exemplo:

  4. Código repetido:

    Você pode pensar que duplicar pequenos trechos de códigos pode ser bom para melhorar a eficiência de um programa, mas deve-se ter em mente que códigos duplicados só trazem problemas de manutenção, pois caso seja necessário mudar este trecho, será necessário verificar todos os locais em que ele foi utilizado para fazer tal modificação e isso se resolveria facilmente utilizando funções. Exemplo:


    Uma possível solução seria:

    Note que as funções substituirVogaisPorEspaco e substituirNumerosPorLetras ficaram ligeiramente menores e mais simples de serem lidas.

  5. Quantidade de parâmetros:

    Uma função com vários parâmetros pode dificultar muito a leitura, por isso é recomendável a criação de estruturas que comportem tais variáveis, pois assim a função necessitará de muito menos parâmetros. Exemplo: pense numa função que irá desenhar um triângulo na tela. Este triângulo tem posição dos vértices na tela, cor de preenchimento e cor da linha. Assim você poderia criar


    mas é possível diminuir o número de parâmetros e facilitar a leitura da função

    Veja quantos detalhes foram suprimidos e mesmo assim somente lendo o nome da função e o parâmetro recebido, é possível afirmar que é feita a ação de desenhar um triângulo.

  6. Padronização:

    Padrão é importante para que você encontre facilmente o que deseja, seja uma função, uma classe, um arquivo, uma variável, ou seja, facilita encontrar qualquer coisa, assim, qualquer pessoa que for usar seu código saberá o que esperar/ como procurar. Exemplo:


    Veja que embora seja uma ligeira mudança no nome, ao tentar usar a função que troca números por uma letra, você provavelmente procuraria por trocarNumerosPorLetras, pois na função que troca vogais por espaço está trocarVogaisPorEspaco, além disso, como o nome está diferente, você pode pensar que existe alguma mudança na implementação das duas funções, já que os nomes são diferentes.

  7. Testes automatizados:

    Pensando que seu código está dividido em funções pequenas, e sendo estas funções especialistas no que fazem. É possível fazer a utilização de teste para procurar falhas e verificar a integridade do sistemas conforme as atualizações ocorrem. Além disso, com teste automatizados você não precisa ficar testando manualmente seu projeto, o que demanda muito menos tempo em comparação a testes manuais. Exemplo: Pensando que a função (citada no ponto 4 - Código Repetido) substituirVogaiPorEspaco faça parte de um projeto maior e que o projeto passou por atualizações. Abaixo temos um teste desta função.


    Veja que a função está colocando as vogais em maiúsculas e não trocando por espaço. Talvez manualmente você não encontraria tal erro facilmente, mas com o teste automatizado foi bem simples e rápido encontrar a falha. Obs: Este teste foi apenas um simples exemplo, para um projeto real seria interessante ter-se mais testes.
  8. Separação em arquivos:

    Agora se seu código segue todos estes padrões, é interessante que as coisas (funções, classes, etc) estejam separados em arquivos, de modo que as mesmas estejam agrupadas de acordo com sua proximidade. Por exemplo, pense num sistema que possua algum tipo de relação entre cliente e produto, neste caso, se você tivesse que alterar algum dado do cliente, você iria procurar na pasta / arquivo referente ao cliente e não em produto.
    Arquivo do cliente:

    Arquivo do produto:


    Assim, se você quisesse adicionar mais um atributo ao cliente, você iria ao arquivo do cliente. E se quisesse implementar uma função para excluir um produto, iria fazer isso no arquivo do produto. Também observe que como estão separados em arquivos, não é necessário colocar os nomes como cadastrarCliente e cadastrarProduto

Tudo isso foi apenas uma visão geral, recomendo a leitura do livro Clean Code que aí você realmente verá mais aprofundadamente como produzir bons trechos de código.

domingo, 25 de junho de 2017

Jogo da forca em linguagem C


Olá pessoal, depois de ver vários projetos de jogo da forca em linguagem C, decidi criar o meu. Fiz isso pois as implementações que encontrei tinham palavras pré-definidas no código fonte ou quando as palavras estavam em um arquivo, elas tinha um tamanho máximo. Daí pensei em criar o jogo da forca em que as palavras e dicas ficassem armazenadas em arquivos e que pudessem ter tamanho qualquer. Assim o projeto utiliza arquivo e alocação dinâmica. Para o projeto não ficar desorganizado ele foi feito com base no MVC.