Exercícios de conceito


Os Exercícios de Conceito são exercícios concebidos para ensinar conceitos (de programação) específicos. Os conceitos ensinados pelos Exercícios de Conceito formam um programa de estudos. Para mais informações sobre como conceber um programa de estudos, consulta a documentação do programa de estudos.

Note

Podes criar rapidamente a estrutura de um novo Exercício de Conceito executando os seguintes comandos a partir do diretório raiz do percurso:

bin/fetch-configlet
bin/configlet create --concept-exercise <slug>

Para mais informações, consulta a documentação do configlet create

Metadados

Os metadados de um Exercício de Conceito são definidos na chave exercises.concept do ficheiro config.json. Os metadados definem o UUID, o slug e muito mais do exercício.

Exemplo

{
  "exercises": {
    "concept": [
      {
        "uuid": "93fbc7cf-3a7e-4450-ad22-e30129c36bb9",
        "slug": "cars-assemble",
        "name": "Cars, Assemble!",
        "concepts": ["if-statements", "numbers"],
        "prerequisites": ["basics"]
      }
    ]
  }
}

Ficheiros

Cada Exercício de Conceito tem o seu próprio diretório dentro do diretório exercises/concept do percurso. O nome do diretório do Exercício de Conceito tem de corresponder à propriedade slug do Exercício de Conceito, tal como definida no ficheiro config.json.

Um Exercício de Conceito tem quatro tipos de ficheiros:

Ficheiros de documentação

Estes ficheiros são apresentados ao estudante para ajudar a explicar o exercício.

  • .docs/introduction.md: apresenta ao estudante o(s) conceito(s) que o exercício ensina (obrigatório)
  • .docs/instructions.md: fornece as instruções do exercício (obrigatório)
  • .docs/hints.md: fornece pistas ao estudante para o ajudar a desbloquear-se num exercício (obrigatório)

Ficheiros de metadados

Estes ficheiros não são apresentados ao estudante, mas são usados para definir os metadados do exercício.

  • .meta/config.json: contém meta-informação sobre o exercício (obrigatório)
  • .meta/design.md: descreve a conceção do exercício (obrigatório)

Ficheiros de abordagem

Estes ficheiros descrevem abordagens para o exercício.

  • .approaches/introduction.md: introdução às abordagens mais comuns para o exercício (opcional)
  • .approaches/config.json: metadados das abordagens (opcional)
  • .approaches/<approach-slug>/content.md: descrição da abordagem (opcional)
  • .approaches/<approach-slug>/snippet.txt: fragmento que mostra a abordagem (opcional)

Ficheiros de artigos

Estes ficheiros descrevem artigos para o exercício.

  • .articles/config.json: metadados dos artigos (opcional)
  • .articles/<article-slug>/content.md: descrição do artigo (opcional)
  • .articles/<article-slug>/snippet.md: fragmento que mostra o artigo (opcional)

Ficheiros do exercício

Os ficheiros específicos da linguagem, como os ficheiros de implementação e de testes. Os nomes destes ficheiros são específicos de cada percurso.

  • Suite de testes: verifica a correção de uma solução (obrigatório)
  • Implementação stub: fornece um ponto de partida aos estudantes (obrigatório)
  • Implementação exemplar: fornece uma implementação idiomática que passa todos os testes (obrigatório)
  • Ficheiros adicionais: garantem que os testes podem ser executados (opcional)

Exemplo

exercises
└── concept
    └── cars-assemble
        ├── .approaches
        |   ├── for-loop
        |   |   ├── content.md
        |   |   └── snippet.txt
        |   ├── config.json
        |   └── introduction.md
        ├── .articles
        |   ├── performance
        |   |   ├── content.md
        |   |   └── snippet.md
        |   └── config.json
        ├── .docs
        |   ├── introduction.md
        |   ├── instructions.md
        |   └── hints.md
        ├── .meta
        |   ├── config.json        
        |   ├── design.md
        |   └── Exemplar.cs (implementação exemplar)
        ├── CarsAssemble.cs (implementação stub)
        └── CarsAssemblyTests.cs (testes)

