Практичні вправи призначені для того, щоб студенти розвʼязували довільну задачу й застосовували концепції, які вже вивчили.
Якщо ми хочемо додати свою першу практичну вправу до треку, варто зазирнути до документації про додавання практичної вправи або подивитися наш відеоогляд 👇
Можна швидко створити заготовку нової практичної вправи, виконавши такі команди в кореневій директорії треку:
bin/fetch-configlet
bin/configlet create --practice-exercise <slug>
Дізнатися більше можна в документації про configlet create
Метадані практичної вправи задаються в ключі exercises.practice у файлі config.json. Ці метадані визначають UUID вправи, її slug та багато іншого.
{
"exercises": {
"practice": [
{
"uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
"slug": "leap",
"name": "Leap",
"practices": ["if-statements", "numbers", "operator-precedence"],
"prerequisites": ["if-statements", "numbers"],
"difficulty": 1
}
]
}
}
practicesКлюч practices має містити перелік slug-ів концепцій, які ця практична вправа дає студентові змогу активно практикувати.
strings). У таких випадках радимо обирати кілька вдалих вправ, які змушують студентів думати про ці концепції в цікавий спосіб. Наприклад, добре підійдуть вправи, які вимагають роботи з UTF-8, конкатенації рядків тексту (англ. string), перебору символів тощо.prerequisitesКлюч prerequisites перелічує концепції, які студент має опанувати, щоб отримати доступ до цієї практичної вправи.
strings, optional-params, implicit-return.loops або recursion), мейнтейнер має обрати той єдиний підхід, яким вправу буде відкрито, з огляду на подорож студента треком. Наприклад, у випадку з циклами й рекурсією мейнтейнер може вважати цю вправу хорошою ранньою практикою loops або вирішити залишити її на пізніше, щоб навчити рекурсії. Також можна скористатися аналізатором, щоб підказати студентові спробувати альтернативний підхід: «Гарна робота з розвʼязанням через цикли. Спробуйте також розвʼязати це за допомогою рекурсії.»Кожна практична вправа має власну директорію всередині директорії exercises/practice треку. Назва директорії практичної вправи має збігатися з властивістю slug цієї вправи, визначеною у файлі config.json.
Практична вправа містить чотири типи файлів:
Ці файли показуються студентові, щоб допомогти пояснити вправу.
.docs/introduction.md: описує контекст і передісторію вправи (необовʼязковий).docs/introduction.append.md: додатковий вступний текст, який дописується після наявного вступу (необовʼязковий).docs/instructions.md: містить вказівки до вправи (обовʼязковий).docs/instructions.append.md: додатковий вступний текст, який дописується після наявних вказівок (необовʼязковий).docs/hints.md: містить підказки, які допомагають студентові вибратися із глухого кута у вправі (необовʼязковий)Ці файли не показуються студентові, а використовуються для задання метаданих вправи.
.meta/config.json: містить метаінформацію про вправу (обовʼязковий).meta/design.md: описує задум вправи (необовʼязковий).meta/tests.toml: містить інформацію про те, які тести реалізовано (необовʼязковий)Ці файли описують підходи до вправи.
.approaches/introduction.md: вступ до найпоширеніших підходів до вправи (необовʼязковий).approaches/config.json: метадані підходів (необовʼязковий).approaches/<approach-slug>/content.md: опис підходу (необовʼязковий).approaches/<approach-slug>/snippet.txt: фрагмент, який демонструє підхід (необовʼязковий)Ці файли описують статті до вправи.
.articles/config.json: метадані статей (необовʼязковий).articles/<article-slug>/content.md: опис статті (необовʼязковий).articles/<article-slug>/snippet.md: фрагмент, який демонструє статтю (необовʼязковий)Файли, специфічні для мови: реалізація, тести тощо. Назви цих файлів залежать від треку.
exercises
└── practice
└── isogram
├── .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
| ├── tests.toml
| └── Example.cs (example implementation)
├── Isogram.cs (stub implementation)
└── IsogramTests.cs (tests)
.docs/introduction.md
Призначення: описати студентові контекст і передісторію вправи.
Наявність: обовʼязковий, якщо вправа є реалізацією вправи з Problem Specifications і містить файл introduction.md
Якщо вправа реалізує вправу з Problem Specifications, вміст цього файлу має збігатися з файлом introduction.md цієї вправи з Problem Specifications. У configlet є можливість автоматично синхронізувати вміст цього файлу.
Якщо вправа не ґрунтується на вправі з Problem Specifications, варто зважити на таке:
Ми дуже цінуємо безпечність контенту Exercism для всіх, тому в питанні доречності історій часто обираємо обережніший шлях. Ми уважно ставимося до того, що додаємо, і розуміємо, що помітити потенційно проблемні речі буває складно, тож завжди припускаємо добрі наміри й намагаємося виявити будь-які проблеми під час ревʼю без конфронтації. Якщо хочеться перевірити історію разом із нами, варто згадати @exercism/leadership, і ми розглянемо її разом. Ось кілька орієнтирів:
# Introduction
Bob is a lackadaisical teenager. In conversation, his responses are very limited.
.docs/introduction.append.md
Призначення: додатковий вступний текст, який дописується після наявного вступу.
Наявність: необовʼязковий
У деяких (рідкісних) випадках може виникнути потреба доповнити файл introduction.md вправи, наприклад коли у вправі реалізовано тести, не охоплені наявними вказівками.
Трек, який не хоче, щоб Bob підтримував не-ASCII повідомлення, може додати таке:
# Introduction append
## Note
As part of his teenage rebellion, Bob has decided to only communicate using ASCII.
Файли-доповнення мають починатися із заголовка H1. Цей заголовок не відображається, але все одно має бути присутнім. Після заголовка H1 часто йде заголовок H2, який допомагає відокремити загальний вміст від вмісту, специфічного для треку.
.docs/instructions.md
Призначення: надати вказівки до вправи.
Наявність: обовʼязковий
Якщо вправа реалізує вправу з Problem Specifications, вміст цього файлу має збігатися з файлом instructions.md цієї вправи з Problem Specifications (або з файлом description.md, якщо файлу instructions.md немає). У configlet є можливість автоматично синхронізувати вміст цього файлу.
Якщо вправа не ґрунтується на вправі з Problem Specifications, варто зважити на таке:
Ми дуже цінуємо безпечність контенту Exercism для всіх, тому в питанні доречності історій часто обираємо обережніший шлях. Ми уважно ставимося до того, що додаємо, і розуміємо, що помітити потенційно проблемні речі буває складно, тож завжди припускаємо добрі наміри й намагаємося виявити будь-які проблеми під час ревʼю без конфронтації. Якщо хочеться перевірити історію разом із нами, варто згадати @exercism/leadership, і ми розглянемо її разом. Ось кілька орієнтирів:
# Instructions
Bob answers 'Sure.' if you ask him a question, such as "How are you?".
He answers 'Whoa, chill out!' if you YELL AT HIM (in all capitals).
He answers 'Calm down, I know what I'm doing!' if you yell a question at him.
He says 'Fine. Be that way!' if you address him without actually saying anything.
He answers 'Whatever.' to anything else.
.docs/instructions.append.md
Призначення: додатковий текст вказівок, який дописується після наявних вказівок.
Наявність: необовʼязковий
У деяких (рідкісних) випадках може виникнути потреба доповнити файл instructions.md вправи, наприклад коли у вправі реалізовано тести, не охоплені наявними вказівками.
# Instructions append
## Note
Bob's conversational partner is a purist when it comes to written communication and always follows normal rules regarding sentence punctuation in English.
Файли-доповнення мають починатися із заголовка H1. Цей заголовок не відображається, але все одно має бути присутнім. Після заголовка H1 часто йде заголовок H2, який допомагає відокремити загальний вміст від вмісту, специфічного для треку.
.docs/hints.md
Призначення: надати студентові підказки, які допоможуть вибратися із глухого кута у вправі.
Наявність: необовʼязковий
## General.Перегляд підказок не вважатиметься «рекомендованим» шляхом, і ми (мʼяко) відмовляємо від нього, якщо без нього студент не може рухатися далі. Тож варто зважати, що студент, який їх читає, буде трохи розгублений чи перевантажений, а може, й засмучений.
## General
- There are many [built-in methods][integers] to simplify working with integers.
[integers]: https://ruby-doc.org/core-2.7.0/Integer.html
Призначення: описати задум вправи.
Наявність: необовʼязковий
Цей файл містить інформацію про задум вправи: її мету, навчальні цілі, те, чого не варто навчати, тощо.
Він існує, щоб майбутні мейнтейнери та контрибʼютори знали про обсяг і обмеження вправи й не піддавалися природній тенденції робити вправи з часом дедалі складнішими.
# Design
## Goal
The goal of this exercise is help students practice how to work with strings.
## Notes
This exercise does not contain any error handling tests.
.meta/config.json
Призначення: містить метаінформацію про вправу.
Наявність: обовʼязковий
Цей файл містить метаінформацію про вправу:
authors: імʼя (імена) користувачів GitHub, які є авторами вправи (необовʼязковий)
contributors: імʼя (імена) користувачів GitHub, які є контрибʼюторами вправи (необовʼязковий)
files: розташування файлів, які використовуються у цій вправі, відносно директорії вправи (обовʼязковий)
solution: файл(и) заглушки реалізації (обовʼязковий)test: файл(и) тестів (обовʼязковий)example: файл(и) прикладу реалізації (обовʼязковий)editor: додаткові файли, які показуються в редакторі лише для читання (необовʼязковий)invalidator: файли, зміна яких робить рішення застарілим (необовʼязковий)language_versions вимоги до версії мови (необовʼязковий)blurb: короткий опис цієї вправи. Довжина має бути <= 350. Markdown не підтримується (обовʼязковий)source: джерело, на якому ґрунтується ця вправа (необовʼязковий)source_url: URL джерела, на якому ґрунтується ця вправа (необовʼязковий)test_runner: указує, чи мають рішення цієї вправи тестуватися в тест-раннері. Якщо не вказано, типовим є true. (необовʼязковий)representer: метаінформація про те, як репрезентер обробляє цей файл (необовʼязковий)
version: ціле число, яке задає версію репрезентера для цієї вправи (обовʼязковий, якщо присутній батьківський ключ)icon: slug іконки (див. повний список іконок). Якщо не вказано, буде використано slug вправи (необовʼязковий)custom: будь-які нестандартні дані, специфічні для вправи. Можна використовувати, щоб налаштувати поведінку інструментарію треку для конкретної вправи (необовʼязковий)Якщо людина є і автором, і контрибʼютором, укажіть її лише як автора.
{
"authors": ["FSharpForever"],
"files": {
"solution": ["Bob.fs"],
"test": ["BobTests.fs"],
"example": [".meta/Example.fs"]
},
"blurb": "Bob is a lackadaisical teenager. In conversation, his responses are very limited"
}
Варто зауважити:
language_versions: це рядок тексту довільної форми, який треки можуть використовувати й тлумачити як завгодно.Призначення: містить інформацію про те, які тести реалізовано.
Наявність: необовʼязковий
Цей файл містить інформацію про те, які тести реалізовано, за умови що у вправи є тести, визначені у файлі canonical-data.json у репозиторії problem-specifications.
Він існує, щоб допомагати мейнтейнерам відстежувати, які тести реалізовано, і (за бажанням) документувати, чому певний тест не реалізовано. Його також можна використовувати для виявлення нереалізованих тестів.
Інструмент configlet оновлює та синхронізує цей файл із даними в репозиторії problem-specifications за допомогою команди configlet sync. Під час синхронізації configlet для кожного нереалізованого тесту запитує, чи включати цей тест.
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.
[3e5c30a8-87e2-4845-a815-a49671ade970]
description = "empty strand"
[a0ea42a6-06d9-4ac6-828c-7ccaccf98fec]
description = "can count one nucleotide in single-character input"
[eca0d565-ed8c-43e7-9033-6cefbf5115b5]
description = "strand with repeated nucleotide"
[40a45eac-c83f-4740-901a-20b22d15a39f]
description = "strand with multiple nucleotides"
[b4c47851-ee9e-4b0a-be70-a86e343bd851]
description = "strand with invalid nucleotides"
include = false
comment = "error handling omitted on purpose"
.approaches/introduction.md
Призначення: вступ до найпоширеніших підходів до вправи
Наявність: необовʼязковий
Цей файл описує найпоширеніші підходи до вправи. Що саме має бути в цьому файлі, описано в документації.
# 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.
.approaches/config.json
Призначення: метадані підходів
Наявність: необовʼязковий (обовʼязковий, якщо існує вступ до підходів або сам підхід)
Цей файл містить метаінформацію про підходи до вправи:
introduction: імʼя (імена) користувачів GitHub, які є авторами вступу до підходів вправи (необовʼязковий)
authors: імʼя (імена) користувачів GitHub, які є авторами вступу до підходів вправи (обовʼязковий)
contributors: імʼя (імена) користувачів GitHub, які є контрибʼюторами вступу до підходів вправи (необовʼязковий)
approaches: масив, який перелічує докладні підходи (необовʼязковий)
uuid: UUID версії V4, який однозначно ідентифікує підхід. UUID має бути унікальним як у межах треку, так і серед усіх треків, і ніколи не має змінюватисяslug: slug підходу, тобто рядок тексту в нижньому регістрі у kebab-case. Slug має бути унікальним серед усіх slug-ів підходів у межах треку. Його довжина має бути <= 255.title: назва підходу. Її довжина має бути <= 255.blurb: короткий опис цього підходу. Довжина має бути <= 350. Markdown не підтримується (обовʼязковий)authors: імʼя (імена) користувачів GitHub, які є авторами підходу до вправи (обовʼязковий)
contributors: імʼя (імена) користувачів GitHub, які є контрибʼюторами підходу до вправи (необовʼязковий)
tags: задають умови, за яких надіслане рішення повʼязується з підходом. (необовʼязковий)
all: масив тегів, які всі мають бути присутні в надісланому рішенні (необовʼязковий, якщо в any немає елементів)any: масив тегів, з яких принаймні один має бути присутній у надісланому рішенні (необовʼязковий, якщо в all немає елементів)not: жоден із тегів не має бути присутній у надісланому рішенні (необовʼязковий){
"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"]
}
]
}
.approaches/<approach-slug>/content.md
Призначення: докладний опис підходу
Наявність: необовʼязковий (обовʼязковий для підходів)
Цей файл містить докладний опис підходу. Що саме має бути в цьому файлі, описано в документації.
# 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.
.approaches/<approach-slug>/snippet.txt
Призначення: фрагмент, який демонструє підхід
Наявність: необовʼязковий (обовʼязковий для підходів)
Цей файл містить невеликий фрагмент, який демонструє підхід. Фрагмент показується на сторінці «Dig Deeper» вправи.
Кількість рядків у ньому має бути <= 8.
Що саме має бути в цьому файлі, описано в документації.
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);
.article/config.json
Призначення: метадані статей
Наявність: необовʼязковий (обовʼязковий, якщо існує стаття)
Цей файл містить метаінформацію про статті до вправи:
articles: масив, який перелічує докладні статті (необовʼязковий)
uuid: UUID версії V4, який однозначно ідентифікує статтю. UUID має бути унікальним як у межах треку, так і серед усіх треків, і ніколи не має змінюватисяslug: slug статті, тобто рядок тексту в нижньому регістрі у kebab-case. Slug має бути унікальним серед усіх slug-ів статей у межах треку. Його довжина має бути <= 255.title: назва статті. Її довжина має бути <= 255.blurb: короткий опис цієї статті. Довжина має бути <= 350. Markdown не підтримується (обовʼязковий)authors: імʼя (імена) користувачів GitHub, які є авторами статті до вправи (обовʼязковий)
contributors: імʼя (імена) користувачів GitHub, які є контрибʼюторами статті до вправи (необовʼязковий)
{
"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"]
}
]
}
.articles/<article-slug>/content.md
Призначення: докладний опис підходу
Наявність: необовʼязковий (обовʼязковий для підходів)
Цей файл містить докладний опис підходу. Що саме має бути в цьому файлі, описано в документації.
# 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 | - |
.articles/<article-slug>/snippet.txt
Призначення: фрагмент, який демонструє підхід
Наявність: необовʼязковий (обовʼязковий для статей)
Цей файл містить невеликий фрагмент, який демонструє статтю. Фрагмент показується на сторінці «Dig Deeper» вправи.
Кількість рядків у ньому має бути <= 8.
Що саме має бути в цьому файлі, описано в документації.
| Method | Mean | Allocated |
| -----: | --------: | --------: |
| Linq | 29.133 ns | 80 B |
| Array | 4.806 ns | - |
Призначення: дати студентові відправну точку.
Наявність: обовʼязковий
"files.solution" файлу .meta/config.json.using System;
public static class Isogram
{
public static bool IsIsogram(string word)
{
throw new NotImplementedException("You need to implement this function.");
}
}
Призначення: перевірити правильність рішення.
Наявність: обовʼязковий
"files.test" файлу .meta/config.json.using Xunit;
public class IsogramTest
{
[Fact]
public void Empty_string() =>
Assert.True(Isogram.IsIsogram(""));
[Fact(Skip = "Remove this Skip property to run this test")]
public void Isogram_with_only_lower_case_characters() =>
Assert.True(Isogram.IsIsogram("isogram"));
[Fact(Skip = "Remove this Skip property to run this test")]
public void Word_with_one_duplicated_character() =>
Assert.False(Isogram.IsIsogram("eleven"));
}
Призначення: надати приклад реалізації, яка проходить усі тести.
Наявність: обовʼязковий
"files.example" файлу .meta/config.json.using System.Linq;
public static class Isogram
{
public static bool IsIsogram(string word)
{
var lowerCaseLetters = word.ToLower().Where(char.IsLetter).ToList();
return lowerCaseLetters.Distinct().Count() == lowerCaseLetters.Count;
}
}
Призначення: додаткові файли проєкту, збірки чи допоміжні файли, потрібні для запуску тестів.
Наявність: обовʼязковий, якщо типових файлів не вистачає для запуску тестів
Деякі мови потребують додаткових файлів, щоб тести могли запускатися. Приклади: файли проєктів у C# та файли package.json у Node, без яких запустити тести неможливо.
Деякі файли не належать окремим вправам, а стосуються всіх вправ. Додаткову інформацію шукайте в документації.
Те, як документація вправи показується студентові, відрізняється під час використання редактора в браузері та CLI. Додаткову інформацію див. у цьому документі.
Кожна вправа має супровідну іконку.
Типово показується та іконка, назва якої збігається зі slug вправи.
Це можна перевизначити, указавши властивість icon у файлі .meta/config.json вправи.
Якщо ми реалізуємо вправу на основі метаданих problem-specifications, для неї, найімовірніше, уже є іконка. Якщо ні, варто відкрити issue в репозиторії website-icons.