연습 문제는 학습자가 지금까지 배운 개념을 활용하는 것을 목표로, 임의의 문제를 풀어 보도록 설계된 문제예요.
트랙에 첫 연습 문제를 추가하고 싶나요? 연습 문제 추가 문서를 확인하거나 안내 영상을 시청해 봐요 👇
트랙의 루트 디렉터리에서 다음 명령어를 실행하면 새 연습 문제의 뼈대를 빠르게 만들 수 있어요:
bin/fetch-configlet
bin/configlet create --practice-exercise <slug>
자세한 내용은 configlet create 문서를 확인해 봐요.
연습 문제 메타데이터는 config.json 파일의 exercises.practice 키에 정의돼요. 메타데이터에는 연습 문제의 UUID, 슬러그 등이 담겨요.
{
"exercises": {
"practice": [
{
"uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
"slug": "leap",
"name": "Leap",
"practices": ["if-statements", "numbers", "operator-precedence"],
"prerequisites": ["if-statements", "numbers"],
"difficulty": 1
}
]
}
}
practicespractices 키에는 이 연습 문제를 통해 학습자가 실제로 연습할 수 있는 개념의 슬러그를 나열해요.
strings). 이런 경우에는 그 개념을 흥미로운 방식으로 생각해 보게 만드는 좋은 연습 문제 몇 개를 고르는 걸 추천해요. 예를 들어 UTF-8, 문자열 연결, 문자 순회 등이 필요한 연습 문제라면 모두 좋은 예시예요.prerequisitesprerequisites 키에는 이 연습 문제에 접근하려면 학습자가 반드시 완료해야 하는 개념이 나열돼요.
strings, optional-params, implicit-return 등이 포함될 수 있어요.loops나 recursion으로 풀 수 있는 문제)라면, 유지보수자는 학습자가 트랙을 따라가는 흐름을 고려해 그 연습 문제의 잠금을 해제할 한 가지 접근법을 골라야 해요. 예를 들어 루프/재귀 예시라면 이 연습 문제가 loops를 일찍 연습하기에 좋다고 생각할 수도 있고, 재귀를 가르치기 위해 나중으로 미루고 싶을 수도 있어요. 분석기를 활용해 학습자에게 다른 접근법을 시도해 보라고 안내할 수도 있어요: "루프로 잘 푸셨어요. 재귀를 사용해서 푸는 것도 시도해 보세요."연습 문제마다 트랙의 exercises/practice 디렉터리 안에 각자의 디렉터리가 있어요. 연습 문제 디렉터리 이름은 config.json 파일에 정의된 연습 문제의 slug 속성과 일치해야 해요.
연습 문제에는 네 가지 종류의 파일이 있어요:
이 파일들은 연습 문제를 설명하는 데 도움이 되도록 학습자에게 제공돼요.
.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
목적: 학습자에게 연습 문제의 상황과 배경을 소개해요.
포함 여부: 연습 문제가 introduction.md 파일을 가진 Problem Specifications 연습 문제를 구현하는 경우 필수
연습 문제가 Problem Specifications 연습 문제를 구현한다면, 이 파일의 내용은 Problem Specifications 연습 문제의 introduction.md 파일과 일치해야 해요. 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 연습 문제를 구현한다면, 이 파일의 내용은 Problem Specifications 연습 문제의 instructions.md 파일(instructions.md 파일이 없다면 description.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 제목 아래에 Markdown 목록으로 나타나야 해요.힌트 보기는 "권장" 경로가 아니며, 학습자가 힌트 없이는 진행할 수 없을 때를 빼고는 (가볍게) 사용을 말리는 편이에요. 그러니 힌트를 읽는 학습자는 다소 혼란스럽거나 벅차하고 어쩌면 답답함을 느낄 수 있다는 점을 염두에 두면 좋아요.
## 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: 이 연습 문제에서 사용하는 파일의 위치를 연습 문제 디렉터리 기준으로 나타내요(필수)
language_versions 언어 버전 요구 사항이에요(선택)blurb: 이 연습 문제에 대한 짧은 설명이에요. 길이는 350 이하여야 해요. Markdown은 지원하지 않아요(필수)source: 이 연습 문제가 기반으로 한 출처예요(선택)source_url: 이 연습 문제가 기반으로 한 출처의 URL이에요(선택)test_runner: 이 연습 문제의 풀이를 테스트 러너에서 테스트해야 하는지를 나타내요. 지정하지 않으면 true가 기본값이에요. (선택)representer: 리프리젠터가 이 파일을 처리하는 방식과 관련된 메타 정보예요(선택)
version: 연습 문제에 사용할 리프리젠터의 버전을 나타내는 정수예요(상위 키가 있으면 필수)icon: 아이콘의 슬러그예요(전체 아이콘 목록 참고). 지정하지 않으면 연습 문제의 슬러그가 사용돼요(선택)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는 자유 형식의 문자열로, 트랙에서 자유롭게 사용하고 해석할 수 있어요.목적: 어떤 테스트가 구현됐는지에 대한 정보를 담고 있어요.
포함 여부: 선택
이 파일에는 어떤 테스트가 구현되는지에 대한 정보가 담겨 있어요. 단, 연습 문제가 problem-specifications 저장소의 canonical-data.json 파일에 테스트를 정의한 경우에만 해당해요.
이 파일은 유지보수자가 어떤 테스트가 구현됐는지 추적하고, (선택적으로) 특정 테스트를 구현하지 않은 이유를 기록하는 데 도움이 돼요. 아직 구현되지 않은 테스트를 찾아내는 데도 쓸 수 있어요.
configlet 도구는 configlet sync 명령을 통해 problem-specifications 저장소의 데이터와 이 파일을 업데이트/동기화해요. 동기화할 때 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: 접근법을 고유하게 식별하는 V4 UUID예요. UUID는 트랙 안에서도, 모든 트랙을 통틀어서도 고유해야 하며 절대 바뀌면 안 돼요.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
목적: 접근법을 보여 주는 스니펫이에요
포함 여부: 선택(접근법에는 필수)
이 파일에는 접근법을 보여 주는 작은 스니펫이 담겨 있어요. 스니펫은 연습 문제의 더 깊이 알아보기 페이지에 표시돼요.
줄 수는 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: 아티클을 고유하게 식별하는 V4 UUID예요. UUID는 트랙 안에서도, 모든 트랙을 통틀어서도 고유해야 하며 절대 바뀌면 안 돼요.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
목적: 아티클을 보여 주는 스니펫이에요
포함 여부: 선택(아티클에는 필수)
이 파일에는 아티클을 보여 주는 작은 스니펫이 담겨 있어요. 스니펫은 연습 문제의 더 깊이 알아보기 페이지에 표시돼요.
줄 수는 8 이하여야 해요.
이 파일에 무엇을 담아야 하는지 자세히 알고 싶다면 문서를 확인해 봐요.
| Method | Mean | Allocated |
| -----: | --------: | --------: |
| Linq | 29.133 ns | 80 B |
| Array | 4.806 ns | - |
목적: 학습자에게 시작점을 제공해요.
포함 여부: 필수
.meta/config.json 파일의 "files.solution" 키에 지정해야 해요.using System;
public static class Isogram
{
public static bool IsIsogram(string word)
{
throw new NotImplementedException("You need to implement this function.");
}
}
목적: 풀이의 정확성을 검증해요.
포함 여부: 필수
.meta/config.json 파일의 "files.test" 키에 지정해야 해요.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"));
}
목적: 모든 테스트를 통과하는 예시 구현을 제공해요.
포함 여부: 필수
.meta/config.json 파일의 "files.example" 키에 지정해야 해요.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#의 프로젝트 파일이나 Node의 package.json 파일이 그 예인데, 이런 파일이 없으면 테스트를 실행할 수 없어요.
일부 파일은 개별 연습 문제에만 해당하지 않고 모든 연습 문제에 적용돼요. 자세한 내용은 문서를 확인해 봐요.
브라우저 편집기를 사용할 때와 CLI를 사용할 때 연습 문제 문서가 학습자에게 표시되는 방식에는 차이가 있어요. 자세한 내용은 이 문서를 참고해요.
연습 문제마다 함께 제공되는 아이콘이 있어요.
기본적으로는 이름이 연습 문제의 슬러그와 일치하는 아이콘이 표시돼요.
연습 문제의 .meta/config.json 파일에 icon 속성을 지정하면 이를 바꿀 수 있어요.
problem-specifications 메타데이터에서 가져온 연습 문제를 구현하고 있다면, 그 연습 문제에 쓸 아이콘이 이미 있을 가능성이 높아요. 없다면 website-icons 저장소에 이슈를 열어 주세요.