Especificação mínima válida

Preferimos uma abordagem de "fusão otimista" para novos exercícios, em que os percursos podem desenvolver exercícios num estado de "trabalho em curso". O estado mínimo válido, que passa no configlet e te permite fazer a fusão, é:

  • Uma entrada válida no config.json do percurso, com o status definido como wip.
  • Um ficheiro .meta/config.json válido
  • A presença dos seguintes ficheiros, ainda que possam estar vazios:
    • .docs/introduction.md
    • .docs/instructions.md
    • .docs/hints.md
    • Implementação stub
    • Ficheiro de testes

Ficheiro: .docs/introduction.md

Objetivo: Apresentar ao estudante o(s) conceito(s) que o exercício ensina.

Presença: Obrigatório

  • A informação fornecida deve dar ao estudante o contexto suficiente para que consiga descobrir a solução por si próprio.
  • Deve ser fornecida apenas a informação necessária para compreender os fundamentos do conceito e resolver o exercício. A informação extra deve ficar para o documento about.md do conceito.
  • Os links devem ser usados com moderação, se forem usados de todo. Embora um link que explique um tópico complexo como a recursão possa ser útil, para a maioria dos conceitos os links fornecem mais informação do que a necessária, por isso o objetivo deve ser explicar as coisas de forma concisa no próprio texto.
  • Devem ser usados termos técnicos corretos, para que o estudante possa facilmente procurar mais informações.
  • Os exemplos de código devem ser usados apenas para introduzir sintaxe nova (os estudantes não devem ter de procurar exemplos de sintaxe na internet). Nos restantes casos, apresenta antes descrições ou links em vez de código.

Por exemplo, a introdução de um exercício de "strings" pode descrever uma string apenas como uma "sequência de carateres Unicode" ou uma "série de bytes", dizer aos utilizadores como criar uma string e explicar que uma string tem métodos que podem ser usados para a manipular. A menos que o estudante precise de compreender detalhes mais subtis para resolver o exercício, este tipo de explicação breve (juntamente com um exemplo da sua sintaxe) deve ser informação suficiente para o estudante resolver o exercício.

Exemplo

# Introduction

There are two primary ways to assign objects to names in Ruby - using variables or constants. Variables are always written in snake case. A variable can reference different objects over its lifetime. For example, `my_first_variable` can be defined and redefined many times using the `=` operator:

```ruby
my_first_variable = 1
my_first_variable = "Some string"
my_first_variable = SomeComplexObject.new
```

Ficheiro: .docs/introduction.md.tpl

Objetivo: Modelo a partir do qual se gera um ficheiro introduction.md.

Presença: Opcional

O documento introduction.md apresenta ao estudante o(s) conceito(s) do exercício. Cada conceito tem também o seu próprio documento introduction.md, que não é mostrado fora do contexto de um exercício.

Se a introdução do conceito deve ser incluída palavra a palavra na introdução do exercício, pode usar-se um ficheiro introduction.md.tpl. Este ficheiro permite referir as introduções dos conceitos através de marcadores: %{concept:<concept-slug>}.

O configlet pode gerar um ficheiro introduction.md a partir de um ficheiro modelo. No ficheiro gerado, os marcadores dos conceitos são substituídos pelo conteúdo introduction do conceito.

O site do Exercism só conhece o documento introduction.md. É responsabilidade do percurso gerar o introduction.md quando se usa um ficheiro modelo.

Os percursos podem decidir, exercício a exercício, se usam um modelo ou não. Em alguns casos, usar a introdução do conceito palavra a palavra pode não ser o ideal. Opta sempre pelo que proporciona a melhor experiência de aprendizagem ao estudante.

Exemplo

# Introduction

%{concept:variables}

Ficheiro: .docs/instructions.md

Objetivo: Fornecer as instruções do exercício.

Presença: Obrigatório

