Metodologia - PythonUFRJ

Objetivo do Curso - Computação 1

Desenvolvimento das competências fundamentais da programação de computadores:

    Identificação das informações relevantes de um problema e sua respectiva representação e manipulação na programação.

    Compreensão dos aspectos sintáticos e semânticos da linguagem de programação.

    Articulação dos comandos, estruturas de dados e estruturas básicas da programação para a construção de soluções para problemas simples.

    Modelagem e implementação de código modularizado para problemas não elementares.

    Construção de código organizado, reutilizável e legível, seguindo os princípios das boas práticas de programação.

Metodologia - Computação 1

O objetivo maior do curso é o desenvolvimento das competências para a construção de programas legíveis e modulares em Python. Os módulos serão implementados por funções em Python. A compreensão do conceito de funções, sua construção e utilização na programação é então vital. Por este motivo, o curso começa com o ensino de funções em Python. A introdução deste conteúdo como base para o ensino da programação se justifica também pelo conceito de função ser o mais concreto, dentro do universo dos alunos, de algo que relacione informação (dados) com sequências de operações que transformam as informação(ões) de entrada na informação desejada (de saída) é a função. Em geral, os alunos já viram funções matemáticas, e conseguem trazer algumas intuições da matemática para as funções da programação.

Os alunos são habituados desde o início do curso a escrever funções simples e usar as funções já escritas para a construção de soluções (outras funções) para problemas mais complexos. Ao escrever as primeiras funções, pouco a pouco extrapolamos a intuição trazida da matemática, que é originalmente declarativa, e focamos em blocos sequenciais. Apesar de simples, trabalhar as estruturas sequenciais é importante porque este tipo de estrutura fundamenta todas as outras, além de refletir o raciocínio básico de montar uma sequência de passos para resolver um problema. Também desde o início do curso são trabalhados exemplos e exercícios onde os alunos devem simular manualmente a execução passo a passo das funções apresentadas ou escritas por eles próprios (atividade conhecida como “chinês” do código). Através da prática do “chinês” os princípios do paradigma imperativo vão sendo melhor compreendidos e assimilados. Trabalhando desde cedo a identificação e construção de módulos coesos, conceitos abstratos importantes como modularização, organização de código, e reuso vão sendo paulatinamente trazidos para a prática e para a consciência dos alunos.

Outras vantagens de se iniciar o curso com o ensino de funções:

  • As noções de entrada e saída de dados são tratadas conceitualmente e não são confundidas com comandos de leitura e escrita na tela/console (propositalmente o ensino dos comandos específicos para entrada e saída de dados são adiados quase que até o final do curso).

  • O conceito de parâmetro precede o de variável. A intuição que os parâmetros de função trazem é de serem meios temporários para referenciar informações, uma noção importante que é mais difícil de se intuir quando o ensino de variáveis precede o de parâmetros. Alguns alunos demoram a entender que a variável é um veículo e não o dado em si, problema que pode ser percebido quando o aluno cria uma variável nova para armazenar qualquer transformação que o dado sofra (uma variável para armazenar o valor de entrada, outra nova para armazenar que se somou um ao valor de entrada, outra pra receber o valor de retorno, etc).

  • Podemos trabalhar o desenvolvimento e chamada de funções em Python sem ter de passar pela escrita de um programa completo.

  • O aluno tem todo o curso para aprofundar seu entendimento sobre a construção e utilização de funções, conteúdo considerado um dos mais importantes neste paradigma. Na metodologia tradicional, este conteúdo é deixado para o final, dando ao aluno poucas oportunidades de praticá-lo.

Após o entendimento do conceito de função e sua utilização, passamos para o ensino de estruturas de decisão (condicionais). Um tempo considerável é despendido no trabalho com a construção de testes e uso da estrutura de decisão. Nosso ponto de vista é que o tipo de dado booleano e suas operações é algo novo e artificial para o aluno, que precisa de um tempo para conseguir transpor a intuição (neste caso propensa a erros) e construir o conhecimento formal adequado com que deve tratar as expressões booleanas e sua utilização com a estrutura condicional.

As listas são apresentadas após a estrutura condicional. Este tipo de dado é o primeiro tipo de dado composto a ser visto no curso. Conceitualmente, as listas são estruturas de dados simples, favoráveis ao entendimento de conceitos como armazenamento e manipulação de vários dados simultaneamente. Operações de manipulação de listas (fatiamento, cópia de listas, funções de manipulação) são apresentadas como forma de melhor fixar o conceito de lista e suas possibilidades.

As estruturas de repetição são introduzidas na segunda metade do curso, quando é esperado que o aluno já esteja maduro no entendimento de que a linguagem de programação é uma linguagem formal, não ambígua e determinística. Neste ponto, o aluno deve estar apto a analisar criticamente e depurar seu próprio código. Para desenvolver esta competência, além de exercícios práticos e construção de programas, apresentamos ao longo do curso vários exercícios de “chinês”. Manipulação de listas e matrizes (listas de listas) são os principais motivadores para a construção de funções que fazem uso de estruturas de repetição, reforçando a importância deste conteúdo ter sido visto imediatamente antes. E após o trabalho com manipulação de listas e estruturas de repetição, passamos para outro tipo de dados composto: os dicionários. Este tipo permite trabalhar o conceito de indexação.

O último conteúdo coberto no curso é o que denominamos “interação com o usuário”, sendo a construção de um programa principal e o uso de comandos de entrada e saída de dados. É neste momento que evidenciamos a importância de que a interação com o usuário seja feita em locais adequados para este fim (funções específicas ou no próprio programa principal), de forma que os mecanismos de entrada e saída de dados para as funções (passagem de parâmetros e retorno de valor) sejam preservados, permitindo o reuso e evitando efeitos colaterais indesejáveis.