HELP 🙌 - Corrigir exercícios de programação de forma automática (Obs. é pro meu TCC)
Contexto
Estou desenvolvendo um projeto de TCC para meu curso de Sistemas de Informação. De forma bem resumida estou criando uma plataforma online para aprender a programar de forma gratuita porém utilizando uma metologia e abordagem bem diferente. Não existe nem video aulas e nem tutores, apenas uma trilha a ser seguida junto com os exercícios. Todo o meu projeto é gamificado e da a sensação de estar jogando um jogo. Me baseei na 42 School uma escola de programação que segue exatamente essa metologia, porém está é presencial e apenas para aqueles que conseguirem a bolsa.
Problema 1
Já desenvolvi grande parte do front-end e do back-end e estou preso no core da minha aplicação, como saber se o código que o usuário enviou está correto com o que foi proposto pelo exercício ???? Resumindo, eu passo um exercício (que sera inicialmente apenas na linguagem C) e exijo uma resposta. Então o usuário envia seu código no qual acredita estar resolvendo o problema e eu preciso pegar isso e verificar se está correto e tem a resposta esperada, assim podendo aprovar sua requisição ou rejeitar.
Problema 2
(Essa parte foi adicionada depois) Segundamente, eu não sei como vou pegar essa resposta dos usuários. Lá na 42 é tudo muito automatizado e eles utilizam git. Porém como é presencial, eles possuem um servidor prórpio na intranet, cada escola processa a resposta daqueles alunos pelo que entendi. Como meu caso é online não sei como poderia ser resolvido. Queria muito tentar a ideia do git, mas não sei nem por onde começar. Caso contrário o usuário ia ter que escrever em algum editor embutido na plataforma e submeter o código que eu vou jogar dentro de algum arquivo pra ler posteriormente.
Ajuda 🙌🙌🙌
Sei que parece tolo, mas nunca fiz nada semelhante, não sei nem como pesquisar por isso, já tentei varías abordagens mas nada específico. Então alguem que tiver mais experiência ou já ouviu falar de algo seria de grande ajuda compartilhar esse conhecimento, qualquer link, referência, livro, vídeo, aplicação sera de muito valor!!!
A forma mais facil seria por meio de testes automatizados.
Uma plataforma que faz algo parecido é o exercism.org, que basicamente tem varios exercícios e cada um deles com o teste, assim que manda o codigo ele ja testa.
O problema seria que voce teria que dazer o teste para uma linguagem em específico, mas parece que o que voce quer é que a pessoa possa mandar em qualquer linguagem, né?
Nesse caso é um pouco mais complicado, voce teria que ter o teste para cada linguagem.
Minhas duas sugestões: tentar usar alguma IA para gerar o código de test e (vai que cola) e a outra seria fazer com que os outros usuários do sistema valide o código enviado, como disse que se inspirou na 42, acho que seria divertido. Seria um tipo de code review
Dá pra fazer algo mais ou menos inspirado nesses sites de exercícios/desafios/etc.
Basicamente, para um problema, tem-se o formato da entrada e saída. Geralmente algo como "O programa deve ler X linhas, em cada linha tem N números. O programa deve fazer A, B e C e deve imprimir o resultado em tal formato".
Aí vc define as entradas, e as respectivas saídas. Depois, roda o programa para cada entrada e compara o resultado com a respectiva saída.
Aí entram outros problemas, já que muitos desses sites com "correção automática" podem dizer que o resultado está errado se tiver uma linha em branco a mais, um espaço a menos, etc. Tem que ver o quão rígido vc quer ser com esses detalhes.
Certifique-se também que os casos de teste são complicados o suficiente para que a pessoa não acerte por coincidência. Por exemplo, um programa que foi implementando errado, mas que por coincidência/sorte dá o resultado correto.
Essa parte é relativamente simples, o mais trabalhoso vai ser bolar tantos exercícios e casos de teste.
Já vi uma solução que era mais ou menos o seguinte:
O corretor era uma série de testes unitários (a maioria era com React Testing Library ou Cypress, pq eram projetos de front-end). O código da pessoa tinha que seguir alguns padrões, por exemplo ter um data-testid específico.
Aí o corretor era um script que rodava os testes unitários e gerava um JSON falando se a pessoa passou ou não no requisito. Tudo isso rodava em uma Github Action na hora que a pessoa abria um Pull Request no GitHub.
Era legal, mas o principal defeito é que você tem que limitar muitas coisas. O código da pessoa tem que ter um certo padrão pra corrigir certo.
Acho que tem dois caminhos para este problema:
- Usar uma biblioteca de testes para uma linguagem escolhida;
- Realizar testes de forma independente da linguagem.
Se seu curso for sobre frontend, acho que a alternativa 1 é a mais indicada. Caso contrário eu indico a segunda saída, que vou explicar como fazer agora.
obs: se seu curso for especificamente para uma linguagem só, pode considerar a alternativa 1 também, mas se decidir adicionar outra linguagem no futuro... boa sorte! Não será fácil converter a suíte de testes para uma maneira agnóstica de linguagem.
Vamos lá! Como eu implementaria a opção 2?
Eu iria utilizar STDIN e STOUT como parâmetros e saída para o programa do usuário. Esta é a maneira mais simples de comunicar entre processos e você pode enviar e receber qualquer tipo de dado: plaintext, json, binário, etc. Exemplos:
- Números para fazer soma:
result="$(echo "10\n5" | somador_do_usuario)"
if [ "$result" -eq "15" ]; then
echo "correto"
elif
echo "errado"
fi
O |
(pipe) do shell é o que permite a saída de um programa (stdout) ser a entrada (stdin) para outro.
- Enviar e receber JSON
const child = child_process.spawn('programa_do_usuario');
child.stdin.write(JSON.stringify({ foo: 'bar' }));
child.stdin.write('\n'); // flush
child.stdout.on('data', (data) => {
const response = JSON. parse(String(Buffer.from(data)));
// validar json
});
Como pode perceber, essa solução independe da linguagem de programação usada pelo usuário e pela linguagem de programação dos testes. A ideia envolve executar o programa e se comunicar pelos pipes unix.
A única coisa a se acertar com os usuários é o formato esperado de entrada e saída de dados, ou seja, JSON (e qual o schema), plaintext e qual a ordem dos dados, etc. Você pode também utilizar argumentos aos programas (programa agr1 arg2
) para indicar mais informações ao programa - exemplo qual teste rodar.
Isole o ambiente!
Idealmente (obrigatoriamente) você deve isolar o ambiente que você está rodando o código do terceiro, por questões de segurança e validação dos testes. Para isso, recomendo a utilização de containers, como o Docker ou Podman. Isso depende muito de cada situação, mas basicamente basta um Dockerfile que faz um git pull do código do usuário, compile (se necessário), rode e realize os testes.
Se tiver alguma pergunta ou algum outro exemplo/implementação sinta-se livre para perguntar e tentarei te ajudar. Muito legal seu projeto de aprendizado de programação gratuito. Sucesso.
obs: nenhum dos códigos foram testados, todos mostrados como exemplos.
Esse video do DevSoutinho pode te dar uma luz.
Fui aluno da 42 São Paulo e lá pude passar pela experiência de correção várias vezes. Nós alunos criamos várias teorias acerca do tema, mas fizemos algumas descobertas legais e vou compartilhar com você!
A norminette
A norminette é a responsável pelas frustações dos alunos, ela é o sistema que faz a correção dos exercícios. A construção da norminette é feita em Python e tem um repositório oficial no github onde você pode tentar se aprofundar
Algumas ideias que podem ser mais simples:
- Verificar somente a saída do programa e ver se tem o retorno esperado
- Verificar a saída do programa e alguns fatores do código Se você olhar a documentação, verá que existem algumas regras, como uma struct deve ter o nome começando por s_, funções devem ter 25 linhas e não podem ter mais de 5 funções em um arquivo,
Envio de projetos
Os projetos são dispostos através do git, então aqui vão algumas ideias
- Utilizar um sistema de upload que envia o código para o servidor onde o sistema de correção fica
- Criar repositórios no git e trabalhar com o uso de SSH para enviar os arquivos para esse repositório
O que você pode fazer é receber as respostas por uma api em formato de json, no formato rest, assim independente da linguagem pode conseguir validar com os seus testes, só comparando a resposta correta com a recebida.