Este ficheiro divide-se em duas partes.

  1. A primeira parte explica a "história" ou o "tema" do exercício. Geralmente, não deve conter exemplos de código.
  2. A segunda parte apresenta instruções claras sobre o que o estudante tem de fazer, sob a forma de uma ou mais tarefas.

Cada tarefa tem de cumprir as seguintes normas:

  • Começa com um cabeçalho de segundo nível que começa por um número (por exemplo, ## 1. Do X, ## 2. Do Y).
  • O cabeçalho deve descrever o que implementar, não como o implementar (por exemplo, ## 1. Check if an appointment has already passed).
  • Descreve qual função/método o estudante tem de definir/implementar (por exemplo, Implement method X(...) that takes an A and returns a Z),
  • Fornece um exemplo de utilização dessa função em código. Estes exemplos devem ser diferentes dos apresentados nos testes.

Damos grande importância a que o conteúdo do Exercism seja seguro para todos e, por isso, muitas vezes pecamos por excesso de prudência ao decidir se as histórias são apropriadas ou não. Embora tenhamos cuidado com o que fundimos, sabemos que é difícil ter consciência do que pode ser visto como problemático, por isso assumimos sempre que estás a agir de boa-fé e fazemos os possíveis por detetar quaisquer problemas na revisão de forma não confrontacional. Se quiseres verificar uma história connosco, menciona @exercism/leadership e analisamo-la em conjunto. Aqui ficam alguns pontos orientadores:

  • Tenta garantir que a história é acolhedora e que todos a conseguem compreender. Se a história contiver piadas internas ou calão regional, tenta pensar em frases alternativas.
  • Tenta escrever exemplos que incluam todos. Por exemplo, considera usar nomes de outras culturas e de géneros variados.
  • Pergunta a ti próprio se conheces alguém que se possa sentir ofendido com a história. Se for o caso, considera alterá-la para o evitar.

Exemplo

# Instructions

In this exercise you're going to write some code to help you cook a brilliant lasagna from your favorite cooking book.

## 1. Calculate the remaining oven time in minutes

Define the `Lasagna#remaining_minutes_in_oven` method that takes the actual minutes the lasagna has been in the oven as a parameter and returns how many minutes the lasagna still has to remain in the oven, based on the expected oven time in minutes from the previous task.

```ruby
lasagna = Lasagna.new
lasagna.remaining_minutes_in_oven(30)
# => 10
```

Ficheiro: .docs/hints.md

Objetivo: Fornecer pistas ao estudante para o ajudar a desbloquear-se num exercício.

Presença: Obrigatório

  • Se o estudante ficar bloqueado, permitimos que clique num botão para pedir uma pista, que mostrará a parte relevante do ficheiro.
  • As pistas devem ser apresentadas como listas de pontos sob cabeçalhos.
  • As pistas devem ser suficientes para desbloquear quase todos os estudantes.
  • As pistas não devem revelar a solução, mas sim apontar para um recurso que a descreva (por exemplo, um link para a documentação da função a usar).
  • As pistas podem usar exemplos de código para explicar conceitos, mas não para esboçar a solução. Por exemplo, num exercício de listas podem mostrar um fragmento de como funciona uma determinada função de listas, mas não de forma que possa ser copiado e colado diretamente na solução.
  • As pistas gerais sobre o exercício podem aparecer como uma lista Markdown sob o cabeçalho ## General.
  • As pistas específicas de uma tarefa devem aparecer como uma lista Markdown sob cabeçalhos que correspondam ao cabeçalho da tarefa no instructions.md (por exemplo, ## 2. Do Y).
  • Se não houver pistas gerais nem pistas para uma tarefa específica, os cabeçalhos devem ser omitidos. Cada cabeçalho tem de ser seguido de uma lista Markdown.
  • Dá prioridade às pistas específicas de tarefas em vez das pistas gerais, uma vez que as primeiras têm mais probabilidade de desbloquear o estudante do que as gerais.
  • Os cabeçalhos das tarefas devem descrever o que se faz na tarefa, não como.
  • Os cabeçalhos das tarefas devem usar maiúsculas e minúsculas normais de frase (por exemplo, ## 2. Check if a book can be borrowed).
  • As tarefas devem indicar explicitamente que método/função/tipo implementar e o seu valor esperado (por exemplo, Implement the 'canBorrowBook' function to check if a book can be borrowed. The function takes a book as its parameter and returns `true` if the book has not already been borrowed; otherwise, return `false`).

Ver as pistas não será um caminho "recomendado" e vamos desaconselhá-lo (com delicadeza), a não ser que o estudante não consiga avançar sem elas. Como tal, vale a pena ter em conta que o estudante que as lê estará um pouco confuso/sobrecarregado e talvez frustrado.

Exemplo

# Hints

## General

- You need to define a [constant][constant] which should contain the [integer][integers] value specified in the recipe.

## 1. Calculate the remaining oven time in minutes

- You need to define a [method][methods] with a single parameter for the actual time so far.

[constants]: https://www.rubyguides.com/2017/07/ruby-constants/
[integers]: https://ruby-doc.org/core-2.7.0/Integer.html
[methods]: https://launchschool.com/books/ruby/read/methods

Ficheiro: .meta/design.md

Objetivo: Descrever a conceção do exercício.

Presença: Obrigatório

Este ficheiro contém informação sobre a conceção do exercício, que inclui coisas como o seu objetivo, os seus objetivos de ensino, o que não ensinar e muito mais. Esta informação pode ser extraída da issue do GitHub correspondente ao exercício.

Existe para informar futuros responsáveis pela manutenção ou contribuidores sobre o âmbito e as limitações de um exercício, de modo a evitar a tendência natural para tornar os exercícios mais complexos com o tempo.

Exemplo

# Design

## Goal

The goal of this exercise is to teach the student the basics of programming in Ruby.

## Learning objectives

- Know what a variable is.
- Know how to define a variable.
- Know how to update a variable.

## Out of scope

- Memory and performance characteristics.
- Method overloads.

## Concepts

The Concepts this exercise unlocks are:

- `basics`: know what a variable is; know how to define a variable; know how to update a variable.

## Prerequisites

There are no prerequisites.

Ficheiro: .meta/config.json

Objetivo: Conter meta-informação sobre o exercício.

Presença: Obrigatório

Este ficheiro contém meta-informação sobre o exercício:

  • authors: O(s) nome(s) de utilizador do GitHub do(s) autor(es) do exercício (obrigatório)
    • Inclui os revisores se as suas revisões alterarem substancialmente o exercício (ao ponto de parecer que "chegaram lá juntos")
  • contributors: O(s) nome(s) de utilizador do GitHub do(s) contribuidor(es) do exercício (opcional)
    • Inclui os revisores se as suas revisões forem relevantes/acionáveis/acionadas.
  • forked_from: De que exercício(s) foi derivado (obrigatório se o exercício for derivado)
  • files: As localizações dos ficheiros usados neste exercício, relativas ao diretório do exercício (obrigatório)
  • language_versions: Requisitos de versão da linguagem (opcional)
  • blurb: Uma descrição breve deste exercício. O comprimento tem de ser <= 350. O Markdown não é suportado (obrigatório)
  • source: A fonte em que este exercício se baseia (opcional)
  • source_url: O URL da fonte em que este exercício se baseia (opcional)
  • representer: Meta-informação relacionada com a forma como o representer processa este ficheiro (opcional)
    • version: Um número inteiro para a versão do representer a usar no exercício (obrigatório se a chave pai estiver presente)
  • icon: O slug do ícone (vê a lista completa de ícones). Se não for especificado, será usado o slug do exercício (opcional)
  • custom: Quaisquer dados não padrão específicos do exercício. Pode ser usado para personalizar o comportamento das ferramentas do percurso para cada exercício (opcional)

Se alguém for simultaneamente autor e contribuidor, indica essa pessoa apenas como autor.

Exemplo mínimo

{
  "authors": ["FSharpForever"],
  "files": {
    "solution": ["Lasagna.fs"],
    "test": ["LasagnaTests.fs"],
    "exemplar": [".meta/Exemplar.fs"]
  },
  "blurb": "Learn the basics of F# by cooking Lucian's Luscious Lasagna"
}

Exemplo completo

Imagina que o utilizador FSharpForever escreveu um exercício chamado log-levels para o percurso de F#. O PythonProfessor adapta o exercício para o percurso de Python. Mais tarde, o utilizador GladToHelp melhora o exercício.

{
  "authors": ["PythonProfessor"],
  "contributors": ["GladToHelp"],
  "files": {
    "solution": ["log_levels.py"],
    "test": ["log_levels_test.py"],
    "exemplar": [".meta/exemplar.py"],
    "editor": ["test_helper.py"]
  },
  "forked_from": ["fsharp/log-levels"],
  "language_versions": ">=3.7",
  "blurb": "Learn how to work with strings by processing log lines.",
  "source": "Wikipedia",
  "source_url": "https://en.wikipedia.org/wiki/Log_file",
  "representer": {
    "version": 2
  },
  "icon": "logs",
  "custom": {
    "parallel": true
  }
}

Repara que:

  • A ordem dos autores e dos contribuidores não é significativa e não tem significado.
  • Se estiveres a derivar um exercício, não faças referência aos autores ou contribuidores originais. Garante apenas que o forked_from está correto.
  • Embora não seja comum, é possível derivar a partir de vários exercícios.
  • language_versions é uma string de formato livre que os percursos podem usar e interpretar como quiserem.

Ficheiro: .approaches/introduction.md

Objetivo: Introdução às abordagens mais comuns para o exercício

Presença: Opcional

Este ficheiro descreve as abordagens mais comuns para o exercício. Consulta a documentação para mais informações sobre o que deve constar deste ficheiro.

Exemplo

# Introduction

The key to this exercise is to deal with C# strings being immutable, which means that a `string`'s value cannot be changed.
Therefore, to reverse a string you'll need to create a _new_ `string`.

## Using LINQ

```csharp
public static string Reverse(string input)
{
    return new string(input.Reverse().ToArray());
}
```

For more information, check the [LINQ approach][approach-linq].

## Which approach to use?

If readability is your primary concern (and it usually should be), the LINQ-based approach is hard to beat.

Ficheiro: .approaches/config.json

Objetivo: Metadados das abordagens

Presença: Opcional (obrigatório quando existe uma introdução das abordagens ou uma abordagem)

Este ficheiro contém meta-informação sobre as abordagens do exercício:

  • introduction: O(s) nome(s) de utilizador do GitHub do(s) autor(es) da introdução das abordagens do exercício (opcional)

    • authors: O(s) nome(s) de utilizador do GitHub do(s) autor(es) da introdução das abordagens do exercício (obrigatório)
      • Inclui os revisores se as suas revisões alterarem substancialmente a introdução das abordagens do exercício (ao ponto de parecer que "chegaram lá juntos")
    • contributors: O(s) nome(s) de utilizador do GitHub do(s) contribuidor(es) da introdução das abordagens do exercício (opcional)
      • Inclui os revisores se as suas revisões forem relevantes/acionáveis/acionadas.
  • approaches: Um array com as abordagens detalhadas (opcional)

    • uuid: um UUID V4 que identifica de forma única a abordagem. O UUID tem de ser único tanto dentro do percurso como em todos os percursos, e nunca pode mudar
    • slug: o slug da abordagem, que é uma string em minúsculas e em kebab-case. O slug tem de ser único entre todos os slugs de abordagens do percurso. O seu comprimento tem de ser <= 255.
    • title: o título da abordagem. O seu comprimento tem de ser <= 255.
    • blurb: Uma descrição breve desta abordagem. O comprimento tem de ser <= 350. O Markdown não é suportado (obrigatório)
    • authors: O(s) nome(s) de utilizador do GitHub do(s) autor(es) da abordagem do exercício (obrigatório)
      • Inclui os revisores se as suas revisões alterarem substancialmente a abordagem do exercício (ao ponto de parecer que "chegaram lá juntos")
    • contributors: O(s) nome(s) de utilizador do GitHub do(s) contribuidor(es) da abordagem do exercício (opcional)
      • Inclui os revisores se as suas revisões forem relevantes/acionáveis/acionadas.
    • tags: Especifica as condições em que uma submissão é associada a uma abordagem. (opcional)
      • all: Um array de etiquetas que têm de estar todas presentes numa submissão (opcional, a menos que any não tenha elementos)
      • any: Um array de etiquetas das quais pelo menos uma tem de estar presente numa submissão (opcional, a menos que all não tenha elementos)
      • not: nenhuma das etiquetas pode estar presente numa submissão (opcional)

Exemplo

{
  "introduction": {
    "authors": ["erikschierboom"]
  },
  "approaches": [
    {
      "uuid": "448fb2b4-18ab-4e55-aa54-ad4ed6d5f7f6",
      "slug": "span",
      "title": "Use Span<T>",
      "blurb": "Use Span<T> to efficiently reverse a string.",
      "authors": ["erikschierboom"]
    }
  ]
}

Ficheiro: .approaches/<approach-slug>/content.md

Objetivo: Descrição detalhada da abordagem

Presença: Opcional (obrigatório para as abordagens)

Este ficheiro contém uma descrição detalhada da abordagem. Consulta a documentação para mais informações sobre o que deve constar deste ficheiro.

Exemplo

# Span

```csharp
Span<char> chars = stackalloc char[input.Length];
for (var i = 0; i < input.Length; i++)
{
    chars[input.Length - 1 - i] = input[i];
}
return new string(chars);
```

This `Span<T>` approach uses a `for` loop.

Ficheiro: .approaches/<approach-slug>/snippet.txt

Objetivo: Fragmento que mostra a abordagem

Presença: Opcional (obrigatório para as abordagens)

Este ficheiro contém um pequeno fragmento que mostra a abordagem. O fragmento é mostrado na página de aprofundamento do exercício.

O seu número de linhas tem de ser <= 8.

Consulta a documentação para mais informações sobre o que deve constar deste ficheiro.

Exemplo

Span<char> chars = stackalloc char[input.Length];
for (var i = 0; i < input.Length; i++)
{
    chars[input.Length - 1 - i] = input[i];
}
return new string(chars);

Ficheiro: .article/config.json

Objetivo: Metadados dos artigos

Presença: Opcional (obrigatório quando existe um artigo)

Este ficheiro contém meta-informação sobre os artigos do exercício:

  • articles: Um array com os artigos detalhados (opcional)
    • uuid: um UUID V4 que identifica de forma única o artigo. O UUID tem de ser único tanto dentro do percurso como em todos os percursos, e nunca pode mudar
    • slug: o slug do artigo, que é uma string em minúsculas e em kebab-case. O slug tem de ser único entre todos os slugs de artigos do percurso. O seu comprimento tem de ser <= 255.
    • title: o título do artigo. O seu comprimento tem de ser <= 255.
    • blurb: Uma descrição breve deste artigo. O comprimento tem de ser <= 350. O Markdown não é suportado (obrigatório)
    • authors: O(s) nome(s) de utilizador do GitHub do(s) autor(es) do artigo do exercício (obrigatório)
      • Inclui os revisores se as suas revisões alterarem substancialmente o artigo do exercício (ao ponto de parecer que "chegaram lá juntos")
    • contributors: O(s) nome(s) de utilizador do GitHub do(s) contribuidor(es) do artigo do exercício (opcional)
      • Inclui os revisores se as suas revisões forem relevantes/acionáveis/acionadas.

Exemplo

{
  "articles": [
    {
      "uuid": "6db71962-62d5-448b-a980-c20ae41013ed",
      "slug": "performance",
      "title": "Optimizing performance",
      "blurb": "Explore how to most efficiently reverse a string and what the trade-offs are.",
      "authors": ["erikschierboom"]
    }
  ]
}

Ficheiro: .articles/<article-slug>/content.md

Objetivo: Descrição detalhada da abordagem

Presença: Opcional (obrigatório para as abordagens)

Este ficheiro contém uma descrição detalhada da abordagem. Consulta a documentação para mais informações sobre o que deve constar deste ficheiro.

Exemplo

# Performance

In this document, we'll find out which approach is the most performant one.

## Benchmark results

| Method |      Mean |     Error |    StdDev |    Median | Allocated |
| -----: | --------: | --------: | --------: | --------: | --------: |
|   Linq | 29.133 ns | 0.5865 ns | 0.5486 ns | 28.984 ns |      80 B |
|  Array |  4.806 ns | 0.4999 ns | 1.4739 ns |  3.967 ns |         - |

Ficheiro: .articles/<article-slug>/snippet.txt

Objetivo: Fragmento que mostra a abordagem

Presença: Opcional (obrigatório para os artigos)

Este ficheiro contém um pequeno fragmento que mostra o artigo. O fragmento é mostrado na página de aprofundamento do exercício.

O seu número de linhas tem de ser <= 8.

Consulta a documentação para mais informações sobre o que deve constar deste ficheiro.

Exemplo

| Method |      Mean | Allocated |
| -----: | --------: | --------: |
|   Linq | 29.133 ns |      80 B |
|  Array |  4.806 ns |         - |

Ficheiro: implementação stub

Objetivo: Fornecer um ponto de partida aos estudantes.

Presença: Obrigatório

  • Concebe o stub de forma a que o estudante saiba onde adicionar código.
  • Define stubs para qualquer sintaxe que não seja introduzida no exercício. Na maioria dos exercícios, isto significa definir funções/métodos stub.
  • Para linguagens compiladas, considera ter código que compile, uma vez que as mensagens do compilador podem por vezes ser difíceis de compreender para estudantes que estão a começar na linguagem.
  • O código deve ser o mais simples possível.
  • Usa apenas funcionalidades da linguagem introduzidas pelo exercício ou pelos seus pré-requisitos (e pelos pré-requisitos destes, e por aí adiante).
  • O ficheiro stub é mostrado ao estudante ao programar no navegador e é descarregado para o sistema de ficheiros do estudante quando se usa a CLI.
  • Os caminhos relativos para o(s) ficheiro(s) da implementação stub têm de ser especificados na chave "files.solution" do ficheiro .meta/config.json.

Exemplo

class Lasagna
  def remaining_minutes_in_oven(actual_minutes_in_oven)
    raise NotImplementedError, 'Please implement the Lasagna#remaining_minutes_in_oven method'
  end

  def preparation_time_in_minutes(layers)
    raise NotImplementedError, 'Please implement the Lasagna#preparation_time_in_minutes method'
  end
end

Ficheiro: testes

Objetivo: Verificar a correção de uma solução.

Presença: Obrigatório

  • Os testes não devem usar os exemplos do ficheiro instructions.md.
  • O código deve ser o mais simples possível.
  • Usa apenas funcionalidades da linguagem introduzidas pelos pré-requisitos do exercício (e pelos pré-requisitos destes, e por aí adiante).
  • O ficheiro de testes não é mostrado ao estudante ao programar no navegador, mas é descarregado para o sistema de ficheiros do estudante quando se usa a CLI.
  • Os caminhos relativos para o(s) ficheiro(s) de teste têm de ser especificados na chave "files.test" do ficheiro .meta/config.json.

Exemplo

require 'minitest/autorun'
require_relative 'lasagna'

class LasagnaTest < Minitest::Test
  def test_remaining_minutes_in_oven
    assert_equal 15, Lasagna.new.remaining_minutes_in_oven(25)
  end

  def test_preparation_time_in_minutes_with_one_layer
    assert_equal 2, Lasagna.new.preparation_time_in_minutes(1)
  end

  def test_preparation_time_in_minutes_with_multiple_layers
    assert_equal 8, Lasagna.new.preparation_time_in_minutes(4)
  end
end

Ficheiro: implementação exemplar

Objetivo: Fornecer a implementação-alvo que o estudante deve procurar alcançar.

Presença: Obrigatório

  • Esta implementação é o código-alvo que queremos que o estudante procure alcançar.
  • Os mentores verão este código como o "alvo" ao escrever feedback
  • A implementação deve usar apenas funcionalidades da linguagem introduzidas pelo exercício ou pelos seus pré-requisitos (e pelos pré-requisitos destes, e por aí adiante).
  • O ficheiro exemplar não é mostrado ao estudante ao programar no navegador e não é descarregado para o sistema de ficheiros do estudante quando se usa a CLI.
  • O ficheiro exemplar será mostrado aos mentores ao comentar soluções ou representações.
  • Os caminhos relativos para o(s) ficheiro(s) da implementação exemplar têm de ser especificados na chave "files.exemplar" do ficheiro .meta/config.json.

Exemplo

class Lasagna
  EXPECTED_MINUTES_IN_OVEN = 40
  PREPARATION_MINUTES_PER_LAYER = 2

  def remaining_minutes_in_oven(actual_minutes_in_oven)
    EXPECTED_MINUTES_IN_OVEN - actual_minutes_in_oven
  end

  def preparation_time_in_minutes(layers)
    layers * PREPARATION_MINUTES_PER_LAYER
  end
end

Ficheiro: ficheiros adicionais

Objetivo: Garantir que os testes podem ser executados.

Presença: Obrigatório se os ficheiros predefinidos não forem suficientes para executar os testes

Algumas linguagens exigem ficheiros adicionais para que os testes possam ser executados. Exemplos disso são os ficheiros de projeto de C# e os ficheiros package.json do Node, sem os quais não será possível executar os testes.

Ficheiros partilhados

Alguns ficheiros não são específicos de exercícios individuais, mas aplicam-se a todos os exercícios. Consulta a documentação para mais informações.

Nomenclatura

Os Exercícios de Conceito devem ser nomeados a partir da sua história/tema, não a partir do(s) seu(s) conceito(s).

Bons exemplos de nomes:

  • Tim from Marketing
  • Lucian's Luscious Lasagna
  • Calculator Conundrum

Nomes não permitidos:

  • Booleans: usa um nome de conceito, não um nome de história
  • Exercise #1: um exercício não é uma história/tema

Ao derivar um exercício sem alterações significativas, usa o nome original quando possível.

Slugs

Cada exercício tem também um slug, que é uma versão normalizada do nome do exercício segundo as seguintes regras:

  1. Usa letras minúsculas.
  2. Usa kebab-case.
  3. Usa carateres alfanuméricos latinos e hífenes (expressão regular: [a-z0-9-]+)
  4. Dá preferência aos algarismos escritos por extenso em vez dos numéricos, a menos que haja uma razão específica para preferir o algarismo (por exemplo, two-fer em vez de 2-fer)

Bons exemplos de slugs:

  • tim-from-marketing
  • lucians-luscious-lasagna
  • calculator-conundrum

Slugs não permitidos:

  • TIM-FROM-MARKETING: não usa letras minúsculas (ou seja, tim-from-marketing)
  • TimFromMarketing: não usa kebab-case (ou seja, tim-from-marketing)
  • floating-point-numbers: usa um nome de conceito, não um nome de história

Apresentação

Há uma diferença na forma como a documentação do exercício é apresentada ao estudante quando se usa o editor no navegador em comparação com a CLI. Consulta este documento para mais informações.

Ícone

Cada exercício tem um ícone de acompanhamento. Por predefinição, o ícone apresentado é aquele cujo nome corresponde ao slug do exercício. É possível substituir esta escolha especificando a propriedade icon no ficheiro .meta/config.json do exercício.

Se estiveres a derivar um exercício existente, provavelmente já existe um ícone para esse exercício. Se não existir, abre uma issue no repositório website-icons.